summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.editorconfig37
-rw-r--r--.eslintignore5
-rw-r--r--.eslintrc.yml63
-rw-r--r--.github/ISSUE_TEMPLATE/broken-site-report.md19
-rw-r--r--.github/SECURITY.md5
-rw-r--r--.gitignore51
-rw-r--r--.travis.yml36
-rw-r--r--.tx/config8
-rw-r--r--CODE_OF_CONDUCT.md1
-rw-r--r--CONTRIBUTING.md23
-rw-r--r--LICENSE844
-rw-r--r--Makefile35
-rw-r--r--README.md32
-rw-r--r--doc/Changelog550
-rw-r--r--doc/DESIGN-AND-ROADMAP.md276
-rw-r--r--doc/Translation.md92
-rw-r--r--doc/admin-deployment.md49
-rw-r--r--doc/develop.md45
-rw-r--r--doc/fixing-broken-sites.md63
-rw-r--r--doc/jid1-MnnxcxisBPnSXQ@jetpack.json11
-rw-r--r--doc/permissions.md27
-rw-r--r--doc/sample-managed-storage-manifest-chrome.json12
-rw-r--r--doc/tests.md92
-rw-r--r--doc/yellowlist-criteria.md8
-rw-r--r--package-lock.json7063
-rw-r--r--package.json22
-rwxr-xr-xrelease-utils/chromium-release.sh26
-rwxr-xr-xrelease-utils/firefox-release.sh45
-rwxr-xr-xrelease-utils/make-eff-zip.sh32
-rwxr-xr-xrelease-utils/make-release-zip.sh43
-rwxr-xr-xrelease-utils/make-release.sh50
-rwxr-xr-xrelease-utils/make-signed-xpi.sh65
-rwxr-xr-xrelease-utils/post-chrome-release.sh29
-rwxr-xr-xrelease-utils/post-release.sh77
-rwxr-xr-xscripts/chromedriver.sh25
-rwxr-xr-xscripts/convertpsl.py36
-rwxr-xr-xscripts/fix_placeholders.py40
-rwxr-xr-xscripts/generate-legacy-yellowlist.sh1
-rwxr-xr-xscripts/run_travis.sh36
-rwxr-xr-xscripts/setup_travis.sh79
-rwxr-xr-xscripts/updategoogle.py51
-rwxr-xr-xscripts/updategoogle.sh27
-rwxr-xr-xscripts/updatepsl.sh28
-rwxr-xr-xscripts/updateseeddata.sh33
-rw-r--r--scripts/verify_json.py18
-rw-r--r--src/_locales/ar/messages.json677
-rw-r--r--src/_locales/bg/messages.json677
-rw-r--r--src/_locales/ca/messages.json677
-rw-r--r--src/_locales/cs/messages.json677
-rw-r--r--src/_locales/da/messages.json677
-rw-r--r--src/_locales/de/messages.json677
-rw-r--r--src/_locales/en_US/messages.json677
-rw-r--r--src/_locales/eo/messages.json677
-rw-r--r--src/_locales/es/messages.json677
-rw-r--r--src/_locales/fa/messages.json677
-rw-r--r--src/_locales/fi/messages.json677
-rw-r--r--src/_locales/fr/messages.json677
-rw-r--r--src/_locales/he/messages.json677
-rw-r--r--src/_locales/it/messages.json677
-rw-r--r--src/_locales/ko/messages.json677
-rwxr-xr-xsrc/_locales/nl/messages.json677
-rw-r--r--src/_locales/pl/messages.json677
-rw-r--r--src/_locales/pt_BR/messages.json677
-rw-r--r--src/_locales/pt_PT/messages.json677
-rw-r--r--src/_locales/ru/messages.json677
-rw-r--r--src/_locales/sv/messages.json677
-rw-r--r--src/_locales/tr/messages.json677
-rw-r--r--src/_locales/uk/messages.json677
-rw-r--r--src/_locales/zh_CN/messages.json677
-rw-r--r--src/_locales/zh_TW/messages.json677
-rw-r--r--src/data/dnt-policies.json9
-rw-r--r--src/data/dnt-policy.txt218
-rw-r--r--src/data/schema.json48
-rw-r--r--src/data/seed.json19505
-rw-r--r--src/data/socialwidgets.json266
-rw-r--r--src/data/surrogates.js474
-rw-r--r--src/data/yellowlist.txt788
-rw-r--r--src/icons/UI-icons-green.svg10
-rw-r--r--src/icons/UI-icons-red.svg10
-rw-r--r--src/icons/UI-icons-yellow.svg17
-rw-r--r--src/icons/badger-128.pngbin0 -> 6072 bytes
-rw-r--r--src/icons/badger-16.pngbin0 -> 1686 bytes
-rw-r--r--src/icons/badger-19-disabled.pngbin0 -> 483 bytes
-rw-r--r--src/icons/badger-19.pngbin0 -> 1959 bytes
-rw-r--r--src/icons/badger-38-disabled.pngbin0 -> 1078 bytes
-rw-r--r--src/icons/badger-38.pngbin0 -> 1442 bytes
-rw-r--r--src/icons/badger-48.pngbin0 -> 2824 bytes
-rw-r--r--src/icons/badger-64.pngbin0 -> 2045 bytes
-rw-r--r--src/icons/badger-bw-noborder.svg72
-rw-r--r--src/icons/badger-pin.pngbin0 -> 436 bytes
-rw-r--r--src/icons/dnt-16.pngbin0 -> 343 bytes
-rw-r--r--src/icons/help.svg3
-rw-r--r--src/icons/options.svg3
-rw-r--r--src/icons/share.svg3
-rw-r--r--src/js/background.js1148
-rw-r--r--src/js/bootstrap.js37
-rw-r--r--src/js/constants.js54
-rw-r--r--src/js/contentscripts/clobbercookie.js60
-rw-r--r--src/js/contentscripts/clobberlocalstorage.js94
-rw-r--r--src/js/contentscripts/collapser.js56
-rw-r--r--src/js/contentscripts/dnt.js66
-rw-r--r--src/js/contentscripts/fingerprinting.js367
-rw-r--r--src/js/contentscripts/socialwidgets.js641
-rw-r--r--src/js/contentscripts/supercookie.js151
-rw-r--r--src/js/contentscripts/utils.js53
-rw-r--r--src/js/firefoxandroid.js90
-rw-r--r--src/js/firstparties/facebook.js56
-rw-r--r--src/js/firstparties/google-search.js39
-rw-r--r--src/js/firstparties/google-static.js41
-rw-r--r--src/js/firstparties/lib/utils.js62
-rw-r--r--src/js/heuristicblocking.js557
-rw-r--r--src/js/htmlutils.js283
-rw-r--r--src/js/incognito.js49
-rw-r--r--src/js/migrations.js356
-rw-r--r--src/js/multiDomainFirstParties.js4133
-rw-r--r--src/js/options.js976
-rw-r--r--src/js/popup.js723
-rw-r--r--src/js/socialwidgetloader.js133
-rw-r--r--src/js/storage.js707
-rw-r--r--src/js/surrogates.js87
-rw-r--r--src/js/utils.js445
-rw-r--r--src/js/webrequest.js1293
-rw-r--r--src/lib/basedomain.js319
-rw-r--r--src/lib/i18n.js151
-rw-r--r--src/lib/options.js120
-rw-r--r--src/lib/publicSuffixList.js7497
-rw-r--r--src/lib/vendor/jquery-3.5.1.js10872
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_55_fbf9ee_1x400.pngbin0 -> 335 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_65_ffffff_1x400.pngbin0 -> 207 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_dadada_1x400.pngbin0 -> 262 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_e6e6e6_1x400.pngbin0 -> 262 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_95_fef1ec_1x400.pngbin0 -> 332 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_highlight-soft_75_cccccc_1x100.pngbin0 -> 280 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_222222_256x240.pngbin0 -> 6922 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_2e83ff_256x240.pngbin0 -> 4549 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_454545_256x240.pngbin0 -> 6992 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_888888_256x240.pngbin0 -> 6999 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_cd0a0a_256x240.pngbin0 -> 4549 bytes
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.js2815
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.structure.css286
-rw-r--r--src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.theme.css443
-rw-r--r--src/lib/vendor/jquery-ui-iconfont-2.3.2/font/jquery-ui.woff2bin0 -> 21208 bytes
-rw-r--r--src/lib/vendor/jquery-ui-iconfont-2.3.2/jquery-ui-1.12.icon-font.css839
-rw-r--r--src/lib/vendor/jquery.smooth-scroll.js357
-rw-r--r--src/lib/vendor/punycode-1.4.1.js533
-rw-r--r--src/lib/vendor/select2-4.0.11/select2-4.0.11.css481
-rw-r--r--src/lib/vendor/select2-4.0.11/select2-4.0.11.js6044
-rw-r--r--src/lib/vendor/toggle-switch.css310
-rw-r--r--src/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.css388
-rw-r--r--src/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.js4273
-rw-r--r--src/lib/vendor/underscore-1.9.1.js1692
-rw-r--r--src/manifest.json522
-rw-r--r--src/skin/background.pngbin0 -> 1070 bytes
-rw-r--r--src/skin/css/firstRun.css798
-rw-r--r--src/skin/firstRun.html131
-rw-r--r--src/skin/fonts/Chunk.ttfbin0 -> 31268 bytes
-rw-r--r--src/skin/fonts/OpenSans-Bold.ttfbin0 -> 224452 bytes
-rw-r--r--src/skin/fonts/OpenSans-Light.ttfbin0 -> 222236 bytes
-rw-r--r--src/skin/images/EFF-red.svg7
-rw-r--r--src/skin/images/carrot-down.svg10
-rw-r--r--src/skin/images/catches-trackers.pngbin0 -> 30571 bytes
-rw-r--r--src/skin/images/disable-badger.pngbin0 -> 19494 bytes
-rw-r--r--src/skin/images/eff-logo.pngbin0 -> 356 bytes
-rw-r--r--src/skin/images/facebook.svg19
-rw-r--r--src/skin/images/learns-trackers.pngbin0 -> 35251 bytes
-rw-r--r--src/skin/images/not-ad-blocker.pngbin0 -> 9138 bytes
-rw-r--r--src/skin/images/pb-logo-outline.svg41
-rw-r--r--src/skin/images/twitter.svg19
-rw-r--r--src/skin/js/firstRun.js25
-rw-r--r--src/skin/options-layout.css260
-rw-r--r--src/skin/options.html307
-rw-r--r--src/skin/popup.css488
-rw-r--r--src/skin/popup.html155
-rw-r--r--src/skin/socialwidgets/AddThis.svg134
-rw-r--r--src/skin/socialwidgets/Digg.svg212
-rw-r--r--src/skin/socialwidgets/FacebookLike.svg216
-rw-r--r--src/skin/socialwidgets/FacebookShare.svg214
-rw-r--r--src/skin/socialwidgets/LinkedIn.svg182
-rw-r--r--src/skin/socialwidgets/Pinterest.svg211
-rw-r--r--src/skin/socialwidgets/Twitter.svg116
-rw-r--r--src/tests/.eslintrc.yml4
-rw-r--r--src/tests/index.html76
-rw-r--r--src/tests/lib/qunit_config.js74
-rw-r--r--src/tests/lib/vendor/qunit-2.9.2.css436
-rw-r--r--src/tests/lib/vendor/qunit-2.9.2.js6604
-rw-r--r--src/tests/lib/vendor/sinon-2.0.0.js11586
-rw-r--r--src/tests/tests/background.js467
-rw-r--r--src/tests/tests/baseDomain.js255
-rw-r--r--src/tests/tests/firstparties.js167
-rw-r--r--src/tests/tests/heuristic.js165
-rw-r--r--src/tests/tests/htmlutils.js241
-rw-r--r--src/tests/tests/multiDomainFirstParties.js73
-rw-r--r--src/tests/tests/options.js105
-rw-r--r--src/tests/tests/storage.js638
-rw-r--r--src/tests/tests/tabData.js310
-rw-r--r--src/tests/tests/utils.js550
-rw-r--r--src/tests/tests/yellowlist.js424
-rw-r--r--tests/requirements.txt3
-rw-r--r--tests/selenium/.flake82
-rw-r--r--tests/selenium/breakage_test.py30
-rw-r--r--tests/selenium/clobbering_test.py102
-rw-r--r--tests/selenium/cookie_test.py163
-rw-r--r--tests/selenium/dnt_test.py324
-rw-r--r--tests/selenium/fingerprinting_test.py105
-rw-r--r--tests/selenium/options_test.py327
-rw-r--r--tests/selenium/pbtest.py498
-rw-r--r--tests/selenium/pbtest_org_test.py71
-rw-r--r--tests/selenium/popup_test.py361
-rw-r--r--tests/selenium/qunit_test.py38
-rw-r--r--tests/selenium/service_workers_test.py56
-rw-r--r--tests/selenium/storage_test.py71
-rw-r--r--tests/selenium/super_cookie_test.py120
-rw-r--r--tests/selenium/surrogates_test.py104
-rw-r--r--tests/selenium/website_testbed/first-party.html13
-rw-r--r--tests/selenium/website_testbed/first-party.js25
-rw-r--r--tests/selenium/widgets_test.py344
216 files changed, 127737 insertions, 0 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..a27ccd2
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,37 @@
+# EditorConfig is awesome: http://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+# Unix-style newlines with a newline ending every file
+[*]
+end_of_line = lf
+insert_final_newline = true
+charset = utf-8
+
+[*.css]
+indent_style = space
+indent_size = 4
+
+[*.html]
+indent_style = space
+indent_size = 2
+
+[*.js]
+indent_style = space
+indent_size = 2
+
+[*.json]
+indent_style=space
+indent_size = 4
+
+[manifest.json]
+indent_size = 2
+
+[*.py]
+indent_style = space
+indent_size = 4
+
+[*.sh]
+indent_style = space
+indent_size = 2
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 0000000..9c8a92f
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,5 @@
+src/lib/vendor/
+src/tests/lib/vendor/
+node_modules/
+**/selenium/
+!tests/selenium/
diff --git a/.eslintrc.yml b/.eslintrc.yml
new file mode 100644
index 0000000..1742cd8
--- /dev/null
+++ b/.eslintrc.yml
@@ -0,0 +1,63 @@
+env:
+ browser: true
+ es6: true
+ jquery: true
+ webextensions: true
+extends: 'eslint:recommended'
+globals:
+ # false to disallow overwriting
+ require: false
+ _: false
+parserOptions:
+ ecmaVersion: 2017
+ # strict mode
+ sourceType: module
+rules:
+ array-callback-return: error
+ brace-style:
+ - error
+ - 1tbs
+ - allowSingleLine: true
+ consistent-this:
+ - error
+ - self
+ curly: error
+ dot-notation: error
+ eol-last: error
+ indent:
+ - error
+ - 2
+ - outerIIFEBody: 0
+ keyword-spacing: error
+ linebreak-style:
+ - error
+ - unix
+ new-cap: error
+ no-array-constructor: error
+ no-bitwise: error
+ no-caller: error
+ no-console: off
+ no-eval: error
+ no-implied-eval: error
+ no-iterator: error
+ no-loop-func: error
+ no-multi-spaces: error
+ no-multi-str: error
+ no-new: error
+ no-new-func: error
+ no-new-object: error
+ no-new-wrappers: error
+ no-proto: error
+ no-script-url: error
+ no-shadow: error
+ no-shadow-restricted-names: error
+ no-tabs: error
+ no-trailing-spaces: error
+ no-unused-expressions: error
+ semi: error
+ space-before-blocks: error
+ space-in-parens: error
+ space-unary-ops:
+ - error
+ - words: true
+ nonwords: false
diff --git a/.github/ISSUE_TEMPLATE/broken-site-report.md b/.github/ISSUE_TEMPLATE/broken-site-report.md
new file mode 100644
index 0000000..ade57fb
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/broken-site-report.md
@@ -0,0 +1,19 @@
+---
+name: Report a broken site
+about: Is Privacy Badger breaking something somewhere? We'd like to get it fixed!
+
+---
+
+#### What is your browser and browser version?
+
+#### What is broken and where?
+
+#### What is the "culprit" domain?
+Please follow the debug instructions to identify which domain breaks stuff when blocked:
+https://github.com/EFForg/privacybadger/wiki/Find-out-why-Privacy-Badger-is-blocking-a-domain
+
+#### What is your debug output for this domain?
+To get the debug output, please see the instructions link above.
+```
+Paste debug output here.
+```
diff --git a/.github/SECURITY.md b/.github/SECURITY.md
new file mode 100644
index 0000000..79d2be9
--- /dev/null
+++ b/.github/SECURITY.md
@@ -0,0 +1,5 @@
+# Security Policy
+
+## Reporting a Vulnerability
+
+Security vulnerabilities can be reported privately to vulnerabilities@eff.org. Please see our [Security Vulnerability Disclosure Program](https://www.eff.org/security) for the GPG key and more information.
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..19d5adb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,51 @@
+*.py[cod]
+
+# C extensions
+*.so
+
+# Packages
+*.egg
+*.egg-info
+dist
+build
+eggs
+parts
+bin
+var
+sdist
+develop-eggs
+.installed.cfg
+lib64
+__pycache__
+
+# Dynamic libraries
+*.dylib
+
+# JSHydra
+buildtools/jshydra/mozilla/js
+
+# Vim swap files
+*.sw*
+
+# Mac DS_Store
+*.DS_Store
+
+node_modules
+
+tests/.cache
+tests/.pytest_cache
+.pytest_cache
+
+*.xpi
+.chrome-profile
+
+.idea
+
+#Eclipse project stuff
+.settings/
+.project
+
+web-ext-artifacts
+pkg
+release-utils/config.sh
+release-utils/xpi
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..9c2ef5a
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,36 @@
+sudo: required
+language: python
+os: linux
+dist: bionic
+python: 3.6
+jobs:
+ fast_finish: true
+ include:
+ - env: INFO="lint"
+ node_js: node
+ - env: INFO="chrome beta" BROWSER=google-chrome-beta
+ addons:
+ chrome: beta
+ - env: INFO="chrome stable" BROWSER=google-chrome-stable
+ addons:
+ chrome: stable
+ - env: INFO="firefox" BROWSER=firefox
+ addons:
+ firefox: latest
+ - env: INFO="firefox esr" BROWSER=firefox
+ addons:
+ firefox: latest-esr
+ - env: INFO="firefox beta" BROWSER=firefox
+ addons:
+ firefox: latest-beta
+ - env: INFO="firefox nightly" BROWSER=firefox
+ addons:
+ firefox: latest-nightly
+ allow_failures:
+ - env: INFO="firefox nightly" BROWSER=firefox
+ addons:
+ firefox: latest-nightly
+before_script: travis_retry ./scripts/setup_travis.sh
+script: . ./scripts/run_travis.sh
+services:
+ - xvfb
diff --git a/.tx/config b/.tx/config
new file mode 100644
index 0000000..bebb04e
--- /dev/null
+++ b/.tx/config
@@ -0,0 +1,8 @@
+[main]
+host = https://www.transifex.com
+
+[privacy-badger.messagesjson]
+file_filter = src/_locales/<lang>/messages.json
+source_file = src/_locales/en_US/messages.json
+source_lang = en_US
+type = CHROME
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..142b31c
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1 @@
+This project is governed by [EFF's Public Projects Code of Conduct](https://www.eff.org/pages/eppcode). \ No newline at end of file
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..f1a46a8
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,23 @@
+# Contributing to Privacy Badger
+
+Welcome dear contributor! There are many ways to help Privacy Badger:
+
+* Did we break a site? We want to fix it,
+ so we wrote a [guide to fixing broken sites](/doc/fixing-broken-sites.md).
+* Want to help translate Privacy Badger? Please see our [guide to translating Privacy Badger](/doc/Translation.md).
+* To review issues we would like help with, visit our
+ ["good first issue"](https://github.com/EFForg/privacybadger/labels/good%20first%20issue)
+ and
+ ["help wanted"](https://github.com/EFForg/privacybadger/labels/help%20wanted)
+ labels.
+* When making changes to Privacy Badger's code, please consult our [developer](/doc/develop.md) and [automated testing](/doc/tests.md) guides.
+* Security vulnerabilities can be reported privately to
+ [vulnerabilities@eff.org](mailto:vulnerabilities@eff.org). Please see our
+ [Security Vulnerability Disclosure Program](https://www.eff.org/security)
+ for the GPG key and more information.
+
+When interacting with us, please remember to follow [EFF's Public Projects Code of Conduct](https://www.eff.org/pages/eppcode).
+
+If you find something confusing or frustrating, please [let us know](mailto:extension-devs@eff.org)! We believe in making Privacy Badger better by making it easier for you to contribute.
+
+Thank you!
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8cef74a
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,844 @@
+Privacy Badger
+Copyright © 2015 Electronic Frontier Foundation and other contributors
+
+Privacy Badger as a whole is presently Licensed GPL v3+, though many portions
+of the code are dual-licensed under other free/open source licenses.
+
+CONTRIBUTORS AGREE TO FREE/OPEN SOURCE DUAL-LICENSING
+=====================================================
+
+By contributing code or other works of authorship to this project ("Your
+Contributions"), you grant to the Electronic Frontier Foundation (EFF) a
+perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+license to reproduce, prepare derivative works of, publicly display, publicly
+perform, sublicense, and distribute Your Contributions and such derivative
+works under the terms of any free software or open source license or licenses,
+such license(s) to be selected by EFF at its sole discretion (such licenses
+will always be consistent with EFF's mission).
+
+By contributing code or other works of authorship to this project, you
+represent that you have the legal right and ability to grant this license.
+
+Except for the license granted herein to EFF and recipients of software
+distributed by EFF, You reserve all right, title, and interest in and to Your
+Contributions.
+
+If you do not agree to these terms, please do not send patches or pull
+requests, or commit any material to this repository.
+
+LICENSES FOR INCORPORATED CODEBASES
+===================================
+
+jQuery JavaScript Library
+Copyright JS Foundation and other contributors
+Released under the MIT license
+https://jquery.org/license
+
+Underscore.js
+http://underscorejs.org
+(c) 2009-2018 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+Underscore may be freely distributed under the MIT license.
+
+jQuery UI
+Copyright jQuery Foundation and other contributors
+Licensed MIT
+
+Incorporating code from CSS Toggle Switch,
+https://github.com/ghinda/css-toggle-switch
+By Ionuț Colceriu - ghinda.net
+Licensed Unlicense
+
+Incorporating code from AdBlockPlus,
+https://adblockplus.org/en/firefox
+Copyright © 2006-2014 Eyeo GmbH
+Licensed GPL v3
+
+basedomain.js incorporates code from ipv6.js
+https://github.com/beaugunderson/javascript-ipv6
+Copyright 2011 Beau Gunderson
+Licensed MIT
+
+src/js/firstparties/facebook.js incorporates code from Facebook™ Tracking & Ad Removal
+https://github.com/mgziminsky/FacebookTrackingRemoval
+Copyright 2018 Michael Ziminsky
+Licensed GPL v3
+
+Incorporating code from ShareMeNot,
+https://sharemenot.cs.washington.edu
+Copyright © 2006-2014 University of Washington
+Licensed MIT
+
+Incorporating code from Chameleon,
+https://github.com/ghostwords/chameleon
+Copyright © 2015 ghostwords
+This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+file, You can obtain one at http://mozilla.org/MPL/2.0/.
+Alternatively, this code may be distributed or
+otherwise used under the terms of GPL v3
+
+Incorporating code from Punycode.js
+http://mths.be/punycode
+Copyright 2011 Mathias Bynens <http://mathiasbynens.be/>
+Licensed MIT
+
+Tooltipster
+http://iamceege.github.io/tooltipster/
+Copyright (c) 2012,2016 Caleb Jacob and Louis Ameline
+Licensed MIT
+
+ChunkFive
+https://www.theleagueofmoveabletype.com/
+All fonts from The League of Moveable Type are subject to the Open Font License and are free and open-source.
+
+OpenSans
+https://www.apache.org/licenses/LICENSE-2.0
+
+jQuery Smooth Scroll - v2.2.0 - 2017-05-05
+https://github.com/kswedberg/jquery-smooth-scroll
+Copyright (c) 2017 Karl Swedberg
+Licensed MIT
+
+Select2
+https://select2.org/
+Copyright (c) 2012-2017 Kevin Brown, Igor Vaynberg, and Select2 contributors
+Licensed MIT
+
+Icon Font for jQuery UI
+Copyright (c) 2015-2017 Michael Keck
+Font version 2.1
+Licensed CC BY-SA 3.0: https://creativecommons.org/licenses/by-sa/3.0/
+Stylesheet version 2.3.2
+Licensed GPL: http://www.gnu.org/licenses/gpl.html
+
+
+TEXT OF GPLv3
+=============
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+
+Text of MIT License:
+====================
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom
+the Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall
+be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+
+
+Text of Unlicense:
+=================
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information, please refer to <http://unlicense.org/>
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..10cc956
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,35 @@
+lint:
+ ./node_modules/.bin/eslint .
+
+updatepsl:
+ scripts/updatepsl.sh
+
+updateseed:
+ scripts/updateseeddata.sh
+
+updategoogle:
+ scripts/updategoogle.sh
+
+todo:
+ grep -rn 'TODO' src
+
+upload:
+ $(eval TMPFILE := $(shell mktemp))
+ scp src/data/yellowlist.txt $$YELLOWLIST_UPLOAD_PATH
+ scripts/generate-legacy-yellowlist.sh > $(TMPFILE) && scp $(TMPFILE) $$YELLOWLIST_LEGACY_UPLOAD_PATH && rm $(TMPFILE)
+ scp src/data/dnt-policies.json $$DNT_POLICIES_UPLOAD_PATH
+
+tx:
+ tx pull -f
+ scripts/fix_placeholders.py
+
+runch:
+ ./node_modules/.bin/web-ext run --target chromium --start-url "chrome://extensions" -s src/
+
+runff:
+ ./node_modules/.bin/web-ext run --start-url "about:debugging#/runtime/this-firefox" -s src/
+
+runfn:
+ ./node_modules/.bin/web-ext run --start-url "about:debugging#/runtime/this-firefox" -s src/ -f nightly
+
+.PHONY: lint updatepsl updateseed updategoogle todo tx runch runff runfn
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..947cedf
--- /dev/null
+++ b/README.md
@@ -0,0 +1,32 @@
+Privacy Badger [![Build Status](https://travis-ci.org/EFForg/privacybadger.svg?branch=master)](https://travis-ci.org/EFForg/privacybadger)
+===================
+Privacy Badger is a browser extension that automatically learns to block invisible trackers. Instead of keeping lists of what to block, Privacy Badger learns by watching which domains appear to be tracking you as you browse the Web.
+
+Privacy Badger sends the [Do Not Track signal](https://www.eff.org/issues/do-not-track) with your browsing. If trackers ignore your wishes, your Badger will learn to block them. Privacy Badger starts blocking once it sees the same tracker on three different websites.
+
+Besides automatic tracker blocking, Privacy Badger removes outgoing link click tracking on [Facebook](https://www.eff.org/deeplinks/2018/05/privacy-badger-rolls-out-new-ways-fight-facebook-tracking) and [Google](https://www.eff.org/deeplinks/2018/10/privacy-badger-now-fights-more-sneaky-google-tracking), with more privacy protections on the way.
+
+To learn more, see [the FAQ on Privacy Badger's homepage](https://privacybadger.org/#faq).
+
+
+## Contributing
+
+We're glad you want to help! Please see [our contributor guide](/CONTRIBUTING.md).
+
+This project is governed by [EFF's Public Projects Code of Conduct](https://www.eff.org/pages/eppcode).
+
+
+## Getting in touch
+
+Besides using [our GitHub issue tracker](https://github.com/EFForg/privacybadger/issues), you could [send us an email](mailto:extension-devs@eff.org), or join the [Privacy Badger mailing list](https://lists.eff.org/mailman/listinfo/privacybadger).
+
+We also hold public meetings using [Jitsi audio conferencing](https://meet.jit.si/PoliteBadgersSingEuphoricly):
+- Mondays at 10:30 AM PST
+- Thursdays at 11:30 AM PST
+
+
+## License
+
+Privacy Badger is licensed under the GPLv3. See [LICENSE](/LICENSE) for more details.
+
+Privacy Badger is a project of the [Electronic Frontier Foundation](https://www.eff.org).
diff --git a/doc/Changelog b/doc/Changelog
new file mode 100644
index 0000000..6e36b14
--- /dev/null
+++ b/doc/Changelog
@@ -0,0 +1,550 @@
+Privacy Badger Release Notes
+============================
+2020.10.7
+* Disabled learning (by default) to address privacy concerns.
+Visit https://www.eff.org/badger-evolution to learn more.
+* Added support for Global Privacy Control, a new specification that
+lets you tell companies you'd like to opt out of data sharing and selling.
+Visit https://globalprivacycontrol.org/ to learn more.
+* Added a new section to the options page to display the browser settings
+that Privacy Badger overrides for privacy reasons
+* Fixed various site breakages
+* Improved translations (Simplified Chinese, Dutch, Finnish, Hebrew, Italian,
+Russian, Spanish, Ukrainian)
+
+2020.8.25
+* Added a button to widget replacements to always allow a widget on a site
+* Improved scrolling of tracking domains on the options page
+* Fixed various site breakages
+* Improved translations (Simplified Chinese, Traditional Chinese, Esperanto,
+Finnish, French, Polish, Brazilian Portuguese, Russian, Spanish, Swedish)
+
+2020.7.21
+* Improved broken site reporting screen in the popup
+* Refreshed the look of options page tabs
+* Fixed various site breakages
+* Improved translations (Simplified Chinese, Danish, European Portuguese,
+Spanish, Turkish)
+
+2020.6.29
+* Added replacement placeholder for Disqus comments widgets
+* Fixed domain sliders on the options page not saving in some cases
+* Fixed slider changes on the options page resetting the list of domains,
+causing you to lose your place if you were scrolled down
+* Fixed domain slider tooltip display
+* Re-enabled custom tooltips in Firefox
+* Fixed various site breakages
+* Improved translations (Esperanto, Hebrew, Ukrainian)
+
+2020.6.2
+* Added replacement placeholders for Facebook Comments/Video and Twitch Player
+* Removed Twitter link unwrapping. We are unable to unwrap t.co links
+on Twitter at this time, as the original URL is no longer present
+in the Twitter website's document structure.
+* Fixed various site breakages
+* Improved translations (Hebrew, Polish, Swedish)
+
+2020.5.12
+* Made buttons in the popup easier to see and click (or tap, on Firefox for
+Android)
+* Added a replacement placeholder widget for Google reCAPTCHA
+* Fixed various site breakages
+* Improved translations (Simplified Chinese, Dutch, Finnish, French, German,
+Hebrew, Italian, Brazilian Portuguese, Spanish, Swedish, Turkish)
+
+2020.2.19
+* Added website breakage warnings, shown in the popup when you block a domain
+known to break websites
+* Removed pixel cookie sharing detection pending security fixes
+* Fixed various site breakages
+* Improved translations (Catalan, Simplified Chinese, Danish, Dutch, German,
+Russian)
+
+2020.1.13
+* Fixed bug that sometimes loses pre-trained data for new users
+* Fixed various site breakages
+
+2020.1.7.1
+* Added helpful text to popup on disabled sites
+* Fixed display issues in popup on smaller displays
+* Fixed Facebook link unwrapping on messenger.com
+* Fixed some cookies getting incorrectly flagged as high entropy
+* Fixed various site breakages
+* Improved translations (Simplified Chinese, Traditional Chinese, French,
+Hebrew, Italian, Korean, Russian, Spanish, Swedish, Ukrainian)
+
+2019.11.18
+* Improved display of domains Privacy Badger hasn't yet learned to block
+* Fixed export/import of the WebRTC protection setting
+* Fixed certain YouTube ("video unavailable"), Vimeo ("Because of its privacy
+settings, this video cannot be played here"), and other video players
+by revising referrer protection for "cookieblocked" domains
+* Fixed various other site breakages
+* Added Korean translations
+* Improved translations (Finnish, French, Hebrew, Swedish)
+
+2019.10.28
+* Refreshed the popup with a higher-contrast look
+* Widget placeholders will no longer be applied for domains on the yellowlist.
+The value of widget placeholders is full blocking (best privacy) combined with
+a clear way to restore potentially useful blocked content (convenience).
+Mixing cookie blocking and placeholders doesn't actually improve privacy or
+convenience but does introduce various bugs.
+* Added a replacement placeholder for YouTube (disabled by default as youtube.com
+is still on the yellowlist for now)
+* Added the Widget Replacement tab to the options page to manage widgets that
+do get blocked and replaced with Privacy Badger placeholders. Visit Widget
+Replacement to selectively disable placeholders. For example, you want social
+buttons out of your life completely.
+* Fixed various site breakages
+* Added Hebrew translations
+* Improved translations (Italian, Russian, Ukrainian)
+
+2019.10.8
+* Fixed image/video thumbnails in Google search results
+* Fixed various other site breakages
+* Removed the green "0" tracker count badge.
+No need to draw attention when there is nothing to show.
+* Improved translations (Simplified Chinese, Ukrainian)
+
+2019.9.23
+* Added helpful text to popup on special browser pages like the New Tab page
+* Fixed pixel cookie sharing detection being broken by First-Party Isolation
+in Firefox
+* Fixed major issues with Service Workers-powered sites like Gmail and Twitter
+* Fixed various other site breakages
+* Improved translations (Simplified Chinese, French, Spanish, Swedish,
+Turkish, Ukrainian)
+
+2019.7.1
+* Added pixel cookie sharing detection. Privacy Badger now records
+tracking by images with querystrings that contain first-party cookie data.
+This catches Google Analytics.
+* Removed display of non-tracking domains from the popup by default.
+Hiding domains that Privacy Badger does not consider to be tracking
+should reduce self-inflicted Web breakage.
+* Enabled Facebook link unwrapping on messenger.com
+* Fixed various site breakages
+* Added Catalan translations
+* Improved translations (Bulgarian, Traditional Chinese, Persian,
+Brazilian Portuguese, European Portuguese, Swedish, Ukrainian)
+
+2019.2.19
+* Improved replacement widgets:
+
+ - Replaced the "play" icon with an "allow once" button to improve
+ accessibility and to make it more clear our widgets are interactive
+ - Made activation also activate any other widgets of the same type
+ - Updated the replacement for Vimeo to ignore background videos
+ - Set minimum dimensions to avoid becoming too small or hidden
+
+* Fixed various site breakages
+
+2019.1.30
+* Added replacement widgets for embedded Spotify, Streamable and Vimeo
+players. Privacy Badger can replace potentially useful third-party widgets
+with placeholders. This avoids on-by-default tracking while providing a clear
+way to restore the original widget on demand.
+* Fixed various site breakages
+* Added Arabic and European Portuguese translations
+* Improved translations (Traditional Chinese, Czech, German, Persian, Swedish,
+Turkish)
+
+2018.12.17
+* Fixed major Privacy Badger breakages in Chrome 72+
+* Fixed various site breakages
+* Improved translations (Simplified Chinese, Spanish, Turkish)
+
+2018.12.5
+* Added a Share button to the popup. This lets you easily copy and paste
+Badger's findings on any page.
+* Updated link protection to work on all Google Search country domains
+* Updated link protection on Facebook to remove the new "fbclid" tracking
+parameter
+* Added support for enterprise/admin/group policy settings overrides. This
+lets administrators preconfigure Privacy Badger installations. For more
+information, please visit
+https://github.com/EFForg/privacybadger/blob/master/doc/admin-deployment.md
+* Fixed various bugs with local storage protection for "cookieblocked" (slider
+set to "yellow") domains
+* Made the options page work better on small and on large displays
+* Fixed various site breakages
+* Improved translations (Simplified Chinese, Dutch, Esperanto, Finnish,
+German, Italian, Persian, Polish, Spanish, Swedish)
+
+2018.10.3.1
+* Fixed style problems with Google Search results
+* Fixed the setting to open results in new browser windows on Google Search
+
+2018.10.3
+* Added protection against outgoing link click tracking on Google Search,
+Google Docs and Google Hangouts
+* Fixed various site breakages
+* Added Finnish translations
+* Improved translations (Simplified Chinese)
+
+2018.9.20
+* Added buttons to back up and restore the disabled sites list using
+Firefox/Google Sync. The new buttons live under the Manage Data tab
+on the options page.
+* Added saving of in-progress error reports so that you no longer lose
+your typing when you close the popup for whatever reason
+* Fixed popup layout problems when opened in the overflow menu in Firefox
+* Updated popup and options to use a higher resolution Badger logo on higher
+pixel density displays
+* Fixed problems with broken fonts and images on Google Docs
+* Improved translations (Traditional Chinese, French, German,
+Brazilian Portuguese, Russian, Spanish, Swedish, Turkish)
+
+2018.8.22
+* Added pre-trained tracker data for new Privacy Badger installations.
+Visit www.eff.org/badger-pretraining to learn more.
+* Added reset/clear tracker data buttons to the Manage Data options page tab
+* Fixed various site breakages
+* Added Persian and Brazilian Portuguese translations
+* Improved translations (Simplified Chinese, Danish, Esperanto, French,
+German, Italian, Norwegian Bokmål, Spanish, Swedish)
+
+2018.8.1
+* Fixed security issues with HTML5 local storage tracking detection as well as
+SoundCloud widget replacement. Thanks again to Cure53 for discovering and
+reporting these vulnerabilities.
+* Improved Facebook link unwrapping; now enabled on the Facebook Onion domain
+* Improved translations (Italian, Norwegian Bokmål, Swedish, Ukrainian)
+
+2018.7.18.1
+* Added setting to disable sending Do Not Track to websites
+* Fixed security issue with link unwrapping on Facebook. Thanks to Cure53 for
+discovering and reporting this vulnerability.
+* Improved ordering of domain names in the popup and on the options page
+* Improved handling of disabled sites with wildcards
+* Added t.co link replacement to user profiles on Twitter
+* Linked to EFF software privacy policy from the new user welcome page
+* Updated to latest dummy Google Tag Manager script from uBlock Origin
+to avoid "failed to redirect a network request" warnings in Chrome
+* Fixed various site breakages
+* Improved translations (Simplified Chinese, Dutch, Esperanto, German,
+Russian, Swedish, Turkish)
+
+2018.5.10
+* Added protection against outgoing link click tracking on Facebook
+* Updated WebRTC protection to revert to browser default (off) when disabled
+* Fixed popup in the Italian locale in Chrome
+* Updated to latest dummy Google Analytics script from uBlock Origin
+to avoid "failed to redirect a network request" warnings in Chrome
+* Fixed various site breakages
+* Improved translations (Traditional Chinese, Danish, Dutch, Esperanto,
+French, German, Italian, Polish, Russian, Swedish, Ukrainian)
+
+2018.4.23
+* Fixed changes not being persisted for domains that appear after scrolling
+the tracking domains list on the options page
+* Improved tracking domains search on the options page
+* Fixed "can't access dead object" errors in Firefox
+* Fixed XML document rendering in Firefox
+* Updated WebRTC protection checkbox to become disabled when the setting is
+controlled by other extensions
+* Fixed various site breakages
+* Improved translations (Traditional Chinese, Czech, Danish, Esperanto,
+French, German, Italian, Polish, Russian, Swedish, Turkish, Ukrainian)
+
+2018.4.10
+* Updated the new user welcome page. The redesigned page is mobile-friendly,
+accessible and already translated into several languages.
+* Fixed Do Not Track being checked sometimes in Private Browsing/Incognito
+windows. By default, Privacy Badger should not record anything in Incognito.
+* Added setting to allow learning in Private Browsing/Incognito windows
+* Fixed unwanted scrolling when switching tabs on the options page
+* Updated replacement icon for Google+
+* Fixed various site breakages
+* Improved translations (Bulgarian, Simplified Chinese, Traditional Chinese,
+Danish, Esperanto, French, German, Italian, Polish, Russian, Spanish,
+Ukrainian)
+
+2018.3.21
+* Fixed Do Not Track not being recognized by sites that test for it by
+checking navigator.doNotTrack with JavaScript
+* Stopped signaling DNT on sites where Privacy Badger is disabled
+* Fixed popup in Private Browsing windows in Firefox
+* Fixed certain kinds of site breakages (such as visual issues with charts)
+not going away even after disabling Privacy Badger on the site
+* Updated to latest dummy Google Tag Manager script from uBlock Origin to
+avoid "failed to redirect a network request" warnings in Chrome
+* Fixed various site breakages
+* Improved translations (Bulgarian, Traditional Chinese, German, Italian,
+Swedish)
+
+2018.2.5
+* Added type/status filters to the tracking domains list on the options page
+* Reworked social widget replacement to avoid WebExtensions fingerprintability
+issue in Firefox
+* New translations (Turkish)
+* Improved translations (Danish, Esperanto, French, German, Polish, Swedish,
+Ukrainian)
+
+2018.1.30
+* Removed the "unlimitedStorage" permission from the manifest
+* Changed the tracker count badge color from red to "Privacy Badger orange"
+
+2018.1.25
+* Added workaround to avoid Privacy Badger getting disabled as "Not from
+Chrome Web Store" in Chrome
+
+2018.1.22
+* Reduced amount of data stored as part of normal operation. Privacy Badger
+will no longer record (or check Do Not Track policies for) non-tracking
+domains. This should enable us to remove the "unlimitedStorage" permission
+with the next Badger update.
+* Improved tracker detection status summaries in popup and options
+* Added explanatory acknowledgement to Tracking Domains options page tab
+* Fixed file download dialog not showing when exporting user data in Firefox
+* Removed tutorial reminder link from popup when already on tutorial page
+* Removed "Requests to the server have been blocked by an extension" messages
+in Chrome and Opera
+* Fixed style issue with replacement social widgets
+* Fixed error reporting on pages where Privacy Badger has been disabled
+* Fixed various site breakages
+* Improved translations (Bulgarian, Danish, Esperanto, French, German,
+Italian, Polish, Russian, Spanish, Swedish, Ukrainian)
+
+2017.11.20
+* Disabled custom tooltips in Firefox to work around browser freezing issues
+* Added validation to the disabled sites form
+* Improved translations (Dutch, Esperanto and German)
+* Added Bulgarian and Polish translations
+
+2017.11.9
+* Fixed various site breakages
+* Improved translations (French, Serbian and Ukrainian)
+* Added Esperanto translation
+
+2017.10.25.1
+* Reverted manifest file change preventing upload to Chrome Web Store
+
+2017.10.25
+* Added Beta support for Firefox for Android
+* Updated popup to close after doing anything that reloads the page
+* Improved handling of long domain names
+* Improved tooltips
+* Restored canvas fingerprinting detection to Firefox
+* Fixed yellowlist updates not getting applied when importing Badger data
+* Updated to latest dummy Google Analytics script from uBlock Origin
+to avoid "failed to redirect a network request" warnings in Chrome
+* Fixed various site breakages
+* Improved translations (Danish, French, German, Italian, Swedish)
+
+2017.9.12.1
+* Fixed build script issue that reintroduced major site breakages on Firefox
+
+2017.9.12
+* Fixed DNT policy checking for blocked domains
+* Fixed exporting large Badger datasets
+* Made progress on Firefox for Android compatibility
+* Fixed various site breakages
+* Improved badge updating performance
+* Improved translations (Czech, Italian, Swedish, Ukrainian)
+* Added Danish translation
+
+2017.7.24
+* Added validation to yellowlist (f.k.a. "cookieblock list") updating
+* Removed faulty yellowlist domain removal logic, which, together with missing
+validation and eff.org serving a maintenance page instead of the actual
+yellowlist, resulted in major breakages all across the Web, something this
+update should prevent from happening ever again
+* Fixed various site breakages
+* Improved translations (Swedish)
+
+2017.6.13.1
+* Added workaround for validation issue preventing upload to Chrome Web Store
+* Fixed chrome.privacy-related exceptions in Firefox 54
+
+2017.6.13
+* Added automatic replacement of t.co shortened tracking URLs with original
+unobfuscated URLs on twitter.com
+* Added option to disable Do Not Track policy checking
+* Restricted DNT policy checking from sending cookies
+* Fixed tooltips for DNT-compliant domains in popup
+* Fixed localStorage tracking sometimes being attributed to unrelated domains
+* Improved translations (Swedish, Ukrainian)
+
+2017.5.9
+* Improved popup rendering
+* Added version number to popup
+* Restricted Do Not Track policy checking from being able to set cookies
+* Fixed several cookie parsing issues
+* Added workaround for Cloudflare security cookies
+* Improved translations (Simplified Chinese, Swedish, Ukrainian)
+
+2017.4.19.1
+* Rework DNT policy rechecking to only happen during browsing. Eliminates
+needless rechecking of unlikely-to-be-visited-again domains. Should further
+mitigate CPU issues.
+* Fix DNT policies to only apply to specific domains they are posted on
+* New translations (Ukrainian)
+* Improved translations (Simplified Chinese, Italian)
+* Fix "trackers" link on popup and options pages
+* Fix broken site (sharepoint.com)
+
+2017.3.28
+* New Translations (Czech)
+* Translation Updates
+* Fix bug in DNT policy re-checking code
+* Rate limit DNT checking to one request per second
+* Fix issue with multiple DNT checks at once for a single domain
+* Fix cookieblock updating issue
+* Fix popup width issue
+* Fix DNT hash updating issue
+* Fix toggle switch issue
+* Automated tests now also run on Firefox
+* Other minor bugfixes and broken site fixes
+
+2017.3.22
+* AMO (Firefox) only release.
+* Fix cookie tracking detection in Firefox.
+
+2017.1.26.1
+* AMO only release
+* Fixes an error in the build scripts which reintroduced a firefox bug for AMO users
+
+2017.1.26
+* Huge speed improvements for settings import and on startup
+* Fixes no content blocking bug (firefox)
+* Several fixes for broken websites
+* Translations fixes
+* New Translation: Nordic
+* New Translation: Traditional Chineese (Taiwan)
+* New Translation: Serbian
+* Bugfix: Crash on browsers without WebRTC
+* Bugfix: narrow poup if icon is in the menu (firefox)
+* Bugfix: Import/Export now uses utf-8 and can handle non english character
+sets
+* Enhancement: Convert icons to SVG
+* Enhancement: Script surrogate for google analytics, gigya, and more...
+* KNOWN ISSUE: Chrome will now display a message "Not downloaded from chrome
+
+2016.12.15.1 (2.0.2)
+* BUGFIX: Chrome browsers no longer display privacy badger as (corrupted)
+* BUGFIX: Fixes lockup issue on some versions of firefox
+* BUGFIX: Fixes issue where privacy badger panel gets cut off
+* BUGFIX: Fixes a non implmeneted API in firefox which was causing numerous
+sites to break.
+* KNOWN ISSUE: Chrome will now display a message "Not downloaded from chrome
+store". This is a known side effect of a workaround for a different bug.
+
+2016.12.8.1 (2.0.1)
+* BUGFIX: Sanitize origin and action in popup
+
+2016.12.8 (2.0)
+* BUGFIX: Fix ublock origin warnings
+* BUGFIX: Remove need for download permission
+
+2016.12.7.2 (2.0RC1)
+* Huge speed improvements
+* Multiprocess Compatible (E10S) for firefox
+* Breaks many fewer websites
+* Many small bugfixes
+* Import and Export your data
+* Block WebRTC from leaking your IP address
+* Forget data in incognito mode
+* block html5 "ping" tracking
+* Translation fixes
+* (Developers) Firefox and Chrome versions now share one code base!
+
+2016.9.7 (1.13)
+* Add exceptions for multi domain first parties
+* Fix google drive download issue
+* Fix wikipedia login issue
+* Fix youtube comments and notifications issues
+* Several other broken site fixes
+* Hopefully a fix for the "corrupted extension" issue
+
+2016.8.29 (1.12)
+* UI Tweaks
+* Remove last adblock plus code
+* Feature: remove domains from list
+* Refactor incognito mode handling
+* Compatibile with firefox web extensions
+
+2016.5.24 (1.11)
+* Fix build error
+
+2016.5.23 (1.10)
+* Fix cookie block list adding bug
+* New migration to fix bug retroactively
+
+2016.5.16 (1.9)
+* Remove Adblock Plus Engine
+* Switch to using storage.js and chrome storage API
+* Massive refactoring of code
+* Huge speed improvements
+* Fixes bug where privacy badger "forgets" settings
+* Fixes first run tab opening on every startup
+* Fix waiting for privacy badger bug
+* Fix high CPU usage bug
+* Uses separate data store for incognito mode
+* Ads selenium test to run pbtest.org sweet
+* Fixes weird subdomain handling edge case
+* Fixes bug where pages stop loading sometimes
+
+2015.4.6 (1.8)
+* Fix "waiting for privacy badger bug"
+* Huge speed improvement
+
+2015.4.6 (1.7)
+* Fix crash when closing options page
+* Add EFF Donate Button
+* New popup to nag user to go through tutorial
+
+2015.3.2 (1.0.6)
+* New feature: Search within blocked domain list
+* Replace soundcloud widget with a click to play button
+* Misc. bug fixes and translation improvements
+
+2015.12.3 (1.0.4)
+* Lots of site bug fixes
+* Chinese Translation
+* Spanish Translation
+* italian translation
+* UI Overhaul
+* Update Swedish locale
+* Typo fixes
+* Numerous bug fixes
+* Added support for disabled sites with wildcards
+* Red badge now reflects the number of domains blocked or cookieblocked
+instead of all third parties.
+* Tooltips show full domain name
+
+2015.8.14 (1.0.1)
+* Fixes a bug where slider settings for a base domain wouldn't take effect
+* Fixes 'this extension is slowing down chrome' errors
+
+2015.8.5 (1.0)
+* 1.0 release
+* Bugfixes from 2015.7.24 (0.99)
+* Detects Canvas Fingerprinting
+* Detect Local Storage Supercookies
+* Improved UI
+* Options page for overriding privacy badger settings
+* Report Broken Site button
+* Many Bugfixes (see github)
+* Translations into swedish, french and german
+
+2015.7.24 (0.99)
+* Release candidate for version 1.0!
+
+2015.4.1
+* Miscellanious bugfixes
+* Improvements to heuristic
+
+2014.9.16
+* Adds lots of tests including selenium tests.
+* Adds lots of domains to the cookie block list.
+* Fixes bug with downloading cookie block list.
+* Fixes other minor stylistic bugs.
+
+2014.7.17
+* Created dialog to allow users to unblock certain third parties on certain
+* sites for addedd functionality. E.g. disqus comments, facebook comments, etc.
+* Added lots of domains to cookie block list.
+* do not show domains that do not appear to be trackers in the popup
+* added missing google+ button override
diff --git a/doc/DESIGN-AND-ROADMAP.md b/doc/DESIGN-AND-ROADMAP.md
new file mode 100644
index 0000000..ca96989
--- /dev/null
+++ b/doc/DESIGN-AND-ROADMAP.md
@@ -0,0 +1,276 @@
+# PRIVACY BADGER DESIGN AND ROADMAP
+
+## DESIGN
+
+### OBJECTIVE
+
+Privacy Badger aims to
+
+ - Protect users against non-consensual tracking by third party domains as they
+ browse the Web.
+
+ - Send and enforce the Do Not Track signal to sites (especially "third party"
+ sites since they are in a position to collect a large fraction of the user's
+ browsing history).
+
+Privacy Badger consists of a primary tracker blocking algorithm, augmented by
+a number of secondary features that extend further privacy protection and
+reduce breakage from the primary mechanism.
+
+### PRIMARY MECHANISM
+
+Privacy Badger:
+
+1. Ensures your browser is sending the DNT: 1 header (in some regulatory
+ environments, it is advisable to note "installing Privacy Badger will enable
+ Do Not Track" on your installation page / app store entry.
+2. Observes which first party origins a given third party origin is setting cookies on
+ (certain cookies are deemed to be "low entropy", as discussed below).
+
+ 2a. Observes which first party origins a given third party is doing certain
+ types of fingerprinting on.
+
+ 2b. Observes which first party origins a given third party is setting certain types
+ of supercookies on.
+
+ 2c. Observes which first party origins a given third party is sending
+ certain parts of first party cookies back to itself using image query
+ strings (pixel cookie sharing).
+
+3. If a third party origin receives a cookie, a supercookie, an image pixel
+ containing first party cookie data, or makes JavaScript fingerprinting API
+ calls on 3 or more first party origins, this is deemed to be "cross site
+ tracking".
+4. Typically, cross site trackers are blocked completely; Privacy Badger
+ prevents the browser from communicating with them. The exception is if the
+ site is on Privacy Badger's "yellow list" (aka the "cookie block list"), in
+ which case resources from the site are loaded, but without access to their
+ (third party) cookies or local storage, and with the referer header either
+ trimmed down to the origin (for GET requests) or removed outright (all other
+ requests). The yellow list is routinely fetched from [an EFF URL](https://www.eff.org/files/cookieblocklist_new.txt)
+ to allow prompt fixes for breakage.
+
+ Until methods for blocking them have been implemented, domains that perform
+ fingerprinting or use third party supercookies should not be added to the
+ yellow list.
+5. Users can also choose custom rules for any given domain flagged by Privacy Badger,
+ overrulling any automatic decision Privacy Badger has made about the domain.
+ Privacy Badger uses three-state sliders (red → block, yellow → cookie block, green → allow) to convey this
+ state in UI. We believe this is less confusing than the UI in many other
+ blocking tools, which often leave the user confused about whether a visual
+ state represents current blocking or the opportunity to block.
+6. Domains can agree to EFF's [Do Not Track policy](https://eff.org/dnt-policy). If a domain does this
+ Privacy Badger will no longer block its traffic or cookies. If a
+ first-party domain posts the policy, this applies to all third parties
+ embedded on that domain.
+ Sites post the policy at [a well-known URL](https://example.com/.well-known/dnt-policy.txt)
+ on their domains. The contents must match those of a file from the list of
+ acceptable policies exactly; the policy file is [maintained on github](https://github.com/EFForg/dnt-policy/),
+ but Privacy Badger fetches a list of known-good hashes periodically [from EFF](https://www.eff.org/files/dnt-policies.json)
+ (version 1.0 of the policy file will be added to that list when Privacy Badger
+ reaches version 1.0)
+
+#### Further Details
+
+# :warning: THIS SECTION IS OUTDATED AND NEEDS TO BE REWRITTEN :warning:
+
+Data Structures:
+
+- action_map = { 'google.com': blocked, 'fonts.google.com': 'cookieblocked', 'apis.fonts.google.com': 'user_cookieblock', 'foo.tracker.net': 'allow', 'tracker.net': 'DNT', }
+- snitch_map = {google.com: array('cooperq.com', 'noah.com', 'eff.org'), tracker.net: array(a.com, b.com, c.com)}
+- dnt_domains = array('tracker.net', 'dnt.eff.org')
+- settings = {social_widgets = true, ...}
+- cookie_block_list = "{'fonts.google.com': true, 'maps.google.com', true}"
+
+
+On Request():
+
+ if privacy badger is not enabled for the tab domain then return
+ if fqdn is not a third party then return
+
+ action = check_action(fqdn) (described below)
+
+ if action is block then cancel request
+ if action is cookie_block then strip headers
+ if fqdn is nontracking (i.e check_action returned nothing) then do nothing
+ if action is noaction or any user override then async_check_tracking
+ if action is allow && count == 2 then blocking_check_tracking
+ if check_tracking changed action then call check_action again
+ else do_nothing
+
+ async_check_dnt(fqdn)
+
+check_action(fqdn): returns action
+
+ related_domains = array()
+ best_action = 'noaction'
+
+ for $domain in range(fqdn ... etld+1)
+ if action_map contains $domain
+ related_domains.shift($domain)
+
+ for each domain in related domains
+ if score(domain.action) > score(best_action)
+ best_action = domain.action
+
+ return best_action
+
+check_tracking(fqdn): return boolean
+
+ var base_domain = etld+1(fqdn)
+
+ if has_cookie or has_supercookie or has_fingerprinting
+ if snitch_map doesn't have base domain add it
+ if snitch_map doesn't have first party add it
+ if snitch_map.base_domain.len >= 3
+ add base domain to action map as blocked
+ add all chlidren of base_domain and self from yellow list to action map
+ return true
+
+##### What is an "origin" for Privacy Badger?
+
+Privacy Badger has two notions of origin. One is the [effective top level
+domain](https://wiki.mozilla.org/Public_Suffix_List) plus one level of
+subdomain (eTLD+1), computed using
+[getBaseDomain](https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIEffectiveTLDService)
+(which is built-in to Firefox; in Chrome we [ship a
+copy](https://github.com/EFForg/privacybadger/blob/8e8ad9838b74b6d13354163f78d362ca60dd44f9/src/lib/basedomain.js#L75).
+The accounting for which origins are trackers or not is performed by looking
+up how many first party fully qualified domain names (FQDNs) have been tracked by each
+of these eTLD + 1 origins. This is a conservative choice, which avoids the
+need to evaluate sets of cookies with different scopes.
+
+When the heuristic determines that the correct response is to block,
+that decision is applied to the third party eTLD+1 from which tracking was seen.
+
+Users are able to override Privacy Badger's decision for any given FQDN if they
+do not wish to block something that is otherwise blocked (or block something
+that is not blocked).
+
+To illustrate this, suppose the site <tt>tracking.co.uk</tt> was embedded on
+every site on the Web, but each embed came from a randomly selected subdomain
+<tt>a.tracking.co.uk</tt>, <tt>b.tracking.co.uk</tt>,
+<tt>c.tracking.co.uk</tt>, etc. Suppose the user visits
+<tt>www.news-example.com</tt> and <tt>search.jobs-example.info</tt>.
+
+The accounting data structure <tt>seenThirdParties</tt> would come to include:
+
+```
+{
+ ...
+ "tracking.co.uk" : {
+ "news-example.com" : true,
+ "jobs-example.info" : true,
+ }
+ ...
+}
+```
+
+Now suppose the user visits a third site, <tt>clickbait.nonprofit.org</tt>,
+and is tracked by <tt>q.tracking.co.uk</tt> on that site. The
+seenThirdParties data structure will have a third entry added to it, meeting
+the threshold of three first party origins and defining
+<tt>tracking.co.uk</tt> as a tracking eTLD+1. At this point
+<tt>tracking.co.uk</tt> will be added to the block list. Any future requests to
+<tt>tracking.co.uk</tt>, or any of its subdomains, will be blocked.
+The user can manually unblock specific subdomains as necessary via the popup menu.
+
+##### What is a "low entropy" cookie?
+
+Our [current cookie heuristic](https://github.com/EFForg/privacybadger/blob/8e8ad9838b74b6d13354163f78d362ca60dd44f9/src/js/heuristicblocking.js#L632) is to assign "number of identifying bits" estimates to
+some known common cookie values, and to bound the sum of these to 12.
+Predetermined low-entropy cookies will not be identified as tracking, nor will
+combinations of them so long as their total estimated entropy is under 12 bits.
+
+### ADDITIONAL MECHANISMS
+
+#### Widget Substitution
+
+Many social media widgets are inherently designed to combine tracking
+and occasionally-useful functionality in a single resource load.
+Privacy Badger aims to give the user access to the functionality when they want
+it, but protection against the tracking at all other times.
+
+To that end, Privacy Badger has incorporated code from the ShareMeNot project
+so that it is able to replace various types of widgets hosted
+by third party origins with local, static equivalents that either replace the
+original widget faithfully, or create a click-through step before the widget
+is loaded and tracks the user.
+
+The widget replacement table lives in the [socialwidgets.json file](https://github.com/EFForg/privacybadger/blob/8e8ad9838b74b6d13354163f78d362ca60dd44f9/src/data/socialwidgets.json).
+Widgets are replaced unless the user has chosen to specifically allow that third party
+domain (by moving the slider to 'green' in the UI), so users can selectively
+disable this functionality if they wish. The code for social media widgets is
+quite diverse, so not all variants (especially custom variants that sites build
+for themselves) are necessarily replaced.
+
+#### What are the states for domain responses?
+
+Currently domains have three states: no action, cookie block, and block. No
+action allows all requests to resolve as normal without intervention from
+Privacy Badger. Cookie block allows for requests to resolve normally but will
+block cookies from being read or created. Cookie block also trims or removes
+the referer header. Block will cause any requests from that origin to be
+blocked entirely; before even a TCP connection can be established. The user can
+toggle these options manually, which will supersede any determinations made
+automatically by Privacy Badger.
+
+#### What does EFFs Do Not Track policy stipulate?
+
+Currently the Do Not Track policy covers where the agreement will be hosted,
+how users who send the DNT header are treated, log retention, how information
+will be shared with other domains, notifications of disclosure, and possible exceptions.
+It can be read in full [here](https://www.eff.org/dnt-policy).
+
+#### How do sites agree to EFFs Do Not Track policy?
+
+Sites can agree to this policy by posting at https://subdomain.example.com/.well-known/dnt-policy.txt,
+where "subdomain" is any domain to which the policy applies, for a given third party.
+
+#### Fingerprinting detection
+Certain aspects of the browser, such as fonts, add-ons or extensions, screen size,
+and seen links, can be used to give the browser a fingerprint that is unique out
+of a very small amount of users (see [Panopticlick](https://panopticlick.eff.org/) for more information).
+
+As of Privacy Badger 1.0, any third party script that writes to an HTML5
+canvas object and then reads a sufficiently large amount back from the third
+party canvas object will be treated the same way as a third party cookie, blocking the
+third party origin if it does this across multiple first party origins. Our
+research has determined that this is a reliable way to distinguish between
+fingerprinting and other third party canvas uses.
+
+This may be augmented by hooks to detect extensive enumeration of properties
+in the <tt>navigator</tt> object in the future.
+
+#### Pixel cookie sharing detection
+
+Detection of first to third party cookie sharing via image pixels was added in [#2088](https://github.com/EFForg/privacybadger/issues/2088).
+
+### ROADMAP
+
+#### High priority issues
+
+Please see our ["high priority"-labeled issues](https://github.com/EFForg/privacybadger/issues?q=is%3Aissue+is%3Aopen+label%3A%22high+priority%22).
+
+## Technical Implementation
+
+### How are origins and the rules for them stored?
+
+When a browser with Privacy Badger enabled makes a request to a third party, if
+the request contains a cookie or the response tries to set a cookie it gets
+flagged as 'tracking'. Origins that make tracking requests get stored in a
+key→value store where the keys are the origins making the request, and the
+values are the first party origins these requests were made on. If that list of
+third parties contains three or more first party origins the third party origin
+gets added to another list of known trackers. When Privacy Badger gets a
+request from an origin on the known trackers list, if it is not on the yellow
+list then Privacy Badger blocks that request. If it is on the yellow list then
+the request is allowed to resolve, but all cookie setting and getting parts of
+it are blocked, while the referer header is trimmed or removed. Both of these
+lists are stored on disk, and persist between browser sessions.
+
+Additionally users can manually set the desired action for any FQDN.
+These get added to their own lists, which are also stored on disk, and get checked
+before Privacy Badger does its default action for a given origin. These are managed
+from the popup window for Privacy Badger on the page as well as the options menu
+for the whole extension.
diff --git a/doc/Translation.md b/doc/Translation.md
new file mode 100644
index 0000000..6292b07
--- /dev/null
+++ b/doc/Translation.md
@@ -0,0 +1,92 @@
+# Translating Privacy Badger
+
+We need your help in translating Privacy Badger to every possible language!
+
+When translating you should always use the source (American English) locale as
+the reference. You can also use existing translations from other languages to
+help you in case of doubt, but you should always consider the English version
+as the correct one.
+
+
+#### A note about adding translation strings in PRs
+
+While working on a Privacy Badger enhancement, you might need to add one or
+more localized strings. You only need to add new strings to the source
+(`en_US`) locale. There is no need to manually add untranslated copies of new
+messages to all other locales. This will be taken care of later by a Privacy
+Badger maintainer.
+
+
+## Working with translations on GitHub
+
+Translations on GitHub are done with JSON files.
+Each language has its own folder inside
+[`src/_locales/`](https://github.com/EFForg/privacybadger/tree/master/src/_locales)
+(e.g. 'es' for Spanish, 'ru' for Russian, etc.).
+Inside each of these folders is a JSON file that contains the translated
+strings for that language. Each entry in the JSON file follows this structure:
+
+ "string_identifier": {
+ "message": "String text"
+ "description": "Some useful info"
+ }
+
+The translated string is the `"String text"` part. You should **NOT** change
+any other part of the entry.
+
+The `"Some useful info"` part sometimes contains useful information (in
+English) about the string. Usually it provides the context of the string: what
+it is ("a section heading") and where it can be found in the UI ("on the new
+user intro page"). You should not translate it.
+
+To contribute on GitHub, first check the status of your local language
+translation: if you don't see a folder with your
+[local language code](https://developer.chrome.com/webstore/i18n?csw=1#localeTable),
+the translation for that language is missing. In this case you should follow
+the instructions below to set up the JSON file for your language. If the
+translation for your language is already there, you can contribute by checking
+its accuracy and by correcting any errors you find (see below for
+instructions).
+
+#### Add a new language
+
+To add a new language on GitHub, follow these steps:
+
+1. Fork this repository
+2. Inside your fork, create a folder in `src/_locales/` and name it
+with your [local language code](https://developer.chrome.com/webstore/i18n?csw=1#localeTable)
+3. Copy the `src/_locales/en_US/messages.json` file to the folder you created
+4. Start translating each message to your language by replacing the
+English strings with the translated ones
+5. When you have completed the translation, [open a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/). Here you can find
+an example translation pull request: [#1270](https://github.com/EFForg/privacybadger/pull/1270).
+
+#### Correct an existing translation
+
+To correct errors in an existing translation:
+
+1. Fork this repository
+2. Open your local language JSON file and apply the changes
+3. When you have completed your work, [open a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/).
+Here you can find an example translation pull request:
+[#1270](https://github.com/EFForg/privacybadger/pull/1270).
+
+
+## Testing your translations
+
+To see your (in-progress) translations in the actual Privacy Badger UI, you should first [load Privacy Badger from source code](/doc/develop.md#install-from-source).
+
+A quick/hacky way to change Privacy Badger's locale is to temporarily copy the locale you want to use to your default (OS) locale's folder in `src/_locales/` and reload Privacy Badger.
+
+The proper way would be to launch the browser in your desired locale.
+
+For Chrome, it might be as easy as [launching it from the command line with `LANGUAGE=fr` (for example) in front of the executable](https://stackoverflow.com/questions/24992240/start-google-chrome-with-a-specific-locale-using-a-command-line-argument).
+
+Firefox requires [downloading a language pack](https://addons.mozilla.org/en-US/firefox/language-tools/) and [setting it as your locale from about:config](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Internationalization#Testing_out_your_extension).
+
+
+## Other information
+
+To learn about outstanding translations-related issues, and to
+see how translations have been handled in the past, take a look
+at issues and pull requests marked with the [translations label](https://github.com/EFForg/privacybadger/issues?utf8=%E2%9C%93&q=label%3Atranslations%20).
diff --git a/doc/admin-deployment.md b/doc/admin-deployment.md
new file mode 100644
index 0000000..41c1d0e
--- /dev/null
+++ b/doc/admin-deployment.md
@@ -0,0 +1,49 @@
+# Privacy Badger enterprise deployment and configuration
+
+Administrators can configure Privacy Badger on managed devices by setting up a policy.
+
+You can find the full list of available settings in [Privacy Badger's managed storage schema](/src/data/schema.json). Please [let us know](https://privacybadger.org/#I-found-a-bug%21-What-do-I-do-now) if you'd like to set something that isn't yet supported.
+
+Note that Privacy Badger currently reads and applies settings from [managed storage](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/storage/managed) on startup. To see your policy take effect on a managed device, first restart that device's browser.
+
+
+## Firefox setup
+
+1. Locate and if necessary create the [managed storage manifests folder](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#Manifest_location). Note that on Windows you need to create a registry key that points to the manifest's location.
+2. Copy the [sample managed storage manifest for Firefox](/doc/jid1-MnnxcxisBPnSXQ@jetpack.json) to this folder.
+
+If your Privacy Badgers were installed from [Privacy Badger's homepage](https://privacybadger.org) (not from [AMO](https://addons.mozilla.org/en-US/firefox/addon/privacy-badger17/)):
+
+3. Rename the manifest to `jid1-MnnxcxisBPnSXQ-eff@jetpack.json`.
+4. Similarly, update the `"name"` property in the manifest to `"jid1-MnnxcxisBPnSXQ-eff@jetpack"`.
+
+
+## Chrome/Chromium setup
+
+Please review the [Configuring Apps and Extensions by Policy](http://www.chromium.org/administrators/configuring-policy-for-extensions) document.
+
+Notes for Chrome OS and Linux follow.
+
+### Chrome OS
+
+The following example JSON policy disables Privacy Badger on `example.com`. This means Privacy Badger will be disabled when you visit any `example.com` page.
+
+```json
+{
+ "disabledSites": {
+ "Value": [
+ "example.com"
+ ]
+ },
+ "showIntroPage": {
+ "Value": false
+ }
+}
+```
+
+### Linux
+
+1. Locate and if necessary create the [managed policies folder for Chrome or Chromium](http://www.chromium.org/administrators/configuring-policy-for-extensions).
+2. Copy the [sample managed storage manifest for Chrome](/doc/sample-managed-storage-manifest-chrome.json) to this folder.
+3. Rename the manifest file to whatever you like (perhaps `privacy-badger-admin-settings.json`).
+4. Update the extension ID inside the manifest if you are not using official Privacy Badger releases from Chrome Web Store.
diff --git a/doc/develop.md b/doc/develop.md
new file mode 100644
index 0000000..cd28b16
--- /dev/null
+++ b/doc/develop.md
@@ -0,0 +1,45 @@
+# Working with Privacy Badger's code
+
+To make changes to Privacy Badger, you have to first load the extension from a source code checkout.
+
+
+## Install from source
+
+To install Privacy Badger from source in Chrome, visit `chrome://extensions`, enable "Developer mode", click "Load unpacked" and select the [`src`](src/) subdirectory inside your copy of the Privacy Badger source code.
+
+In Firefox, visit `about:debugging`, click "Load Temporary Add-on" and select the [`src/manifest.json`](src/manifest.json) file. Note that this only installs the extension temporarily; it will be removed when you close Firefox.
+
+To install Privacy Badger from source in Firefox for Android, please see [Mozilla's guide to developing extensions for Firefox for Android](https://extensionworkshop.com/documentation/develop/developing-extensions-for-firefox-for-android/) and [`web-ext` documentation](https://extensionworkshop.com/documentation/develop/getting-started-with-web-ext/#testing-in-firefox-for-android).
+
+
+## Send a pull request
+
+Before submitting a pull request (PR), please review the sections below.
+
+### Style guide
+
+All JavaScript code going forward should use the following naming conventions:
+
+- Objects and their properties should be Java or camelCase style.
+- Primitive types should be Python or snake_case style.
+- Constants should be ALL_CAPS.
+
+Examples:
+
+```javascript
+const TRACKER_ENTROPY_THRESHOLD = 33;
+
+let tab_id = details.tabId;
+
+window.badger.getTrackerCount(tab_id);
+```
+
+### Catch errors early with static code analysis
+
+First, install the exact expected version of [ESLint](https://eslint.org) by running `npm install` in your Privacy Badger source code checkout directory. You should then be able to produce a lint report by running `make lint` in the same directory.
+
+You can review our set of ESLint rules in [`.eslintrc.yml`](/.eslintrc.yml). Files we want ESLint to ignore are specified in [`.eslintignore`](/.eslintignore).
+
+### Commit messages
+
+Please review the suggestions in this excellent [guide to writing commit messages](https://chris.beams.io/posts/git-commit/).
diff --git a/doc/fixing-broken-sites.md b/doc/fixing-broken-sites.md
new file mode 100644
index 0000000..7a31da9
--- /dev/null
+++ b/doc/fixing-broken-sites.md
@@ -0,0 +1,63 @@
+# How to fix broken site issues
+
+Unfortunately, while working to protect your privacy, Privacy Badger can end up breaking website functionality. Here are the [open "broken site" and "help wanted"-labeled issues](https://github.com/EFForg/privacybadger/issues?utf8=✓&q=is%3Aissue%20is%3Aopen%20label%3A"broken%20site"%20label%3A"help%20wanted"%20).
+
+This document is about the process of classifying and resolving these breakages.
+
+
+## Confirm Privacy Badger is responsible
+
+The first thing to do is to confirm that Privacy Badger blocks (or will eventually learn to block) the domain, and that blocking the domain does indeed break the site.
+
+Browser caching can get in our way here, as cached resources bypass request filtering by extensions. Disable your browser cache when debugging, for example by reloading using <kbd>Ctrl+Shift+R</kbd> every time.
+
+Try disabling Privacy Badger for the site, and then reloading the page. Does that fix the issue? If it doesn't, does disabling the entire Privacy Badger add-on and reloading the page fix the issue? If it still doesn't, Privacy Badger is not at fault.
+
+If disabling Badger and reloading the page fixed the issue, and re-enabling and reloading brought the issue back, let's try to figure out the responsible domain(s). Try allowing half the blocked domains to load. If (after reloading the page) the issue was fixed, pick half of those domains and revert them back to Badger's control. Eventually you should find the exact domain(s) that, when blocked, cause the issue to appear.
+
+
+## Resolve the breakage
+
+Once the issue is confirmed (and the responsible domains have been identified), you should try to find the most appropriate way to resolve it. Privacy Badger comes with several approaches:
+
+| Approach | Label | Original issue | Difficulty | Notes |
+| --- | :---: | :---: | :---: | --- |
+| Multi-domain first parties | [MDFP](https://github.com/EFForg/privacybadger/labels/MDFP) | [#781](https://github.com/EFForg/privacybadger/issues/781) | Easy | Narrowly applicable |
+| Script surrogates | [surrogates](https://github.com/EFForg/privacybadger/labels/surrogates) | [#400](https://github.com/EFForg/privacybadger/issues/400) | Hard | Should use uBlock Origin's surrogates ("neutered scripts") as much as possible |
+| Widget replacement | [widgets](https://github.com/EFForg/privacybadger/labels/widgets) | [#196](https://github.com/EFForg/privacybadger/issues/196), [#1467](https://github.com/EFForg/privacybadger/issues/1467) | Medium | Still needs review/improvements, although some progress being made ([#2262](https://github.com/EFForg/privacybadger/pull/2262)) |
+| EFF's Do Not Track policy | [DNT Policy](https://github.com/EFForg/privacybadger/labels/DNT%20policy)| - | n/a | Narrowly applicable |
+| Yellowlisting | [yellowlist](https://github.com/EFForg/privacybadger/labels/yellowlist)| - | Easy | Only protects against some types of tracking |
+
+The question to ask is, which way addresses the issue most specifically, resolving the breakage while increasing privacy exposure by the smallest amount? If you are not sure, that's OK! Opening a new issue (or chiming in on an existing issue) to ask for help is fine.
+
+Let's look at some common kinds of breakages and see how they relate to the approaches above.
+
+
+### Domains that are part of the site but don't look like it
+
+Does the blocked domain actually belong to the site, but Privacy Badger doesn't know that and so treats the domain as an external tracker? Sounds like a job for [multi-domain first parties](https://github.com/EFForg/privacybadger/issues/781) (MDFP).
+
+When adding domains to the MDFP list, please add base ([eTLD](https://en.wikipedia.org/wiki/Public_Suffix_List)+1) domains only. For example, there is no need to add `api.example.net` when adding `example.com` and `example.net`.
+
+For past examples, you could browse [the list of merged pull requests with the "MDFP" label](https://github.com/EFForg/privacybadger/issues?q=label%3AMDFP+is%3Amerged).
+
+
+### JavaScript errors
+
+Does blocking the domain block a JavaScript analytics library that the site tries to use and fails, breaking site navigation? This could be resolved by [script surrogates](https://github.com/EFForg/privacybadger/issues/400).
+
+
+### External services
+
+Is the missing comments section powered by a commenting service that Privacy Badger learned to block? Perhaps a new [widget replacement](https://github.com/EFForg/privacybadger/pull/196) should be added.
+
+We should also ask the service to to adopt the [EFF Do Not Track policy](https://www.eff.org/dnt-policy), which is a way for privacy-conscious companies to receive recognition for their good practices. If their service can and will abide by the policy's requirements, posting the policy on the service's domains will tell Privacy Badger to allow loading of resources from those domains.
+
+
+### External domains too complex to surrogate or replace with placeholders
+
+If nothing else seems to fit, adding the affected domain to the "[yellowlist](/doc/yellowlist-criteria.md)" will make Privacy Badger set the domain to "yellow" ("cookie-blocked") instead of "red" (blocked) after seeing it track on three or more sites.
+
+Resources from yellowlisted domains are requested without referrer headers, and are restricted from reading or writing cookies or localStorage.
+
+[Here is an example yellowlist pull request](https://github.com/EFForg/privacybadger/pull/1543) that shows what's good to know when deciding how to fix a breakage, and how to get that information.
diff --git a/doc/jid1-MnnxcxisBPnSXQ@jetpack.json b/doc/jid1-MnnxcxisBPnSXQ@jetpack.json
new file mode 100644
index 0000000..b9242ca
--- /dev/null
+++ b/doc/jid1-MnnxcxisBPnSXQ@jetpack.json
@@ -0,0 +1,11 @@
+{
+ "name": "jid1-MnnxcxisBPnSXQ@jetpack",
+ "description": "This is a sample Firefox managed storage manifest.",
+ "type": "storage",
+ "data": {
+ "showIntroPage": false,
+ "disabledSites": [
+ "example.com"
+ ]
+ }
+}
diff --git a/doc/permissions.md b/doc/permissions.md
new file mode 100644
index 0000000..1211b2a
--- /dev/null
+++ b/doc/permissions.md
@@ -0,0 +1,27 @@
+# Permissions
+
+This document explains the need for each [extension permission](https://developer.chrome.com/extensions/declare_permissions) declared in Privacy Badger's [extension manifest](/src/manifest.json).
+
+## Privacy
+The Privacy API lets extensions modify browser-wide privacy settings. Privacy Badger uses it to disable a setting that lets Chrome send third-party requests to resolve errors, and to turns off link tracking via the HTML ping attribute. We also give users the option to change their WebRTC privacy level in order to prevent leaking local network address information.
+
+## Cookies
+Privacy Badger needs access to the cookies API in order to detect and correct a common error where Cloudflare domains are identified as trackers and blocked.
+
+## Storage
+The storage API lets extensions store information that persists after the browser is closed. Privacy Badger uses it to save user settings and information it has learned about trackers.
+
+## WebRequest
+The WebRequest API allows extensions to observe all incoming and outgoing network requests made by the browser. Privacy Badger inspects request for tracking behavior, and logs the destinations of outgoing requests that are flagged as tracking. No information is ever shared outside of the browser.
+
+## WebRequestBlocking
+The blocking version of the WebRequest API allows extensions to modify or block network requests before they leave the browser. Privacy Badger uses this API to synchronously view, modify, and block requests to trackers. For example, Privacy Badger modifies requests made to domains on the yellowlist to remove the referer header and cookies.
+
+## WebNavigation
+This API allows extensions to detect when the user navigates from one web page to another. Privacy Badger needs this in order to correctly determine whether each request is a first-party request (to the same domain as the web page) or a third-party request (to somewhere else). This permission allows it to avoid misattributing trackers on special pages such as Service Worker pages.
+
+## http://\*/\* and https://\*/\*
+These permissions allow Privacy Badger to use the WebRequest and WebRequestBlocking permissions on requests to all websites. As described above, Privacy Badger uses these APIs to analyze requests and detect tracking, then modify or block requests to known trackers. No information is ever shared outside of the browser.
+
+## Tabs
+Privacy Badger needs access to the tabs API so that the extension can detect which tab is active and which tabs are simply present in the background. The extension icon, badge and popup update to reflect the state of Privacy Badger. This often requires knowing the tab's URL. For example, updating the icon requires the URL in order to determine whether Privacy Badger should be shown as disabled on that tab. Privacy Badger also uses the tabs API for miscellaneous tasks such as opening or switching to the already open new user welcome page.
diff --git a/doc/sample-managed-storage-manifest-chrome.json b/doc/sample-managed-storage-manifest-chrome.json
new file mode 100644
index 0000000..194bd02
--- /dev/null
+++ b/doc/sample-managed-storage-manifest-chrome.json
@@ -0,0 +1,12 @@
+{
+ "3rdparty": {
+ "extensions": {
+ "pkehgijcmpdhfbdbbnkijodmdjhbjlgp": {
+ "showIntroPage": false,
+ "disabledSites": [
+ "example.com"
+ ]
+ }
+ }
+ }
+}
diff --git a/doc/tests.md b/doc/tests.md
new file mode 100644
index 0000000..b03c4a3
--- /dev/null
+++ b/doc/tests.md
@@ -0,0 +1,92 @@
+# Working with Privacy Badger's tests
+
+We have a few different types of tests:
+
+* We use [unit tests](/doc/tests.md#unit-tests) for confirming that smaller pieces of code behave as expected.
+* [Functional tests](/doc/tests.md#functional-tests) test the UI and that things integrate together properly.
+* [Travis CI](/doc/tests.md#travis-ci) runs all these automatically for every pull request on both Chrome and Firefox.
+
+## Travis CI
+
+Every pull request runs the full suite of functional and unit tests on [Travis CI](https://travis-ci.org/). We test on latest stable Chrome and Firefox releases, as well as on Chrome Beta, Firefox Beta and Firefox ESR.
+
+See [`.travis.yml`](/.travis.yml) for Travis configuration, [`scripts/setup_travis.sh`](/scripts/setup_travis.sh) for test setup, and [`scripts/run_travis.sh`](/scripts/run_travis.sh) for test execution procedures.
+
+We use [ESLint](https://eslint.org) to flag potential JavaScript errors and style issues. Please see our [developer guide](/doc/develop.md#lint-your-changes) for setup instructions.
+
+## Unit tests
+
+We use [QUnit](https://qunitjs.com/) for unit tests.
+Unit tests are defined in [`/src/tests/tests`](/src/tests/tests). Unit test dependencies live in [`/src/tests/lib`](/src/tests/lib).
+
+To run unit tests, first [load Privacy Badger from source code](/doc/develop.md#install-from-source) (as we don't ship unit tests with published versions).
+Once you loaded Badger from source, click on its button in your browser toolbar to open Badger's popup.
+Then in the popup, click on the gear icon (⚙) to open the options page.
+Your browser should navigate to an internal URL that starts with `chrome-extension://` or `moz-extension://` and ends with `/skin/options.html`.
+Replace `/skin/options.html` with `/tests/index.html` and hit <kbd>Enter</kbd>.
+This will open the unit test suite and run the tests.
+
+### Writing unit tests
+
+When writing unit tests, try to scope each test to the function or method in question, then each individual assertion within that test addressing a core piece of functionality or expectation of that test. Consider testing expected input, potential breaking points, and expected outputs. It's easy to get caught going down rabbit holes testing unlikely scenarios, so consider which edge cases are most important to consider, and which are more likely to occur.
+
+Do verify that removing or mutating the code being tested produces failed assertions.
+
+## Functional tests
+
+Our [functional tests](/tests/selenium/) are written in Python and driven by [Selenium](https://selenium-python.readthedocs.io/) and [pytest](https://docs.pytest.org/en/latest/).
+
+To run them in Chrome, you need to [install `chromedriver`](http://chromedriver.chromium.org/getting-started). In Firefox, you need to [install `geckodriver`](https://github.com/EFForg/privacybadger/blob/1550b9efb64c1d5e276361e3940f402c3ec87afc/scripts/setup_travis.sh#L21-L50).
+
+You also need to [install the Python packages](https://snarky.ca/a-quick-and-dirty-guide-on-how-to-install-packages-for-python/) specified in [`/tests/requirements.txt`](/tests/requirements.txt).
+
+You should now be able to run the Selenium tests. Try them out by running
+the code below. This should take several minutes.
+```bash
+$ BROWSER=chrome pytest -v tests/
+```
+
+macOS users may need to provide the full path to the browser application folder. For example, to run tests on macOS:
+```bash
+$ BROWSER=/Applications/Firefox.app/Contents/MacOS/firefox-bin pytest -v tests/
+# or
+$ BROWSER=/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome pytest -v tests/
+```
+
+For more information, see our Travis CI [setup](/scripts/setup_travis.sh) and
+[run](/scripts/run_travis.sh) scripts.
+
+
+### Invocation examples
+
+Note that to use a debugger like `pdb` or `ipdb` you must pass the `-s` (`--capture=no`) flag to pytest.
+```bash
+# run qunit_test.py, with Firefox, with verbose output (-v)
+$ BROWSER=/usr/bin/firefox pytest -v tests/selenium/qunit_test.py tests/
+
+# run a specific test on a specific class in a specific module with Chrome Beta
+$ BROWSER=google-chrome-beta pytest tests/selenium/super_cookie_test.py::SupercookieTest::test_should_detect_ls_of_third_party_frame
+
+# run any tests whose name (including the module and class) matches the string cookie_test
+# this is often useful as a less verbose way to run a single test
+$ BROWSER=firefox pytest -k cookie_test tests/
+```
+
+More pytest invocations can be found [here](https://docs.pytest.org/en/latest/usage.html).
+
+If you are on Linux, you can also run the tests headlessly (without displaying a GUI).
+Install `Xvfb` with your system package manager, then set the `ENABLE_XVFB=1` environment variable:
+
+```bash
+$ BROWSER=firefox ENABLE_XVFB=1 pytest -s -v -k PopupTest tests/
+```
+
+### Writing functional tests
+
+Test methods that you want to be discovered and run by `pytest` must be prefixed with the keyword `test`. For example: `test_pixel_tracking_detection`. A similar rule applies to naming any new test class files that you want to be detected by the testing suite: the `test` keyword must be appended to the end of the title. For example: `pixel_test.py`.
+
+When testing Badger's tracker detection/learning, you should first clear the pre-trained/seed tracker data. For example (run on Badger's options page): `self.js("chrome.extension.getBackgroundPage().badger.storage.clearTrackerData();")`. Clearing seed data ensures that the tracking domain was discovered just now and not from seed data.
+
+You should also set up your tracking detection test in a way where your test fixture has a "no tracking" mode that you visit first and assert that no tracking was detected. This is to ensure that when we detect the tracking being tested we didn't actually detect some other kind of tracking instead.
+
+Just as with unit tests, please verify that removing or mutating the code being tested produces failed assertions.
diff --git a/doc/yellowlist-criteria.md b/doc/yellowlist-criteria.md
new file mode 100644
index 0000000..c209328
--- /dev/null
+++ b/doc/yellowlist-criteria.md
@@ -0,0 +1,8 @@
+EFF maintains a Privacy Badger "yellowlist" of domains for which requests are allowed but Privacy Badger restricts access or availability of objectionable cookies and potentially other objectionable identifiers.
+
+Our objective in curating that list is to maximize user privacy while minimizing disruption to functionality that users expect from sites. The criteria we examine when considering possible yellowlist entries include (but are not limited to):
+
+* Was this in [Bau and Mayer's](https://jonathanmayer.org/papers_data/bau13.pdf) manually curated non-tracker list?
+* Is this domain necessary for functionality the user expects from 1st party pages?
+* Is the domain's privacy policy clear that it does not perform non-consensual tracking?
+* Is there a reasonable self-hosted surrogate available that could replace the functionality of this domain (e.g. https://github.com/EFForg/privacybadgerchrome/issues/400).
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..deba7a3
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,7063 @@
+{
+ "name": "privacy-badger-dev-tools",
+ "version": "0.0.1",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@babel/code-frame": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
+ "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
+ "requires": {
+ "@babel/highlight": "^7.0.0"
+ }
+ },
+ "@babel/highlight": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
+ "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
+ "requires": {
+ "chalk": "^2.0.0",
+ "esutils": "^2.0.2",
+ "js-tokens": "^4.0.0"
+ },
+ "dependencies": {
+ "js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ }
+ }
+ },
+ "@babel/polyfill": {
+ "version": "7.11.5",
+ "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.11.5.tgz",
+ "integrity": "sha512-FunXnE0Sgpd61pKSj2OSOs1D44rKTD3pGOfGilZ6LGrrIH0QEtJlTjqOqdF8Bs98JmjfGhni2BBkTfv9KcKJ9g==",
+ "dev": true,
+ "requires": {
+ "core-js": "^2.6.5",
+ "regenerator-runtime": "^0.13.4"
+ }
+ },
+ "@babel/runtime": {
+ "version": "7.11.2",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz",
+ "integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==",
+ "dev": true,
+ "requires": {
+ "regenerator-runtime": "^0.13.4"
+ }
+ },
+ "@cliqz-oss/firefox-client": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/@cliqz-oss/firefox-client/-/firefox-client-0.3.1.tgz",
+ "integrity": "sha512-RO+Tops/wGnBzWoZYkCraqyh2JqOejqJq5/a4b54HhmjTNSKdUPwAOK17EGg/zPb0nWqkuB7QyZsI9bo+ev8Kw==",
+ "dev": true,
+ "requires": {
+ "colors": "0.5.x",
+ "js-select": "~0.6.0"
+ }
+ },
+ "@cliqz-oss/node-firefox-connect": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@cliqz-oss/node-firefox-connect/-/node-firefox-connect-1.2.1.tgz",
+ "integrity": "sha512-O/IyiB5pfztCdmxQZg0/xeq5w+YiP3gtJz8d4We2EpLPKzbDVjOrtfLKYgVfm6Ya6mbvDge1uLkSRwaoVCWKnA==",
+ "dev": true,
+ "requires": {
+ "@cliqz-oss/firefox-client": "0.3.1",
+ "es6-promise": "^2.0.1"
+ }
+ },
+ "@devicefarmer/adbkit": {
+ "version": "2.11.3",
+ "resolved": "https://registry.npmjs.org/@devicefarmer/adbkit/-/adbkit-2.11.3.tgz",
+ "integrity": "sha512-rsgWREAvSRQjdP9/3GoAV6Tq+o97haywgbTfCgt5yUqiDpaaq3hlH9FTo9XsdG8x+Jd0VQ9nTC2IXsDu8JGRSA==",
+ "dev": true,
+ "requires": {
+ "@devicefarmer/adbkit-logcat": "^1.1.0",
+ "@devicefarmer/adbkit-monkey": "~1.0.1",
+ "bluebird": "~2.9.24",
+ "commander": "^2.3.0",
+ "debug": "~2.6.3",
+ "node-forge": "^0.10.0",
+ "split": "~0.3.3"
+ }
+ },
+ "@devicefarmer/adbkit-logcat": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@devicefarmer/adbkit-logcat/-/adbkit-logcat-1.1.0.tgz",
+ "integrity": "sha512-K90P5gUXM/w+yzLvJIRQ+tJooNU6ipUPPQkljtPJ0laR66TGtpt4Gqsjm0n9dPHK1W5KGgU1R5wnCd6RTSlPNA==",
+ "dev": true
+ },
+ "@devicefarmer/adbkit-monkey": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@devicefarmer/adbkit-monkey/-/adbkit-monkey-1.0.1.tgz",
+ "integrity": "sha512-HilPrVrCosYWqSyjfpDtaaN1kJwdlBpS+IAflP3z+e7nsEgk3JGJf1Vg0NgHJooTf5HDfXSyZqMVg+5jvXCK0g==",
+ "dev": true,
+ "requires": {
+ "async": "~0.2.9"
+ }
+ },
+ "@eslint/eslintrc": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz",
+ "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.12.4",
+ "debug": "^4.1.1",
+ "espree": "^7.3.0",
+ "globals": "^12.1.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^3.13.1",
+ "lodash": "^4.17.19",
+ "minimatch": "^3.0.4",
+ "strip-json-comments": "^3.1.1"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
+ "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true
+ }
+ }
+ },
+ "@sindresorhus/is": {
+ "version": "0.14.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
+ "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==",
+ "dev": true
+ },
+ "@szmarczak/http-timer": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz",
+ "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==",
+ "dev": true,
+ "requires": {
+ "defer-to-connect": "^1.0.1"
+ }
+ },
+ "@types/minimatch": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
+ "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
+ "dev": true
+ },
+ "@types/node": {
+ "version": "14.11.2",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.2.tgz",
+ "integrity": "sha512-jiE3QIxJ8JLNcb1Ps6rDbysDhN4xa8DJJvuC9prr6w+1tIh+QAbYyNF3tyiZNLDBIuBCf4KEcV2UvQm/V60xfA==",
+ "dev": true
+ },
+ "JSONSelect": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/JSONSelect/-/JSONSelect-0.2.1.tgz",
+ "integrity": "sha1-QVQYpSbTP+MddLTe+jyDbUhewgM=",
+ "dev": true
+ },
+ "acorn": {
+ "version": "7.4.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
+ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+ "dev": true
+ },
+ "acorn-jsx": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
+ "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
+ "dev": true
+ },
+ "addons-linter": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/addons-linter/-/addons-linter-2.7.0.tgz",
+ "integrity": "sha512-kH+0fAKSc461PnCyYQ0/SeKcxEQ2zxCZwG2GB6xjvfkMiMAwwic87VP62Cffc8H/zHEfYuT8uFmy42ayH5mqEQ==",
+ "dev": true,
+ "requires": {
+ "@babel/runtime": "7.11.2",
+ "ajv": "6.12.5",
+ "ajv-merge-patch": "4.1.0",
+ "chalk": "4.1.0",
+ "cheerio": "1.0.0-rc.3",
+ "columnify": "1.5.4",
+ "common-tags": "1.8.0",
+ "deepmerge": "4.2.2",
+ "dispensary": "0.57.0",
+ "es6-promisify": "6.1.1",
+ "eslint": "7.9.0",
+ "eslint-plugin-no-unsanitized": "3.1.2",
+ "eslint-visitor-keys": "2.0.0",
+ "espree": "7.3.0",
+ "esprima": "4.0.1",
+ "first-chunk-stream": "4.0.0",
+ "fluent-syntax": "0.13.0",
+ "fsevents": "2.1.3",
+ "glob": "7.1.6",
+ "is-mergeable-object": "1.1.1",
+ "jed": "1.1.1",
+ "mdn-browser-compat-data": "1.0.39",
+ "os-locale": "5.0.0",
+ "pino": "6.6.1",
+ "postcss": "7.0.35",
+ "probe-image-size": "5.0.0",
+ "relaxed-json": "1.0.3",
+ "semver": "7.3.2",
+ "source-map-support": "0.5.19",
+ "strip-bom-stream": "4.0.0",
+ "tosource": "1.0.0",
+ "upath": "1.2.0",
+ "whatwg-url": "8.2.2",
+ "yargs": "15.4.1",
+ "yauzl": "2.10.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "chalk": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "debug": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
+ "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
+ "emoji-regex": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+ "dev": true
+ },
+ "eslint": {
+ "version": "7.9.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.9.0.tgz",
+ "integrity": "sha512-V6QyhX21+uXp4T+3nrNfI3hQNBDa/P8ga7LoQOenwrlEFXrEnUEE+ok1dMtaS3b6rmLXhT1TkTIsG75HMLbknA==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "@eslint/eslintrc": "^0.1.3",
+ "ajv": "^6.10.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.0.1",
+ "doctrine": "^3.0.0",
+ "enquirer": "^2.3.5",
+ "eslint-scope": "^5.1.0",
+ "eslint-utils": "^2.1.0",
+ "eslint-visitor-keys": "^1.3.0",
+ "espree": "^7.3.0",
+ "esquery": "^1.2.0",
+ "esutils": "^2.0.2",
+ "file-entry-cache": "^5.0.1",
+ "functional-red-black-tree": "^1.0.1",
+ "glob-parent": "^5.0.0",
+ "globals": "^12.1.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "js-yaml": "^3.13.1",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash": "^4.17.19",
+ "minimatch": "^3.0.4",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.1",
+ "progress": "^2.0.0",
+ "regexpp": "^3.1.0",
+ "semver": "^7.2.1",
+ "strip-ansi": "^6.0.0",
+ "strip-json-comments": "^3.1.0",
+ "table": "^5.2.3",
+ "text-table": "^0.2.0",
+ "v8-compile-cache": "^2.0.3"
+ },
+ "dependencies": {
+ "eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+ "dev": true
+ }
+ }
+ },
+ "eslint-scope": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "eslint-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
+ "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
+ "dev": true,
+ "requires": {
+ "eslint-visitor-keys": "^1.1.0"
+ },
+ "dependencies": {
+ "eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+ "dev": true
+ }
+ }
+ },
+ "eslint-visitor-keys": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz",
+ "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==",
+ "dev": true
+ },
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true
+ },
+ "esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^5.2.0"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "dev": true
+ }
+ }
+ },
+ "file-entry-cache": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
+ "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==",
+ "dev": true,
+ "requires": {
+ "flat-cache": "^2.0.1"
+ }
+ },
+ "flat-cache": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
+ "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==",
+ "dev": true,
+ "requires": {
+ "flatted": "^2.0.0",
+ "rimraf": "2.6.3",
+ "write": "1.0.3"
+ }
+ },
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "optionator": {
+ "version": "0.9.1",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+ "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+ "dev": true,
+ "requires": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.3"
+ }
+ },
+ "prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true
+ },
+ "rimraf": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+ "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ }
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ },
+ "strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true
+ },
+ "table": {
+ "version": "5.4.6",
+ "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz",
+ "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.10.2",
+ "lodash": "^4.17.14",
+ "slice-ansi": "^2.1.0",
+ "string-width": "^3.0.0"
+ }
+ },
+ "type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "requires": {
+ "prelude-ls": "^1.2.1"
+ }
+ },
+ "write": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz",
+ "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==",
+ "dev": true,
+ "requires": {
+ "mkdirp": "^0.5.1"
+ }
+ }
+ }
+ },
+ "adm-zip": {
+ "version": "0.4.16",
+ "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz",
+ "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==",
+ "dev": true
+ },
+ "ajv": {
+ "version": "6.12.5",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz",
+ "integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "ajv-merge-patch": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ajv-merge-patch/-/ajv-merge-patch-4.1.0.tgz",
+ "integrity": "sha512-0mAYXMSauA8RZ7r+B4+EAOYcZEcO9OK5EiQCR7W7Cv4E44pJj56ZnkKLJ9/PAcOc0dT+LlV9fdDcq2TxVJfOYw==",
+ "dev": true,
+ "requires": {
+ "fast-json-patch": "^2.0.6",
+ "json-merge-patch": "^0.2.3"
+ }
+ },
+ "ansi-align": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz",
+ "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==",
+ "dev": true,
+ "requires": {
+ "string-width": "^3.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
+ "dev": true
+ },
+ "emoji-regex": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ }
+ }
+ },
+ "ansi-colors": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+ "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
+ "dev": true
+ },
+ "ansi-escapes": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz",
+ "integrity": "sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ=="
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^2.0.1"
+ },
+ "dependencies": {
+ "color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "requires": {
+ "color-name": "~1.1.4"
+ }
+ },
+ "color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ }
+ }
+ },
+ "any-promise": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+ "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=",
+ "dev": true
+ },
+ "anymatch": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
+ "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ }
+ },
+ "archiver": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.0.2.tgz",
+ "integrity": "sha512-Tq3yV/T4wxBsD2Wign8W9VQKhaUxzzRmjEiSoOK0SLqPgDP/N1TKdYyBeIEu56T4I9iO4fKTTR0mN9NWkBA0sg==",
+ "dev": true,
+ "requires": {
+ "archiver-utils": "^2.1.0",
+ "async": "^3.2.0",
+ "buffer-crc32": "^0.2.1",
+ "readable-stream": "^3.6.0",
+ "readdir-glob": "^1.0.0",
+ "tar-stream": "^2.1.4",
+ "zip-stream": "^4.0.0"
+ },
+ "dependencies": {
+ "async": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz",
+ "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==",
+ "dev": true
+ }
+ }
+ },
+ "archiver-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz",
+ "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.4",
+ "graceful-fs": "^4.2.0",
+ "lazystream": "^1.0.0",
+ "lodash.defaults": "^4.2.0",
+ "lodash.difference": "^4.5.0",
+ "lodash.flatten": "^4.4.0",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.union": "^4.6.0",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^2.0.0"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "graceful-fs": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+ "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+ "dev": true
+ },
+ "readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "argparse": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz",
+ "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=",
+ "requires": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
+ "dev": true,
+ "optional": true
+ },
+ "arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+ "dev": true,
+ "optional": true
+ },
+ "arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
+ "dev": true,
+ "optional": true
+ },
+ "array-differ": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz",
+ "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==",
+ "dev": true
+ },
+ "array-filter": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz",
+ "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=",
+ "dev": true
+ },
+ "array-map": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz",
+ "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=",
+ "dev": true
+ },
+ "array-reduce": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz",
+ "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=",
+ "dev": true
+ },
+ "array-union": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+ "requires": {
+ "array-uniq": "^1.0.1"
+ }
+ },
+ "array-uniq": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY="
+ },
+ "array-unique": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
+ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
+ "dev": true,
+ "optional": true
+ },
+ "arrify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0="
+ },
+ "asn1": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+ "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+ "dev": true,
+ "requires": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "assert-plus": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+ "dev": true
+ },
+ "assign-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+ "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
+ "dev": true,
+ "optional": true
+ },
+ "astral-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
+ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg=="
+ },
+ "async": {
+ "version": "0.2.10",
+ "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
+ "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=",
+ "dev": true
+ },
+ "async-each": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
+ "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
+ "dev": true,
+ "optional": true
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+ "dev": true
+ },
+ "at-least-node": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
+ "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
+ "dev": true
+ },
+ "atob": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+ "dev": true,
+ "optional": true
+ },
+ "atomic-sleep": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
+ "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==",
+ "dev": true
+ },
+ "aws-sign2": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+ "dev": true
+ },
+ "aws4": {
+ "version": "1.10.1",
+ "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz",
+ "integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==",
+ "dev": true
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+ },
+ "base": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
+ "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "cache-base": "^1.0.1",
+ "class-utils": "^0.3.5",
+ "component-emitter": "^1.2.1",
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.1",
+ "mixin-deep": "^1.2.0",
+ "pascalcase": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "base64-js": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
+ "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==",
+ "dev": true
+ },
+ "bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+ "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+ "dev": true,
+ "requires": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "binary-extensions": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
+ "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
+ "dev": true,
+ "optional": true
+ },
+ "bl": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.3.tgz",
+ "integrity": "sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg==",
+ "dev": true,
+ "requires": {
+ "buffer": "^5.5.0",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ },
+ "dependencies": {
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ }
+ }
+ },
+ "bluebird": {
+ "version": "2.9.34",
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.9.34.tgz",
+ "integrity": "sha1-L3tOyAIWMoqf3evfacjUlC/v99g=",
+ "dev": true
+ },
+ "boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
+ "dev": true
+ },
+ "boxen": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz",
+ "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==",
+ "dev": true,
+ "requires": {
+ "ansi-align": "^3.0.0",
+ "camelcase": "^5.3.1",
+ "chalk": "^3.0.0",
+ "cli-boxes": "^2.2.0",
+ "string-width": "^4.1.0",
+ "term-size": "^2.1.0",
+ "type-fest": "^0.8.1",
+ "widest-line": "^3.1.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true
+ },
+ "chalk": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+ "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ }
+ }
+ },
+ "brace-expansion": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
+ "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "braces": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "fill-range": "^7.0.1"
+ }
+ },
+ "buffer": {
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz",
+ "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==",
+ "dev": true,
+ "requires": {
+ "base64-js": "^1.0.2",
+ "ieee754": "^1.1.4"
+ }
+ },
+ "buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=",
+ "dev": true
+ },
+ "buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=",
+ "dev": true
+ },
+ "buffer-from": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+ "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+ "dev": true
+ },
+ "bunyan": {
+ "version": "1.8.14",
+ "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.14.tgz",
+ "integrity": "sha512-LlahJUxXzZLuw/hetUQJmRgZ1LF6+cr5TPpRj6jf327AsiIq2jhYEH4oqUUkVKTor+9w2BT3oxVwhzE5lw9tcg==",
+ "dev": true,
+ "requires": {
+ "dtrace-provider": "~0.8",
+ "moment": "^2.19.3",
+ "mv": "~2",
+ "safe-json-stringify": "~1"
+ }
+ },
+ "cache-base": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
+ "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "collection-visit": "^1.0.0",
+ "component-emitter": "^1.2.1",
+ "get-value": "^2.0.6",
+ "has-value": "^1.0.0",
+ "isobject": "^3.0.1",
+ "set-value": "^2.0.0",
+ "to-object-path": "^0.3.0",
+ "union-value": "^1.0.0",
+ "unset-value": "^1.0.0"
+ }
+ },
+ "cacheable-request": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz",
+ "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==",
+ "dev": true,
+ "requires": {
+ "clone-response": "^1.0.2",
+ "get-stream": "^5.1.0",
+ "http-cache-semantics": "^4.0.0",
+ "keyv": "^3.0.0",
+ "lowercase-keys": "^2.0.0",
+ "normalize-url": "^4.1.0",
+ "responselike": "^1.0.2"
+ },
+ "dependencies": {
+ "lowercase-keys": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
+ "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==",
+ "dev": true
+ }
+ }
+ },
+ "caller-path": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
+ "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
+ "requires": {
+ "callsites": "^0.2.0"
+ }
+ },
+ "callsites": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
+ "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo="
+ },
+ "camelcase": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.0.0.tgz",
+ "integrity": "sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w==",
+ "dev": true
+ },
+ "caseless": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+ "dev": true
+ },
+ "chalk": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz",
+ "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==",
+ "requires": {
+ "ansi-styles": "^3.1.0",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^4.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz",
+ "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==",
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "supports-color": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz",
+ "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=",
+ "requires": {
+ "has-flag": "^2.0.0"
+ }
+ }
+ }
+ },
+ "cheerio": {
+ "version": "1.0.0-rc.3",
+ "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz",
+ "integrity": "sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==",
+ "dev": true,
+ "requires": {
+ "css-select": "~1.2.0",
+ "dom-serializer": "~0.1.1",
+ "entities": "~1.1.1",
+ "htmlparser2": "^3.9.1",
+ "lodash": "^4.15.0",
+ "parse5": "^3.0.1"
+ }
+ },
+ "chokidar": {
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz",
+ "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "anymatch": "~3.1.1",
+ "braces": "~3.0.2",
+ "fsevents": "~2.1.2",
+ "glob-parent": "~5.1.0",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.4.0"
+ }
+ },
+ "chrome-launcher": {
+ "version": "0.13.4",
+ "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.13.4.tgz",
+ "integrity": "sha512-nnzXiDbGKjDSK6t2I+35OAPBy5Pw/39bgkb/ZAFwMhwJbdYBp6aH+vW28ZgtjdU890Q7D+3wN/tB8N66q5Gi2A==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*",
+ "escape-string-regexp": "^1.0.5",
+ "is-wsl": "^2.2.0",
+ "lighthouse-logger": "^1.0.0",
+ "mkdirp": "^0.5.3",
+ "rimraf": "^3.0.2"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ }
+ }
+ },
+ "ci-info": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
+ "dev": true
+ },
+ "circular-json": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
+ "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A=="
+ },
+ "class-utils": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
+ "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "arr-union": "^3.1.0",
+ "define-property": "^0.2.5",
+ "isobject": "^3.0.0",
+ "static-extend": "^0.1.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "cli-boxes": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz",
+ "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==",
+ "dev": true
+ },
+ "cli-cursor": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
+ "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=",
+ "requires": {
+ "restore-cursor": "^2.0.0"
+ }
+ },
+ "cli-width": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
+ "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk="
+ },
+ "cliui": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+ "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+ "dev": true,
+ "requires": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^6.2.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ }
+ }
+ },
+ "clone": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+ "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
+ "dev": true
+ },
+ "clone-response": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz",
+ "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=",
+ "dev": true,
+ "requires": {
+ "mimic-response": "^1.0.0"
+ }
+ },
+ "collection-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
+ "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "map-visit": "^1.0.0",
+ "object-visit": "^1.0.0"
+ }
+ },
+ "color-convert": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
+ "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
+ "requires": {
+ "color-name": "^1.1.1"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+ },
+ "colors": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz",
+ "integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q=",
+ "dev": true
+ },
+ "columnify": {
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz",
+ "integrity": "sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=",
+ "dev": true,
+ "requires": {
+ "strip-ansi": "^3.0.0",
+ "wcwidth": "^1.0.0"
+ },
+ "dependencies": {
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ }
+ }
+ },
+ "combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dev": true,
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
+ "commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
+ },
+ "common-tags": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz",
+ "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==",
+ "dev": true
+ },
+ "component-emitter": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
+ "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
+ "dev": true,
+ "optional": true
+ },
+ "compress-commons": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.0.1.tgz",
+ "integrity": "sha512-xZm9o6iikekkI0GnXCmAl3LQGZj5TBDj0zLowsqi7tJtEa3FMGSEcHcqrSJIrOAk1UG/NBbDn/F1q+MG/p/EsA==",
+ "dev": true,
+ "requires": {
+ "buffer-crc32": "^0.2.13",
+ "crc32-stream": "^4.0.0",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^3.6.0"
+ }
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+ },
+ "concat-stream": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
+ "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+ "dev": true,
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "configstore": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz",
+ "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==",
+ "dev": true,
+ "requires": {
+ "dot-prop": "^5.2.0",
+ "graceful-fs": "^4.1.2",
+ "make-dir": "^3.0.0",
+ "unique-string": "^2.0.0",
+ "write-file-atomic": "^3.0.0",
+ "xdg-basedir": "^4.0.0"
+ }
+ },
+ "copy-descriptor": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+ "dev": true,
+ "optional": true
+ },
+ "core-js": {
+ "version": "2.6.11",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz",
+ "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==",
+ "dev": true
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "dev": true
+ },
+ "crc": {
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz",
+ "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==",
+ "dev": true,
+ "requires": {
+ "buffer": "^5.1.0"
+ }
+ },
+ "crc32-stream": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.0.tgz",
+ "integrity": "sha512-tyMw2IeUX6t9jhgXI6um0eKfWq4EIDpfv5m7GX4Jzp7eVelQ360xd8EPXJhp2mHwLQIkqlnMLjzqSZI3a+0wRw==",
+ "dev": true,
+ "requires": {
+ "crc": "^3.4.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "requires": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "dependencies": {
+ "path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true
+ },
+ "shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "requires": {
+ "shebang-regex": "^3.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true
+ },
+ "which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ }
+ }
+ },
+ "crypto-random-string": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
+ "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==",
+ "dev": true
+ },
+ "css-select": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
+ "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
+ "dev": true,
+ "requires": {
+ "boolbase": "~1.0.0",
+ "css-what": "2.1",
+ "domutils": "1.5.1",
+ "nth-check": "~1.0.1"
+ }
+ },
+ "css-what": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
+ "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==",
+ "dev": true
+ },
+ "dashdash": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+ "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "debounce": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.0.tgz",
+ "integrity": "sha512-mYtLl1xfZLi1m4RtQYlZgJUNQjl4ZxVnHzIR8nLLgi4q1YT8o/WM+MK/f8yfcc9s5Ir5zRaPZyZU6xs1Syoocg==",
+ "dev": true
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "decamelize": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz",
+ "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==",
+ "dev": true
+ },
+ "decode-uri-component": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+ "dev": true,
+ "optional": true
+ },
+ "decompress-response": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
+ "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=",
+ "dev": true,
+ "requires": {
+ "mimic-response": "^1.0.0"
+ }
+ },
+ "deep-equal": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
+ "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
+ "dev": true,
+ "requires": {
+ "is-arguments": "^1.0.4",
+ "is-date-object": "^1.0.1",
+ "is-regex": "^1.0.4",
+ "object-is": "^1.0.1",
+ "object-keys": "^1.1.1",
+ "regexp.prototype.flags": "^1.2.0"
+ }
+ },
+ "deep-extend": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+ "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
+ "dev": true
+ },
+ "deep-is": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ="
+ },
+ "deepcopy": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/deepcopy/-/deepcopy-2.1.0.tgz",
+ "integrity": "sha512-8cZeTb1ZKC3bdSCP6XOM1IsTczIO73fdqtwa2B0N15eAz7gmyhQo+mc5gnFuulsgN3vIQYmTgbmQVKalH1dKvQ==",
+ "dev": true,
+ "requires": {
+ "type-detect": "^4.0.8"
+ }
+ },
+ "deepmerge": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
+ "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
+ "dev": true
+ },
+ "defaults": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
+ "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=",
+ "dev": true,
+ "requires": {
+ "clone": "^1.0.2"
+ }
+ },
+ "defer-to-connect": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz",
+ "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==",
+ "dev": true
+ },
+ "define-properties": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
+ "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
+ "dev": true,
+ "requires": {
+ "object-keys": "^1.0.12"
+ }
+ },
+ "define-property": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+ "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-descriptor": "^1.0.2",
+ "isobject": "^3.0.1"
+ },
+ "dependencies": {
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "del": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
+ "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
+ "requires": {
+ "globby": "^5.0.0",
+ "is-path-cwd": "^1.0.0",
+ "is-path-in-cwd": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0",
+ "rimraf": "^2.2.8"
+ }
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+ "dev": true
+ },
+ "diff": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
+ "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
+ "dev": true
+ },
+ "dispensary": {
+ "version": "0.57.0",
+ "resolved": "https://registry.npmjs.org/dispensary/-/dispensary-0.57.0.tgz",
+ "integrity": "sha512-vgRaZa9Ok8QdrAVtx+s6heBgI1RGT+Y6VA336oPWYADZZz83K+5NOTpLamEKRyJdRY5pYLaWhV2Js7bau1JyKg==",
+ "dev": true,
+ "requires": {
+ "async": "~3.2.0",
+ "natural-compare-lite": "~1.4.0",
+ "pino": "~6.6.0",
+ "request": "~2.88.0",
+ "sha.js": "~2.4.4",
+ "source-map-support": "~0.5.4",
+ "yargs": "~15.4.0"
+ },
+ "dependencies": {
+ "async": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz",
+ "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==",
+ "dev": true
+ }
+ }
+ },
+ "doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "requires": {
+ "esutils": "^2.0.2"
+ }
+ },
+ "dom-serializer": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
+ "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "^1.3.0",
+ "entities": "^1.1.1"
+ }
+ },
+ "domelementtype": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
+ "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
+ "dev": true
+ },
+ "domhandler": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
+ "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "1"
+ }
+ },
+ "domutils": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
+ "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
+ "dev": true,
+ "requires": {
+ "dom-serializer": "0",
+ "domelementtype": "1"
+ }
+ },
+ "dot-prop": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
+ "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
+ "dev": true,
+ "requires": {
+ "is-obj": "^2.0.0"
+ }
+ },
+ "dtrace-provider": {
+ "version": "0.8.8",
+ "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.8.tgz",
+ "integrity": "sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "nan": "^2.14.0"
+ }
+ },
+ "duplexer3": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
+ "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=",
+ "dev": true
+ },
+ "ecc-jsbn": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+ "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+ "dev": true,
+ "requires": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "dev": true,
+ "requires": {
+ "once": "^1.4.0"
+ }
+ },
+ "enquirer": {
+ "version": "2.3.6",
+ "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
+ "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
+ "dev": true,
+ "requires": {
+ "ansi-colors": "^4.1.1"
+ }
+ },
+ "entities": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
+ "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
+ "dev": true
+ },
+ "error-ex": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+ "dev": true,
+ "requires": {
+ "is-arrayish": "^0.2.1"
+ }
+ },
+ "es-abstract": {
+ "version": "1.18.0-next.1",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz",
+ "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==",
+ "dev": true,
+ "requires": {
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1",
+ "is-callable": "^1.2.2",
+ "is-negative-zero": "^2.0.0",
+ "is-regex": "^1.1.1",
+ "object-inspect": "^1.8.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.1",
+ "string.prototype.trimend": "^1.0.1",
+ "string.prototype.trimstart": "^1.0.1"
+ }
+ },
+ "es-to-primitive": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
+ "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+ "dev": true,
+ "requires": {
+ "is-callable": "^1.1.4",
+ "is-date-object": "^1.0.1",
+ "is-symbol": "^1.0.2"
+ }
+ },
+ "es6-error": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
+ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
+ "dev": true
+ },
+ "es6-promise": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-2.3.0.tgz",
+ "integrity": "sha1-lu258v2wGZWCKyY92KratnSBgbw=",
+ "dev": true
+ },
+ "es6-promisify": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-6.1.1.tgz",
+ "integrity": "sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg==",
+ "dev": true
+ },
+ "escape-goat": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz",
+ "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==",
+ "dev": true
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+ },
+ "eslint": {
+ "version": "5.10.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-5.10.0.tgz",
+ "integrity": "sha512-HpqzC+BHULKlnPwWae9MaVZ5AXJKpkxCVXQHrFaRw3hbDj26V/9ArYM4Rr/SQ8pi6qUPLXSSXC4RBJlyq2Z2OQ==",
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "ajv": "^6.5.3",
+ "chalk": "^2.1.0",
+ "cross-spawn": "^6.0.5",
+ "debug": "^4.0.1",
+ "doctrine": "^2.1.0",
+ "eslint-scope": "^4.0.0",
+ "eslint-utils": "^1.3.1",
+ "eslint-visitor-keys": "^1.0.0",
+ "espree": "^5.0.0",
+ "esquery": "^1.0.1",
+ "esutils": "^2.0.2",
+ "file-entry-cache": "^2.0.0",
+ "functional-red-black-tree": "^1.0.1",
+ "glob": "^7.1.2",
+ "globals": "^11.7.0",
+ "ignore": "^4.0.6",
+ "imurmurhash": "^0.1.4",
+ "inquirer": "^6.1.0",
+ "js-yaml": "^3.12.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.3.0",
+ "lodash": "^4.17.5",
+ "minimatch": "^3.0.4",
+ "mkdirp": "^0.5.1",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.8.2",
+ "path-is-inside": "^1.0.2",
+ "pluralize": "^7.0.0",
+ "progress": "^2.0.0",
+ "regexpp": "^2.0.1",
+ "require-uncached": "^1.0.3",
+ "semver": "^5.5.1",
+ "strip-ansi": "^4.0.0",
+ "strip-json-comments": "^2.0.1",
+ "table": "^5.0.2",
+ "text-table": "^0.2.0"
+ },
+ "dependencies": {
+ "acorn": {
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
+ "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA=="
+ },
+ "acorn-jsx": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.0.1.tgz",
+ "integrity": "sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg=="
+ },
+ "ajv": {
+ "version": "6.6.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz",
+ "integrity": "sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g==",
+ "requires": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "ansi-regex": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.0.0.tgz",
+ "integrity": "sha512-iB5Dda8t/UqpPI/IjsejXu5jOGDrzn41wJyljwPH65VCIbk6+1BzFIMJGFwTNrYXT1CrD+B4l19U7awiQ8rk7w=="
+ },
+ "chardet": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="
+ },
+ "cross-spawn": {
+ "version": "6.0.5",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+ "requires": {
+ "nice-try": "^1.0.4",
+ "path-key": "^2.0.1",
+ "semver": "^5.5.0",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ },
+ "debug": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz",
+ "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==",
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "requires": {
+ "esutils": "^2.0.2"
+ }
+ },
+ "espree": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-5.0.0.tgz",
+ "integrity": "sha512-1MpUfwsdS9MMoN7ZXqAr9e9UKdVHDcvrJpyx7mm1WuQlx/ygErEQBzgi5Nh5qBHIoYweprhtMkTCb9GhcAIcsA==",
+ "requires": {
+ "acorn": "^6.0.2",
+ "acorn-jsx": "^5.0.0",
+ "eslint-visitor-keys": "^1.0.0"
+ }
+ },
+ "esquery": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz",
+ "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==",
+ "requires": {
+ "estraverse": "^4.0.0"
+ }
+ },
+ "external-editor": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.0.3.tgz",
+ "integrity": "sha512-bn71H9+qWoOQKyZDo25mOMVpSmXROAsTJVVVYzrrtol3d4y+AsKjf4Iwl2Q+IuT0kFSQ1qo166UuIwqYq7mGnA==",
+ "requires": {
+ "chardet": "^0.7.0",
+ "iconv-lite": "^0.4.24",
+ "tmp": "^0.0.33"
+ }
+ },
+ "fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
+ },
+ "globals": {
+ "version": "11.9.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.9.0.tgz",
+ "integrity": "sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg=="
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg=="
+ },
+ "inquirer": {
+ "version": "6.2.1",
+ "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz",
+ "integrity": "sha512-088kl3DRT2dLU5riVMKKr1DlImd6X7smDhpXUCkJDCKvTEJeRiXh0G132HG9u5a+6Ylw9plFRY7RuTnwohYSpg==",
+ "requires": {
+ "ansi-escapes": "^3.0.0",
+ "chalk": "^2.0.0",
+ "cli-cursor": "^2.1.0",
+ "cli-width": "^2.0.0",
+ "external-editor": "^3.0.0",
+ "figures": "^2.0.0",
+ "lodash": "^4.17.10",
+ "mute-stream": "0.0.7",
+ "run-async": "^2.2.0",
+ "rxjs": "^6.1.0",
+ "string-width": "^2.1.0",
+ "strip-ansi": "^5.0.0",
+ "through": "^2.3.6"
+ },
+ "dependencies": {
+ "strip-ansi": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.0.0.tgz",
+ "integrity": "sha512-Uu7gQyZI7J7gn5qLn1Np3G9vcYGTVqB+lFTytnDJv83dd8T22aGH451P3jueT2/QemInJDfxHB5Tde5OzgG1Ow==",
+ "requires": {
+ "ansi-regex": "^4.0.0"
+ }
+ }
+ }
+ },
+ "js-yaml": {
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+ "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+ },
+ "lodash": {
+ "version": "4.17.19",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
+ "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
+ },
+ "ms": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+ "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+ },
+ "regexpp": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
+ "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw=="
+ },
+ "rxjs": {
+ "version": "6.3.3",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz",
+ "integrity": "sha512-JTWmoY9tWCs7zvIk/CvRjhjGaOd+OVBM987mxFo+OW66cGpdKjZcpmc74ES1sB//7Kl/PAe8+wEakuhG4pcgOw==",
+ "requires": {
+ "tslib": "^1.9.0"
+ }
+ },
+ "semver": {
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
+ "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg=="
+ }
+ }
+ },
+ "eslint-plugin-no-unsanitized": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-3.1.2.tgz",
+ "integrity": "sha512-KPShfliA3Uy9qqwQx35P1fwIOeJjZkb0FbMMUFztRYRposzaynsM8JCEb952fqkidROl1kpqY80uSvn+TcWkQQ==",
+ "dev": true
+ },
+ "eslint-scope": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.0.tgz",
+ "integrity": "sha512-1G6UTDi7Jc1ELFwnR58HV4fK9OQK4S6N985f166xqXxpjU6plxFISJa2Ba9KCQuFa8RCnj/lSFJbHo7UFDBnUA==",
+ "requires": {
+ "esrecurse": "^4.1.0",
+ "estraverse": "^4.1.1"
+ }
+ },
+ "eslint-utils": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.2.tgz",
+ "integrity": "sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q==",
+ "requires": {
+ "eslint-visitor-keys": "^1.0.0"
+ }
+ },
+ "eslint-visitor-keys": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
+ "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ=="
+ },
+ "espree": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz",
+ "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==",
+ "dev": true,
+ "requires": {
+ "acorn": "^7.4.0",
+ "acorn-jsx": "^5.2.0",
+ "eslint-visitor-keys": "^1.3.0"
+ },
+ "dependencies": {
+ "eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+ "dev": true
+ }
+ }
+ },
+ "esprima": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
+ "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw=="
+ },
+ "esquery": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz",
+ "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==",
+ "dev": true,
+ "requires": {
+ "estraverse": "^5.1.0"
+ },
+ "dependencies": {
+ "estraverse": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+ "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+ "dev": true
+ }
+ }
+ },
+ "esrecurse": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz",
+ "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=",
+ "requires": {
+ "estraverse": "^4.1.0",
+ "object-assign": "^4.0.1"
+ }
+ },
+ "estraverse": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
+ "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM="
+ },
+ "esutils": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
+ },
+ "event-to-promise": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/event-to-promise/-/event-to-promise-0.8.0.tgz",
+ "integrity": "sha1-S4TxF3K28l93Uvx02XFTGsb1tiY=",
+ "dev": true
+ },
+ "execa": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.3.tgz",
+ "integrity": "sha512-WFDXGHckXPWZX19t1kCsXzOpqX9LWYNqn4C+HqZlk/V0imTkzJZqf87ZBhvpHaftERYknpk0fjSylnXVlVgI0A==",
+ "dev": true,
+ "requires": {
+ "cross-spawn": "^7.0.0",
+ "get-stream": "^5.0.0",
+ "human-signals": "^1.1.1",
+ "is-stream": "^2.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^4.0.0",
+ "onetime": "^5.1.0",
+ "signal-exit": "^3.0.2",
+ "strip-final-newline": "^2.0.0"
+ },
+ "dependencies": {
+ "mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true
+ },
+ "onetime": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+ "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+ "dev": true,
+ "requires": {
+ "mimic-fn": "^2.1.0"
+ }
+ }
+ }
+ },
+ "expand-brackets": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+ "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "debug": "^2.3.3",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "posix-character-classes": "^0.1.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true
+ },
+ "extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "assign-symbols": "^1.0.0",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "extglob": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+ "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "array-unique": "^0.3.2",
+ "define-property": "^1.0.0",
+ "expand-brackets": "^2.1.4",
+ "extend-shallow": "^2.0.1",
+ "fragment-cache": "^0.2.1",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "extsprintf": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+ "dev": true
+ },
+ "fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
+ },
+ "fast-json-patch": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-2.2.1.tgz",
+ "integrity": "sha512-4j5uBaTnsYAV5ebkidvxiLUYOwjQ+JSFljeqfTxCrH9bDmlCQaOJFS84oDJ2rAXZq2yskmk3ORfoP9DCwqFNig==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^2.0.1"
+ },
+ "dependencies": {
+ "fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
+ "dev": true
+ }
+ }
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
+ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
+ },
+ "fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
+ },
+ "fast-redact": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-2.1.0.tgz",
+ "integrity": "sha512-0LkHpTLyadJavq9sRzzyqIoMZemWli77K2/MGOkafrR64B9ItrvZ9aT+jluvNDsv0YEHjSNhlMBtbokuoqii4A==",
+ "dev": true
+ },
+ "fast-safe-stringify": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz",
+ "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==",
+ "dev": true
+ },
+ "fd-slicer": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+ "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=",
+ "dev": true,
+ "requires": {
+ "pend": "~1.2.0"
+ }
+ },
+ "figures": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
+ "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=",
+ "requires": {
+ "escape-string-regexp": "^1.0.5"
+ }
+ },
+ "file-entry-cache": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
+ "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
+ "requires": {
+ "flat-cache": "^1.2.1",
+ "object-assign": "^4.0.1"
+ }
+ },
+ "fill-range": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "to-regex-range": "^5.0.1"
+ }
+ },
+ "find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "firefox-profile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/firefox-profile/-/firefox-profile-4.0.0.tgz",
+ "integrity": "sha512-Vw31AsjfLDbcApMDwwnhZcz3tWjV6lxB9BNf84FaV44rZXtU87cVbFMBzPEtrJdUDbwPYiuYzprp6yksYGwjSw==",
+ "dev": true,
+ "requires": {
+ "adm-zip": "~0.4.x",
+ "archiver": "~5.0.2",
+ "async": "~2.5.0",
+ "fs-extra": "~4.0.2",
+ "ini": "~1.3.3",
+ "jetpack-id": "1.0.0",
+ "lazystream": "~1.0.0",
+ "lodash": "~4.17.2",
+ "minimist": "^1.1.1",
+ "uuid": "^3.0.0",
+ "xml2js": "~0.4.4"
+ },
+ "dependencies": {
+ "async": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz",
+ "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==",
+ "dev": true,
+ "requires": {
+ "lodash": "^4.14.0"
+ }
+ },
+ "fs-extra": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz",
+ "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "jsonfile": "^4.0.0",
+ "universalify": "^0.1.0"
+ }
+ }
+ }
+ },
+ "first-chunk-stream": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-4.0.0.tgz",
+ "integrity": "sha512-8TOz/mJp7+zc2HN63vnJHotwceq4gQI1+/gdJVnJcG4dEB96oUxw7wV9We4QKjSFWUc/V0ADDfaGba5cDoG6EA==",
+ "dev": true
+ },
+ "flat-cache": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz",
+ "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=",
+ "requires": {
+ "circular-json": "^0.3.1",
+ "del": "^2.0.2",
+ "graceful-fs": "^4.1.2",
+ "write": "^0.2.1"
+ }
+ },
+ "flatstr": {
+ "version": "1.0.12",
+ "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz",
+ "integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==",
+ "dev": true
+ },
+ "flatted": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
+ "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==",
+ "dev": true
+ },
+ "fluent-syntax": {
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/fluent-syntax/-/fluent-syntax-0.13.0.tgz",
+ "integrity": "sha512-0Bk1AsliuYB550zr4JV9AYhsETsD3ELXUQzdXGJfIc1Ni/ukAfBdQInDhVMYJUaT2QxoamNslwkYF7MlOrPUwg==",
+ "dev": true
+ },
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+ "dev": true,
+ "optional": true
+ },
+ "forever-agent": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+ "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+ "dev": true
+ },
+ "form-data": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+ "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+ "dev": true,
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "formatio": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.2.0.tgz",
+ "integrity": "sha1-87IWfZBoxGmKjVH092CjmlTYGOs=",
+ "dev": true,
+ "requires": {
+ "samsam": "1.x"
+ }
+ },
+ "fragment-cache": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+ "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "map-cache": "^0.2.2"
+ }
+ },
+ "fs-constants": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+ "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+ "dev": true
+ },
+ "fs-extra": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
+ "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
+ "dev": true,
+ "requires": {
+ "at-least-node": "^1.0.0",
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^1.0.0"
+ },
+ "dependencies": {
+ "graceful-fs": {
+ "version": "4.2.4",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+ "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+ "dev": true
+ },
+ "jsonfile": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz",
+ "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.6",
+ "universalify": "^1.0.0"
+ }
+ },
+ "universalify": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
+ "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
+ "dev": true
+ }
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+ },
+ "fsevents": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
+ "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
+ "dev": true,
+ "optional": true
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+ "dev": true
+ },
+ "functional-red-black-tree": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
+ },
+ "fx-runner": {
+ "version": "1.0.13",
+ "resolved": "https://registry.npmjs.org/fx-runner/-/fx-runner-1.0.13.tgz",
+ "integrity": "sha512-Ces2bm+LNuXehkvmN1/Z+oEDkI/jHBp9xdyBtBy7hcgvF18/pv/D8F6A6kQgNkMZsnBgLEv+VvdDxyqkfkYycw==",
+ "dev": true,
+ "requires": {
+ "commander": "2.9.0",
+ "shell-quote": "1.6.1",
+ "spawn-sync": "1.0.15",
+ "when": "3.7.7",
+ "which": "1.2.4",
+ "winreg": "0.0.12"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.9.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
+ "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
+ "dev": true,
+ "requires": {
+ "graceful-readlink": ">= 1.0.0"
+ }
+ },
+ "isexe": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz",
+ "integrity": "sha1-NvPiLmB1CSD15yQaR2qMakInWtA=",
+ "dev": true
+ },
+ "which": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.2.4.tgz",
+ "integrity": "sha1-FVf5YIBgTlsRs1meufRbUKnv1yI=",
+ "dev": true,
+ "requires": {
+ "is-absolute": "^0.1.7",
+ "isexe": "^1.1.1"
+ }
+ }
+ }
+ },
+ "get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true
+ },
+ "get-stream": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+ "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+ "dev": true,
+ "requires": {
+ "pump": "^3.0.0"
+ }
+ },
+ "get-value": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+ "dev": true,
+ "optional": true
+ },
+ "getpass": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+ "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+ "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "glob-parent": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
+ "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "global-dirs": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.0.1.tgz",
+ "integrity": "sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A==",
+ "dev": true,
+ "requires": {
+ "ini": "^1.3.5"
+ }
+ },
+ "globals": {
+ "version": "12.4.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
+ "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
+ "dev": true,
+ "requires": {
+ "type-fest": "^0.8.1"
+ }
+ },
+ "globby": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
+ "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
+ "requires": {
+ "array-union": "^1.0.1",
+ "arrify": "^1.0.0",
+ "glob": "^7.0.3",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ }
+ },
+ "got": {
+ "version": "9.6.0",
+ "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
+ "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==",
+ "dev": true,
+ "requires": {
+ "@sindresorhus/is": "^0.14.0",
+ "@szmarczak/http-timer": "^1.1.2",
+ "cacheable-request": "^6.0.0",
+ "decompress-response": "^3.3.0",
+ "duplexer3": "^0.1.4",
+ "get-stream": "^4.1.0",
+ "lowercase-keys": "^1.0.1",
+ "mimic-response": "^1.0.1",
+ "p-cancelable": "^1.0.0",
+ "to-readable-stream": "^1.0.0",
+ "url-parse-lax": "^3.0.0"
+ },
+ "dependencies": {
+ "get-stream": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+ "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+ "dev": true,
+ "requires": {
+ "pump": "^3.0.0"
+ }
+ }
+ }
+ },
+ "graceful-fs": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+ "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
+ },
+ "graceful-readlink": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
+ "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
+ "dev": true
+ },
+ "growly": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
+ "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=",
+ "dev": true
+ },
+ "har-schema": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+ "dev": true
+ },
+ "har-validator": {
+ "version": "5.1.5",
+ "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
+ "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
+ "dev": true,
+ "requires": {
+ "ajv": "^6.12.3",
+ "har-schema": "^2.0.0"
+ }
+ },
+ "has": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+ "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+ "dev": true,
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-flag": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
+ "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE="
+ },
+ "has-symbols": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
+ "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
+ "dev": true
+ },
+ "has-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "get-value": "^2.0.6",
+ "has-values": "^1.0.0",
+ "isobject": "^3.0.0"
+ }
+ },
+ "has-values": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
+ "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-number": "^3.0.0",
+ "kind-of": "^4.0.0"
+ },
+ "dependencies": {
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "kind-of": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+ "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "has-yarn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz",
+ "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==",
+ "dev": true
+ },
+ "htmlparser2": {
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
+ "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
+ "dev": true,
+ "requires": {
+ "domelementtype": "^1.3.1",
+ "domhandler": "^2.3.0",
+ "domutils": "^1.5.1",
+ "entities": "^1.1.1",
+ "inherits": "^2.0.1",
+ "readable-stream": "^3.1.1"
+ }
+ },
+ "http-cache-semantics": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz",
+ "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==",
+ "dev": true
+ },
+ "http-signature": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+ "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ }
+ },
+ "human-signals": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
+ "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
+ "dev": true
+ },
+ "ieee754": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
+ "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==",
+ "dev": true
+ },
+ "ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+ "dev": true
+ },
+ "import-fresh": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
+ "integrity": "sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==",
+ "dev": true,
+ "requires": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "dependencies": {
+ "resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true
+ }
+ }
+ },
+ "import-lazy": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz",
+ "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=",
+ "dev": true
+ },
+ "imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ },
+ "ini": {
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+ "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+ "dev": true
+ },
+ "invert-kv": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-3.0.1.tgz",
+ "integrity": "sha512-CYdFeFexxhv/Bcny+Q0BfOV+ltRlJcd4BBZBYFX/O0u4npJrgZtIcjokegtiSMAvlMTJ+Koq0GBCc//3bueQxw==",
+ "dev": true
+ },
+ "is-absolute": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz",
+ "integrity": "sha1-hHSREZ/MtftDYhfMc39/qtUPYD8=",
+ "dev": true,
+ "requires": {
+ "is-relative": "^0.1.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+ "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-arguments": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
+ "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==",
+ "dev": true
+ },
+ "is-arrayish": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+ "dev": true
+ },
+ "is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "binary-extensions": "^2.0.0"
+ }
+ },
+ "is-buffer": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+ "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
+ "dev": true,
+ "optional": true
+ },
+ "is-callable": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz",
+ "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==",
+ "dev": true
+ },
+ "is-ci": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
+ "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
+ "dev": true,
+ "requires": {
+ "ci-info": "^2.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+ "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "is-date-object": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
+ "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==",
+ "dev": true
+ },
+ "is-descriptor": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
+ "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-accessor-descriptor": "^0.1.6",
+ "is-data-descriptor": "^0.1.4",
+ "kind-of": "^5.0.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
+ "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "is-docker": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz",
+ "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==",
+ "dev": true
+ },
+ "is-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+ "dev": true,
+ "optional": true
+ },
+ "is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+ },
+ "is-glob": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^2.1.1"
+ }
+ },
+ "is-installed-globally": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz",
+ "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==",
+ "dev": true,
+ "requires": {
+ "global-dirs": "^2.0.1",
+ "is-path-inside": "^3.0.1"
+ },
+ "dependencies": {
+ "is-path-inside": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz",
+ "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==",
+ "dev": true
+ }
+ }
+ },
+ "is-mergeable-object": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-mergeable-object/-/is-mergeable-object-1.1.1.tgz",
+ "integrity": "sha512-CPduJfuGg8h8vW74WOxHtHmtQutyQBzR+3MjQ6iDHIYdbOnm1YC7jv43SqCoU8OPGTJD4nibmiryA4kmogbGrA==",
+ "dev": true
+ },
+ "is-negative-zero": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz",
+ "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=",
+ "dev": true
+ },
+ "is-npm": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz",
+ "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==",
+ "dev": true
+ },
+ "is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "optional": true
+ },
+ "is-obj": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
+ "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
+ "dev": true
+ },
+ "is-path-cwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
+ "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0="
+ },
+ "is-path-in-cwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz",
+ "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=",
+ "requires": {
+ "is-path-inside": "^1.0.0"
+ }
+ },
+ "is-path-inside": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz",
+ "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=",
+ "requires": {
+ "path-is-inside": "^1.0.1"
+ }
+ },
+ "is-plain-object": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "is-promise": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
+ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o="
+ },
+ "is-regex": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz",
+ "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==",
+ "dev": true,
+ "requires": {
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "is-relative": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz",
+ "integrity": "sha1-kF/uiuhvRbPsYUvDwVyGnfCHboI=",
+ "dev": true
+ },
+ "is-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
+ "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
+ "dev": true
+ },
+ "is-symbol": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
+ "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
+ "dev": true,
+ "requires": {
+ "has-symbols": "^1.0.1"
+ }
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+ "dev": true
+ },
+ "is-utf8": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
+ "dev": true
+ },
+ "is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+ "dev": true,
+ "optional": true
+ },
+ "is-wsl": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+ "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+ "dev": true,
+ "requires": {
+ "is-docker": "^2.0.0"
+ }
+ },
+ "is-yarn-global": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz",
+ "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==",
+ "dev": true
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true,
+ "optional": true
+ },
+ "isstream": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+ "dev": true
+ },
+ "jed": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/jed/-/jed-1.1.1.tgz",
+ "integrity": "sha1-elSbvZ/+FYWwzQoZHiAwVb7ldLQ=",
+ "dev": true
+ },
+ "jetpack-id": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/jetpack-id/-/jetpack-id-1.0.0.tgz",
+ "integrity": "sha1-LPn7rkbYB0/Ba33gBxyO/rykc6Y=",
+ "dev": true
+ },
+ "jquery": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.5.1.tgz",
+ "integrity": "sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg==",
+ "dev": true
+ },
+ "jquery-smooth-scroll": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/jquery-smooth-scroll/-/jquery-smooth-scroll-2.2.0.tgz",
+ "integrity": "sha1-h9wa3YQWi39Gazza7rgcgD/SKio=",
+ "dev": true,
+ "requires": {
+ "jquery": ">=1.7.0"
+ }
+ },
+ "jquery-ui": {
+ "version": "1.12.1",
+ "resolved": "https://registry.npmjs.org/jquery-ui/-/jquery-ui-1.12.1.tgz",
+ "integrity": "sha1-vLQEXI3QU5wTS8FIjN0+dop6nlE=",
+ "dev": true
+ },
+ "jquery-ui-iconfont": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/jquery-ui-iconfont/-/jquery-ui-iconfont-2.3.2.tgz",
+ "integrity": "sha1-WwhjzM6U281q3qJCdgWZjdaNNJY=",
+ "dev": true
+ },
+ "js-reporters": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/js-reporters/-/js-reporters-1.2.1.tgz",
+ "integrity": "sha1-+IxgjjJKM3OpW8xFrTBeXJecRZs=",
+ "dev": true
+ },
+ "js-select": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/js-select/-/js-select-0.6.0.tgz",
+ "integrity": "sha1-woTiKCTVknrsli3N8kcXSu+w0ZA=",
+ "dev": true,
+ "requires": {
+ "JSONSelect": "0.2.1",
+ "traverse": "0.4.x"
+ }
+ },
+ "js-yaml": {
+ "version": "3.14.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
+ "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
+ "dev": true,
+ "requires": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ }
+ },
+ "jsbn": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+ "dev": true
+ },
+ "json-buffer": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz",
+ "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=",
+ "dev": true
+ },
+ "json-merge-patch": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-merge-patch/-/json-merge-patch-0.2.3.tgz",
+ "integrity": "sha1-+ixrWvh9p3uuKWalidUuI+2B/kA=",
+ "dev": true,
+ "requires": {
+ "deep-equal": "^1.0.0"
+ }
+ },
+ "json-parse-better-errors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
+ "dev": true
+ },
+ "json-schema": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
+ "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+ "dev": true
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE="
+ },
+ "json-stringify-safe": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+ "dev": true
+ },
+ "jsonfile": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+ "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
+ "dev": true,
+ "requires": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "jsonify": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
+ "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
+ "dev": true
+ },
+ "jsonwebtoken": {
+ "version": "8.5.1",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
+ "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
+ "dev": true,
+ "requires": {
+ "jws": "^3.2.2",
+ "lodash.includes": "^4.3.0",
+ "lodash.isboolean": "^3.0.3",
+ "lodash.isinteger": "^4.0.4",
+ "lodash.isnumber": "^3.0.3",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.isstring": "^4.0.1",
+ "lodash.once": "^4.0.0",
+ "ms": "^2.1.1",
+ "semver": "^5.6.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+ "dev": true
+ }
+ }
+ },
+ "jsprim": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
+ "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ }
+ },
+ "jszip": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/jszip/-/jszip-2.6.1.tgz",
+ "integrity": "sha1-uI86ey5noqBIFSmCx6N1bZxIKPA=",
+ "dev": true,
+ "requires": {
+ "pako": "~1.0.2"
+ }
+ },
+ "jwa": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+ "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+ "dev": true,
+ "requires": {
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "jws": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+ "dev": true,
+ "requires": {
+ "jwa": "^1.4.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "keyv": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz",
+ "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==",
+ "dev": true,
+ "requires": {
+ "json-buffer": "3.0.0"
+ }
+ },
+ "kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true,
+ "optional": true
+ },
+ "latest-version": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz",
+ "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==",
+ "dev": true,
+ "requires": {
+ "package-json": "^6.3.0"
+ }
+ },
+ "lazystream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
+ "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
+ "dev": true,
+ "requires": {
+ "readable-stream": "^2.0.5"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "lcid": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/lcid/-/lcid-3.1.1.tgz",
+ "integrity": "sha512-M6T051+5QCGLBQb8id3hdvIW8+zeFV2FyBGFS9IEK5H9Wt4MueD4bW1eWikpHgZp+5xR3l5c8pZUkQsIA0BFZg==",
+ "dev": true,
+ "requires": {
+ "invert-kv": "^3.0.0"
+ }
+ },
+ "levn": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+ "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+ "requires": {
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2"
+ }
+ },
+ "lighthouse-logger": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.2.0.tgz",
+ "integrity": "sha512-wzUvdIeJZhRsG6gpZfmSCfysaxNEr43i+QT+Hie94wvHDKFLi4n7C2GqZ4sTC+PH5b5iktmXJvU87rWvhP3lHw==",
+ "dev": true,
+ "requires": {
+ "debug": "^2.6.8",
+ "marky": "^1.2.0"
+ }
+ },
+ "lines-and-columns": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
+ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
+ "dev": true
+ },
+ "locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^4.1.0"
+ }
+ },
+ "lodash": {
+ "version": "4.17.19",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
+ "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
+ },
+ "lodash.defaults": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
+ "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=",
+ "dev": true
+ },
+ "lodash.difference": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz",
+ "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=",
+ "dev": true
+ },
+ "lodash.flatten": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
+ "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=",
+ "dev": true
+ },
+ "lodash.includes": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+ "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=",
+ "dev": true
+ },
+ "lodash.isboolean": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+ "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=",
+ "dev": true
+ },
+ "lodash.isinteger": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+ "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=",
+ "dev": true
+ },
+ "lodash.isnumber": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+ "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=",
+ "dev": true
+ },
+ "lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=",
+ "dev": true
+ },
+ "lodash.isstring": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+ "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=",
+ "dev": true
+ },
+ "lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=",
+ "dev": true
+ },
+ "lodash.sortby": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
+ "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
+ "dev": true
+ },
+ "lodash.union": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz",
+ "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=",
+ "dev": true
+ },
+ "lolex": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz",
+ "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=",
+ "dev": true
+ },
+ "lowercase-keys": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
+ "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==",
+ "dev": true
+ },
+ "make-dir": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+ "dev": true,
+ "requires": {
+ "semver": "^6.0.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "map-age-cleaner": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
+ "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
+ "dev": true,
+ "requires": {
+ "p-defer": "^1.0.0"
+ }
+ },
+ "map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
+ "dev": true,
+ "optional": true
+ },
+ "map-visit": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
+ "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "object-visit": "^1.0.0"
+ }
+ },
+ "marky": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/marky/-/marky-1.2.1.tgz",
+ "integrity": "sha512-md9k+Gxa3qLH6sUKpeC2CNkJK/Ld+bEz5X96nYwloqphQE0CKCVEKco/6jxEZixinqNdz5RFi/KaCyfbMDMAXQ==",
+ "dev": true
+ },
+ "mdn-browser-compat-data": {
+ "version": "1.0.39",
+ "resolved": "https://registry.npmjs.org/mdn-browser-compat-data/-/mdn-browser-compat-data-1.0.39.tgz",
+ "integrity": "sha512-1U5Lt+pjYxJ1mosBIdK5fr3guzV4v81f8yy0rLAj/cu7ki3ciCe85LVJJ0RLK0lP6VwFtjpXSOESfwAEpz0FyQ==",
+ "dev": true,
+ "requires": {
+ "extend": "3.0.2"
+ }
+ },
+ "mem": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/mem/-/mem-5.1.1.tgz",
+ "integrity": "sha512-qvwipnozMohxLXG1pOqoLiZKNkC4r4qqRucSoDwXowsNGDSULiqFTRUF05vcZWnwJSG22qTsynQhxbaMtnX9gw==",
+ "dev": true,
+ "requires": {
+ "map-age-cleaner": "^0.1.3",
+ "mimic-fn": "^2.1.0",
+ "p-is-promise": "^2.1.0"
+ },
+ "dependencies": {
+ "mimic-fn": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+ "dev": true
+ }
+ }
+ },
+ "merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "dev": true
+ },
+ "micromatch": {
+ "version": "3.1.10",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+ "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "braces": "^2.3.1",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "extglob": "^2.0.4",
+ "fragment-cache": "^0.2.1",
+ "kind-of": "^6.0.2",
+ "nanomatch": "^1.2.9",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.2"
+ },
+ "dependencies": {
+ "braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "to-regex-range": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ }
+ }
+ }
+ },
+ "mime-db": {
+ "version": "1.44.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
+ "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
+ "dev": true
+ },
+ "mime-types": {
+ "version": "2.1.27",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
+ "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
+ "dev": true,
+ "requires": {
+ "mime-db": "1.44.0"
+ }
+ },
+ "mimic-fn": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz",
+ "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg="
+ },
+ "mimic-response": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
+ "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
+ "dev": true
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
+ },
+ "mixin-deep": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+ "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "for-in": "^1.0.2",
+ "is-extendable": "^1.0.1"
+ },
+ "dependencies": {
+ "is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-plain-object": "^2.0.4"
+ }
+ }
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz",
+ "integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==",
+ "requires": {
+ "minimist": "^1.2.5"
+ }
+ },
+ "moment": {
+ "version": "2.29.0",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.0.tgz",
+ "integrity": "sha512-z6IJ5HXYiuxvFTI6eiQ9dm77uE0gyy1yXNApVHqTcnIKfY9tIwEjlzsZ6u1LQXvVgKeTnv9Xm7NDvJ7lso3MtA==",
+ "dev": true,
+ "optional": true
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "dev": true
+ },
+ "multimatch": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz",
+ "integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==",
+ "dev": true,
+ "requires": {
+ "@types/minimatch": "^3.0.3",
+ "array-differ": "^3.0.0",
+ "array-union": "^2.1.0",
+ "arrify": "^2.0.1",
+ "minimatch": "^3.0.4"
+ },
+ "dependencies": {
+ "array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true
+ },
+ "arrify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
+ "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
+ "dev": true
+ }
+ }
+ },
+ "mute-stream": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
+ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
+ },
+ "mv": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz",
+ "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "mkdirp": "~0.5.1",
+ "ncp": "~2.0.0",
+ "rimraf": "~2.4.0"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "6.0.4",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz",
+ "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "2 || 3",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "rimraf": {
+ "version": "2.4.5",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz",
+ "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "glob": "^6.0.1"
+ }
+ }
+ }
+ },
+ "mz": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+ "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+ "dev": true,
+ "requires": {
+ "any-promise": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "thenify-all": "^1.0.0"
+ }
+ },
+ "nan": {
+ "version": "2.14.1",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz",
+ "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==",
+ "dev": true,
+ "optional": true
+ },
+ "nanomatch": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
+ "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "arr-diff": "^4.0.0",
+ "array-unique": "^0.3.2",
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "fragment-cache": "^0.2.1",
+ "is-windows": "^1.0.2",
+ "kind-of": "^6.0.2",
+ "object.pick": "^1.3.0",
+ "regex-not": "^1.0.0",
+ "snapdragon": "^0.8.1",
+ "to-regex": "^3.0.1"
+ }
+ },
+ "native-promise-only": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz",
+ "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=",
+ "dev": true
+ },
+ "natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc="
+ },
+ "natural-compare-lite": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz",
+ "integrity": "sha1-F7CVgZiJef3a/gIB6TG6kzyWy7Q=",
+ "dev": true
+ },
+ "ncp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
+ "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=",
+ "dev": true,
+ "optional": true
+ },
+ "neo-async": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+ "dev": true
+ },
+ "next-tick": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
+ "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==",
+ "dev": true
+ },
+ "nice-try": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
+ },
+ "node-forge": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
+ "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==",
+ "dev": true
+ },
+ "node-notifier": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.0.tgz",
+ "integrity": "sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA==",
+ "dev": true,
+ "requires": {
+ "growly": "^1.3.0",
+ "is-wsl": "^2.2.0",
+ "semver": "^7.3.2",
+ "shellwords": "^0.1.1",
+ "uuid": "^8.3.0",
+ "which": "^2.0.2"
+ },
+ "dependencies": {
+ "uuid": {
+ "version": "8.3.1",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz",
+ "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==",
+ "dev": true
+ },
+ "which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ }
+ }
+ },
+ "node-watch": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.6.0.tgz",
+ "integrity": "sha512-XAgTL05z75ptd7JSVejH1a2Dm1zmXYhuDr9l230Qk6Z7/7GPcnAs/UyJJ4ggsXSvWil8iOzwQLW0zuGUvHpG8g==",
+ "dev": true
+ },
+ "normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true
+ },
+ "normalize-url": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz",
+ "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==",
+ "dev": true
+ },
+ "npm-run-path": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+ "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+ "dev": true,
+ "requires": {
+ "path-key": "^3.0.0"
+ },
+ "dependencies": {
+ "path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true
+ }
+ }
+ },
+ "nth-check": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
+ "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
+ "dev": true,
+ "requires": {
+ "boolbase": "~1.0.0"
+ }
+ },
+ "oauth-sign": {
+ "version": "0.9.0",
+ "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+ "dev": true
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+ },
+ "object-copy": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
+ "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "copy-descriptor": "^0.1.0",
+ "define-property": "^0.2.5",
+ "kind-of": "^3.0.3"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "object-inspect": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
+ "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==",
+ "dev": true
+ },
+ "object-is": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.3.tgz",
+ "integrity": "sha512-teyqLvFWzLkq5B9ki8FVWA902UER2qkxmdA4nLf+wjOLAWgxzCWZNCxpDq9MvE8MmhWNr+I8w3BN49Vx36Y6Xg==",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.1"
+ }
+ },
+ "object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "dev": true
+ },
+ "object-visit": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
+ "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "isobject": "^3.0.0"
+ }
+ },
+ "object.assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz",
+ "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.18.0-next.0",
+ "has-symbols": "^1.0.1",
+ "object-keys": "^1.1.1"
+ }
+ },
+ "object.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "onetime": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
+ "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=",
+ "requires": {
+ "mimic-fn": "^1.0.0"
+ }
+ },
+ "open": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/open/-/open-7.3.0.tgz",
+ "integrity": "sha512-mgLwQIx2F/ye9SmbrUkurZCnkoXyXyu9EbHtJZrICjVAJfyMArdHp3KkixGdZx1ZHFPNIwl0DDM1dFFqXbTLZw==",
+ "dev": true,
+ "requires": {
+ "is-docker": "^2.0.0",
+ "is-wsl": "^2.1.1"
+ }
+ },
+ "optionator": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
+ "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
+ "requires": {
+ "deep-is": "~0.1.3",
+ "fast-levenshtein": "~2.0.4",
+ "levn": "~0.3.0",
+ "prelude-ls": "~1.1.2",
+ "type-check": "~0.3.2",
+ "wordwrap": "~1.0.0"
+ }
+ },
+ "os-locale": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-5.0.0.tgz",
+ "integrity": "sha512-tqZcNEDAIZKBEPnHPlVDvKrp7NzgLi7jRmhKiUoa2NUmhl13FtkAGLUVR+ZsYvApBQdBfYm43A4tXXQ4IrYLBA==",
+ "dev": true,
+ "requires": {
+ "execa": "^4.0.0",
+ "lcid": "^3.0.0",
+ "mem": "^5.0.0"
+ }
+ },
+ "os-shim": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz",
+ "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=",
+ "dev": true
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
+ },
+ "p-cancelable": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz",
+ "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==",
+ "dev": true
+ },
+ "p-defer": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
+ "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=",
+ "dev": true
+ },
+ "p-is-promise": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
+ "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==",
+ "dev": true
+ },
+ "p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^2.2.0"
+ }
+ },
+ "p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true
+ },
+ "package-json": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz",
+ "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==",
+ "dev": true,
+ "requires": {
+ "got": "^9.6.0",
+ "registry-auth-token": "^4.0.0",
+ "registry-url": "^5.0.0",
+ "semver": "^6.2.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "pako": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+ "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
+ "dev": true
+ },
+ "parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "requires": {
+ "callsites": "^3.0.0"
+ },
+ "dependencies": {
+ "callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true
+ }
+ }
+ },
+ "parse-json": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.1.tgz",
+ "integrity": "sha512-ztoZ4/DYeXQq4E21v169sC8qWINGpcosGv9XhTDvg9/hWvx/zrFkc9BiWxR58OJLHGk28j5BL0SDLeV2WmFZlQ==",
+ "dev": true,
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1",
+ "lines-and-columns": "^1.1.6"
+ }
+ },
+ "parse5": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz",
+ "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "pascalcase": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
+ "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
+ "dev": true,
+ "optional": true
+ },
+ "path-dirname": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
+ "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
+ "dev": true,
+ "optional": true
+ },
+ "path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+ },
+ "path-is-inside": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM="
+ },
+ "path-key": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
+ },
+ "path-parse": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+ "dev": true
+ },
+ "path-to-regexp": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
+ "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
+ "dev": true,
+ "requires": {
+ "isarray": "0.0.1"
+ },
+ "dependencies": {
+ "isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+ "dev": true
+ }
+ }
+ },
+ "pend": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+ "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=",
+ "dev": true
+ },
+ "performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
+ "dev": true
+ },
+ "picomatch": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
+ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
+ "dev": true,
+ "optional": true
+ },
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
+ },
+ "pinkie": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
+ },
+ "pinkie-promise": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+ "requires": {
+ "pinkie": "^2.0.0"
+ }
+ },
+ "pino": {
+ "version": "6.6.1",
+ "resolved": "https://registry.npmjs.org/pino/-/pino-6.6.1.tgz",
+ "integrity": "sha512-DOgm7rn6ctBkBYemHXSLj7+j3o3U1q1FWBXbHcprur8mA93QcJSycEkEqhqKiFB9Mx/3Qld2FGr6+9yfQza0kA==",
+ "dev": true,
+ "requires": {
+ "fast-redact": "^2.0.0",
+ "fast-safe-stringify": "^2.0.7",
+ "flatstr": "^1.0.12",
+ "pino-std-serializers": "^2.4.2",
+ "quick-format-unescaped": "^4.0.1",
+ "sonic-boom": "^1.0.2"
+ }
+ },
+ "pino-std-serializers": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-2.5.0.tgz",
+ "integrity": "sha512-wXqbqSrIhE58TdrxxlfLwU9eDhrzppQDvGhBEr1gYbzzM4KKo3Y63gSjiDXRKLVS2UOXdPNR2v+KnQgNrs+xUg==",
+ "dev": true
+ },
+ "pluralize": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
+ "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow=="
+ },
+ "posix-character-classes": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
+ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
+ "dev": true,
+ "optional": true
+ },
+ "postcss": {
+ "version": "7.0.35",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz",
+ "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.2",
+ "source-map": "^0.6.1",
+ "supports-color": "^6.1.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+ "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "prelude-ls": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+ "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
+ },
+ "prepend-http": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz",
+ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=",
+ "dev": true
+ },
+ "probe-image-size": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/probe-image-size/-/probe-image-size-5.0.0.tgz",
+ "integrity": "sha512-V6uBYw5eBc5UVIE7MUZD6Nxg0RYuGDWLDenEn0B1WC6PcTvn1xdQ6HLDDuznefsiExC6rNrCz7mFRBo0f3Xekg==",
+ "dev": true,
+ "requires": {
+ "deepmerge": "^4.0.0",
+ "inherits": "^2.0.3",
+ "next-tick": "^1.0.0",
+ "request": "^2.83.0",
+ "stream-parser": "~0.3.1"
+ }
+ },
+ "process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true
+ },
+ "progress": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz",
+ "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8="
+ },
+ "psl": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
+ "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==",
+ "dev": true
+ },
+ "pump": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+ "dev": true,
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "punycode": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+ "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
+ "dev": true
+ },
+ "pupa": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.0.1.tgz",
+ "integrity": "sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==",
+ "dev": true,
+ "requires": {
+ "escape-goat": "^2.0.0"
+ }
+ },
+ "qs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+ "dev": true
+ },
+ "quick-format-unescaped": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.1.tgz",
+ "integrity": "sha512-RyYpQ6Q5/drsJyOhrWHYMWTedvjTIat+FTwv0K4yoUxzvekw2aRHMQJLlnvt8UantkZg2++bEzD9EdxXqkWf4A==",
+ "dev": true
+ },
+ "qunit": {
+ "version": "2.9.2",
+ "resolved": "https://registry.npmjs.org/qunit/-/qunit-2.9.2.tgz",
+ "integrity": "sha512-wTOYHnioWHcx5wa85Wl15IE7D6zTZe2CQlsodS14yj7s2FZ3MviRnQluspBZsueIDEO7doiuzKlv05yfky1R7w==",
+ "dev": true,
+ "requires": {
+ "commander": "2.12.2",
+ "js-reporters": "1.2.1",
+ "minimatch": "3.0.4",
+ "node-watch": "0.6.0",
+ "resolve": "1.9.0"
+ },
+ "dependencies": {
+ "commander": {
+ "version": "2.12.2",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz",
+ "integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==",
+ "dev": true
+ },
+ "resolve": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.9.0.tgz",
+ "integrity": "sha512-TZNye00tI67lwYvzxCxHGjwTNlUV70io54/Ed4j6PscB8xVfuBJpRenI/o6dVk0cY0PYTY27AgCoGGxRnYuItQ==",
+ "dev": true,
+ "requires": {
+ "path-parse": "^1.0.6"
+ }
+ }
+ }
+ },
+ "rc": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+ "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+ "dev": true,
+ "requires": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ }
+ },
+ "readable-stream": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+ "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ },
+ "readdir-glob": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.0.tgz",
+ "integrity": "sha512-KgT0oXPIDQRRRYFf+06AUaodICTep2Q5635BORLzTEzp7rEqcR14a47j3Vzm3ix7FeI1lp8mYyG7r8lTB06Pyg==",
+ "dev": true,
+ "requires": {
+ "minimatch": "^3.0.4"
+ }
+ },
+ "readdirp": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz",
+ "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "picomatch": "^2.2.1"
+ }
+ },
+ "regenerator-runtime": {
+ "version": "0.13.7",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
+ "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==",
+ "dev": true
+ },
+ "regex-not": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
+ "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "extend-shallow": "^3.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "regexp.prototype.flags": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz",
+ "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.0-next.1"
+ },
+ "dependencies": {
+ "es-abstract": {
+ "version": "1.17.7",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
+ "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
+ "dev": true,
+ "requires": {
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1",
+ "is-callable": "^1.2.2",
+ "is-regex": "^1.1.1",
+ "object-inspect": "^1.8.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.1",
+ "string.prototype.trimend": "^1.0.1",
+ "string.prototype.trimstart": "^1.0.1"
+ }
+ }
+ }
+ },
+ "regexpp": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz",
+ "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==",
+ "dev": true
+ },
+ "registry-auth-token": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.0.tgz",
+ "integrity": "sha512-P+lWzPrsgfN+UEpDS3U8AQKg/UjZX6mQSJueZj3EK+vNESoqBSpBUD3gmu4sF9lOsjXWjF11dQKUqemf3veq1w==",
+ "dev": true,
+ "requires": {
+ "rc": "^1.2.8"
+ }
+ },
+ "registry-url": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz",
+ "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==",
+ "dev": true,
+ "requires": {
+ "rc": "^1.2.8"
+ }
+ },
+ "relaxed-json": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/relaxed-json/-/relaxed-json-1.0.3.tgz",
+ "integrity": "sha512-b7wGPo7o2KE/g7SqkJDDbav6zmrEeP4TK2VpITU72J/M949TLe/23y/ZHJo+pskcGM52xIfFoT9hydwmgr1AEg==",
+ "dev": true,
+ "requires": {
+ "chalk": "^2.4.2",
+ "commander": "^2.6.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+ "dev": true
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ }
+ }
+ },
+ "remove-trailing-separator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+ "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
+ "dev": true,
+ "optional": true
+ },
+ "repeat-element": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+ "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
+ "dev": true,
+ "optional": true
+ },
+ "repeat-string": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
+ "dev": true,
+ "optional": true
+ },
+ "request": {
+ "version": "2.88.2",
+ "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
+ "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
+ "dev": true,
+ "requires": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.3",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.5.0",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ }
+ },
+ "require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+ "dev": true
+ },
+ "require-main-filename": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
+ "dev": true
+ },
+ "require-uncached": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
+ "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
+ "requires": {
+ "caller-path": "^0.1.0",
+ "resolve-from": "^1.0.0"
+ }
+ },
+ "resolve-from": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
+ "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY="
+ },
+ "resolve-url": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
+ "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+ "dev": true,
+ "optional": true
+ },
+ "responselike": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz",
+ "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=",
+ "dev": true,
+ "requires": {
+ "lowercase-keys": "^1.0.0"
+ }
+ },
+ "restore-cursor": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
+ "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=",
+ "requires": {
+ "onetime": "^2.0.0",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "ret": {
+ "version": "0.1.15",
+ "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
+ "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
+ "dev": true,
+ "optional": true
+ },
+ "rimraf": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
+ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+ "requires": {
+ "glob": "^7.0.5"
+ }
+ },
+ "run-async": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
+ "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=",
+ "requires": {
+ "is-promise": "^2.1.0"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true
+ },
+ "safe-json-stringify": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.2.0.tgz",
+ "integrity": "sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==",
+ "dev": true,
+ "optional": true
+ },
+ "safe-regex": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+ "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "ret": "~0.1.10"
+ }
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "samsam": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz",
+ "integrity": "sha512-1HwIYD/8UlOtFS3QO3w7ey+SdSDFE4HRNLZoZRYVQefrOY3l17epswImeB1ijgJFQJodIaHcwkp3r/myBjFVbg==",
+ "dev": true
+ },
+ "sax": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
+ "dev": true
+ },
+ "select2": {
+ "version": "4.0.11",
+ "resolved": "https://registry.npmjs.org/select2/-/select2-4.0.11.tgz",
+ "integrity": "sha512-8Z/yd43F5EMOkz2Mo+aE7nOx2i8nSuxGZVFkbeyCklkU+WTwCa+xdZqG+IPgZ75lkEkLD+X+f8vEG9aKBxISqA==",
+ "dev": true
+ },
+ "semver": {
+ "version": "7.3.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
+ "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
+ "dev": true
+ },
+ "semver-diff": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz",
+ "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==",
+ "dev": true,
+ "requires": {
+ "semver": "^6.3.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+ "dev": true
+ }
+ }
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+ "dev": true
+ },
+ "set-value": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+ "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-extendable": "^0.1.1",
+ "is-plain-object": "^2.0.3",
+ "split-string": "^3.0.1"
+ },
+ "dependencies": {
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ }
+ }
+ },
+ "sha.js": {
+ "version": "2.4.11",
+ "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+ "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+ "requires": {
+ "shebang-regex": "^1.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
+ },
+ "shell-quote": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz",
+ "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=",
+ "dev": true,
+ "requires": {
+ "array-filter": "~0.0.0",
+ "array-map": "~0.0.0",
+ "array-reduce": "~0.0.0",
+ "jsonify": "~0.0.0"
+ }
+ },
+ "shellwords": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz",
+ "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
+ "dev": true
+ },
+ "sign-addon": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/sign-addon/-/sign-addon-3.1.0.tgz",
+ "integrity": "sha512-zZ7nKc5/3QWM3skYBosGDvYQf2jkKhW2u8BELrZoN1wgCSOnwsV9T47Vx9uaNbA3CyZ+V9XSA0tDVHoV1QfVPw==",
+ "dev": true,
+ "requires": {
+ "common-tags": "1.8.0",
+ "core-js": "3.6.5",
+ "deepcopy": "2.1.0",
+ "es6-error": "4.1.1",
+ "es6-promisify": "6.1.1",
+ "jsonwebtoken": "8.5.1",
+ "mz": "2.7.0",
+ "request": "2.88.2",
+ "source-map-support": "0.5.19",
+ "stream-to-promise": "3.0.0"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "3.6.5",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz",
+ "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==",
+ "dev": true
+ }
+ }
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+ },
+ "sinon": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/sinon/-/sinon-2.0.0.tgz",
+ "integrity": "sha1-SDN/pIkGnlMK1+L0TwewrpPTeyQ=",
+ "dev": true,
+ "requires": {
+ "diff": "^3.1.0",
+ "formatio": "1.2.0",
+ "lolex": "^1.6.0",
+ "native-promise-only": "^0.8.1",
+ "path-to-regexp": "^1.7.0",
+ "samsam": "^1.1.3",
+ "text-encoding": "0.6.4",
+ "type-detect": "^4.0.0"
+ }
+ },
+ "slice-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
+ "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^3.2.0",
+ "astral-regex": "^1.0.0",
+ "is-fullwidth-code-point": "^2.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ }
+ }
+ },
+ "snapdragon": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
+ "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "base": "^0.11.1",
+ "debug": "^2.2.0",
+ "define-property": "^0.2.5",
+ "extend-shallow": "^2.0.1",
+ "map-cache": "^0.2.2",
+ "source-map": "^0.5.6",
+ "source-map-resolve": "^0.5.0",
+ "use": "^3.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "snapdragon-node": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
+ "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "define-property": "^1.0.0",
+ "isobject": "^3.0.0",
+ "snapdragon-util": "^3.0.1"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+ "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-descriptor": "^1.0.0"
+ }
+ },
+ "is-accessor-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+ "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-data-descriptor": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+ "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "kind-of": "^6.0.0"
+ }
+ },
+ "is-descriptor": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+ "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-accessor-descriptor": "^1.0.0",
+ "is-data-descriptor": "^1.0.0",
+ "kind-of": "^6.0.2"
+ }
+ }
+ }
+ },
+ "snapdragon-util": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
+ "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "kind-of": "^3.2.0"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "sonic-boom": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.3.0.tgz",
+ "integrity": "sha512-4nX6OYvOYr6R76xfQKi6cZpTO3YSWe/vd+QdIfoH0lBy0MnPkeAbb2rRWgmgADkXUeCKPwO1FZAKlAVWAadELw==",
+ "dev": true,
+ "requires": {
+ "atomic-sleep": "^1.0.0",
+ "flatstr": "^1.0.12"
+ }
+ },
+ "source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true
+ },
+ "source-map-resolve": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
+ "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "atob": "^2.1.2",
+ "decode-uri-component": "^0.2.0",
+ "resolve-url": "^0.2.1",
+ "source-map-url": "^0.4.0",
+ "urix": "^0.1.0"
+ }
+ },
+ "source-map-support": {
+ "version": "0.5.19",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
+ "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
+ "dev": true,
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "source-map-url": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
+ "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
+ "dev": true,
+ "optional": true
+ },
+ "spawn-sync": {
+ "version": "1.0.15",
+ "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz",
+ "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=",
+ "dev": true,
+ "requires": {
+ "concat-stream": "^1.4.7",
+ "os-shim": "^0.1.2"
+ }
+ },
+ "split": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz",
+ "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=",
+ "dev": true,
+ "requires": {
+ "through": "2"
+ }
+ },
+ "split-string": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
+ "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "extend-shallow": "^3.0.0"
+ }
+ },
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
+ },
+ "sshpk": {
+ "version": "1.16.1",
+ "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+ "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+ "dev": true,
+ "requires": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ }
+ },
+ "static-extend": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
+ "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "define-property": "^0.2.5",
+ "object-copy": "^0.1.0"
+ },
+ "dependencies": {
+ "define-property": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+ "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-descriptor": "^0.1.0"
+ }
+ }
+ }
+ },
+ "stream-parser": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz",
+ "integrity": "sha1-FhhUhpRCACGhGC/wrxkRwSl2F3M=",
+ "dev": true,
+ "requires": {
+ "debug": "2"
+ }
+ },
+ "stream-to-array": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/stream-to-array/-/stream-to-array-2.3.0.tgz",
+ "integrity": "sha1-u/azn19D7DC8cbq8s3VXrOzzQ1M=",
+ "dev": true,
+ "requires": {
+ "any-promise": "^1.1.0"
+ }
+ },
+ "stream-to-promise": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/stream-to-promise/-/stream-to-promise-3.0.0.tgz",
+ "integrity": "sha512-h+7wLeFiYegOdgTfTxjRsrT7/Op7grnKEIHWgaO1RTHwcwk7xRreMr3S8XpDfDMesSxzgM2V4CxNCFAGo6ssnA==",
+ "dev": true,
+ "requires": {
+ "any-promise": "~1.3.0",
+ "end-of-stream": "~1.4.1",
+ "stream-to-array": "~2.3.0"
+ }
+ },
+ "string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "requires": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ }
+ },
+ "string.prototype.trimend": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz",
+ "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.5"
+ },
+ "dependencies": {
+ "es-abstract": {
+ "version": "1.17.7",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
+ "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
+ "dev": true,
+ "requires": {
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1",
+ "is-callable": "^1.2.2",
+ "is-regex": "^1.1.1",
+ "object-inspect": "^1.8.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.1",
+ "string.prototype.trimend": "^1.0.1",
+ "string.prototype.trimstart": "^1.0.1"
+ }
+ }
+ }
+ },
+ "string.prototype.trimstart": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz",
+ "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==",
+ "dev": true,
+ "requires": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.5"
+ },
+ "dependencies": {
+ "es-abstract": {
+ "version": "1.17.7",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
+ "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
+ "dev": true,
+ "requires": {
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1",
+ "is-callable": "^1.2.2",
+ "is-regex": "^1.1.1",
+ "object-inspect": "^1.8.0",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.1",
+ "string.prototype.trimend": "^1.0.1",
+ "string.prototype.trimstart": "^1.0.1"
+ }
+ }
+ }
+ },
+ "string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+ }
+ }
+ },
+ "strip-bom": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
+ "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
+ "dev": true
+ },
+ "strip-bom-buf": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom-buf/-/strip-bom-buf-2.0.0.tgz",
+ "integrity": "sha512-gLFNHucd6gzb8jMsl5QmZ3QgnUJmp7qn4uUSHNwEXumAp7YizoGYw19ZUVfuq4aBOQUtyn2k8X/CwzWB73W2lQ==",
+ "dev": true,
+ "requires": {
+ "is-utf8": "^0.2.1"
+ }
+ },
+ "strip-bom-stream": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-4.0.0.tgz",
+ "integrity": "sha512-0ApK3iAkHv6WbgLICw/J4nhwHeDZsBxIIsOD+gHgZICL6SeJ0S9f/WZqemka9cjkTyMN5geId6e8U5WGFAn3cQ==",
+ "dev": true,
+ "requires": {
+ "first-chunk-stream": "^3.0.0",
+ "strip-bom-buf": "^2.0.0"
+ },
+ "dependencies": {
+ "first-chunk-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-3.0.0.tgz",
+ "integrity": "sha512-LNRvR4hr/S8cXXkIY5pTgVP7L3tq6LlYWcg9nWBuW7o1NMxKZo6oOVa/6GIekMGI0Iw7uC+HWimMe9u/VAeKqw==",
+ "dev": true
+ }
+ }
+ },
+ "strip-final-newline": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+ "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+ "dev": true
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ },
+ "dependencies": {
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ }
+ }
+ },
+ "table": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/table/-/table-5.1.1.tgz",
+ "integrity": "sha512-NUjapYb/qd4PeFW03HnAuOJ7OMcBkJlqeClWxeNlQ0lXGSb52oZXGzkO0/I0ARegQ2eUT1g2VDJH0eUxDRcHmw==",
+ "requires": {
+ "ajv": "^6.6.1",
+ "lodash": "^4.17.11",
+ "slice-ansi": "2.0.0",
+ "string-width": "^2.1.1"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "6.6.2",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz",
+ "integrity": "sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g==",
+ "requires": {
+ "fast-deep-equal": "^2.0.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "fast-deep-equal": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
+ "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+ },
+ "slice-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.0.0.tgz",
+ "integrity": "sha512-4j2WTWjp3GsZ+AOagyzVbzp4vWGtZ0hEZ/gDY/uTvm6MTxUfTUIsnMIFb1bn8o0RuXiqUw15H1bue8f22Vw2oQ==",
+ "requires": {
+ "ansi-styles": "^3.2.0",
+ "astral-regex": "^1.0.0",
+ "is-fullwidth-code-point": "^2.0.0"
+ }
+ }
+ }
+ },
+ "tar-stream": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.4.tgz",
+ "integrity": "sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw==",
+ "dev": true,
+ "requires": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ }
+ },
+ "term-size": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz",
+ "integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==",
+ "dev": true
+ },
+ "text-encoding": {
+ "version": "0.6.4",
+ "resolved": "https://registry.npmjs.org/text-encoding/-/text-encoding-0.6.4.tgz",
+ "integrity": "sha1-45mpgiV6J22uQou5KEXLcb3CbRk=",
+ "dev": true
+ },
+ "text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ="
+ },
+ "thenify": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+ "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+ "dev": true,
+ "requires": {
+ "any-promise": "^1.0.0"
+ }
+ },
+ "thenify-all": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+ "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=",
+ "dev": true,
+ "requires": {
+ "thenify": ">= 3.1.0 < 4"
+ }
+ },
+ "through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
+ },
+ "tmp": {
+ "version": "0.0.33",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+ "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+ "requires": {
+ "os-tmpdir": "~1.0.2"
+ }
+ },
+ "to-object-path": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
+ "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ },
+ "dependencies": {
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ }
+ }
+ },
+ "to-readable-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz",
+ "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==",
+ "dev": true
+ },
+ "to-regex": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
+ "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "define-property": "^2.0.2",
+ "extend-shallow": "^3.0.2",
+ "regex-not": "^1.0.2",
+ "safe-regex": "^1.1.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-number": "^7.0.0"
+ }
+ },
+ "tooltipster": {
+ "version": "4.2.6",
+ "resolved": "https://registry.npmjs.org/tooltipster/-/tooltipster-4.2.6.tgz",
+ "integrity": "sha1-+/ej9bQL2D6BV04o2WZ8+CZnvHk=",
+ "dev": true
+ },
+ "tosource": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/tosource/-/tosource-1.0.0.tgz",
+ "integrity": "sha1-QtiN0RZhi88A1hBt1URvNCeQL/E=",
+ "dev": true
+ },
+ "tough-cookie": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+ "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+ "dev": true,
+ "requires": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true
+ }
+ }
+ },
+ "tr46": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz",
+ "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==",
+ "dev": true,
+ "requires": {
+ "punycode": "^2.1.1"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+ "dev": true
+ }
+ }
+ },
+ "traverse": {
+ "version": "0.4.6",
+ "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.4.6.tgz",
+ "integrity": "sha1-0EsigOTHkqWBVCnve4tgxkyczDQ=",
+ "dev": true
+ },
+ "tslib": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
+ "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ=="
+ },
+ "tunnel-agent": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+ "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "tweetnacl": {
+ "version": "0.14.5",
+ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+ "dev": true
+ },
+ "type-check": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+ "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+ "requires": {
+ "prelude-ls": "~1.1.2"
+ }
+ },
+ "type-detect": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
+ "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
+ "dev": true
+ },
+ "type-fest": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+ "dev": true
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+ "dev": true
+ },
+ "typedarray-to-buffer": {
+ "version": "3.1.5",
+ "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+ "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+ "dev": true,
+ "requires": {
+ "is-typedarray": "^1.0.0"
+ }
+ },
+ "underscore": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz",
+ "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==",
+ "dev": true
+ },
+ "union-value": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+ "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "arr-union": "^3.1.0",
+ "get-value": "^2.0.6",
+ "is-extendable": "^0.1.1",
+ "set-value": "^2.0.1"
+ }
+ },
+ "unique-string": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz",
+ "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==",
+ "dev": true,
+ "requires": {
+ "crypto-random-string": "^2.0.0"
+ }
+ },
+ "universalify": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+ "dev": true
+ },
+ "unset-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
+ "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "has-value": "^0.3.1",
+ "isobject": "^3.0.0"
+ },
+ "dependencies": {
+ "has-value": {
+ "version": "0.3.1",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
+ "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "get-value": "^2.0.3",
+ "has-values": "^0.1.4",
+ "isobject": "^2.0.0"
+ },
+ "dependencies": {
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ }
+ }
+ },
+ "has-values": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
+ "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
+ "dev": true,
+ "optional": true
+ }
+ }
+ },
+ "upath": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
+ "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
+ "dev": true
+ },
+ "update-notifier": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.0.0.tgz",
+ "integrity": "sha512-8tqsiVrMv7aZsKNSjqA6DdBLKJpZG1hRpkj1RbOJu1PgyP69OX+EInAnP1EK/ShX5YdPFgwWdk19oquZ0HTM8g==",
+ "dev": true,
+ "requires": {
+ "boxen": "^4.2.0",
+ "chalk": "^4.1.0",
+ "configstore": "^5.0.1",
+ "has-yarn": "^2.1.0",
+ "import-lazy": "^2.1.0",
+ "is-ci": "^2.0.0",
+ "is-installed-globally": "^0.3.1",
+ "is-npm": "^5.0.0",
+ "is-yarn-global": "^0.3.0",
+ "latest-version": "^5.0.0",
+ "pupa": "^2.0.1",
+ "semver": "^7.3.2",
+ "semver-diff": "^3.1.1",
+ "xdg-basedir": "^4.0.0"
+ },
+ "dependencies": {
+ "chalk": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+ "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ }
+ }
+ }
+ },
+ "uri-js": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
+ "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
+ "requires": {
+ "punycode": "^2.1.0"
+ },
+ "dependencies": {
+ "punycode": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+ }
+ }
+ },
+ "urix": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
+ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
+ "dev": true,
+ "optional": true
+ },
+ "url-parse-lax": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz",
+ "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=",
+ "dev": true,
+ "requires": {
+ "prepend-http": "^2.0.0"
+ }
+ },
+ "use": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
+ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
+ "dev": true,
+ "optional": true
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+ "dev": true
+ },
+ "uuid": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
+ "dev": true
+ },
+ "v8-compile-cache": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz",
+ "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==",
+ "dev": true
+ },
+ "verror": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+ "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+ "dev": true,
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "watchpack": {
+ "version": "1.7.4",
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.4.tgz",
+ "integrity": "sha512-aWAgTW4MoSJzZPAicljkO1hsi1oKj/RRq/OJQh2PKI2UKL04c2Bs+MBOB+BBABHTXJpf9mCwHN7ANCvYsvY2sg==",
+ "dev": true,
+ "requires": {
+ "chokidar": "^3.4.1",
+ "graceful-fs": "^4.1.2",
+ "neo-async": "^2.5.0",
+ "watchpack-chokidar2": "^2.0.0"
+ }
+ },
+ "watchpack-chokidar2": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz",
+ "integrity": "sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "chokidar": "^2.1.8"
+ },
+ "dependencies": {
+ "anymatch": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "micromatch": "^3.1.4",
+ "normalize-path": "^2.1.1"
+ },
+ "dependencies": {
+ "normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "remove-trailing-separator": "^1.0.1"
+ }
+ }
+ }
+ },
+ "binary-extensions": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
+ "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
+ "dev": true,
+ "optional": true
+ },
+ "braces": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+ "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "arr-flatten": "^1.1.0",
+ "array-unique": "^0.3.2",
+ "extend-shallow": "^2.0.1",
+ "fill-range": "^4.0.0",
+ "isobject": "^3.0.1",
+ "repeat-element": "^1.1.2",
+ "snapdragon": "^0.8.1",
+ "snapdragon-node": "^2.0.1",
+ "split-string": "^3.0.2",
+ "to-regex": "^3.0.1"
+ }
+ },
+ "chokidar": {
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
+ "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "anymatch": "^2.0.0",
+ "async-each": "^1.0.1",
+ "braces": "^2.3.2",
+ "fsevents": "^1.2.7",
+ "glob-parent": "^3.1.0",
+ "inherits": "^2.0.3",
+ "is-binary-path": "^1.0.0",
+ "is-glob": "^4.0.0",
+ "normalize-path": "^3.0.0",
+ "path-is-absolute": "^1.0.0",
+ "readdirp": "^2.2.1",
+ "upath": "^1.1.1"
+ }
+ },
+ "extend-shallow": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+ "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-extendable": "^0.1.0"
+ }
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "extend-shallow": "^2.0.1",
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "to-regex-range": "^2.1.0"
+ }
+ },
+ "fsevents": {
+ "version": "1.2.13",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
+ "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "nan": "^2.12.1"
+ }
+ },
+ "glob-parent": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
+ "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-glob": "^3.1.0",
+ "path-dirname": "^1.0.0"
+ },
+ "dependencies": {
+ "is-glob": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
+ "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-extglob": "^2.1.0"
+ }
+ }
+ }
+ },
+ "is-binary-path": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+ "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "binary-extensions": "^1.0.0"
+ }
+ },
+ "is-number": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+ "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ }
+ },
+ "kind-of": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+ "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-buffer": "^1.1.5"
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "readdirp": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
+ "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "graceful-fs": "^4.1.11",
+ "micromatch": "^3.1.10",
+ "readable-stream": "^2.0.2"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true,
+ "optional": true
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "to-regex-range": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+ "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
+ "dev": true,
+ "optional": true,
+ "requires": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ }
+ }
+ }
+ },
+ "wcwidth": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
+ "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=",
+ "dev": true,
+ "requires": {
+ "defaults": "^1.0.3"
+ }
+ },
+ "web-ext": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/web-ext/-/web-ext-5.2.0.tgz",
+ "integrity": "sha512-o/s206JW2U/vXHTe/XeBnsUQhIcuphsSVNVrJU+MoMFq8JlU9vI1VdS2RCW+u5NuqAsMvTyV+pA+4hLGB9CGCw==",
+ "dev": true,
+ "requires": {
+ "@babel/polyfill": "7.11.5",
+ "@babel/runtime": "7.11.2",
+ "@cliqz-oss/firefox-client": "0.3.1",
+ "@cliqz-oss/node-firefox-connect": "1.2.1",
+ "@devicefarmer/adbkit": "2.11.3",
+ "addons-linter": "2.7.0",
+ "bunyan": "1.8.14",
+ "camelcase": "6.0.0",
+ "chrome-launcher": "0.13.4",
+ "debounce": "1.2.0",
+ "decamelize": "4.0.0",
+ "es6-error": "4.1.1",
+ "event-to-promise": "0.8.0",
+ "firefox-profile": "4.0.0",
+ "fs-extra": "9.0.1",
+ "fx-runner": "1.0.13",
+ "import-fresh": "3.2.1",
+ "mkdirp": "1.0.4",
+ "multimatch": "4.0.0",
+ "mz": "2.7.0",
+ "node-notifier": "8.0.0",
+ "open": "7.3.0",
+ "parse-json": "5.0.1",
+ "sign-addon": "3.1.0",
+ "source-map-support": "0.5.19",
+ "strip-bom": "4.0.0",
+ "strip-json-comments": "3.1.1",
+ "tmp": "0.2.1",
+ "update-notifier": "5.0.0",
+ "watchpack": "1.7.4",
+ "ws": "7.3.1",
+ "yargs": "15.4.1",
+ "zip-dir": "1.0.2"
+ },
+ "dependencies": {
+ "glob": {
+ "version": "7.1.6",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+ "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+ "dev": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "mkdirp": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+ "dev": true
+ },
+ "rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "dev": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true
+ },
+ "tmp": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+ "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+ "dev": true,
+ "requires": {
+ "rimraf": "^3.0.0"
+ }
+ }
+ }
+ },
+ "webidl-conversions": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
+ "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==",
+ "dev": true
+ },
+ "whatwg-url": {
+ "version": "8.2.2",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.2.2.tgz",
+ "integrity": "sha512-PcVnO6NiewhkmzV0qn7A+UZ9Xx4maNTI+O+TShmfE4pqjoCMwUMjkvoNhNHPTvgR7QH9Xt3R13iHuWy2sToFxQ==",
+ "dev": true,
+ "requires": {
+ "lodash.sortby": "^4.7.0",
+ "tr46": "^2.0.2",
+ "webidl-conversions": "^6.1.0"
+ }
+ },
+ "when": {
+ "version": "3.7.7",
+ "resolved": "https://registry.npmjs.org/when/-/when-3.7.7.tgz",
+ "integrity": "sha1-q6A/w7tzbWyIsJHQE9io5ZDYRxg=",
+ "dev": true
+ },
+ "which": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
+ "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==",
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "which-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+ "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+ "dev": true
+ },
+ "widest-line": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz",
+ "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==",
+ "dev": true,
+ "requires": {
+ "string-width": "^4.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ }
+ }
+ },
+ "winreg": {
+ "version": "0.0.12",
+ "resolved": "https://registry.npmjs.org/winreg/-/winreg-0.0.12.tgz",
+ "integrity": "sha1-BxBVVLoanQiXklHRKUdb/64wBrc=",
+ "dev": true
+ },
+ "word-wrap": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
+ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
+ "dev": true
+ },
+ "wordwrap": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
+ "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
+ },
+ "wrap-ansi": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+ "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ }
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ },
+ "write": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
+ "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
+ "requires": {
+ "mkdirp": "^0.5.1"
+ }
+ },
+ "write-file-atomic": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
+ "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
+ "dev": true,
+ "requires": {
+ "imurmurhash": "^0.1.4",
+ "is-typedarray": "^1.0.0",
+ "signal-exit": "^3.0.2",
+ "typedarray-to-buffer": "^3.1.5"
+ }
+ },
+ "ws": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz",
+ "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==",
+ "dev": true
+ },
+ "xdg-basedir": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz",
+ "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==",
+ "dev": true
+ },
+ "xml2js": {
+ "version": "0.4.23",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
+ "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
+ "dev": true,
+ "requires": {
+ "sax": ">=0.6.0",
+ "xmlbuilder": "~11.0.0"
+ }
+ },
+ "xmlbuilder": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+ "dev": true
+ },
+ "y18n": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
+ "dev": true
+ },
+ "yargs": {
+ "version": "15.4.1",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+ "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
+ "dev": true,
+ "requires": {
+ "cliui": "^6.0.0",
+ "decamelize": "^1.2.0",
+ "find-up": "^4.1.0",
+ "get-caller-file": "^2.0.1",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^2.0.0",
+ "set-blocking": "^2.0.0",
+ "string-width": "^4.2.0",
+ "which-module": "^2.0.0",
+ "y18n": "^4.0.0",
+ "yargs-parser": "^18.1.2"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+ "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
+ "dev": true
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+ "dev": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true
+ },
+ "string-width": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+ "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+ "dev": true,
+ "requires": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+ "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.0"
+ }
+ }
+ }
+ },
+ "yargs-parser": {
+ "version": "18.1.3",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+ "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+ "dev": true,
+ "requires": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ },
+ "dependencies": {
+ "camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "dev": true
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+ "dev": true
+ }
+ }
+ },
+ "yauzl": {
+ "version": "2.10.0",
+ "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
+ "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=",
+ "dev": true,
+ "requires": {
+ "buffer-crc32": "~0.2.3",
+ "fd-slicer": "~1.1.0"
+ }
+ },
+ "zip-dir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/zip-dir/-/zip-dir-1.0.2.tgz",
+ "integrity": "sha1-JT+QeurWKiGs2HIdi4gDKyQRwFE=",
+ "dev": true,
+ "requires": {
+ "async": "^1.5.2",
+ "jszip": "^2.4.0"
+ },
+ "dependencies": {
+ "async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
+ "dev": true
+ }
+ }
+ },
+ "zip-stream": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.0.2.tgz",
+ "integrity": "sha512-TGxB2g+1ur6MHkvM644DuZr8Uzyz0k0OYWtS3YlpfWBEmK4woaC2t3+pozEL3dBfIPmpgmClR5B2QRcMgGt22g==",
+ "dev": true,
+ "requires": {
+ "archiver-utils": "^2.1.0",
+ "compress-commons": "^4.0.0",
+ "readable-stream": "^3.6.0"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..509957c
--- /dev/null
+++ b/package.json
@@ -0,0 +1,22 @@
+{
+ "name": "privacy-badger-dev-tools",
+ "version": "0.0.1",
+ "description": "Developer tools for Privacy Badger.",
+ "dependencies": {
+ "eslint": "~5.10.0"
+ },
+ "devDependencies": {
+ "jquery": "3.5.1",
+ "jquery-smooth-scroll": "2.2.0",
+ "jquery-ui": "1.12.1",
+ "jquery-ui-iconfont": "2.3.2",
+ "punycode": "1.4.1",
+ "qunit": "2.9.2",
+ "select2": "4.0.11",
+ "sinon": "2.0.0",
+ "tooltipster": "4.2.6",
+ "underscore": "1.9.1",
+ "web-ext": "~5.2.0"
+ },
+ "private": true
+}
diff --git a/release-utils/chromium-release.sh b/release-utils/chromium-release.sh
new file mode 100755
index 0000000..491d172
--- /dev/null
+++ b/release-utils/chromium-release.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+if [ $# -ne 3 ]; then
+ echo "$0 TAG KEY DESTINATION"
+ exit
+fi
+
+SUBDIR=checkout
+[ -d $SUBDIR ] && rm -rf $SUBDIR
+mkdir $SUBDIR
+cp -r -f -a .git $SUBDIR
+cd $SUBDIR
+git reset --hard "$1"
+
+# clean up
+# TODO duplicated in make-eff-zip.sh
+rm -rf src/tests # remove unit tests
+rm src/data/dnt-policy.txt # only used by unit tests
+cp LICENSE src/ # include LICENSE in build
+
+echo "Building chrome version" "$1"
+
+chromium --pack-extension="src/" --pack-extension-key="$2"
+cd -
+mv checkout/src.crx "$3"
+rm -rf checkout
diff --git a/release-utils/firefox-release.sh b/release-utils/firefox-release.sh
new file mode 100755
index 0000000..0242c6d
--- /dev/null
+++ b/release-utils/firefox-release.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+set -e
+cd "$(dirname "$0")"
+
+PKGDIR=../pkg
+
+# To make an Privacy Badger firefox release, signed with an offline key
+
+# 1. get the repo into a sane state for a release
+# 2. ensure that doc/Changelog approximately describes this release
+# 3. tag the release with "git tag -s <release version number>"
+# 4. run this script with <release version number> as the argument
+
+
+if [ $# -ne 1 ] ; then
+ echo "Usage: $0 <version to release>"
+ exit 1
+fi
+TARGET=$1
+
+
+if ! git show release-"$TARGET" > /dev/null 2> /dev/null ; then
+ echo "$TARGET is not a valid git target"
+ exit 1
+fi
+
+PKG=$PKGDIR/privacy-badger-eff-$TARGET.xpi
+ALT=$PKGDIR/privacy-badger-eff-latest.xpi
+
+if ! ./make-signed-xpi.sh "$TARGET" ; then
+ echo "Failed to build target $TARGET XPI"
+ exit 1
+fi
+
+if ! [ -f "$PKG" ] ; then
+ echo "Failed to find package $PKG after build"
+ exit 1
+fi
+
+# XXX: Why make a gpg detached sig?
+echo "Making (secondary) GPG signature"
+gpg --detach-sign "$PKG"
+
+cp "$PKG" "$ALT"
diff --git a/release-utils/make-eff-zip.sh b/release-utils/make-eff-zip.sh
new file mode 100755
index 0000000..e06be24
--- /dev/null
+++ b/release-utils/make-eff-zip.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+# make a release zip of Privacy Badger for opera and firefox
+# chrome releases happen in chromium-release.sh
+
+# this script takes a mandatory argument which is the git tag to build
+
+if [ -n "$1" ]; then
+ SUBDIR=checkout
+ [ -d $SUBDIR ] && rm -rf $SUBDIR
+ mkdir $SUBDIR
+ cp -r -f -a .git $SUBDIR
+ cd $SUBDIR
+ git reset --hard "$1"
+
+ # clean up
+ # TODO duplicated in chromium-release.sh
+ rm -rf src/tests # remove unit tests
+ rm src/data/dnt-policy.txt # only used by unit tests
+ cp LICENSE src/ # include LICENSE in build
+
+else
+ echo "Please supply a tag name for the release you are zipping"
+ exit 1
+fi
+
+
+echo "Building zip version" "$1"
+
+(cd src && zip -q -r ../privacy_badger-"$TARGET".zip .)
+mv privacy_badger*.zip ../pkg/
+cd -
diff --git a/release-utils/make-release-zip.sh b/release-utils/make-release-zip.sh
new file mode 100755
index 0000000..8010b1f
--- /dev/null
+++ b/release-utils/make-release-zip.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+# We use the immutable filesystem attribute as a workaround for the fact that
+# the build scripts are not currently idempotent.
+
+# The fact that the package is marked immutable means that it has been built
+# for release.
+
+if ! lsattr "$PREPKG" | cut -f 1 -d" " | grep -q i ; then
+
+ if [ -f "$PREPKG" ] ; then
+ echo "$PREPKG" is not immutable, rebuilding it for release!
+ else
+ echo building "$PREPKG" for the first time...
+ fi
+
+ if ! release-utils/make-eff-zip.sh "$GITTAG" ; then
+ echo "Failed to build target $GITTAG"
+ exit 1
+ fi
+
+ if ! [ -f "$PREPKG" -a -f "$PREPKGCWS" ] ; then
+ echo "Failed to find package $PREPKG after build"
+ exit 1
+ fi
+
+ # Verification and testing of build goes here!
+
+ echo Marking "$PREPKG" immutable...
+ if ! sudo true ; then
+ echo "Failed to sudo :("
+ exit 1
+ fi
+ if ! sudo chattr +i "$PREPKG" "$PREPKGCWS"; then
+ echo ""
+ echo "WARNING: FAILED TO MARK $PREPKG or $PREPKGCWS IMMUTABLE."
+ echo "DO NOT RERUN THIS SCRIPT AFTER SIGNING"
+ echo ""
+ read -p "(Press Enter to acknowledge)"
+ fi
+else
+ echo "$PREPKG is immutable; good, not rebuilding it..."
+fi
diff --git a/release-utils/make-release.sh b/release-utils/make-release.sh
new file mode 100755
index 0000000..4cda497
--- /dev/null
+++ b/release-utils/make-release.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+# To make a privacy badger release see wiki
+
+if [ $# -ne 1 ] ; then
+ echo "Usage: $0 <version to release>"
+ exit 1
+fi
+export TARGET=$1
+export GITTAG
+
+if ! [ -f ./release-utils/config.sh ] ; then
+ echo "Missing config file. Cannot continue."
+ exit 1
+fi
+source ./release-utils/config.sh
+
+
+if echo "$TARGET" | grep -q release- ; then
+ GITTAG=$TARGET
+ TARGET=$(echo "$TARGET" | sed s/release-//)
+else
+ GITTAG=release-$TARGET
+fi
+
+if ! git show "$GITTAG" > /dev/null 2> /dev/null ; then
+ echo "$GITTAG is not a valid git target"
+ exit 1
+fi
+
+export PREPKG=pkg/privacy_badger-$TARGET.zip
+export PREPKGCWS=pkg/privacy_badger-$TARGET.zip
+
+
+echo "Making Opera zip"
+if ! release-utils/make-release-zip.sh "$TARGET"; then
+ echo "Failed to build target $TARGET for Opera"
+ exit 1
+fi
+
+echo "Making Firefox release"
+if ! release-utils/firefox-release.sh "$TARGET"; then
+ echo "Failed to build target $TARGET for Firefox"
+ exit 1
+fi
+
+
+./release-utils/post-release.sh "$TARGET"
+
+rm -rf checkout
diff --git a/release-utils/make-signed-xpi.sh b/release-utils/make-signed-xpi.sh
new file mode 100755
index 0000000..cf3fe73
--- /dev/null
+++ b/release-utils/make-signed-xpi.sh
@@ -0,0 +1,65 @@
+#!/bin/sh
+
+set -e
+
+cd "$(dirname "$0")"
+
+LATEST_SDK_VERSION=5.2.0
+WEB_EXT=../node_modules/.bin/web-ext
+
+# Auto-generated XPI name from 'web-ext sign'
+PRE_XPI_NAME=privacy_badger_by_eff-$TARGET-an+fx.xpi
+XPI_NAME="privacy-badger-eff-$1.xpi"
+AMO_ZIP_NAME="privacy_badger-$1.amo.zip"
+
+if ! type $WEB_EXT > /dev/null; then
+ echo "Please install web-ext before running this script."
+ exit 1
+fi
+
+if ! $WEB_EXT --version | grep -q "$LATEST_SDK_VERSION"; then
+ echo "Please use the latest stable web-ext version or edit this script to the current version."
+ exit 1
+fi
+
+if [ $# -ne 1 ]; then
+ echo "Usage: $0 <version to release>"
+ exit 1
+fi
+
+echo "changing author value"
+sed -i -e '/eff.software.projects@gmail.com/,+1d' -e 's/"author": {/"author": "privacybadger-owner@eff.org",/' ../checkout/src/manifest.json
+
+echo "removing Chrome's update_url"
+# remove update_url
+sed -i -e '/"update_url": "https:\/\/clients2.google.com\/service\/update2\/crx"/,+0d' ../checkout/src/manifest.json
+# fix the trailing comma
+# TODO fragile! at least we validate the JSON below
+# https://unix.stackexchange.com/a/26288
+# https://unix.stackexchange.com/a/26290
+sed -i -e '/"storage": {/{
+ n
+ n
+ s/},/}/
+}' ../checkout/src/manifest.json
+
+# lint the checkout folder
+$WEB_EXT lint -s ../checkout/src
+
+echo "making zip file for AMO"
+
+(cd ../checkout/src && rm -f ../../pkg/"$AMO_ZIP_NAME" && zip -q -r ../../pkg/"$AMO_ZIP_NAME" ./*)
+
+echo "insert self hosting package id"
+# Insert self hosted package id
+sed -i 's,"id": "jid1-MnnxcxisBPnSXQ@jetpack","id": "jid1-MnnxcxisBPnSXQ-eff@jetpack"\,\n "update_url": "https://www.eff.org/files/privacy-badger-updates.json",' ../checkout/src/manifest.json
+
+# lint checkout again as our modification above could have broken something
+# disable AMO-specific checks to allow applications.gecko.update_url
+$WEB_EXT lint -s ../checkout/src --self-hosted
+
+#"update_url": "https://www.eff.org/files/privacy-badger-updates.json"
+# Build and sign the XPI
+echo "Running web-ext sign"
+$WEB_EXT sign -s ../checkout/src --api-key "$AMO_API_KEY" --api-secret "$AMO_API_SECRET" -a ../pkg
+mv "../pkg/$PRE_XPI_NAME" "../pkg/$XPI_NAME"
diff --git a/release-utils/post-chrome-release.sh b/release-utils/post-chrome-release.sh
new file mode 100755
index 0000000..a751ef7
--- /dev/null
+++ b/release-utils/post-chrome-release.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+if ! [ -f ./release-utils/config.sh ] ; then
+ echo "Missing config file. Cannot continue."
+ exit 1
+fi
+source ./release-utils/config.sh
+
+if [ $# -ne 1 ] ; then
+ echo "Usage: $0 <version to release>"
+ exit 1
+fi
+TARGET=$1
+if ! git show release-"$TARGET" > /dev/null 2> /dev/null ; then
+ echo "$TARGET is not a valid git target"
+ exit 1
+fi
+
+PKGDIR=pkg
+CHROME_PKG=$PKGDIR/privacy_badger-"$TARGET".crx
+if ! [ -f "$CHROME_PKG" ] ; then
+ mv $PKGDIR/privacy-badger-"$TARGET".crx "$CHROME_PKG"
+fi
+CHROME_ALT=$PKGDIR/privacy_badger-chrome.crx
+echo "Uploading chrome package"
+cp "$CHROME_PKG" "$CHROME_ALT"
+echo Copying .crx files...
+scp "$CHROME_PKG" "$USER@$SERVER:/www/eff.org/files" || exit 1
+scp "$CHROME_ALT" "$USER@$SERVER:/www/eff.org/files" || exit 1
diff --git a/release-utils/post-release.sh b/release-utils/post-release.sh
new file mode 100755
index 0000000..4bfe00e
--- /dev/null
+++ b/release-utils/post-release.sh
@@ -0,0 +1,77 @@
+#!/bin/bash
+
+cd "$(dirname "$0")"
+source ./config.sh
+PKGDIR=../pkg
+if [ $# -ne 1 ] ; then
+ echo "Usage: $0 <version to release>"
+ exit 1
+fi
+TARGET=$1
+if ! git show release-"$TARGET" > /dev/null 2> /dev/null ; then
+ echo "$TARGET is not a valid git target"
+ exit 1
+fi
+PKG="$PKGDIR"/privacy-badger-eff-$TARGET.xpi
+ALT="$PKGDIR"/privacy-badger-eff-latest.xpi
+
+echo Copying .xpi files...
+scp "$PKG" "$USER@$SERVER:/www/eff.org/files" || exit 1
+scp "$ALT" "$USER@$SERVER:/www/eff.org/files" || exit 1
+echo Copying detached signature
+scp "$PKG".sig "$USER@$SERVER:/www/eff.org/files" || exit 1
+echo Copying Changelog.txt
+git show release-"$TARGET":doc/Changelog > /tmp/pbchangelog$$ || exit 1
+scp /tmp/pbchangelog$$ "$USER@$SERVER:/www/eff.org/files/pbChangelog.txt" || exit 1
+rm -f /tmp/changelog$$
+
+MSG=/tmp/email$$
+
+echo "Privacy Badger $TARGET has been released for all supported browsers." > $MSG
+echo "As always, you can get it from https://privacybadger.org/ or from your browser's add-on gallery." >> $MSG
+echo "" >> $MSG
+echo "Notable updates:" >> $MSG
+echo "" >> $MSG
+tail -n+5 ../doc/Changelog | sed '/^$/q' >> $MSG
+echo "For further details, consult our release notes on GitHub:" >> $MSG
+echo "https://github.com/EFForg/privacybadger/releases/tag/release-$TARGET" >> $MSG
+
+echo To send email to the mailing list...
+echo mutt -s "Privacy\ Badger\ version\ $TARGET\ released" privacybadger@eff.org '<' $MSG
+echo "Now please edit https://www.eff.org/files/privacy-badger-updates.json to include the following"
+echo ""
+echo "{"
+echo " \"version\": \"$TARGET\","
+echo " \"update_link\": \"https://eff.org/files/privacy-badger-eff-$TARGET.xpi\","
+echo " \"update_hash\": \"sha256:$(sha256sum "$PKG" | cut -c 1-64)\","
+echo " \"applications\": {"
+echo " \"gecko\": { \"strict_min_version\": \"52.0\" }"
+echo " }"
+echo "}"
+
+echo ""
+echo "AMO release notes:"
+echo ""
+echo "<ul>"
+tail -n+5 ../doc/Changelog | sed '/^$/q' | {
+ out=""
+ while IFS= read -r line; do
+ # changelog entries start with "*"
+ if [ "${line:0:1}" = "*" ]; then
+ # this is the first entry
+ if [ -z "$out" ]; then
+ out="<li>${line:2}"
+ else
+ out="$out</li>\n<li>${line:2}"
+ fi
+ # changelog entry continues
+ else
+ if [ -n "$line" ]; then
+ out="$out $line"
+ fi
+ fi
+ done
+ echo -e "$out</li>"
+}
+echo "</ul>"
+echo ""
diff --git a/scripts/chromedriver.sh b/scripts/chromedriver.sh
new file mode 100755
index 0000000..3bd55d6
--- /dev/null
+++ b/scripts/chromedriver.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+
+# stop on errors (nonzero exit codes), uninitialized vars
+set -eu
+
+TEMPFILE=$(mktemp)
+CHROME="$1"
+
+trap 'rm $TEMPFILE' EXIT
+
+# install the appropriate version of ChromeDriver
+chrome_version=$("$CHROME" --product-version | cut -d . -f 1-3)
+chromedriver_version_url=https://chromedriver.storage.googleapis.com/LATEST_RELEASE_"$chrome_version"
+chromedriver_version=$(wget "$chromedriver_version_url" -q -O -)
+echo "Setting up ChromeDriver version $chromedriver_version ..."
+chromedriver_url=https://chromedriver.storage.googleapis.com/"$chromedriver_version"/chromedriver_linux64.zip
+wget -q -O "$TEMPFILE" "$chromedriver_url"
+sudo unzip -q -o "$TEMPFILE" chromedriver -d /usr/local/bin/
+sudo chmod a+x /usr/local/bin/chromedriver
+
+# check that chromedriver is now present
+type chromedriver >/dev/null 2>&1 || {
+ echo "Failed to install ChromeDriver!"
+ exit 1
+}
diff --git a/scripts/convertpsl.py b/scripts/convertpsl.py
new file mode 100755
index 0000000..3cd78be
--- /dev/null
+++ b/scripts/convertpsl.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+# script based on
+# https://github.com/adblockplus/buildtools/blob/d090e00610a58cebc78478ae33e896e6b949fc12/publicSuffixListUpdater.py
+
+from __future__ import print_function
+
+import json
+import sys
+
+def convert(psl_text):
+ suffixes = {}
+
+ for line in psl_text:
+ line = line.rstrip()
+ if line.startswith('//') or '.' not in line:
+ continue
+ if line.startswith('*.'):
+ suffixes[line[2:]] = 2
+ elif line.startswith('!'):
+ suffixes[line[1:]] = 0
+ else:
+ suffixes[line] = 1
+
+ return suffixes
+
+
+if __name__ == '__main__':
+ with open(sys.argv[1], 'r+') as f:
+ psl = convert(f)
+ f.seek(0)
+ text = 'window.publicSuffixes = %s;' % (
+ json.dumps(psl, sort_keys=True, indent=2, separators=(',', ': '))
+ )
+ print(text, file=f)
+ f.truncate()
diff --git a/scripts/fix_placeholders.py b/scripts/fix_placeholders.py
new file mode 100755
index 0000000..e940dcc
--- /dev/null
+++ b/scripts/fix_placeholders.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python3
+
+import json
+
+from collections import OrderedDict
+from glob import glob
+
+SOURCE_LOCALE = 'src/_locales/en_US/messages.json'
+
+
+def fix_locale(locale, placeholder_keys):
+ # read in locale, preserving existing ordering
+ with open(locale, 'r') as f:
+ data = json.load(f, object_pairs_hook=OrderedDict)
+
+ # restore missing placeholders
+ for key in placeholder_keys:
+ if key in data and "placeholders" not in data[key]:
+ data[key]["placeholders"] = source_data[key]["placeholders"]
+
+ with open(locale, 'w') as f:
+ json.dump(data, f, ensure_ascii=False, indent=4)
+
+
+if __name__ == '__main__':
+ with open(SOURCE_LOCALE, 'r') as f:
+ source_data = json.load(f, object_pairs_hook=OrderedDict)
+
+ # get keys of locale messages with placeholders
+ placeholder_keys = []
+ for key in source_data:
+ if "placeholders" in source_data[key]:
+ placeholder_keys.append(key)
+
+ # fix all locales
+ for locale in glob('src/_locales/*/*.json'):
+ if locale == SOURCE_LOCALE:
+ continue
+
+ fix_locale(locale, placeholder_keys)
diff --git a/scripts/generate-legacy-yellowlist.sh b/scripts/generate-legacy-yellowlist.sh
new file mode 100755
index 0000000..b74712e
--- /dev/null
+++ b/scripts/generate-legacy-yellowlist.sh
@@ -0,0 +1 @@
+sed -e "s/^\([^\!].*\)$/@@||\1^\$third-party/g" src/data/yellowlist.txt
diff --git a/scripts/run_travis.sh b/scripts/run_travis.sh
new file mode 100755
index 0000000..fa20fdb
--- /dev/null
+++ b/scripts/run_travis.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+toplevel=$(git rev-parse --show-toplevel)
+testdir=${toplevel}/tests/selenium
+
+function run_lint {
+ if ! make -C "$toplevel" lint; then
+ echo "Linting errors"
+ exit 1
+ fi
+}
+
+function run_selenium {
+ # autodiscover and run the tests
+ pytest --capture=no --verbose --durations=10 "$testdir"
+}
+
+if [ "$INFO" == "lint" ]; then
+ echo "running lint tests"
+ run_lint
+else
+ case $BROWSER in
+ *chrome*)
+ echo "running tests on chrome"
+ run_selenium
+ ;;
+ *firefox*)
+ echo "running tests on firefox"
+ run_selenium
+ ;;
+ *)
+ echo "bad INFO variable, got $INFO"
+ exit 1
+ ;;
+ esac
+fi
diff --git a/scripts/setup_travis.sh b/scripts/setup_travis.sh
new file mode 100755
index 0000000..5e4bbf0
--- /dev/null
+++ b/scripts/setup_travis.sh
@@ -0,0 +1,79 @@
+#!/usr/bin/env bash
+
+# stop on errors (nonzero exit codes), uninitialized vars
+set -eu
+
+toplevel=$(git rev-parse --show-toplevel)
+
+function setup_firefox {
+ # Install the latest version of geckodriver
+ version=$(curl -sI https://github.com/mozilla/geckodriver/releases/latest | grep -i "^Location: " | sed 's/.*\///' | tr -d '\r')
+
+ # check that we got something
+ if [ -z "$version" ]; then
+ echo "Failed to determine the latest geckodriver version!"
+ exit 1
+ fi
+
+ # Geckodriver distribution is MacOS or Linux specific
+ os="$(uname -s)"
+ if [[ $os == "Darwin" ]]; then
+ os_dist="macos.tar.gz"
+ else
+ os_dist="linux64.tar.gz"
+ fi
+
+ echo "Setting up geckodriver version $version ..."
+ url="https://github.com/mozilla/geckodriver/releases/download/${version}/geckodriver-${version}-${os_dist}"
+ wget -q -O /tmp/geckodriver.tar.gz "$url"
+ sudo tar -xvf /tmp/geckodriver.tar.gz -C /usr/local/bin/
+ sudo chmod a+x /usr/local/bin/geckodriver
+
+ # check that geckodriver is now present
+ type geckodriver >/dev/null 2>&1 || {
+ echo "Failed to install geckodriver!"
+ exit 1
+ }
+}
+
+function browser_setup {
+ # install python stuff
+ pip install -r "$toplevel"/tests/requirements.txt
+}
+
+function setup_lint {
+ # "--production" to skip installing devDependencies modules
+ npm install --production || exit 1
+}
+
+# check that the desired browser is present as it might fail to install
+# for example: https://travis-ci.org/EFForg/privacybadger/jobs/362381214
+function check_browser {
+ type "$BROWSER" >/dev/null 2>&1 || {
+ echo "$BROWSER seems to be missing!"
+ exit 1
+ }
+
+ # print the version
+ echo "Found $("$BROWSER" --version)"
+}
+
+case $INFO in
+ *chrome*)
+ check_browser
+ "$toplevel"/scripts/chromedriver.sh "$BROWSER"
+ browser_setup
+ ;;
+ *firefox*) # Install the latest version of geckodriver
+ check_browser
+ setup_firefox
+ browser_setup
+ ;;
+ *lint*)
+ setup_lint
+ ;;
+ *)
+ echo "bad INFO variable, got $INFO"
+ exit 1
+ ;;
+esac
diff --git a/scripts/updategoogle.py b/scripts/updategoogle.py
new file mode 100755
index 0000000..a3046d4
--- /dev/null
+++ b/scripts/updategoogle.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+
+import json
+import sys
+
+from collections import OrderedDict
+
+def convert(text):
+ patterns = []
+ for domain in text.split():
+ patterns.append("https://www" + domain + "/*")
+ patterns.append("http://www" + domain + "/*")
+ return patterns
+
+def update_manifest(tempfile_path, manifest_path):
+ with open(manifest_path, 'r') as f:
+ manifest = json.load(f, object_pairs_hook=OrderedDict)
+
+ with open(tempfile_path, 'r+') as f:
+ # tempfile_path contains Google's supported domains
+ match_patterns = convert(f.read())
+
+ scripts_idx = -1
+ for idx, entry in enumerate(manifest['content_scripts']):
+ if "js/firstparties/google-search.js" in entry['js']:
+ scripts_idx = idx
+ break
+ if scripts_idx == -1:
+ print("Failed to locate the Google Search content script in the manifest!")
+ sys.exit(1)
+
+ manifest['content_scripts'][scripts_idx]['matches'] = match_patterns
+
+ # overwrite tempfile_path with the updated manifest
+ f.seek(0)
+ # print() auto-adds a trailing newline
+ print(
+ json.dumps(
+ manifest,
+ sort_keys=False,
+ indent=2,
+ separators=(',', ': ')
+ ),
+ file=f
+ )
+ f.truncate()
+
+if __name__ == '__main__':
+ # argv[1]: the path to a copy of https://www.google.com/supported_domains
+ # argv[2]: the path to the extension manifest
+ update_manifest(sys.argv[1], sys.argv[2])
diff --git a/scripts/updategoogle.sh b/scripts/updategoogle.sh
new file mode 100755
index 0000000..d446861
--- /dev/null
+++ b/scripts/updategoogle.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+# stop on errors (nonzero exit codes), uninitialized vars
+set -eu
+
+GOOGLE_DOMAINS_URL=https://www.google.com/supported_domains
+MANIFEST_PATH=src/manifest.json
+TEMPFILE=$(mktemp)
+
+trap 'rm $TEMPFILE' EXIT
+
+echo "fetching Google Search domains ..."
+if wget -q -T 30 -O "$TEMPFILE" -- $GOOGLE_DOMAINS_URL && [ -s "$TEMPFILE" ]; then
+ ./scripts/updategoogle.py "$TEMPFILE" "$MANIFEST_PATH"
+ if cmp -s "$TEMPFILE" $MANIFEST_PATH; then
+ echo " no Google Search domain updates"
+ else
+ cp "$TEMPFILE" $MANIFEST_PATH
+ echo " updated Google Search domains in $MANIFEST_PATH"
+ echo " please verify, update Google's MDFP list, and commit both!"
+ exit 1
+ fi
+else
+ echo " failed to fetch $GOOGLE_DOMAINS_URL"
+ echo " aborting build!"
+ exit 1
+fi
diff --git a/scripts/updatepsl.sh b/scripts/updatepsl.sh
new file mode 100755
index 0000000..fa91741
--- /dev/null
+++ b/scripts/updatepsl.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+# Update the Public Suffix List (psl)
+
+# stop on errors (nonzero exit codes), uninitialized vars
+set -eu
+
+PSL_PATH=src/lib/publicSuffixList.js
+PSL_URL=https://publicsuffix.org/list/public_suffix_list.dat
+TEMPFILE=$(mktemp)
+
+trap 'rm $TEMPFILE' EXIT
+
+echo "fetching Public Suffix List ..."
+if wget -q -T 30 -O "$TEMPFILE" -- $PSL_URL && [ -s "$TEMPFILE" ]; then
+ python scripts/convertpsl.py "$TEMPFILE"
+ if cmp -s "$TEMPFILE" $PSL_PATH; then
+ echo " no PSL updates"
+ else
+ cp "$TEMPFILE" $PSL_PATH
+ echo " updated PSL at $PSL_PATH"
+ echo " please verify and commit!"
+ exit 1
+ fi
+else
+ echo " failed to fetch PSL from $PSL_URL"
+ echo " aborting build!"
+ exit 1
+fi
diff --git a/scripts/updateseeddata.sh b/scripts/updateseeddata.sh
new file mode 100755
index 0000000..bb1d221
--- /dev/null
+++ b/scripts/updateseeddata.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+# Update the pre-trained "seed" tracker list
+
+# stop on errors (nonzero exit codes), uninitialized vars
+set -eu
+
+SEED_PATH=src/data/seed.json
+SEED_URL=https://raw.githubusercontent.com/EFForg/badger-sett/master/results.json
+TEMPFILE=$(mktemp)
+
+trap 'rm $TEMPFILE' EXIT
+
+echo "fetching seed tracker lists..."
+if wget -q -T 30 -O "$TEMPFILE" -- $SEED_URL && [ -s "$TEMPFILE" ]; then
+ if ! python scripts/verify_json.py "$TEMPFILE"; then
+ echo " new seed data is not formatted correctly"
+ echo " aborting build!"
+ exit 1
+ fi
+
+ if cmp -s "$TEMPFILE" $SEED_PATH; then
+ echo " no seed data updates"
+ else
+ cp "$TEMPFILE" $SEED_PATH
+ echo " updated seed data at $SEED_PATH"
+ echo " please verify and commit!"
+ exit 1
+ fi
+else
+ echo " failed to fetch seed data from $SEED_URL"
+ echo " aborting build!"
+ exit 1
+fi
diff --git a/scripts/verify_json.py b/scripts/verify_json.py
new file mode 100644
index 0000000..e5a17ac
--- /dev/null
+++ b/scripts/verify_json.py
@@ -0,0 +1,18 @@
+#!/usr/bin/env python3
+
+import json
+import sys
+
+KEYS = set(['snitch_map', 'action_map', 'version'])
+
+with open(sys.argv[1]) as f:
+ try:
+ js = json.load(f)
+ if set(js.keys()) == KEYS:
+ sys.exit(0)
+ else:
+ print("json keys %s are not correct" % js.keys())
+ sys.exit(1)
+ except Exception as e:
+ print("error parsing json:", e)
+ sys.exit(1)
diff --git a/src/_locales/ar/messages.json b/src/_locales/ar/messages.json
new file mode 100644
index 0000000..4c424d3
--- /dev/null
+++ b/src/_locales/ar/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "$DOMAIN$ محجوب",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "ملف JSON غير سليم.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "أمتأكد أنك تريد إزالة النطاق من «غرير الخصوصية»",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "لا تَعقب للنطاق $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "حاليا «غرير الخصوصية» لا يتحقق إلا من كون الأطراف الخارجية تستخدم الكعكات، أو تخزين HTML5 المحلي، أو بصمات مساحة الرسم لتعقب تصفحك. ربما تستخدم بعض هذه النطاقات طرقًا أخرى لا يستطيع «غرير الخصوصية» اكتشافها.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "تحقق من كون <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>نطاقات الأطراف الخارحية</a> تلتزم <a target='_blank' href='https://www.eff.org/dnt-policy'>سياسة EFF لعدم التعقب</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "رجاء أضف مسارا أو نطاقا صحيحا.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "تبرع إلى EFF",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "ساعدنا بالتبرع ونشر دعمك لأدواتنا",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "لست حاجبًا للإعلانات، أنا مختلف",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "شكرا، سنفحص الأمر.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "يعِد هذا النطاق بألا يتعقبك",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Blocking this domain is known to break websites",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Click to return control of this domain to Privacy Badger",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "القسم التالي",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "رجاء <a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>أخبرنا</a> بتفاصيل العطل التالي:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "أدِر البيانات",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "أبلغ عن عطل",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "مثلا: www.domain.com، أو ‪*.domain.net‬، أو domain.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "انقر هنا لحجب هذا النطاق من إضافة كعكات",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "المحجوب",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "امنع WebRTC من تسريب عناوين الإنترنت المحلية",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "يتعلم «غرير الخصوصية» تلقائيا كيف يحجب المتعقبات الخفية. خذ دقيقة من وقتك لتعرف كيف يحدث هذا.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "ما المشكلة؟",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "النطاقات المتعقِّبة",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "شارك على تويتر",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "تعرف كيف يحمي «غرير الخصوصية» خصوصيتك",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "نزّل",
+ "description": ""
+ },
+ "import": {
+ "message": "استورد",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "Don't replace the following widgets:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Enable widget replacement",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Show domains that don't appear to be tracking you",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "أرسل العطل",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "$DOMAIN$ غير محجوب",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "ما «غرير الخصوصية»؟",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "ابحث في النطاقات:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Learn to block new trackers from your browsing",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Enabling learning may make you more identifiable to websites",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "تعلم في نوافذ التصفح الخاص",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "تفعيل التعلم في نوافذ التصفح الخاص قد يترك آثارا لتأريخ تصفحك الخاص على حاسوبك. مبدئيا سيحجب «غرير الخصوصية» المتعقبات التي يعرفها من قبل في نوافذ التصفح الخاص، لكنه لن يتعلم أي متعقبات جديدة. قد تريد تفعيل هذا الخيار إن كان الكثير من تصفحك في نوافذ خاصة.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger will no longer learn from your browsing by default.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Click below to learn more.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Learn how Privacy Badger is changing",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Show count of trackers",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "ما المتعقب؟",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "رجاء لا تنس النقر على ”هل أفسد «غرير الخصوصية» هذا الموقع“. لأننا نحترم خصوصيتك لا نرسل أي بلاغات تلقائية.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "خيارات «غرير الخصوصية»",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "This will automatically send the following information to EFF: the page you're currently visiting, your browser version, the version of Privacy Badger, and the state of all of the sliders on this page.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "المواقع غير المفعلة",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "فعّل «غرير الخصوصية» على هذا الموقع",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "رشّح بالنوع:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "حُدثت قائمة المتعقبات و إعداداتها بنجاح.",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "صدّر بيانات المستخدم",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "استيراد بيانات المستخدم: <ul><li>يكتب فوق قيم الإعدادات العامة</li><li>يدمج قوائم المواقع غير المفعلة</li><li>يدمج معلومات المتعقبات التي رآها «غرير الخصوصية»</li><li>يكتب فوق إعدادات المواقع</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "أعِد إلى الأصل",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "أعِد النطاقات المتعقِّبة إلى أصلها",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "إعادة النطاقات المتعقِّبة إلى أصلها:\n\n • سيحذف كل البيانات التي تعلمها «غرير الخصوصية» عن هذه النطاقات أثناء تصفحك\n • سيعيد قائمة النطاقات المتعقِّبة إلى آخر قائمة قبل التعلم (زر www.eff.org/badger-pretraining لمزيد من المعلومات)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "أزل الكل",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "أزل كل النطاقات المتعقِّبة",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "إزالة كل النطاقات المتعقِّبة:\n\n • سيحذف كل ما يعرفه «غرير الخصوصية» عن المتعقبات\n • سيمنع «غرير الخصوصية» من حجب أي شيء إلى أن يعيد التعلم من تصفحك",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "يحميك «غرير الخصوصية» الآن.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "انقر أدناه لتطلع أكثر على كيف يعمل.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "يمكن أن يسرب WebRTC عنواوين الإنترنت (IP) المحلية. لاحظ أن تفعيل هذا الخيار قد يقلل من أداء برمجيات الاجتماعات على الوب مثل Google Hangouts.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "الإعدادات العامة",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Privacy",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Advanced",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "خذ جولة",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "انقر هنا لحجب هذا النطاق تماما",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "إصدارة $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "الكعكات محجوبة من النطاق $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "المحجوب جزئيا",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "أفهم هذا؛ أرني رجاء قائمة المتعقبات",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "شكرا على تنصيب «غرير الخصوصية»",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "رجاء اختر ملفا لاستيراده",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "هل أفسد «غرير الخصوصية» هذا الموقع؟ أعلمنا بهذا.",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "وسط المؤشر لحجب الكعكات",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Learns automatically",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Instead of keeping lists of what to block, Privacy Badger automatically discovers trackers based on their behavior.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "يمسك بالمتعقبات المتخفية",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Invisible tracking happens in all sorts of ways; ads are just the visible tip of the iceberg. Privacy Badger sends the <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control signal</a>, to opt you out of data sharing and selling, and the <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track signal</a> to tell companies not to track you. If they ignore your wishes, Privacy Badger will learn to block them—whether they are advertisers or trackers of other kinds.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "أغلق",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "استورد بيانات المستخدم",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "متوافق مع ”لا تتعقبني“",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "مساعدة",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "المسموح به",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "الخصوصية رياضة جماعية",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "يفترض ألا تحتاج لتغيير أي شيء هنا.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "الكل",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "ألغ",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "حرك المؤشر شمالا لحجب النطاق",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Send websites the \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" and \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\" signals",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Disable sending web addresses you visit to Google. This disables suggestions for similar pages when a page can't be found.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Disable hyperlink auditing",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "تحت تحكم المستخدم",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is disabled on the following sites. This means that Privacy Badger will not block anything when you visit the sites listed here, and it will not send the Do Not Track or Global Privacy Control signals.</p><p>If you think Privacy Badger is breaking a page, or you would like to allow a particular site to share or sell your data, you can type that page's domain in the box below and click the \"Add domain\" button.</p><p>Alternatively, when you already have the page's tab selected, you can just click on Privacy Badger's button in the browser toolbar and then click the \"Disable\" button.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ potential $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "No $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "There are no third party resources on this page. Hooray for privacy!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "مشروع من مؤسسة الجبهة الإلكترونية (Electronic Frontier Foundation)",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "أضف النطاق",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "حرك المؤشر يمينا للسماح بالنطاق",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "عطّل «غرير الخصوصية» على هذا الموقع",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "انقر هنا للسماح بهذا النطاق",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "لن يشارك «غرير الخصوصية» أبدا أي معلومات عن تصفحك إلا إن اخترت أن تشاركها.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger has decided to block $COUNT$ potential $TRACKER_LINK_START$tracking domains$TRACKER_LINK_END$ so far",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "لم يكتشف «غرير الخصوصية» أي <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>نطاقات متعقِّبة</a> حتى الآن. واصل تصفحك.",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "«غرير الخصوصية»",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "يبدأ «غرير الخصوصية» في الحجب ما إن يرى نفس المتعقب على ثلاثة مواقع مختلفة. ثلاث فرص ثم يخرج!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "رشّح بالحالة:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "صف العطل باختصار أدناه.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "أزل المحدد",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "باستخدامك «غرير الخصوصية» تنضم إلى <a href='https://www.eff.org/' target='_blank'>مؤسسة الجبهة الإلكترونية</a> و ملايين المستخدمين في قتالهم من أجل الخصوصية. نحن مؤسسة غير ربحية نقاتل لحقوقك على الإنترنت. شكرًا لانضمامك إلينا.",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "لاستبعاد النطاقات، ضع ”-“ قبل عبارة البحث. فمثلا، ”‪.co -.com‬“ ستظهر نطاقات ‪.co‬ و ‪.co.uk‬ لكن لن تظهر نطاقات ‪.com‬ في نتائج البحث.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "إذا كنت تظن أن «غرير الخصوصية» يفسد إحدى الصفحات (الفديو لا يعمل مثلا)، فيمكنك النقر على زر ’عطّل‘ لتعطيل «غرير الخصوصية» على هذا الموقع.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "سياسة الخصوصية",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "الوصف",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Your Badger hasn't decided yet if these domains should get blocked",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Show domains your Badger hasn't decided yet to block:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "لا يظهر أن النطاقات التالية تتعقبك",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "الخيارات",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "شارك على فيسبوك",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "يتعلم «غرير الخصوصية» تلقائيا أن يحجب المتعقبات الخفية.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "حدث عطل ما.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "استبدل «غرير الخصوصية» زر $BUTTON$ هذا",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger has replaced this $WIDGET$ widget",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Allow once",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Always allow on this site",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "مزامنة السحاب:<ul><li>تحتاج إلى مزامنة فيرفكس\\كروم</li><li>الرفع يكتب فوق أي بيانات ل‍«‍غرير الخصوصية» موجودة على السحاب.</li><li>التنزيل يدمج قائمة المواقع التي عطلت عليها «غرير الخصوصية»</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "ارفع",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "صدّر المواقع غير المفعلة إلى السحاب",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "استورد المواقع غير المفعلة من السحاب",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "تم استيراد البيانات من السحاب.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "تعذّر تنزيل البيانات.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "تم رفع البيانات.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "تعذّر رفع البيانات.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "لم تنزّل أي بيانات من السحاب.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "أخبر أصدقائك",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "شارك",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger blocked $COUNT$ potential trackers on $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "«غرير الخصوصية» (www.eff.org/privacybadger) هو امتداد للمتصفح يتعلم تلقائيا أن يحجب المتعقبات الخفية. «غرير الخصوصية» من مؤسسة الجبهة الإلكترونية، و هي منظمة غير ربحية تقاتل لحقوقك على الإنترنت.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "انسخ إلى الحافظة",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "نُسِخ",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Nothing to do on this page",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger doesn't work on special pages like this one. Try browsing somewhere else.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger is disabled on this site",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Widget Replacement",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "When blocking social buttons and other potentially useful (video, audio, comments) widgets, Privacy Badger can replace them with click-to-activate placeholders.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/bg/messages.json b/src/_locales/bg/messages.json
new file mode 100644
index 0000000..b7edfd0
--- /dev/null
+++ b/src/_locales/bg/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "Блокирах $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "Невалиден JSON файл.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Сигурен ли си, че искаш да премахнеш този домейн от Privacy Badger?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "Няма преследвачи в $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "Засега Privacy Badger проверява само дали трети страни ползват бисквитки, локалната памет на HTML5, или canvas fingerprinting, за да те следят. Някои от тези домейни може би използват други начини за следене, които Privacy Badger не може да засече.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "Проверявай дали <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>домейните от трети страни</a> се съобразяват с <a target='_blank' href='https://www.eff.org/dnt-policy'>Do Not Track (Не ме следи) политиката на EFF</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Моля добави валиден домейн или URL.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "Подкрепи EFF",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Помогни ни с дарение или като споделиш подкрепата си за инструментите ни",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "Не съм блокирач на реклами. Аз съм малко по-различен",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "Мерси! Ще разнищим проблема.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "Този домейн обещава да не те следи",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Blocking this domain is known to break websites",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Click to return control of this domain to Privacy Badger",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "следваща част",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "Моля те <a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>кажи ни</a> за следната грешка:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Управление на данни",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Докладвай за грешка",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "например www.domain.com, *.domain.net, domain.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Щракни тук, за да забраниш на този домейн да оставя бисквитки",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "блокирани",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "Спри изтичането на локалния ти IP адрес през WebRTC",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger автоматично се научава да блокира невидими преследвачи. Отдели си минутка, за да видиш как.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "Какво не е наред?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Домейни-преследвачи",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Сподели в Twitter",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Научи как Privacy Badger защитава личното ти пространство и поверителност",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "Дръпни",
+ "description": ""
+ },
+ "import": {
+ "message": "Импортирай",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "Don't replace the following widgets:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Enable widget replacement",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Show domains that don't appear to be tracking you",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Изпрати грешката",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "Разреших $DOMAIN$",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "Какво е Privacy Badger?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Търси в домейните:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Learn to block new trackers from your browsing",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Enabling learning may make you more identifiable to websites",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Учи се в Поверителни/Инкогнито прозорци",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "Ако позволиш ученето в Поверителни/Инкогнито прозорци, това може да остави на компютъра ти следи от историята, докато си сърфирал поверително. По подразбиране Privacy Badger ще блокира в Поверителните/Инкогнито прозорци преследвачите, за които вече знае, но няма да се учи за нови преследвачи. Би било полезно да включиш тази настройка, ако сърфираш редовно в Поверителни/Инкогнито прозорци.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger will no longer learn from your browsing by default.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Click below to learn more.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Learn how Privacy Badger is changing",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Show count of trackers",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "Какво е преследвач?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "Моля те не забравай да щракнеш на \"Развали ли Privacy Badger този сайт\". Уважаваме личното ти пространство, така че не изпращаме автоматични доклади.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Настройки на Privacy Badger",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "This will automatically send the following information to EFF: the page you're currently visiting, your browser version, the version of Privacy Badger, and the state of all of the sliders on this page.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Сайтове-изключения",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Включи Privacy Badger за този сайт",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Филтрирай според вид:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "Списъкът с преследвачи и опциите бяха променени успешно!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Експортирай потребителските данни",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "Импортирането на потребителски данни:<ul><li>Презаписва общите настройки</li><li>Слива списъците със сайтове-изключения</li><li>Слива информацията за това кои преследвачи е виждал Privacy Badger</li><li>Презаписва персонализирането на плъзгачите</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Започни отначало",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Започни отначало с домейните-преследвачи",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Започването отначало с домейните-преследвачи ще:\n\n • Изтрие всички данни за преследвачи, които Privacy Badger е научил от твоето сърфиране\n • Възвърне списъка на домейните-преслевдачи към най-новия предварително трениран списък (посети www.eff.org/badger-pretraining, за да научиш повече)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Премахни всички",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Премахни всички домейни-преследвачи",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "Премахването на всички домейни-преследвачи ще:\n\n • Изтрие всичко, което Privacy Badger знае за преследвачите\n • Накара Privacy Badger да не блокира нищо, докато не успее да се научи наново от твоето сърфиране",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "Privacy Badger вече те защитава.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "За да разбереш как работи Privacy Badger, щракни долу, за да ти обясни набързо.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "През WebRTC може да изтече локалния ти IP адрес. Имай предвид, че включването на тази опция може да забави някои апове за разговори, като например Google Hangouts.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "Общи настройки",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Privacy",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Advanced",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Обясни ми набързо",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Щракни тук, за да блокираш този домейн напълно",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "версия $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "Блокирах бисквитки от $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "частично блокирани",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "Разбирам; покажи ми все пак домейните-преследвачи",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Благодаря, че инсталира Privacy Badger!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "Моля избери файл за импорт.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "Развали ли Privacy Badger този сайт? Уведоми ни!",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Премести плъзгача в средата, за да блокираш бисквитките",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Learns automatically",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Instead of keeping lists of what to block, Privacy Badger automatically discovers trackers based on their behavior.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Хващам подмолни преследвачи",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Invisible tracking happens in all sorts of ways; ads are just the visible tip of the iceberg. Privacy Badger sends the <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control signal</a>, to opt you out of data sharing and selling, and the <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track signal</a> to tell companies not to track you. If they ignore your wishes, Privacy Badger will learn to block them—whether they are advertisers or trackers of other kinds.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Затвори",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Импортирай потребителски данни",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "съобразяващи се с DNT",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Помощ",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "разрешени",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "Личното пространство е отборна игра!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "Не би трябвало да се налага да променяш каквото и да е тук.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "всички",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "Откажи",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Премести плъзгача наляво, за да блокираш домейн",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Send websites the \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" and \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\" signals",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Disable sending web addresses you visit to Google. This disables suggestions for similar pages when a page can't be found.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Disable hyperlink auditing",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "контролирани от теб",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is disabled on the following sites. This means that Privacy Badger will not block anything when you visit the sites listed here, and it will not send the Do Not Track or Global Privacy Control signals.</p><p>If you think Privacy Badger is breaking a page, or you would like to allow a particular site to share or sell your data, you can type that page's domain in the box below and click the \"Add domain\" button.</p><p>Alternatively, when you already have the page's tab selected, you can just click on Privacy Badger's button in the browser toolbar and then click the \"Disable\" button.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ potential $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "No $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "There are no third party resources on this page. Hooray for privacy!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Един проект на Electronic Frontier Foundation",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Добави домейн",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Премести плъзгача надясно, за да разрешиш домейн",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Изключи Privacy Badger за този сайт",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Щракни тук, за да разрешиш този домейн",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privacy Badger НИКОГА няма да споделя данни за сърфирането ти, освен ако ти не решиш да ги споделиш.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger has decided to block $COUNT$ potential $TRACKER_LINK_START$tracking domains$TRACKER_LINK_END$ so far",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privacy Badger досега не е открил <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>домейни-преследвачи</a>. Продължавай да си сърфираш!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger започва да блокира, когато види един и същ преследвач на три различни сайта. Три картона и е аут!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Филтрирай според настройка:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Опиши накратко грешката по́ долу.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Премахни избраните",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "Когато използваш Privacy Badger, се присъединяваш към <a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundation</a> и милиони други потребители в борбата за лично пространство и поверителност. Ние сме сдружение с непарична цел, което се бори за онлайн правата ти. Благодаря, че си с нас!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "За да изключиш домейни от търсенето, започни с \"-\". Например: \".co -.com\" ще покаже домейни с .co и .co.uk, но не и .com.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Ако смяташ, че Privacy Badger е развалил страница (например не върви видео клип), можеш да щракнеш на бутона \"Изключи\", за да изключиш Privacy Badger за този сайт.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Политика за поверителност",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Описание",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Your Badger hasn't decided yet if these domains should get blocked",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Show domains your Badger hasn't decided yet to block:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "Домейните по́ долу не изглеждат сякаш те следят",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Настройки",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Сподели във Facebook",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privacy Badger автоматично се научава да блокира невидими преследвачи.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "Опа. Нещо се обърка.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "Privacy Badger замени този $BUTTON$ бутон",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger has replaced this $WIDGET$ widget",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Разреши веднъж",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Разрешаване винаги на този сайт",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Синхронизацията с облака:<ul><li>Изисква Firefox/Chrome Синхронизация</li><li>Качването презаписва всички съществуващи в облака данни на Privacy Badger</li><li>Дърпането слива списъците със сайтове, на които язовеца ти е изключен</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Качи",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Експортирай сайтовете-изключения в облака",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Импортирай сайтовете-изключения от облака",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Импортирах успешно данните от облака.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "Не успях да дръпна данните от облака.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "Качих успешно данните в обалака.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "Не успях да кача данните в облака.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "В облака няма данни за дърпане.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Кажи на приятелите си",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Сподели",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger blocked $COUNT$ potential trackers on $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privacy Badger (www.eff.org/privacybadger) е разширение за браузер, което автоматично се научава да блокира невидими преследвачи. Privacy Badger е направен от Electronic Frontier Foundation, организация с нестопанска цел, която се бори за твоите онлайн права.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "Копирай в клипборда",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Копирах",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Nothing to do on this page",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger doesn't work on special pages like this one. Try browsing somewhere else.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger is disabled on this site",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Widget Replacement",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "When blocking social buttons and other potentially useful (video, audio, comments) widgets, Privacy Badger can replace them with click-to-activate placeholders.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/ca/messages.json b/src/_locales/ca/messages.json
new file mode 100644
index 0000000..790c4b3
--- /dev/null
+++ b/src/_locales/ca/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "S'ha blocat $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "Arxiu JSON no vàlid",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Segur que voleu treure aquest domini de Privacy Badger?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "El domini $DOMAIN$ no fa seguiments",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "Ara mateix, Privacy Badger només comprova si terceres parts estan utilitzant galetes, emmagatzematge local d'HTML5 o el marcat del llenç per fer seguiments del vostre navegador. Alguns d'aquests dominis poden utilitzar mètodes de seguiment que Privacy Badger no pot detectar.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "Comproveu si els <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>dominis de terceres parts</a> compleixen amb la <a target='_blank' href='https://www.eff.org/dnt-policy'>política d'EFF de no seguiment</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Si us plau, afegiu un domini vàlid o un URL",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "Feu un donatiu a EFF",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Ajudeu-nos fent un donatiu i compartint el vostre suport per les nostres eines",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "No bloco anuncis, sóc diferent",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "Gràcies! Arribarem al fons d'això.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "Aquest domini promet no seguir-vos",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Blocking this domain is known to break websites",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Click to return control of this domain to Privacy Badger",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "següent secció",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "Si us plau, <a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>expliqueu-nos</a> alguna cosa sobre el següent error:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Gestió de dades",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Informeu d'un error",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "p. ex. www.domini.com, *.domini.net, domini.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Cliqueu aquí per blocar les galetes d'aquest domini",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "blocat",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "Impediu que el WebRTC filtri una adreça IP local",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger aprèn automàticament a blocar rastrejadors invisibles. Deixeu-nos un minut per ensenyar-vos com.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "Què ha fallat?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Dominis de seguiment",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Compartiu-lo a Twitter",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Apreneu com Privacy Badger protegeix la vostra privacitat",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "Descarregar",
+ "description": ""
+ },
+ "import": {
+ "message": "Importar",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "No reemplaçar els ginys següents:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Habilita el reemplaçament de ginys",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Mostra els dominis que, aparentment, no us segueixen",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Enviar Errada",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "Permès $DOMAIN$",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "Què és Privacy Badger?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Cerca de dominis:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Learn to block new trackers from your browsing",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Enabling learning may make you more identifiable to websites",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Aprendre en finestres Privades/Incògnit",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "Habilitant l'aprenentatge en finestres Privades/Incògnit, podeu deixar traces a l'historial privat de navegació del vostre ordinador. Per defecte, Privacy Badger blocarà els rastrejadors coneguts a les finestres Privades/Incògnit, però no aprendrà sobre nous rastrejadors. Cal que habiliteu aquesta opció si la majoria de la vostra navegació la feu en finestres Privades/Incògnit",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger will no longer learn from your browsing by default.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Click below to learn more.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Learn how Privacy Badger is changing",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Mostra el comptador de rastrejadors",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "Què és un rastrejador?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "Si us plau, no us oblideu de clicar a 'El Privacy Badger ha espatllat aquest lloc'. Respectem tant la vostra privacitat que no enviem informes de forma automàtica.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Opcions de Privacy Badger",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "This will automatically send the following information to EFF: the page you're currently visiting, your browser version, the version of Privacy Badger, and the state of all of the sliders on this page.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Llocs deshabilitats",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Habilita el Privacy Badger per aquest lloc",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Filtra per tipus:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "La llista i la configuració del rastrejador s'ha actualitzat correctament!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Exporta les dades d'usuari",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "Si importeu les dades d'usuari: <ul><li>Sobreescriureu la configuració general</li><li>Fusionareu les llistes de llocs deshabilitats</li><li>Fusionareu la informació sobre els rastrejadors que Privacy Badger ha vist</li><li>Sobreescriureu la personalització dels lliscadors</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Restablir",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Restablir els dominis de seguiment",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Restablint els dominis de seguiment:\n\n • Esborrareu totes les dades que el Privacy Badger hagi après sobre rastrejadors durant la vostra navegació\n • Restaurareu la llista de dominis de seguiment a la llista d'abans de començar a aprendre (visiteu www.eff.org/badger-pretraining per saber-ne més)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Eliminar-ho tot",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Eliminar tots els dominis de seguiment",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "Eliminant tots els dominis de seguiment:\n\n • Esborrareu tot el que Privacy Badger sap sobre els rastrejadors\n • Provocareu que Privacy Badger no bloqui res fins que hagi tornat a aprendre amb la vostra navegació",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "Ara el Privacy Badger ja us protegeix.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "Per saber com treballa el Privacy Badger, cliqueu aquí baix i seguiu la guia ràpida.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC pot filtrar la vostra IP local. Teniu en compte que aquesta opció pot degradar el rendiment d'aplicacions de videoconferència com Google Hangouts.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "Configuració general",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Privacy",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Advanced",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Feu la visita guiada",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Cliqueu aquí per blocar completament aquest domini",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "versió $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "S'han blocat les galetes de $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "blocat parcialment",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "Ho entenc; si us plau, mostra'm igualment el llistat de dominis de seguiment",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Gràcies per instal·lar el Privacy Badger!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "Si us plau, seleccioneu l'arxiu a importar",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "El Privacy Badger ha espatllat aquest lloc? Feu-nos-ho saber!",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Centreu el lliscador per blocar les galetes",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Learns automatically",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Instead of keeping lists of what to block, Privacy Badger automatically discovers trackers based on their behavior.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Captura rastrejadors furtius",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Invisible tracking happens in all sorts of ways; ads are just the visible tip of the iceberg. Privacy Badger sends the <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control signal</a>, to opt you out of data sharing and selling, and the <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track signal</a> to tell companies not to track you. If they ignore your wishes, Privacy Badger will learn to block them—whether they are advertisers or trackers of other kinds.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Tanca",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Importa dades d'usuari",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "respecta el No Em Seguiu",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Ajuda",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "permès",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "La privacitat és un esport d'equip!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "Aquí no hauria de ser necessari modificar res",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "tot",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "Cancel·la",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Moveu el lliscador a l'esquerra per blocar el domini",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Send websites the \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" and \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\" signals",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Disable sending web addresses you visit to Google. This disables suggestions for similar pages when a page can't be found.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Disable hyperlink auditing",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "controlat per l'usuari",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is disabled on the following sites. This means that Privacy Badger will not block anything when you visit the sites listed here, and it will not send the Do Not Track or Global Privacy Control signals.</p><p>If you think Privacy Badger is breaking a page, or you would like to allow a particular site to share or sell your data, you can type that page's domain in the box below and click the \"Add domain\" button.</p><p>Alternatively, when you already have the page's tab selected, you can just click on Privacy Badger's button in the browser toolbar and then click the \"Disable\" button.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ potential $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "No $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "There are no third party resources on this page. Hooray for privacy!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Un projecte de l'Electronic Frontier Foundation",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Afegeix domini",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Moveu el lliscador a la dreta per permetre un domini",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Deshabiliteu el Privacy Badger en aquest lloc",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Cliqueu aquí per permetre aquest domini",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "El Privacy Badger MAI compartirà dades sobre la vostra navegació, excepte si decidiu compartir-les.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger has decided to block $COUNT$ potential $TRACKER_LINK_START$tracking domains$TRACKER_LINK_END$ so far",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "El Privacy Badger encara no ha detectat cap <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>domini de seguiment</a>. Seguiu navegant!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger comença a blocar un cop veu el mateix rastrejador en tres llocs web diferents. Tres strikes i eliminat! Com al beisbol.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Filtrar per estat:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Descriviu breument l'errada a sota.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Treu els seleccionats",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "Quan utilitzeu el Privacy Badger, us uniu a l'<a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundation</a> i milions de persones en la lluita per la privacitat. Som una entitat sense ànim de lucre lluitant pels vostres drets en línia. Gràcies per unir-vos a nosaltres!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "Per excloure dominis, utilitzeu el caràcter \"-\". Per exemple, si cerqueu \".co -.com\" us mostrarà els dominis .co i .co.uk, però no us mostrarà el domini .com",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Si penseu que el Privacy Badger ha espatllat una pàgina (un vídeo que no es veu, per exemple), podeu clicar el botó 'Deshabilita' perquè el Privacy Badger no controli el lloc.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Política de privacitat",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Descripció",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Your Badger hasn't decided yet if these domains should get blocked",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Show domains your Badger hasn't decided yet to block:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "Els dominis de sota, aparentment, no us segueixen.",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Opcions",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Compartiu-ho a Facebook",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "El Privacy Badger aprèn automàticament a blocar rastrejadors invisibles.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "Ai! Alguna cosa no ha anat bé.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "El Privacy Badger ha substituït aquest botó de $BUTTON$",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger has replaced this $WIDGET$ widget",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Permetre-ho un cop",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Permet sempre en aquest lloc",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Sincronització al núvol: <ul><li>Requereix Firefox/Chrome Sync</li><li>La càrrega sobreescriu qualsevol dada del Privacy Badger existent al núvol</li><li>La descàrrega fusiona les llistes dels llocs que heu deshabilitat al teixó (Badger)</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Carrega",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Exporta els llocs deshabilitats al núvol",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Importa els llocs deshabilitats del núvol",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Les dades del núvol s'han importat correctament.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "Les dades del núvol no s'han pogut descarregar.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "S'han carregat les dades al núvol correctament.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "Les dades no s'han pogut carregar al núvol.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "Al núvol no hi ha dades per descarregar.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Expliqueu-ho a les vostres amistats",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Compartiu",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger blocked $COUNT$ potential trackers on $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "El Privacy Badger (www.eff.org/privacybadger) és una extensió del navegador que aprèn automàticament a blocar rastrejadors invisibles. El Privacy Badger l'ha creat l'Electronic Frontier Foundation, una entitat sense ànim de lucre que lluita pels vostres drets en línia.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "Copia-ho al porta-retalls",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Copiat",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "En aquesta pàgina no hi ha res a fer",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger no funciona en pàgines especials com aquesta. Proveu de navegar per altres llocs.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "En aquest lloc, el Privacy Badger està deshabilitat",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Reemplaçament de ginys",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "Quan es bloquegen els botons de les xarxes socials i altres ginys (vídeo, àudio, comentaris) habituals, el Privacy Badger pot reemplaçar-los per espais reservats activables amb un clic.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/cs/messages.json b/src/_locales/cs/messages.json
new file mode 100644
index 0000000..275960c
--- /dev/null
+++ b/src/_locales/cs/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "Doména $DOMAIN$ je blokována",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "Neplatný soubor JSON.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Jste si jistí, že chcete odebrat tuto doménu ze seznamu Privacy Badger?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "Žádné sledovací prvky pro $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "V současnosti Privacy Badger hlídá, zda soubory cookies třetích stran, lokální úložiště HTML5 a metoda canvas fingerprinting neslouží ke sledování Vašeho procházení internetu. Některé domény mohou používat metody sledování, které Privacy Badger dosud nedokáže detekovat.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "Zkontrolujte, zda <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>domény třetích stran</a> dodržují <a target='_blank' href='https://www.eff.org/dnt-policy'>pravidla Žádosti o nesledování od organizace EFF.</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Prosím, vložte validní doménu nebo adresu URL.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "Přispět EFF",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Můžete nám přispět finanční obnos, nebo sdílet Vaši podporu na sociálních sítích",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "Není to prostý program na blokování reklam",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "Děkujeme! Přijdeme tomu na kloub.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "Tato doména slibuje, že Vás nebude sledovat",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Blocking this domain is known to break websites",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Click to return control of this domain to Privacy Badger",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "další sekce",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "Prosím, <a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>napište nám</a> o vzniklé chybě:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Spravovat data",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Nahlásit chybu",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "např. www.domain.com, *.domain.net, domain.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Kliknutím zde zakážete doméně nastavovat soubory cookies",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "blokované",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "Bránit uniku lokální IP adresy skrze WebRTC",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger se automaticky učí blokovat neviditelné sledovací prvky na webových stránkách. Jestliže máte minutku, ukážeme Vám jak.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "Co je špatně?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Sledovací domény",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Sdílet na Twitteru",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Zjistěte, jak Privacy Badger chrání Vaše soukromí",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "Stáhnout",
+ "description": ""
+ },
+ "import": {
+ "message": "Importovat",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "Don't replace the following widgets:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Enable widget replacement",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Show domains that don't appear to be tracking you",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Odeslat hlášení o chybě",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "Doména $DOMAIN je povolena",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "Co je to Privacy Badger?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Hledat domény:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Learn to block new trackers from your browsing",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Enabling learning may make you more identifiable to websites",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Učit se v Anonymním okně prohlížeče",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "Jestliže povolíte učení v Anonymním okně, může zůstat na počítači Vaše historie procházení. Ve výchozím nastavení Privacy Badger blokuje v Anonymním okně pouze sledovací prvky, které již zná, ale nebude se snažit objevovat nové a učit se z nich. Zvažte zapnutí této možnosti v případě, že často používáte Anonymní okno.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger will no longer learn from your browsing by default.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Click below to learn more.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Learn how Privacy Badger is changing",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Show count of trackers",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "Co je to sledovací prvek?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "Nezapomeňte prosím kliknout na tlačítko \"Rozbil Privacy Badger tuto stránku?\", jelikož respektujeme Vaše soukromí a neposíláme automatické hlášení o chybách.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Nastavení Privacy Badger",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "This will automatically send the following information to EFF: the page you're currently visiting, your browser version, the version of Privacy Badger, and the state of all of the sliders on this page.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Vyloučené stránky",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Zapnout Privacy Badger pro tuto stránku",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Filtrovat podle druhu:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "Seznam sledovacích prvků a nastavení bylo úspěšně aktualizováno!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Exportovat uživatelská data",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "Importováním uživatelských dat:<ul><li>přepíšete základní nastavení,</li><li>sloučíte seznamy vyloučených domén,</li><li>sloučíte seznamy sledovacích domén, které Privacy Badger objevil,</li><li>přepíšete nastavení posuvníků.</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Resetovat",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Resetovat seznam sledovacích domén",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Resetování sledovacích domén způsobí:\n\n • Všechna data o sledovacích doménách, které se Privacy Badger naučil během Vašeho používání, budou smazána.\n • Seznam sledovacích domén se obnoví do základního nastavení (na adrese www.eff.org/badger-pretraining naleznete více informací).",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Odstranit vše",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Odstranit všechny sledovací domény",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "Odstranění všech sledovacích domén způsobí:\n\n • Všechny zjištěné údaje o sledovacích doménách budou smazána.\n • Privacy Badger nebude nic blokovat, dokud se opětovně nenaučí odhalovat sledovací domény během Vašeho procházení internetu.",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "Nyní Vás chrání Privacy Badger.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "Pokud chcete vědět, jak Privacy Badger funguje, klikněte níže pro rychlý tutoriál.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "Skrze WebRTC může unikat Vaše lokání IP adresa. Jestliže povolíte toto nastavení, kvalita Vašich hovorů na službách jako jsou Google Hangouts se může zhoršit.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "Obecná nastavení",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Privacy",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Advanced",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Spustit prohlídku",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Kliknutím zde doménu zablokujete úplně",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "verze $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "Blokovány soubory cookies z domény $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "částečně blokované",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "Rozumím, přesto mi ukažte seznam sledovacích domén",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Děkujeme Vám za instalaci Privacy Badger!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "Vyberte prosím soubor pro importování.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "Rozbil Privacy Badger tuto stránku? Dejte nám vědět!",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Umístěte posuvník doprostřed pro zablokování souborů cookies",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Learns automatically",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Instead of keeping lists of what to block, Privacy Badger automatically discovers trackers based on their behavior.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Chytá zákeřné sledovací prvky",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Invisible tracking happens in all sorts of ways; ads are just the visible tip of the iceberg. Privacy Badger sends the <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control signal</a>, to opt you out of data sharing and selling, and the <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track signal</a> to tell companies not to track you. If they ignore your wishes, Privacy Badger will learn to block them—whether they are advertisers or trackers of other kinds.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Zavřít",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Importovat uživatelská data",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "v souladu s Do Not Track",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Nápověda",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "povolené",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "Snaha o soukromí je týmový sport!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "Obvykle zde nemusíte nic upravovat.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "všechny",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "Zrušit",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Posuňte posuvník vlevo pro zablokování domény",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Send websites the \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" and \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\" signals",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Disable sending web addresses you visit to Google. This disables suggestions for similar pages when a page can't be found.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Disable hyperlink auditing",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "nastavené uživatelem",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is disabled on the following sites. This means that Privacy Badger will not block anything when you visit the sites listed here, and it will not send the Do Not Track or Global Privacy Control signals.</p><p>If you think Privacy Badger is breaking a page, or you would like to allow a particular site to share or sell your data, you can type that page's domain in the box below and click the \"Add domain\" button.</p><p>Alternatively, when you already have the page's tab selected, you can just click on Privacy Badger's button in the browser toolbar and then click the \"Disable\" button.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ potential $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "No $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "There are no third party resources on this page. Hooray for privacy!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Projekt Electronic Frontier Foundation",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Přidat doménu",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Posuňte posuvník vpravo pro povolení domény",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Vypnout Privacy Badger pro tuto stránku",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Klikněte zde pro povolení této domény",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privacy Badger NIKDY nesdílí žádná data o Vašem procházení, jestliže se k tomu sami nerozhodnete.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger has decided to block $COUNT$ potential $TRACKER_LINK_START$tracking domains$TRACKER_LINK_END$ so far",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privacy Badger zatím neobjevil žádné <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>sledovací domény</a>. Můžete pokračovat v procházení internetu!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger začne blokovat prvek teprve ve chvíli, kdy jej najde na třech různých webových stránkách. Tři zářezy a jde ze hry!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Filtrovat podle stavu:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Níže stručně popište chybu.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Smazat vybrané",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "Používáním rozšíření Privacy Badger se připojíte k organizaci <a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundation</a> a milionům dalších uživatelů k boji za soukromí. Jsme nezisková organizace, která bojuje za Vaše práva na internetu. Děkujeme, že jste s námi!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "Pro vyloučení určitých domén z vyhledávní přidejte před hledaný výraz znak \"-\". Například jestliže chcete najít všechny domény .co a .co.uk, ale chcete vynechat doménu .com, můžete použít hledání \".co -.com\".",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Pokud si myslíte, že Privacy Badger rozbil nějakou webovou stránku (například se nezobrazí video), můžete kliknout na tlačítko \"Vypnout Privacy Badger pro tuto stránku\", díky čemuž nebude Privacy Badger na této stránce aktivní.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Zásady ochrany osobních údajů",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Popis",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Your Badger hasn't decided yet if these domains should get blocked",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Show domains your Badger hasn't decided yet to block:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "Domény níže nevypadají, že Vás sledují",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Nastavení",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Sdílet na Facebooku",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privacy Badger se automaticky učí blokovat neviditelné sledovací prvky na webových stránkách.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "Jejda. Něco se pokazilo.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "Privacy Badger nahradil toto $BUTTON$ tlačítko",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger has replaced this $WIDGET$ widget",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Allow once",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Povolit vždy na tomto webu",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Synchronizace s cloudovou službou:<ul><li>Vyžaduje účet pro synchronizaci dat prohlížeče Firefox nebo Google Chrome.</li><li>Nahráním údajů přepíšete veškerá předchozí data rozšíření Privacy Badger na cloudu.</li><li>Stáhnutím dat z cloudu se sjednotí seznamy domén, na kterých je Privacy Badger vypnutý.</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Nahrát",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Nahrát vyloučené stránky na cloud",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Importovat vyloučené stránky z cloudu",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Data z cloudu byla úspěšně importována.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "Data z cloudu nemohla být stáhnuta.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "Data byla úspěšně nahrána na cloud.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "Data nemohla být nahrána na cloud.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "Žádná data z cloudu nejsou k dispozici ke stažení.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Povězte to svým přátelům",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Sdílet",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger blocked $COUNT$ potential trackers on $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privacy Badger (www.eff.org/privacybadger) je rozšíření prohlížeče, které automaticky detekuje neviditelné sledovací prvky. Privacy Badger je tvořen kolektivem Electronic Frontier Foundation, neziskovou organizací, která bojuje za Vaše práva na internetu.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "Zkopírovat do schránky",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Zkopírováno",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Nothing to do on this page",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger doesn't work on special pages like this one. Try browsing somewhere else.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger is disabled on this site",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Widget Replacement",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "When blocking social buttons and other potentially useful (video, audio, comments) widgets, Privacy Badger can replace them with click-to-activate placeholders.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/da/messages.json b/src/_locales/da/messages.json
new file mode 100644
index 0000000..0fcd47c
--- /dev/null
+++ b/src/_locales/da/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "Blokerede $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "Ugyldig JSON-fil.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Er du sikker på at du vil fjerne dette domæne fra Privacy Badger?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "Ingen sporing fra $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "I øjeblikket tjekker Privacy Badger kun om tredjeparter bruger cookies, HTML5 lokal lagring, eller kanvasfingeraftryk til at spore din netlæsning. Nogle af disse domæner kan bruge sporingsmetoder som Privacy Badger ikke kan opdage.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "Tjek om <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>tredjepartsdomæner</a> overholder <a target='_blank' href='https://www.eff.org/dnt-policy'>EFFs \"Spor Ikke\"-politik</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Tilføj venligst et gyldigt domæne eller URL.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "Doner til EFF",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Hjælp os ved at donere og dele din støtte til vores væktøjer",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "Ikke en reklameblokering, jeg er anderledes",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "Tak! Vi skal nok komme til bunds i det.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "Dette domæne lover ikke at spore dig",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Nogle netsteder virker ikke når dette domæne blokeres",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Klik for at give Privacy Badger kontrol over dette domæne",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "næste sektion",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "<a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>Fortæl os</a> om følgende fejl:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Håndter Data",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Rapporter en fejl",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "fx www.domain.com, *.domain.net, domain.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Klik her for at blokere dette domæne fra at sætte cookies",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "blokeret",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "Forhindr WebRTC i at lække lokal IP-adresse",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger lærer automatisk at blokere usynlige sporinger. Brug et minut på at se hvordan.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "Hvad er der galt?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Sporingsdomæner",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Del på Twitter",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Lær hvordan Privacy Badger beskytter dit privatliv",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "Hent",
+ "description": ""
+ },
+ "import": {
+ "message": "Importer",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "Udskift ikke følgende ting:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Aktiver udskiftning",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Vis domæner der ser ud til ikke at spore dig",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Indsend fejl",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "Tillod $DOMAIN$",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "Hvad er Privacy Badger?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Søg domæner:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Learn to block new trackers from your browsing",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Enabling learning may make you more identifiable to websites",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Lær i Private/Inkognito-vinduer",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "At aktivere læring i Private/Inkognito-vinduer kan efterlade spor af din private browsinghistorik på din computer. Som standard vil Privacy Badger blokere sporinger den allerede kender til i Private/Inkognito-vinduer, men den vil ikke lære om nye sporinger. Du vil muligvis slå denne indsilling til hvis du browser meget med Private/Inkognito-vinduer.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger will no longer learn from your browsing by default.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Click below to learn more.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Learn how Privacy Badger is changing",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Vis antal sporinger",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "Hvad er en sporing?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "Glem ikke at klikke på 'Ødelagde Privacy Badger dette netsted'. Vi respekterer dit privatliv, så vi sender ikke automatiske rapporter.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Privacy Badger Indstillinger",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "This will automatically send the following information to EFF: the page you're currently visiting, your browser version, the version of Privacy Badger, and the state of all of the sliders on this page.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Deaktiverede Steder",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Aktiver Privacy Badger for dette netsted",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Filtrer efter type:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "Sporingsliste og opsætning successfuldt opdateret!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Eksporter brugerdata",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "Import af brugerdata:<ul><li>Overskriver generelle indstillinger</li><li>Kombinerer lister over deaktiverede steder</li><li>Kombinerer informationer om hvilke sporinger Privacy Badger har set</li><li>Overskriver skyderes brugerindstillinger</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Nulstil",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Nulstil sporingsdomæner",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Nulstilling af sporingsdomæner vil:\n\n• Slette alle data om sporinger som Privacy Badger har lært fra din browsning.\n• Gendanner listen over sporingdomæner til den seneste før-trænede liste (besøg www.eff.org/badger-pretraining for at lære mere)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Fjern alle",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Fjern alle sporingsdomæner",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "At fjerne alle sporingsdomæner vil:\n\n• Slette alt Privacy Badger ved om sporinger\n• Få Privacy Badger til ikke at blokere noget indtil den har haft en chance til igen at lære fra din browsning",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "Du er nu beskyttet af Privacy Badger.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "For at lære hvordan Privacy Badger virker, klik herunder for en hurtig gennemgang.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC kan lække din lokale IP-addresse. Bemærk at aktivering af denne funktion kan have en negativ effekt på ydeevnen af webkonferenceprogrammer som Google Hangouts.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "Generelle Indstillinger",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Privacy",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Advanced",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Tag turen",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Klik her for at blokere dette domæne fuldstændigt",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "version $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "Blokerede cookies fra $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "delvist blokeret",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "Jeg forstår; vis mig listen over sporingsdomæner alligevel",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Tak for at installere Privacy Badger!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "Vælg en fil at importere.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "Ødelagde Privacy Badger dette netsted? Fortæl os om det!",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Centrer skyderen for at blokere cookies",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Learns automatically",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Instead of keeping lists of what to block, Privacy Badger automatically discovers trackers based on their behavior.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Fanger luskede sporinger",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Invisible tracking happens in all sorts of ways; ads are just the visible tip of the iceberg. Privacy Badger sends the <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control signal</a>, to opt you out of data sharing and selling, and the <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track signal</a> to tell companies not to track you. If they ignore your wishes, Privacy Badger will learn to block them—whether they are advertisers or trackers of other kinds.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Luk",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Importer brugerdata",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "\"Spor ikke\"-kompatibel",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Hjælp",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "tilladt",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "Privatliv er en gruppesport!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "Du burde ikke have nødigt at ændre noget her.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "alle",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "Annuller",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Flyt skyderen til venstre for at blokere et domæne",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Send websites the \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" and \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\" signals",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Disable sending web addresses you visit to Google. This disables suggestions for similar pages when a page can't be found.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Disable hyperlink auditing",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "brugerstyret",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is disabled on the following sites. This means that Privacy Badger will not block anything when you visit the sites listed here, and it will not send the Do Not Track or Global Privacy Control signals.</p><p>If you think Privacy Badger is breaking a page, or you would like to allow a particular site to share or sell your data, you can type that page's domain in the box below and click the \"Add domain\" button.</p><p>Alternatively, when you already have the page's tab selected, you can just click on Privacy Badger's button in the browser toolbar and then click the \"Disable\" button.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ potential $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "No $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "There are no third party resources on this page. Hooray for privacy!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Et projekt fra Electronic Frontier Foundation",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Tilføj domæne",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Flyt skyderen til højre for at tillade domænet",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Deaktiver Privacy Badger for dette netsted",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Klik her for at tillade dette domæne",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privacy Badger vil ALDRIG dele data om din browsning, med mindre du vælger at dele det.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger has decided to block $COUNT$ potential $TRACKER_LINK_START$tracking domains$TRACKER_LINK_END$ so far",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privacy Badger har ikke opdaget nogle <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>sporingsdomæner</a> endnu. Fortsæt med at browse!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger starts blocking once it sees the same tracker on three different websites. Three strikes and it's out!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Filtrer efter status:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Beskriv fejlen kort herunder.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Fjern valgte",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "Når du bruger Privacy Badger, tilslutter du dig <a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundation</a> og millioner af andre brugere i kampen for privatliv. Vi er en nonprofit organisation der kæmper for dine rettigheder online. Tak for at slutte dig til os!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "Sæt \"-\" foran dine søgeudtryk for at udelukke domæner. For eksempel vil \".co -.com\" vise .co og .co.uk men ikke .com-domæner.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Hvis du tror at Privacy Badger ødelægger en side (f.eks. en video spiller ikke), kan du klikke på \"Deaktiver\"-knappen for at slå Privacy Badger fra på det netsted.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Privatlivspolitik",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Beskrivelse",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Din Badger har endnu ikke besluttet om disse domæner skal blokeres",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Vis domæner din Badger endnu ikke har besluttet at blokere:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "Domænerne herunder ser ikke ud til at spore dig",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Opsætning",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Del på Facebook",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privacy Badger lærer automatisk at blokere usynlige sporinger.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "Ups. Noget gik galt.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "Privacy Badger har erstattet denne $BUTTON$ knap",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger har erstattet denne $WIDGET$-kontrol",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Tillad en gang",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Tillad altid på dette netsted",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Skysynkronisering:<ul><li>Kræver Firefox/Chrome-Synkronisering</li><li>Oplægning overskriver eksisterende Privacy Badger-data i skyen</li><li>Hentning kombinerer listerne over steder hvor din Privacy Badger er deaktiveret</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Læg op",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Eksporter deaktiverede steder til skyen",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Importer deaktiverede steder fra skyen",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Skydata importeret med success.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "Skydata kunne ikke hentes.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "Skydata lagt op med success.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "Skydata kunne ikke lægges op.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "Ingen skydata at hente.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Del med dine venner",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Del",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger blocked $COUNT$ potential trackers on $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privacy Badger (www.eff.org/privacybadger) er en browserudvidelse som automatisk lærer at blokere usynlige sporinger. Privacy Badger laves af Electronic Frontier Foundation, en nonprofit-orginsation der kæmper for dine rettigheder online.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "Kopiér til klippebord",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Kopieret",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Der er intet at gøre på denne side",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger virker ikke på specielle sider som denne. Prøv at browse et andet sted.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger er deaktiveret på dette netsted",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Kontroludskiftning",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "Ved blokering af sociale knapper og andre potentielt brugbare (video, lyd, kommentarer) kontroller, kan Privacy Badger udskifte dem med klik-for-at-aktivere pladsholdere.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/de/messages.json b/src/_locales/de/messages.json
new file mode 100644
index 0000000..ea2535d
--- /dev/null
+++ b/src/_locales/de/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "$DOMAIN$ geblockt",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "Ungültige JSON-Datei.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Möchten Sie diese Domain wirklich aus Privacy Badger entfernen?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "Kein Tracking für $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "Derzeit überprüft Privacy Badger nur, ob Drittparteien zum Verfolgen Ihrer Internetaktivitäten Cookies, lokalen HTML5-Speicher oder Canvas-Fingerprinting verwenden. Einige dieser Domains könnten allerdings Tracking-Methoden benutzen, die Privacy Badger nicht erkennen kann.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "Überprüfen, ob <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>Drittanbieter-Domains</a> <a target='_blank' href='https://www.eff.org/dnt-policy'>EFFs Do-Not-Track-Richtlinie</a> befolgen",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Bitte eine gültige Domain oder Adresse hinzufügen.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "An EFF spenden",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Helfen Sie uns durch Spenden und Weiterempfehlen unserer Software",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "Kein Adblocker: Ich bin anders",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "Vielen Dank! Wir werden den Fehler umgehend untersuchen.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "Diese Domain verspricht, Ihre Internetaktivitäten nicht zu verfolgen",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Das Blocken dieser Domain ist dafür bekannt, bei Websites Probleme zu verursachen",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Anklicken, um die Kontrolle dieser Domain an Privacy Badger zurückzugeben",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "nächster Abschnitt",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "Bitte <a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>informieren Sie uns</a> über den folgenden Fehler:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Benutzerdaten verwalten",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Melden eines Fehlers",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "z. B. www.domain.com, *.domain.net, domain.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Hier klicken, um zu verhindern, dass diese Domain Cookies setzt",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "geblockt",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "WebRTC hindern, die lokale IP-Adresse zu verraten",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger lernt automatisch, unsichtbare Tracker zu blocken. Nehmen Sie sich eine Minute Zeit, um zu erfahren wie.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "Was läuft falsch?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Tracking-Domains",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Auf Twitter teilen",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Erfahren Sie, wie Privacy Badger Ihre Privatsphäre schützt",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "Herunterladen",
+ "description": ""
+ },
+ "import": {
+ "message": "Importieren",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "Folgende Widgets nicht ersetzen:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Ersetzen von Widgets aktivieren",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Domains anzeigen, die Ihre Internetaktivitäten anscheinend nicht verfolgen",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Fehler übermitteln",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "$DOMAIN$ erlaubt",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "Was ist Privacy Badger?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Domains suchen:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Blocken neuer Tracker beim Browsen lernen",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Aktiviertes Lernen macht dich für Websites möglicherweise leichter identifizierbar",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Auch in privaten bzw. Inkognito-Fenstern lernen",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "Die Aktivierung des Lernens in privaten bzw. Inkognito-Fenstern hinterlässt eventuell Spuren Ihres privaten Surfverlaufs auf Ihrem Computer. In privaten/Inkognito-Fenstern blockt Privacy Badger standardmäßig bereits bekannte Tracker, erlernt aber keine neuen. Falls Sie oft private/Inkognito-Fenster verwenden, kann die Aktivierung dieser Option Sinn machen.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger wird standardmäßig nicht mehr aus Ihrem Browsen lernen.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Klicken Sie unten, um mehr zu erfahren.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Erfahren Sie, was sich in Privacy Badger ändert.",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Trackeranzahl anzeigen",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "Was ist ein Tracker?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "Bitte vergessen Sie nicht, auf »Verursacht Privacy Badger bei dieser Website Probleme?« zu klicken. Da wir Ihre Privatsphäre respektieren, senden wir keine automatisierten Berichte.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Optionen von Privacy Badger",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "Dies wird folgende Informationen automatisch an die EFF senden: Die von Ihnen derzeit besuchte Webseite, Ihre Browserversion, die Version von Privacy Badger und den Status aller Schieberegler auf dieser Webseite.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Deaktivierte Websites",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Für diese Website Privacy Badger aktivieren",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Nach Typ filtern:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "Trackerliste und Einstellungen erfolgreich aktualisiert!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Benutzerdaten exportieren",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "Importieren von Benutzerdaten:<ul><li>Überschreibt allgemeine Einstellungen</li><li>Kombiniert Listen deaktivierter Sites</li><li>Kombiniert Informationen über die bereits erkannten Tracker</li><li>Überschreibt Veränderungen der Schieberegler</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Zurücksetzen",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Tracking-Domains zurücksetzen",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Zurücksetzen der Tracking-Domains wird:\n\n • Alle Daten über Tracker löschen, die Privacy Badger während Ihrer Browsernutzung gelernt hat\n • Die Tracking-Domain-Liste auf die neueste vorgegebene Liste zurücksetzen (besuchen Sie www.eff.org/badger-pretraining für weitere Informationen)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Alle entfernen",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Alle Tracking-Domains entfernen",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "Entfernen aller Tracking-Domains wird:\n\n • Alles löschen, was Privacy Badger über Tracker weiß\n • Privacy Badger veranlassen, solange nichts zu blocken, bis er Gelegenheit hatte, von Ihrer Browsernutzung neu zu lernen",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "Sie werden nun von Privacy Badger geschützt.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "Um zu erfahren, wie Privacy Badger funktioniert, klicken Sie bitte unten für eine kurze Einführung.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC kann Ihre lokale IP-Adresse verraten. Bitte beachten Sie, dass das Aktivieren dieser Option eventuell die Leistung bei Apps für Webkonferenzen wie Google Hangouts verringert.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "Allgemeine Einstellungen",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Datenschutz",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Erweitert",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Rundgang machen",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Hier klicken, um diese Domain vollständig zu blocken",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "Version $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "Cookies von $DOMAIN$ geblockt",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "teilweise geblockt",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "Verstanden. Bitte die Liste der Tracking-Domains trotzdem anzeigen.",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Danke für das Installieren von Privacy Badger!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "Bitte eine Datei zum Importieren auswählen.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "Verursacht Privacy Badger bei dieser Website Probleme?",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Bewegen Sie den Schieberegler in die Mitte, um Cookies zu blocken",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Lernt automatisch",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Anstatt vorgefertigte Listen zu blockender Domains zu verwenden, entdeckt Privacy Badger Tracker aufgrund ihres Verhaltens automatisch.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Fängt hinterlistige Tracker",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Unsichtbares Tracking wird auf unterschiedlichen Wegen realisiert; Werbeanzeigen sind hierbei nur die sichtbare Spitze des Eisbergs. Privacy Badger signalisiert Websites durch <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>, dass Ihre Daten nicht geteilt und verkauft werden sollen, und durch <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>, dass Sie nicht verfolgt werden wollen. Falls diese Ihren Wunsch ignorieren, lernt Privacy Badger, sie zu blocken — egal, ob es sich dabei um Werbung oder andere Arten von Tracking handelt.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Schließen",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Benutzerdaten importieren",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "DNT-konform",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Hilfe",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "erlaubt",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "Datenschutz ist ein Teamsport!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "Hier sollten keine Änderungen notwendig sein.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "alle",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "Abbrechen",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Bewegen Sie den Schieberegler nach links, um eine Domain zu blocken",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Websites »<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>« und »<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>« signalisieren",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Senden besuchter Web-Adressen an Google deaktivieren. Dies deaktiviert Vorschläge für ähnliche Seiten, wenn eine Seite nicht gefunden werden kann.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Hyperlink-Auditing deaktivieren",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "benutzergesteuert",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger ist auf den folgenden Websites deaktiviert. Das heißt, Privacy Badger wird nichts blocken, wenn Sie die hier aufgeführten Sites besuchen, und wird weder »Do Not Track« noch »Global Privacy Control« signalisieren.</p><p>Falls Sie annehmen, dass Privacy Badger bei einer Webseite Probleme verursacht, oder wenn Sie einer bestimmten Site erlauben möchten, Ihre Daten zu teilen oder zu verkaufen, so können Sie die Domain der entsprechenden Seite in das Feld unten eingeben und auf die Schaltfläche »Domain hinzufügen« klicken.</p><p>Falls Sie den Tab der Seite bereits ausgewählt haben, können Sie auch einfach auf Privacy Badgers Schaltfläche in der Browsersymbolleiste und dann dort auf die Schaltfäche »Deaktivieren« klicken.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ mögliche $LINK_START$Tracker$LINK_END$ geblockt",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "Keine $LINK_START$Tracker$LINK_END$ geblockt",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "Auf dieser Webseite sind keine Elemente von Drittparteien vorhanden. Ein Hoch auf die Privatsphäre!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Ein Projekt der Electronic Frontier Foundation",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Domain hinzufügen",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Bewegen Sie den Schieberegler nach rechts, um eine Domain zu erlauben",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Für diese Website Privacy Badger deaktivieren",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Hier klicken, um diese Domain zu erlauben",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privacy Badger wird NIEMALS Daten über Ihre Internetaktivitäten weitergeben, solange Sie sich selbst nicht dazu entscheiden.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger hat entschieden, bisher $COUNT$ mögliche $TRACKER_LINK_START$Tracking-Domains$TRACKER_LINK_END$ zu blocken",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privacy Badger hat bisher keine <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>Tracking-Domains</a> erkannt. Surfen Sie weiter!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger beginnt mit dem Blocken, sobald er denselben Tracker auf drei verschiedenen Websites erkennt.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Nach Status filtern:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Beschreiben Sie bitte unten kurz den Fehler.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Ausgewählte entfernen",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "Durch das Verwenden von Privacy Badger werden Sie Teil der <a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundation</a> und Millionen anderer Nutzer im Kampf für Datenschutz. Wir sind eine gemeinnützige Organisation, die sich für Ihre Rechte im Internet einsetzt. Vielen Dank für Ihre Teilnahme!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "Stellen Sie zum Ausschließen von Domains Ihrem Suchbegriff ein »-« voran. Beispielsweise zeigt ».co -.com« als Ergebnis ».co«- und ».co.uk«-Domains an, aber keine ».com«-Domains.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Falls Sie annehmen, dass Privacy Badger bei einer Webseite Probleme verursacht (z. B. ein Video wird nicht wiedergegeben), so können Sie auf die Schaltfläche »Deaktivieren« klicken, um Privacy Badger für diese Website auszuschalten.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Datenschutzerklärung",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Beschreibung",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Ihr Badger hat noch nicht entschieden, ob diese Domains geblockt werden sollen",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Domains anzeigen, deren Blockstatus noch nicht entschieden ist:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "Die nachfolgenden Domains scheinen Ihre Internetaktivitäten nicht zu verfolgen",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Optionen",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Auf Facebook teilen",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privacy Badger lernt automatisch, unsichtbare Tracker zu blocken.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "Huch! Etwas ist schief gelaufen.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "Privacy Badger hat diese $BUTTON$-Schaltfläche ersetzt",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger hat dieses $WIDGET$-Widget ersetzt",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Einmalig erlauben",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Auf dieser Site immer erlauben",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Cloud-Sync:<ul><li>Erfordert Firefox-/Chrome-Sync</li><li>»Hochladen« überschreibt alle in der Cloud gespeicherten Privacy-Badger-Daten</li><li>»Herunterladen« kombiniert die Listen der Sites, auf denen Privacy Badger deaktiviert ist</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Hochladen",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Deaktivierte Sites zu Cloud exportieren",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Deaktivierte Sites von Cloud importieren",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Cloud-Daten erfolgreich importiert.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "Cloud-Daten konnten nicht heruntergeladen werden.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "Cloud-Daten erfolgreich hochgeladen.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "Cloud-Daten konnten nicht hochgeladen werden.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "Keine herunterzuladenden Cloud-Daten.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Ihren Freunden mitteilen",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Teilen",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger hat $COUNT$ mögliche Tracker auf $DOMAIN$ geblockt:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privacy Badger (www.eff.org/privacybadger) ist eine Browser-Erweiterung, die automatisch lernt, unsichtbare Tracker zu blocken. Privacy Badger wird von der Electronic Frontier Foundation entwickelt, einer gemeinnützigen Organisation, die sich für Ihre Rechte im Internet einsetzt.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "In Zwischenablage kopieren",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Kopiert",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Nichts zu tun auf dieser Seite",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Auf besonderen Seiten wie dieser funktioniert Privacy Badger nicht. Versuchen Sie eine andere.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Für diese Website ist Privacy Badger deaktiviert",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Ersetzen von Widgets",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "Beim Blocken von sozialen Schaltflächen und anderen potentiell nützlichen (Video-, Audio-, Kommentar-)Widgets kann Privacy Badger diese mit Platzhaltern ersetzen, die durch Anklicken aktiviert werden können.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/en_US/messages.json b/src/_locales/en_US/messages.json
new file mode 100644
index 0000000..f10fe37
--- /dev/null
+++ b/src/_locales/en_US/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "Blocked $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "Invalid JSON file.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Are you sure you want to remove this domain from Privacy Badger?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "No tracking for $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "Currently Privacy Badger only checks if third parties are using cookies, HTML5 local storage, or canvas fingerprinting to track your browsing. Some of these domains may be using tracking methods that Privacy Badger can't detect.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "Check if <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>third-party domains</a> comply with <a target='_blank' href='https://www.eff.org/dnt-policy'>EFF's Do Not Track policy</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Please add a valid domain or URL.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "Donate to EFF",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Help us by donating and sharing your support for our tools",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "Not an ad blocker, I'm different",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "Thanks! We'll get to the bottom of it.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "This domain promises to not track you",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Blocking this domain is known to break websites",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Click to return control of this domain to Privacy Badger",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "next section",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "Please <a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>tell us</a> about the following error:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Manage Data",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Report an Error",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "e.g. www.domain.com, *.domain.net, domain.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Click here to block this domain from setting cookies",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "blocked",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "Prevent WebRTC from leaking local IP address",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger automatically learns to block invisible trackers. Take a minute to see how.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "What's Wrong?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Tracking Domains",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Share on Twitter",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Learn how Privacy Badger protects your privacy",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "Download",
+ "description": ""
+ },
+ "import": {
+ "message": "Import",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "Don't replace the following widgets:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Enable widget replacement",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Show domains that don't appear to be tracking you",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Submit Error",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "Allowed $DOMAIN$",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "What is Privacy Badger?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Search domains:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Learn to block new trackers from your browsing",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Enabling learning may make you more identifiable to websites",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Learn in Private/Incognito windows",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "Enabling learning in Private/Incognito windows may leave traces of your private browsing history on your computer. By default, Privacy Badger will block trackers it already knows about in Private/Incognito windows, but it won't learn about new trackers. You might want to enable this option if a lot of your browsing happens in Private/Incognito windows.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger will no longer learn from your browsing by default.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Click below to learn more.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Learn how Privacy Badger is changing",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Show count of trackers",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "What is a tracker?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "Please don't forget to click on 'Did Privacy Badger break this site'. We respect your privacy so we don't send automatic reports.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Privacy Badger Options",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "This will automatically send the following information to EFF: the page you're currently visiting, your browser version, the version of Privacy Badger, and the state of all of the sliders on this page.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Disabled Sites",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Enable Privacy Badger for this site",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Filter by type:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "Tracker list and settings updated successfully!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Export user data",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "Importing user data:<ul><li>Overwrites general settings</li><li>Combines lists of disabled sites</li><li>Combines information about what trackers Privacy Badger has seen</li><li>Overwrites slider customizations</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Reset",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Reset tracking domains",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Resetting tracking domains will:\n\n • Delete all data about trackers that Privacy Badger has learned from your browsing\n • Restore the tracking domain list to the latest pre-trained list (visit www.eff.org/badger-pretraining to learn more)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Remove all",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Remove all tracking domains",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "Removing all tracking domains will:\n\n • Delete everything Privacy Badger knows about trackers\n • Cause Privacy Badger to not block anything until it has had a chance to re-learn from your browsing",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "You're now protected by Privacy Badger.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "To learn how Privacy Badger works, click below for a quick tutorial.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC can leak your local IP address. Note that enabling this option may degrade performance on web conferencing apps like Google Hangouts.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "General Settings",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Privacy",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Advanced",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Take the tour",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Click here to block this domain entirely",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "version $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "Blocked cookies from $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "partially-blocked",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "I understand; please show me the tracking domains list anyway",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Thank you for installing Privacy Badger!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "Please select a file to import.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "Did Privacy Badger break this site? Let us know!",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Center the slider to block cookies",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Learns automatically",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Instead of keeping lists of what to block, Privacy Badger automatically discovers trackers based on their behavior.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Catches sneaky trackers",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Invisible tracking happens in all sorts of ways; ads are just the visible tip of the iceberg. Privacy Badger sends the <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control signal</a>, to opt you out of data sharing and selling, and the <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track signal</a> to tell companies not to track you. If they ignore your wishes, Privacy Badger will learn to block them—whether they are advertisers or trackers of other kinds.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Close",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Import user data",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "DNT-compliant",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Help",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "allowed",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "Privacy is a team sport!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "You shouldn't need to modify anything here.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "all",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "Cancel",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Move the slider left to block a domain",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Send websites the \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" and \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\" signals",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Disable sending web addresses you visit to Google. This disables suggestions for similar pages when a page can't be found.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Disable hyperlink auditing",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "user-controlled",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is disabled on the following sites. This means that Privacy Badger will not block anything when you visit the sites listed here, and it will not send the Do Not Track or Global Privacy Control signals.</p><p>If you think Privacy Badger is breaking a page, or you would like to allow a particular site to share or sell your data, you can type that page's domain in the box below and click the \"Add domain\" button.</p><p>Alternatively, when you already have the page's tab selected, you can just click on Privacy Badger's button in the browser toolbar and then click the \"Disable\" button.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ potential $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "No $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "There are no third party resources on this page. Hooray for privacy!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "A project of the Electronic Frontier Foundation",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Add domain",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Move the slider right to allow a domain",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Disable Privacy Badger for this site",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Click here to allow this domain",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privacy Badger will NEVER share data about your browsing unless you choose to share it.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger has decided to block $COUNT$ potential $TRACKER_LINK_START$tracking domains$TRACKER_LINK_END$ so far",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privacy Badger hasn't detected any <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>tracking domains</a> yet. Keep browsing!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger starts blocking once it sees the same tracker on three different websites. Three strikes and it's out!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Filter by status:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Briefly describe the error below.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Remove selected",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "When you use Privacy Badger you join the <a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundation</a> and millions of other users in the fight for privacy. We are a nonprofit fighting for your rights online. Thanks for joining us!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "To exclude domains, prepend your search term with \"-\". For example, \".co -.com\" will show .co and .co.uk but not .com domains.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "If you think Privacy Badger is breaking a page (a video doesn't play, for example), you can click the 'Disable' button to turn off Privacy Badger for that site.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Privacy Policy",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Description",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Your Badger hasn't decided yet if these domains should get blocked",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Show domains your Badger hasn't decided yet to block:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "The domains below don't appear to be tracking you",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Options",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Share on Facebook",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privacy Badger automatically learns to block invisible trackers.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "Oops. Something went wrong.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "Privacy Badger has replaced this $BUTTON$ button",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger has replaced this $WIDGET$ widget",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Allow once",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Always allow on this site",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Cloud sync:<ul><li>Requires Firefox/Chrome Sync</li><li>Upload overwrites any existing Privacy Badger data in the cloud</li><li>Download combines the lists of sites where your Badger is disabled</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Upload",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Export disabled sites to cloud",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Import disabled sites from cloud",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Cloud data imported successfully.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "Cloud data could not be downloaded.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "Cloud data uploaded successfully.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "Cloud data could not be uploaded.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "No cloud data to download.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Tell your friends",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Share",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger blocked $COUNT$ potential trackers on $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privacy Badger (www.eff.org/privacybadger) is a browser extension that automatically learns to block invisible trackers. Privacy Badger is made by the Electronic Frontier Foundation, a nonprofit that fights for your rights online.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "Copy to clipboard",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Copied",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Nothing to do on this page",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger doesn't work on special pages like this one. Try browsing somewhere else.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger is disabled on this site",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Widget Replacement",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "When blocking social buttons and other potentially useful (video, audio, comments) widgets, Privacy Badger can replace them with click-to-activate placeholders.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+}
diff --git a/src/_locales/eo/messages.json b/src/_locales/eo/messages.json
new file mode 100644
index 0000000..a410b93
--- /dev/null
+++ b/src/_locales/eo/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "Blokita $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "Malĝusta dosiero JSON.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Ĉu vi certas pri forigi tiun ĉi nomregnon el Privata Melo?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "Ne spuras por $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "Nune Privata Melo nur kontrolas ĉu eksteraj liverantoj uzas kuketojn, lokan konservejon HTML5 aŭ kanvasan fingrospuron por spuri vian retumadon. Iuj de tiuj nomregnoj povas uzi aliajn spurajn rimedojn, kiujn Privata Melo ne povas malkovri.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "Kontroli ĉu <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>eksteraj domajnoj</a> kongruas kun la <a target='_blank' href='https://www.eff.org/dnt-policy'>politiko pri nespurado de EFF</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Bonvolu aldoni ĝustan nomregnon aŭ URL-n.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "Donaci al EFF",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Helpu nin per donaci kaj oferi helpon al niaj iloj",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "Malsama ol reklam-spuriloj",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "Dankon! Ni okupiĝos pri tio.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "Tiu ĉi nomregno promesas al vi ne spuri.",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Per bloki tiun ĉi nomregnon, retejoj povus misfunkcii",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Klaku por permesi al Privata Melo decidi kiel trakti tiun ĉi nomregnon",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "antaŭen",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "Bonvolu <a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>informi nin</a> pri la jena eraro:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Administri datumojn",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Raporti eraron",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "ekz. www.nomregno.com, *.nomregno.net, nomregno.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Klaku tie ĉi por bloki tiun ĉi nomregnon de agordi kuketojn",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "blokitaj",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "Preventi WebRTC de malkovri lokan IP-adreson",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privata Melo aŭtomate lernas bloki nevideblajn spurilojn. Jen konciza klarigo kiel.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "Kio malfunkcias?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Spurantaj nomregnoj",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Kunhavigi per Twitter",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Sciigi pri kiel Privata Melo protektas vian privatecon",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "Elŝuti",
+ "description": ""
+ },
+ "import": {
+ "message": "Enporti",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "Ne anstataŭigi la jenajn ret‑aplikaĵetojn:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Aktivigi anstataŭigon de ret‑aplikaĵetoj",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Montri nomregnojn, kiuj verŝajne ne spuras vin",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Raporti eraron",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "Permesata $DOMAIN$",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "Kio la Privata Melo estas?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Serĉi nomregnon:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Lerni bloki novajn spurilojn surbaze de via retumado",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Aktivigo de lernadu dum retumado povas igi vin pli identigebla al retejoj",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Lerni en privataj fenestroj",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "Aktivigo de lernado en privataj fenestroj povas resti spurojn de historio de via privata retumado en via komputilo. Implicite Privata Melo blokos jam-konatajn spurilojn en privataj langetoj, tamen ne lernos pri novaj spuriloj. Vi povas aktivigi tiun ĉi agordon, se vi multe retumas en privataj fenestroj.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger will no longer learn from your browsing by default.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Click below to learn more.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Learn how Privacy Badger is changing",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Montri nombron de spuriloj",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "Kio estas spurilo?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "Bonvolu ne forgesi klaki “Ĉu Privata Melo difektis tiun ĉi retejon?”. Ni estimas vian privatecon, do ni ne sendas aŭtomatajn raportojn.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Agordoj pri Privata Melo",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "Tio ĉi aŭtomate sendos la jenajn datumojn al EFF: la nune vizitatan retpaĝon, version de via retumilo, version de Privata Melo kaj staton de ĉiuj ŝovilojn por tiu ĉi retpaĝo.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Neblokataj retejoj",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Aktivigi Privatan Melon por tiu ĉi retejo",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Filtri laŭ speco:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "Sukcese enportis spuril-liston kaj agordojn!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Elporti datumojn de uzanto",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "Enporti datumojn de uzantoj por:\n<ul>\n<li>anstataŭigi ĝeneralajn agordojn</li>\n<li>kombini listojn de neblokataj retejoj</li>\n<li>kombini informojn pri observitaj spuriloj</li>\n<li>anstataŭigi agordojn de ŝovilo</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Rekomencigi",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Rekomencigi spurantajn nomregnojn",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Rekomencigu spurantajn nomregnojn por:\n\n • forviŝi ĉiujn datumojn pri spurilojn, kiujn Privata Melo lernis dum retumado\n • restarigi la liston de spurantaj nomregnoj al la plej aktuala antaŭlernita versio (legu www.eff.org/badger-pretraining por pli da informoj)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Forigi ĉiujn",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Forigi ĉiujn spurantajn nomregnojn",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "Forigu ĉiujn spurantajn nomregnojn por:\n\n • forigi ĉion, kion Privata Melo scias pri spuriloj\n • igi Privatan Melon ne bloki ion ajn ĝis ĝi relernos surbaze de via retumado",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "Vi nun estas protektata de Privata Melo.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "Por lerni kiel Privata Melo funkcias, klaku sube por koncizan gvidilon.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC povas malkovri vian lokan IP-adreson. Rimarku, ke tio ĉi povas malpliigi rendimenton de aplikaĵoj por retaj konferencoj, ekz. Google Hangouts.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "Ĝeneralaj agordoj",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Privateco",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Spertulaj",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Enkonduko",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Klaku tie ĉi por tute bloki tiun ĉi nomregnon",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "versio $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "Blokitaj kuketoj el $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "parte-blokitaj",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "Mi konscias, tamen bonvolu montri al mi la liston de spurantaj nomregnoj.",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Dankon al vi pro instali Privatan Melon!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "Bonvolu elekti dosieron por enporti.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "Ĉu Privata Melo difektis tiun ĉi retejon? Sciigu nin!",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Centrigu la ŝovilon por bloki kuketojn.",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Learns automatically",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Instead of keeping lists of what to block, Privacy Badger automatically discovers trackers based on their behavior.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Kaptas trompajn spurilojn",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Invisible tracking happens in all sorts of ways; ads are just the visible tip of the iceberg. Privacy Badger sends the <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control signal</a>, to opt you out of data sharing and selling, and the <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track signal</a> to tell companies not to track you. If they ignore your wishes, Privacy Badger will learn to block them—whether they are advertisers or trackers of other kinds.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Fermi",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Enporti datumojn de uzanto",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "DNT-kongruaj",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Helpo",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "permesitaj",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "Privateco estas kunlaboro!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "Vi ne devus bezoni modifi ion ajn tie ĉi.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "ĉiuj",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "Nuligi",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Movu la ŝovilon maldekstren por bloki nomregnon.",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Send websites the \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" and \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\" signals",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Malaktivigi sendi adresojn de vizitataj retejoj al Google. Tio ĉi malaktivigas sugestojn pri similaj retejoj, kiam la paĝo ne povas esti malfermita.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Malaktivigi kontroladon de ligiloj",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "uzant-kontrolitaj",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is disabled on the following sites. This means that Privacy Badger will not block anything when you visit the sites listed here, and it will not send the Do Not Track or Global Privacy Control signals.</p><p>If you think Privacy Badger is breaking a page, or you would like to allow a particular site to share or sell your data, you can type that page's domain in the box below and click the \"Add domain\" button.</p><p>Alternatively, when you already have the page's tab selected, you can just click on Privacy Badger's button in the browser toolbar and then click the \"Disable\" button.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "Blokitaj eblaj $LINK_START$spuriloj$LINK_END$: $COUNT$",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "Neniu blokita $LINK_START$spurilo$LINK_END$",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "Estas neniu ekstera rimedo sur tiu ĉi retpaĝo. Vivu la privateco!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Projekto de Electronic Frontier Foundation",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Aldoni nomregnon",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Movu la ŝovilon dekstren por permesi nomregnon.",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Malaktivigi Privatan Melon por tiu ĉi retejo",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Klaku tie ĉi por permesi tiun ĉi nomregnon",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privata Melo NENIAM diskonigos datumojn pri via retumado escepte se vi decidos alie.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger has decided to block $COUNT$ potential $TRACKER_LINK_START$tracking domains$TRACKER_LINK_END$ so far",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privata Melo ne malkovris iun ajn <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>spurantan nomregnon</a> ĝis nun. Pluigu retumi!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privata Melo",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privata Melo komencas bloki kiam ĝi rimarkas la saman spurilon ĉe tri diversaj retejoj. Tri aperoj kaj ĝi malaperas!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Filtri laŭ stato:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Koncize priskribu la eraron sube.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Forigi elektitajn",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "Kiam vi uzas Privatan Melon vi aniĝas al la <a href='https://www.eff.org/' target='_blank'>Ret-Lima Fondaĵo (EFF)</a> kune kun milionoj da aliaj retanoj en la batalo por privateco. Ni estas ne-profit-cela fondaĵo, kiu batalas por viaj rajtoj en la interreto. Dankon por kuniĝi al ni!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "Por escepti nomregnojn, antaŭskribu vian serĉon per “-”. Ekzemplo: “co -.com” montros domajnojn .co kaj .co.uk sed ne .com.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Se viaopinie Privata Melo difektas retpaĝon (ekzemple filmeto ne ludas), vi povas klaki la butonon “malaktivigi” por malaktivigi Privatan Melon por tiu retejo.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Privateca politiko",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Priskribo",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Via Melĉjo ankoraŭ ne decidiĝis ĉu tiuj ĉi nomregnoj estu blokitaj",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Montri nomregnojn, pri kiuj Privata Melo ne decidiĝis ĉu bloki ilin:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "La subaj nomregnoj verŝajne ne spuras vin",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Agordoj",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Kunhavigi per Facebook",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privata Melo aŭtomate lernas bloki nevideblajn spurilojn.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "Ho ne! Eraro okazis.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "Privata Melo anstataŭigis tiun ĉi butonon de $BUTTON$",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privata Melo anstataŭigis tiun ĉi ret‑aplikaĵeton $WIDGET$",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Permesi unufoje",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Ĉiam permesi en tiu ĉi retejo",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Samtempigo en servilo:\n<ul>\n<li>postulas Firefox Spegulado/Chrome Sync</li>\n<li>alŝuto anstataŭigas ĉiujn ekzistajn datumojn de Privata Melo en la servilo</li>\n<li>elŝuto kunigas listojn de retejoj kun malaktiva Privata Melo</li>\n</ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Alŝuti",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Elporti neblokatajn retejojn al servilo",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Enporti neblokatajn retejojn el servilo",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Sukcese enportis datumojn.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "Ne povas elŝuti datumojn el servilo.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "Sukcese alŝutis datumojn.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "Ne povas alŝuti datumojn al servilo.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "Neniuj datumoj en la servilo por elŝuti.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Sciigu amikojn",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Diskonigi",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privata Melo blokis $COUNT$ eblajn spurilojn ĉe $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privata Melo (www.eff.org/privacybadger) estas retumila etendaĵo, kiu aŭtomate lernas kiel bloki nevideblajn spurilojn. Privata Melo estas farita de Electronic Frontier Foundation, ne-profit-cela fondaĵo, kiu batalas por viaj rajtoj en la interreto.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "Kopii al tondejo",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Kopiita",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Estas nenio por fari sur tiu ĉi paĝo",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privata Melo ne funkcias sur specialaj paĝoj kiel tiu ĉi. Provu malfermi alian paĝon.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privata Melo estas malaktivigita por tiu ĉi retejo",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Anstataŭigi ret‑aplikaĵetojn",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "Privata Melo povas bloki butonojn de sociaj retejoj kaj aliajn virtuale uzeblajn aplikaĵetojn (filmetojn, aŭdaĵojn, komentojn), tiu ĉi eblaĵo anstataŭigas ilin per klakeblaj (ne aŭtomate montriĝantaj) butonoj.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/es/messages.json b/src/_locales/es/messages.json
new file mode 100644
index 0000000..76d4f17
--- /dev/null
+++ b/src/_locales/es/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "Bloqueado $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "Archivo JSON no válido.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "¿Seguro de que deseas eliminar este dominio de Privacy Badger?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "Sin rastreo para $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "Actualmente, Privacy Badger solo comprueba si hay terceras partes usando cookies, almacenamiento local HTML5 o huellas digitales de «canvas» para rastrear tu navegación. Algunos de estos dominios pueden estar usando métodos de rastreo que Privacy Badger no puede detectar.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "Comprobar si los <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>dominios de terceros</a> cumplen con la <a target='_blank' href='https://www.eff.org/dnt-policy'>política de No rastrear de la EFF</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Por favor, añade un dominio o URL válido.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "Donar a la EFF",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Ayúdenos con un donativo, o tu apoyo compartiendo nuestras herramientas",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "No soy un bloqueador de anuncios, soy diferente",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "¡Gracias! Llegaremos al fondo del asunto.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "Este dominio promete no rastrearte",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Bloquear este dominio es conocido por romper sitios web",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Haz clic para devolver el control de este dominio a Privacy Badger",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "siguiente sección",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "Por favor, <a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>infórmanos</a> del siguiente error:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Gestionar datos",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Reportar un error",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "p. ej., www.dominio.com, *.dominio.net, dominio.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Haz clic aquí para impedir que este dominio cree cookies",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "bloqueado",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "Impedir que WebRTC divulgue la dirección IP local",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger aprende automáticamente a bloquear rastreadores invisibles. Tómate un minuto para ver cómo lo hace.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "¿Qué está mal?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Dominios de rastreo",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Compartir en Twitter",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Aprende cómo Privacy Badger protege tu privacidad",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "Descargar",
+ "description": ""
+ },
+ "import": {
+ "message": "Importar",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "No sustituir los siguientes widgets:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Habilitar la sustitución de widgets",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Mostrar los dominios que no parecen estar rastreándote",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Informar de un error",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "Permitido $DOMAIN$",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "¿Qué es Privacy Badger?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Buscar dominios:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Aprende a bloquear rastreadores nuevos de tu navegación",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Permitir el aprendizaje puede hacerte más identificable con los sitios web",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Aprender en ventanas privadas o de incógnito",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "Permitir el aprendizaje en ventanas privadas o de incógnito puede dejar rastros de tu historial de navegación privada en tu computadora. Privacy Badger bloquea de forma predeterminada los rastreadores que ya conoce en las ventanas privadas o de incógnito, pero no reconoce rastreadores nuevos. Es posible que desees habilitar esta opción si gran parte de tu navegación ocurre en ventanas privadas o de incógnito.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger ya no aprenderá de tu navegación de forma predeterminada.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Clic abajo para más información.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Aprende cómo está cambiando Privacy Badger",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Mostrar el número de rastreadores",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "¿Qué es un rastreador?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "Por favor, no olvides hacer clic en «¿Ha roto Privacy Badger este sitio?». Respetamos tu privacidad, por lo que no enviamos reportes de forma automática.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Opciones de Privacy Badger",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "Esto enviará automáticamente la siguiente información a la EFF: la página que estás visitando actualmente, la versión de tu navegador, la versión de Privacy Badger y el estado de todos los controles deslizantes en esta página.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Sitios deshabilitados",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Habilitar Privacy Badger en este sitio",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Filtrar por tipo:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "¡La lista de rastreadores y la configuración se han actualizado correctamente!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Exportar datos de usuario",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "La importación de datos de usuario: <ul><li>Sobrescribe la configuración general</li><li>Combina listas de sitios deshabilitados</li><li>Combina información sobre los rastreadores que Privacy Badger has visto</li><li>Sobrescribe las personalizaciones de los controles deslizantes</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Restablecer",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Restablecer dominios de rastreo",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Restablecer los dominios de rastreo:\n\n • Elimina todos los datos sobre los rastreadores que Privacy Badger ha aprendido de tu navegación\n • Restaura la lista de dominios de rastreo a la más reciente ya entrenada (visita www.eff.org/badger-pretraining para obtener más información)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Eliminar todo",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Eliminar todos los dominios de rastreo",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "Eliminar todos los dominios de rastreo:\n\n • Elimina todo lo que sabe Privacy Badger sobre los rastreadores\n • Hace que Privacy Badger no bloquee nada hasta que haya tenido la oportunidad de volver a aprender de tu navegación",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "Ahora te encuentras bajo la protección de Privacy Badger.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "Para saber cómo funciona Privacy Badger, haz clic abajo para un tutorial rápido.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC puede divulgar tu dirección IP local. Ten en cuenta que habilitar esta opción puede reducir el rendimiento en aplicaciones de conferencia web como Google Hangouts.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "Configuración general",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Privacidad",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Avanzado",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Hacer el recorrido",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Haz clic aquí para bloquear por completo este dominio",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "versión $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "Cookies bloqueadas de $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "parcialmente bloqueado",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "Entiendo; por favor, muéstrame la lista de dominios de rastreo de todos modos",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "¡Gracias por instalar Privacy Badger!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "Por favor, selecciona un archivo para importar.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "¿Ha roto Privacy Badger este sitio? ¡Háganoslo saber!",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Centra el control deslizante para bloquear las cookies",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Aprende automáticamente",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "En lugar de mantener listas de qué bloquear, Privacy Badger descubre automáticamente los rastreadores según su comportamiento.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Neutraliza rastreadores ocultos",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "El rastreo invisible ocurre de muchas formas; los anuncios son solo la punta visible del iceberg. Privacy Badger envía la <a href='https://globalprivacycontrol.org/' target='_blank'>señal Control de privacidad global</a>, para excluirte de compartir y vender datos, y la <a href='https://www.eff.org/issues/do-not-track' target='_blank'>señal No rastrear</a> para indicar a las empresas que no te rastreen. Si ignoran tus deseos, Privacy Badger aprenderá a bloquearlos, ya sean anunciantes o rastreadores de otro tipo.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Cerrar",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Importar datos de usuario",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "respeta DNT",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Ayuda",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "permitido",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "¡La privacidad es un deporte de equipo!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "No deberías necesitar modificar nada aquí.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "todo",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "Cancelar",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Mueve el control deslizante a la izquierda para bloquear un dominio",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Enviar a los sitios web las señales «<a href='https://globalprivacycontrol.org/' target='_blank'>Control de privacidad global</a>» y «<a href='https://www.eff.org/issues/do-not-track' target='_blank'>No rastrear</a>»",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Deshabilitar el envío de las direcciones web que visitas a Google. Esto deshabilita las sugerencias de páginas similares cuando no se puede encontrar una página.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Deshabilitar auditoría de hipervínculos",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "controlado por usuario",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger está deshabilitado en los siguientes sitios. Esto significa que Privacy Badger no bloqueará nada cuando visites los sitios listados aquí, y no enviará las señales No rastrear o Control de privacidad global.</p><p>Si crees que Privacy Badger está rompiendo una página o deseas permitir que un sitio en particular comparta o venda tus datos, puedes escribir el dominio de dicha página en el cuadro de abajo y hacer clic en el botón «Añadir dominio».</p><p>Alternativamente, cuando ya tengas seleccionada la pestaña de la página, simplemente haz clic en el botón de Privacy Badger en la barra de herramientas del navegador y luego haz clic en el botón «Deshabilitar».</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ $LINK_START$rastreadores$LINK_END$ potenciales bloqueados",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "No hay $LINK_START$rastreadores$LINK_END$ bloqueados",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "No hay recursos de terceros en esta página. ¡Hurra por la privacidad!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Un proyecto de la Electronic Frontier Foundation",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Añadir dominio",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Mueve el control deslizante a la derecha para permitir un dominio",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Deshabilitar Privacy Badger en este sitio",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Haz clic aquí para permitir este dominio",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privacy Badger NUNCA comparte datos sobre tu navegación a menos que elijas compartirlos.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger ha decidido bloquear $COUNT$ $TRACKER_LINK_START$dominios de rastreo$TRACKER_LINK_END$ potenciales hasta el momento",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privacy Badger no ha detectado ningún <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>dominio de rastreo</a> por el momento. ¡Sigue navegando!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger comienza a bloquear una vez que ve el mismo rastreador en tres sitios web diferentes. ¡Tres strikes y está afuera!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Filtrar por estado:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Describe brevemente el error aquí abajo.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Eliminar seleccionado",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "Cuando utilizas Privacy Badger te unes a la <a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundation</a> y a millones de otros usuarios en la lucha por la privacidad. Somos una organización sin ánimo de lucro que lucha por tus derechos en línea. ¡Gracias por unirte a nosotros!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "Para excluir dominios, preceda el término de búsqueda con «-». Por ejemplo, «.co -.com» muestra dominios .co y .co.uk, pero no .com.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Si crees que Privacy Badger está rompiendo una página (un vídeo no se reproduce, por ejemplo), puede hacer clic en el botón «Deshabilitar» para deshabilitar Privacy Badger en ese sitio.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Política de privacidad",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Descripción",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Privacy Badger aún no ha decidido si estos dominios deben ser bloqueados",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Mostrar dominios que Privacy Badger aún no ha decidido bloquear:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "Los siguientes dominios no parecen estar rastreándote",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Opciones",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Compartir en Facebook",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privacy Badger aprende automáticamente a bloquear rastreadores invisibles.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "Ups. Algo salió mal.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "Privacy Badger ha sustituido este botón de $BUTTON$",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger ha sustituido este widget de $WIDGET$",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Permitir una vez",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Permitir siempre en este sitio",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Sincronización en la nube:<ul><li>Requiere Firefox/Chrome Sync</li><li>La subida de datos sobrescribe cualquier dato existente de Privacy Badger en la nube</li><li>La descarga combina las listas de sitios en los que Privacy Badger está deshabilitado</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Subir",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Exportar sitios deshabilitados a la nube",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Importar sitios deshabilitados de la nube",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Los datos de la nube se han importado correctamente.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "No se han podido descargar los datos de la nube.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "Los datos para nube se han subido correctamente.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "No se han podido subir los datos para la nube.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "No hay datos en la nube para descargar.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Cuéntaselo a tus amigos",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Compartir",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger ha bloqueado $COUNT$ rastreadores potenciales en $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privacy Badger (www.eff.org/privacybadger) es una extensión de navegador que aprende automáticamente a bloquear rastreadores invisibles. Privacy Badger está hecho por la Electronic Frontier Foundation, una organización sin ánimo de lucro que lucha por tus derechos en línea.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "Copiar al portapapeles",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Copiado",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Nada que hacer en esta página",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger no funciona en páginas especiales como ésta. Intenta buscar en otro lugar.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger está deshabilitado en este sitio",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Sustitución de widgets",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "Al bloquear botones de redes sociales y otros widgets potencialmente útiles (vídeo, audio, comentarios), Privacy Badger puede sustituirlos con marcadores de posición de clic para activarlos.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/fa/messages.json b/src/_locales/fa/messages.json
new file mode 100644
index 0000000..cc1562e
--- /dev/null
+++ b/src/_locales/fa/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "$DOMAIN$ بلاک شد",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "فایل JSON نامعتبر.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "آیا مطمئن هستید که میخواهید این را از پرایوسی بجر حذف کنید؟",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "هیچ ردیابی برای $DOMAIN$ وجود ندارد",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "هم اکنون پرایوسی بجر فقط چک میکند آیا اشخاص ثالث از کوکی ها، مخزن محلی HTML5، اثرانگشت کانواس برای ردیابی شما استفاده میکنند یا نه. بعضی از این دامنه ها ممکن است از متد های ردیابی استفاده کنند که پرایوسی بجر قابلیت شناسایی آن ها را ندارد.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "چک کن آیا <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'> دامنه های شخص ثالث </a> با <a target='_blank' href='https://www.eff.org/dnt-policy'> خط مشی ردیابی نکن EFF </a> تطابق دارند",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "لطفا یک دامنه یا URL معتبر اضافه کنید.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "کمک مالی به EFF",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "با کمک مالی و حمایت از ابزار هایمان میتوانید به ما کمک کنید",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "اد بلاکر نیستم، من فرق دارم",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "ممنون! پیگیری خواهیم کرد.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "این دامنه اطمینان می دهد که شما را ردیابی نخواهد کرد",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Blocking this domain is known to break websites",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Click to return control of this domain to Privacy Badger",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "بخش بعدی",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "لطفا <a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'> به ما </a> درباره خطای زیر بگویید:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "مدیریت داده",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "گزارش خطا",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "برای مثال www.domain.com, *.domain.net, domain.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "برای منع این دامنه از تنظیم کردن کوکی ها اینجا کلیک کنید",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "بلاک شده",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "نگذار WebRTC آدرس IP را لو بدهد",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "پرایوسی بجر به صورت اتوماتیک یاد می گیرد تا ردیاب های مخفی را بلاک کند. برای اینکه بفهمید چگونه اینکار را انجام می دهد، یک دقیقه وقت بگذارید.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "چه مشکلی وجود دارد؟",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "دامنه های ردیاب",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "اشتراک گذاری بر روی توییتر",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "درباره اینکه پرایوسی بجر چگونه از حریم خصوصی شما محافظت میکند مطالعه کنید",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "دانلود",
+ "description": ""
+ },
+ "import": {
+ "message": "ایمپورت",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "Don't replace the following widgets:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Enable widget replacement",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "دامنه‌هایی که شما را ردیابی نمی‌کنند را نمایش بده",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "ارسال خطا",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "به $DOMAIN$ اجازه داده شده است",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "پرایوسی بجر چیست؟",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "جستجوی دامنه ها:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Learn to block new trackers from your browsing",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Enabling learning may make you more identifiable to websites",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "یادگیری در پنجره های خصوصی/ناشناس",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "اجازه یادگیری در پنجره های خصوصی/ناشناس ممکن است ردی از تاریخچه گشت خصوصی شما در وب روی کامپیوترتان به جا بگذارد. به صورت پیش فرض، پرایوسی بجر ردیاب هایی که در پنجره های خصوصی/ناشناس می شناسد را بلاک خواهد کرد، اما درباره ردیاب های جدید اطلاعی کسب نخواهد کرد. اگر بیشتر وقت خود را در پنجره های خصوصی/ناشناس می گذرانید شاید بهتر باشد که این گزینه را فعال کنید.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger will no longer learn from your browsing by default.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Click below to learn more.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Learn how Privacy Badger is changing",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "نمایش تعداد ردیاب‌ها",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "ردیاب چیست؟",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "فراموش نکنید تا روی 'آیا پرایوسی بجر باعث شده است تا این سایت به درستی کار نکند' کلیک کنید. ما به حریم خصوصی شما احترام میگذاریم برای همین به صورت خودکار گزارش نمی فرستیم.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "گزینه های پرایوسی بجر",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "This will automatically send the following information to EFF: the page you're currently visiting, your browser version, the version of Privacy Badger, and the state of all of the sliders on this page.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "سایت های غیر فعال شده",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "فعال سازی پرایوسی بجر برای این سایت",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "فیلتر کردن بر اساس نوع:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "لیست ردیاب و تنظیمات با موفقیت آپدیت شد!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "انتقال داده کاربری",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "ایمپورت داده کاربری:<ul><li> اوورایت تنظیمات کلی</li><li>ترکیب لیست سایت های غیرفعال شده</li><li>ترکیب اطلاعات درباره ردیاب هایی که پرایوسی بجر با آن ها برخورد داشته است</li><li>اوورایت کاستومایزیشن اسلایدر</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "ریست",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "ریست دامنه های ردیاب",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "ریست کردن دامنه های ردیاب باعث می شود:\n\n• تمام داده های مربوط به ردیاب هایی که پرایوسی بجر از گردش شما در وب آموخته از بین برود\n• بازیابی لیست دامنه ردیاب به آخرین لیست از پیش پرورش شده ( برای اطلاعات بیشتر به www.eff.org/badger-pretraining بروید)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "حذف همه",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "حذف همه دامنه های ردیاب",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "حذف تمام دامنه های ردیاب باعث می شود:\n\n• تمام چیزهایی که پرایوسی بجر درباره ردیاب ها می داند از بین برود\n• پرایوسی بجر تا دفعه بعدی که مشغول گردش در وب هستید و فرصت یادگیری دوباره دارد چیزی را بلاک نکند",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "شما هم اکنون توسط پرایوسی بجر محافظت می شوید.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "برای یادگیری بیشتر درباره عملکرد پرایوسی بجر، روی قسمت پایین کلیک کنید.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC میتواند منجر به لو رفتن آدرس IP شما شود. توجه داشته باشید که این گزینه میتواند باعث کندی عملکرد در برنامه های کنفرانسی وب مثل Google Hangouts شود.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "تنظیمات کلی",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Privacy",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Advanced",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "انجام تور",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "برای بلاک کردن این دامنه به صورت کامل روی اینجا کلیک کنید",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "نسخه $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "کوکی های متعلق به$DOMAIN$ بلاک شد",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "بلاک شده به صورت جزئی",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "متوجه هستم; لطفا لیست دامنه هایی که ردیابی میکنند را به من نشان بده",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "بابت نصب پرایوسی از شما ممنونیم!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "لطفا یک فایل را برای ایمپورت کردن انتخاب کنید.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "آیا پرایوسی بجر باعث شده است تا این سایت به درستی کار نکند؟ ما را در جریان بگذارید!",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "برای بلاک کردن کوکی ها اسلایدر را در وسط قرار بدهید",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Learns automatically",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Instead of keeping lists of what to block, Privacy Badger automatically discovers trackers based on their behavior.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "ردیاب های موذی را میگیرد",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Invisible tracking happens in all sorts of ways; ads are just the visible tip of the iceberg. Privacy Badger sends the <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control signal</a>, to opt you out of data sharing and selling, and the <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track signal</a> to tell companies not to track you. If they ignore your wishes, Privacy Badger will learn to block them—whether they are advertisers or trackers of other kinds.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "بستن",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "ایمپورت داده کاربری",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "سازگار با DNT (ردیابی نکن)",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "راهنما",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "اجازه داده شده",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "حریم خصوصی یک ورزش تیمی می باشد.",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "در اینجا نیاز نیست چیزی را تغییر دهید.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "همه",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "لغو",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "برای بلاک کردن یک دامنه اسلایدر را به سمت چپ حرکت دهید",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Send websites the \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" and \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\" signals",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Disable sending web addresses you visit to Google. This disables suggestions for similar pages when a page can't be found.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Disable hyperlink auditing",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "کنترل شده توسط کاربر",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is disabled on the following sites. This means that Privacy Badger will not block anything when you visit the sites listed here, and it will not send the Do Not Track or Global Privacy Control signals.</p><p>If you think Privacy Badger is breaking a page, or you would like to allow a particular site to share or sell your data, you can type that page's domain in the box below and click the \"Add domain\" button.</p><p>Alternatively, when you already have the page's tab selected, you can just click on Privacy Badger's button in the browser toolbar and then click the \"Disable\" button.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ potential $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "No $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "There are no third party resources on this page. Hooray for privacy!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "پروژه ای از EFF",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "افزودن دامنه",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "برای اجازه دادن به یک دامنه، اسلایدر را به سمت راست حرکت دهید",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "غیرفعال سازی پرایوسی بجر برای این سایت",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "برای اجازه دادن به این دامنه روی اینجا کلیک کنید",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privacy Badger will NEVER share data about your browsing unless you choose to share it.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger has decided to block $COUNT$ potential $TRACKER_LINK_START$tracking domains$TRACKER_LINK_END$ so far",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "پرایوسی بجر هنوز نتوانسته هیچ <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'> دامنه ی ردیابی </a> پیدا کنید. به گردش خود در وب ادامه دهید!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "پرایوسی بجر",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "زمانی که یک ردیاب را در سه سایت مختلف ببیند، پرایوسی بجر شروع به بلاک کردن آن می کند.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "فیلتر کردن بر اساس وضعیت:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "به طور مختصر خطای زیر را شرح دهید.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "حذف گزینه (های) انتخاب شده",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "هنگام استفاده از پرایوسی بجر شما به <a href='https://www.eff.org/' target='_blank'> بنیاد مرزی الکترونیکی </a> و میلیون ها کاربر دیگر در مبارزه برای حریم خصوصی می پیوندید. ما یک بنیاد غیر انتفاعی هستیم که برای حقوق آنلاین شما می جنگیم. ممنون از اینکه به ما پیوستید!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "برای استثناء قائل شدن دامنه ها، به اول عبارت \"-\" اضافه کنید. برای مثال، \".co -.com\" دامنه های co. و co.uk. را نمایش داده می شود اما دامنه های com. نمایش داده نخواهند شد.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "اگر فکر میکنید که پرایوسی بجر باعث از کار افتادن سایتی شده است ( برای مثال، یک ویدیو پخش نمی شود)، میتوانید روی دکمه 'غیرفعال سازی' کلیک کنید تا پرایوسی بجر برای آن سایت غیرفعال شود.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "سیاست حفظ حریم خصوصی",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "توضیحات",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Your Badger hasn't decided yet if these domains should get blocked",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Show domains your Badger hasn't decided yet to block:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "دامنه های زیر به نظر شما را ردیابی نمی کنند",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "گزینه ها",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "اشتراک گذاری بر روی فیسبوک",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "پرایوسی بجر به صورت اتوماتیک یاد می گیرد تا ردیاب های مخفی را بلاک کند.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "اوه. خطایی رخ داد.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "پرایوسی بجر دکمه $BUTTON$ را جایگزین کرده است",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger has replaced this $WIDGET$ widget",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "یکبار اجازه دادن",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Always allow on this site",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "همگام سازی ابری: <ul><li>به همگام سازی فایرفاکس/کروم نیاز دارد</li><li>آپلود باعث دوباره نویسی داده پرایوسی بجر در کلود می شود</li><li>دانلود، لیست سایت هایی که پرایوسی بجر برای آن ها غیرفعال است را ترکیب میکند</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "آپلود",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "انتقال سایت های غیرفعال شده به کلود",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "ایمپورت سایت های غیرفعال شده از کلود",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "داده ابری با موفقیت ایمپورت شد.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "داده ابری دانلود نشد.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "داده ابری با موفقیت آپلود شد.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "داده ابری آپلود نشد.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "هیچ داده ابری برای دانلود وجود ندارد.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "به دوستانتان اطلاع دهید",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "به اشتراک بگذارید",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger blocked $COUNT$ potential trackers on $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "پرایوسی بجر (www.eff.org/privacybadger) یک افزونه‌ی مرورگر است که به صورت خودکار می‌آموزد تا ردیاب‌های مخفی را مسدود کند. پرایوسی بجر توسط Electronic Frontier Foundation ساخته شده که به صورت غیر انتفاعی و آنلاین برای حقوق شما به می‌جنگد.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "کپی به کلیپ‌بورد",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "کپی شد",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Nothing to do on this page",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger doesn't work on special pages like this one. Try browsing somewhere else.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger is disabled on this site",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Widget Replacement",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "When blocking social buttons and other potentially useful (video, audio, comments) widgets, Privacy Badger can replace them with click-to-activate placeholders.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/fi/messages.json b/src/_locales/fi/messages.json
new file mode 100644
index 0000000..bd7796f
--- /dev/null
+++ b/src/_locales/fi/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "$DOMAIN$ estetty",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "JSON-tiedosto ei kelpaa.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Haluatko varmasti poistaa tämän verkkotunnuksen Privacy Badgerista?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "Ei jäljitystä verkkotunnuksesta $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "Tällä hetkellä Privacy Badger tarkistaa ainoastaan, käyttävätkö kolmannet osapuolet evästeitä, HTML5:n paikallista tallennusta tai canvas-elementtiin perustuvaa sormenjälkeä seuratakseen verkkoselaamistasi. Jotkin näistä verkkotunnuksista saattavat käyttää seurantamenetelmiä, joita Privacy Badger ei tunnista.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "Tarkista, noudattavatko <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>kolmansien osapuolten verkkotunnukset</a> <a target='_blank' href='https://www.eff.org/dnt-policy'>EFF:n Do Not Track -käytäntöä</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Lisää kelvollinen verkkotunnus tai URL.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "Lahjoita EFF:lle",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Auta meitä lahjoittamalla ja antamalla tukesi työkaluillemme",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "En ole mainosten estäjä, olen erilainen",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "Kiitos! Selvitämme asian perin pohjin.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "Tämä verkkotunnus lupaa, ettei se jäljitä sinua",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Tämän verkkotunnuksen estämisen tiedetään rikkovan sivustoja",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Klikkaa palauttaaksesi tämän verkkotunnuksen hallinnan Privacy Badgerille",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "seuraava osio",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "<a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>Kerro meille</a> seuraavasta virheestä:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Hallitse dataa",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Ilmoita virheestä",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "esim. www.verkkotunnus.com, *.verkkotunnus.net, verkkotunnus.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Klikkaa tästä estääksesi tätä verkkotunnusta asettamasta evästeitä",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "estetty",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "Estä WebRTC:tä vuotamasta paikallista IP-osoitetta",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger oppii automaattisesti estämään näkymättömät jäljittimet. Näin se käy:",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "Mikä on pielessä?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Jäljittävät verkkotunnukset",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Jaa Twitterissä",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Lue, miten Privacy Badger suojelee yksityisyyttäsi",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "Lataa",
+ "description": ""
+ },
+ "import": {
+ "message": "Tuo",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "Älä korvaa seuraavia sovelmia:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Ota sovelmien korvaaminen käyttöön",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Näytä verkkotunnukset, jotka eivät vaikuta jäljittävän sinua",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Lähetä virheilmoitus",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "$DOMAIN$ sallittu",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "Mikä on Privacy Badger?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Etsi verkkotunnuksia:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Learn to block new trackers from your browsing",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Enabling learning may make you more identifiable to websites",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Opi yksityisessä selauksessa",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "Jos otat oppimisen käyttöön yksityisessä selauksissakin, tietokoneellesi voi jäädä jälkiä selaushistoriastasi. Oletusarvoisesti Privacy Badger estää tuntemansa jäljittimet selattaessa yksityisesti, muttei opettele uusia jäljittimiä. Tämä valinta voi olla paikallaan, jos selaat nettiä paljon yksityisesti.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger will no longer learn from your browsing by default.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Click below to learn more.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Learn how Privacy Badger is changing",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Näytä jäljitinten määrä",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "Mikä on jäljitin?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "Muista klikata 'Rikkoiko Privacy Badger tämän sivuston?' -painiketta. Kunnioitamme yksityisyyttäsi, emmekä siksi lähetä automaattisesti virheilmoituksia.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Privacy Badgerin asetukset",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "Seuraavat tiedot lähetetään automaattisesti EFF:lle: sivu, jolla olet nyt, selaimesi versio, Privacy Badgerin versio sekä kaikkien liukuvalitsimien tila tämän sivun osalta.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Käytöstä poistetut sivustot",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Ota Privacy Badger käyttöön tällä sivustolla",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Suodata tyypin mukaan:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "Jäljitinlista ja asetukset päivitetty!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Vie käyttäjädata",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "Käyttäjädatan tuominen:<ul><li>Ylikirjoittaa yleiset asetukset</li><li>Yhdistää listat käytöstä poistetuista sivustoista</li><li>Yhdistää tiedot Privacy Badgerin havaitsemista jäljittimistä</li><li>Ylikirjoittaa liukuvalitsimien muokkaukset</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Nollaa",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Nollaa jäljittävät verkkotunnukset",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Jäljittävien verkkotunnusten nollaaminen:\n\n • Poistaa kaiken jäljittäjiä koskevan datan, jonka Privacy Badger on oppinut selaamisestasi\n • Palauttaa jäljittävien verkkotunnusten listaksi uusimman esikoulutetun listan (katso lisätietoja osoitteesta www.eff.org/badger-pretraining )",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Poista kaikki",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Poista kaikki jäljittävät verkkotunnukset",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "Kaikkien jäljittävien verkkotunnusten poistaminen:\n\n • Poistaa kaiken, mitä Privacy Badger tietää jäljittimistä\n • Saa Privacy Badgerin olemaan estämättä mitään, kunnes se on saanut mahdollisuuden oppia uudelleen selaamisesi pohjalta",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "Privacy Badger suojelee nyt sinua.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "Voit klikata alta avataksesi nopean oppaan, joka kertoo, miten Privacy Badger toimii.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC voi vuotaa paikallisen IP-osoitteesi. Huomaa, että tämä valinta voi haitata Google Hangoutsin tapaisten konferenssisovellusten toimintaa.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "Yleiset asetukset",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Tietosuoja",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Advanced",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Esittelykierros",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Klikkaa tästä estääksesi tämän verkkotunnuksen kokonaan",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "versio $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "Evästeet estetty verkkotunnuksesta $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "osittain estetty",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "Ymmärrän; näytä silti lista jäljittävistä verkkotunnuksista",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Kiitos, että asensit Privacy Badgerin!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "Valitse tuotava tiedosto.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "Rikkoiko Privacy Badger tämän sivuston? Kerro siitä meille!",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Evästeet estetään, kun liukuvalitsin on keskellä",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Learns automatically",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Instead of keeping lists of what to block, Privacy Badger automatically discovers trackers based on their behavior.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Nappaa katalat jäljittimet",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Invisible tracking happens in all sorts of ways; ads are just the visible tip of the iceberg. Privacy Badger sends the <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control signal</a>, to opt you out of data sharing and selling, and the <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track signal</a> to tell companies not to track you. If they ignore your wishes, Privacy Badger will learn to block them—whether they are advertisers or trackers of other kinds.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Sulje",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Tuo käyttäjädata",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "DNT:tä noudattava",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Ohje",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "sallittu",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "Yksityisyys on tiimipeliä!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "Näitä ei pitäisi olla tarpeen muuttaa.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "kaikki",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "Peruuta",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Verkkotunnus estetään, kun liukuvalitsin on vasemmalla",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Send websites the \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" and \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\" signals",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Disable sending web addresses you visit to Google. This disables suggestions for similar pages when a page can't be found.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Disable hyperlink auditing",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "käyttäjän hallitsema",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is disabled on the following sites. This means that Privacy Badger will not block anything when you visit the sites listed here, and it will not send the Do Not Track or Global Privacy Control signals.</p><p>If you think Privacy Badger is breaking a page, or you would like to allow a particular site to share or sell your data, you can type that page's domain in the box below and click the \"Add domain\" button.</p><p>Alternatively, when you already have the page's tab selected, you can just click on Privacy Badger's button in the browser toolbar and then click the \"Disable\" button.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ mahdollista $LINK_START$jäljitintä$LINK_END$ estetty",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "Yhtään $LINK_START$jäljitintä$LINK_END$ ei ole estetty",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "Tällä sivulla ei ole kolmansien osapuolten resursseja. Eläköön yksityisyys!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Electronic Frontier Foundationin projekti",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Lisää verkkotunnus",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Verkkotunnus sallitaan, kun liukuvalitsin on oikealla",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Poista Privacy Badger käytöstä tällä sivustolla",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Klikkaa tästä salliaksesi tämän verkkotunnuksen",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privacy Badger ei koskaan jaa tietoa nettiselaamisestasi, ellet itse halua.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger has decided to block $COUNT$ potential $TRACKER_LINK_START$tracking domains$TRACKER_LINK_END$ so far",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privacy Badger ei ole vielä havainnut yhtään <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>jäljittävää verkkotunnusta</a>. Jatka selaamista!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger aloittaa estämisen, kun se näkee saman jäljittimen kolmella eri sivustolla. Kolmesta poikki!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Suodata tilan mukaan:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Kuvaile virhetilanne lyhyesti alapuolelle.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Poista valitut",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "Käyttämällä Privacy Badgeria liityt <a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundationin</a> ja miljoonien muiden käyttäjien joukkoon taistelussa yksityisyyden puolesta. Olemme voittoa tavoittelematon järjestö, joka taistelee oikeuksiesi puolesta verkossa. Kiitos, että liityt mukaan!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "Sulkeaksesi verkkotunnuksia pois hausta, laita hakutermisi eteen \"-\". Esimerkiksi \".co -.com\" näyttää .co- ja .co.uk-verkkotunnukset, muttei .com-verkkotunnuksia.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Jos arvelet, että Privacy Badger rikkoo nettisivun (esim. video ei toimi), voit klikata 'Poista käytöstä' -painiketta poistaaksesi Privacy Badgerin käytöstä kyseisellä sivustolla.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Tietosuojakäytäntö",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Kuvaus",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Badgerisi ei ole vielä päättänyt, estetäänkö nämä verkkotunnukset",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Näytä verkkotunnukset, joita Badgerisi ei ole vielä päättänyt estää:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "Alla olevat verkkotunnukset eivät vaikuta jäljittävän sinua",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Asetukset",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Jaa Facebookissa",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privacy Badger oppii automaattisesti estämään näkymättömät jäljittimet.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "Hups. Jotakin meni pieleen.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "Privacy Badger on korvannut tämän $BUTTON$-painikkeen",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger on korvannut tämän $WIDGET$-sovelman",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Salli tämän kerran",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Salli aina tällä sivustolla",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Pilvisynkronointi:<ul><li>Vaatii Firefox/Chrome Syncin</li><li>Pilveen lataaminen ylikirjoittaa pilvessä mahdollisesti jo olevan Privacy Badgerin datan</li><li>Pilvestä lataaminen yhdistää listat sivustoista, joilla Badgerisi on poistettu käytöstä</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Lataa pilveen",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Vie käytöstä poistetut sivustot pilveen",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Tuo käytöstä poistetut sivustot pilvestä",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Data tuotu pilvestä.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "Dataa ei voitu ladata pilvestä.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "Data ladattu pilveen.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "Dataa ei voitu ladata pilveen.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "Pilvessä ei ole dataa ladattavaksi.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Kerro kavereillesi",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Jaa",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger blocked $COUNT$ potential trackers on $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privacy Badger (www.eff.org/privacybadger) on selainlaajennus, joka oppii automaattisesti estämään näkymättömät jäljittimet. Privacy Badgerin on tehnyt Electronic Frontier Foundation, voittoa tavoittelematon järjestö joka taistelee oikeuksiesi puolesta verkossa.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "Kopioi leikepöydälle",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Kopioitu",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Ei mitään tehtävää tällä sivulla",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger ei toimi tämänkaltaisilla erikoissivuilla. Kokeile selata muualla.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger on poistettu käytöstä tällä sivustolla",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Sovelmien korvaaminen",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "Estäessään sosiaalisen median painikkeita ja muita mahdollisesti hyödyllisiä (video-, ääni-, kommentti-) sovelmia, Privacy Badger voi korvata ne klikkaamalla aktivoitavilla korvikkeilla.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/fr/messages.json b/src/_locales/fr/messages.json
new file mode 100644
index 0000000..0814767
--- /dev/null
+++ b/src/_locales/fr/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "Blocage de $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "Fichier JSON invalide.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Voulez-vous vraiment supprimer ce domaine de Privacy Badger ?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "Pas de traçage de $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "À ce jour, Privacy Badger vérifie seulement si un tiers se sert de cookies, du stockage HTML5 local ou de l'empreinte par canvas pour épier votre navigation. Il se peut que d'autres méthodes non détectées soient utilisées.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "Vérifier si les <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>domaines tiers</a> se conforment à la charte de <a target='_blank' href='https://www.eff.org/dnt-policy'>non-pistage de l'EFF</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Veuillez ajouter un domaine ou une URL valide.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "Faire un don à l'EFF",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Aidez-nous par un don et en partageant votre appréciation de nos outils",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "Différent d'un bloqueur de publicités",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "Merci ! Nous allons étudier ça.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "Ce domaine s'engage à ne pas vous tracer",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Bloquer ce domaine est connu pour perturber certains sites",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Cliquer pour redonner le contrôle de ce domaine à Privacy Badger",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "section suivante",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "Merci de nous <a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>signaler</a> l'erreur suivante :",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Gestion des données",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Signaler une erreur",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "p. ex. www.domaine.com, *.domaine.net, domaine.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Cliquer ici pour bloquer les cookies de ce domaine",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "bloqués",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "Empêcher la fuite des adresses IP locales via WebRTC",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger apprend automatiquement à bloquer les traceurs invisibles. Prenez une minute pour comprendre comment.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "Quel est le problème ?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Domaines traceurs",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Partager sur Twitter",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Apprendre comment Privacy Badger protège votre vie privée",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "Télécharger",
+ "description": ""
+ },
+ "import": {
+ "message": "Importer",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "Ne pas remplacer les widgets suivant :",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Autoriser le remplacement des widgets",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Afficher les domaines qui ne semblent pas vous tracer",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Soumettre l'erreur",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "Autorisation de $DOMAIN$",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "Qu'est-ce que Privacy Badger ?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Rechercher un nom de domaine :",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Apprendre à bloquer de nouveaux traceurs en naviguant",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Activer l'apprentissage peut vous rendre plus identifiable par les sites internet",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Activer l'apprentissage dans les fenêtres de navigation privée",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "Dans les fenêtres de navigation privée, Privacy Badger se contente de bloquer les traceurs qu'il connait. En activant cette option, il cherchera aussi à en identifier de nouveaux. Ceci pourrait laisser sur votre ordinateur des traces de sites que vous visitez. Son utilité pourrait se révéler si vous naviguez beaucoup en mode privé.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger will no longer learn from your browsing by default.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Click below to learn more.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Learn how Privacy Badger is changing",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Afficher le nombre de traceurs",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "Qu'est-ce qu'un traceur ?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "N'hésitez pas à cliquer sur « Signaler un site non fonctionnel ». Respectant votre vie privée, les rapports ne sont pas automatiquement envoyés.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Options de Privacy Badger",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "La page que vous visitez, la version de votre navigateur et de Privacy Badger, ainsi que le réglage des curseurs pour cette page seront automatiquement transmis à l'EFF.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Liste blanche",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Activer Privacy Badger pour ce site",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Filtrer par type :",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "Liste des traceurs et paramètres mis à jour avec succès !",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Exporter les données utilisateur",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "Importer des données utilisateur :<ul><li>Remplace les réglages généraux</li><li>Combine les listes blanches</li><li>Combine les informations sur les sites que Privacy Badger a vus</li><li>Remplace les personnalisations des curseurs</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Réinitialiser",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Réinitialisation des domaines traceurs",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Réinitialiser les domaines traceurs :\n\n• supprimera toutes les données apprises par Privacy Badger sur les traceurs  ;\n• restaurera la liste des domaines traceurs à la dernière liste préétablie (www.eff.org/badger-pretraining pour en savoir plus).",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Tout supprimer",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Supprimer tous les domaines traceurs",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "Supprimer tous les domaines traceurs :\n\n• supprimera tout ce que Privacy Badger a appris sur les traceurs ;\n• suspendra tout blocage des traceurs jusqu'à ce que Privacy Badger apprenne à les reconnaitre de nouveau.",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "Vous êtes maintenant protégé par Privacy Badger.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "Pour découvrir son fonctionnement, cliquez ci-dessous pour un tutoriel rapide.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC peut divulguer vos adresses IP locales. Activer cette option peut dégrader les performances des logiciels de visiophonie comme Google Hangouts.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "Réglages généraux",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Confidentialité",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Avancées",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Commencer la visite",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Cliquer ici pour bloquer entièrement ce domaine",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "version $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "Blocage des cookies de $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "partiellement bloqués",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "Je comprends. Montrez-moi quand même la liste de domaines traceurs.",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Merci d'avoir installé Privacy Badger !",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "Veuillez sélectionner un fichier à importer.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "Signaler un site non fonctionnel",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Centrer le curseur pour bloquer les cookies",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Learns automatically",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Instead of keeping lists of what to block, Privacy Badger automatically discovers trackers based on their behavior.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Intercepte les traceurs sournois",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Invisible tracking happens in all sorts of ways; ads are just the visible tip of the iceberg. Privacy Badger sends the <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control signal</a>, to opt you out of data sharing and selling, and the <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track signal</a> to tell companies not to track you. If they ignore your wishes, Privacy Badger will learn to block them—whether they are advertisers or trackers of other kinds.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Fermer",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Importer des données utilisateur",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "respectant les règles de non-pistage",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Aide",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "autorisés",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "La vie privée est un effort de groupe !",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "Vous ne devriez pas avoir besoin de modifier quoi que ce soit ici.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "tous",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "Annuler",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Déplacer le curseur à gauche pour bloquer un domaine",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Send websites the \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" and \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\" signals",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Désactiver l'envoi à Google des adresses web que vous visitez. Des pages similaires ne seront alors plus suggérer lorsqu'une page n'est pas trouvée.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Désactiver l'analyse des hyperliens",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "définis par l'utilisateur",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is disabled on the following sites. This means that Privacy Badger will not block anything when you visit the sites listed here, and it will not send the Do Not Track or Global Privacy Control signals.</p><p>If you think Privacy Badger is breaking a page, or you would like to allow a particular site to share or sell your data, you can type that page's domain in the box below and click the \"Add domain\" button.</p><p>Alternatively, when you already have the page's tab selected, you can just click on Privacy Badger's button in the browser toolbar and then click the \"Disable\" button.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ $LINK_START$traceurs$LINK_END$ potentiels bloqués",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "Aucun $LINK_START$traceur$LINK_END$ bloqué",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "Il n'y a pas de ressource tierce sur cette page. Un point pour la vie privée !",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Un projet de l'Electronic Frontier Foundation",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Ajouter un domaine",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Déplacer le curseur à droite pour autoriser un domaine",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Désactiver Privacy Badger pour ce site",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Cliquer ici pour autoriser ce domaine",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Il ne communiquera jamais sur votre navigation, sauf si vous le décidez.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger has decided to block $COUNT$ potential $TRACKER_LINK_START$tracking domains$TRACKER_LINK_END$ so far",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privacy Badger n'a pas encore détecté de <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>domaine traceur</a>. Continuez à naviguer !",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger décide de bloquer un traceur lorsqu'il est détecté sur trois sites internet différents.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Filtrer par statut :",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Décrivez brièvement ci-dessous l'erreur.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Supprimer la sélection",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "Lorsque vous utilisez Privacy Badger, vous rejoignez l'<a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundation</a> et des millions d'autres utilisateurs dans le combat pour la vie privée. Nous sommes à but non lucratif et nous battons pour vos droits en ligne. Merci d'en faire parti !",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "Pour exclure un domaine, ajoutez \"-\" devant celui-ci lors de votre recherche. Par exemple, \".co -.com\" affichera les domaines en .co ou .co.uk, mais pas .com.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Si vous soupçonner Privacy Badger de perturber le fonctionnement d'une page (par exemple, la lecture d'une vidéo), vous pouvez cliquer sur le bouton « Désactiver » pour l'empêcher d'opérer sur ce site.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Politique de confidentialité",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Description",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Privacy Badger n'a pas encore décidé si ces domaines devaient être bloqués",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Afficher les domaines que Privacy Badger ne s'est pas encore décidé à bloquer : ",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "Les domaines ci-dessous ne semblent pas vous tracer.",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Options",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Partager sur Facebook",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privacy Badger apprend automatiquement à bloquer les traceurs invisibles.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "Oups, quelque chose a râté.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "Privacy Badger a remplacé ce bouton $BUTTON$",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger a remplacé ce widget $WIDGET$",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Autoriser une fois",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Toujours autoriser sur ce site",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Synchronisation avec le nuage : <ul><li>Nécessite Firefox ou Chrome Sync</li><li>Le téléversement écrase toutes données de Privacy Badger dans le nuage</li><li>Télécharger combinera la liste blanche avec celle présente</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Téléverser",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Exporter la liste blanche dans le nuage",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Importer la liste blanche du nuage",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Données du nuage correctement importées.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "Les données du nuage n'ont pas pu être téléchargées.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "Données correctement téléversées dans le nuage.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "Les données du nuage n'ont pas pu être téléversées.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "Pas de données dans le nuage à télécharger.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Parlez-en à vos amis",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Partager",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger a bloqué $COUNT$ traceurs potentiels sur $DOMAIN$ :",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privacy Badger (www.eff.org/privacybadger) est une extension de navigateur qui apprend automatiquement à bloquer les traceurs invisibles. Il est conçu par l'Electronic Frontier Foundation, une organisation à but non lucratif qui se bat pour vos droits en ligne.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "Copier dans le presse-papiers",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Copié",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Rien à faire sur cette page",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger ne fonctionne pas sur les pages spéciales comme celle-ci. Essayez de naviguer ailleurs.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger est désactivé pour ce site",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Remplacement de widgets",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "Les boutons sociaux bloqués, et autres widgets potentiellement utiles (vidéos, sons, commentaires), peuvent être remplacés par une option « cliquer pour activer ».",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/he/messages.json b/src/_locales/he/messages.json
new file mode 100644
index 0000000..ce3203a
--- /dev/null
+++ b/src/_locales/he/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "$DOMAIN$ חסום",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "קובץ JSON בלתי תקף.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "האם אתה בטוח שאתה רוצה להסיר תחום זה מתוך Privacy Badger?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "אין מעקב עבור $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "כרגע Privacy Badger בודק רק אם צדדים שלישיים משתמשים בעוגיות, אחסון מקומי HTML5 או לקיחת טביעת אצבע של בד כדי לאתר את גלישתך. חלק מתחומים אלו עשוי להשתמש בשיטות מעקב אשר Privacy Badger אינו יכול לגלות.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "בדוק אם <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>תחומי צד־שלישי</a> מצייתים אל <a target='_blank' href='https://www.eff.org/dnt-policy'>מדיניות אל תעקוב של EFF</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "אנא הוסף תחום או כתובת תקפים.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "תרום אל EFF",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "עזור לנו ע״י תרומה ושיתוף של תמיכתך בכלים שלנו",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "לא חוסם פרסומות, אני שונה",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "תודה! נחקור זאת לעומק.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "תחום זה מבטיח לא לעקוב אחריך.",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "חסימת תחום זה ידועה בתור שוברת אתרים",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "לחץ כדי להחזיר שליטה בתחום זה אל Privacy Badger",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "הקטע הבא",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "אנא <a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>ספר לנו</a> על השגיאה הבאה:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "ניהול נתונים",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "דווח על שגיאה",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "לדוגמה www.domain.com, *.domain.net, domain.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "לחץ כאן כדי למנוע מתחום זה להשתמש בעוגיות",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "חסום",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "מנע מן WebRTC להדליף כתובת IP מקומית",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger לומד באופן אוטומטי לחסום עוקבנים בלתי נראים. קח דקה כדי לראות כיצד.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "מה לא בסדר?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "תחומי מעקב",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "שתף ב־Twitter",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "למד כיצד Privacy Badger מגן על פרטיותך",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "הורד",
+ "description": ""
+ },
+ "import": {
+ "message": "ייבא",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "אל תחליף את היישומונים הבאים:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "אפשר החלפת יישומונים",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "הראה תחומים שנראה כי אינם עוקבים אחריך",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "הגש שגיאה",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "$DOMAIN$ מותר",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "מהו Privacy Badger?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "חפש תחומים:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "למד לחסום עוקבנים חדשים מתוך גלישתך",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "אפשור למידה עשוי לעשות אותך בר־זיהוי יותר כלפי אתרים",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "למד בחלונות פרטיים או בחלונות עילום שם",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "איפשור למידה בחלונות פרטיים או בחלונות עילום שם עלול להותיר עקבות של היסטוריה של גלישה פרטית. כברירת מחדל, Privacy Badger יחסום עוקבנים שהוא כבר יודע עליהם בחלונות פרטיים או בחלונות עילום שם, אבל הוא לא ילמד על עוקבנים חדשים. ייתכן שתרצה לאפשר אפשרות זו אם חלק גדול של הגלישה שלך מתרחש בחלונות פרטיים או בחלונות עילום שם.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger לא ילמד עוד מגלישתך כברירת מחדל.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "לחץ למטה כדי ללמוד עוד.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "למד כיצד Privacy Badger משתנה",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "הראה ספירת עוקבנים",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "מהו עוקבן?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "אנא אל תשכח ללחוץ על 'Privacy Badger שבר את האתר הזה'. אנו מכבדים את פרטיותך כך שלא נשלח דוחות אוטומטיים.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "אפשרויות Privacy Badger",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "זה ישלח באופן אוטומטי את המידע הבא אל EFF: הדף שאתה כרגע מבקר בו, גרסת הדפדפן שלך, הגרסה של Privacy Badger והמצב של כל המחוונים בדף זה.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "אתרים מושבתים",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "אפשר את Privacy Badger עבור אתר זה",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "סנן לפי סוג:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "רשימת עוקבנים והגדרות עודכנו בהצלחה!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "ייצא נתוני משתמש",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "יבוא נתוני משתמש:<ul><li>דריסת הגדרות כלליות</li><li>שילוב רשימות של אתרים מושבתים</li><li>שילוב מידע על אילו עוקבנים Privacy Badger ראה</li><li>דריסת התאמות אישיות של מחוונים</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "אפס",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "אפס תחומי מעקב",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "איפוס תחומי מעקב:\n\n • ימחק את כל הנתונים על עוקבנים אשר Privacy Badger למד מגלישתך \n • ישחזר את רשימת תחומי המעקב אל הרשימה הקדם־מאומנת (בקר בכתובת www.eff.org/badger-pretraining כדי ללמוד עוד)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "הסר הכל",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "הסר את כל תחומי המעקב",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "הסרת כל תחומי המעקב:\n\n • תמחק את כל מה ש־Privacy Badger יודע על עוקבנים\n • תיגרום אל Privacy Badger לא לחסום שום דבר עד שיהיה לו סיכוי ללמוד את זה שוב מגלישתך",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "אתה מוגן כעת על ידי Privacy Badger.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "כדי ללמוד כיצד Privacy Badger עובד, לחץ למטה עבור הדרכה זריזה.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC יכול להדליף את כתובת ה־IP המקומית שלך. שים לב שאיפשור אפשרות זו עלול להפחית ביצועים על יישומי ועידת רשת כמו Google Hangouts.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "הגדרות כלליות",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "פרטיות",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "מתקדם",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "צא לסיור",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "לחץ כאן כדי לחסום לגמרי תחום זה",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "גרסה $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "עוגיות חסומות מן $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "חסום חלקית",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "אני מבין; אנא הראה לי את רשימת תחומי המעקב בכל זאת",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "תודה על התקנת Privacy Badger!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "אנא בחר קובץ לייבא.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "Privacy Badger שבר את האתר הזה? יידע אותנו!",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "מרכז את המחוון כדי לחסום עוגיות",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "לומד באופן אוטומטי",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "במקום לשמור רשימות של מה לחסום, Privacy Badger מגלה באופן אוטומטי עוקבנים על סמך התנהגותם.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "תופס עוקבנים ערמומיים",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "מעקב בלתי נראה מתרחש בכל מיני דרכים; פרסומות הן הקצה הנראה של הקרחון. Privacy Badger שולח את <a href='https://globalprivacycontrol.org/' target='_blank'>האות בקרה גלובלית של פרטיות</a>, כדי להוציא אותך משיתוף ומכירה של נתונים, ואת <a href='https://www.eff.org/issues/do-not-track' target='_blank'>האות אל תעקוב</a> כדי לומר לחברות לא לעקוב אחריך. אם הן מתעלמות מבקשותיך, Privacy Badger ילמד לחסום אותן—בין אם הן מפרסמים או עוקבנים מסוגים אחרים.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "סגור",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "ייבא נתוני משתמש",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "תואם־DNT",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "עזרה",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "מותר",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "פרטיות היא ספורט קבוצתי!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "אינך אמור להיות צריך לשנות שום דבר כאן.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "הכל",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "בטל",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "הזז את המחוון שמאלה כדי לחסום תחום",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "שלח אל אתרים את האותות \"<a href='https://globalprivacycontrol.org/' target='_blank'>בקרה גלובלית של פרטיות</a> ו\"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>אל תעקוב</a>",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "השבת שליחת כתובות אתר שאתה מבקר בהן אל Google. זה משבית הצעות אל דפים דומים כאשר דף אינו יכול להימצא.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "השבת בדיקת היפר־קישורים",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "נשלט־משתמש",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger מושבת באתרים הבאים. זה אומר כי Privacy Badger לא יחסום שום דבר כאשר תבקר באתרים הכתובים למטה, והוא לא ישלח את האות אל תעקוב או את האות בקרה גלובלית של פרטיות.</p><p>אם אתה חושב כי Privacy Badger שובר עמוד, או אם אתה רוצה להתיר לאתר מסוים לשתף או למכור את הנתונים שלך, אתה יכול להקליד את תחום האתר בתיבה למטה וללחוץ על הכפתור \"הוסף תחום\".</p><p>לחלופין, כאשר לשונית העמוד כבר נבחרה, אתה יכול פשוט ללחוץ על הכפתור של Privacy Badger בסרגל הכלים של הדפדפן ואז ללחוץ על הכפתור \"השבת\".</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ $LINK_START$עוקבנים$LINK_END$ פוטנציאליים נחסמו",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "$LINK_START$עוקבנים$LINK_END$ לא נחסמו",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "אין משאבי צד שלישי בדף זה. הידד לפרטיות!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "מיזם של הקרן של החזית האלקטרונית",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "הוסף תחום",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "הזז את המחוון ימינה כדי להתיר תחום",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "השבת את Privacy Badger עבור אתר זה",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "לחץ כאן כדי להתיר תחום זה",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privacy Badger לעולם לא ישתף נתונים על גלישתך אלא אם תבחר לשתף אותם.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger החליט לחסום $COUNT$ $TRACKER_LINK_START$תחומי מעקב$TRACKER_LINK_END$ פוטנציאליים עד כה",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privacy Badger לא גילה <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>תחומי מעקב</a> עדין. המשך לגלוש!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger מתחיל לחסום ברגע שהוא רואה את אותו עוקבן בשלושה אתרים שונים. שלוש פגיעות והוא בחוץ!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "סנן לפי מעמד:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "תאר בקצרה את השגיאה למטה.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "הסר נבחרים",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "כאשר אתה משתמש ב־Privacy Badger אתה מצטרף אל <a href='https://www.eff.org/' target='_blank'>הקרן של החזית האלקטרונית</a> ואל מיליוני משתמשים אחרים בלחימה למען פרטיות. אנחנו ארגון ללא מטרות רווח הנלחם על זכויותיך באופן מקוון. תודה שהצטרפת אלינו!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "כדי לשלול תחומים, הוסף בראש אל מונח החיפוש שלך \"-\". לדוגמה, \".co -.com\" יראה תחומי .co ותחומי .co.uk אבל לא תחומי .com",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "אם אתה חושב כי Privacy Badger שובר עמוד (סרטון לא מתנגן, לדוגמה), אתה יכול ללחוץ על הכפתור 'השבת' כדי לכבות את Privacy Badger עבור אותו אתר.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "מדיניות פרטיות",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "תיאור",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Privacy Badger לא החליט עדין אם תחומים אלו צריכים להיחסם",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "הראה תחומים אשר Privacy Badger לא החליט עדין אם לחסום:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "לא נראה שהתחומים למטה עוקבים אחריך",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "אפשרויות",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "שתף ב־Facebook",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privacy Badger לומד באופן אוטומטי לחסום עוקבנים בלתי נראים.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "אופס. משהו השתבש.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "זה $BUTTON$ החליף כפתור Privacy Badger",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger החליף יישומון $WIDGET$ זה",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "התר פעם אחת",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "התר תמיד באתר זה",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "סינכרון ענן:<ul><li>דורש סינכרון Firefox/Chrome</li><li>העלאה דורסת נתונים קיימים כלשהם של Privacy Badger בענן</li><li>הורדה משלבת את רשימות האתרים בהם Privacy Badger מושבת</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "העלה",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "ייצא אתרים מושבתים אל ענן",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "ייבא אתרים מושבתים מענן",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "נתוני ענן יובאו בהצלחה.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "נתוני ענן לא יכלו לרדת.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "נתוני ענן הועלו בהצלחה.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "נתוני ענן לא יכלו להיעלות.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "אין נתוני ענן להוריד.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "ספר לחבריך",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "שתף",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger חסם $COUNT$ עוקבנים פוטנציאליים בתחום $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privacy Badger (www.eff.org/privacybadger) הוא הרחבת דפדפן אשר לומדת באופן אוטומטי לחסום עוקבנים בלתי נראים. Privacy Badger נוצר על ידי הקרן של החזית האלקטרונית, ארגון ללא מטרות רווח שנלחם על זכויותיך באופן מקוון.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "העתק ללוח עריכה",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "הועתק",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "אין מה לעשות בדף זה",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger אינו עובד על עמודים מיוחדים כמו זה. נסה לגלוש במקום כלשהו אחר.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger מושבת באתר זה",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "החלפת יישומונים",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "בעת חסימת כפתורים חברתיים ויישומונים שימושיים פוטנציאלים אחרים (סרטון, שמע, תגובות), Privacy Badger יכול להחליף אותם בממלאי מקום של לחץ־כדי־לשפעל.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/it/messages.json b/src/_locales/it/messages.json
new file mode 100644
index 0000000..b1185e2
--- /dev/null
+++ b/src/_locales/it/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "Bloccato $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "File JSON non valido.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Sei sicuro di voler rimuovere questo dominio da Privacy Badger?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "Nessun tracciamento da $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "Al momento Privacy Badger sta controllando esclusivamente se terze parti stanno usando dei cookie, local storage HTML5 o il canvas fingerprinting per tracciare la navigazione. Alcuni di questi domini potrebbero utilizzare metodi di tracciamento che Privacy Badger non è in grado rilevare.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "Controlla se i <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>domini di terze parti</a> rispettano la <a target='_blank' href='https://www.eff.org/dnt-policy'>politica Do Not Track della EFF</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Inserisci un dominio o URL valido.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "Dona alla EFF",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Aiutaci donando e offrendo il tuo supporto per i nostri strumenti",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "Non un ad-blocker, sono diverso",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "Grazie! Indagheremo a fondo.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "Questo dominio si impegna a non tracciarti",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Bloccando questo dominio si rovinano alcuni siti web",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Clicca per restituire il controllo di questo dominio a Privacy Badger",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "prossima sezione",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "<a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>Scrivici</a> riguardo il seguente errore:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Gestione dati",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Segnala un errore",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "es. www.domain.com, *.domain.net, domain.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Clicca qui per bloccare questo dominio dalle impostazioni dei cookie",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "bloccati",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "Impedisci a WebRTC di rivelare l'indirizzo IP locale",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger impara automaticamente a bloccare i tracker invisibili. Prenditi un minuto per vedere come.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "Cosa c'è che non va?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Domini Traccianti",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Condividi su Twitter",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Scopri come Privacy Badger protegge la tua privacy",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "Scarica",
+ "description": ""
+ },
+ "import": {
+ "message": "Importa",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "Non sostituire i seguenti widget:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Attiva sostituzione dei widget",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Mostra i domini che non sembra ti stiano tracciando",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Invia errore",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "Permesso $DOMAIN$",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "Cos'è Privacy Badger?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Cerca domini:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Impara a bloccare nuovi tracker dalla tua navigazione",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "L'attivazione dell'apprendimento può renderti più identificabile dai siti",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Apprendi nelle finestre Private/Incognito",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "L'attivazione dell'apprendimento nelle finestre Private/Incognito potrebbe lasciare tracce nel computer della tua cronologia privata. Normalmente, nelle finestre Private/Incognito Privacy Badger blocca i tracker che conosce già, ma non ricorderà quelli nuovi. Potresti volere attivare questa opzione se navighi spesso utilizzando le finestre Private/Incognito.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger non imparerà più dalla tua navigazione in modo predefinito.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Clicca sotto per maggiori informazioni.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Scopri come Privacy Badger sta cambiando",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Mostra numero di tracker",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "Cos'è un tracker?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "Non dimenticare di cliccare 'Privacy Badger ha dato problemi a questo sito'. Rispettiamo la tua privacy, quindi non inviamo segnalazioni automatiche.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Opzioni di Privacy Badger",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "Verranno inviate automaticamente le seguenti informazioni alla EFF: la pagina che stai visitando, la versione del browser, la versione di Privacy Badger e lo stato di tutti i pulsanti per questa pagina.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Siti disattivati",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Attiva Privacy Badger per questo sito",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Filtra per tipo:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "Lista di tracker e impostazioni aggiornate correttamente!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Esporta dati utente",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "Importazione dati utente:<ul><li>Sovrascrive impostazioni generali</li><li>Combina liste di siti disattivati</li><li>Combina informazioni su quali tracker ha visto Privacy Badger</li><li>Sovrascrive le scelte dei pulsanti</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Ripristina",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Ripristina domini traccianti",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Il ripristino dei domini traccianti causa:\n\n • L'eliminazione di tutti i dati sui tracker che Privacy Badger ha imparato dalla tua navigazione\n • Il ripristino dell'elenco dei domini traccianti all'ultimo elenco pre-istruzione (visita www.eff.org/badger-pretraining per altre info)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Rimuovi tutto",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Rimuovi tutti i domini traccianti",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "La rimozione di tutti i domini traccianti causa:\n\n • L'eliminazione di tutto ciò che Privacy Badger sa sui tracker\n • Privacy Badger non bloccherà nulla finchè non ha avuto la possibilità di re-imparare dalla tua navigazione",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "Ora sei protetto da Privacy Badger.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "Per conoscere il funzionamento del programma, cliccare sotto per una breve guida.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC può rivelare il tuo indirizzo IP locale. Nota che attivare questa opzione potrebbe incidere sulle prestazioni con app di conferenze web come Google Hangouts.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "Impostazioni generali",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Privacy",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Avanzate",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Fai un giro",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Clicca qui per bloccare completamente questo dominio",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "versione $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "Cookie bloccati da $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "parzialmente bloccati",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "Ho capito; mostrami comunque l'elenco dei domini traccianti",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Grazie per aver installato Privacy Badger!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "Seleziona un file da importare.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "Privacy Badger ha dato problemi a questo sito? Faccelo sapere!",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Sposta il pulsante al centro per bloccare i cookie",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Impara automaticamente",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Invece di tenere liste di cosa bloccare, Privacy Badger scopre automaticamente i tracker in base al loro comportamento.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Cattura i tracker subdoli",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Il tracciamento invisibile ha molte forme; le pubblicità sono solo la punta visibile dell'iceberg. Privacy Badger invia il <a href='https://globalprivacycontrol.org/' target='_blank'>segnale Global Privacy Control</a> per escluderti dalla condivisione e vendita di dati e il <a href='https://www.eff.org/issues/do-not-track' target='_blank'>segnale Do Not Track</a> per dire alle aziende di non tracciarti. Se ignorano le tue scelte, Privacy Badger imparerà a bloccarli—che siano inserzionisti o tracker di altro tipo.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Chiudi",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Importa dati utente",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "DNT-compatibili",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Aiuto",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "permessi",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "La privacy è un gioco di squadra!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "Non dovresti aver bisogno di modificare nulla qui.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "tutti",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "Annulla",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Sposta il pulsante a sinistra per bloccare un dominio",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Invia ai siti i segnali \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" e \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\"",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Disattiva l'invio degli indirizzi web che visiti a Google. Ciò disattiva i suggerimenti per pagine simili quando una pagina non può essere trovata.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Disattiva controllo dei link ipertestuali",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "utente-dipendenti",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger è disattivato nei seguenti siti. Ciò significa che Privacy Badger non bloccherà nulla mentre visiti i siti elencati qui e non invierà i segnali Do Not Track e Global Privacy Control.</p><p>Se pensi che con Privacy Badger non funzioni bene una pagina, o se volessi permettere a uno specifico sito di condividere o vendere i tuoi dati, puoi digitare il dominio di quella pagina nella casella sotto e cliccare il pulsante \"Aggiungi dominio\".</p><p>Altrimenti, quando la scheda della pagina è selezionata, puoi cliccare il pulsante di Privacy Badger nella barra degli strumenti e poi cliccare il pulsante \"Disattiva\".</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ potenziali $LINK_START$tracker$LINK_END$ bloccati",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "Nessun $LINK_START$tracker$LINK_END$ bloccato",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "Non ci sono risorse di terze parti in questa pagina. Urrà per la privacy!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Un progetto della Electronic Frontier Foundation",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Aggiungi dominio",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Spostare il pulsante a destra per consentire un dominio",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Disattiva Privacy Badger per questo sito",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Clicca qui per permettere questo dominio",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privacy Badger non condivide MAI i tuoi dati di navigazione a meno che non lo scegli.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger ha deciso di bloccare $COUNT$ potenziali $TRACKER_LINK_START$domini traccianti$TRACKER_LINK_END$ finora",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privacy Badger non ha ancora rilevato alcun <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>dominio tracciante</a> . Continua a navigare!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger inizia a bloccare una volta visto lo stesso tracker su tre siti diversi. Tre colpi ed è fuori!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Filtra per stato:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Descrivi brevemente l'errore qui sotto.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Rimuovi selezionati",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "Quando usi Privacy Badger ti unisci alla <a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundation</a> e a milioni di altri utenti nella lotta per la privacy. Siamo senza scopo di lucro e combattiamo per i diritti nella rete. Grazie per la partecipazione!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "Per escludere domini, apponi al termine di ricerca il segno \"-\". Ad esempio, \".co -.com\" mostrerà i domini .co e .co.uk ma non .com.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Se pensi che Privacy Badger stia dando problemi a una pagina (ad esempio un video non si avvia), puoi cliccare il tasto 'Disattiva' per spegnere Privacy Badger in quel sito.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Politica sulla privacy",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Descrizione",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Il tuo tasso non ha ancora deciso se questi domini andrebbero bloccati",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Mostra i domini che il tuo tasso non ha ancora deciso di bloccare:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "I domini sottostanti sembrano non tracciarti",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Opzioni",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Condividi su Facebook",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privacy Badger impara automaticamente a bloccare i tracker invisibili.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "Ops. Qualcosa è andato storto.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "Privacy Badger ha sostituito questo pulsante $BUTTON$",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger ha sostituito questo widget $WIDGET$",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Permetti una volta",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Permetti sempre in questo sito",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Sincronizzazione cloud:<ul><li>Richiede Firefox/Chrome Sync</li><li>L'invio sovrascrive qualsiasi dato di Privacy Badger nel cloud</li><li>Lo scaricamento combina gli elenchi di siti dove il tuo tasso è disattivato</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Invia",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Esporta nel cloud i siti disattivati",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Importa dal cloud i siti disattivati",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Dati cloud importati con successo.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "Impossibile scaricare i dati cloud.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "Dati cloud inviati con successo.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "Impossibile inviare i dati cloud.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "Nessun dato cloud da scaricare.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Dillo ai tuoi amici",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Condividi",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger ha bloccato $COUNT$ potenziali tracker su $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privacy Badger (www.eff.org/privacybadger) è un'estensione del browser che impara automaticamente a bloccare i tracker invisibili. Privacy Badger è creato da Electronic Frontier Foundation, un'organizzazione senza scopo di lucro che combatte per i tuoi diritti nella rete.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "Copia negli appunti",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Copiato",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Niente da fare in questa pagina",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger non funziona in pagine speciali come questa. Prova a navigare altrove.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger è disattivato in questo sito",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Sostituzione dei widget",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "Quando vengono bloccati i pulsanti social ed altri widget possibilmente utili (video, audio, commenti), Privacy Badger li può sostituire con segnaposto clicca-per-attivare.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/ko/messages.json b/src/_locales/ko/messages.json
new file mode 100644
index 0000000..2ff65b2
--- /dev/null
+++ b/src/_locales/ko/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "차단된 $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "유효하지 않은 JSON 파일",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Privacy Badger로부터 이 도메인을 제거합니까?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "추적되지 않는 $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "현재 Privacy Badger는 검색 추적을 위해 제3자가 쿠키, HTML5 로컬 스토리지 또는 캔버스 지문 채취를 사용하는 경우에만 검사합니다. 이러한 도메인 중 일부는 Privacy Badger가 감지할 수 없는 추적 방법을 사용하고 있을 수 있습니다.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "<a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>제 3자 도메인</a>이 <a target='_blank' href='https://www.eff.org/dnt-policy'>EFF의 추적 금지 정책</a>을 준수하는지 확인합니다.",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "유효한 도메인 또는 URL을 추가하세요.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "EFF에게 기부",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "기부 또는 툴에 대한 지원을 공유함으로써 저희를 도와주세요.",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "저는 ad blocker와는 다릅니다.",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "감사합니다! 원인을 밝혀내겠습니다.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "이 도메인은 당신을 추적하지 않습니다.",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Blocking this domain is known to break websites",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Click to return control of this domain to Privacy Badger",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "다음 섹션",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "다음 오류에 대해 <a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>말씀해 주세요</a>:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "데이터 관리",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "오류 보고",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "예시, www.domain.com, *.domain.net, domain.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "이 도메인의 쿠키 설정을 차단하려면 여기를 클릭하세요.",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "차단",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "WebRTC가 로컬 IP 주소를 유출하지 못하도록 합니다.",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger는 자동으로 보이지 않는 추적기를 차단하는 방법을 배웁니다. 잠시 시간을 내서 어떻게 동작하는지 알아보세요.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "무슨 문제가 있나요?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "추적 도메인",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "트위터에 공유",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Privacy Badger가 개인 정보를 보호하는 방법에 대해 알아봅니다.",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "다운로드",
+ "description": ""
+ },
+ "import": {
+ "message": "가져오기",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "다음 위젯을 교체하지 마세요:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "위젯 교체를 사용하도록 설정합니다.",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "사용자를 추적하지 않는 것으로 보이는 도메인을 표시합니다.",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "오류 보고",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "허용된 $DOMAIN$",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "Privacy Badger란?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "도메인 검색:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Learn to block new trackers from your browsing",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Enabling learning may make you more identifiable to websites",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Private/Incognito 창에서 학습합니다.",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "Private/Incognito 창에서 학습을 활성화하면 컴퓨터에 개인 검색 기록을 남길 수 있습니다. 기본적으로 Privacy Badger는 Private/Incognito 창에서 이미 알고 있는 추적기를 차단하지만 새로운 추적기에 대해서는 학습하지 않습니다. Private/Incognito 창에서 많은 검색이 발생하는 경우 이 옵션을 사용하도록 설정할 수 있습니다.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger will no longer learn from your browsing by default.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Click below to learn more.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Learn how Privacy Badger is changing",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "추적기의 수를 표시합니다.",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "추적기란?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "'Privacy Badger가 이 사이트를 파손했습니까?'를 클릭하는 것을 잊지 마세요. 우리는 당신의 프라이버시를 존중합니다. 그래서 우리는 자동으로 보고서를 보내지 않습니다.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Privacy Badger 옵션",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "This will automatically send the following information to EFF: the page you're currently visiting, your browser version, the version of Privacy Badger, and the state of all of the sliders on this page.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "비활성화 사이트",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "이 사이트에 대해 Privacy Badger를 사용하도록 설정합니다.",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "유형별 필터:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "추적기목록 및 설정이 성공적으로 업데이트 되었습니다!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "사용자 데이터 내보내기",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "사용자 데이터 가져오기:<ul><li>일반 설정을 덮어씁니다.</li><li>차단된 사이트의 목록을 결합합니다.</li><li>Privacy Badger가 찾은 추적기정보를 결합합니다.</li><li>사용자 지정 슬라이더를 덮어씁니다.</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "초기화",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "추적 도메인 초기화",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "추적 도메인을 초기화하면\n\n • Privacy Badger가 검색을 통해 학습한 추적기에 대한 모든 데이터를 삭제합니다.\n • 추적 도메인 목록을 최신 사전 훈련된 목록으로 복원합니다(자세한 내용은 www.eff.org/badger-pretraining 참조)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "모두 제거",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "추적 도메인 모두 제거",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "추적 도메인을 모두 제거하면\n\n • Privacy Badger가 추적기에 대해 알고 있는 모든 데이터를 삭제합니다.\n • Privacy Badger가 검색을 통해서 다시 학습할 때까지 아무것도 차단하지 않습니다.",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "이제 Privacy Badger의 보호를 받습니다.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "Privacy Badger의 동작 방식을 알아보려면 아래를 클릭하여 간단한 튜토리얼을 확인하세요.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC에서 로컬 IP 주소가 유출될 수 있습니다. 이 옵션을 활성화하면 Google Hangouts와 같은 웹 회의 앱의 성능이 저하될 수 있습니다.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "일반 설정",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Privacy",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Advanced",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "알아보기",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "이 도메인을 완전히 차단하려면 여기를 클릭하세요.",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "버전 $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "$DOMAIN$로부터 차단된 쿠키",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "부분적으로 차단",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "그래도 추적 도메인 목록을 확인하나요?",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Privacy Badger를 설치해 주셔서 감사합니다!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "가져올 파일을 선택하세요.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "Privacy Badger가 이 사이트를 파손했습니까? 우리에게 알려주세요!",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "슬라이더를 중앙에 배치하여 쿠키를 차단합니다.",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Learns automatically",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Instead of keeping lists of what to block, Privacy Badger automatically discovers trackers based on their behavior.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "은밀한 추적기를 잡습니다.",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Invisible tracking happens in all sorts of ways; ads are just the visible tip of the iceberg. Privacy Badger sends the <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control signal</a>, to opt you out of data sharing and selling, and the <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track signal</a> to tell companies not to track you. If they ignore your wishes, Privacy Badger will learn to block them—whether they are advertisers or trackers of other kinds.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "닫기",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "사용자 데이터 가져오기",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "추적 금지에 순응",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "도움",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "허용",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "프라이버시는 팀 활동입니다!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "여기서 어떤 것도 수정할 필요가 없습니다.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "전체",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "취소",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "슬라이더를 왼쪽으로 이동하여 도메인을 차단합니다.",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Send websites the \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" and \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\" signals",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Disable sending web addresses you visit to Google. This disables suggestions for similar pages when a page can't be found.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Disable hyperlink auditing",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "사용자 정의",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is disabled on the following sites. This means that Privacy Badger will not block anything when you visit the sites listed here, and it will not send the Do Not Track or Global Privacy Control signals.</p><p>If you think Privacy Badger is breaking a page, or you would like to allow a particular site to share or sell your data, you can type that page's domain in the box below and click the \"Add domain\" button.</p><p>Alternatively, when you already have the page's tab selected, you can just click on Privacy Badger's button in the browser toolbar and then click the \"Disable\" button.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ potential $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "No $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "There are no third party resources on this page. Hooray for privacy!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Electronic Frontier Foundation의 프로젝트입니다.",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "도메인 추가",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "슬라이더를 오른쪽으로 이동하여 도메인을 허용합니다.",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "이 사이트에 대해 Privacy Badger를 사용하지 않도록 설정합니다.",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "이 도메인을 허용하려면 여기를 클릭하세요.",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privacy Badger는 사용자가 검색을 공유하도록 선택하지 않는 한 검색에 대한 데이터를 절대 공유하지 않습니다.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger has decided to block $COUNT$ potential $TRACKER_LINK_START$tracking domains$TRACKER_LINK_END$ so far",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privacy Badger가 아직 <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>추적 도메인</a>을 감지하지 못했습니다. 계속 탐색하세요!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger는 세 개의 다른 웹 사이트에서 동일한 추적기를 보면 차단하기 시작합니다. 삼진 아웃이에요!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "상태별 필터:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "아래에 오류에 대해서 간략하게 설명해주세요.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "제거",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "Privacy Badger를 사용하면 개인 정보 보호를 위해 <a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundation</a>및 수백만 명의 다른 사용자와 함께합니다. 우리는 온라인에서 당신의 권리를 위해 싸우는 비영리 단체입니다. 참여해 주셔서 감사합니다!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "도메인을 제외하려면 검색어를 \"-\"로 미리 입력합니다. 예를 들어 \".co -.com\"에는 .co 및 .co.uk이 표시되지만 .com 도메인은 표시되지 않습니다.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Privacy Badger가 페이지를 파손하고 있다고 생각되면 (예를 들어 비디오가 재생되지 않는 등) ‘이 사이트에 대해 Privacy Badger를 사용하지 않도록 설정’ 버튼을 클릭하여 해당 사이트에 대한 Privacy Badger를 해제할 수 있습니다.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "개인 정보 보호 정책",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "설명",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Your Badger hasn't decided yet if these domains should get blocked",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Show domains your Badger hasn't decided yet to block:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "아래 도메인은 사용자를 추적하는 것 같지 않습니다.",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "옵션",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "페이스북에 공유",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privacy Badger는 자동으로 보이지 않는 추적기를 차단하는 법을 학습합니다.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "앗, 뭔가 잘못됐어요.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "Privacy Badger가 이 $BUTTON$버튼을 대체했습니다.",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger has replaced this $WIDGET$ widget",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "한 번 허용",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "이 사이트에서 항상 허용",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "클라우드 동기화:<ul><li>Firefox/Chrome 동기화가 필요합니다.</li><li>업로드는 클라우드에 있는 기존의 모든 Privacy Badger 데이터를 덮어씁니다.</li><li>다운로드는 Privacy Badger를 사용할 수 없는 사이트 목록을 결합합니다.</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "업로드",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "클라우드로 비활성화 사이트 내보내기",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "클라우드에서 비활성화 사이트 가져오기",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "클라우드 데이터를 성공적으로 가져왔습니다.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "클라우드 데이터를 다운로드할 수 없습니다.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "클라우드 데이터가 성공적으로 업로드 되었습니다.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "클라우드 데이터를 업로드할 수 없습니다.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "다운로드할 클라우드 데이터가 없습니다.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "당신의 친구들에게 추천하세요.",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "공유",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger blocked $COUNT$ potential trackers on $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privacy Badger (www.eff.org/privacybadger)는 보이지 않는 추적기를 자동으로 차단하는 방법을 학습하는 브라우저 확장 기능입니다. Privacy Badger는 온라인에서 당신의 권리를 위해 싸우는 비영리 단체인 Electronic Frontier Foundation에서 만들어졌습니다.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "클립보드에 복사",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "복사됨",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "이 페이지에서 할 일이 없습니다.",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger는 이러한 특수 페이지에서는 동작하지 않습니다. 다른 곳을 찾아보세요.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger is disabled on this site",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "위젯 교체",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "소셜 버튼 및 기타 잠재적으로 유용한 (비디오, 오디오, 댓글) 위젯을 차단할 때 Privacy Badger는 이를 클릭하여 활성화하는 플레이스홀더로 대체할 수 있습니다.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/nl/messages.json b/src/_locales/nl/messages.json
new file mode 100755
index 0000000..392875c
--- /dev/null
+++ b/src/_locales/nl/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "$DOMAIN$ geblokkeerd",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "Ongeldig JSON-bestand.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Weet u zeker dat u dit domein van Privacy Badger wilt verwijderen?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "Uw surfgedrag wordt niet gevolgd door $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "Momenteel controleert Privacy Badger alleen of derde partijen cookies, HTML5 lokale opslag of canvas fingerprinting gebruiken om uw surfgedrag te volgen. Sommige van deze domeinen gebruiken wellicht volgmethoden die Privacy Badger (nog) niet detecteert.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "Controleer of <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>domeinen van derde partijen</a> voldoen aan <a target='_blank' href='https://www.eff.org/dnt-policy'>het Niet-volgen-beleid (Do Not Track) van het EFF</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Voeg een geldig domein of URL toe.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "Aan EFF doneren",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Help ons door te doneren en uw steun voor onze hulpprogramma's te delen",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "Geen advertentieblokkade, ik ben anders",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "Bedankt voor uw inzet! We gaan dit verder uitzoeken.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "Dit domein belooft u niet te volgen",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Het staat bekend dat door het blokkeren van dit domein sommige websites niet langer goed werken",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Klik om controle voor dit domein terug te geven aan Privacy Badger",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "volgende onderdeel",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "<a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>Vertel ons</a> over de onderstaande fout:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Gegevens beheren",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Een fout melden",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "bv. www.domain.com, *.domain.net, domain.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Klik hier om cookies van dit domein te blokkeren",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "geblokkeerd",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "Voorkom dat WebRTC het lokale IP-adres lekt",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger leert automatisch onzichtbare volgers te blokkeren. Neem even de tijd om te zien hoe het werkt.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "Wat ging er mis?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Volgerdomeinen",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Op Twitter delen",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Leer meer over hoe Privacy Badger uw privacy beschermt",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "Downloaden",
+ "description": ""
+ },
+ "import": {
+ "message": "Importeren",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "De volgende widgets niet vervangen:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Widgets vervangen inschakelen",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Geef domeinen weer welke u niet lijken te volgen",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Foutmelding indienen",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "Toegestaan $DOMAIN$",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "Wat is Privacy Badger?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Zoek domeinen:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Leer door het web te surfen nieuwe volgers te blokkeren",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Door leren in te schakelen wirdt je mogelijk meer identificeerbaar voor websites",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Leer in incognitovensters",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "Als u leren in incognitovensters inschakelt kunnen er sporen van uw privé browsegeschiedenis op uw computer achterblijven. Standaard blokkeert Privacy Badger wel bekende volgers in incognitovensters, maar leert het niets over nieuwe volgers. U kunt deze optie inschakelen als u veel gebruik maakt van incognitovensters.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger zal niet langer als standaard gedrag leren van jouw surfgedrag.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Klik hieronder om meer te leren.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Lees how Privacy Badger verandert",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Geef het aantal geblokkeerde volgers weer",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "Wat is een volger?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "Vergeet niet op 'Een website melden die niet meer werkt' te klikken. Om uw privacy te respecteren verzenden we geen automatische meldingen.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Privacy Badger-opties",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "Dit zal automatisch de volgende gegevens naar het EFF verzenden: de webpagina die je momenteel bezoekt, de versie van je webbrowser, de versie van Privacy Badger en de instelling van alle schuifknoppen voor deze webpagina.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Uitgeschakelde websites",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Privacy Badger inschakelen op deze website",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Op type filteren:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "Volgerlijst en instellingen zijn succesvol bijgewerkt!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Exporteer gebruikersgegevens",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "Gebruikersgegevens importeren:<ul><li>Overschrijft algemene instellingen</li><li>Combineert lijsten van uitgeschakelde sites</li><li>Combineert informatie over welke volgers Privacy Badger heeft gevonden</li><li>Overschrijft aanpassingen aan schuifbalkjes</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Herstellen",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Volgerdomeinen herstellen",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Het herstellen van volgerdomeinen zal:\n\n • De gegevens van alle volgers verwijderen die Privacy Badger op basis van uw surfgedrag kent.\n • De lijst met volgerdomeinen terugzetten naar de laatste standaardlijst (bezoek www.eff.org/badger-pretraining voor meer informatie).",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Alles verwijderen",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Alle volgerdomeinen verwijderen",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "Het verwijderen van alle volgerdomeinen zal:\n\n • Alles verwijderen wat Privacy Badger heeft geleerd over volgers.\n • Er voor zorgen dat Privacy Badger niets meer blokkeert totdat het de kans heeft gehad om opnieuw te leren uit uw surfgedrag.",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "U wordt nu beschermd door Privacy Badger.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "Om te leren hoe Privacy Badger werkt klikt u hieronder voor een kort overzicht.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC kan uw lokale IP-adres lekken. Door dit te blokkeren kunnen de prestaties van sommige videoconferentie apps zoals Google Hangouts verminderen.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "Algemene instellingen",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Privacy",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Geavanceerd",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Neem de rondleiding",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Klik hier om dit domein volledig te blokkeren",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "versie $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "Cookies geblokkeerd van $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "gedeeltelijk geblokkeerd",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "Ik snap het; laat me de lijst met volgerdomeinen zien",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Bedankt voor het installeren van Privacy Badger!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "Kies een bestand om te importeren.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "Een website melden die niet meer werkt",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Zet het schuifbalkje in het midden om cookies te blokkeren",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Leert automatisch",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "In plaats van lijsten bij te houden over wat je wilt blokkeren, zal Privacy Badger automatisch volgers ontdekken op basis van hun gedrag.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Vangt stiekeme volgers",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Onzichtbaar volgen gebeurd op allerlei manieren; advertenties zijn slechts het zichtbare topje van de ijsberg. Privacy Badger verzendt het <a href='https://globalprivacycontrol.org/' target='_blank'>“Global Privacy Control”-signaal</a>, om niet mee te doen aan het doorgeven en verkopen van je data, en het <a href='https://www.eff.org/issues/do-not-track' target='_blank'>“Volg me niet”-signaal</a> om aan bedrijven aan te geven dat je niet gevolgd wil worden. Als ze je keuze niet respecteren, dan zal Privacy Badger leren om ze te blokkeren, ongeacht of ze adverteerders, volgers of iets anders zijn.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Sluiten",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Importeer gebruikersgegevens",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "voldoet aan Niet-volgen-beleid",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Help",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "toegestaan",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "Privacy is een teamsport!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "Het zou voor u niet nodig moeten zijn om hier iets aan te passen.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "alle",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "Annuleren",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Schuif de balk naar links om een domein te blokkeren",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Verzend de “<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>” en “<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Volg me niet</a>” signalen naar websites",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Schakel het naar Google verzenden van webadressen die je bezoekt uit. Hierdoor worden ook suggesties voor vergelijkbare pagina's als een pagina niet kan worden gevonden uitgeschakeld.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "‘Hyperlink auditing’ blokkeren",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "ingesteld door gebruiker",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is op de volgende websitess uitgeschakeld. Dit betekent dat Privacy Badger niets zal blokkeren op één van de websites in deze lijst, en dat het ook niet het “Volg me niet”- of “Global Privacy Control”-signaal zal verzenden.</p><p>Als je vermoedt dat Privacy Badger het laden van een bepaalde webpagina verstoort, of als je een bepaalde website wil toestaan om je data door te geven of verkopen, dan kun je de domeinnaam van die webpagina invullen in het invoerveld hieronder en op de knop \"Domein toevoegen\" klikken.</p><p>Als je het tabblad met die webpagina al open en geselecteerd hebt kun jet als alternatief op de Privacy Badger-knop klikken de de werkbalk van je webbrowser en vervolgens op de knop ‘Uitschakelen’ klikken.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ potentiele $LINK_START$volgers$LINK_END$ geblokkeerd",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "Geen $LINK_START$volgers$LINK_END$ geblokkeerd",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "Ee is geen bron van een derde partij op deze webpagina aanwezig. Hoera voor privacy!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Een project van de Electronic Frontier Foundation",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Domein toevoegen",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Schuif de balk naar rechts om een domein toe te staan",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Privacy Badger uitschakelen op deze website",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Klik hier om dit domein toe te laten",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privacy Badger zal NOOIT uw surfgedrag delen, tenzij u hiervoor kiest.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger heeft tot nog toe besloten om $COUNT$ potentiële $TRACKER_LINK_START$volgerdomeinen$TRACKER_LINK_END$ te blokkeren",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privacy Badger heeft nog geen <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>volgerdomeinen</a> gedetecteerd. Blijf browsen!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger begint met blokkeren zodra het dezelfde volger op drie verschillende websites ziet. Drie slag en ze zijn uit!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Op status filteren:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Omschrijf de fout in het kort.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Verwijder geselecteerde",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "Wanneer u Privacy Badger gebruikt vecht u met de <a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundation</a> en miljoenen andere gebruikers in de strijd voor privacy. Wij zijn een organisatie zonder winstoogmerk die vecht voor uw online rechten. Bedankt voor het deelnemen!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "Om domeinen uit te sluiten plaatst u een \"-\" voor uw zoekterm. \".co -.com\" geeft bijvoorbeeld .co- en .co.uk-domeinen weer, maar sluit .com-domeinen uit.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Als u vermoedt dat een webpagina niet meer werkt vanwege Privacy Badger (een video speelt bijvoorbeeld niet), dan kunt u op de knop 'Privacy Badger uitschakelen op deze website' klikken.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Privacybeleid",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Omschrijving",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Uw Badger heeft nog niet bepaald of deze domeinen geblokkeerd moeten worden",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Geef domeinen weer waarvan uw Badger nog niet heeft bepaald of ze geblokkeerd moeten worden:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "De onderstaande domeinen lijken u niet te volgen",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Instellingen",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Op Facebook delen",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privacy Badger leert automatisch onzichtbare volgers te blokkeren.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "Oeps. Er is iets misgegaan.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "Privacy Badger heeft deze $BUTTON$-knop vervangen",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger heeft deze $WIDGET$-widget vervangen",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Eenmalig toestaan",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Altijd toestaan op deze website",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Synchroniseren met de cloud:<ul><li>Vereist Firefox/Chrome Sync</li><li>Uploaden overschrijft bestaande gegevens van Privacy Badger in de cloud.</li><li>Downloaden combineert de lijsten van websites waar Privacy Badger is uitgeschakeld.</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Uploaden",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Uitgeschakelde websites exporteren naar de cloud",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Uitgeschakelde websites importeren vanuit de cloud",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Cloudgegevens succesvol geïmporteerd.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "Cloudgegevens konden niet worden gedownload.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "Cloudgegevens succesvol geüpload.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "Cloudgegevens konden niet worden geüpload.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "Geen cloudgegevens om te downloaden",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Vertel uw kennissen over Privacy Badger",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Delen",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger heeft $COUNT$ potentiële volgers geblokkeerd op $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privacy Badger (www.eff.org/privacybadger) is een browserextensie die automatisch leert om onzichtbare volgers te blokkeren. Privacy Badger is gemaakt door de Electronic Frontier Foundation, een organisatie zonder winstoogmerk die vecht voor uw online rechten.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "Kopiëren naar klembord",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Gekopieerd",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Er valt niets te doen op deze pagina",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger werkt niet op speciale pagina's zoals deze. Surf ergens anders heen om het daar te proberen.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger is voor deze website uitgeschakeld",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Widgets vervangen",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "Wanneer socialemedia-knoppen en andere potentieel nuttige widgets worden geblokkeerd, dan kan Privacy Badger ze vervangen door klikken-om-te-activeren-plaatsvervangers.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/pl/messages.json b/src/_locales/pl/messages.json
new file mode 100644
index 0000000..c64dfac
--- /dev/null
+++ b/src/_locales/pl/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "Zablokowany $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "Nieprawidłowy plik JSON.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Czy na pewno chcesz usunąć tę domenę z Privacy Badgera?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "Nie szpieguje $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "Obecnie Privacy Badger sprawdza tylko czy strony trzecie używają ciasteczek, pamięci podręcznej HTML5 lub odcisku palca canvas, aby śledzić Twoją historię przeglądania. Niektóre z tych domen mogą śledzić metodami, których Privacy Badger nie potrafi wykryć.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "Sprawdź czy <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>domeny stron trzecich</a> są zgodne z <a target='_blank' href='https://www.eff.org/dnt-policy'>polityką o nieszpiegowaniu EFF</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Wprowadź poprawną domenę lub URL.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "Darowizna na EFF",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Wspomóż nas poprzez dotacje bądź zaoferuj wsparcie dla naszych narzędzi",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "Nie bloker reklam, jestem inny",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "Dzięki! Zajmiemy się sprawą.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "Ta domena obiecuje Ci nie szpiegować.",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Zablokowanie tej domeny może spowodować, że strony internetowe przestaną działać poprawnie",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Kliknij, aby Privacy Badger zdecydował za Ciebie jak obchodzić się z tą domeną",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "dalej",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "Prosimy <a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>poinformować nas</a> o następującym błędzie:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Zarządzaj danymi",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Zgłoś problem",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "np. www.domena.com, *.domena.net, domena.pl",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Kliknij tutaj, aby uniemożliwić tej domenie ustawiać ciasteczka",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "zablokowane",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "Zapobiegnij wyciekowi lokalnego IP przez WebRTC",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger automatycznie uczy się blokować niewidoczne elementy śledzące. Poświęć minutę, aby dowiedzieć się jak.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "Co się zepsuło?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Szpiegujące domeny",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Udostępnij na Twitterze",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Więcej informacji o tym jak Privacy Badger chroni Twoją prywatność",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "Pobierz",
+ "description": ""
+ },
+ "import": {
+ "message": "Import",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "Nie zastępuj następujących widżetów:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Zastępuj widżety",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Wyświetla domeny, które chyba Cię nie szpiegują",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Zgłoś problem",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "Odblokowany $DOMAIN$",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "Czym jest Privacy Badger?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Szukaj domen:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Ucz się blokować nowe elementy śledzące na podstawie Twojego surfowania",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Włączenie nauki na podstawie Twojej aktywności sieciowej może uczynić Cię bardziej identyfikowalnym dla witryn internetowych",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Ucz się w trybie prywatnym",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "Włączenie nauki w trybie prywatnym może pozostawić ślady Twojego przeglądania prywatnego na komputerze. Domyślnie Privacy Badger będzie blokował już znane elementy śledzące w oknach prywatnych, ale nie będzie uczył się na temat nowych. Możesz zmienić tę opcję, jeżeli dużo serfujesz w trybie prywatnym.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger will no longer learn from your browsing by default.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Click below to learn more.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Learn how Privacy Badger is changing",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Wyświetl liczbę elementów śledzących",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "Czym jest element śledzący?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "Nie zapomnij kliknąć „Czy Privacy Badger zepsuł tę stronę?”. Szanujemy Twoją prywatność, więc nie wysyłamy raportów automatycznie.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Ustawienia Privacy Badger",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "Następujące informacje zostaną automatycznie wysłane do EFF: obecnie odwiedzana strona, wersja przeglądarki, wersja Privacy Badgera i stan wszystkich suwaków na tej stronie.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Nieblokowane witryny",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Włącz Privacy Badger na tej witrynie",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Filtruj wg rodzaju:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "Pomyślnie zaimportowano ustawienia i listę elementów śledzących!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Eksport danych użytkownika",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "Import danych użytkownika:\n<ul>\n<li>nadpisze ogólne ustawienia</li>\n<li>połączy listy wykluczanych domen</li>\n<li>połączy informacje o znalezionych elementach śledzących</li>\n<li>nadpisze ustawienia suwaka</li>\n</ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Reset",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Reset szpiegujących domen",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Reset szpiegujących domen spowoduje:\n\n • wymazanie wszystkich danych o elementach śledzących, o których Privacy Badger nauczył się podczas Twojego serfowania\n • zastąpienie listy szpiegujących domen najnowszą listą początkową (przeczytaj www.eff.org/badger-pretraining aby dowiedzieć się więcej)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Usuń wszystko",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Usuń wszystkie szpiegujące domeny",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "Usunięcie wszystkich szpiegujących domen spowoduje:\n\n • usunięcie wszystkiego, co Privacy Badger wie o elementach śledzących\n • że Privacy Badger nie będzie blokował czegokolwiek zanim ponownie nie wyuczy się na podstawie Twojego przeglądania",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "Jesteś obecnie ochroniony przez Privacy Badgera.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "Aby dowiedzieć się więcej o tym jak działa Privacy Badger, kliknij poniżej po krótki przewodnik.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC może ujawnić Twój lokalny adres IP. Zauważ, że może to zmniejszyć wydajność aplikacji do konferencji sieciowych, np. Google Hangouts.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "Ogólne ustawienia",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Prywatność",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Zaawansowane",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Wprowadzenie",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Kliknij tutaj, aby całkowicie zablokować tę domenę",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "wersja $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "Zablokowano ciasteczka z $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "częściowo zablokowane",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "Tak, rozumiem, ale proszę wyświetlić mi listę szpiegujących domen.",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Dziękujemy za zainstalowanie Privacy Badgera!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "Wybierz plik do zaimportowania.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "Czy Privacy Badger zepsuł tę stronę? Zgłoś to nam!",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Wycentruj suwak, aby zablokować ciasteczka",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Learns automatically",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Instead of keeping lists of what to block, Privacy Badger automatically discovers trackers based on their behavior.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Wyłapuje sprytne elementy śledzące",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Invisible tracking happens in all sorts of ways; ads are just the visible tip of the iceberg. Privacy Badger sends the <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control signal</a>, to opt you out of data sharing and selling, and the <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track signal</a> to tell companies not to track you. If they ignore your wishes, Privacy Badger will learn to block them—whether they are advertisers or trackers of other kinds.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Zamknij",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Import danych użytkownika",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "zgodne z DNT",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Pomoc",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "odblokowane",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "Prywatność to sport zespołowy!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "Nie powinieneś mieć potrzeby zmieniać czegokolwiek tutaj.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "wszystkie",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "Anuluj",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Przesuń suwak w lewo, aby zablokować domenę",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Send websites the \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" and \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\" signals",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Wyłącz wysyłanie adresów stron internetowych do Google. Opcja ta wyłącza sugestie podobnych stron wyświetlanych kiedy żądana strona nie została znaleziona.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Wyłącz sprawdzanie odnośników",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "ustawione przez użytkownika",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is disabled on the following sites. This means that Privacy Badger will not block anything when you visit the sites listed here, and it will not send the Do Not Track or Global Privacy Control signals.</p><p>If you think Privacy Badger is breaking a page, or you would like to allow a particular site to share or sell your data, you can type that page's domain in the box below and click the \"Add domain\" button.</p><p>Alternatively, when you already have the page's tab selected, you can just click on Privacy Badger's button in the browser toolbar and then click the \"Disable\" button.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "Zablokowanych potencjalnych $LINK_START$elementów śledzących$LINK_END$: $COUNT$",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "Brak zablokowanych $LINK_START$elementów śledzących$LINK_END$",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "Brak zasobów stron trzecich na tej stronie. Niech żyje prywatność!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Projekt Electronic Frontier Foundation",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Dodaj domenę",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Przesuń suwak w prawo, aby odblokować domenę",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Wyłącz Privacy Badgera na tej witrynie",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Kliknij tutaj, aby odblokować tę domenę",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privacy Badger NIGDY prześle dane dotyczące Twojej aktywności w Sieci, o ile sam o tym nie zdecydujesz.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger has decided to block $COUNT$ potential $TRACKER_LINK_START$tracking domains$TRACKER_LINK_END$ so far",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privacy Badger nie wykrył jakichkolwiek <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>szpiegujących domen</a> do tej pory. Serfuj śmiało!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger blokuje element śledzący po zauważeniu go na trzech różnych witrynach. Trzy uderzenia i koniec!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Filtruj wg stanu:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Zwięźle opisz problem poniżej.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Usuń zaznaczone",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "Podczas korzystania z Privacy Badgera stajesz się członkiem <a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundation</a> wraz z milionami użytkowników walczącymi o prywatność. Jesteśmy organizacją non-profit walczącą o Twoje prawa w Sieci. Dziękujemy za dołączenie do nas!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "Aby wykluczyć domeny, poprzedź wyszukiwaną frazę znakiem „-”. Przykład: „.co -.com” wskaże domeny .co i .co.uk, ale nie .com.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Jeżeli Twoim zdaniem Privacy Badger zepsuł jakąś stronę (np. filmik się nie odtwarza), możesz kliknąć przycisk „wyłącz”, aby wyłączyć dodatek na tej witrynie.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Polityka prywatności",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Opis",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Twój Badger jeszcze nie zdecydował, czy te domeny należy blokować",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Wyświetl domeny, co do których Privacy Badger nie zdecydował, czy powinny być blokowane:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "Poniższe domeny chyba Cię nie szpiegują",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Ustawienia",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Udostępnij na Facebooku",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privacy Badger automatycznie uczy się blokować niewidoczne elementy śledzące.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "O nie, coś się schrzaniło.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "Privacy Badger zastąpił ten przycisk $BUTTON$",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger zastąpił ten widżet $WIDGET$",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Odblokuj jednorazowo",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Zawsze odblokuj na tej witrynie",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Synchronizacja w chmurze:\n<ul>\n<li>wymaga usługi Firefox/Chrome Sync</li>\n<li>wysyłanie nadpisuje istniejące dane na serwerze</li>\n<li>pobranie łączy listy stron nieblokowanych przez Privacy Badgera</li>\n</ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Wyślij",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Eksport nieblokowanych stron na serwer",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Import nieblokowanych stron z serwera",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Pomyślnie zaimportowano dane z serwera.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "Nie udało się pobrać danych z serwera.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "Pomyślnie wysłano dane na serwer.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "Nie udało się wysłać danych na serwer.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "Brak danych na serwerze do pobrania.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Poinformuj znajomych",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Podziel się",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger zablokował $COUNT$ potencjalnych elementów śledzących na $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privacy Badger (www.eff.org/privacybadger) jest rozszerzeniem przeglądarkowym, które automatycznie uczy się blokować niewidzialne elementy śledzące. Privacy Badger jest dziełem Electronic Frontier Foundation – organizacji non-profit walczącej o Twoje prawa w Sieci.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "Skopiuj do schowka",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Skopiowano",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Nic do roboty na tej stronie",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger nie działa na specjalnych stronach jak ta. Spróbuj otworzyć inną stronę.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger jest wyłączony na tej witrynie",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Zastępowanie widżetów",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "Podczas blokowania przycisków mediów społecznościowych i innych potencjalnie użytecznych widżetów (filmów, dźwięków, komentarzy), Privacy Badger może zastępować je przyciskami (które nie ładują się automatycznie).",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/pt_BR/messages.json b/src/_locales/pt_BR/messages.json
new file mode 100644
index 0000000..1367310
--- /dev/null
+++ b/src/_locales/pt_BR/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "$DOMAIN$ bloqueado",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "Arquivo JSON inválido.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Tem certeza de que deseja remover esse domínio do Privacy Badger?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "Nenhum rastreamento em $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "Atualmente, o Privacy Badger apenas verifica se terceiros estão usando cookies, armazenamento local em HTML5, ou canvas fingerprinting para rastrear sua navegação. Alguns desses domínios podem estar usando métodos de rastreamento que o Privacy Badger não consegue detectar.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "Verificar se os <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>domínios de terceiros</a> estão em conformidade com a <a target='_blank' href='https://www.eff.org/dnt-policy'>política de Não Rastrear da EFF</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Por favor, adicione uma URL ou um domínio válido.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "Doar para EFF",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Ajude-nos doando e compartilhando seu apoio para nossas ferramentas",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "Não sou um bloqueador de anúncios, sou diferente",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "Obrigado! Nós chegaremos ao fundo disso.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "Este domínio prometeu não rastreá-lo",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Bloquear este domínio é conhecido por quebrar sites",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Clique para retornar o controle deste domínio para o Privacy Badger",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "próxima seção",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "Por favor, <a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>conte-nos</a> sobre o seguinte erro:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Gerenciar dados",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Relatar um erro",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "ex. www.dominio.com, *.dominio.net, dominio.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Clique aqui para bloquear este domínio de usar cookies",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "bloqueado",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "Impedir que o WebRTC vaze o endereço de IP local",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "O Privacy Badger aprende automaticamente a bloquear rastreadores invisíveis. Tire um minuto para saber como.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "O que há de errado?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Domínios de rastreamento",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Compartilhar no Twitter",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Saiba como o Privacy Badger protege sua privacidade",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "Baixar",
+ "description": ""
+ },
+ "import": {
+ "message": "Importar",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "Não substituir os seguintes widgets:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Habilitar substituição de widgets",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Mostrar domínios que parecem não estar rastreando você",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Enviar erro",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "$DOMAIN$ permitido",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "O que é Privacy Badger?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Procurar domínios:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Learn to block new trackers from your browsing",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Enabling learning may make you more identifiable to websites",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Aprender em janelas Privadas/Anônimas",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "Ativar o aprendizado em janelas Privadas/Anônimas pode deixar rastros do seu histórico de navegação privada em seu computador. Por padrão, o Privacy Badger irá bloquear rastreadores já conhecidos em janelas Privadas/Anônimas, mas não aprenderá sobre novos rastreadores. É possível que deseje habilitar esta opção se grande parte de sua navegação ocorrer em janelas Privadas/Anônimas.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger will no longer learn from your browsing by default.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Click below to learn more.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Learn how Privacy Badger is changing",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Mostrar contagem de rastreadores",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "O que é um rastreador?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "Por favor, não esqueça de clicar em \"O Privacy Badger quebrou este site\". Nós respeitamos sua privacidade já que não enviamos relatórios automáticos.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Opções do Privacy Badger",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "This will automatically send the following information to EFF: the page you're currently visiting, your browser version, the version of Privacy Badger, and the state of all of the sliders on this page.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Sites desativados",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Ativar o Privacy Badger para este site",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Filtrar por tipo:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "Lista de rastreadores e configurações atualizadas com sucesso!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Exportar dados de usuário",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "Importar dados do usuário:<ul><li>Substitui as configurações gerais</li><li>Combina listas de sites desativados</li><li>Combina informações sobre os rastreadores que o Privacy Badger detectou</li><li> Substitui personalizações do controle deslizante</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Resetar",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Resetar domínios de rastreamento",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Resetar os domínios de rastreamento irá:\n\n • Deletar todos os dados sobre rastreadores que o Privacy Badger aprendeu com sua navegação\n • Restaurar a lista de domínios de rastreamento para a última lista pré-criada (visite www.eff.org/badger-pretraining para saber mais)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Remover tudo",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Remover todos os domínios de rastreamento",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "Remover todos os domínios de rastreamento irá:\n\n • Deletar tudo que o Privacy Badger sabe sobre os rastreadores\n • Fazer com que o Privacy Badger não bloqueie nada até que tenha a chance de reaprender a partir de sua navegação",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "Agora você está protegido pelo Privacy Badger.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "Para saber como o Privacy Badger funciona, clique abaixo para um tutorial rápido.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "O WebRTC pode vazar seu endereço de IP local. Tenha em mente que ativar esta opção pode reduzir o desempenho em aplicações de conferência Web como Google Hangouts.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "Configurações gerais",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Privacy",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Advanced",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Saber como funciona",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Clique aqui para bloquear totalmente este domínio",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "versão $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "Cookies bloqueados de $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "parcialmente bloqueado",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "Compreendo; por favor, mostre-me a lista de domínios de rastreamento.",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Obrigado por instalar o Privacy Badger!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "Por favor, selecione um arquivo para importar.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "O Privacy Badger quebrou este site? Deixe-nos saber!",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Centralize o controle deslizante para bloquear cookies",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Learns automatically",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Instead of keeping lists of what to block, Privacy Badger automatically discovers trackers based on their behavior.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Detecta rastreadores ocultos",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Invisible tracking happens in all sorts of ways; ads are just the visible tip of the iceberg. Privacy Badger sends the <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control signal</a>, to opt you out of data sharing and selling, and the <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track signal</a> to tell companies not to track you. If they ignore your wishes, Privacy Badger will learn to block them—whether they are advertisers or trackers of other kinds.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Fechar",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Importar dados de usuário",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "Compatível com DNT",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Ajuda",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "permitido",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "A privacidade é um esporte de equipe!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "Você não precisa modificar nada aqui.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "todos",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "Cancelar",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Mova o controle deslizante para a esquerda para bloquear um domínio",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Send websites the \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" and \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\" signals",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Disable sending web addresses you visit to Google. This disables suggestions for similar pages when a page can't be found.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Disable hyperlink auditing",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "controlado pelo usuário",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is disabled on the following sites. This means that Privacy Badger will not block anything when you visit the sites listed here, and it will not send the Do Not Track or Global Privacy Control signals.</p><p>If you think Privacy Badger is breaking a page, or you would like to allow a particular site to share or sell your data, you can type that page's domain in the box below and click the \"Add domain\" button.</p><p>Alternatively, when you already have the page's tab selected, you can just click on Privacy Badger's button in the browser toolbar and then click the \"Disable\" button.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ potential $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "No $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "There are no third party resources on this page. Hooray for privacy!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Um projeto da Electronic Frontier Foundation",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Adicionar domínio",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Mova o controle deslizante para a direita para permitir um domínio",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Desabilitar o Privacy Badger para este site",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Clique aqui para permitir este domínio",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "O Privacy Badger NUNCA compartilhará dados sobre sua navegação, a menos que você escolha compartilhá-los.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger has decided to block $COUNT$ potential $TRACKER_LINK_START$tracking domains$TRACKER_LINK_END$ so far",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "O Privacy Badger ainda não detectou nenhum <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>domínio de rastreamento</a>. Continue navegando.",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "O Privacy Badger começa a bloquear uma vez que vê o mesmo rastreador em três sites diferentes. Três strikes e está fora!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Filtrar por status:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Descreva brevemente o erro abaixo.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Remover selecionado",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "Quando você usa o Privacy Badger, você se junta à <a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundation</a> e outros milhões de usuários na luta pela privacidade. Somos uma organização sem fins lucrativos que luta pelos seus direitos on-line. Obrigado por se juntar a nós.",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "Para excluir domínios, preceda seu termo de busca com \"-\". Por exemplo, \".co -.com\" mostrará domínios .co e .co.uk, mas não domínios .com.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Se você acha que o Privacy Badger está quebrando uma página (por exemplo, um vídeo não reproduz), você pode clicar no botão \"Desabilitar\" para desativar o Privacy Badger para esse site.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Política de Privacidade",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Descrição",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Seu Badger ainda não decidiu se esses domínios devem ser bloqueados",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Mostrar domínios que seu Badger ainda não decidiu se deve bloquear:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "Os domínios abaixo não parecem estar rastreando você",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Opções",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Compartilhar no Facebook",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "O Privacy Badger aprende automaticamente a bloquear rastreadores invisíveis.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "Oops. Algo deu errado.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "O Privacy Badger substituiu este botão $BUTTON$",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "O Privacy Badger substituiu esse $WIDGET$ widget",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Permitir uma vez",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Sempre permitir neste site",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Sincronização em nuvem:<ul><li>Requer Firefox/Chrome Sync</li><li>O upload sobrescreve quaisquer dados existentes do Privacy Badger na nuvem</li><li>O download combina as listas de sites onde o Privacy Badger está desativado</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Upload",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Exportar sites desativados para a nuvem",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Importar sites desativados da nuvem",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Os dados em nuvem foram importados com sucesso.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "Não foi possível baixar os dados da nuvem.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "Os dados foram enviados com sucesso para a nuvem.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "Não foi possível enviar os dados para a nuvem.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "Não há dados em nuvem para download.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Diga aos seus amigos",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Compartilhar",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger blocked $COUNT$ potential trackers on $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "O Privacy Badger (www.eff.org/privacybadger) é uma extensão de navegador que aprende automaticamente a bloquear rastreadores invisíveis. O Privacy Badger é feito pela Electronic Frontier Foundation, uma organização sem fins lucrativos que luta pelos seus direitos online.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "Copiar para área de transferência",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Copiado",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Nada a fazer nesta página",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "O Privacy Badger não funciona em páginas especiais como esta. Tente navegar em outro lugar.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "O Privacy Badger está desabilitado neste site",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Substituição de widgets",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "Quando bloquear botões de redes sociais e outros widgets potencialmente úteis (de vídeo, áudio, comentários), o Privacy Badger pode substitui-los por espaços reservados do tipo clique-para-ativar.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/pt_PT/messages.json b/src/_locales/pt_PT/messages.json
new file mode 100644
index 0000000..fd321a0
--- /dev/null
+++ b/src/_locales/pt_PT/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "$DOMAIN$ bloqueado",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "Ficheiro JSON inválido.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Tem certeza de que deseja remover esse domínio do Privacy Badger?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "Nenhum rastreamento em $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "Atualmente, o Privacy Badger apenas verifica se terceiros estão a usar cookies, armazenamento local em HTML5, ou canvas fingerprinting para rastrear a sua navegação. Alguns desses domínios podem estar a usar métodos de rastreamento que o Privacy Badger não consegue detetar.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "Verificar se os <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>domínios de terceiros</a> estão em conformidade com a <a target='_blank' href='https://www.eff.org/dnt-policy'>política de Não Rastrear da EFF</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Por favor, adicione um URL ou um domínio válido.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "Fazer um donativo à EFF",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Ajude-nos com um donativo e partilhando o seu apoio às nossas ferramentas",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "Não sou um bloqueador de anúncios, sou diferente",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "Obrigado! Nós iremos verificar o problema.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "Este domínio prometeu não rastreá-lo",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Bloqueando este domínio é conhecido por quebrar os sítios da Internet",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Clicar para devolver o controlo deste domínio ao Privacy Badger",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "próxima secção",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "Por favor, <a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>reporte-nos</a> o seguinte erro:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Gerir Dados",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Reportar um Erro",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "por ex. www.dominio.com, *.dominio.net, dominio.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Clique aqui para impedir que este domínio use cookies",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "bloqueado",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "Impedir que o WebRTC mostre o endereço de IP local",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "O Privacy Badger aprende automaticamente a bloquear rastreadores invisíveis. Tire um minuto para saber como.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "O que há de errado?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Domínios de Rastreamento",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Partilhar no Twitter",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Saiba como o Privacy Badger protege a sua privacidade",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "Descarregar",
+ "description": ""
+ },
+ "import": {
+ "message": "Importar",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "Não substituir os seguintes widgets:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Permitir a substituição do widget",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Mostrar domínios que não parecem estar a rastreá-lo",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Enviar erro",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "$DOMAIN$ permitido",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "O que é o Privacy Badger?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Procurar domínios:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Learn to block new trackers from your browsing",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Enabling learning may make you more identifiable to websites",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Aprender em janelas Privadas/Anónimas",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "Ativar o aprendizado em janelas Privadas/Anónimas/Incógnito pode deixar rastros do seu histórico de navegação privada no seu computador. Por padrão, o Privacy Badger irá bloquear rastreadores já conhecidos em janelas Privadas/Anónimas/Incógnito, mas não aprenderá sobre novos rastreadores. Pode querer ativar esta opção caso utilize muito o modo de navegação em janelas Privadas/Anónimas/Incógnito.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger will no longer learn from your browsing by default.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Click below to learn more.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Learn how Privacy Badger is changing",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Mostrar número de rastreadores",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "O que é um rastreador?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "Por favor não esqueça de clicar em \"O Privacy Badger estragou este site? Diga-nos!\" se quiser ajudar-nos. Nós respeitamos a sua privacidade por isso os relatórios de problemas não são enviados automaticamente.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Opções do Privacy Badger",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "This will automatically send the following information to EFF: the page you're currently visiting, your browser version, the version of Privacy Badger, and the state of all of the sliders on this page.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Sites desativados",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Ativar o Privacy Badger para este site",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Filtrar por tipo:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "Lista de rastreadores e configurações atualizadas com sucesso!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Exportar dados de utilizador",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "Importar dados do utilizador:<ul><li>Substitui as configurações gerais</li><li>Combina as listas de sites desativados</li><li>Combina informações sobre os rastreadores que o Privacy Badger detetou</li><li> Substitui personalizações do controlo deslizante</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Limpar",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Limpar domínios de rastreamento",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Limpar os domínios de rastreamento irá:\n\n • Eliminar todos os dados sobre rastreadores que o Privacy Badger aprendeu com sua navegação\n • Restaurar a lista de domínios de rastreamento para a última lista pré-criada (visite www.eff.org/badger-pretraining para saber mais)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Remover tudo",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Remover todos os domínios de rastreamento",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "Remover todos os domínios de rastreamento irá:\n\n • Eliminar tudo que o Privacy Badger sabe sobre os rastreadores\n • Fazer com que o Privacy Badger não bloqueie nada até que tenha a hipótese de reaprender a partir da sua navegação",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "Agora está protegido pelo Privacy Badger.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "Para saber como o Privacy Badger funciona, clique abaixo para um tutorial rápido.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "O WebRTC pode revelar o seu endereço de IP local. Tenha em mente que se ativar esta opção pode reduzir o desempenho em aplicações de conferência Web como o Google Hangouts.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "Configurações Gerais",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Privacy",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Advanced",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Saber como funciona",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Clique aqui para bloquear totalmente este domínio",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "versão $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "Cookies bloqueados de $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "parcialmente bloqueado",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "Compreendo, mesmo assim quero ver a lista de domínios de rastreamento.",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Obrigado por instalar o Privacy Badger!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "Por favor, selecione um ficheiro para importar.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "O Privacy Badger estragou este site? Diga-nos!",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Centralize o controlo deslizante para bloquear cookies",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Learns automatically",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Instead of keeping lists of what to block, Privacy Badger automatically discovers trackers based on their behavior.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Deteta rastreadores ocultos",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Invisible tracking happens in all sorts of ways; ads are just the visible tip of the iceberg. Privacy Badger sends the <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control signal</a>, to opt you out of data sharing and selling, and the <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track signal</a> to tell companies not to track you. If they ignore your wishes, Privacy Badger will learn to block them—whether they are advertisers or trackers of other kinds.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Fechar",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Importar dados de utilizador",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "Compatível com DNT",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Ajuda",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "permitido",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "A privacidade é um desporto de equipa!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "Não deve precisar de alterar nada aqui.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "todos",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "Cancelar",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Mova o controlo deslizante para a esquerda para bloquear um domínio",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Send websites the \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" and \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\" signals",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Disable sending web addresses you visit to Google. This disables suggestions for similar pages when a page can't be found.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Disable hyperlink auditing",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "controlado pelo utilizador",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is disabled on the following sites. This means that Privacy Badger will not block anything when you visit the sites listed here, and it will not send the Do Not Track or Global Privacy Control signals.</p><p>If you think Privacy Badger is breaking a page, or you would like to allow a particular site to share or sell your data, you can type that page's domain in the box below and click the \"Add domain\" button.</p><p>Alternatively, when you already have the page's tab selected, you can just click on Privacy Badger's button in the browser toolbar and then click the \"Disable\" button.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ potential $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "No $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "There are no third party resources on this page. Hooray for privacy!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Um projeto da Electronic Frontier Foundation",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Adicionar domínio",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Mova o controlo deslizante para a direita para permitir um domínio",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Desativar o Privacy Badger para este site",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Clique aqui para permitir este domínio",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "O Privacy Badger NUNCA partilhará dados sobre a sua navegação, a não ser que escolha partilhá-los.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger has decided to block $COUNT$ potential $TRACKER_LINK_START$tracking domains$TRACKER_LINK_END$ so far",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "O Privacy Badger ainda não detetou nenhum <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>domínio de rastreamento</a>. Continue a navegar.",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "O Privacy Badger começa a bloquear após detetar o mesmo rastreador em três sites diferentes. Três golpes e está fora!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Filtrar por estado:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Descreva brevemente o erro abaixo.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Remover selecionado",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "Quando usa o Privacy Badger, está a junta-se à <a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundation</a> e a outros milhões de utilizadores na luta pela privacidade. Somos uma organização sem fins lucrativos que luta pelos seus direitos na Internet. Obrigado por se juntar a nós.",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "Para excluir domínios, preceda o seu termo de busca com \"-\". Por exemplo, \".co -.com\" mostrará domínios .co e .co.uk, mas não domínios .com.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Se acha que o Privacy Badger está a estragar uma página (por exemplo, não consegue ver um vídeo), pode clicar no botão \"Desativar\" para desativar o Privacy Badger para esse site.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Política de privacidade",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Descrição",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "O seu Badger ainda não decidiu se estes domínios devem ser bloqueados",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Mostrar domínios que o seu Badger ainda não se decidiu bloquear:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "Os domínios abaixo não parecem estar a rastreá-lo",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Opções",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Partilhar no Facebook",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "O Privacy Badger aprende automaticamente a bloquear rastreadores invisíveis.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "Ups. Algo correu mal.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "O Privacy Badger substituiu este botão $BUTTON$",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "O Privacy Badger substituiu este widget $WIDGET$",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Permitir esta vez",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Permitir sempre neste site",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Sincronização na nuvem:<ul><li>Requer o Firefox/Chrome Sync</li><li>O envio substitui quaisquer dados existentes do Privacy Badger na nuvem</li><li>O descarregamento combina as listas de sites onde o Privacy Badger está desativado</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Enviar",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Exportar sites desativados para a nuvem",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Importar sites desativados da nuvem",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Os dados na nuvem foram importados com sucesso.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "Não foi possível descarregar os dados na nuvem.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "Os dados foram enviados com sucesso para a nuvem.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "Não foi possível enviar os dados para a nuvem.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "Não há dados na nuvem para descarregar.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Diga aos seus amigos",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Partilhar",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger blocked $COUNT$ potential trackers on $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "O Privacy Badger (www.eff.org/privacybadger) é uma extensão de navegador que aprende automaticamente a bloquear rastreadores invisíveis. O Privacy Badger é feito pela Electronic Frontier Foundation, uma organização sem fins lucrativos que luta pelos seus direitos na Internet.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "Copiar para área de transferência",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Copiado",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Nada a fazer nesta página",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "O Privacy Badger não funciona em páginas especiais como esta. Tente navegar noutro lugar.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "O Privacy Badger está desactivado neste site",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Substituição de Widgets",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "Ao bloquear botões sociais e outros widgets possivelmente úteis (para vídeo, áudio, comentários, etc.), o Privacy Badger pode substituí-los por marcadores de lugar que clicam para ativar.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/ru/messages.json b/src/_locales/ru/messages.json
new file mode 100644
index 0000000..4e38f63
--- /dev/null
+++ b/src/_locales/ru/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "Заблокирован $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "Неверный файл JSON.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Вы уверены, что хотите удалить этот домен из Privacy Badger?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "Нет отслеживающей активности на $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "На данный момент Privacy Badger проверяет только использование сторонних файлов cookie, локального хранилища HTML5 или метода canvas fingerprinting для отслеживания вашей сетевой активности. Некоторые домены могут использовать методы отслеживания, которые Privacy Badger не может обнаружить.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "Проверять, соблюдают ли <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>сторонние домены</a> <a target='_blank' href='https://www.eff.org/dnt-policy'>политику EFF «Do Not Track»</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Пожалуйста, добавьте действительный домен или URL.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "Пожертвовать EFF",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Помогите нам пожертвованиями и вашей поддержкой наших инструментов",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "Не блокировщик рекламы, я другой",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "Спасибо! Мы внимательно изучим эту проблему.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "Этот домен обещает не отслеживать вас",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Блокирование этого домена вызывает неполадки на веб-сайтах",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Щелкните, чтобы вернуть этот домен под контроль Privacy Badger",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "следующий раздел",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "Пожалуйста, <a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>сообщите нам</a> о возникшей проблеме:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Управление данными",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Сообщить об ошибке",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "например: www.domain.com, *.domain.net, domain.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Щелкните здесь, чтобы заблокировать создание файлов cookie с этого домена",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "заблокированные",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "Предотвращать утечку локального IP-адреса через WebRTC",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger автоматически учится блокировать невидимые трекеры. Уделите минуту вашего времени, чтобы увидеть как.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "Что случилось?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Домены с трекерами",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Поделиться в Twitter",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Узнайте, как Privacy Badger защищает вашу приватность",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "Cкачать",
+ "description": ""
+ },
+ "import": {
+ "message": "Импортировать",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "Не заменят следующих виджетов:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Включить замену виджетов",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Отображать домены у которых отслеживающая активность не обнаружена",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Отправить сообщение об ошибке",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "Разрешен $DOMAIN$",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "Что такое Privacy Badger?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Поиск доменов:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Обучение блокировки новых трекеров по мере вашего пользования Интернетом",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Включение обучения может помочь веб-сайтам идентифицировать вас",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Обучение в приватных/инкогнито окнах",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "Включенное обучение в приватных/инкогнито окнах может оставить следы из приватной истории браузера на вашем компьютере. По умолчанию Privacy Badger блокирует уже известные ему трекеры в приватных/инкогнито окнах, но не обучается поиску новых трекеров. Вы можете захотеть включить эту опцию, если часто используете приватные/инкогнито окна.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger по умолчанию больше не будет обучаться по мере вашего пользования Интернетом.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Щелкните ниже, чтобы узнать больше.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Узнайте, как Privacy Badger развивается",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Отображать счетчик трекеров",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "Что такое трекер?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "Пожалуйста, не забывайте нажимать на кнопку 'Сообщить о неполадках на сайте'. Мы уважаем вашу приватность, поэтому не отправляем отчеты автоматически.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Настройки Privacy Badger",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "Это действие автоматически отправит в EFF следующую информацию: адрес страници, на которой вы находитесь в данный момент, версию вашего браузера, версию Privacy Badger и состояние всех переключателей на этой страницe.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Отключенные сайты",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Включить Privacy Badger на этом сайте",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Фильтр по типу:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "Список трекеров и настройки успешно обновлены!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Экспорт пользовательских данных",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "Импорт пользовательских данных:<ul><li>Перезапишет общие настройки</li><li>Объединит списки отключенных сайтов</li><li>Объединит информацию о том, какие трекеры Privacy Badger встретил</li><li>Перезапишет настройки переключателей</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Сбросить",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Сбросить домены с трекерами",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Сброс доменов с трекерами:\n\n • удалит все данные о трекерах, полученные Privacy Badger в процессе вашего пользования Интернетом\n • восстановит список доменов с трекерами до последней версии перед началом обучения (для получения более подробной информации посетите www.eff.org/badger-pretraining)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Удалить все",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Удалить все домены с трекерами",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "Удаление всех доменов с трекерами:\n\n • удалит все трекеры, известные Privacy Badger\n • приведет к тому, что Privacy Badger не будет ничего блокировать до включения режима обучения во время пользования Интернетом",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "Теперь вы под защитой Privacy Badger.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "Щелкните ниже, чтобы узнать, как работает Privacy Badger.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC может раскрыть ваш локальный IP-адрес. Примечание: включение данной опции может снизить производительность в приложениях для конференций, например Google Hangouts.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "Общие настройки",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Приватность",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Дополнительные",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Пройти тур",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Щелкните здесь, чтобы заблокировать этот домен полностью",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "версия $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "Заблокированы файлы cookie от $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "частично заблокированные",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "Понятно; пожалуйста, покажите список доменов с трекерами",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Спасибо вам за то, что установили Privacy Badger!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "Пожалуйста, выберите файл для импорта.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "Сообщить о неполадках на сайте",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Передвиньте переключатель в центр, чтобы заблокировать файлы cookie",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Обучается автоматически",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Вместо составления списков блокировки, Privacy Badger автоматически обнаруживает трекеры на основе их поведения.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Ловит скользкие трекеры",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Невидимое отслеживание осуществляется многими способами; реклама — лишь видимая вершина айсберга. Privacy Badger отправляет <a href='https://globalprivacycontrol.org/' target='_blank'>сигнал Global Privacy Control</a>, чтобы отказаться от разпростровления и продажи ваших данных, и отправляет <a href='https://www.eff.org/issues/do-not-track' target='_blank'>сигнал Do Not Track</a> компаниям, говоря им не отслеживать вас. Если они игнорируют ваши желания, Privacy Badger научится блокировать их вне зависимости от того, рекламные они трекеры или нет.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Закрыть",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Импорт пользовательских данных",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "DNT-зависимые",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Помощь",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "разрешенные",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "Приватность — это командная работа!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "Вам не придется здесь ничего менять.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "все",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "Отмена",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Передвиньте переключатель влево, чтобы заблокировать домен",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Отправлять сайтам сигналы «<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>» и «<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>»",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Отключить отправление адресов посещаемых веб-страниц в Google (это отключит предложение вариантов когда страница не найдена)",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Отключить аудит гиперссылок",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "измененные пользователем",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger отключен для данных сайтов. Это означает, что Privacy Badger не будет ничего блокировать на сайтах, находящихся в данном списке. Privacy Badger также не будет отправлять этим сайтам сигналы Do Not Track и Global Privacy Control.</p><p>Если вы считаете, что Privacy Badger вызывает неполадки на странице, или вы хотите позволить какой-то сайте разпростровлять или продавать ваши данные, вы можете напечатать домен данной страницы в поле ниже и нажать кнопку «Добавить домен».</p><p>Или же, если у вас открыта вкладка со страницей, вы можете выбрать Privacy Badger на панели инструментов и затем нажать кнопку «Отключить». ",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "Заблокировано $COUNT$ потенциальных $LINK_START$трекеров$LINK_END$",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "$LINK_START$Трекеров$LINK_END$ заблокированных нет",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "На этой странице нет сторонних веб-ресурсов. Приватность соблюдена.",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Проект Electronic Frontier Foundation",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Добавить домен",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Передвиньте переключатель вправо, чтобы разблокировать домен",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Отключить Privacy Badger на этом сайте",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Щелкните здесь, чтобы разблокировать этот домен",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privacy Badger НИКОГДА не будет делиться данными о вашей активности в Интернете, пока вы сами того не захотите.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger решил заблокировать $COUNT$ потенциальных $TRACKER_LINK_START$доменов с трекерами$TRACKER_LINK_END$ на данный момент",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privacy Badger не обнаружил ни одного <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>домена с трекерами</a>. Продолжайте просмотр Интернета.",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger начинает блокировать трекер после того, как обнаруживает его на трёх разных веб-сайтах. Три удара — и все!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Фильтр по статусу:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Введите короткое описание ошибки.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Удалить выбранные элементы",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "Когда вы используете Privacy Badger, вы присоединяетесь к <a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundation</a> и миллионам других пользователей в борьбе за приватность. Мы — некоммерческая организация, борющаяся на ваши права в Интернете. Спасибо, что присоединились к нам!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "Для исключения доменов, добавьте «-» перед поисковым запросом. Например, «.co -.com» выведет .co и .co.uk, но не домены .com.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Если вы думаете, что Privacy Badger портит веб-страницу (например, не воспроизводится видео), вы можете нажать кнопку 'Отключить', чтобы выключить Privacy Badger для этого сайта.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Политика конфиденциальности",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Описание",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Ваш Badger еще не решил, нужно ли заблокировать этих домен",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Отображать домены, которые ваш Badger еще не решил заблокировать:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "У приведенных ниже доменов отслеживающая активность не обнаружена",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Настройки",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Поделиться в Facebook",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privacy Badger автоматически учится блокировать невидимые трекеры.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "Ой, что-то пошло не так.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "Privacy Badger заменил кнопку $BUTTON$",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger заменил виджет $WIDGET$",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Разрешить однократно",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Всегда разрешать на этом сайте",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Облачная синхронизация:<ul><li>Требуется Firefox/Chrome Sync</li><li>При загрузке все находящиеся в облаке данные Privacy Badger перезаписываются</li><li>При скачивании списки сайтов с отключенным Privacy Badger объединяются</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Загрузить",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Экспорт отключенных сайтов в облако",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Импорт отключенных сайтов из облака",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Данные успешно импортированы из облака.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "Данные не могут быть загружены из облака.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "Данные успешно загружены в облако.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "Данные не могут быть загружены в облако.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "В облаке нет данных для загрузки.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Расскажите друзьям",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Поделиться",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger заблокировал $COUNT$ потенциальных трекеров на $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privacy Badger (www.eff.org/privacybadger) — это расширение для браузера, которое автоматически учится блокировать невидимые трекеры. Privacy Badger разработан некоммерческой организацией Electronic Frontier Foundation, которая борется на ваши права в Интернете.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "Скопировать в буфер обмена",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Скопировано",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Нечего делать на этой странице",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger не работает на специальных страницах, как эта. Попробуйте где-нибудь еще.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger отключен на этом сайте",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Замена виджетов",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "При блокирование кнопок социальных сетей и других потенциально полезных виджетов (видео, аудио, комментарии), Privacy Badger можеt заменить их специальными элементами.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/sv/messages.json b/src/_locales/sv/messages.json
new file mode 100644
index 0000000..69befb5
--- /dev/null
+++ b/src/_locales/sv/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "Blockerade $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "Ogiltig JSON-fil.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Är du säker på att du vill ta bort den här domänen från Privacy Badger?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "Ingen spårare för $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "För närvarande kontrollerar Privacy Badger endast om tredjeparter använder kakor, HTML5-lagring eller canvas fingeravtryck för att spåra din surfning. Vissa av domänerna kan använda spårningsmetoder som Privacy Badger inte kan upptäcka.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "Kontrollera om <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>tredjepartsdomäner</a> rättar sig efter <a target='_blank' href='https://www.eff.org/dnt-policy'>EFF:s Spåra inte policy</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Lägg till en giltig domän eller webbadress.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "Donera till EFF",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Hjälp oss genom att donera och dela ditt stöd till våra verktyg",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "Inte en annonsblockerare, jag är annorlunda",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "Tack! Vi kommer att gå till botten med det.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "Denna domän lovar att inte spåra dig",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Blockering av denna domän är känt att bryta webbplatser",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Klicka för att återställa kontrollen över denna domän till Privacy Badger",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "nästa avsnitt",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "<a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>Berätta för oss</a> om följande fel:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Hantera data",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Påpeka ett fel",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "t.ex. www.domain.com, *.domain.net, domain.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Klicka här för att blockera den här domänen från att ställa in cookies",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "blockerad",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "Förhindra WebRTC från att läcka din lokala IP-adress",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger lär sig automatiskt att blockera osynliga spårare. Ta en minut för att se hur.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "Vad är fel?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Spårningsdomäner",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Dela på Twitter",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Lär dig hur Privacy Badger skyddar din integritet",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "Hämta",
+ "description": ""
+ },
+ "import": {
+ "message": "Importera",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "Ersätt inte följande gränssnittskomponenter:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Aktivera gränssnittskomponentsersättning",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Visa domäner som inte verkar spåra dig",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Skicka fel",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "Tillät $DOMAIN$",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "Vad är Privacy Badger?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Sök domäner:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Learn to block new trackers from your browsing",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Enabling learning may make you more identifiable to websites",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Inlärning i privata-/inkognitofönster",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "Aktivering av inlärning i privata-/inkognitofönster kan lämna spår av din privata surfhistorik på din dator. Som standard kommer Privacy Badger att blockera spårare som den redan känner till i privata-/inkognitofönster, men den kommer inte att lära sig om nya spårare. Du kan vilja aktivera den här inställningen om du ofta använder privata-/inkognitofönster när du surfar.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger will no longer learn from your browsing by default.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Click below to learn more.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Learn how Privacy Badger is changing",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Visa räkningen av spårare",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "Vad är en spårare?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "Glöm inte att klicka på \"Bröt Privacy Badger denna webbplats\". Vi respekterar din integritet så vi skickar inte automatiska rapporter.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Privacy Badger-inställningar",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "Detta skickar automatiskt följande information till EFF: sidan du för närvarande besöker, din webbläsarversion, versionen av Privacy Badger och lägen för alla skjutreglagen för den här sidan.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Inaktiverade webbplatser",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Aktivera Privacy Badger för denna webbplats",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Filtrera efter typ:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "Listan över spårare och inställningarna uppdaterades!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Exportera användardata",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "Importera användardata:<ul><li>Skriver över allmänna inställningar</li><li>Kombinerar listor över inaktiva webbplatser</li><li>Kombinerar information om vilka spårare Privacy Badger har sett</li><li>Skriver över skjutreglage-anpassningar</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Återställ",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Återställ spårningsdomäner",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Återställa spårningsdomäner kommer att:\n\n • Ta bort all data om spårare som Privacy Badger har lärt dig från din surfning\n • Återställ spårningsdomänlistan till den senaste förutbildade listan (besök www.eff.org/badger-pretraining för mer information)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Ta bort alla",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Ta bort alla spårningsdomäner",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "Ta bort alla spårningsdomäner kommer att:\n\n • Ta bort allt Privacy Badger känner till om spårare\n • Göra att Privacy Badger inte blockera någonting förrän den har fått en chans att återlära av din surfning",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "Du skyddas nu av Privacy Badger.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "För att lära dig hur Privacy Badger fungerar, klicka nedan för en snabb handledning.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC kan läcka din lokala IP-adress. Observera att aktivering av den här inställningen kan försämra prestanda för webbkonferensprogram som Google Hangouts.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "Allmänna inställningar",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Privacy",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Advanced",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Ta turen",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Klicka här för att helt blockera den här domänen",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "version $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "Blockerade kakor från $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "delvis blockerad",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "Jag förstår; visa mig spårningsdomänlistan ändå",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Tack för att du installerat Privacy Badger!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "Vänligen välj en fil att importera.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "Bröt Privacy Badger denna webbplats? Låt oss veta!",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Centrera skjutreglaget för att blockera kakor",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Learns automatically",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Instead of keeping lists of what to block, Privacy Badger automatically discovers trackers based on their behavior.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Fångar lömska spårare",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Invisible tracking happens in all sorts of ways; ads are just the visible tip of the iceberg. Privacy Badger sends the <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control signal</a>, to opt you out of data sharing and selling, and the <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track signal</a> to tell companies not to track you. If they ignore your wishes, Privacy Badger will learn to block them—whether they are advertisers or trackers of other kinds.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Stäng",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Importera användardata",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "DNT-kompatibel",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Hjälp",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "tillåten",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "Integritet är en lagsport!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "Du ska inte behöva ändra någonting här.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "alla",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "Avbryt",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Flytta skjutreglaget till vänster för att blockera en domän",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Send websites the \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" and \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\" signals",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Disable sending web addresses you visit to Google. This disables suggestions for similar pages when a page can't be found.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Disable hyperlink auditing",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "användarstyrd",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is disabled on the following sites. This means that Privacy Badger will not block anything when you visit the sites listed here, and it will not send the Do Not Track or Global Privacy Control signals.</p><p>If you think Privacy Badger is breaking a page, or you would like to allow a particular site to share or sell your data, you can type that page's domain in the box below and click the \"Add domain\" button.</p><p>Alternatively, when you already have the page's tab selected, you can just click on Privacy Badger's button in the browser toolbar and then click the \"Disable\" button.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ potential $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "No $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "Det finns inga resurser från tredje part på den här sidan. Hurra för privatliv!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Ett projekt av Electronic Frontier Foundation",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Lägg till domän",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Flytta skjutreglaget till höger för att tillåta en domän",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Inaktivera Privacy Badger för denna webbplats",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Klicka här för att registrera dig",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privacy Badger kommer ALDRIG att dela data om din surfning om du inte väljer att dela den.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger has decided to block $COUNT$ potential $TRACKER_LINK_START$tracking domains$TRACKER_LINK_END$ so far",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privacy Badger har inte detekterat några <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>spårningsdomäner</a> ännu. Fortsätt surfa!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger börjar blockera när den ser samma spårare på tre olika webbplatser. Tre strike och den är ute!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Filtrera efter status:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Beskriv kortfattat felet nedan.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Ta bort valda",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "När du använder Privacy Badger, går du med i <a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundation</a> och miljontals andra användare i kampen för integritet. Vi är en ideell organisation som kämpar för dina rättigheter på nätet. Tack för att du blev en av oss!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "För att utesluta domäner, börja ditt sökord med \"-\". Till exempel kommer \".co -.com\" för att visa .co och .co.uk men inte .com domäner.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Om du tror att Privacy Badger bryter en sida (till exempel en video spelar inte) kan du klicka på knappen \"Inaktivera\" för att stänga av Privacy Badger för den webbplatsen.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Sekretesspolicy",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Beskrivning",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Din Badger har ännu inte beslutat om dessa domäner ska blockeras",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Visa domäner som din Badger inte har beslutat att blockera ännu:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "Domänerna nedan verkar inte spåra dig",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Inställningar",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Dela på Facebook",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privacy Badger lär sig automatiskt att blockera osynliga spårare.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "Hoppsan. Något gick snett.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "Privacy Badger har ersatt den här $BUTTON$-knappen",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger har ersatt den här $WIDGET$-gränssnittskomponenten",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Tillåt en gång",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Tillåt alltid på den här webbplatsen",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Molnsynkronisering:<ul><li>Kräver Firefox/Chrome Sync</li><li>Sändningen skriver över alla befintliga Privacy Badger-data i molnet</li><li>Hämtning kombinerar listorna över webbplatser där din Badger är inaktiverad</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Skicka",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Exportera inaktiverade webbplatser till molnet",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Importera inaktiverade webbplatser från molnet",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Molndata importerades.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "Molndata kunde inte hämtas.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "Molndata skickades.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "Molndata kunde inte skickas.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "Inga molndata att hämta.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Berätta för dina vänner",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Dela",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger blocked $COUNT$ potential trackers on $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privacy Badger (www.eff.org/privacybadger) är ett webbläsartillägg som automatiskt lär sig att blockera osynliga spårare. Privacy Badger är gjord av Electronic Frontier Foundation, en ideell organisation som kämpar för dina rättigheter på nätet.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "Kopiera till urklipp",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Kopierad",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Inget att göra på den här sidan",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger fungerar inte på särskilda sidor som den här. Prova att surfa någon annanstans.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger är inaktiverad på denna webbplats",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Gränssnittskomponentsersättning",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "Vid blockering av sociala knappar och andra potentiellt användbara gränssnittskomponenter (video, ljud, kommentarer) kan Privacy Badger ersätta med klick-för-att-aktivera platshållare.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/tr/messages.json b/src/_locales/tr/messages.json
new file mode 100644
index 0000000..876576d
--- /dev/null
+++ b/src/_locales/tr/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "Engellendi $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "Geçersiz JSON dosyası.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Bu adresi Privacy Badger'dan kaldırmak istediğinize emin misiniz?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "Takip yok $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "Şu an Privacy Badger sadece 3. partilerin çerez, yerel HTML5 depolaması, veya tuval parmak izi kullanarak taramanızı takip edip etmediğini kontrol ediyor. Bazı adresler Privacy Badger tarafından algılanmayan yöntemler kullanıyor olabilir.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "<a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>Üçüncü parti adreslerin</a> <a target='_blank' href='https://www.eff.org/dnt-policy'>EFF'nin Do Not Track poliçesine</a> uyup uymadığını kontrol et",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Lütfen geçerli bir adres veya URL girin.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "EFF'ye bağış yap",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Bağışta bulunarak ve araçlarımıza desteğinizi paylaşarak bize yardım edin",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "Ben bir reklam önleyici değilim, farklıyım",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "Teşekkürler! Bunu araştıracağız.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "Bu adres sizi takip etmeme sözü veriyor.",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Bu domainin engellenmesinin websiteleri bozduğu biliniyor",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Bu domainin kontrolünü Privacy Badger'a bırakmak için tıklayın",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "sonraki bölüm",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "Lütfen bize şu hata hakkında <a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>bilgi verin</a>:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Veriyi Düzenle",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Hata Rapor Et",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "örn. www.adres.com, *.adres.net, adres.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Bu adresin çerez kullanmasını engellemek için buraya tıkla",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "engellenmiş",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "WebRTC'nin yerel IP adresini açığa çıkarmasını engelle",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger görünmez takipçileri engellemeyi otomatik olarak öğrenir. Nasıl olduğunu görmek için bir dakika ayırın.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "Sorun Nedir?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Takip Eden Adresler",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Twitter'da Paylaş",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Privacy Badger'ın gizliliğinizi nasıl koruduğunu öğrenin",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "İndir",
+ "description": ""
+ },
+ "import": {
+ "message": "İçeri aktar",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "Şu widgetları değiştirme:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Widget değiştirmesini aç",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Sizi izlemiyor gibi görünen adresleri göster",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Hata Gönder",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "Şuna izin verildi: $DOMAIN$",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "Privacy Badger nedir?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Adresleri ara:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Learn to block new trackers from your browsing",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Enabling learning may make you more identifiable to websites",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Özel/Gizli pencerelerde öğren",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "Özel/gizli pencerelerde öğrenmeyi etkinleştirmek bilgisayarınızdaki özel arama geçmişinize dair izler bırakabilir. Varsayılan olarak, Privacy Badger halihazırda haberdar olduğu takipçileri Özel/Gizli pencerelerde engeller, ancak yeni takipçiler hakkında bilgi edinmez. Eğer gezintinizin büyük bölümü Özel/Gizli pencerelerde oluyorsa bunu etkinleştirmek isteyebilirsiniz.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger will no longer learn from your browsing by default.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Click below to learn more.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Learn how Privacy Badger is changing",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Takipçi sayısını göster",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "Takipçi nedir?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "Lütfen 'Privacy Badger bu siteyi bozdu mu' butonuna tıklamayı unutmayın. Gizliliğinize önem veriyoruz ve bu yüzden otomatik raporlar göndermiyoruz.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Privacy Badger Seçenekleri",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "This will automatically send the following information to EFF: the page you're currently visiting, your browser version, the version of Privacy Badger, and the state of all of the sliders on this page.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Engellenmiş Siteler",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Bu Site İçin Privacy Badger'ı Etkinleştir",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Türe göre filtrele:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "Takipçi listesi ve ayarlar başarıyla değiştirildi!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Kullanıcı verisini dışa aktar",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "Kullanıcı verisini içe aktarmak: <ul><li>Genel ayarları değiştirir</li><li>Engellenmiş sitelerin listesini birleştirir</li><li>Privacy Badger'ın takipçiler hakkındaki bilgilerini birleştirir</li><li>Kaydırıcı ayarlarını değiştirir</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Sıfırla",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Takip eden adresleri sıfırla",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Takip eden adresleri sıfırlamak:\n\n • Privacy Badger'ın gezinmeniz sırasında elde ettiği verileri silecek\n • Takip eden adres listesini en son önceden-eğitimli listeye geri döndürecek (daha fazlasını öğrenmek için www.eff.org/badger-pretraining adresini ziyaret edin)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Hepsini kaldır",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Takip eden adreslerin hepsini kaldır",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "Takip eden adreslerin hepsini kaldırmak:\n\n • Privacy Badger'ın takipçilerle ilgili bildiği her şeyi silecek\n • Privacy Badger gezinmeniz sırasında tekrar birşeyler öğrenene dek hiçbir şeyi engellemeyecek",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "Şu an Privacy Badger tarafından korunuyorsunuz.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "Privacy Badger'ın nasıl çalıştığını öğrenmek için aşağıdaki kısa öğreticiye tıklayabilirsiniz.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC yerel IP adresinizi açığa çıkarabilir. Bu seçeneğin etkinleştirilmesinin Google Hangouts gibi web konferans araçlarında performansı düşürebileceğini göz önünde bulundurun.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "Genel Ayarlar",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Privacy",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Advanced",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Tura çık",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Bu adresi tamamen engellemek için tıklayın",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "versiyon $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "Şuradan çerezler engellendi: $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "kısmen engellenmiş",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "Anladım; yine de lütfen bana takip eden adreslerin listesini göster",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Privacy Badger'ı yüklediğiniz için teşekkürler!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "İçeri aktarmak için bir dosya seçin.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "Privacy Badger bu siteyi bozdu mu? Bizi bilgilendirin!",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Çerezleri engellemek için kaydırıcıyı ortalayın",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Learns automatically",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Instead of keeping lists of what to block, Privacy Badger automatically discovers trackers based on their behavior.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Sinsi takipçileri yakalar",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Invisible tracking happens in all sorts of ways; ads are just the visible tip of the iceberg. Privacy Badger sends the <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control signal</a>, to opt you out of data sharing and selling, and the <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track signal</a> to tell companies not to track you. If they ignore your wishes, Privacy Badger will learn to block them—whether they are advertisers or trackers of other kinds.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Kapat",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Kullanıcı verisini içe aktar",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "DNT uyumlu",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Yardım",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "izin verilmiş",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "Gizlilik bir takım sporudur!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "Buradaki hiçbir şeyi düzenlemeniz gerekmez.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "hepsi",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "İptal",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Bir adresi engellemek için kaydırıcıyı sola kaydırın",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Send websites the \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" and \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\" signals",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Disable sending web addresses you visit to Google. This disables suggestions for similar pages when a page can't be found.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Disable hyperlink auditing",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "kullanıcı kontrolünde",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is disabled on the following sites. This means that Privacy Badger will not block anything when you visit the sites listed here, and it will not send the Do Not Track or Global Privacy Control signals.</p><p>If you think Privacy Badger is breaking a page, or you would like to allow a particular site to share or sell your data, you can type that page's domain in the box below and click the \"Add domain\" button.</p><p>Alternatively, when you already have the page's tab selected, you can just click on Privacy Badger's button in the browser toolbar and then click the \"Disable\" button.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ potential $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "No $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "There are no third party resources on this page. Hooray for privacy!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Bir Electronic Frontier Foundation projesi",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Adres Ekle",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Bir adrese izin vermek için kaydırıcıyı sağa kaydırın",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Bu Site İçin Privacy Badger'ı Devre Dışı Bırak",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Bu adrese izin vermek için tıklayın",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privacy Badger siz istemediğiniz sürece gezintiniz hakkında ASLA veri paylaşmaz.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger has decided to block $COUNT$ potential $TRACKER_LINK_START$tracking domains$TRACKER_LINK_END$ so far",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privacy Badger hiçbir <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>takipçi adres</a> algılamadı. Gezinmeye devam!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger, bir takipçiyi üç farklı websitesinde gördükten sonra engellemeye başlar.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Duruma göre filtrele:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Hatayı aşağıda kısaca özetleyin.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Seçilenleri kaldır",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "Privacy Badger kullandığınızda <a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundation</a>'a ve gizlilik için savaşan milyonlarca diğer kullanıcıya katılmış olursunuz. Biz çevrimiçi haklarınız için savaşan, kar amacı gütmeyen bir kuruluşuz. Bize katıldığınız için teşekkür ederiz!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "Adresleri dışlamak için, arama metninizin başına \"-\" getirin. Örneğin, \".co -.com\" size .co ve .co.uk adreslerini gösterir ancak .com göstermez.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Eğer Privacy Badger'ın bir sayfayı bozduğunu düşünüyorsanız (örneğin başlatılamayan bir video), 'Devre Dışı Bırak' butonuna tıklayarak Privacy Badger'ı o site için kapatabilirsiniz.",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Gizlilik Politikası",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Açıklama",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Badger'ınız henüz bu adreslerin engellenmesi gerekip gerekmediğine karar vermemiş",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Badger'ınızın henüz engellemeye karar vermediği adresleri göster:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "Aşağıdaki adresler sizi takip etmiyor gibi görünüyor",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Ayarlar",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Facebook'ta Paylaş",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privacy Badger görünmez takipçileri engellemeyi otomatik olarak öğrenir.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "Tüh. Birşeyler ters gitti.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "Privacy Badger bu $BUTTON$ butonunu değiştirdi",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger bu $WIDGET$ widgetı değiştirdi",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Bir kerelik izin ver",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Bu sitede her zaman izin ver",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Bulut senkronizasyonu:<ul><li>Firefox/Chrome Sync gerekir</li><li>Buluta yapılan yükleme, buluttaki Privacy Badger verisinin üstüne yazılır</li><li>İndirme işlemi Badger'ınızın engellediği sitelerin listelerini birleştirir</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Buluta yükle",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Engellenmiş siteleri buluta aktar",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Engellenmiş siteleri buluttan içe aktar",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Buluttaki veri başarıyla yüklendi.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "Buluttaki veri indirilemedi.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "Veri başarıyla buluta yüklendi.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "Veri, buluta yüklenemedi.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "İndirilecek bulut verisi yok.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Arkadaşlarınızla paylaşın",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Paylaş",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger blocked $COUNT$ potential trackers on $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privacy Badger (www.eff.org/privacybadger), görünmez takipçileri otomatik olarak engellemeyi öğrenen bir tarayıcı eklentisidir. Privacy Badger, çevrimiçi haklarınız için savaşan, kar amacı gütmeyen bir kuruluş olan Electronic Frontier Foundation tarafından yapılmıştır.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "Panoya kopyala",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Kopyalandı",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Bu sayfada yapılacak bir şey yok",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger bu gibi özel sayfalarda çalışmaz. Başka bir yerde gezinmeyi deneyin.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger bu sitede devre dışı bırakıldı",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Widget Değiştirme",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "Sosyal butonları ve diğer potansiyel olarak yararlı (video, ses, yorum) widgetlarını engellerken, Privacy Badger onları tıkla-çalıştır yer tutucularla değiştirebilir.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/uk/messages.json b/src/_locales/uk/messages.json
new file mode 100644
index 0000000..7262120
--- /dev/null
+++ b/src/_locales/uk/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "Заблоковано $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "Неправильний файл JSON.",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "Ви справді хочете вилучити цей домен з Privacy Badger?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "Немає стеження для $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "В даний момент Privacy Badger лише перевіряє, чи сторонні елементи не використовують куки, локальне сховище HTML5, або відбиток canvas для стеження за вашим переглядом. Деякі з цих доменів можуть використовувати способи стеження, які Privacy Badger не в змозі виявити.",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "Перевіряти, чи <a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>сторонні домени</a> підтримують <a target='_blank' href='https://www.eff.org/dnt-policy'>політику EFF щодо відмови від стеження</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "Будь ласка, додайте дійсний домен чи URL-адресу.",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "Зробити внесок для EFF",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "Допоможіть нам, зробивши внесок і виявивши свою підтримку наших засобів",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "Дещо інше, ніж звичайні засоби для блокування реклами",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "Дякуємо! Ми доберемося до причини виникнення проблеми.",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "Цей домен обіцяє не стежити за вами",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "Блокування цього домену пошкоджує вебсайти",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "Натисніть для повернення контролю над цим доменом до Privacy Badger",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "наступний розділ",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "Будь ласка, <a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>розкажіть нам</a> про наступну помилку:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "Керувати даними",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "Звіт про помилку",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "наприклад, www.domain.com, *.domain.net, domain.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "Натисніть тут, щоб заблокувати встановлення куків з цього домена",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "заблоковані",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "Не дозволяти WebRTC виявляти локальну IP-адресу",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger автоматично навчається блокувати невидимі елементи стеження. Витратьте хвилинку, щоб поглянути як.",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "Що не так?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "Домени стеження",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "Поширити у Twitter",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "Дізнайтеся, як Privacy Badger захищає вашу приватність",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "Завантажити",
+ "description": ""
+ },
+ "import": {
+ "message": "Імпорт",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "Не замінювати такі віджети:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "Увімкнути заміну віджетів",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "Показувати домени, що не стежать за вами",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "Повідомити про помилку",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "Дозволено $DOMAIN$",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "Що таке Privacy Badger?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "Пошук доменів:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Навчитися блокувати нові елементи стеження під час перегляду",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Увімкнення навчання може дозволити вебсайтам легше ідентифікувати вас",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "Навчання у приватних/анонімних вікнах",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "Увімкнення навчання у приватних/анонімних вікнах може залишати сліди історії перегляду на комп'ютері. Типово, Privacy Badger буде блокувати відомі йому елементи стеження в приватних/анонімних вікнах, але не буде вивчати нові. Ймовірно, ви захочете увімкнути цю функцію, якщо багато часу проводите у приватному/анонімному перегляді.",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger відтепер типово не навчатиметься під час перегляду.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Натисніть внизу, щоб дізнатися більше.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Дізнатися, як розвивається Privacy Badger",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "Показувати лічильник стеження",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "Що таке стеження?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "Будь ласка, не забудьте натиснути на \"Privacy Badger пошкодив цей сайт? Повідомте нас!\". Ми поважаємо вашу приватність, і тому не надсилаємо автоматичні звіти.",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Налаштування Privacy Badger",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "Ця дія призведе до автоматичного надсилання такої інформації до EFF: відвідувана сторінка, версія браузера, версія Privacy Badger, а також положення всіх перемикачів для цієї сторінки.",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "Вимкнені сайти",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "Увімкнути Privacy Badger для цього сайту",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "Фільтр за типом:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "Список елементів стеження й налаштування успішно оновлено!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "Експорт користувацьких даних",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "Імпорт даних користувача:<ul><li>Перезаписуються загальні налаштування</li><li>Об'єднуються списки вимкнених сайтів</li><li>Об'єднується інформація про виявлені елементи стеження Privacy Badger</li><li>Перезаписуються налаштування перемикачів</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "Відновити",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "Відновити домени стеження",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "Відновлення доменів стеження спричинить:\n\n • Вилучення всіх даних про елементи стеження, які Privacy Badger виявив за час користування браузером\n • Відновлення списку доменів стеження до останньої стандартної версії (для докладних відомостей відвідайте www.eff.org/badger-pretraining)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "Вилучити все",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "Вилучити всі домени стеження",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "Вилучення всіх доменів стеження спричинить:\n\n • Вилучення всіх даних, відомих Privacy Badger про стеження\n • Privacy Badger не буде блокувати нічого, доки не виявить стеження під час роботи браузера",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "Тепер вас захищає Privacy Badger.",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "Щоб дізнатися, як працює Privacy Badger, натисніть внизу для швидкого ознайомлення.",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC може виявляти вашу локальну IP-адресу. Зауважте, що ця опція може спричинити погіршення швидкодії певних інструментів для веб-конференцій, таких як Google Hangouts.",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "Загальні налаштування",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "Приватність",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "Розширені",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "Переглянути знайомство",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "Натисніть тут, щоб повністю заблокувати цей домен",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "версія $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "Заблоковано куки з $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "частково заблоковані",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "Я розумію. Будь ласка, все одно покажіть мені перелік доменів стеження",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "Дякуємо за встановлення Privacy Badger!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "Оберіть файл для імпорту.",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "Privacy Badger пошкодив цей сайт? Повідомте нас!",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "Встановіть перемикач посередині, щоб дозволити куки",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Навчається автоматично",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Замість використання списків блокування, Privacy Badger автоматично виявляє елементи стеження на основі їх поведінки.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "Перехоплює підступне стеження",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Invisible tracking happens in all sorts of ways; ads are just the visible tip of the iceberg. Privacy Badger sends the <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control signal</a>, to opt you out of data sharing and selling, and the <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track signal</a> to tell companies not to track you. If they ignore your wishes, Privacy Badger will learn to block them—whether they are advertisers or trackers of other kinds.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "Закрити",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "Імпорт користувацьких даних",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "DNT-сумісні",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "Допомога",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "дозволені",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "Приватність - це командна гра!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "Вам не слід щось тут змінювати.",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "всі",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "Скасувати",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "Змініть положення перемикача вліво, щоб заблокувати домен",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Send websites the \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" and \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\" signals",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "Вимкнути надсилання відвідуваних веб адрес в Google. Ця дія вимикає пропозиції для схожих сторінок, коли сторінку не вдається знайти.",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "Вимкнути аудит гіперпосилань",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "контрольовані користувачем",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is disabled on the following sites. This means that Privacy Badger will not block anything when you visit the sites listed here, and it will not send the Do Not Track or Global Privacy Control signals.</p><p>If you think Privacy Badger is breaking a page, or you would like to allow a particular site to share or sell your data, you can type that page's domain in the box below and click the \"Add domain\" button.</p><p>Alternatively, when you already have the page's tab selected, you can just click on Privacy Badger's button in the browser toolbar and then click the \"Disable\" button.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "Заблоковано $COUNT$ потенційних $LINK_START$елементів стеження$LINK_END$",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "Немає заблокованих $LINK_START$елементів стеження$LINK_END$",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "На цій сторінці немає сторонніх ресурсів. Приватність на найвищому рівні!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "Проект Electronic Frontier Foundation",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "Додати домен",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "Змініть положення перемикача вправо, щоб дозволити домен",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "Вимкнути Privacy Badger для цього сайту",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "Натисніть тут, щоб дозволити цей домен",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privacy Badger НІКОЛИ нікому не передає ваші дані доки ви самі не захочете зробите це.",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger наразі вирішив заблокувати $COUNT$ потенційних $TRACKER_LINK_START$доменів стеження$TRACKER_LINK_END$",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privacy Badger досі не виявив жодного <a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>домену стеження</a>. Продовжуйте перегляд!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger починає блокування, як тільки він бачить, що один і той самий елемент стеження з'являється на трьох різних вебсайтах. Три попадання і він заблокований!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "Фільтр за статусом:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "Коротко опишіть помилку.",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "Вилучити обрані",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "Використовуючи Privacy Badger, ви долучаєтесь до спільноти <a href='https://www.eff.org/' target='_blank'>Electronic Frontier Foundation</a> разом з мільйонами інших користувачів, які відстоюють приватність. Ми є некомерційною організацією, яка відстоює ваші права онлайн. Дякуємо, що приєдналися до нас!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "Щоб виключити домени, поставте на початку свого пошукового запиту \"-\". Наприклад, \".co -.com\" буде показувати домени .co та .co.uk але не .com.",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "Якщо ви вважаєте, що Privacy Badger пошкодив сторінку (наприклад, не відтворюється відео), ви можете вимкнути його на цій сторінці, натиснувши \"Вимкнути Privacy Badger для цього сайту\".",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "Політика приватності",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "Опис",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "Badger ще не вирішив, чи слід блокувати ці домени",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "Показати домени, які Badger ще не вирішив блокувати:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "Домени, що не стежать за вами",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "Налаштування",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "Поширити на Facebook",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privacy Badger автоматично навчається блокувати невидимі елементи стеження.",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "Ой. Щось пішло не так.",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "Privacy Badger змінив цю кнопку $BUTTON$",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger замінив цей віджет $WIDGET$",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "Дозволити один раз",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "Завжди дозволяти на цьому сайті",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "Синхронізація:<ul><li>Необхідний обліковий запис Firefox/Chrome</li><li>Вивантаження перезаписує наявні дані в хмарному сховищі</li><li>Завантаження об'єднує списки сайтів, на яких Privacy Badger вимкнений</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "Вивантажити",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "Експорт вимкнених сайтів у хмарне сховище",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "Імпорт вимкнених сайтів з хмарного сховища",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "Дані успішно імпортовано з хмарного сховища.",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "Не вдалося завантажити дані з хмарного сховища.",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "Дані успішно вивантажено в хмарне сховище.",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "Не вдалося вивантажити дані в хмарне сховище.",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "Хмарне сховище не містить даних для завантаження.",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "Розповісти друзям",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "Поширити",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger заблокував $COUNT$ потенційних елементів стеження на $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privacy Badger (www.eff.org/privacybadger) - це розширення для браузера, що автоматично навчається блокувати невидимі елементи стеження. Privacy Badger розроблено некомерційною організацією Electronic Frontier Foundation, яка відстоює ваші права онлайн.",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "Копіювати в буфер обміну",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "Скопійовано",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "Немає чого робити на цій сторінці",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger не працює на таких сторінках, як ця. Спробуйте переглянути інші сторінки.",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger вимкнений на цьому сайті",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "Заміна віджетів",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "При блокуванні кнопок соціальних мереж та інших потенційно корисних віджетів (відео, аудіо, коментарі), Privacy Badger може замінювати їх спеціальними елементами з можливістю вибіркової активації.",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/zh_CN/messages.json b/src/_locales/zh_CN/messages.json
new file mode 100644
index 0000000..d216921
--- /dev/null
+++ b/src/_locales/zh_CN/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "已屏蔽 $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "无效的 JSON 文件。",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "确定要从隐私獾中移除这个域名吗?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "$DOMAIN$ 没有追踪",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "隐私獾只检查第三方域名是否在使用 Cookies、HTML5 本地存储和 canvas 指纹来追踪你的浏览记录。 有些域名可能使用了隐私獾无法检测的追踪方式。",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "检查<a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>第三方域名</a>是否遵守<a target='_blank' href='https://www.eff.org/dnt-policy'>电子前哨基金会的“请勿追踪”政策</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "请添加一个有效的域名或者 URL。",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "向电子前哨基金会捐款",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "捐款并分享对我们工具的支持来帮助我们",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "不是广告拦截器,我不一样",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "谢谢!我们会调查这个问题。",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "这个域名承诺不会追踪你",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "已知屏蔽此域名会破坏网站",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "点击让隐私獾重新控制此域名",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "下一节",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "请<a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>告诉我们</a>以下的错误信息:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "管理数据",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "报告错误",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "例如 www.domain.com, *.domain.net, domain.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "点击这里屏蔽此域名的 Cookies",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "已屏蔽",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "阻止 WebRTC 泄露本地 IP 地址",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "隐私獾会自动学习去屏蔽不可见的追踪器。看看这是如何做到的吧。",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "发生了什么问题?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "追踪域名",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "分享到 Twitter",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "了解隐私獾如何保护你的隐私",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "下载",
+ "description": ""
+ },
+ "import": {
+ "message": "导入",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "不要替换以下小部件:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "开启小部件替换",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "显示看起来没有追踪你的域名",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "报告错误",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "允许 $DOMAIN$",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "什么是隐私獾?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "搜索域名:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "Learn to block new trackers from your browsing",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "Enabling learning may make you more identifiable to websites",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "在隐私/无痕模式下学习",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "启用“在隐私/无痕模式学习”后,你的隐私浏览历史可能会在电脑中留下痕迹。默认设置下,隐私獾会在隐私/无痕模式时屏蔽已知的追踪器,但不会学习新的追踪器。如果你平时经常使用隐私/无痕模式的话,你可能想要启用这个选项。",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "Privacy Badger will no longer learn from your browsing by default.",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "Click below to learn more.",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "Learn how Privacy Badger is changing",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "显示追踪器数量",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "什么是追踪器?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "请不要忘记点击“报告隐私獾导致的显示异常的网站”。我们尊重您的隐私,因此我们不自动发送报告。",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "隐私獾设置",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "这将会向电子前哨基金会发送这些信息:你当前正在访问的页面、浏览器版本、隐私獾版本以及本页面所有滑块的状态。",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "已禁用的域名",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "在当前的网站上启用隐私獾",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "按类型过滤:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "成功更新追踪器列表与设置!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "导出用户数据",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "导入用户数据将会:<ul><li>覆盖通用设置</li><li>与已禁用站点列表合并</li><li>与隐私獾探测到的追踪器信息合并</li><li>覆盖自定义滑块设置</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "重置",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "重置追踪域名列表",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "重置追踪域名将会:\n\n• 删除所有隐私獾从您浏览中学习到的数据\n• 将追踪域名列表重置为最新的预训练列表(访问 www.eff.org/badger-pretraining 以了解更多)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "移除所有",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "移除所有追踪域名",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "移除所有追踪域名将会:\n\n• 删除所有隐私獾对追踪器的了解\n• 使隐私獾在有机会重新从您的浏览中学习前不屏蔽任何东西",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "你现在已经被隐私獾保护了。",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "要了解隐私獾是如何工作的,点击这里来访问快速教程。",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC 可能泄露您的本地 IP 地址。请注意,开启这个功能可能降低网络会议软件(如谷歌环聊)的性能。",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "通用设置",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "隐私",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "高级",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "了解一下",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "点击这里以完全屏蔽此域名",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "版本 $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "屏蔽此网站的 cookies $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "部分被屏蔽",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "我明白;无论如何,请显示追踪域名列表",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "感谢你安装隐私獾!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "请选择一个你要导入的文件。",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "报告隐私獾导致的显示异常的网站",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "将滑块移至中间来屏蔽 cookies",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "Learns automatically",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Instead of keeping lists of what to block, Privacy Badger automatically discovers trackers based on their behavior.",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "发现鬼鬼祟祟的追踪器",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "Invisible tracking happens in all sorts of ways; ads are just the visible tip of the iceberg. Privacy Badger sends the <a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control signal</a>, to opt you out of data sharing and selling, and the <a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track signal</a> to tell companies not to track you. If they ignore your wishes, Privacy Badger will learn to block them—whether they are advertisers or trackers of other kinds.",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "关闭",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "导入用户数据",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "DNT(请勿追踪) 兼容",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "帮助",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "已允许",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "保护隐私人人有责!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "你应该无需更改这里的任何东西。",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "全部",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "取消",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "将滑块移至左边以屏蔽一个域名",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "Send websites the \"<a href='https://globalprivacycontrol.org/' target='_blank'>Global Privacy Control</a>\" and \"<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>\" signals",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "禁止向谷歌发送你访问的网址。如果此项开启,在找不到要访问的网页时将不会显示有关类似网页的建议。",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "禁用超链接审计",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "用户控制",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger is disabled on the following sites. This means that Privacy Badger will not block anything when you visit the sites listed here, and it will not send the Do Not Track or Global Privacy Control signals.</p><p>If you think Privacy Badger is breaking a page, or you would like to allow a particular site to share or sell your data, you can type that page's domain in the box below and click the \"Add domain\" button.</p><p>Alternatively, when you already have the page's tab selected, you can just click on Privacy Badger's button in the browser toolbar and then click the \"Disable\" button.</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ potential $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "No $LINK_START$trackers$LINK_END$ blocked",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "本页面上没有第三方资源。隐私万岁!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "一个电子前哨基金会的项目",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "添加域名",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "将滑块移至右边来允许一个域名",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "在当前的网站上禁用隐私獾",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "点击这里以允许这个域名",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "除非你主动分享,否则隐私獾永远都不会上传你的浏览记录。",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "Privacy Badger has decided to block $COUNT$ potential $TRACKER_LINK_START$tracking domains$TRACKER_LINK_END$ so far",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "隐私獾还没有检测到任何<a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>追踪域名</a>。继续浏览吧!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "隐私獾",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "隐私獾会在三个网站发现同一个追踪器后开始屏蔽。三振出局!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "按状态过滤:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "在下面简要描述发生的错误。",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "删除所选",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "当您使用隐私獾,您就和<a href='https://www.eff.org/' target='_blank'>电子前哨基金会</a>和成千上万的其它用户一道共同保卫隐私。我们是为您在线权利奋斗的非营利性组织。感谢您加入我们!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "在搜索关键词前加入“-”来排除域名。例如,“.co -.com”将会显示 .co 和 .co.uk,但不显示.com域名。",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "如果您认为隐私獾使得网站显示异常(例如无法播放视频),您可以点击“禁用”按钮来在此网站关闭隐私獾。",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "隐私政策",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "描述",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "隐私獾尚未决定是否屏蔽这些域名",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "显示隐私獾尚未决定的域名:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "以下域名看起来不在追踪你",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "选项",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "分享到 Facebook",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "隐私獾会自动学习去阻止不可见的追踪器。",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "哎呀。出错了。",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "隐私獾已经替换了这个 $BUTTON$ 按钮",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "隐私獾已经替换了这个$WIDGET$小工具",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "允许一次",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "总是在该网站允许",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "云端同步:<ul><li>需要火狐或 Chrome 同步</li><li>上传将覆盖任何云端已有的隐私獾数据</li><li>下载内容将与您将隐私獾禁用的站点结合</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "上传",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "导出已禁用的域名到云端",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "从云端导入禁用域名",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "成功导入云端数据。",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "无法下载云端数据。",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "成功上传数据到云端。",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "无法上传数据到云端。",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "无云端数据可供下载。",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "告诉您的朋友",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "分享",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger blocked $COUNT$ potential trackers on $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "隐私獾(www.eff.org/privacybadger)是一款浏览器扩展,它能够自动学习去屏蔽不可见的追踪器。隐私獾由一家为您在线权利而战的非营利组织——电子前哨基金会创造。",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "复制到剪贴板",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "已复制",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "对这个页面无事可做",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "隐私獾不在特殊页面工作——比如这一个。试着浏览一下别的网页。",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "隐私獾在此站点被禁用",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "小部件替换",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "当屏蔽社交媒体按钮和其他可能有用的小部件(如音视频和评论区)时,隐私獾可以将他们替换成“点击以启用”的占位部件。",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/_locales/zh_TW/messages.json b/src/_locales/zh_TW/messages.json
new file mode 100644
index 0000000..717851d
--- /dev/null
+++ b/src/_locales/zh_TW/messages.json
@@ -0,0 +1,677 @@
+{
+ "badger_status_block": {
+ "message": "封鎖 $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a red slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "invalid_json": {
+ "message": "無效的 JSON 檔案。",
+ "description": ""
+ },
+ "options_remove_origin_confirm": {
+ "message": "您確定要從 Privacy Badger 移除此網域?",
+ "description": "Confirmation shown when you click to remove a domain from Privacy Badger's tracking domains list on the options page."
+ },
+ "badger_status_noaction": {
+ "message": "沒有追蹤 $DOMAIN$",
+ "description": "Tooltip shown when you hover over a non-tracking domain name with a green slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "non_tracker_tip": {
+ "message": "目前 Privacy Badger 只檢查透過第三方 cookie、HTML5 Local Storage、Canvas 指紋來追蹤您瀏覽網頁的情況。有些網域可能使用了 Privacy Badger 無法偵測的追蹤方式。",
+ "description": ""
+ },
+ "options_dnt_policy_setting": {
+ "message": "檢查<a target='_blank' href='https://www.eff.org/privacybadger/faq#What-is-a-third-party-tracker'>第三方網域</a>是否遵守<a target='_blank' href='https://www.eff.org/dnt-policy'>EFF 的 Do Not Track 政策</a>",
+ "description": "Checkbox label on the general settings page"
+ },
+ "invalid_domain": {
+ "message": "請新增有效的網域或 URL。",
+ "description": ""
+ },
+ "donate_to_eff": {
+ "message": "捐款給 EFF 電子前鋒基金會",
+ "description": "Button shown in the popup and on the intro page."
+ },
+ "intro_donate_subheading": {
+ "message": "透過捐款與分享對我們的工具的支援來協助我們",
+ "description": "Shown below the Donate button on the intro page."
+ },
+ "intro_not_an_adblocker": {
+ "message": "不是廣告阻擋器,我不一樣",
+ "description": "Intro page paragraph heading."
+ },
+ "report_success": {
+ "message": "謝謝!我們將會調查這個問題。",
+ "description": ""
+ },
+ "dnt_tooltip": {
+ "message": "此網域承諾不會追蹤您",
+ "description": "Tooltip shown when you hover over a DNT-compliant domain name in the list of domains in the popup or under the Tracking Domains tab on the options page."
+ },
+ "breakage_warning_tooltip": {
+ "message": "已知封鎖此網域會破壞網站",
+ "description": "Tooltip for a warning icon that appears when move a domain slider to 'red' (block) for a domain that was automatically set to 'yellow' (block cookies)."
+ },
+ "feed_the_badger_title": {
+ "message": "點擊以將此網域的控制權還給 Privacy Badger",
+ "description": "Tooltip shown when you hover over an undo arrow that appears when you move a domain slider away from its automatic setting."
+ },
+ "next_section": {
+ "message": "下一區",
+ "description": "Image alt. text on a couple of \"scroll down\" arrow buttons on the intro page."
+ },
+ "extension_error_text": {
+ "message": "請<a href='https://www.eff.org/privacybadger#faq-I-found-a-bug!-What-do-I-do-now?' target='_blank'>告訴我們</a>關於下列錯誤的訊息:",
+ "description": "Shown in the popup when there is a problem with the user's Privacy Badger extension that we want to encourage the user to tell us about."
+ },
+ "data_settings": {
+ "message": "管理資料",
+ "description": "This is an options page tab heading."
+ },
+ "report_title": {
+ "message": "回報錯誤",
+ "description": ""
+ },
+ "whitelist_form_domain_input_placeholder": {
+ "message": "範例:www.domain.com, *.domain.net, domain.org",
+ "description": "Placeholder text for the Add domain input under the Disabled Sites tab on the options page."
+ },
+ "domain_slider_cookieblock_tooltip": {
+ "message": "在此點按以從設定 cookies 阻擋此網域",
+ "description": "Tooltip shown when you hover over the center part of a slider shown for each domain in the domain list."
+ },
+ "options_domain_filter_block": {
+ "message": "已阻擋",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "options_webrtc_setting": {
+ "message": "防止 WebRTC 洩漏本機 IP 地址",
+ "description": "Checkbox label on the general settings page"
+ },
+ "intro_welcome": {
+ "message": "Privacy Badger 會自動學習並阻擋不可見的追蹤器。花一分鐘來看看它怎麼運作的。",
+ "description": "Intro page welcome paragraph."
+ },
+ "error_input": {
+ "message": "有什麼問題?",
+ "description": ""
+ },
+ "options_domain_list_tab": {
+ "message": "追蹤網域",
+ "description": "This is an options page tab heading."
+ },
+ "share_button_title_twitter": {
+ "message": "在 Twitter 上分享",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "first_run_text": {
+ "message": "瞭解 Privacy Badger 如何保護您的隱私",
+ "description": "Part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "download": {
+ "message": "下載",
+ "description": ""
+ },
+ "import": {
+ "message": "匯入",
+ "description": ""
+ },
+ "options_hide_social_widgets": {
+ "message": "不要取代下列的小工具:",
+ "description": "Multiple selection box on the widget replacement tab"
+ },
+ "options_social_widgets_checkbox": {
+ "message": "啟用小工具取代",
+ "description": "Checkbox label on the widget replacement tab"
+ },
+ "options_show_nontracking_domains_checkbox": {
+ "message": "顯示似乎未在追蹤您的網域",
+ "description": "Checkbox label on the general settings page. Should match wording used in the 'non_tracker' message."
+ },
+ "report_button": {
+ "message": "送出錯誤",
+ "description": ""
+ },
+ "badger_status_allow": {
+ "message": "允許 $DOMAIN$",
+ "description": "Tooltip shown when you hover over a tracking but still allowed (green slider) domain name in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "privacy_badger_what_is": {
+ "message": "Privacy Badger 是什麼?",
+ "description": ""
+ },
+ "options_domain_search": {
+ "message": "搜尋網域:",
+ "description": "Label for a text input box on the Tracking Domains options page tab."
+ },
+ "options_learn_setting": {
+ "message": "了解如何透過您的瀏覽封鎖新的追蹤器",
+ "description": "Checkbox label on the general settings page"
+ },
+ "local_learning_warning": {
+ "message": "啟用學習可能會讓您更容易被網站識別",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_incognito_setting": {
+ "message": "在隱私/無痕視窗中學習",
+ "description": "Checkbox label on the general settings page"
+ },
+ "options_incognito_warning": {
+ "message": "在隱私/無痕視窗中啟用學習可能會導致隱私瀏覽紀錄留在您的電腦上。預設情況下,Privacy Badger 會在隱私/無痕視窗中阻擋任何已知的追蹤器,但是不會學習任何新的追蹤器。您可能會想要在您的瀏覽大部份都在隱私/無痕視窗中度過時啟用此選項。",
+ "description": "Tooltip on the general settings page"
+ },
+ "learning_prompt_text1": {
+ "message": "預設情況下,Privacy Badger 將不會再從您的瀏覽中學習。",
+ "description": "First part of a prompt to visit the blog."
+ },
+ "learning_prompt_text2": {
+ "message": "點擊下方以取得更多資訊。",
+ "description": "Second part of a prompt to visit the blog."
+ },
+ "learning_prompt_button": {
+ "message": "了解 Privacy Badger 如何變更",
+ "description": "Button text, part of a prompt to visit the blog."
+ },
+ "show_counter_checkbox": {
+ "message": "顯示追蹤器數量",
+ "description": "Checkbox label on the general settings page"
+ },
+ "what_is_a_tracker": {
+ "message": "什麼是追蹤器?",
+ "description": "Tooltip that comes up when you hover over the 'tracking domains' link under the Tracking Domains tab on the options page."
+ },
+ "intro_report_button": {
+ "message": "請不要忘記點按「回報 Privacy Badger 導致顯示異常的網站」。我們尊重您的隱私,所以我們不會自動傳送回報。",
+ "description": "Intro page paragraph. The quoted message ('Did Privacy Badger break this site') should match the first part of the translation for the 'report_broken_site' message."
+ },
+ "options_title": {
+ "message": "Privacy Badger 設定",
+ "description": ""
+ },
+ "report_terms": {
+ "message": "將會自動回報下列資訊給 EFF 電子前鋒基金會:您目前造訪的頁面、瀏覽器版本、Privacy Badger 版本,以及此頁面所有滾動條的狀態。",
+ "description": ""
+ },
+ "whitelisted_domains": {
+ "message": "停用的網站",
+ "description": "This is an options page tab heading."
+ },
+ "popup_enable_for_site": {
+ "message": "在目前網站開啟 Privacy Badger",
+ "description": ""
+ },
+ "options_domain_type_filter": {
+ "message": "以類型過濾:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "import_successful": {
+ "message": "追蹤器清單和設定更新成功!",
+ "description": ""
+ },
+ "export_user_data": {
+ "message": "匯出使用者資料",
+ "description": ""
+ },
+ "manage_data_intro": {
+ "message": "正在匯入使用者資料:<ul><li>覆寫一般設定</li><li>結合停用的網站清單</li><li>結合 Privacy Badger 已經看過哪些追蹤器的資訊</li><li>覆寫滑桿自訂</li></ul>",
+ "description": "A brief explanation of what happens when you import Badger user data. Shown above the import/export user data buttons under the Manage Data options page tab."
+ },
+ "reset": {
+ "message": "重設",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "reset_data": {
+ "message": "重設追蹤網域",
+ "description": "Caption above reset button"
+ },
+ "reset_data_confirm": {
+ "message": "重設追蹤網域將會:\n\n • 刪除所有 Privacy Badger 已從您的瀏覽中學習到的追蹤器\n • 將追蹤網域復原為最新的預訓練清單(請見 www.eff.org/badger-pretraining 以取得更多資訊)",
+ "description": "Pop-up triggered when the reset_data button is clicked"
+ },
+ "remove_all": {
+ "message": "移除全部",
+ "description": "Options page button, under the Manage Data tab"
+ },
+ "remove_all_data": {
+ "message": "移除所有追蹤網域",
+ "description": "Caption above remove_all button"
+ },
+ "remove_all_data_confirm": {
+ "message": "移除所有追蹤網域將會:\n\n • 刪除 Privacy Badger 知道的所有關於追蹤器的東西\n • 造成 Privacy Badger 在有機會重新自您的瀏覽中學習前無法阻擋任何東西",
+ "description": "Pop-up triggered when the remove_all_data button is clicked"
+ },
+ "intro_text1": {
+ "message": "Privacy Badger 正在保護您。",
+ "description": "First part of a reminder to visit the intro page. Shown in popup until the user clicks on the reminder link or browses through the intro page."
+ },
+ "intro_text2": {
+ "message": "若要了解 Privacy Badger 的運作原理,請點擊下方進行快速教學。",
+ "description": "Second part of a reminder to visit the intro page"
+ },
+ "options_webrtc_warning": {
+ "message": "WebRTC 可能會洩漏您的 IP 地址。注意:開啟此選項可能會造成 Google Hangouts 等網路會議應用程式的效能變差。",
+ "description": "Tooltip on the general settings page"
+ },
+ "options_general_settings": {
+ "message": "一般設定",
+ "description": "This is an options page tab heading."
+ },
+ "options_privacy_settings": {
+ "message": "隱私",
+ "description": "Subheading on the general settings options page."
+ },
+ "options_advanced_settings": {
+ "message": "進階",
+ "description": "Subheading on the general settings options page."
+ },
+ "intro_next_button": {
+ "message": "看看教學",
+ "description": "Intro page welcome button."
+ },
+ "domain_slider_block_tooltip": {
+ "message": "點按此處以完全阻擋此網域",
+ "description": "Tooltip shown when you hover over the leftmost part of a slider shown for each domain in the domain list."
+ },
+ "version": {
+ "message": "版本 $VERSION_STRING$",
+ "description": "Shows Privacy Badger's version in the popup. For example, \"version 2018.8.1\".",
+ "placeholders": {
+ "version_string": {
+ "content": "$1",
+ "example": "2018.8.1"
+ }
+ }
+ },
+ "badger_status_cookieblock": {
+ "message": "封鎖此網站的 cookie $DOMAIN$",
+ "description": "Tooltip shown when you hover over a domain name with a yellow slider in the list of domains in the popup or under the Tracking Domains tab on the options page.",
+ "placeholders": {
+ "domain": {
+ "content": "$1",
+ "example": "example.com"
+ }
+ }
+ },
+ "options_domain_filter_cookieblock": {
+ "message": "部份阻擋",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "show_tracking_domains_acknowledgement": {
+ "message": "我了解;無論如何都顯示追蹤網域清單給我",
+ "description": "Acknowledgement shown next to the checkbox required to reveal the tracking domains list on the options page."
+ },
+ "firstRun_title": {
+ "message": "感謝您安裝 Privacy Badger!",
+ "description": ""
+ },
+ "import_select_file": {
+ "message": "請選擇要匯入的檔案",
+ "description": ""
+ },
+ "report_broken_site": {
+ "message": "回報 Privacy Badger 導致顯示異常的網站",
+ "description": "Button in the popup."
+ },
+ "tooltip_cookieblock": {
+ "message": "將滾動條滑到中間封鎖該網域的 cookie",
+ "description": ""
+ },
+ "intro_learns": {
+ "message": "自動學習",
+ "description": "Intro page paragraph heading"
+ },
+ "intro_learns_paragraph": {
+ "message": "Privacy Badger 不會保留要封鎖的東西的清單,而是以追蹤器的行為當作基礎,自動探索要封鎖的追蹤器。",
+ "description": "Intro page paragraph"
+ },
+ "intro_beyond_ads": {
+ "message": "捕捉鬼鬼祟祟的追蹤器",
+ "description": "Intro page paragraph heading."
+ },
+ "intro_beyond_ads_paragraph": {
+ "message": "不可見的追蹤會以各種方式發生;廣告只是可見的冰山一角。Privacy Badger 傳送<a href='https://globalprivacycontrol.org/' target='_blank'>全域隱私控制訊號</a>,來讓您退出資料分享與販售,以及 <a href='https://www.eff.org/issues/do-not-track' target='_blank'>「Do Not Track」訊號</a>來告訴公司不要追蹤您。如果他們忽略了您的請求,Privacy Badger 將會學習封鎖它們,不論它們是廣告還是其他類型的追蹤器都一樣。",
+ "description": "Intro page paragraph."
+ },
+ "report_close": {
+ "message": "關閉",
+ "description": ""
+ },
+ "import_user_data": {
+ "message": "匯入使用者資料",
+ "description": ""
+ },
+ "options_domain_filter_dnt": {
+ "message": "相容於 DNT",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "popup_help_button": {
+ "message": "說明",
+ "description": "Tooltip that comes up when you hover over the question mark button in the upper right corner of the popup."
+ },
+ "options_domain_filter_allow": {
+ "message": "允許",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "intro_donate_heading": {
+ "message": "隱私是一場團隊比賽!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "show_tracking_domains_message": {
+ "message": "您應該不需要修改這裡的任何東西。",
+ "description": "Shown above the acknowledgement checkbox required to reveal the tracking domains list on the options page. This is the second paragraph; the first paragraph is the message under the \"intro_not_an_adblocker_paragraph\" key."
+ },
+ "options_domain_filter_all": {
+ "message": "全部",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "report_cancel": {
+ "message": "取消",
+ "description": ""
+ },
+ "tooltip_block": {
+ "message": "將滾動條滑到左邊封鎖該網域",
+ "description": ""
+ },
+ "options_enable_dnt_checkbox": {
+ "message": "傳送「<a href='https://globalprivacycontrol.org/' target='_blank'>全域隱私控制</a>」訊號與「<a href='https://www.eff.org/issues/do-not-track' target='_blank'>Do Not Track</a>」訊號給網頁",
+ "description": "Checkbox label for enabling/disabling the Sec-GPC and DNT signals, found on the general settings page"
+ },
+ "options_disable_google_nav_error_service": {
+ "message": "停用將您造訪的網址傳送給 Google 的功能。這會在找不到網頁時停用相似頁面的建議。",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_disable_hyperlink_auditing": {
+ "message": "停用超連結審核",
+ "description": "Checkbox label found on the general settings page"
+ },
+ "options_domain_filter_user": {
+ "message": "使用者控制",
+ "description": "Dropdown control setting on the Tracking Domains options page tab."
+ },
+ "disabled_for_these_domains": {
+ "message": "<p>Privacy Badger 已在下列的網站中停用。這代表了 Privacy Badger 將不會在您造訪在這裡列出來的網站時阻擋任何東西,其也將不會傳送「Do Not Track」或全域隱私控制訊號。</p><p>若您覺得 Privacy Badger 把頁面弄壞了,或您希望與特定的網站分享或販售您的資料,那麼您可以透過在下方的輸入框中輸入網域並點按「新增網域」按鈕來新增網域。</p><p>或者是當您已經選取了網頁的分頁,您也可以點選在瀏覽器工具列中的 Privacy Badger 按鈕並點選「停用」按鈕。</p>",
+ "description": ""
+ },
+ "popup_instructions": {
+ "message": "$COUNT$ 個潛在的 $LINK_START$追蹤器$LINK_END$ 已封鎖",
+ "description": "Popup message shown when at least one tracker was blocked.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_instructions_no_trackers": {
+ "message": "無 $LINK_START$追蹤器$LINK_END$ 被封鎖",
+ "description": "Text shown in the popup when there are no trackers on the page.",
+ "placeholders": {
+ "link_start": {
+ "content": "$1",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "popup_blocked": {
+ "message": "此頁面中沒有第三方資源。為隱私歡呼!",
+ "description": "Text shown in the popup when showing non-tracking domains is enabled, and there are no third-party domains on the page."
+ },
+ "intro_by_eff": {
+ "message": "EFF 電子前鋒基金會的專案",
+ "description": ""
+ },
+ "add_domain_button": {
+ "message": "新增網域",
+ "description": ""
+ },
+ "tooltip_allow": {
+ "message": "將滾動條滑到右邊允許該網域",
+ "description": ""
+ },
+ "popup_disable_for_site": {
+ "message": "在目前網站停用 Privacy Badger",
+ "description": "Button in the popup."
+ },
+ "domain_slider_allow_tooltip": {
+ "message": "點按此處以允許此網域",
+ "description": "Tooltip shown when you hover over the rightmost part of a slider shown for each domain in the domain list."
+ },
+ "intro_privacy_note": {
+ "message": "Privacy Badger 在您選擇分享關於您的瀏覽資料前,將永遠不會分享它們。",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_list_trackers": {
+ "message": "到目前為止,Privacy Badger 已決定封鎖 $COUNT$ 個潛在的 $TRACKER_LINK_START$追蹤網域$TRACKER_LINK_END$",
+ "description": "Shown on the Tracking Domains tab on the options page after Privacy Badger learned to block one or more domains",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "900"
+ },
+ "tracker_link_start": {
+ "content": "$2",
+ "example": "<a href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ },
+ "tracker_link_end": {
+ "content": "</a>"
+ }
+ }
+ },
+ "options_domain_list_no_trackers": {
+ "message": "Privacy Badger 未偵測到任何<a target='_blank' tabindex=-1 title='i18n_what_is_a_tracker' class='tooltip' href='https://www.eff.org/privacybadger#faq-What-is-a-third-party-tracker?'>追蹤網域</a>。繼續瀏覽!",
+ "description": "Shown on the Tracking Domains tab on the options page if all tracking domains have been removed."
+ },
+ "name": {
+ "message": "Privacy Badger",
+ "description": ""
+ },
+ "intro_not_an_adblocker_paragraph": {
+ "message": "Privacy Badger 將會在三個不同的網頁上發現同一個追蹤器時開始阻擋該追蹤器。三振出局!",
+ "description": "Intro page paragraph."
+ },
+ "options_domain_status_filter": {
+ "message": "以狀態過濾:",
+ "description": "Label for a dropdown control on the Tracking Domains options page tab."
+ },
+ "report_text": {
+ "message": "在下面簡要描述發生的錯誤。",
+ "description": ""
+ },
+ "remove_button": {
+ "message": "刪除所選",
+ "description": "This is the label for the 'Remove selected' buttons."
+ },
+ "intro_donate1": {
+ "message": "當您使用 Privacy Badger,您就會加入<a href='https://www.eff.org/' target='_blank'>電子前鋒基金會 (EFF)</a>與其他數百萬個使用者一同為隱私而戰。我們是一個為您的線上權利而戰的非營利組織。感謝您加入我們!",
+ "description": "Part of the 'donate' section on the intro page."
+ },
+ "options_domain_search_tooltip": {
+ "message": "要排除網域,請在您的搜尋字詞前加入\"-\"。舉例來說,\".co -.com\"將會顯示 .co 與 .co.uk 但不會有 .com 網域。",
+ "description": "Tooltip for an \"information\" icon next to the domain search input on the Tracking Domains options page tab."
+ },
+ "intro_disable_button": {
+ "message": "若您覺得 Privacy Badger 破壞了某個頁面(舉例來說,影片無法播放之類的),您可以點按「停用」按鈕來將 Privacy Badger 在該網站上關閉。",
+ "description": "Intro page paragraph. The quoted string ('Disable') should match the verb used for the 'popup_disable_for_site' message."
+ },
+ "intro_link_policy": {
+ "message": "隱私權政策",
+ "description": "Shown at the bottom of the intro page, links to the EFF software and technology projects privacy policy."
+ },
+ "report_input_label": {
+ "message": "描述",
+ "description": ""
+ },
+ "not_yet_blocked_header": {
+ "message": "您的 Badger 尚未決定這些網域是否應該要封鎖",
+ "description": "Popup domain list header text; separates blocked from haven't-yet-seen-enough-to-block potential trackers."
+ },
+ "options_show_not_yet_blocked": {
+ "message": "顯示您的 Badger 尚未決定是否要封鎖的網域:",
+ "description": "Label for a checkbox on the Tracking Domains options page tab. Should match wording used in the 'not_yet_blocked_header' message."
+ },
+ "non_tracker": {
+ "message": "以下網域看起來都沒有在追蹤您",
+ "description": "Header text; separates tracking from non-tracking domains in the popup."
+ },
+ "popup_options_button": {
+ "message": "選項",
+ "description": ""
+ },
+ "share_button_title_facebook": {
+ "message": "在 Facebook 上分享",
+ "description": "Text that comes up when you hover over the social sharing buttons on the intro page."
+ },
+ "description": {
+ "message": "Privacy Badger 會自動學習並阻擋不可見的追蹤器。",
+ "description": ""
+ },
+ "report_fail": {
+ "message": "哎呀。出錯了。",
+ "description": ""
+ },
+ "social_tooltip_pb_has_replaced": {
+ "message": "Privacy Badger 已經取代了 $BUTTON$ 按鈕",
+ "description": "Tooltip shown over a replaced social button. For example, \"Privacy Badger has replaced this Facebook Like button\". See also the widget_placeholder_pb_has_replaced message.",
+ "placeholders": {
+ "button": {
+ "content": "$1",
+ "example": "Facebook Like"
+ }
+ }
+ },
+ "widget_placeholder_pb_has_replaced": {
+ "message": "Privacy Badger 已經取代了 $WIDGET$ 小工具",
+ "description": "Text shown inside a replaced widget's placeholder. For example, \"Privacy Badger has replaced this Google reCAPTCHA widget\". See also the social_tooltip_pb_has_replaced message.",
+ "placeholders": {
+ "widget": {
+ "content": "$1",
+ "example": "Google reCAPTCHA"
+ }
+ }
+ },
+ "allow_once": {
+ "message": "允許一次",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking it will allow the third-party widget to load this one time only."
+ },
+ "allow_on_site": {
+ "message": "此網站上一律允許",
+ "description": "Button in the placeholder shown in place of certain third-party (video, audio, commenting) widgets. Clicking this button will always allow the widget to load on this particular site."
+ },
+ "sync_intro": {
+ "message": "雲端同步:<ul><li>需要 Firefox/Chrome 同步</li><li>上傳會覆寫任何在雲端中既有的 Privacy Badger 資料</li><li>下載會結合您的 Privacy Badger 停用的網站清單</li></ul>",
+ "description": "A brief explanation of how syncing works. Shown above the upload/download cloud data buttons under the Manage Data options page tab."
+ },
+ "upload": {
+ "message": "上傳",
+ "description": "Button label for uploading data to the cloud on Manage Data options page tab."
+ },
+ "upload_cloud": {
+ "message": "匯出停用的網站到雲端",
+ "description": "Button title for uploading data to the cloud on Manage Data options page tab."
+ },
+ "download_cloud": {
+ "message": "從雲端匯入停用的網站",
+ "description": "Button title for downloading data from the cloud on Manage Data options page tab."
+ },
+ "download_cloud_success": {
+ "message": "雲端資料匯入成功。",
+ "description": "Message displayed to the user after successfully merging cloud data."
+ },
+ "download_cloud_failure": {
+ "message": "雲端資料無法下載。",
+ "description": "Message displayed to the user after failing to download cloud data."
+ },
+ "upload_cloud_success": {
+ "message": "雲端資料上傳成功。",
+ "description": "Message displayed to the user after successfully uploading local data."
+ },
+ "upload_cloud_failure": {
+ "message": "雲端資料無法上傳。",
+ "description": "Message displayed to the user after failing to upload local data."
+ },
+ "download_cloud_no_data": {
+ "message": "沒有雲端資料可供下載。",
+ "description": "'Error' message when there is on cloud data to download."
+ },
+ "share_title": {
+ "message": "告訴你的朋友",
+ "description": "Title of the share overlay."
+ },
+ "popup_share_button": {
+ "message": "分享",
+ "description": "Tooltip that comes up when you hover over the share button in the upper right corner of the popup."
+ },
+ "share_tracker_header": {
+ "message": "Privacy Badger 封鎖了 $COUNT$ 潛在的追蹤器於 $DOMAIN$:",
+ "description": "Header above the list of tracking domains in the share message.",
+ "placeholders": {
+ "count": {
+ "content": "$1",
+ "example": "15"
+ },
+ "domain": {
+ "content": "$2",
+ "example": "example.com"
+ }
+ }
+ },
+ "share_base_message": {
+ "message": "Privacy Badger (www.eff.org/privacybadger) 是一個會自動學習阻擋不可見追蹤器的瀏覽器附加元件。Privacy Badger 由電子前鋒基金會製作,它是一個為您的線上權利戰鬥的非營利組織。",
+ "description": "The base message that is always included in the share message."
+ },
+ "copy_button_initial": {
+ "message": "複製到剪貼簿",
+ "description": "Initial text of the copy button on the share overlay."
+ },
+ "copy_button_copied": {
+ "message": "已複製",
+ "description": "On-click text of the copy button on the share overlay."
+ },
+ "popup_special_page_header": {
+ "message": "在此頁面上沒有事情可做",
+ "description": "Heading for popup_special_page_paragraph"
+ },
+ "popup_special_page_paragraph": {
+ "message": "Privacy Badger 在像這類的特殊頁面上無法運作。試著瀏覽其他的頁面看看。",
+ "description": "Shown in the popup for special browser pages such as the New Tab page and 'about:' pages."
+ },
+ "popup_disabled_site_header": {
+ "message": "Privacy Badger 已對此網站停用",
+ "description": "Shown in the popup on disabled sites."
+ },
+ "options_widget_replacement_tab": {
+ "message": "小工具取代",
+ "description": "Options page tab heading"
+ },
+ "options_widget_replacement_desc": {
+ "message": "當阻擋社群媒體按鈕與其他可能有用(影片、音訊、留言)的小工具時,Privacy Badger 可以使用點擊啟用的按鈕來取代它們。",
+ "description": "Introduction to the Widget Replacement tab on the options page."
+ }
+} \ No newline at end of file
diff --git a/src/data/dnt-policies.json b/src/data/dnt-policies.json
new file mode 100644
index 0000000..6e7ed13
--- /dev/null
+++ b/src/data/dnt-policies.json
@@ -0,0 +1,9 @@
+{
+ "Preliminary DNT Policy": "41ae62ddfee360fe1e0e7dbae0f35b2dc06212eb",
+ "Discussion Draft DNT Policy v0.1": "96297930e450cb795004ae5b1fcc88290a2fe982",
+ "Discussion Draft v0.2 in progress feb 2015": "76d89351d48f10c633fd1b5273587913f0851367",
+ "DNT Policy v1.0": "a18e8dba6848d3fc241b03b88291cb75a3cfec3b",
+ "DNT Policy v1.0 no-trailing-space": "5b8972a0e8df8236bb28061ddc462767d4366218",
+ "DNT Policy v1.0 dos-line-endings": "c09f71363bb29d0250a1f5524eef36f9ab07669b",
+ "DNT Policy v1.0 no-eof-newline": "7861462d500fbb6ccb74c614782f4937377bec76"
+}
diff --git a/src/data/dnt-policy.txt b/src/data/dnt-policy.txt
new file mode 100644
index 0000000..ad946d1
--- /dev/null
+++ b/src/data/dnt-policy.txt
@@ -0,0 +1,218 @@
+Do Not Track Compliance Policy
+
+Version 1.0
+
+This domain complies with user opt-outs from tracking via the "Do Not Track"
+or "DNT" header [http://www.w3.org/TR/tracking-dnt/]. This file will always
+be posted via HTTPS at https://example-domain.com/.well-known/dnt-policy.txt
+to indicate this fact.
+
+SCOPE
+
+This policy document allows an operator of a Fully Qualified Domain Name
+("domain") to declare that it respects Do Not Track as a meaningful privacy
+opt-out of tracking, so that privacy-protecting software can better determine
+whether to block or anonymize communications with this domain. This policy is
+intended first and foremost to be posted on domains that publish ads, widgets,
+images, scripts and other third-party embedded hypertext (for instance on
+widgets.example.com), but it can be posted on any domain, including those users
+visit directly (such as www.example.com). The policy may be applied to some
+domains used by a company, site, or service, and not to others. Do Not Track
+may be sent by any client that uses the HTTP protocol, including websites,
+mobile apps, and smart devices like TVs. Do Not Track also works with all
+protocols able to read HTTP headers, including SPDY.
+
+NOTE: This policy contains both Requirements and Exceptions. Where possible
+terms are defined in the text, but a few additional definitions are included
+at the end.
+
+REQUIREMENTS
+
+When this domain receives Web requests from a user who enables DNT by actively
+choosing an opt-out setting in their browser or by installing software that is
+primarily designed to protect privacy ("DNT User"), we will take the following
+measures with respect to those users' data, subject to the Exceptions, also
+listed below:
+
+1. END USER IDENTIFIERS:
+
+ a. If a DNT User has logged in to our service, all user identifiers, such as
+ unique or nearly unique cookies, "supercookies" and fingerprints are
+ discarded as soon as the HTTP(S) response is issued.
+
+ Data structures which associate user identifiers with accounts may be
+ employed to recognize logged in users per Exception 4 below, but may not
+ be associated with records of the user's activities unless otherwise
+ excepted.
+
+ b. If a DNT User is not logged in to our service, we will take steps to ensure
+ that no user identifiers are transmitted to us at all.
+
+2. LOG RETENTION:
+
+ a. Logs with DNT Users' identifiers removed (but including IP addresses and
+ User Agent strings) may be retained for a period of 10 days or less,
+ unless an Exception (below) applies. This period of time balances privacy
+ concerns with the need to ensure that log processing systems have time to
+ operate; that operations engineers have time to monitor and fix technical
+ and performance problems; and that security and data aggregation systems
+ have time to operate.
+
+ b. These logs will not be used for any other purposes.
+
+3. OTHER DOMAINS:
+
+ a. If this domain transfers identifiable user data about DNT Users to
+ contractors, affiliates or other parties, or embeds from or posts data to
+ other domains, we will either:
+
+ b. ensure that the operators of those domains abide by this policy overall
+ by posting it at /.well-known/dnt-policy.txt via HTTPS on the domains in
+ question,
+
+ OR
+
+ ensure that the recipient's policies and practices require the recipient
+ to respect the policy for our DNT Users' data.
+
+ OR
+
+ obtain a contractual commitment from the recipient to respect this policy
+ for our DNT Users' data.
+
+ NOTE: if an “Other Domain” does not receive identifiable user information
+ from the domain because such information has been removed, because the
+ Other Domain does not log that information, or for some other reason, these
+ requirements do not apply.
+
+ c. "Identifiable" means any records which are not Anonymized or otherwise
+ covered by the Exceptions below.
+
+4. PERIODIC REASSERTION OF COMPLIANCE:
+
+ At least once every 12 months, we will take reasonable steps commensurate
+ with the size of our organization and the nature of our service to confirm
+ our ongoing compliance with this document, and we will publicly reassert our
+ compliance.
+
+5. USER NOTIFICATION:
+
+ a. If we are required by law to retain or disclose user identifiers, we will
+ attempt to provide the users with notice (unless we are prohibited or it
+ would be futile) that a request for their information has been made in
+ order to give the users an opportunity to object to the retention or
+ disclosure.
+
+ b. We will attempt to provide this notice by email, if the users have given
+ us an email address, and by postal mail if the users have provided a
+ postal address.
+
+ c. If the users do not challenge the disclosure request, we may be legally
+ required to turn over their information.
+
+ d. We may delay notice if we, in good faith, believe that an emergency
+ involving danger of death or serious physical injury to any person
+ requires disclosure without delay of information relating to the
+ emergency.
+
+EXCEPTIONS
+
+Data from DNT Users collected by this domain may be logged or retained only in
+the following specific situations:
+
+1. CONSENT / "OPT BACK IN"
+
+ a. DNT Users are opting out from tracking across the Web. It is possible
+ that for some feature or functionality, we will need to ask a DNT User to
+ "opt back in" to be tracked by us across the entire Web.
+
+ b. If we do that, we will take reasonable steps to verify that the users who
+ select this option have genuinely intended to opt back in to tracking.
+ One way to do this is by performing scientifically reasonable user
+ studies with a representative sample of our users, but smaller
+ organizations can satisfy this requirement by other means.
+
+ c. Where we believe that we have opt back in consent, our server will
+ send a tracking value status header "Tk: C" as described in section 6.2
+ of the W3C Tracking Preference Expression draft:
+
+ http://www.w3.org/TR/tracking-dnt/#tracking-status-value
+
+2. TRANSACTIONS
+
+ If a DNT User actively and knowingly enters a transaction with our
+ services (for instance, clicking on a clearly-labeled advertisement,
+ posting content to a widget, or purchasing an item), we will retain
+ necessary data for as long as required to perform the transaction. This
+ may for example include keeping auditing information for clicks on
+ advertising links; keeping a copy of posted content and the name of the
+ posting user; keeping server-side session IDs to recognize logged in
+ users; or keeping a copy of the physical address to which a purchased
+ item will be shipped. By their nature, some transactions will require data
+ to be retained indefinitely.
+
+3. TECHNICAL AND SECURITY LOGGING:
+
+ a. If, during the processing of the initial request (for unique identifiers)
+ or during the subsequent 10 days (for IP addresses and User Agent strings),
+ we obtain specific information that causes our employees or systems to
+ believe that a request is, or is likely to be, part of a security attack,
+ spam submission, or fraudulent transaction, then logs of those requests
+ are not subject to this policy.
+
+ b. If we encounter technical problems with our site, then, in rare
+ circumstances, we may retain logs for longer than 10 days, if that is
+ necessary to diagnose and fix those problems, but this practice will not be
+ routinized and we will strive to delete such logs as soon as possible.
+
+4. AGGREGATION:
+
+ a. We may retain and share anonymized datasets, such as aggregate records of
+ readership patterns; statistical models of user behavior; graphs of system
+ variables; data structures to count active users on monthly or yearly
+ bases; database tables mapping authentication cookies to logged in
+ accounts; non-unique data structures constructed within browsers for tasks
+ such as ad frequency capping or conversion tracking; or logs with truncated
+ and/or encrypted IP addresses and simplified User Agent strings.
+
+ b. "Anonymized" means we have conducted risk mitigation to ensure
+ that the dataset, plus any additional information that is in our
+ possession or likely to be available to us, does not allow the
+ reconstruction of reading habits, online or offline activity of groups of
+ fewer than 5000 individuals or devices.
+
+ c. If we generate anonymized datasets under this exception we will publicly
+ document our anonymization methods in sufficient detail to allow outside
+ experts to evaluate the effectiveness of those methods.
+
+5. ERRORS:
+
+From time to time, there may be errors by which user data is temporarily
+logged or retained in violation of this policy. If such errors are
+inadvertent, rare, and made in good faith, they do not constitute a breach
+of this policy. We will delete such data as soon as practicable after we
+become aware of any error and take steps to ensure that it is deleted by any
+third-party who may have had access to the data.
+
+ADDITIONAL DEFINITIONS
+
+"Fully Qualified Domain Name" means a domain name that addresses a computer
+connected to the Internet. For instance, example1.com; www.example1.com;
+ads.example1.com; and widgets.example2.com are all distinct FQDNs.
+
+"Supercookie" means any technology other than an HTTP Cookie which can be used
+by a server to associate identifiers with the clients that visit it. Examples
+of supercookies include Flash LSO cookies, DOM storage, HTML5 storage, or
+tricks to store information in caches or etags.
+
+"Risk mitigation" means an engineering process that evaluates the possibility
+and likelihood of various adverse outcomes, considers the available methods of
+making those adverse outcomes less likely, and deploys sufficient mitigations
+to bring the probability and harm from adverse outcomes below an acceptable
+threshold.
+
+"Reading habits" includes amongst other things lists of visited DNS names, if
+those domains pertain to specific topics or activities, but records of visited
+DNS names are not reading habits if those domain names serve content of a very
+diverse and general nature, thereby revealing minimal information about the
+opinions, interests or activities of the user.
diff --git a/src/data/schema.json b/src/data/schema.json
new file mode 100644
index 0000000..b265b61
--- /dev/null
+++ b/src/data/schema.json
@@ -0,0 +1,48 @@
+{
+ "type": "object",
+ "properties": {
+ "checkForDNTPolicy": {
+ "title": "Check if third-parties comply with EFF's DNT policy",
+ "description": "If set to false then do not query third-party domains for declared compliance with EFF's Do Not Track policy.",
+ "type": "boolean"
+ },
+ "disabledSites": {
+ "title": "Disabled sites",
+ "description": "List of site domains where Privacy Badger is disabled.",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "learnLocally": {
+ "title": "Learn to block new trackers from your browsing",
+ "description": "Enabling learning may make you more identifiable to websites. Please see https://www.eff.org/badger-evolution for more information.",
+ "type": "boolean"
+ },
+ "learnInIncognito": {
+ "title": "Learn in Private/Incognito windows",
+ "description": "Enabling learning in Private/Incognito windows may leave traces of your private browsing history on your computer. By default, Privacy Badger will block trackers it already knows about in Private/Incognito windows, but it won't learn about new trackers. You might want to enable this option if a lot of your browsing happens in Private/Incognito windows.",
+ "type": "boolean"
+ },
+ "sendDNTSignal": {
+ "title": "Send websites the Do Not Track signal",
+ "description": "Toggles sending the DNT header and setting navigator.doNotTrack on websites.",
+ "type": "boolean"
+ },
+ "showCounter": {
+ "title": "Show count of blocked items",
+ "description": "Toggles showing the counter over Privacy Badger's button in the browser toolbar.",
+ "type": "boolean"
+ },
+ "showIntroPage": {
+ "title": "Show intro page",
+ "description": "If set to false then do not open the new user intro page upon install.",
+ "type": "boolean"
+ },
+ "socialWidgetReplacementEnabled": {
+ "title": "Replace social widgets",
+ "description": "Toggles social widget replacement.",
+ "type": "boolean"
+ }
+ }
+}
diff --git a/src/data/seed.json b/src/data/seed.json
new file mode 100644
index 0000000..42fc36f
--- /dev/null
+++ b/src/data/seed.json
@@ -0,0 +1,19505 @@
+{
+ "action_map": {
+ "008-jlc-434.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602149702509
+ },
+ "017-dvc-111.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602160757426
+ },
+ "01net.com": {
+ "heuristicAction": "allow"
+ },
+ "067-umd-991.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602330684483
+ },
+ "0914.global.ssl.fastly.net": {
+ "heuristicAction": "allow"
+ },
+ "100008946.collect.igodigital.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601989505746
+ },
+ "1001.netrk.net": {
+ "heuristicAction": "allow"
+ },
+ "10014956.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602015754030
+ },
+ "10088969.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601907792167
+ },
+ "100widgets.com": {
+ "heuristicAction": "allow"
+ },
+ "10176687.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602024707132
+ },
+ "10190460.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602052259567
+ },
+ "10192984.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602166739691
+ },
+ "10214854.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602197720890
+ },
+ "10233691.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602052712508
+ },
+ "10259902.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602059721131
+ },
+ "10270662.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602346686015
+ },
+ "107-fms-070.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602124849160
+ },
+ "10870841.collect.igodigital.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602076836260
+ },
+ "10hui.es": {
+ "heuristicAction": "allow"
+ },
+ "110.93.143.144": {
+ "heuristicAction": "allow"
+ },
+ "11183.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "11186.global.siteimproveanalytics.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602250469591
+ },
+ "112.2o7.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "120askimages.com": {
+ "heuristicAction": "allow"
+ },
+ "122.2o7.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "123apps.com": {
+ "heuristicAction": "allow"
+ },
+ "126.net": {
+ "heuristicAction": "allow"
+ },
+ "1361549.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602355502897
+ },
+ "140cc.v.fwmrm.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "14108.global.siteimproveanalytics.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602275317686
+ },
+ "163.com": {
+ "heuristicAction": "allow"
+ },
+ "172-qer-842.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602301651252
+ },
+ "17620.global.siteimproveanalytics.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602385615672
+ },
+ "178-uxe-734.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602250689044
+ },
+ "180-pay-466.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601903596238
+ },
+ "1dmp.io": {
+ "heuristicAction": "block"
+ },
+ "20726339p.rfihub.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602380586214
+ },
+ "20790133p.rfihub.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602268247489
+ },
+ "20824283p.rfihub.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602013061513
+ },
+ "2315.oadz.com": {
+ "heuristicAction": "allow"
+ },
+ "247-inc.net": {
+ "heuristicAction": "block"
+ },
+ "24smi.net": {
+ "heuristicAction": "allow"
+ },
+ "26434.global.siteimproveanalytics.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601975541289
+ },
+ "2988354.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601882902532
+ },
+ "2checkout.com": {
+ "heuristicAction": "allow"
+ },
+ "2o7.net": {
+ "heuristicAction": "block"
+ },
+ "2t23.net": {
+ "heuristicAction": "allow"
+ },
+ "3071236.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602224215187
+ },
+ "315-ftt-121.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602374155829
+ },
+ "316-gsv-089.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602152384258
+ },
+ "320-chp-056.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602398839433
+ },
+ "3281045.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602293457750
+ },
+ "329-zem-341.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602214859996
+ },
+ "33across.com": {
+ "heuristicAction": "block"
+ },
+ "3573159.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602124529455
+ },
+ "358-ejs-102.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602040460457
+ },
+ "360-xjz-500.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601912496651
+ },
+ "360.cn": {
+ "heuristicAction": "block"
+ },
+ "360yield.com": {
+ "heuristicAction": "block"
+ },
+ "3668425.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601950532846
+ },
+ "367-mrv-360.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602149618905
+ },
+ "3810813.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602235841060
+ },
+ "3864313.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602087650625
+ },
+ "3conline.com": {
+ "heuristicAction": "block"
+ },
+ "3ds.com": {
+ "heuristicAction": "allow"
+ },
+ "3gl.net": {
+ "heuristicAction": "block"
+ },
+ "3lift.com": {
+ "heuristicAction": "block"
+ },
+ "406-iur-638.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601980754875
+ },
+ "40nuggets.com": {
+ "heuristicAction": "allow"
+ },
+ "4234560.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601975178749
+ },
+ "4248738.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601893149252
+ },
+ "4338867.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602114796555
+ },
+ "4389858.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602149801047
+ },
+ "4394967.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602187406773
+ },
+ "4480363.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602019710952
+ },
+ "4599337.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602288870993
+ },
+ "4765202.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602026229016
+ },
+ "4934753.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602058653506
+ },
+ "4968275.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602249574231
+ },
+ "4dex.io": {
+ "heuristicAction": "block"
+ },
+ "4paradigm.com": {
+ "heuristicAction": "allow"
+ },
+ "4pda.to": {
+ "heuristicAction": "allow"
+ },
+ "4strokemedia.com": {
+ "heuristicAction": "allow"
+ },
+ "50bang.org": {
+ "heuristicAction": "block"
+ },
+ "51.la": {
+ "heuristicAction": "block"
+ },
+ "5165113.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601918619303
+ },
+ "5219529.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602269417704
+ },
+ "5322751.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601940717356
+ },
+ "53kf.com": {
+ "heuristicAction": "allow"
+ },
+ "5490350.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602020056441
+ },
+ "5617400.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602230121505
+ },
+ "564-vfr-008.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602119698899
+ },
+ "58.com": {
+ "heuristicAction": "allow"
+ },
+ "58.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "5865816.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602253920458
+ },
+ "58cdn.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "58che.com": {
+ "heuristicAction": "allow"
+ },
+ "6019066.global.siteimproveanalytics.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602139271771
+ },
+ "6027462.global.siteimproveanalytics.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602152296091
+ },
+ "6034097.global.siteimproveanalytics.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602333530601
+ },
+ "6097260.global.siteimproveanalytics.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602034555469
+ },
+ "6231350.global.siteimproveanalytics.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602319648057
+ },
+ "6254122.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602137743743
+ },
+ "6266241.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602021900067
+ },
+ "638-hhz-510.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602324515078
+ },
+ "6417561.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601985457352
+ },
+ "650-kge-239.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602084388732
+ },
+ "653-smc-783.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601979896861
+ },
+ "6564653.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602044654233
+ },
+ "66356256.global.siteimproveanalytics.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601899997191
+ },
+ "66357621.global.siteimproveanalytics.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601884660235
+ },
+ "66357691.global.siteimproveanalytics.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602156123863
+ },
+ "66357711.global.siteimproveanalytics.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602222197777
+ },
+ "6812680.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602250693884
+ },
+ "6noy.net": {
+ "heuristicAction": "allow"
+ },
+ "6sc.co": {
+ "heuristicAction": "block"
+ },
+ "706-yia-261.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602295888522
+ },
+ "71360.com": {
+ "heuristicAction": "allow"
+ },
+ "715-yzo-232.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602283385759
+ },
+ "7217216.collect.igodigital.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601882948730
+ },
+ "7324166.collect.igodigital.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602209477442
+ },
+ "745-buq-779.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602351977279
+ },
+ "75536.global.siteimproveanalytics.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602116595842
+ },
+ "768-oqw-145.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602381617080
+ },
+ "7eer.net": {
+ "heuristicAction": "block"
+ },
+ "7gra.us": {
+ "heuristicAction": "allow"
+ },
+ "7nwhwds3ex7vjw54abqzb2u3nxyqh6543r2tktmbcada04fd8200f860sac.d.aa.online-metrix.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601906736341
+ },
+ "7xbid.com": {
+ "heuristicAction": "allow"
+ },
+ "8034948.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602349213523
+ },
+ "805-kok-719.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602060502665
+ },
+ "8133010.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601967837951
+ },
+ "81956.global.siteimproveanalytics.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601935447862
+ },
+ "8324482.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602249390225
+ },
+ "8371571.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602272284955
+ },
+ "8379289.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601993766721
+ },
+ "8463383.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601893919453
+ },
+ "8464365.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601918124761
+ },
+ "8496125.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602352685872
+ },
+ "850-zwr-066.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602361665675
+ },
+ "855-qah-699.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602292968596
+ },
+ "8555493.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602297374703
+ },
+ "8666708.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601988700694
+ },
+ "867-pkr-571.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602364740987
+ },
+ "8704383.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602163924057
+ },
+ "8832015.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602233311813
+ },
+ "88721.global.siteimproveanalytics.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601981538168
+ },
+ "893-qif-790.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601961058405
+ },
+ "896-pbj-036.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602262838874
+ },
+ "8v4lqg.net": {
+ "heuristicAction": "allow"
+ },
+ "9.global.siteimproveanalytics.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601948736260
+ },
+ "9200540.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602153371559
+ },
+ "9277599.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602247449028
+ },
+ "942-mym-356.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601936104157
+ },
+ "9446450.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602002577445
+ },
+ "9499947.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602302965497
+ },
+ "9535906.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601880023391
+ },
+ "9591937.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602275502932
+ },
+ "9774013.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602101126331
+ },
+ "9786142.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602099310665
+ },
+ "983-kvh-814.mktoresp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602350102119
+ },
+ "9838407.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602348228862
+ },
+ "9920620.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602000601439
+ },
+ "9949476.fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602351250829
+ },
+ "a-mo.net": {
+ "heuristicAction": "block"
+ },
+ "a.adroll.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602332774637
+ },
+ "a.centrum.cz": {
+ "heuristicAction": "allow"
+ },
+ "a.exdynsrv.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601882457106
+ },
+ "a.o333o.com": {
+ "heuristicAction": "allow"
+ },
+ "a.pgtb.me": {
+ "heuristicAction": "allow"
+ },
+ "a.pub.network": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602275227626
+ },
+ "a.quora.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602377293204
+ },
+ "a.realsrv.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602229106916
+ },
+ "a.teads.tv": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602232486838
+ },
+ "a.wishabi.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "a2.adform.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601928954271
+ },
+ "aa.agkn.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602048297215
+ },
+ "aafp.net": {
+ "heuristicAction": "allow"
+ },
+ "aamcf.aamsitecertifier.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601880349664
+ },
+ "aamcftag.aamsitecertifier.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602116239808
+ },
+ "aamsitecertifier.com": {
+ "heuristicAction": "block"
+ },
+ "aan.com": {
+ "heuristicAction": "allow"
+ },
+ "aasaam.com": {
+ "heuristicAction": "block"
+ },
+ "aau-search-web-prod.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "aau-search-webservice-v1-prod.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "aax-eu.amazon-adsystem.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602303655288
+ },
+ "aax-fe.amazon-adsystem.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602244910440
+ },
+ "aaxads.com": {
+ "heuristicAction": "block"
+ },
+ "about.co.kr": {
+ "heuristicAction": "allow"
+ },
+ "abtasty.com": {
+ "heuristicAction": "allow"
+ },
+ "abtshield.com": {
+ "heuristicAction": "allow"
+ },
+ "acast.cloud": {
+ "heuristicAction": "allow"
+ },
+ "acast.com": {
+ "heuristicAction": "allow"
+ },
+ "accesstrade.net": {
+ "heuristicAction": "allow"
+ },
+ "accorhotels.com": {
+ "heuristicAction": "allow"
+ },
+ "accorhotels.ws": {
+ "heuristicAction": "allow"
+ },
+ "account.berush.com": {
+ "heuristicAction": "allow"
+ },
+ "accounts.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "accu-web-raine.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "acdn.adnxs.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602136078728
+ },
+ "ace-sync.toast.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602166272069
+ },
+ "acint.net": {
+ "heuristicAction": "allow"
+ },
+ "acpm.fr": {
+ "heuristicAction": "block"
+ },
+ "acquia.com": {
+ "heuristicAction": "block"
+ },
+ "acstat.com": {
+ "heuristicAction": "allow"
+ },
+ "action.media6degrees.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602231039734
+ },
+ "actionnetwork.org": {
+ "heuristicAction": "allow"
+ },
+ "activecalendar.com": {
+ "heuristicAction": "allow"
+ },
+ "activehosted.com": {
+ "heuristicAction": "block"
+ },
+ "activetrail.com": {
+ "heuristicAction": "allow"
+ },
+ "acuityplatform.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602241789938
+ },
+ "acyzh.com": {
+ "heuristicAction": "allow"
+ },
+ "ad-cdn.technoratimedia.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601889638410
+ },
+ "ad-lancers.jp": {
+ "heuristicAction": "allow"
+ },
+ "ad-plus.cn": {
+ "heuristicAction": "allow"
+ },
+ "ad-score.com": {
+ "heuristicAction": "block"
+ },
+ "ad-srv.net": {
+ "heuristicAction": "allow"
+ },
+ "ad-stir.com": {
+ "heuristicAction": "block"
+ },
+ "ad-survey.com": {
+ "heuristicAction": "allow"
+ },
+ "ad-track.jp": {
+ "heuristicAction": "allow"
+ },
+ "ad.crwdcntrl.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601976893526
+ },
+ "ad.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602154976198
+ },
+ "ad.gt": {
+ "heuristicAction": "block"
+ },
+ "ad.lkqd.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601982456143
+ },
+ "ad.org.vn": {
+ "heuristicAction": "allow"
+ },
+ "ad1x.com": {
+ "heuristicAction": "allow"
+ },
+ "adalliance.io": {
+ "heuristicAction": "block"
+ },
+ "adalyser.com": {
+ "heuristicAction": "block"
+ },
+ "adaptiveads.com": {
+ "heuristicAction": "allow"
+ },
+ "adaraanalytics.com": {
+ "heuristicAction": "allow"
+ },
+ "adbinead.com": {
+ "heuristicAction": "allow"
+ },
+ "adbox.lv": {
+ "heuristicAction": "allow"
+ },
+ "adcampo.com": {
+ "heuristicAction": "allow"
+ },
+ "adda247.in": {
+ "heuristicAction": "allow"
+ },
+ "addevent.com": {
+ "heuristicAction": "allow"
+ },
+ "addthis.com": {
+ "heuristicAction": "block"
+ },
+ "adentifi.com": {
+ "heuristicAction": "block"
+ },
+ "adform.net": {
+ "heuristicAction": "block"
+ },
+ "adfox.ru": {
+ "heuristicAction": "block"
+ },
+ "adgeek.net": {
+ "heuristicAction": "allow"
+ },
+ "adhaven.com": {
+ "heuristicAction": "allow"
+ },
+ "adhigh.net": {
+ "heuristicAction": "block"
+ },
+ "adinc.kr": {
+ "heuristicAction": "allow"
+ },
+ "adingo.jp": {
+ "heuristicAction": "allow"
+ },
+ "adition.com": {
+ "heuristicAction": "block"
+ },
+ "adjetter.com": {
+ "heuristicAction": "allow"
+ },
+ "adkernel.com": {
+ "heuristicAction": "block"
+ },
+ "adlmerge.com": {
+ "heuristicAction": "allow"
+ },
+ "adm.fwmrm.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "adman.gr": {
+ "heuristicAction": "block"
+ },
+ "admaster.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "admatic.com.tr": {
+ "heuristicAction": "allow"
+ },
+ "admatrix.jp": {
+ "heuristicAction": "allow"
+ },
+ "admedia.com": {
+ "heuristicAction": "allow"
+ },
+ "admedo.com": {
+ "heuristicAction": "block"
+ },
+ "admetrica.ru": {
+ "heuristicAction": "block"
+ },
+ "admicro.vn": {
+ "heuristicAction": "block"
+ },
+ "admission.net": {
+ "heuristicAction": "allow"
+ },
+ "admithub.com": {
+ "heuristicAction": "allow"
+ },
+ "admixer.net": {
+ "heuristicAction": "block"
+ },
+ "admost.com": {
+ "heuristicAction": "block"
+ },
+ "adnuntius.com": {
+ "heuristicAction": "block"
+ },
+ "adnxs.com": {
+ "heuristicAction": "block"
+ },
+ "adnz.co": {
+ "heuristicAction": "allow"
+ },
+ "adobe.com": {
+ "heuristicAction": "block"
+ },
+ "adobecqms.net": {
+ "heuristicAction": "allow"
+ },
+ "adocean.pl": {
+ "heuristicAction": "block"
+ },
+ "adop.cc": {
+ "heuristicAction": "block"
+ },
+ "adotmob.com": {
+ "heuristicAction": "block"
+ },
+ "adpnut.com": {
+ "heuristicAction": "allow"
+ },
+ "adpushup.com": {
+ "heuristicAction": "block"
+ },
+ "adpxl.co": {
+ "heuristicAction": "allow"
+ },
+ "adrecover.com": {
+ "heuristicAction": "allow"
+ },
+ "adriver.ru": {
+ "heuristicAction": "block"
+ },
+ "adroll.com": {
+ "heuristicAction": "block"
+ },
+ "adrta.com": {
+ "heuristicAction": "block"
+ },
+ "ads.exoclick.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602011200868
+ },
+ "ads.exosrv.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602157893909
+ },
+ "ads.pubmatic.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602024130584
+ },
+ "ads.realsrv.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602271837180
+ },
+ "ads.rubiconproject.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602316976938
+ },
+ "ads.undertone.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602014150970
+ },
+ "ads.yieldmo.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602138201841
+ },
+ "adsafeprotected.com": {
+ "heuristicAction": "allow"
+ },
+ "adscale.de": {
+ "heuristicAction": "block"
+ },
+ "adschoom.com": {
+ "heuristicAction": "allow"
+ },
+ "adscience.nl": {
+ "heuristicAction": "allow"
+ },
+ "adsco.re": {
+ "heuristicAction": "allow"
+ },
+ "adserver-us.adtech.advertising.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602059968709
+ },
+ "adserver.mk": {
+ "heuristicAction": "allow"
+ },
+ "adservice.google.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602096281580
+ },
+ "adservices.brandcdn.com": {
+ "heuristicAction": "allow"
+ },
+ "adsfactor.net": {
+ "heuristicAction": "allow"
+ },
+ "adskeeper.co.uk": {
+ "heuristicAction": "block"
+ },
+ "adskeeper.com": {
+ "heuristicAction": "allow"
+ },
+ "adsniper.ru": {
+ "heuristicAction": "allow"
+ },
+ "adspsp.com": {
+ "heuristicAction": "allow"
+ },
+ "adsrv.io": {
+ "heuristicAction": "allow"
+ },
+ "adsrvr.org": {
+ "heuristicAction": "block"
+ },
+ "adswizz.com": {
+ "heuristicAction": "block"
+ },
+ "adsymptotic.com": {
+ "heuristicAction": "block"
+ },
+ "adtarget.com.tr": {
+ "heuristicAction": "block"
+ },
+ "adtdp.com": {
+ "heuristicAction": "block"
+ },
+ "adtelli.com": {
+ "heuristicAction": "allow"
+ },
+ "adtelligent.com": {
+ "heuristicAction": "block"
+ },
+ "adtimaserver.vn": {
+ "heuristicAction": "block"
+ },
+ "adtlgc.com": {
+ "heuristicAction": "allow"
+ },
+ "adtng.com": {
+ "heuristicAction": "block"
+ },
+ "adtodate.net": {
+ "heuristicAction": "allow"
+ },
+ "adtrue.com": {
+ "heuristicAction": "block"
+ },
+ "adup-tech.com": {
+ "heuristicAction": "allow"
+ },
+ "advanced-web-analytics.com": {
+ "heuristicAction": "allow"
+ },
+ "advangelists.com": {
+ "heuristicAction": "block"
+ },
+ "advertising.com": {
+ "heuristicAction": "block"
+ },
+ "advertserve.com": {
+ "heuristicAction": "allow"
+ },
+ "advg.jp": {
+ "heuristicAction": "block"
+ },
+ "advividnetwork.com": {
+ "heuristicAction": "block"
+ },
+ "advsnx.net": {
+ "heuristicAction": "allow"
+ },
+ "adweb.co.kr": {
+ "heuristicAction": "allow"
+ },
+ "adwstats.com": {
+ "heuristicAction": "allow"
+ },
+ "adx.adform.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602260040187
+ },
+ "adxadserv.com": {
+ "heuristicAction": "allow"
+ },
+ "adxvip.com": {
+ "heuristicAction": "allow"
+ },
+ "adyen.com": {
+ "heuristicAction": "allow"
+ },
+ "adzerk.net": {
+ "heuristicAction": "block"
+ },
+ "aegis.qq.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602044921410
+ },
+ "aetn.com": {
+ "heuristicAction": "allow"
+ },
+ "aetnd.com": {
+ "heuristicAction": "allow"
+ },
+ "af-110.com": {
+ "heuristicAction": "allow"
+ },
+ "af-web-cms-0-prod.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "affec.tv": {
+ "heuristicAction": "allow"
+ },
+ "affirm.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "afftrack.pro": {
+ "heuristicAction": "allow"
+ },
+ "aftonbladet.se": {
+ "heuristicAction": "allow"
+ },
+ "agenziaentrate.it": {
+ "heuristicAction": "allow"
+ },
+ "agilemeasure.com": {
+ "heuristicAction": "allow"
+ },
+ "agilone.com": {
+ "heuristicAction": "allow"
+ },
+ "agkn.com": {
+ "heuristicAction": "block"
+ },
+ "agoda.net": {
+ "heuristicAction": "allow"
+ },
+ "agora.pl": {
+ "heuristicAction": "allow"
+ },
+ "ahighapi.com": {
+ "heuristicAction": "allow"
+ },
+ "aidata.io": {
+ "heuristicAction": "block"
+ },
+ "aihelp.net": {
+ "heuristicAction": "allow"
+ },
+ "aimediagroup.com": {
+ "heuristicAction": "block"
+ },
+ "aio.media": {
+ "heuristicAction": "allow"
+ },
+ "aiproxies.com": {
+ "heuristicAction": "block"
+ },
+ "airpr.com": {
+ "heuristicAction": "block"
+ },
+ "aismo.ru": {
+ "heuristicAction": "allow"
+ },
+ "aj1015.online": {
+ "heuristicAction": "allow"
+ },
+ "aj1431.online": {
+ "heuristicAction": "allow"
+ },
+ "aj2031.online": {
+ "heuristicAction": "allow"
+ },
+ "aj2208.online": {
+ "heuristicAction": "allow"
+ },
+ "ajax.googleapis.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "akamaihd.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "akamaized.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "akstat.io": {
+ "heuristicAction": "allow"
+ },
+ "alb.reddit.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "albacross.com": {
+ "heuristicAction": "block"
+ },
+ "alcmpn.com": {
+ "heuristicAction": "block"
+ },
+ "alexametrics.com": {
+ "heuristicAction": "block"
+ },
+ "alfasense.com": {
+ "heuristicAction": "block"
+ },
+ "aliapp.org": {
+ "heuristicAction": "allow"
+ },
+ "alibaba.com": {
+ "heuristicAction": "block"
+ },
+ "alicdn.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "aliexpress.com": {
+ "heuristicAction": "allow"
+ },
+ "alifafdlnjeruif.com": {
+ "heuristicAction": "allow"
+ },
+ "alipay.com": {
+ "heuristicAction": "allow"
+ },
+ "aliyun.com": {
+ "heuristicAction": "block"
+ },
+ "aliyuncs.com": {
+ "heuristicAction": "allow"
+ },
+ "all-cod.com": {
+ "heuristicAction": "allow"
+ },
+ "allure.com": {
+ "heuristicAction": "block"
+ },
+ "almamedia.fi": {
+ "heuristicAction": "allow"
+ },
+ "alocdn.com": {
+ "heuristicAction": "block"
+ },
+ "alphonso.tv": {
+ "heuristicAction": "allow"
+ },
+ "alsa.org": {
+ "heuristicAction": "allow"
+ },
+ "alwasela.com": {
+ "heuristicAction": "allow"
+ },
+ "am15.net": {
+ "heuristicAction": "allow"
+ },
+ "amap.com": {
+ "heuristicAction": "block"
+ },
+ "amazon-adsystem.com": {
+ "heuristicAction": "block"
+ },
+ "amazon.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "amazonaws.com": {
+ "heuristicAction": "allow"
+ },
+ "amazoncustomerservice.d2.sc.omtrdc.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "amazonwebservices.d2.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602353927309
+ },
+ "amazonwebservicesinc.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601904603488
+ },
+ "amcdn.vn": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602189818063
+ },
+ "ameba.jp": {
+ "heuristicAction": "allow"
+ },
+ "amnet.tw": {
+ "heuristicAction": "allow"
+ },
+ "amplify.outbrain.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602163387484
+ },
+ "amplifypixel.outbrain.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602336500276
+ },
+ "amunx.de": {
+ "heuristicAction": "allow"
+ },
+ "an.facebook.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602383201434
+ },
+ "an.yandex.ru": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602217661472
+ },
+ "analytics-egain.com": {
+ "heuristicAction": "block"
+ },
+ "analytics-sm.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602273074367
+ },
+ "analytics.aasaam.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602229451869
+ },
+ "analytics.contentexchange.me": {
+ "heuristicAction": "block"
+ },
+ "analytics.google.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602050172332
+ },
+ "analytics.prod.jpp.cnyes.cool": {
+ "heuristicAction": "allow"
+ },
+ "analytics.vodgc.net": {
+ "heuristicAction": "allow"
+ },
+ "anandabazar.com": {
+ "heuristicAction": "allow"
+ },
+ "and.co.uk": {
+ "heuristicAction": "allow"
+ },
+ "andertoons.com": {
+ "heuristicAction": "allow"
+ },
+ "aniview.com": {
+ "heuristicAction": "block"
+ },
+ "anm.co.uk": {
+ "heuristicAction": "allow"
+ },
+ "anquan.org": {
+ "heuristicAction": "block"
+ },
+ "ansira.com": {
+ "heuristicAction": "allow"
+ },
+ "answerscloud.com": {
+ "heuristicAction": "allow"
+ },
+ "anura.io": {
+ "heuristicAction": "allow"
+ },
+ "anvato.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "anyclip.com": {
+ "heuristicAction": "allow"
+ },
+ "anz.com": {
+ "heuristicAction": "allow"
+ },
+ "ap.lijit.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601949385805
+ },
+ "aparat.com": {
+ "heuristicAction": "block"
+ },
+ "apeartalb.site": {
+ "heuristicAction": "allow"
+ },
+ "apester.com": {
+ "heuristicAction": "block"
+ },
+ "apex.go.sonobi.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601985122364
+ },
+ "api-maps.yandex.ru": {
+ "heuristicAction": "cookieblock"
+ },
+ "api.adsymptotic.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601902177122
+ },
+ "api.aws.parking.godaddy.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602110820606
+ },
+ "api.clerk.io": {
+ "heuristicAction": "allow"
+ },
+ "api.company-target.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602116268703
+ },
+ "api.connecto.io": {
+ "heuristicAction": "allow"
+ },
+ "api.flocktory.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602334865404
+ },
+ "api.growingio.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602134271770
+ },
+ "api.hubspot.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "api.ipgeolocation.io": {
+ "heuristicAction": "allow"
+ },
+ "api.livechatinc.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "api.look.360.cn": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602249379189
+ },
+ "api.map.baidu.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "api.nanigans.com": {
+ "heuristicAction": "allow"
+ },
+ "api.parking.godaddy.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602389760124
+ },
+ "api.parsely.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602263472144
+ },
+ "api.popin.cc": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602358565468
+ },
+ "api.rec-engine.com": {
+ "heuristicAction": "allow"
+ },
+ "api.rlcdn.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601933549471
+ },
+ "api.soundcloud.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "api.tw.weibo.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601971482641
+ },
+ "api.viafoura.co": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602039952667
+ },
+ "api3847.d41.co": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601942740723
+ },
+ "api4773.d41.co": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602104337602
+ },
+ "apihotels.net": {
+ "heuristicAction": "allow"
+ },
+ "apis.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "apollo.miniclip.com": {
+ "heuristicAction": "allow"
+ },
+ "app-script.monsido.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601909505904
+ },
+ "app-us1.com": {
+ "heuristicAction": "block"
+ },
+ "app.hubspot.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "app.link": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602015382068
+ },
+ "app.usercentrics.eu": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602016595116
+ },
+ "apparmor.com": {
+ "heuristicAction": "block"
+ },
+ "appconsent.io": {
+ "heuristicAction": "block"
+ },
+ "appdynamics.com": {
+ "heuristicAction": "block"
+ },
+ "appier.net": {
+ "heuristicAction": "block"
+ },
+ "apple.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "appmifile.com": {
+ "heuristicAction": "allow"
+ },
+ "apps.elfsight.com": {
+ "heuristicAction": "allow"
+ },
+ "appsflyer.com": {
+ "heuristicAction": "block"
+ },
+ "apvdr.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601949486273
+ },
+ "aqyzmedia.yunaq.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602266570665
+ },
+ "aralego.com": {
+ "heuristicAction": "block"
+ },
+ "arc.io": {
+ "heuristicAction": "allow"
+ },
+ "architecturaldigest.com": {
+ "heuristicAction": "block"
+ },
+ "ard.de": {
+ "heuristicAction": "allow"
+ },
+ "arrivalist.com": {
+ "heuristicAction": "allow"
+ },
+ "arte.tv": {
+ "heuristicAction": "allow"
+ },
+ "artipbox.net": {
+ "heuristicAction": "allow"
+ },
+ "aruba.it": {
+ "heuristicAction": "allow"
+ },
+ "as-sec.casalemedia.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602276547266
+ },
+ "as.com": {
+ "heuristicAction": "allow"
+ },
+ "asadcdn.com": {
+ "heuristicAction": "block"
+ },
+ "asapp.com": {
+ "heuristicAction": "block"
+ },
+ "ascap.com": {
+ "heuristicAction": "allow"
+ },
+ "ascendeum-d.openx.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602318370598
+ },
+ "ascpqnj-oam.global.ssl.fastly.net": {
+ "heuristicAction": "allow"
+ },
+ "asia.creativecdn.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601955971649
+ },
+ "asianmedia.com": {
+ "heuristicAction": "allow"
+ },
+ "ask.com": {
+ "heuristicAction": "allow"
+ },
+ "askvamygov-ui.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "aso1.net": {
+ "heuristicAction": "block"
+ },
+ "aspencore.com": {
+ "heuristicAction": "allow"
+ },
+ "assets.bounceexchange.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601882616948
+ },
+ "assets.maerskline.com": {
+ "heuristicAction": "allow"
+ },
+ "assets.pinterest.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601935852342
+ },
+ "assets.revcontent.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602268569676
+ },
+ "associates-amazon.com": {
+ "heuristicAction": "block"
+ },
+ "asteannunci.it": {
+ "heuristicAction": "allow"
+ },
+ "async-px-eu.dynamicyield.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601883862412
+ },
+ "async-px.dynamicyield.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602203445235
+ },
+ "atdmt.com": {
+ "heuristicAction": "block"
+ },
+ "atgsvcs.com": {
+ "heuristicAction": "block"
+ },
+ "ati-host.net": {
+ "heuristicAction": "block"
+ },
+ "atlas.atsptp.com": {
+ "heuristicAction": "allow"
+ },
+ "atlassian.net": {
+ "heuristicAction": "allow"
+ },
+ "atp.io": {
+ "heuristicAction": "block"
+ },
+ "ats.rlcdn.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602125519491
+ },
+ "atsptp.com": {
+ "heuristicAction": "allow"
+ },
+ "att.com": {
+ "heuristicAction": "allow"
+ },
+ "attentivemobile.com": {
+ "heuristicAction": "block"
+ },
+ "attservicesinc.tt.omtrdc.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "au.tags.newscgp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602049014872
+ },
+ "au11-tracker.inside-graph.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602184235101
+ },
+ "audex.userreport.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602262150404
+ },
+ "audiencerun.com": {
+ "heuristicAction": "allow"
+ },
+ "audioboom.com": {
+ "heuristicAction": "allow"
+ },
+ "audioburst.com": {
+ "heuristicAction": "allow"
+ },
+ "aufp.io": {
+ "heuristicAction": "allow"
+ },
+ "auone.jp": {
+ "heuristicAction": "allow"
+ },
+ "auth.adobe.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "auth0.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "authorize.net": {
+ "heuristicAction": "allow"
+ },
+ "autoimg.cn": {
+ "heuristicAction": "allow"
+ },
+ "autonom8.com": {
+ "heuristicAction": "allow"
+ },
+ "autopilothq.com": {
+ "heuristicAction": "block"
+ },
+ "avangate.com": {
+ "heuristicAction": "allow"
+ },
+ "avantisvideo.com": {
+ "heuristicAction": "block"
+ },
+ "avd.innity.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602065557805
+ },
+ "avmws.com": {
+ "heuristicAction": "block"
+ },
+ "aweber.com": {
+ "heuristicAction": "allow"
+ },
+ "axisbank.co.in": {
+ "heuristicAction": "allow"
+ },
+ "ayads.co": {
+ "heuristicAction": "block"
+ },
+ "ayc0zsm69431gfebd.xyz": {
+ "heuristicAction": "block"
+ },
+ "ayo.co.id": {
+ "heuristicAction": "allow"
+ },
+ "azet.sk": {
+ "heuristicAction": "allow"
+ },
+ "azureedge.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "azurefd.net": {
+ "heuristicAction": "allow"
+ },
+ "b-code.liadm.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602339921290
+ },
+ "b.ws.sessioncam.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602234050802
+ },
+ "b0e8.com": {
+ "heuristicAction": "block"
+ },
+ "b1img.com": {
+ "heuristicAction": "allow"
+ },
+ "b1sync.zemanta.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602158714232
+ },
+ "b2c.insticator.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602187927759
+ },
+ "b92.yahoo.co.jp": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602315244317
+ },
+ "b97.yahoo.co.jp": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602020393717
+ },
+ "b9i7.net": {
+ "heuristicAction": "allow"
+ },
+ "bablic.com": {
+ "heuristicAction": "block"
+ },
+ "baidu.com": {
+ "heuristicAction": "block"
+ },
+ "baidustatic.com": {
+ "heuristicAction": "allow"
+ },
+ "baikalize.com": {
+ "heuristicAction": "allow"
+ },
+ "baixing.net": {
+ "heuristicAction": "allow"
+ },
+ "baiying.cn": {
+ "heuristicAction": "allow"
+ },
+ "bam-x.com": {
+ "heuristicAction": "block"
+ },
+ "bam.eu01.nr-data.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601889093359
+ },
+ "bam.nr-data.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602152131553
+ },
+ "bancogalicia.com.ar": {
+ "heuristicAction": "allow"
+ },
+ "banggood.com": {
+ "heuristicAction": "allow"
+ },
+ "barchart.com": {
+ "heuristicAction": "allow"
+ },
+ "barilliance.net": {
+ "heuristicAction": "allow"
+ },
+ "bashirian.biz": {
+ "heuristicAction": "allow"
+ },
+ "basspro.com": {
+ "heuristicAction": "allow"
+ },
+ "bat.bing.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602387663629
+ },
+ "bayan.ir": {
+ "heuristicAction": "allow"
+ },
+ "baynote.net": {
+ "heuristicAction": "block"
+ },
+ "bazaarvoice.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "bbelements.com": {
+ "heuristicAction": "allow"
+ },
+ "bbg.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602309051055
+ },
+ "bcicdn.com": {
+ "heuristicAction": "allow"
+ },
+ "bcn.cat": {
+ "heuristicAction": "allow"
+ },
+ "bd4travel.com": {
+ "heuristicAction": "allow"
+ },
+ "bdash-cloud.com": {
+ "heuristicAction": "allow"
+ },
+ "bdg-analytics.appspot.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "bdimg.share.baidu.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602145458005
+ },
+ "beacon.riskified.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601996068641
+ },
+ "bebi.com": {
+ "heuristicAction": "block"
+ },
+ "become.co.jp": {
+ "heuristicAction": "allow"
+ },
+ "beian.gov.cn": {
+ "heuristicAction": "allow"
+ },
+ "benchmarkemail.com": {
+ "heuristicAction": "allow"
+ },
+ "berush.com": {
+ "heuristicAction": "allow"
+ },
+ "bestyang.cn": {
+ "heuristicAction": "allow"
+ },
+ "betgorebysson.club": {
+ "heuristicAction": "block"
+ },
+ "betweendigital.com": {
+ "heuristicAction": "block"
+ },
+ "bf-tools.net": {
+ "heuristicAction": "allow"
+ },
+ "bfmio.com": {
+ "heuristicAction": "block"
+ },
+ "bh.contextweb.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602151063649
+ },
+ "bhphotovideo.com": {
+ "heuristicAction": "allow"
+ },
+ "bibox360.com": {
+ "heuristicAction": "allow"
+ },
+ "bid.contextweb.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602005816713
+ },
+ "bid.g.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602267094770
+ },
+ "bidder.criteo.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601956754101
+ },
+ "bidgear.com": {
+ "heuristicAction": "block"
+ },
+ "bidr.io": {
+ "heuristicAction": "block"
+ },
+ "bidstreamserver.com": {
+ "heuristicAction": "allow"
+ },
+ "bidswitch.net": {
+ "heuristicAction": "block"
+ },
+ "bidvertiser.com": {
+ "heuristicAction": "allow"
+ },
+ "bigmining.com": {
+ "heuristicAction": "block"
+ },
+ "bigo.tv": {
+ "heuristicAction": "allow"
+ },
+ "bing.com": {
+ "heuristicAction": "block"
+ },
+ "binstats.com": {
+ "heuristicAction": "allow"
+ },
+ "bitdefender.demdex.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602165974974
+ },
+ "bitdefender.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601989445163
+ },
+ "bithumb.com": {
+ "heuristicAction": "allow"
+ },
+ "bitninja.io": {
+ "heuristicAction": "block"
+ },
+ "bitrix.info": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602045878490
+ },
+ "bizbuysell.com": {
+ "heuristicAction": "allow"
+ },
+ "bizfly.vn": {
+ "heuristicAction": "allow"
+ },
+ "bizible.com": {
+ "heuristicAction": "block"
+ },
+ "bizibly.com": {
+ "heuristicAction": "block"
+ },
+ "bizographics.com": {
+ "heuristicAction": "block"
+ },
+ "bizrate.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "bizspring.co.kr": {
+ "heuristicAction": "allow"
+ },
+ "bizspring.net": {
+ "heuristicAction": "allow"
+ },
+ "bjcathay.com": {
+ "heuristicAction": "allow"
+ },
+ "blisspointmedia.com": {
+ "heuristicAction": "allow"
+ },
+ "blogsky.com": {
+ "heuristicAction": "allow"
+ },
+ "bluecava.com": {
+ "heuristicAction": "allow"
+ },
+ "blueconic.net": {
+ "heuristicAction": "block"
+ },
+ "bluekai.com": {
+ "heuristicAction": "block"
+ },
+ "bm.adentifi.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602184160391
+ },
+ "bmwofnorthamericallc.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601878977610
+ },
+ "bn-web.com": {
+ "heuristicAction": "allow"
+ },
+ "bnidx.com": {
+ "heuristicAction": "allow"
+ },
+ "bnpparibas.fr": {
+ "heuristicAction": "allow"
+ },
+ "bob.dmpxs.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602299324826
+ },
+ "bold.adman.gr": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602152587390
+ },
+ "boldchat.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "bonappetit.com": {
+ "heuristicAction": "block"
+ },
+ "bongacams.com": {
+ "heuristicAction": "allow"
+ },
+ "bonnier-subscriptions.com": {
+ "heuristicAction": "allow"
+ },
+ "booking.com": {
+ "heuristicAction": "allow"
+ },
+ "books.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "boostingads.com": {
+ "heuristicAction": "allow"
+ },
+ "boot.pubstack.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602259547561
+ },
+ "bounceexchange.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602370139470
+ },
+ "bouncex.net": {
+ "heuristicAction": "allow"
+ },
+ "boxx.ai": {
+ "heuristicAction": "allow"
+ },
+ "brand-display.com": {
+ "heuristicAction": "allow"
+ },
+ "brandcdn.com": {
+ "heuristicAction": "allow"
+ },
+ "brandonsun.com": {
+ "heuristicAction": "allow"
+ },
+ "brdmin.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602327375504
+ },
+ "breaktime.com.tw": {
+ "heuristicAction": "allow"
+ },
+ "brightcove.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "brightedge.com": {
+ "heuristicAction": "allow"
+ },
+ "broadstreetads.com": {
+ "heuristicAction": "block"
+ },
+ "brsrvr.com": {
+ "heuristicAction": "block"
+ },
+ "bs.serving-sys.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601965040769
+ },
+ "btlr.sharethrough.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601945188066
+ },
+ "bttrack.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602206723567
+ },
+ "btttag.com": {
+ "heuristicAction": "block"
+ },
+ "buckridge.link": {
+ "heuristicAction": "allow"
+ },
+ "bugsnag.com": {
+ "heuristicAction": "allow"
+ },
+ "bullionyield.com": {
+ "heuristicAction": "allow"
+ },
+ "bumlam.com": {
+ "heuristicAction": "allow"
+ },
+ "burly.io": {
+ "heuristicAction": "allow"
+ },
+ "businessclick.com": {
+ "heuristicAction": "allow"
+ },
+ "businessinsider.com": {
+ "heuristicAction": "allow"
+ },
+ "buysellads.net": {
+ "heuristicAction": "allow"
+ },
+ "buzzfeed.com": {
+ "heuristicAction": "allow"
+ },
+ "buzzoola.com": {
+ "heuristicAction": "block"
+ },
+ "byteoversea.com": {
+ "heuristicAction": "allow"
+ },
+ "c-ctrip.com": {
+ "heuristicAction": "allow"
+ },
+ "c.aaxads.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602133117190
+ },
+ "c.amazon-adsystem.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602116423667
+ },
+ "c.cintnetworks.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601985045135
+ },
+ "c.echoban.ru": {
+ "heuristicAction": "allow"
+ },
+ "c.finder.com.au": {
+ "heuristicAction": "allow"
+ },
+ "c.imedia.cz": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602338007739
+ },
+ "c.tvpixel.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602281468764
+ },
+ "c0.adalyser.com": {
+ "heuristicAction": "block"
+ },
+ "c2.taboola.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602199865122
+ },
+ "c212.net": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601926998289
+ },
+ "c2shb.ssp.yahoo.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602119360923
+ },
+ "c3tag.com": {
+ "heuristicAction": "block"
+ },
+ "c8.net.ua": {
+ "heuristicAction": "allow"
+ },
+ "ca.clcknads.pro": {
+ "heuristicAction": "allow"
+ },
+ "calendar.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "calendly.com": {
+ "heuristicAction": "allow"
+ },
+ "canliskor.com.tr": {
+ "heuristicAction": "allow"
+ },
+ "captcha.qq.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "captcha.su.baidu.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602035118165
+ },
+ "capterra.com": {
+ "heuristicAction": "allow"
+ },
+ "capture.ma.knnlab.com": {
+ "heuristicAction": "allow"
+ },
+ "capturehighered.net": {
+ "heuristicAction": "block"
+ },
+ "carfax.com": {
+ "heuristicAction": "allow"
+ },
+ "caroda.io": {
+ "heuristicAction": "allow"
+ },
+ "casalemedia.com": {
+ "heuristicAction": "block"
+ },
+ "caspio.com": {
+ "heuristicAction": "allow"
+ },
+ "castbox.fm": {
+ "heuristicAction": "allow"
+ },
+ "castle.io": {
+ "heuristicAction": "block"
+ },
+ "cbjs.baidu.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602318189107
+ },
+ "cbs.com": {
+ "heuristicAction": "allow"
+ },
+ "cbsi.com": {
+ "heuristicAction": "allow"
+ },
+ "cbsi.demdex.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602025130249
+ },
+ "cctv.com": {
+ "heuristicAction": "allow"
+ },
+ "cdeledu.com": {
+ "heuristicAction": "allow"
+ },
+ "cdn-9.nikon-cdn.com": {
+ "heuristicAction": "allow"
+ },
+ "cdn-eu.dynamicyield.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "cdn-gl.imrworldwide.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602360335129
+ },
+ "cdn-net.com": {
+ "heuristicAction": "allow"
+ },
+ "cdn-payscale.com": {
+ "heuristicAction": "allow"
+ },
+ "cdn.admixer.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601998059247
+ },
+ "cdn.adpushup.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602346792119
+ },
+ "cdn.adrta.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602255264722
+ },
+ "cdn.adswizz.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601877259582
+ },
+ "cdn.adtrue.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601977551091
+ },
+ "cdn.anvato.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "cdn.appdynamics.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602206414606
+ },
+ "cdn.ayc0zsm69431gfebd.xyz": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602022432060
+ },
+ "cdn.b0e8.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602218730077
+ },
+ "cdn.bizible.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602072684408
+ },
+ "cdn.blueconic.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601919649170
+ },
+ "cdn.bttrack.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601902953164
+ },
+ "cdn.c212.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602010562584
+ },
+ "cdn.connectad.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602189715401
+ },
+ "cdn.cquotient.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602143996048
+ },
+ "cdn.cxense.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601930190742
+ },
+ "cdn.districtm.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601878123166
+ },
+ "cdn.dynamicyield.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "cdn.engine.phn.doublepimp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602186508607
+ },
+ "cdn.feathr.co": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601879578239
+ },
+ "cdn.feedify.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601995161512
+ },
+ "cdn.heapanalytics.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602295105858
+ },
+ "cdn.id5-sync.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601902679665
+ },
+ "cdn.intergient.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602102160456
+ },
+ "cdn.izooto.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602163468708
+ },
+ "cdn.jsdelivr.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "cdn.jwplayer.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "cdn.keywee.co": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602224814381
+ },
+ "cdn.monsido.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602197579155
+ },
+ "cdn.onthe.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602222920034
+ },
+ "cdn.parsely.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601948971800
+ },
+ "cdn.pbbl.co": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602226564814
+ },
+ "cdn.pendo.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602386182050
+ },
+ "cdn.quantummetric.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602195067300
+ },
+ "cdn.scarabresearch.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602071096077
+ },
+ "cdn.segment.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601955658663
+ },
+ "cdn.sift.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602118383507
+ },
+ "cdn.siftscience.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601898263432
+ },
+ "cdn.taboola.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601874073082
+ },
+ "cdn.tradelab.fr": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601905707251
+ },
+ "cdn.tsyndicate.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602278154788
+ },
+ "cdn.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602352155956
+ },
+ "cdn.userreplay.net": {
+ "heuristicAction": "block"
+ },
+ "cdn.yektanet.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601925614365
+ },
+ "cdn1.affirm.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "cdn4.buysellads.net": {
+ "heuristicAction": "allow"
+ },
+ "cdninstagram.com": {
+ "heuristicAction": "allow"
+ },
+ "cdnpub.info": {
+ "heuristicAction": "allow"
+ },
+ "cdns.brsrvr.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602189823139
+ },
+ "cdnssl.clicktale.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602106370607
+ },
+ "cdnvideo.mobi": {
+ "heuristicAction": "allow"
+ },
+ "cdnwidget.com": {
+ "heuristicAction": "block"
+ },
+ "ceet.co": {
+ "heuristicAction": "allow"
+ },
+ "cengage.com": {
+ "heuristicAction": "allow"
+ },
+ "center.io": {
+ "heuristicAction": "allow"
+ },
+ "centerdigitaled.com": {
+ "heuristicAction": "allow"
+ },
+ "centrum.cz": {
+ "heuristicAction": "allow"
+ },
+ "cern.ch": {
+ "heuristicAction": "allow"
+ },
+ "certify-js.alexametrics.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602101327808
+ },
+ "certify.alexametrics.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601882930135
+ },
+ "cfzu.net": {
+ "heuristicAction": "allow"
+ },
+ "channelnewsasia.com": {
+ "heuristicAction": "allow"
+ },
+ "charlotteobserver.com": {
+ "heuristicAction": "allow"
+ },
+ "chartbeat.net": {
+ "heuristicAction": "block"
+ },
+ "chase.com": {
+ "heuristicAction": "allow"
+ },
+ "chat.chatra.io": {
+ "heuristicAction": "allow"
+ },
+ "chatdealer.jp": {
+ "heuristicAction": "allow"
+ },
+ "chatplus.jp": {
+ "heuristicAction": "allow"
+ },
+ "chatra.io": {
+ "heuristicAction": "allow"
+ },
+ "chaturbate.com": {
+ "heuristicAction": "allow"
+ },
+ "checkout.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "chegg.com": {
+ "heuristicAction": "allow"
+ },
+ "cheqzone.com": {
+ "heuristicAction": "block"
+ },
+ "cheyisou.com": {
+ "heuristicAction": "allow"
+ },
+ "childsplayclothing.co.uk": {
+ "heuristicAction": "allow"
+ },
+ "chipweb.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "choozle.com": {
+ "heuristicAction": "block"
+ },
+ "cian.site": {
+ "heuristicAction": "allow"
+ },
+ "cint.com": {
+ "heuristicAction": "allow"
+ },
+ "cintnetworks.com": {
+ "heuristicAction": "block"
+ },
+ "cisco.com": {
+ "heuristicAction": "block"
+ },
+ "citi.com": {
+ "heuristicAction": "allow"
+ },
+ "citiservi.es": {
+ "heuristicAction": "allow"
+ },
+ "citrix.com": {
+ "heuristicAction": "allow"
+ },
+ "clarivate.com": {
+ "heuristicAction": "allow"
+ },
+ "classistatic.com": {
+ "heuristicAction": "allow"
+ },
+ "clcknads.pro": {
+ "heuristicAction": "allow"
+ },
+ "clearbit.com": {
+ "heuristicAction": "allow"
+ },
+ "clerk.io": {
+ "heuristicAction": "allow"
+ },
+ "clevernt.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602225098998
+ },
+ "clickability.com": {
+ "heuristicAction": "allow"
+ },
+ "clickagy.com": {
+ "heuristicAction": "allow"
+ },
+ "clickcertain.com": {
+ "heuristicAction": "allow"
+ },
+ "clickfuse.com": {
+ "heuristicAction": "allow"
+ },
+ "clickondetroit.com": {
+ "heuristicAction": "allow"
+ },
+ "clicktale.net": {
+ "heuristicAction": "block"
+ },
+ "clicktripz.com": {
+ "heuristicAction": "block"
+ },
+ "clientgear.com": {
+ "heuristicAction": "allow"
+ },
+ "clients1.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "clients6.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "clinch.co": {
+ "heuristicAction": "allow"
+ },
+ "clink.cn": {
+ "heuristicAction": "allow"
+ },
+ "clive.cloud": {
+ "heuristicAction": "block"
+ },
+ "clmbtech.com": {
+ "heuristicAction": "block"
+ },
+ "cloob.com": {
+ "heuristicAction": "allow"
+ },
+ "cloud-iq.com": {
+ "heuristicAction": "allow"
+ },
+ "cloud-us.analytics-egain.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602025793764
+ },
+ "cloudflare.com": {
+ "heuristicAction": "allow"
+ },
+ "clublibertaddigital.com": {
+ "heuristicAction": "allow"
+ },
+ "cluep.com": {
+ "heuristicAction": "allow"
+ },
+ "cluesnetwork.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602169279411
+ },
+ "cm.g.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602229275079
+ },
+ "cma.ecommerce.highwire.org": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602019896483
+ },
+ "cmanager-prometeo.appspot.com": {
+ "heuristicAction": "allow"
+ },
+ "cmsadmin30.convio.net": {
+ "heuristicAction": "allow"
+ },
+ "cnmo-img.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "cnnd.vn": {
+ "heuristicAction": "allow"
+ },
+ "cnrs.fr": {
+ "heuristicAction": "allow"
+ },
+ "cntraveler.com": {
+ "heuristicAction": "block"
+ },
+ "cntv.cn": {
+ "heuristicAction": "allow"
+ },
+ "cnyes.cool": {
+ "heuristicAction": "allow"
+ },
+ "cnzz.com": {
+ "heuristicAction": "block"
+ },
+ "cobaltgroup.com": {
+ "heuristicAction": "allow"
+ },
+ "coccusadmanlob.com": {
+ "heuristicAction": "allow"
+ },
+ "codon.vn": {
+ "heuristicAction": "allow"
+ },
+ "coherentpath.com": {
+ "heuristicAction": "allow"
+ },
+ "cohesionapps.com": {
+ "heuristicAction": "block"
+ },
+ "coinmama.com": {
+ "heuristicAction": "allow"
+ },
+ "cointiply.com": {
+ "heuristicAction": "allow"
+ },
+ "col1.wiqhit.com": {
+ "heuristicAction": "allow"
+ },
+ "collect-eu-west-1.tealiumiq.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601922968466
+ },
+ "collect.tealiumiq.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602028785345
+ },
+ "collectandgather.com": {
+ "heuristicAction": "block"
+ },
+ "collector-4113.tvsquared.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601956166811
+ },
+ "collector-7762.tvsquared.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602278064501
+ },
+ "collector-8013.tvsquared.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601892538336
+ },
+ "collector-9152.us.tvsquared.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602362051662
+ },
+ "collector_sr.contentexchange.me": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602076112287
+ },
+ "collegenet.com": {
+ "heuristicAction": "allow"
+ },
+ "colossusssp.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601940122536
+ },
+ "comm100.com": {
+ "heuristicAction": "allow"
+ },
+ "comm100.io": {
+ "heuristicAction": "allow"
+ },
+ "commander1.com": {
+ "heuristicAction": "block"
+ },
+ "commitchange.com": {
+ "heuristicAction": "block"
+ },
+ "company-target.com": {
+ "heuristicAction": "block"
+ },
+ "compass.adop.cc": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602230218761
+ },
+ "complex.com": {
+ "heuristicAction": "allow"
+ },
+ "comptia.informz.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602085621894
+ },
+ "condenastdigital.com": {
+ "heuristicAction": "block"
+ },
+ "connatix.com": {
+ "heuristicAction": "block"
+ },
+ "connect.ok.ru": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601990579341
+ },
+ "connectad.io": {
+ "heuristicAction": "block"
+ },
+ "connecto.io": {
+ "heuristicAction": "allow"
+ },
+ "connexity.net": {
+ "heuristicAction": "allow"
+ },
+ "connextra.com": {
+ "heuristicAction": "block"
+ },
+ "consent-st.trustarc.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601993514944
+ },
+ "consent.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "consent.is": {
+ "heuristicAction": "allow"
+ },
+ "consent.trustarc.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601902285274
+ },
+ "consentag.eu": {
+ "heuristicAction": "allow"
+ },
+ "constantcontact.com": {
+ "heuristicAction": "allow"
+ },
+ "consumer.truefitcorp.com": {
+ "heuristicAction": "allow"
+ },
+ "consumerreports.org": {
+ "heuristicAction": "allow"
+ },
+ "contentabc.com": {
+ "heuristicAction": "allow"
+ },
+ "contentexchange.me": {
+ "heuristicAction": "block"
+ },
+ "contentinsights.com": {
+ "heuristicAction": "allow"
+ },
+ "contentive.com": {
+ "heuristicAction": "allow"
+ },
+ "contentsfeed.com": {
+ "heuristicAction": "block"
+ },
+ "contentsquare.net": {
+ "heuristicAction": "block"
+ },
+ "contextads.live": {
+ "heuristicAction": "block"
+ },
+ "contextual.media.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602079811699
+ },
+ "contextweb.com": {
+ "heuristicAction": "block"
+ },
+ "contobox.com": {
+ "heuristicAction": "allow"
+ },
+ "contributor.google.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602152524397
+ },
+ "conversantmedia.com": {
+ "heuristicAction": "allow"
+ },
+ "conversionlogic.net": {
+ "heuristicAction": "allow"
+ },
+ "convertkit.com": {
+ "heuristicAction": "allow"
+ },
+ "convertlanguage.com": {
+ "heuristicAction": "allow"
+ },
+ "convio.net": {
+ "heuristicAction": "allow"
+ },
+ "coremetrics.com": {
+ "heuristicAction": "block"
+ },
+ "corus.ca": {
+ "heuristicAction": "allow"
+ },
+ "costco.com": {
+ "heuristicAction": "allow"
+ },
+ "cotsta.ru": {
+ "heuristicAction": "allow"
+ },
+ "counter.yadro.ru": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602079868998
+ },
+ "coupang.com": {
+ "heuristicAction": "allow"
+ },
+ "coupons.net": {
+ "heuristicAction": "allow"
+ },
+ "coveo.com": {
+ "heuristicAction": "allow"
+ },
+ "coxbusiness.com": {
+ "heuristicAction": "allow"
+ },
+ "cpmstar.com": {
+ "heuristicAction": "block"
+ },
+ "cpx.to": {
+ "heuristicAction": "block"
+ },
+ "cquotient.com": {
+ "heuristicAction": "block"
+ },
+ "crain.112.2o7.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "craommunications.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602014878244
+ },
+ "creative-serving.com": {
+ "heuristicAction": "allow"
+ },
+ "creativecdn.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602095708225
+ },
+ "creativelive.com": {
+ "heuristicAction": "allow"
+ },
+ "creativemarket.com": {
+ "heuristicAction": "allow"
+ },
+ "crentgate.com": {
+ "heuristicAction": "allow"
+ },
+ "cretgate.com": {
+ "heuristicAction": "allow"
+ },
+ "criteo.com": {
+ "heuristicAction": "block"
+ },
+ "crossref.matomo.cloud": {
+ "heuristicAction": "allow"
+ },
+ "crsspxl.com": {
+ "heuristicAction": "block"
+ },
+ "crwdcntrl.net": {
+ "heuristicAction": "block"
+ },
+ "cryptobrowser.site": {
+ "heuristicAction": "allow"
+ },
+ "cs.emxdgt.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602364516530
+ },
+ "cs.nakanohito.jp": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602275724198
+ },
+ "cse.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "csp.yahoo.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602239706221
+ },
+ "csus.regroup.com": {
+ "heuristicAction": "allow"
+ },
+ "csync.smilewanted.com": {
+ "heuristicAction": "allow"
+ },
+ "cszz.ru": {
+ "heuristicAction": "allow"
+ },
+ "ct.pinterest.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601908512461
+ },
+ "cta-service-cms2.hubspot.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "ctags.cn": {
+ "heuristicAction": "allow"
+ },
+ "ctnsnet.com": {
+ "heuristicAction": "block"
+ },
+ "ctrack.trafficjunky.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602211127901
+ },
+ "ctrip.com": {
+ "heuristicAction": "allow"
+ },
+ "cts.w55c.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602020353458
+ },
+ "cuberoot.co": {
+ "heuristicAction": "allow"
+ },
+ "culturaltracking.ru": {
+ "heuristicAction": "allow"
+ },
+ "curalate.com": {
+ "heuristicAction": "block"
+ },
+ "custhelp.com": {
+ "heuristicAction": "allow"
+ },
+ "customer.io": {
+ "heuristicAction": "block"
+ },
+ "custora.com": {
+ "heuristicAction": "block"
+ },
+ "cvent.com": {
+ "heuristicAction": "allow"
+ },
+ "cvshealth.com": {
+ "heuristicAction": "allow"
+ },
+ "cxense.com": {
+ "heuristicAction": "block"
+ },
+ "cyol.net": {
+ "heuristicAction": "allow"
+ },
+ "d-bi.fr": {
+ "heuristicAction": "allow"
+ },
+ "d-markets.net": {
+ "heuristicAction": "allow"
+ },
+ "d.agkn.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602306895135
+ },
+ "d.nativendo.de": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602203469675
+ },
+ "d.otaserve.net": {
+ "heuristicAction": "allow"
+ },
+ "d.turn.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602273365299
+ },
+ "d.us.criteo.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602110104637
+ },
+ "d1af033869koo7.cloudfront.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "d1d3jupgwm7m5r.cloudfront.net": {
+ "heuristicAction": "allow"
+ },
+ "d1dns4zpgsd7rz.cloudfront.net": {
+ "heuristicAction": "allow"
+ },
+ "d1epsz32winqbo.cloudfront.net": {
+ "heuristicAction": "allow"
+ },
+ "d1rv23qj5kas56.cloudfront.net": {
+ "heuristicAction": "allow"
+ },
+ "d226aj4ao1t61q.cloudfront.net": {
+ "heuristicAction": "allow"
+ },
+ "d2t77mnxyo7adj.cloudfront.net": {
+ "heuristicAction": "allow"
+ },
+ "d32blsbofe2158.cloudfront.net": {
+ "heuristicAction": "allow"
+ },
+ "d32hpx6p5we0tx.cloudfront.net": {
+ "heuristicAction": "allow"
+ },
+ "d38xvr37kwwhcm.cloudfront.net": {
+ "heuristicAction": "allow"
+ },
+ "d395dw5zk780j2.cloudfront.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "d41.co": {
+ "heuristicAction": "block"
+ },
+ "d5nxst8fruw4z.cloudfront.net": {
+ "heuristicAction": "allow"
+ },
+ "d9jj3mjthpub.cloudfront.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "dable.io": {
+ "heuristicAction": "block"
+ },
+ "dadcdigital.com": {
+ "heuristicAction": "allow"
+ },
+ "dadicinema.com": {
+ "heuristicAction": "allow"
+ },
+ "dailymail.co.uk": {
+ "heuristicAction": "block"
+ },
+ "dailymotion.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "dam-broadcast.com": {
+ "heuristicAction": "allow"
+ },
+ "danv01ao0kdr2.cloudfront.net": {
+ "heuristicAction": "allow"
+ },
+ "dapadobeproxyql.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "dapadobeproxytest.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "data.caroda.io": {
+ "heuristicAction": "allow"
+ },
+ "datamind.ru": {
+ "heuristicAction": "allow"
+ },
+ "dataplusmath.com": {
+ "heuristicAction": "allow"
+ },
+ "dataprev.gov.br": {
+ "heuristicAction": "allow"
+ },
+ "datasink.canva.sensorsdatavip.com": {
+ "heuristicAction": "allow"
+ },
+ "datasteam.io": {
+ "heuristicAction": "allow"
+ },
+ "datastudio.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "dataxpand.com": {
+ "heuristicAction": "block"
+ },
+ "daum.net": {
+ "heuristicAction": "block"
+ },
+ "dc-storm.com": {
+ "heuristicAction": "block"
+ },
+ "dc-tag.jp": {
+ "heuristicAction": "allow"
+ },
+ "dc.ads.linkedin.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602057970891
+ },
+ "dc.services.visualstudio.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602300861026
+ },
+ "dcmn.io": {
+ "heuristicAction": "allow"
+ },
+ "dditscdn.com": {
+ "heuristicAction": "allow"
+ },
+ "dditservices.com": {
+ "heuristicAction": "allow"
+ },
+ "ddos-guard.net": {
+ "heuristicAction": "allow"
+ },
+ "de.ioam.de": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602378579779
+ },
+ "de.tynt.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602052768098
+ },
+ "deadline.com": {
+ "heuristicAction": "allow"
+ },
+ "deadlinefunnel.com": {
+ "heuristicAction": "allow"
+ },
+ "dealerinspire.com": {
+ "heuristicAction": "allow"
+ },
+ "deema.agency": {
+ "heuristicAction": "allow"
+ },
+ "deep.bi": {
+ "heuristicAction": "allow"
+ },
+ "deepintent.com": {
+ "heuristicAction": "block"
+ },
+ "dell.com": {
+ "heuristicAction": "allow"
+ },
+ "demdex.net": {
+ "heuristicAction": "block"
+ },
+ "denakop.com": {
+ "heuristicAction": "allow"
+ },
+ "denverpost.com": {
+ "heuristicAction": "allow"
+ },
+ "deployads.com": {
+ "heuristicAction": "block"
+ },
+ "deqwas.net": {
+ "heuristicAction": "block"
+ },
+ "desipearl.com": {
+ "heuristicAction": "allow"
+ },
+ "detik.com": {
+ "heuristicAction": "block"
+ },
+ "dev.visualwebsiteoptimizer.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602216650289
+ },
+ "developers.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "dezeenjobs.com": {
+ "heuristicAction": "allow"
+ },
+ "dfapvmql-q.global.ssl.fastly.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "dfcfw.com": {
+ "heuristicAction": "allow"
+ },
+ "dhgate.com": {
+ "heuristicAction": "allow"
+ },
+ "di-dtaectolog-us-prod-1.appspot.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "di.rlcdn.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601957759123
+ },
+ "dialogtech.com": {
+ "heuristicAction": "block"
+ },
+ "diffuser-cdn.app-us1.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602287762831
+ },
+ "diginetica.net": {
+ "heuristicAction": "allow"
+ },
+ "digitalaudienz.com": {
+ "heuristicAction": "allow"
+ },
+ "digitalbee.al": {
+ "heuristicAction": "allow"
+ },
+ "digitalbox.ru": {
+ "heuristicAction": "allow"
+ },
+ "digitalfirstmedia.com": {
+ "heuristicAction": "allow"
+ },
+ "digitalkites.com": {
+ "heuristicAction": "allow"
+ },
+ "digitaloceanspaces.com": {
+ "heuristicAction": "allow"
+ },
+ "digitalriver.com": {
+ "heuristicAction": "allow"
+ },
+ "digitaltarget.ru": {
+ "heuristicAction": "block"
+ },
+ "digitru.st": {
+ "heuristicAction": "block"
+ },
+ "diqp43fm0w6zs.cloudfront.net": {
+ "heuristicAction": "allow"
+ },
+ "discord.com": {
+ "heuristicAction": "allow"
+ },
+ "display.popt.in": {
+ "heuristicAction": "allow"
+ },
+ "distribuidoraliverpo.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601944420774
+ },
+ "districtm.ca": {
+ "heuristicAction": "allow"
+ },
+ "districtm.io": {
+ "heuristicAction": "block"
+ },
+ "dj.xesimg.com": {
+ "heuristicAction": "allow"
+ },
+ "djiops.com": {
+ "heuristicAction": "allow"
+ },
+ "dkb01.webtrekk.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602106992136
+ },
+ "dkuim.de": {
+ "heuristicAction": "allow"
+ },
+ "dl1d2m8ri9v3j.cloudfront.net": {
+ "heuristicAction": "allow"
+ },
+ "dmg.digitaltarget.ru": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601940466077
+ },
+ "dmgmediaprivacy.co.uk": {
+ "heuristicAction": "block"
+ },
+ "dmm.com": {
+ "heuristicAction": "allow"
+ },
+ "dmp.adform.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602352172322
+ },
+ "dmpxs.com": {
+ "heuristicAction": "block"
+ },
+ "dmx.districtm.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602339487062
+ },
+ "dmxleo.com": {
+ "heuristicAction": "block"
+ },
+ "docomo.ne.jp": {
+ "heuristicAction": "block"
+ },
+ "docs.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "doga.cm": {
+ "heuristicAction": "allow"
+ },
+ "donorbox.org": {
+ "heuristicAction": "allow"
+ },
+ "dotmetrics.net": {
+ "heuristicAction": "block"
+ },
+ "dotomi.com": {
+ "heuristicAction": "block"
+ },
+ "doubleclick.net": {
+ "heuristicAction": "block"
+ },
+ "doublepimp.com": {
+ "heuristicAction": "block"
+ },
+ "douyucdn.cn": {
+ "heuristicAction": "allow"
+ },
+ "dowjoneson.com": {
+ "heuristicAction": "block"
+ },
+ "dpgmedia.net": {
+ "heuristicAction": "block"
+ },
+ "dpm.demdex.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602295925191
+ },
+ "dpmsrv.com": {
+ "heuristicAction": "block"
+ },
+ "dpx.airpr.com": {
+ "heuristicAction": "block"
+ },
+ "drcareers.ca": {
+ "heuristicAction": "allow"
+ },
+ "dreamlab.pl": {
+ "heuristicAction": "allow"
+ },
+ "drive.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "dropbox.com": {
+ "heuristicAction": "block"
+ },
+ "dropboxusercontent.com": {
+ "heuristicAction": "allow"
+ },
+ "drtvagency.matomo.cloud": {
+ "heuristicAction": "allow"
+ },
+ "ds.reson8.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602064407139
+ },
+ "dsp.com": {
+ "heuristicAction": "allow"
+ },
+ "dsspn.com": {
+ "heuristicAction": "allow"
+ },
+ "dsw.tt.omtrdc.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "dtprofit.com": {
+ "heuristicAction": "allow"
+ },
+ "dtscdn.com": {
+ "heuristicAction": "allow"
+ },
+ "dtscout.com": {
+ "heuristicAction": "block"
+ },
+ "dttq.net": {
+ "heuristicAction": "allow"
+ },
+ "duba.com": {
+ "heuristicAction": "allow"
+ },
+ "dugout.com": {
+ "heuristicAction": "allow"
+ },
+ "duoyi.com": {
+ "heuristicAction": "allow"
+ },
+ "dw.cbsi.com": {
+ "heuristicAction": "allow"
+ },
+ "dx.steelhousemedia.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602027732124
+ },
+ "dxcdn.com": {
+ "heuristicAction": "allow"
+ },
+ "dynad.net": {
+ "heuristicAction": "allow"
+ },
+ "dynadot.com": {
+ "heuristicAction": "allow"
+ },
+ "dynamics.com": {
+ "heuristicAction": "allow"
+ },
+ "dynamicyield.com": {
+ "heuristicAction": "block"
+ },
+ "dyntrk.com": {
+ "heuristicAction": "allow"
+ },
+ "e-9550.adzerk.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602010620823
+ },
+ "e-contenta.com": {
+ "heuristicAction": "allow"
+ },
+ "e-himart.co.kr": {
+ "heuristicAction": "allow"
+ },
+ "e-planning.net": {
+ "heuristicAction": "block"
+ },
+ "e.issuu.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "e.serverbid.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602043765681
+ },
+ "e1.emxdgt.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602349294120
+ },
+ "easemob.com": {
+ "heuristicAction": "allow"
+ },
+ "eb.com": {
+ "heuristicAction": "allow"
+ },
+ "eb2.3lift.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601953769138
+ },
+ "ebay.com": {
+ "heuristicAction": "allow"
+ },
+ "ebayimg.com": {
+ "heuristicAction": "allow"
+ },
+ "ebis.ne.jp": {
+ "heuristicAction": "block"
+ },
+ "ebu.io": {
+ "heuristicAction": "allow"
+ },
+ "ecbsn.com": {
+ "heuristicAction": "allow"
+ },
+ "eccmp.com": {
+ "heuristicAction": "block"
+ },
+ "ecdn.firstimpression.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601895613084
+ },
+ "echoban.ru": {
+ "heuristicAction": "allow"
+ },
+ "ecustomeropinions.com": {
+ "heuristicAction": "allow"
+ },
+ "ecwid.ru": {
+ "heuristicAction": "allow"
+ },
+ "edge-cdn.net": {
+ "heuristicAction": "allow"
+ },
+ "edge.quantserve.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602307465005
+ },
+ "edigitalsurvey.com": {
+ "heuristicAction": "allow"
+ },
+ "editor80.com": {
+ "heuristicAction": "allow"
+ },
+ "editorx.com": {
+ "heuristicAction": "allow"
+ },
+ "eestatic.com": {
+ "heuristicAction": "allow"
+ },
+ "effectivemeasure.net": {
+ "heuristicAction": "block"
+ },
+ "egain.cloud": {
+ "heuristicAction": "allow"
+ },
+ "el-mundo.net": {
+ "heuristicAction": "block"
+ },
+ "eland-tech.com": {
+ "heuristicAction": "allow"
+ },
+ "elfsight.com": {
+ "heuristicAction": "allow"
+ },
+ "elmercurio.com": {
+ "heuristicAction": "allow"
+ },
+ "eloqua.com": {
+ "heuristicAction": "block"
+ },
+ "elpais.com": {
+ "heuristicAction": "allow"
+ },
+ "elsevier.com": {
+ "heuristicAction": "block"
+ },
+ "elsevierhealth.com": {
+ "heuristicAction": "allow"
+ },
+ "eltiempo.co": {
+ "heuristicAction": "allow"
+ },
+ "eltiempo.digital": {
+ "heuristicAction": "allow"
+ },
+ "embedly.com": {
+ "heuristicAction": "allow"
+ },
+ "emxdgt.com": {
+ "heuristicAction": "block"
+ },
+ "enamad.ir": {
+ "heuristicAction": "block"
+ },
+ "ename.cn": {
+ "heuristicAction": "allow"
+ },
+ "engageclick.com": {
+ "heuristicAction": "allow"
+ },
+ "engageya.com": {
+ "heuristicAction": "block"
+ },
+ "engine.phn.doublepimp.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602305443129
+ },
+ "ens.fr": {
+ "heuristicAction": "allow"
+ },
+ "ensighten.com": {
+ "heuristicAction": "allow"
+ },
+ "entertainow.com": {
+ "heuristicAction": "allow"
+ },
+ "entitlements.jwplayer.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "entrust.net": {
+ "heuristicAction": "allow"
+ },
+ "envoke.com": {
+ "heuristicAction": "allow"
+ },
+ "epicurious.com": {
+ "heuristicAction": "block"
+ },
+ "episerver.net": {
+ "heuristicAction": "allow"
+ },
+ "eqads.com": {
+ "heuristicAction": "allow"
+ },
+ "equalstyle.com": {
+ "heuristicAction": "allow"
+ },
+ "erepublic.com": {
+ "heuristicAction": "allow"
+ },
+ "essayassist.com": {
+ "heuristicAction": "allow"
+ },
+ "essayprofit.com": {
+ "heuristicAction": "block"
+ },
+ "estadao-bi-ga360.appspot.com": {
+ "heuristicAction": "allow"
+ },
+ "estat.com": {
+ "heuristicAction": "block"
+ },
+ "etihadairways.demdex.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601940306055
+ },
+ "etihadairways.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602374005443
+ },
+ "etracker.de": {
+ "heuristicAction": "allow"
+ },
+ "eu2.cdn.thunderhead.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602312245822
+ },
+ "eum-appdynamics.com": {
+ "heuristicAction": "block"
+ },
+ "eus.rubiconproject.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601972290746
+ },
+ "event.insticator.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602130252649
+ },
+ "everesttech.net": {
+ "heuristicAction": "block"
+ },
+ "evergage.com": {
+ "heuristicAction": "block"
+ },
+ "everyaction.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "everzones.com": {
+ "heuristicAction": "allow"
+ },
+ "evise.com": {
+ "heuristicAction": "allow"
+ },
+ "evo.company": {
+ "heuristicAction": "allow"
+ },
+ "evolok.net": {
+ "heuristicAction": "block"
+ },
+ "evsuite.com": {
+ "heuristicAction": "allow"
+ },
+ "ewrvdi.net": {
+ "heuristicAction": "allow"
+ },
+ "exactag.com": {
+ "heuristicAction": "allow"
+ },
+ "exacttarget.com": {
+ "heuristicAction": "allow"
+ },
+ "excite.co.jp": {
+ "heuristicAction": "allow"
+ },
+ "exdynsrv.com": {
+ "heuristicAction": "block"
+ },
+ "exelator.com": {
+ "heuristicAction": "block"
+ },
+ "exitintel.com": {
+ "heuristicAction": "allow"
+ },
+ "exoclick.com": {
+ "heuristicAction": "block"
+ },
+ "exosrv.com": {
+ "heuristicAction": "block"
+ },
+ "exoticads.com": {
+ "heuristicAction": "allow"
+ },
+ "expedia.com": {
+ "heuristicAction": "allow"
+ },
+ "expediapartnercentral.com": {
+ "heuristicAction": "allow"
+ },
+ "experiancs.com": {
+ "heuristicAction": "allow"
+ },
+ "expertrec.com": {
+ "heuristicAction": "allow"
+ },
+ "exponea.com": {
+ "heuristicAction": "block"
+ },
+ "eyeota.net": {
+ "heuristicAction": "block"
+ },
+ "eyereturn.com": {
+ "heuristicAction": "block"
+ },
+ "ezoic.net": {
+ "heuristicAction": "block"
+ },
+ "f.convertkit.com": {
+ "heuristicAction": "allow"
+ },
+ "f1272serve.xyz": {
+ "heuristicAction": "allow"
+ },
+ "f5.com": {
+ "heuristicAction": "allow"
+ },
+ "f5networks.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602305082923
+ },
+ "f5networks.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602114980021
+ },
+ "fabled.com": {
+ "heuristicAction": "allow"
+ },
+ "facebook.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601894588684
+ },
+ "fairfaxregional.com.au": {
+ "heuristicAction": "allow"
+ },
+ "faisys.com": {
+ "heuristicAction": "allow"
+ },
+ "famousbirthdays-d.openx.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601877671741
+ },
+ "fanduel.pxf.io": {
+ "heuristicAction": "allow"
+ },
+ "fang.com": {
+ "heuristicAction": "allow"
+ },
+ "farfetch-contents.com": {
+ "heuristicAction": "allow"
+ },
+ "farfetch.net": {
+ "heuristicAction": "allow"
+ },
+ "faromen.online": {
+ "heuristicAction": "allow"
+ },
+ "fastapi.net": {
+ "heuristicAction": "allow"
+ },
+ "fastcounter.de": {
+ "heuristicAction": "allow"
+ },
+ "fastlane.rubiconproject.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602217867653
+ },
+ "fbc.wcfbc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602112890625
+ },
+ "fcglcdn.com": {
+ "heuristicAction": "allow"
+ },
+ "feathr.co": {
+ "heuristicAction": "block"
+ },
+ "feedburner.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "feedify.net": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602289571761
+ },
+ "feedproxy.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "feeds.soundcloud.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "felmat.net": {
+ "heuristicAction": "allow"
+ },
+ "fengimg.com": {
+ "heuristicAction": "allow"
+ },
+ "fengkongcloud.com": {
+ "heuristicAction": "allow"
+ },
+ "ferret-one.com": {
+ "heuristicAction": "allow"
+ },
+ "ffmapi.com": {
+ "heuristicAction": "allow"
+ },
+ "fieldtest.cc": {
+ "heuristicAction": "allow"
+ },
+ "filmibeat.com": {
+ "heuristicAction": "allow"
+ },
+ "finam.ru": {
+ "heuristicAction": "allow"
+ },
+ "financialjuice.com": {
+ "heuristicAction": "allow"
+ },
+ "finder.com.au": {
+ "heuristicAction": "allow"
+ },
+ "firebaselogging.googleapis.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "firstimpression.io": {
+ "heuristicAction": "block"
+ },
+ "fiverr.com": {
+ "heuristicAction": "allow"
+ },
+ "fivetran.com": {
+ "heuristicAction": "allow"
+ },
+ "fkw.com": {
+ "heuristicAction": "allow"
+ },
+ "flashtalking.com": {
+ "heuristicAction": "block"
+ },
+ "flipp.com": {
+ "heuristicAction": "allow"
+ },
+ "flocktory.com": {
+ "heuristicAction": "block"
+ },
+ "flowtype.press": {
+ "heuristicAction": "allow"
+ },
+ "fls.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602298978063
+ },
+ "flw.li": {
+ "heuristicAction": "allow"
+ },
+ "focas.jp": {
+ "heuristicAction": "allow"
+ },
+ "fontplus.jp": {
+ "heuristicAction": "allow"
+ },
+ "fonts.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "fooby.ch": {
+ "heuristicAction": "allow"
+ },
+ "foodnetwork.com": {
+ "heuristicAction": "allow"
+ },
+ "force.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "foreks.com": {
+ "heuristicAction": "allow"
+ },
+ "foresee.com": {
+ "heuristicAction": "allow"
+ },
+ "forms.hubspot.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "formstack.io": {
+ "heuristicAction": "allow"
+ },
+ "fospha.com": {
+ "heuristicAction": "allow"
+ },
+ "foursquare.com": {
+ "heuristicAction": "allow"
+ },
+ "fout.jp": {
+ "heuristicAction": "block"
+ },
+ "fox.com": {
+ "heuristicAction": "allow"
+ },
+ "foxycart.com": {
+ "heuristicAction": "allow"
+ },
+ "fp-cdn.azureedge.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "fppressa.ru": {
+ "heuristicAction": "allow"
+ },
+ "franecki.net": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601943091186
+ },
+ "franeski.net": {
+ "heuristicAction": "allow"
+ },
+ "freelancer.com": {
+ "heuristicAction": "allow"
+ },
+ "freeskreen.com": {
+ "heuristicAction": "block"
+ },
+ "freespee.com": {
+ "heuristicAction": "allow"
+ },
+ "freevisitorcounters.com": {
+ "heuristicAction": "allow"
+ },
+ "freshchat.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "freshdesk.com": {
+ "heuristicAction": "allow"
+ },
+ "freshrelevance.com": {
+ "heuristicAction": "allow"
+ },
+ "fresnobee.com": {
+ "heuristicAction": "allow"
+ },
+ "friendbuy.com": {
+ "heuristicAction": "allow"
+ },
+ "frosmo.com": {
+ "heuristicAction": "allow"
+ },
+ "fstrk.net": {
+ "heuristicAction": "allow"
+ },
+ "fujitsu-webmart.com": {
+ "heuristicAction": "allow"
+ },
+ "fundingchoicesmessages.google.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601995078989
+ },
+ "fundraiseup.com": {
+ "heuristicAction": "allow"
+ },
+ "fusiontables.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "fwmrm.net": {
+ "heuristicAction": "block"
+ },
+ "fx678img.com": {
+ "heuristicAction": "allow"
+ },
+ "fxgate.baidu.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602267253256
+ },
+ "fyi-marketing.com": {
+ "heuristicAction": "allow"
+ },
+ "fyrsbckgi-c.global.ssl.fastly.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "g.3gl.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602335264413
+ },
+ "g.cn.miaozhen.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602062702205
+ },
+ "g.ezoic.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601926536970
+ },
+ "g2.gumgum.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602082400987
+ },
+ "gadasource.storage.googleapis.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "gamania.com": {
+ "heuristicAction": "allow"
+ },
+ "gameanalytics.dev": {
+ "heuristicAction": "allow"
+ },
+ "gammaplatform.com": {
+ "heuristicAction": "block"
+ },
+ "gannett-d.openx.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602095868386
+ },
+ "garanti.com.tr": {
+ "heuristicAction": "allow"
+ },
+ "gars.hit.gemius.pl": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602151845116
+ },
+ "gator.io": {
+ "heuristicAction": "allow"
+ },
+ "gatr.hit.gemius.pl": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602181888460
+ },
+ "gaua.hit.gemius.pl": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602237830028
+ },
+ "gaug.es": {
+ "heuristicAction": "allow"
+ },
+ "gazeta.pl": {
+ "heuristicAction": "allow"
+ },
+ "gcimetrics.com": {
+ "heuristicAction": "allow"
+ },
+ "gd.gov.cn": {
+ "heuristicAction": "allow"
+ },
+ "gdz.work": {
+ "heuristicAction": "allow"
+ },
+ "geekbuying.com": {
+ "heuristicAction": "allow"
+ },
+ "geetest.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "geilicdn.com": {
+ "heuristicAction": "allow"
+ },
+ "geistm.com": {
+ "heuristicAction": "block"
+ },
+ "gelbmann.info": {
+ "heuristicAction": "allow"
+ },
+ "geminimedia-eg.com": {
+ "heuristicAction": "allow"
+ },
+ "gemius.pl": {
+ "heuristicAction": "block"
+ },
+ "generaltracking.de": {
+ "heuristicAction": "allow"
+ },
+ "genieesspv.jp": {
+ "heuristicAction": "allow"
+ },
+ "geniusmonkey.com": {
+ "heuristicAction": "allow"
+ },
+ "geofli.com": {
+ "heuristicAction": "allow"
+ },
+ "geoip.insticator.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602061367261
+ },
+ "geotrust.com": {
+ "heuristicAction": "allow"
+ },
+ "get4click.ru": {
+ "heuristicAction": "allow"
+ },
+ "getadmiral.com": {
+ "heuristicAction": "allow"
+ },
+ "getapp.com": {
+ "heuristicAction": "allow"
+ },
+ "getblue.io": {
+ "heuristicAction": "allow"
+ },
+ "getblueshift.com": {
+ "heuristicAction": "block"
+ },
+ "getclicky.com": {
+ "heuristicAction": "block"
+ },
+ "getcreditone.com": {
+ "heuristicAction": "allow"
+ },
+ "getdrip.com": {
+ "heuristicAction": "block"
+ },
+ "getletterpress.com": {
+ "heuristicAction": "block"
+ },
+ "getnshow.com": {
+ "heuristicAction": "allow"
+ },
+ "getrockerbox.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601911242469
+ },
+ "getsmartcontent.com": {
+ "heuristicAction": "allow"
+ },
+ "getway.biz": {
+ "heuristicAction": "allow"
+ },
+ "gg.faromen.online": {
+ "heuristicAction": "allow"
+ },
+ "gh-base.com": {
+ "heuristicAction": "allow"
+ },
+ "ghb.adtelligent.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601993374434
+ },
+ "ghmtr.hit.gemius.pl": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601977732129
+ },
+ "gigazine.asia": {
+ "heuristicAction": "allow"
+ },
+ "gigya.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "gimp.org": {
+ "heuristicAction": "allow"
+ },
+ "giraff.io": {
+ "heuristicAction": "block"
+ },
+ "gitee.com": {
+ "heuristicAction": "allow"
+ },
+ "github.com": {
+ "heuristicAction": "allow"
+ },
+ "gixioanalytics.com": {
+ "heuristicAction": "allow"
+ },
+ "gjirafa.com": {
+ "heuristicAction": "allow"
+ },
+ "glamour.com": {
+ "heuristicAction": "block"
+ },
+ "glassboxdigital.io": {
+ "heuristicAction": "block"
+ },
+ "glassdoor.com": {
+ "heuristicAction": "allow"
+ },
+ "gleam.io": {
+ "heuristicAction": "block"
+ },
+ "global-e.com": {
+ "heuristicAction": "allow"
+ },
+ "globalwebindex.net": {
+ "heuristicAction": "block"
+ },
+ "globo.com": {
+ "heuristicAction": "allow"
+ },
+ "gmossp-sp.jp": {
+ "heuristicAction": "block"
+ },
+ "go.activecalendar.com": {
+ "heuristicAction": "allow"
+ },
+ "go.bebi.com": {
+ "heuristicAction": "block"
+ },
+ "go.com": {
+ "heuristicAction": "block"
+ },
+ "go.ezoic.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602149490039
+ },
+ "godaddy.com": {
+ "heuristicAction": "block"
+ },
+ "goepson.com": {
+ "heuristicAction": "allow"
+ },
+ "gogocdn.net": {
+ "heuristicAction": "allow"
+ },
+ "goinflow.com": {
+ "heuristicAction": "allow"
+ },
+ "goo.ne.jp": {
+ "heuristicAction": "allow"
+ },
+ "google-analytics.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602152953782
+ },
+ "google.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602051816434
+ },
+ "google.com.pk": {
+ "heuristicAction": "allow"
+ },
+ "googleads.g.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601934731697
+ },
+ "googleadservices.com": {
+ "heuristicAction": "allow"
+ },
+ "goop.com": {
+ "heuristicAction": "allow"
+ },
+ "gosuslugi.ru": {
+ "heuristicAction": "allow"
+ },
+ "gotprofits.com": {
+ "heuristicAction": "allow"
+ },
+ "goutee.top": {
+ "heuristicAction": "allow"
+ },
+ "governing.com": {
+ "heuristicAction": "allow"
+ },
+ "gq.com": {
+ "heuristicAction": "block"
+ },
+ "grahammedia-d.openx.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602383448244
+ },
+ "graizoah.com": {
+ "heuristicAction": "allow"
+ },
+ "gravito.net": {
+ "heuristicAction": "allow"
+ },
+ "grctech.com": {
+ "heuristicAction": "allow"
+ },
+ "green-red.com": {
+ "heuristicAction": "allow"
+ },
+ "grid.bidswitch.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601990443489
+ },
+ "gridsumdissector.com": {
+ "heuristicAction": "block"
+ },
+ "groovinads.com": {
+ "heuristicAction": "block"
+ },
+ "group-ib.ru": {
+ "heuristicAction": "allow"
+ },
+ "groupondata.com": {
+ "heuristicAction": "allow"
+ },
+ "groups.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "growingio.com": {
+ "heuristicAction": "block"
+ },
+ "grumft.com": {
+ "heuristicAction": "allow"
+ },
+ "grupaonet.pl": {
+ "heuristicAction": "allow"
+ },
+ "grupapino.pl": {
+ "heuristicAction": "allow"
+ },
+ "grupoelcorteingles.es": {
+ "heuristicAction": "allow"
+ },
+ "gsoi.fr": {
+ "heuristicAction": "allow"
+ },
+ "gsspat.jp": {
+ "heuristicAction": "block"
+ },
+ "gssprt.jp": {
+ "heuristicAction": "block"
+ },
+ "gtags.net": {
+ "heuristicAction": "block"
+ },
+ "guess.mediav.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601919942237
+ },
+ "gum.criteo.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602237556932
+ },
+ "gumgum.com": {
+ "heuristicAction": "block"
+ },
+ "guoshipartners.com": {
+ "heuristicAction": "allow"
+ },
+ "gwdg.de": {
+ "heuristicAction": "allow"
+ },
+ "gwmtracking.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602203373944
+ },
+ "h.online-metrix.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601979507397
+ },
+ "haaretz.co.il": {
+ "heuristicAction": "allow"
+ },
+ "hactar.is": {
+ "heuristicAction": "allow"
+ },
+ "hainanfp.com": {
+ "heuristicAction": "allow"
+ },
+ "halfclub.com": {
+ "heuristicAction": "allow"
+ },
+ "hanmaker.com": {
+ "heuristicAction": "allow"
+ },
+ "hao123.com": {
+ "heuristicAction": "allow"
+ },
+ "hao123img.com": {
+ "heuristicAction": "allow"
+ },
+ "harrisinteractive.eu": {
+ "heuristicAction": "allow"
+ },
+ "hasbroapps.com": {
+ "heuristicAction": "allow"
+ },
+ "hatena.ne.jp": {
+ "heuristicAction": "allow"
+ },
+ "hb-api.omnitagjs.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602354917196
+ },
+ "hb.adscale.de": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602056789456
+ },
+ "hb.districtm.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602034880855
+ },
+ "hb.emxdgt.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602321299708
+ },
+ "hb.hb.selectmedia.asia": {
+ "heuristicAction": "allow"
+ },
+ "hb.undertone.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602205722690
+ },
+ "hbabit.com": {
+ "heuristicAction": "allow"
+ },
+ "hbc.com": {
+ "heuristicAction": "allow"
+ },
+ "hbopenbid.pubmatic.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602166340014
+ },
+ "hbx.media.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601933742853
+ },
+ "hcaptcha.com": {
+ "heuristicAction": "allow"
+ },
+ "headbidder.net": {
+ "heuristicAction": "allow"
+ },
+ "healthunlocked.com": {
+ "heuristicAction": "allow"
+ },
+ "heapanalytics.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602078647969
+ },
+ "hellorf.com": {
+ "heuristicAction": "allow"
+ },
+ "helpdaohang1.ksmobile.com": {
+ "heuristicAction": "allow"
+ },
+ "heraldm.com": {
+ "heuristicAction": "allow"
+ },
+ "hexagon-analytics.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601839741096
+ },
+ "hgbn.network": {
+ "heuristicAction": "allow"
+ },
+ "hgtv.com": {
+ "heuristicAction": "block"
+ },
+ "hhcdn.ru": {
+ "heuristicAction": "allow"
+ },
+ "highlow.net": {
+ "heuristicAction": "allow"
+ },
+ "highwire.org": {
+ "heuristicAction": "block"
+ },
+ "hihainan.info": {
+ "heuristicAction": "allow"
+ },
+ "hiido.com": {
+ "heuristicAction": "block"
+ },
+ "hilton.com": {
+ "heuristicAction": "allow"
+ },
+ "hindustantimes.com": {
+ "heuristicAction": "block"
+ },
+ "hinet.net": {
+ "heuristicAction": "allow"
+ },
+ "hiphotos.baidu.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "histats.com": {
+ "heuristicAction": "block"
+ },
+ "hitslink.com": {
+ "heuristicAction": "allow"
+ },
+ "hive.co": {
+ "heuristicAction": "allow"
+ },
+ "hket.com": {
+ "heuristicAction": "allow"
+ },
+ "hketgroup.com": {
+ "heuristicAction": "allow"
+ },
+ "hlserve.com": {
+ "heuristicAction": "allow"
+ },
+ "hm.baidu.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601900616410
+ },
+ "hmhost.co.uk": {
+ "heuristicAction": "allow"
+ },
+ "holder.com.ua": {
+ "heuristicAction": "block"
+ },
+ "holmesmind.com": {
+ "heuristicAction": "allow"
+ },
+ "homeway.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "hosted-inin.com": {
+ "heuristicAction": "allow"
+ },
+ "hot-mob.com": {
+ "heuristicAction": "allow"
+ },
+ "hotelscombined.com": {
+ "heuristicAction": "allow"
+ },
+ "hotwire.com": {
+ "heuristicAction": "allow"
+ },
+ "hq3x.com": {
+ "heuristicAction": "allow"
+ },
+ "hr.hit.gemius.pl": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602129775791
+ },
+ "hsbc.com.hk": {
+ "heuristicAction": "allow"
+ },
+ "htcvive.com": {
+ "heuristicAction": "allow"
+ },
+ "htlb.casalemedia.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602024321704
+ },
+ "hton.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "hubpd.com": {
+ "heuristicAction": "allow"
+ },
+ "hubspot.com": {
+ "heuristicAction": "block"
+ },
+ "hujiang.com": {
+ "heuristicAction": "allow"
+ },
+ "hulu.com": {
+ "heuristicAction": "allow"
+ },
+ "huluqa.com": {
+ "heuristicAction": "allow"
+ },
+ "humcommerce.com": {
+ "heuristicAction": "allow"
+ },
+ "hurpass.com": {
+ "heuristicAction": "allow"
+ },
+ "hushly.com": {
+ "heuristicAction": "block"
+ },
+ "hybrid.ai": {
+ "heuristicAction": "block"
+ },
+ "hyros.com": {
+ "heuristicAction": "allow"
+ },
+ "i-mobile.co.jp": {
+ "heuristicAction": "block"
+ },
+ "i.connectad.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601950923438
+ },
+ "i.prcdn.co": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602142939005
+ },
+ "i.ua": {
+ "heuristicAction": "allow"
+ },
+ "i115008.net": {
+ "heuristicAction": "allow"
+ },
+ "i347961.net": {
+ "heuristicAction": "allow"
+ },
+ "iadvize.com": {
+ "heuristicAction": "block"
+ },
+ "iasds01.com": {
+ "heuristicAction": "allow"
+ },
+ "ib-ibi.com": {
+ "heuristicAction": "allow"
+ },
+ "ib.adnxs.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602058704649
+ },
+ "ibclick.stream": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602067793428
+ },
+ "ibillboard.com": {
+ "heuristicAction": "allow"
+ },
+ "ibt.com": {
+ "heuristicAction": "allow"
+ },
+ "ice.360yield.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602257154062
+ },
+ "icon.cnzz.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602060496911
+ },
+ "iconmedia.containers.piwik.pro": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602136201860
+ },
+ "iconnode.com": {
+ "heuristicAction": "allow"
+ },
+ "id5-sync.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601847755643
+ },
+ "idealmedia.io": {
+ "heuristicAction": "allow"
+ },
+ "ideaplus.mk": {
+ "heuristicAction": "allow"
+ },
+ "idio.co": {
+ "heuristicAction": "block"
+ },
+ "idsync.rlcdn.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601893974937
+ },
+ "idx.liadm.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602207345216
+ },
+ "iesnare.com": {
+ "heuristicAction": "block"
+ },
+ "ign.com": {
+ "heuristicAction": "allow"
+ },
+ "igodigital.com": {
+ "heuristicAction": "block"
+ },
+ "iheart.com": {
+ "heuristicAction": "allow"
+ },
+ "iherb.com": {
+ "heuristicAction": "allow"
+ },
+ "ijento.com": {
+ "heuristicAction": "allow"
+ },
+ "iljmp.com": {
+ "heuristicAction": "allow"
+ },
+ "im-apps.net": {
+ "heuristicAction": "block"
+ },
+ "image2.pubmatic.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602002545841
+ },
+ "image8.pubmatic.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601943701706
+ },
+ "imagesrv.adition.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "imedao.com": {
+ "heuristicAction": "allow"
+ },
+ "imedia.cz": {
+ "heuristicAction": "block"
+ },
+ "img-fotki.yandex.ru": {
+ "heuristicAction": "cookieblock"
+ },
+ "img.ak.impact-ad.jp": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601914355849
+ },
+ "img.youtube.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "img1.qq.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602277301385
+ },
+ "imgm5.cnmo-img.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "imgsa.baidu.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "imgsrc.baidu.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "imhd.io": {
+ "heuristicAction": "block"
+ },
+ "imi.chat": {
+ "heuristicAction": "allow"
+ },
+ "impact-ad.jp": {
+ "heuristicAction": "block"
+ },
+ "impact.com": {
+ "heuristicAction": "allow"
+ },
+ "implishing.club": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602190394831
+ },
+ "impression.link": {
+ "heuristicAction": "allow"
+ },
+ "imrworldwide.com": {
+ "heuristicAction": "block"
+ },
+ "imspublishergroup.com": {
+ "heuristicAction": "allow"
+ },
+ "in-page-push.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602158534716
+ },
+ "in.wzrkt.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601988518138
+ },
+ "in.xspadvertising.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602193965892
+ },
+ "inbenta.com": {
+ "heuristicAction": "allow"
+ },
+ "indacolive.com": {
+ "heuristicAction": "allow"
+ },
+ "indapass.hu": {
+ "heuristicAction": "allow"
+ },
+ "indeed.com": {
+ "heuristicAction": "allow"
+ },
+ "india.com": {
+ "heuristicAction": "allow"
+ },
+ "indianexpress.com": {
+ "heuristicAction": "allow"
+ },
+ "indoleads.com": {
+ "heuristicAction": "allow"
+ },
+ "infeed.id": {
+ "heuristicAction": "block"
+ },
+ "infinigrow.com": {
+ "heuristicAction": "allow"
+ },
+ "infinity-tracking.net": {
+ "heuristicAction": "block"
+ },
+ "infolinks.com": {
+ "heuristicAction": "allow"
+ },
+ "informer.yandex.ru": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602205708201
+ },
+ "informz.net": {
+ "heuristicAction": "block"
+ },
+ "infosys.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601970262601
+ },
+ "infusionsoft.app": {
+ "heuristicAction": "allow"
+ },
+ "infusionsoft.com": {
+ "heuristicAction": "allow"
+ },
+ "ingage.tech": {
+ "heuristicAction": "allow"
+ },
+ "ingrammicro.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602072736093
+ },
+ "injapan.com": {
+ "heuristicAction": "allow"
+ },
+ "inmobi.net": {
+ "heuristicAction": "allow"
+ },
+ "inmoment.com": {
+ "heuristicAction": "allow"
+ },
+ "innity.com": {
+ "heuristicAction": "block"
+ },
+ "innocraft.cloud": {
+ "heuristicAction": "allow"
+ },
+ "innogamescdn.com": {
+ "heuristicAction": "allow"
+ },
+ "innologica.com": {
+ "heuristicAction": "allow"
+ },
+ "innovid.com": {
+ "heuristicAction": "block"
+ },
+ "inpagepush.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602274122689
+ },
+ "inpwrd.net": {
+ "heuristicAction": "allow"
+ },
+ "inq.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "insent.ai": {
+ "heuristicAction": "allow"
+ },
+ "inside-graph.com": {
+ "heuristicAction": "block"
+ },
+ "insider.com": {
+ "heuristicAction": "allow"
+ },
+ "insight.adsrvr.org": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602017675765
+ },
+ "insightexpressai.com": {
+ "heuristicAction": "block"
+ },
+ "instabot.io": {
+ "heuristicAction": "allow"
+ },
+ "instagram.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "insticator.com": {
+ "heuristicAction": "block"
+ },
+ "insurads.com": {
+ "heuristicAction": "block"
+ },
+ "intellitxt.com": {
+ "heuristicAction": "allow"
+ },
+ "intent-apps.com": {
+ "heuristicAction": "allow"
+ },
+ "intent.ai": {
+ "heuristicAction": "allow"
+ },
+ "intentiq.com": {
+ "heuristicAction": "block"
+ },
+ "intentmedia.net": {
+ "heuristicAction": "block"
+ },
+ "intentsify.io": {
+ "heuristicAction": "allow"
+ },
+ "intergient.com": {
+ "heuristicAction": "block"
+ },
+ "internetbrands.com": {
+ "heuristicAction": "block"
+ },
+ "intljs.rmtag.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602006223363
+ },
+ "investingchannel.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "investis.com": {
+ "heuristicAction": "block"
+ },
+ "investorwords.com": {
+ "heuristicAction": "allow"
+ },
+ "invl.co": {
+ "heuristicAction": "allow"
+ },
+ "invttjs.com.br": {
+ "heuristicAction": "allow"
+ },
+ "ioam.de": {
+ "heuristicAction": "block"
+ },
+ "iocnt.net": {
+ "heuristicAction": "block"
+ },
+ "ip-label.net": {
+ "heuristicAction": "allow"
+ },
+ "ipac.ctnsnet.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602051374101
+ },
+ "ipchaxun.com": {
+ "heuristicAction": "allow"
+ },
+ "iperceptions.com": {
+ "heuristicAction": "block"
+ },
+ "ipgeolocation.io": {
+ "heuristicAction": "allow"
+ },
+ "ipify.org": {
+ "heuristicAction": "allow"
+ },
+ "ipinyou.com": {
+ "heuristicAction": "allow"
+ },
+ "ipredictive.com": {
+ "heuristicAction": "block"
+ },
+ "ipvanish.com": {
+ "heuristicAction": "allow"
+ },
+ "iqair-international.myshopify.com": {
+ "heuristicAction": "allow"
+ },
+ "iqoption.com": {
+ "heuristicAction": "allow"
+ },
+ "irs.tools.investis.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602185835514
+ },
+ "irs03.com": {
+ "heuristicAction": "block"
+ },
+ "isanook.com": {
+ "heuristicAction": "allow"
+ },
+ "islamist-movements.com": {
+ "heuristicAction": "allow"
+ },
+ "ispot.tv": {
+ "heuristicAction": "block"
+ },
+ "issuu.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "istruzione.it": {
+ "heuristicAction": "allow"
+ },
+ "iteratehq.com": {
+ "heuristicAction": "block"
+ },
+ "itmedia.co.jp": {
+ "heuristicAction": "allow"
+ },
+ "itmedia.jp": {
+ "heuristicAction": "allow"
+ },
+ "ivcbrasil.org.br": {
+ "heuristicAction": "block"
+ },
+ "ivideosmart.com": {
+ "heuristicAction": "block"
+ },
+ "ivx.cn": {
+ "heuristicAction": "allow"
+ },
+ "ixiaa.com": {
+ "heuristicAction": "allow"
+ },
+ "izooto.com": {
+ "heuristicAction": "block"
+ },
+ "j.6sc.co": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602031048697
+ },
+ "jabmo.app": {
+ "heuristicAction": "allow"
+ },
+ "jads.co": {
+ "heuristicAction": "allow"
+ },
+ "jadserve.postrelease.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602376568598
+ },
+ "janrainsso.com": {
+ "heuristicAction": "block"
+ },
+ "jassfederal.ch": {
+ "heuristicAction": "allow"
+ },
+ "jd.com": {
+ "heuristicAction": "allow"
+ },
+ "jhu.edu": {
+ "heuristicAction": "allow"
+ },
+ "jilt.com": {
+ "heuristicAction": "allow"
+ },
+ "jiosaavn.com": {
+ "heuristicAction": "allow"
+ },
+ "jivosite.com": {
+ "heuristicAction": "allow"
+ },
+ "jixie.io": {
+ "heuristicAction": "allow"
+ },
+ "jnqsge.net": {
+ "heuristicAction": "allow"
+ },
+ "jobat.be": {
+ "heuristicAction": "allow"
+ },
+ "jobs.thejobnetwork.com": {
+ "heuristicAction": "allow"
+ },
+ "journalmedia.ie": {
+ "heuristicAction": "allow"
+ },
+ "jrs5.com": {
+ "heuristicAction": "allow"
+ },
+ "js.adscale.de": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602013246334
+ },
+ "js.adsrvr.org": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602367042150
+ },
+ "js.agkn.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601879971284
+ },
+ "js.center.io": {
+ "heuristicAction": "allow"
+ },
+ "js.gleam.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601961463103
+ },
+ "js.gumgum.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602245489700
+ },
+ "js.hubspot.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "js.matheranalytics.com": {
+ "dnt": true,
+ "heuristicAction": "",
+ "nextUpdateTime": 1602130658236
+ },
+ "js.rating-widget.com": {
+ "heuristicAction": "allow"
+ },
+ "js.rfp.fout.jp": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602064806470
+ },
+ "jsc.adskeeper.co.uk": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601936670745
+ },
+ "jsc.lentainform.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601942393057
+ },
+ "jsc.mgid.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601984865895
+ },
+ "jschina.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "jsdelivr.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "jsn.24smi.net": {
+ "heuristicAction": "allow"
+ },
+ "jsrdn.com": {
+ "heuristicAction": "block"
+ },
+ "juicyads.com": {
+ "heuristicAction": "allow"
+ },
+ "justpremium.com": {
+ "heuristicAction": "block"
+ },
+ "jwplayer.com": {
+ "heuristicAction": "block"
+ },
+ "jwpltx.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "jxtrackers.azurewebsites.net": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602237469796
+ },
+ "kaipuyun.cn": {
+ "heuristicAction": "block"
+ },
+ "kaixin001.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "kakao.com": {
+ "heuristicAction": "allow"
+ },
+ "kameleoon.eu": {
+ "heuristicAction": "block"
+ },
+ "kampyle.com": {
+ "heuristicAction": "allow"
+ },
+ "kanade-ad.net": {
+ "heuristicAction": "allow"
+ },
+ "kaprila.com": {
+ "heuristicAction": "block"
+ },
+ "kaptcha.com": {
+ "heuristicAction": "block"
+ },
+ "kargo.com": {
+ "heuristicAction": "block"
+ },
+ "karpishe.com": {
+ "heuristicAction": "allow"
+ },
+ "kartra.com": {
+ "heuristicAction": "allow"
+ },
+ "kaspersky-labs.com": {
+ "heuristicAction": "allow"
+ },
+ "kaxsdc.com": {
+ "heuristicAction": "allow"
+ },
+ "kayak.com": {
+ "heuristicAction": "allow"
+ },
+ "kcsfile.com": {
+ "heuristicAction": "allow"
+ },
+ "kexin001.com": {
+ "heuristicAction": "allow"
+ },
+ "keybank.demdex.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601920825832
+ },
+ "keybank.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601946937119
+ },
+ "keybankassociation.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602080701126
+ },
+ "keywee.co": {
+ "heuristicAction": "block"
+ },
+ "kf5.com": {
+ "heuristicAction": "allow"
+ },
+ "kh.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "khms0.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "khms1.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "khms2.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "khms3.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "khms4.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "kinsta.com": {
+ "heuristicAction": "allow"
+ },
+ "kivpro.com": {
+ "heuristicAction": "allow"
+ },
+ "kl-youniverse.com": {
+ "heuristicAction": "block"
+ },
+ "klangoo.com": {
+ "heuristicAction": "allow"
+ },
+ "klarnaservices.com": {
+ "heuristicAction": "allow"
+ },
+ "klarnauserservices.com": {
+ "heuristicAction": "allow"
+ },
+ "kleecks.com": {
+ "heuristicAction": "allow"
+ },
+ "klick2contact.com": {
+ "heuristicAction": "allow"
+ },
+ "knet.cn": {
+ "heuristicAction": "block"
+ },
+ "knnlab.com": {
+ "heuristicAction": "allow"
+ },
+ "knotch.it": {
+ "heuristicAction": "allow"
+ },
+ "koddi.com": {
+ "heuristicAction": "allow"
+ },
+ "kompas.com": {
+ "heuristicAction": "block"
+ },
+ "kooora.ws": {
+ "heuristicAction": "allow"
+ },
+ "kpcdn.net": {
+ "heuristicAction": "allow"
+ },
+ "kraken.com": {
+ "heuristicAction": "allow"
+ },
+ "krxd.net": {
+ "heuristicAction": "block"
+ },
+ "ksmobile.com": {
+ "heuristicAction": "allow"
+ },
+ "kwanzoo.com": {
+ "heuristicAction": "allow"
+ },
+ "labocleo.org": {
+ "heuristicAction": "allow"
+ },
+ "labs.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "ladbible.com": {
+ "heuristicAction": "allow"
+ },
+ "ladsp.com": {
+ "heuristicAction": "block"
+ },
+ "lan.com": {
+ "heuristicAction": "allow"
+ },
+ "landc.co.uk": {
+ "heuristicAction": "allow"
+ },
+ "landsend.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602240776449
+ },
+ "lasteventf-tm.everesttech.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601970932797
+ },
+ "latinongroup.com": {
+ "heuristicAction": "allow"
+ },
+ "leadexpert.pl": {
+ "heuristicAction": "allow"
+ },
+ "leadlab.click": {
+ "heuristicAction": "allow"
+ },
+ "leadlander.com": {
+ "heuristicAction": "block"
+ },
+ "leadquizzes.com": {
+ "heuristicAction": "allow"
+ },
+ "leadspace.com": {
+ "heuristicAction": "allow"
+ },
+ "leadsrx.com": {
+ "heuristicAction": "allow"
+ },
+ "leady.com": {
+ "heuristicAction": "allow"
+ },
+ "leafly.ca": {
+ "heuristicAction": "allow"
+ },
+ "ledger.com": {
+ "heuristicAction": "allow"
+ },
+ "leju.com": {
+ "heuristicAction": "allow"
+ },
+ "lemnisk.co": {
+ "heuristicAction": "allow"
+ },
+ "lennyletter.com": {
+ "heuristicAction": "block"
+ },
+ "lenovo.com": {
+ "heuristicAction": "allow"
+ },
+ "lentainform.com": {
+ "heuristicAction": "block"
+ },
+ "letv.com": {
+ "heuristicAction": "allow"
+ },
+ "lexmark.d2.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601950960219
+ },
+ "lexmark.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602009697216
+ },
+ "lfeeder.com": {
+ "heuristicAction": "allow"
+ },
+ "liadm.com": {
+ "heuristicAction": "block"
+ },
+ "libs.coremetrics.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602121256610
+ },
+ "liebao.cn": {
+ "heuristicAction": "allow"
+ },
+ "lietou-static.com": {
+ "heuristicAction": "allow"
+ },
+ "lightboxcdn.com": {
+ "heuristicAction": "block"
+ },
+ "lightinthebox.com": {
+ "heuristicAction": "allow"
+ },
+ "lijit.com": {
+ "heuristicAction": "block"
+ },
+ "likeevideo.com": {
+ "heuristicAction": "allow"
+ },
+ "likr.com.tw": {
+ "heuristicAction": "block"
+ },
+ "line.me": {
+ "heuristicAction": "block"
+ },
+ "linkback.contentsfeed.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601961218192
+ },
+ "linkconnector.com": {
+ "heuristicAction": "block"
+ },
+ "linkedin.com": {
+ "heuristicAction": "block"
+ },
+ "linker.hr": {
+ "heuristicAction": "allow"
+ },
+ "linkonlineworld.com": {
+ "heuristicAction": "allow"
+ },
+ "linkprice.com": {
+ "heuristicAction": "allow"
+ },
+ "linksynergy.com": {
+ "heuristicAction": "block"
+ },
+ "list-manage.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "listrakbi.com": {
+ "heuristicAction": "block"
+ },
+ "literatumonline.com": {
+ "heuristicAction": "allow"
+ },
+ "liuzhuni.com": {
+ "heuristicAction": "allow"
+ },
+ "live2support.com": {
+ "heuristicAction": "allow"
+ },
+ "livechatinc.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "livejasmin.com": {
+ "heuristicAction": "allow"
+ },
+ "liveperson.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "liverpool.demdex.net.demdex.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602381421777
+ },
+ "livetex.me": {
+ "heuristicAction": "allow"
+ },
+ "livetex.ru": {
+ "heuristicAction": "allow"
+ },
+ "lkqd.net": {
+ "heuristicAction": "block"
+ },
+ "lmiutil.com": {
+ "heuristicAction": "allow"
+ },
+ "lndata.com": {
+ "heuristicAction": "allow"
+ },
+ "load.sumo.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602042602464
+ },
+ "loadercdn.net": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602225591817
+ },
+ "loadus.exelator.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602226276007
+ },
+ "loc.gov": {
+ "heuristicAction": "allow"
+ },
+ "localytics.com": {
+ "heuristicAction": "allow"
+ },
+ "lockerdome.com": {
+ "heuristicAction": "allow"
+ },
+ "log.pinterest.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602213847671
+ },
+ "logger.co.kr": {
+ "heuristicAction": "allow"
+ },
+ "login.dotomi.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602037890996
+ },
+ "loginfra.com": {
+ "heuristicAction": "allow"
+ },
+ "loginhood.io": {
+ "heuristicAction": "block"
+ },
+ "loginside.co.kr": {
+ "heuristicAction": "allow"
+ },
+ "logitech.com": {
+ "heuristicAction": "allow"
+ },
+ "logly.co.jp": {
+ "heuristicAction": "block"
+ },
+ "logo.samandehi.ir": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602201489957
+ },
+ "logsss.com": {
+ "heuristicAction": "allow"
+ },
+ "logws1312.ati-host.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602250297502
+ },
+ "loop11.com": {
+ "heuristicAction": "allow"
+ },
+ "loopassets.net": {
+ "heuristicAction": "allow"
+ },
+ "loopgift.com": {
+ "heuristicAction": "block"
+ },
+ "lp4.io": {
+ "heuristicAction": "block"
+ },
+ "lpage.co": {
+ "heuristicAction": "allow"
+ },
+ "lpoint.com": {
+ "heuristicAction": "allow"
+ },
+ "lps.lpages.co": {
+ "heuristicAction": "allow"
+ },
+ "lsurl.cn": {
+ "heuristicAction": "allow"
+ },
+ "ltwebstatic.com": {
+ "heuristicAction": "allow"
+ },
+ "lwcal.com": {
+ "heuristicAction": "allow"
+ },
+ "lww.com": {
+ "heuristicAction": "block"
+ },
+ "lytics.io": {
+ "heuristicAction": "block"
+ },
+ "lz-pub-ads.com": {
+ "heuristicAction": "allow"
+ },
+ "m.giraff.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602063382046
+ },
+ "m.stripe.network": {
+ "heuristicAction": "cookieblock"
+ },
+ "m6r.eu": {
+ "heuristicAction": "allow"
+ },
+ "maases.com": {
+ "heuristicAction": "allow"
+ },
+ "mabping.chartbeat.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602230398929
+ },
+ "macromill.com": {
+ "heuristicAction": "block"
+ },
+ "mad-docs.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "maerskline.com": {
+ "heuristicAction": "allow"
+ },
+ "magnetmail.net": {
+ "heuristicAction": "block"
+ },
+ "mail.ru": {
+ "heuristicAction": "cookieblock"
+ },
+ "mailfire.io": {
+ "heuristicAction": "block"
+ },
+ "mailmunch.co": {
+ "heuristicAction": "allow"
+ },
+ "mainetodaymedia.com": {
+ "heuristicAction": "allow"
+ },
+ "mantisadnetwork.com": {
+ "heuristicAction": "block"
+ },
+ "mapixl.com": {
+ "heuristicAction": "allow"
+ },
+ "mapquestapi.com": {
+ "heuristicAction": "allow"
+ },
+ "maps-api-ssl.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "maps.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "mapsengine.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "marchex.io": {
+ "heuristicAction": "allow"
+ },
+ "marinsm.com": {
+ "heuristicAction": "block"
+ },
+ "marketdatasystems.com": {
+ "heuristicAction": "allow"
+ },
+ "marketingautomation.services": {
+ "heuristicAction": "allow"
+ },
+ "marketlinc.com": {
+ "heuristicAction": "block"
+ },
+ "marketo.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "marketperf.com": {
+ "heuristicAction": "allow"
+ },
+ "marktplaats.net": {
+ "heuristicAction": "allow"
+ },
+ "massrelevance.com": {
+ "heuristicAction": "allow"
+ },
+ "mat1.qq.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601929422756
+ },
+ "match.adsrvr.org": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602215627100
+ },
+ "match.prod.bidr.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601922249940
+ },
+ "matchid.adfox.yandex.ru": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602280223811
+ },
+ "matchtv.ru": {
+ "heuristicAction": "allow"
+ },
+ "mateti.net": {
+ "heuristicAction": "allow"
+ },
+ "matheranalytics.com": {
+ "heuristicAction": "block"
+ },
+ "mathtag.com": {
+ "heuristicAction": "block"
+ },
+ "matomo.cloud": {
+ "heuristicAction": "allow"
+ },
+ "maven.io": {
+ "heuristicAction": "block"
+ },
+ "mavencoalition.io": {
+ "heuristicAction": "block"
+ },
+ "maxmind.com": {
+ "heuristicAction": "allow"
+ },
+ "maxymiser.net": {
+ "heuristicAction": "block"
+ },
+ "mc.admetrica.ru": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602220261900
+ },
+ "mc.webvisor.org": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602340801801
+ },
+ "mc.yandex.ru": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602191356302
+ },
+ "mcclatchy.com": {
+ "heuristicAction": "block"
+ },
+ "mcclatchy.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602266371270
+ },
+ "mcclatchy.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602232665786
+ },
+ "mcp-media5.anvato.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "mdgms.com": {
+ "heuristicAction": "allow"
+ },
+ "mea.gov.in": {
+ "heuristicAction": "allow"
+ },
+ "media.mcclatchy.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602346736506
+ },
+ "media.net": {
+ "heuristicAction": "block"
+ },
+ "media.richrelevance.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602255030467
+ },
+ "media6degrees.com": {
+ "heuristicAction": "block"
+ },
+ "mediaad.org": {
+ "heuristicAction": "block"
+ },
+ "mediacategory.com": {
+ "heuristicAction": "allow"
+ },
+ "mediacdn.vn": {
+ "heuristicAction": "allow"
+ },
+ "mediacorp.sg": {
+ "heuristicAction": "allow"
+ },
+ "mediaforge.com": {
+ "heuristicAction": "allow"
+ },
+ "mediafuse.com": {
+ "heuristicAction": "block"
+ },
+ "mediaset.net": {
+ "heuristicAction": "allow"
+ },
+ "mediav.com": {
+ "heuristicAction": "block"
+ },
+ "mediavine.com": {
+ "heuristicAction": "allow"
+ },
+ "mediawallahscript.com": {
+ "heuristicAction": "block"
+ },
+ "mediawayss.com": {
+ "heuristicAction": "allow"
+ },
+ "mediaweaver.jp": {
+ "heuristicAction": "allow"
+ },
+ "medium.al": {
+ "heuristicAction": "block"
+ },
+ "medium.com": {
+ "heuristicAction": "allow"
+ },
+ "medtargetsystem.com": {
+ "heuristicAction": "block"
+ },
+ "meetings.hubspot.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "meiqia.com": {
+ "heuristicAction": "block"
+ },
+ "meizu.cn": {
+ "heuristicAction": "allow"
+ },
+ "mellowads.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602211905379
+ },
+ "mer.stdout.cz": {
+ "heuristicAction": "allow"
+ },
+ "mercadopago.cl": {
+ "heuristicAction": "allow"
+ },
+ "meredithcorp.io": {
+ "heuristicAction": "allow"
+ },
+ "metagaua.hit.gemius.pl": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602118504782
+ },
+ "metricool.com": {
+ "heuristicAction": "allow"
+ },
+ "metrics.brightcove.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "metrics.timewarnercable.com": {
+ "heuristicAction": "allow"
+ },
+ "metroscubicos.com": {
+ "heuristicAction": "allow"
+ },
+ "mfadsrvr.com": {
+ "heuristicAction": "block"
+ },
+ "mgid.com": {
+ "heuristicAction": "block"
+ },
+ "mgzqlnev.micpn.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602374553528
+ },
+ "mhtr.be": {
+ "heuristicAction": "allow"
+ },
+ "mia-chat.com": {
+ "heuristicAction": "allow"
+ },
+ "miamiherald.com": {
+ "heuristicAction": "allow"
+ },
+ "miaozhen.com": {
+ "heuristicAction": "block"
+ },
+ "mib.gov.in": {
+ "heuristicAction": "allow"
+ },
+ "michelintravelpartner.d3.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602030194383
+ },
+ "micpn.com": {
+ "heuristicAction": "block"
+ },
+ "microad.jp": {
+ "heuristicAction": "block"
+ },
+ "microadinc.com": {
+ "heuristicAction": "block"
+ },
+ "microcontenidos.com": {
+ "heuristicAction": "allow"
+ },
+ "microntechnology.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602269322046
+ },
+ "microsoft.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "microsofttranslator.com": {
+ "heuristicAction": "allow"
+ },
+ "mid.rkdms.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602229355570
+ },
+ "midas-network.com": {
+ "heuristicAction": "allow"
+ },
+ "mimilcnf.pro": {
+ "heuristicAction": "allow"
+ },
+ "mindbox.cloud": {
+ "heuristicAction": "allow"
+ },
+ "mindbox.ru": {
+ "heuristicAction": "block"
+ },
+ "minibc.com": {
+ "heuristicAction": "allow"
+ },
+ "miniclip.com": {
+ "heuristicAction": "allow"
+ },
+ "miniclippt.com": {
+ "heuristicAction": "allow"
+ },
+ "miniinthebox.com": {
+ "heuristicAction": "allow"
+ },
+ "mirror.co.uk": {
+ "heuristicAction": "block"
+ },
+ "mituo.cn": {
+ "heuristicAction": "allow"
+ },
+ "mixcloud.com": {
+ "heuristicAction": "allow"
+ },
+ "mixi.media": {
+ "heuristicAction": "block"
+ },
+ "mktoresp.com": {
+ "heuristicAction": "block"
+ },
+ "ml314.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602137982531
+ },
+ "mlsys.xyz": {
+ "heuristicAction": "allow"
+ },
+ "mmonline.io": {
+ "heuristicAction": "allow"
+ },
+ "mmstat.com": {
+ "heuristicAction": "block"
+ },
+ "mmtro.com": {
+ "heuristicAction": "allow"
+ },
+ "moatads.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602075366073
+ },
+ "mobizone.mobi": {
+ "heuristicAction": "allow"
+ },
+ "mobvista.com": {
+ "heuristicAction": "allow"
+ },
+ "modlily.com": {
+ "heuristicAction": "allow"
+ },
+ "moe.video": {
+ "heuristicAction": "allow"
+ },
+ "moevideo.biz": {
+ "heuristicAction": "allow"
+ },
+ "monetate.net": {
+ "heuristicAction": "block"
+ },
+ "monohost.com": {
+ "heuristicAction": "block"
+ },
+ "monsido.com": {
+ "heuristicAction": "block"
+ },
+ "mookie1.com": {
+ "heuristicAction": "block"
+ },
+ "moovit.com": {
+ "heuristicAction": "allow"
+ },
+ "mopinion.com": {
+ "heuristicAction": "allow"
+ },
+ "motorsport.com": {
+ "heuristicAction": "allow"
+ },
+ "mox.tv": {
+ "heuristicAction": "allow"
+ },
+ "moxielinks.com": {
+ "heuristicAction": "allow"
+ },
+ "mozzart.ideaplus.mk": {
+ "heuristicAction": "allow"
+ },
+ "mp.4dex.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602098830165
+ },
+ "mpeasylink.com": {
+ "heuristicAction": "block"
+ },
+ "mpianalytics.com": {
+ "heuristicAction": "block"
+ },
+ "mpio.io": {
+ "heuristicAction": "allow"
+ },
+ "mpp.vindicosuite.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601938263068
+ },
+ "mpshark.com": {
+ "heuristicAction": "allow"
+ },
+ "mpsnare.iesnare.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "mrelko.com": {
+ "heuristicAction": "allow"
+ },
+ "mrpfd.com": {
+ "heuristicAction": "allow"
+ },
+ "mrtnsvr.com": {
+ "heuristicAction": "allow"
+ },
+ "msgapp.com": {
+ "heuristicAction": "allow"
+ },
+ "msn.com": {
+ "heuristicAction": "allow"
+ },
+ "mt0.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "mt1.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "mtgroup.kr": {
+ "heuristicAction": "allow"
+ },
+ "mtmo.cc": {
+ "heuristicAction": "allow"
+ },
+ "mts.ru": {
+ "heuristicAction": "block"
+ },
+ "mts0.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "mts1.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "mtvnetworks.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602165322464
+ },
+ "mtvnservices.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "muji.net": {
+ "heuristicAction": "allow"
+ },
+ "mulesoft.com": {
+ "heuristicAction": "allow"
+ },
+ "musthird.com": {
+ "heuristicAction": "block"
+ },
+ "mw1.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "mw2.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "mxapis.com": {
+ "heuristicAction": "allow"
+ },
+ "mxplay.com": {
+ "heuristicAction": "allow"
+ },
+ "mydoterra.queue-it.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "myfinance.com": {
+ "heuristicAction": "allow"
+ },
+ "mykhel.com": {
+ "heuristicAction": "allow"
+ },
+ "myopenads.com": {
+ "heuristicAction": "allow"
+ },
+ "myshopify.com": {
+ "heuristicAction": "allow"
+ },
+ "myvisualiq.net": {
+ "heuristicAction": "block"
+ },
+ "myvoicenation.com": {
+ "heuristicAction": "allow"
+ },
+ "n.gemini.yahoo.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602129777154
+ },
+ "n1272serv.xyz": {
+ "heuristicAction": "allow"
+ },
+ "n2.hk": {
+ "heuristicAction": "allow"
+ },
+ "nakamasweb.com": {
+ "heuristicAction": "allow"
+ },
+ "nakanohito.jp": {
+ "heuristicAction": "block"
+ },
+ "namebrightstatic.com": {
+ "heuristicAction": "allow"
+ },
+ "nanda.vn": {
+ "heuristicAction": "block"
+ },
+ "nanigans.com": {
+ "heuristicAction": "allow"
+ },
+ "nanorep.co": {
+ "heuristicAction": "cookieblock"
+ },
+ "nanosemantics.ru": {
+ "heuristicAction": "allow"
+ },
+ "narrative.io": {
+ "heuristicAction": "block"
+ },
+ "native.sharethrough.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602018288094
+ },
+ "nativendo.de": {
+ "heuristicAction": "block"
+ },
+ "nativeroll.tv": {
+ "heuristicAction": "block"
+ },
+ "navdmp.com": {
+ "heuristicAction": "block"
+ },
+ "naver.com": {
+ "heuristicAction": "block"
+ },
+ "nbc.com": {
+ "heuristicAction": "allow"
+ },
+ "nbcume.hb.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602005003033
+ },
+ "nbcuni.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "nc0.co": {
+ "heuristicAction": "allow"
+ },
+ "nch.com.au": {
+ "heuristicAction": "allow"
+ },
+ "neodatagroup.com": {
+ "heuristicAction": "allow"
+ },
+ "neppa-dsp-ad.com": {
+ "heuristicAction": "allow"
+ },
+ "netdna-ssl.com": {
+ "heuristicAction": "allow"
+ },
+ "netmng.com": {
+ "heuristicAction": "block"
+ },
+ "netrk.net": {
+ "heuristicAction": "allow"
+ },
+ "network.bazaarvoice.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "networkad.net": {
+ "heuristicAction": "allow"
+ },
+ "networkn-d.openx.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602351211629
+ },
+ "newaircloud.com": {
+ "heuristicAction": "allow"
+ },
+ "newmedia.az": {
+ "heuristicAction": "block"
+ },
+ "newrelic.com": {
+ "heuristicAction": "allow"
+ },
+ "news-network.ru": {
+ "heuristicAction": "allow"
+ },
+ "news.cn": {
+ "heuristicAction": "allow"
+ },
+ "news.google.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601973685701
+ },
+ "newscgp.com": {
+ "heuristicAction": "block"
+ },
+ "newshub.id": {
+ "heuristicAction": "allow"
+ },
+ "newsmaxwidget.com": {
+ "heuristicAction": "allow"
+ },
+ "newsmemory.com": {
+ "heuristicAction": "allow"
+ },
+ "newsobserver.com": {
+ "heuristicAction": "allow"
+ },
+ "newyorker.com": {
+ "heuristicAction": "block"
+ },
+ "newzit.com": {
+ "heuristicAction": "allow"
+ },
+ "nextclick.pl": {
+ "heuristicAction": "allow"
+ },
+ "nextelection.app": {
+ "heuristicAction": "allow"
+ },
+ "ngpvan.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "ngs.ru": {
+ "heuristicAction": "allow"
+ },
+ "nicequest.com": {
+ "heuristicAction": "allow"
+ },
+ "nikon-cdn.com": {
+ "heuristicAction": "allow"
+ },
+ "nikonsso.com": {
+ "heuristicAction": "allow"
+ },
+ "nimbleswan.io": {
+ "heuristicAction": "allow"
+ },
+ "ninahale.net": {
+ "heuristicAction": "allow"
+ },
+ "nine.com.au": {
+ "heuristicAction": "block"
+ },
+ "nissanheliosna.d3.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602119730377
+ },
+ "nissanheliosna.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602272496857
+ },
+ "njih.net": {
+ "heuristicAction": "allow"
+ },
+ "no-cache.hubspot.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "norstatsurveys.com": {
+ "heuristicAction": "allow"
+ },
+ "norton.com": {
+ "heuristicAction": "allow"
+ },
+ "nosto.com": {
+ "heuristicAction": "block"
+ },
+ "notifyvisitors.com": {
+ "heuristicAction": "allow"
+ },
+ "noxgroup.com": {
+ "heuristicAction": "allow"
+ },
+ "nperf.com": {
+ "heuristicAction": "allow"
+ },
+ "npo.nl": {
+ "heuristicAction": "allow"
+ },
+ "npohosting.nl": {
+ "heuristicAction": "allow"
+ },
+ "nr-data.net": {
+ "heuristicAction": "block"
+ },
+ "nsaudience.pl": {
+ "heuristicAction": "allow"
+ },
+ "ntnu.edu": {
+ "heuristicAction": "allow"
+ },
+ "ntvk1.ru": {
+ "heuristicAction": "allow"
+ },
+ "nuggad.net": {
+ "heuristicAction": "allow"
+ },
+ "nxtck.com": {
+ "heuristicAction": "allow"
+ },
+ "o-s.io": {
+ "heuristicAction": "allow"
+ },
+ "o333o.com": {
+ "heuristicAction": "allow"
+ },
+ "oa-mssp.data.aliyun.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602232879017
+ },
+ "oa-ssp.data.aliyun.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602273544731
+ },
+ "oadz.com": {
+ "heuristicAction": "allow"
+ },
+ "obs.cheqzone.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602347445747
+ },
+ "ocdn.eu": {
+ "heuristicAction": "allow"
+ },
+ "octclck.xyz": {
+ "heuristicAction": "allow"
+ },
+ "octivid.com": {
+ "heuristicAction": "allow"
+ },
+ "oddcast.com": {
+ "heuristicAction": "allow"
+ },
+ "odoocdn.com": {
+ "heuristicAction": "allow"
+ },
+ "officeworks.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602105908337
+ },
+ "officeworks.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602358562632
+ },
+ "offlinx.com": {
+ "heuristicAction": "allow"
+ },
+ "ojrq.net": {
+ "heuristicAction": "block"
+ },
+ "ok.ru": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601973576526
+ },
+ "okccdn.com": {
+ "heuristicAction": "allow"
+ },
+ "okezone.com": {
+ "heuristicAction": "allow"
+ },
+ "okt.to": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601981510026
+ },
+ "okta.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "olark.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "olnl.net": {
+ "heuristicAction": "allow"
+ },
+ "olx-st.com": {
+ "heuristicAction": "block"
+ },
+ "omchanseyr.com": {
+ "heuristicAction": "allow"
+ },
+ "omgpm.com": {
+ "heuristicAction": "allow"
+ },
+ "omguk.com": {
+ "heuristicAction": "allow"
+ },
+ "omniscientai.com": {
+ "heuristicAction": "allow"
+ },
+ "omnitagjs.com": {
+ "heuristicAction": "block"
+ },
+ "omny.fm": {
+ "heuristicAction": "cookieblock"
+ },
+ "omtrdc.net": {
+ "heuristicAction": "block"
+ },
+ "onaudience.com": {
+ "heuristicAction": "allow"
+ },
+ "oncueapp.appspot.com": {
+ "heuristicAction": "allow"
+ },
+ "one.gov.hk": {
+ "heuristicAction": "allow"
+ },
+ "onecms.io": {
+ "heuristicAction": "allow"
+ },
+ "onecount.net": {
+ "heuristicAction": "allow"
+ },
+ "oneindia.com": {
+ "heuristicAction": "allow"
+ },
+ "onelink.me": {
+ "heuristicAction": "allow"
+ },
+ "onesignal.com": {
+ "heuristicAction": "allow"
+ },
+ "onet.hit.gemius.pl": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602319350963
+ },
+ "onet.pl": {
+ "heuristicAction": "allow"
+ },
+ "onevision.com.tw": {
+ "heuristicAction": "block"
+ },
+ "online-metrix.net": {
+ "heuristicAction": "block"
+ },
+ "onlyred.net": {
+ "heuristicAction": "allow"
+ },
+ "onrcx.com": {
+ "heuristicAction": "allow"
+ },
+ "onsugar.com": {
+ "heuristicAction": "allow"
+ },
+ "onthe.io": {
+ "heuristicAction": "block"
+ },
+ "ooyala.com": {
+ "heuristicAction": "allow"
+ },
+ "opecloud.com": {
+ "heuristicAction": "block"
+ },
+ "open.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "openbid.pubmatic.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602050638764
+ },
+ "openstat.net": {
+ "heuristicAction": "allow"
+ },
+ "openx.net": {
+ "heuristicAction": "block"
+ },
+ "opinionstage.com": {
+ "heuristicAction": "allow"
+ },
+ "optaim.com": {
+ "heuristicAction": "allow"
+ },
+ "optimahub.com": {
+ "heuristicAction": "allow"
+ },
+ "optimix.cn": {
+ "heuristicAction": "block"
+ },
+ "optimizely.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "optimove.events": {
+ "heuristicAction": "allow"
+ },
+ "oracle.com": {
+ "heuristicAction": "block"
+ },
+ "oraclecloud.com": {
+ "heuristicAction": "allow"
+ },
+ "oracleimg.com": {
+ "heuristicAction": "block"
+ },
+ "orange-business.com": {
+ "heuristicAction": "allow"
+ },
+ "orangeads.fr": {
+ "heuristicAction": "allow"
+ },
+ "orbita.cloud": {
+ "heuristicAction": "allow"
+ },
+ "oreillystatic.com": {
+ "heuristicAction": "allow"
+ },
+ "osano.com": {
+ "heuristicAction": "block"
+ },
+ "otaserve.net": {
+ "heuristicAction": "allow"
+ },
+ "otm-r.com": {
+ "heuristicAction": "block"
+ },
+ "outbrain.com": {
+ "heuristicAction": "block"
+ },
+ "outlookhindi.com": {
+ "heuristicAction": "allow"
+ },
+ "outstream.today": {
+ "heuristicAction": "allow"
+ },
+ "ow5a.net": {
+ "heuristicAction": "allow"
+ },
+ "owneriq.net": {
+ "heuristicAction": "block"
+ },
+ "ownpage.fr": {
+ "heuristicAction": "allow"
+ },
+ "p.alocdn.com": {
+ "heuristicAction": "block"
+ },
+ "p.cpx.to": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602258148192
+ },
+ "p.teads.tv": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602311638230
+ },
+ "p.tvpixel.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602188727534
+ },
+ "p.typekit.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "p1.zemanta.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601966397031
+ },
+ "p242.mimilcnf.pro": {
+ "heuristicAction": "allow"
+ },
+ "pacificgasandelectricco.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602138803143
+ },
+ "paddle.com": {
+ "heuristicAction": "allow"
+ },
+ "padletcdn.com": {
+ "heuristicAction": "allow"
+ },
+ "pages02.net": {
+ "heuristicAction": "allow"
+ },
+ "pages03.net": {
+ "heuristicAction": "block"
+ },
+ "pages04.net": {
+ "heuristicAction": "allow"
+ },
+ "pages06.net": {
+ "heuristicAction": "allow"
+ },
+ "pages07.net": {
+ "heuristicAction": "allow"
+ },
+ "pages08.net": {
+ "heuristicAction": "allow"
+ },
+ "panel.adtodate.net": {
+ "heuristicAction": "allow"
+ },
+ "panet.eu": {
+ "heuristicAction": "allow"
+ },
+ "pangu.kcsfile.com": {
+ "heuristicAction": "allow"
+ },
+ "papi.look.360.cn": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602367932182
+ },
+ "pardot.com": {
+ "heuristicAction": "block"
+ },
+ "parsely.com": {
+ "heuristicAction": "block"
+ },
+ "parsons.edu": {
+ "heuristicAction": "allow"
+ },
+ "particularaudience.com": {
+ "heuristicAction": "allow"
+ },
+ "patreon.com": {
+ "heuristicAction": "allow"
+ },
+ "paxful.com": {
+ "heuristicAction": "allow"
+ },
+ "pay.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "paycom.com": {
+ "heuristicAction": "allow"
+ },
+ "paypal.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "pb.ua": {
+ "heuristicAction": "allow"
+ },
+ "pba.aws.lijit.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601939611868
+ },
+ "pbbl.co": {
+ "heuristicAction": "block"
+ },
+ "pbstck.com": {
+ "heuristicAction": "allow"
+ },
+ "pc.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "pcmag.com": {
+ "heuristicAction": "block"
+ },
+ "pconline.com.cn": {
+ "heuristicAction": "block"
+ },
+ "pd.sharethis.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602153809133
+ },
+ "pdvacde.com": {
+ "heuristicAction": "allow"
+ },
+ "pelcro.com": {
+ "heuristicAction": "allow"
+ },
+ "pelmorex.com": {
+ "heuristicAction": "allow"
+ },
+ "pendo.io": {
+ "heuristicAction": "block"
+ },
+ "people.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "percycle.com": {
+ "heuristicAction": "allow"
+ },
+ "performancefirst.jp": {
+ "heuristicAction": "allow"
+ },
+ "performi.com": {
+ "heuristicAction": "allow"
+ },
+ "permutive.app": {
+ "heuristicAction": "block"
+ },
+ "petametrics.com": {
+ "heuristicAction": "block"
+ },
+ "pgtb.me": {
+ "heuristicAction": "allow"
+ },
+ "philips.co.uk": {
+ "heuristicAction": "allow"
+ },
+ "philips.com": {
+ "heuristicAction": "allow"
+ },
+ "photo.store.qq.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "photorank.me": {
+ "heuristicAction": "block"
+ },
+ "pi.pardot.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602088740721
+ },
+ "piano.io": {
+ "heuristicAction": "allow"
+ },
+ "picasaweb.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "pinduoduo.com": {
+ "heuristicAction": "allow"
+ },
+ "ping.chartbeat.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602278560774
+ },
+ "pingan.com": {
+ "heuristicAction": "allow"
+ },
+ "pingback.issuu.com": {
+ "heuristicAction": "allow"
+ },
+ "pinterest.com": {
+ "heuristicAction": "block"
+ },
+ "pipes.yahoo.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "piri.net": {
+ "heuristicAction": "allow"
+ },
+ "pitchfork.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601846670134
+ },
+ "piwik.pro": {
+ "heuristicAction": "block"
+ },
+ "pixel.advertising.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601995995645
+ },
+ "pixel.cdnwidget.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602319269087
+ },
+ "pixel.mathtag.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602083998093
+ },
+ "pixel.pointmediatracker.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602345582748
+ },
+ "pixel.quantserve.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601976314353
+ },
+ "pixel.rubiconproject.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602020795935
+ },
+ "pixel.servebom.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602349576142
+ },
+ "pixel.sitescout.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601880779902
+ },
+ "pixel.sojern.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601891472357
+ },
+ "pixel.tapad.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602296209272
+ },
+ "pixel2.cheqzone.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601964731632
+ },
+ "pixelg.adswizz.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602290080722
+ },
+ "pixlee.co": {
+ "heuristicAction": "allow"
+ },
+ "pixlee.com": {
+ "heuristicAction": "block"
+ },
+ "pixnet.cc": {
+ "heuristicAction": "allow"
+ },
+ "pk.labocleo.org": {
+ "heuristicAction": "allow"
+ },
+ "placed.com": {
+ "heuristicAction": "allow"
+ },
+ "planalto.gov.br": {
+ "heuristicAction": "allow"
+ },
+ "platform-api.sharethis.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602223994935
+ },
+ "platform.bidgear.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602133549361
+ },
+ "platform.iteratehq.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602038115638
+ },
+ "platform.linkedin.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602145546636
+ },
+ "platform.twitter.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "play.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "play.vidyard.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602282917182
+ },
+ "playbuzz.com": {
+ "heuristicAction": "allow"
+ },
+ "player.aniview.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601892578750
+ },
+ "playreplay.me": {
+ "heuristicAction": "allow"
+ },
+ "playreplay.net": {
+ "heuristicAction": "allow"
+ },
+ "plezi.co": {
+ "heuristicAction": "allow"
+ },
+ "plista.com": {
+ "heuristicAction": "block"
+ },
+ "plus.google.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602215355828
+ },
+ "plus.sabavision.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601905204908
+ },
+ "poemsdeucewee.com": {
+ "heuristicAction": "allow"
+ },
+ "pointmediatracker.com": {
+ "heuristicAction": "block"
+ },
+ "polarbyte.com": {
+ "heuristicAction": "allow"
+ },
+ "poll-maker.com": {
+ "heuristicAction": "allow"
+ },
+ "poll.fm": {
+ "heuristicAction": "allow"
+ },
+ "poool.fr": {
+ "heuristicAction": "allow"
+ },
+ "popin.cc": {
+ "heuristicAction": "block"
+ },
+ "popt.in": {
+ "heuristicAction": "allow"
+ },
+ "port.hu": {
+ "heuristicAction": "allow"
+ },
+ "portalinmobiliario.com": {
+ "heuristicAction": "allow"
+ },
+ "pos.baidu.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601915381141
+ },
+ "postaffiliatepro.com": {
+ "heuristicAction": "allow"
+ },
+ "postrelease.com": {
+ "heuristicAction": "block"
+ },
+ "powerlinks.com": {
+ "heuristicAction": "block"
+ },
+ "powerreviews.com": {
+ "heuristicAction": "allow"
+ },
+ "pp.lp4.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601906355280
+ },
+ "pplive.com": {
+ "heuristicAction": "allow"
+ },
+ "prcdn.co": {
+ "heuristicAction": "block"
+ },
+ "prebid-eu.creativecdn.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602250362504
+ },
+ "prebid.a-mo.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602128690166
+ },
+ "prebid.technoratimedia.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601937523227
+ },
+ "prensaiberica.es": {
+ "heuristicAction": "allow"
+ },
+ "prfct.co": {
+ "heuristicAction": "block"
+ },
+ "prg.smartadserver.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601918796093
+ },
+ "priceline.com": {
+ "heuristicAction": "allow"
+ },
+ "primead.jp": {
+ "heuristicAction": "allow"
+ },
+ "primecaster.net": {
+ "heuristicAction": "allow"
+ },
+ "printful.com": {
+ "heuristicAction": "allow"
+ },
+ "prisasd.com": {
+ "heuristicAction": "allow"
+ },
+ "prismamedia.com": {
+ "heuristicAction": "allow"
+ },
+ "privacy.trustcommander.net": {
+ "heuristicAction": "allow"
+ },
+ "privacymanager.io": {
+ "heuristicAction": "allow"
+ },
+ "privally.io": {
+ "heuristicAction": "allow"
+ },
+ "privymktg.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602264700400
+ },
+ "prixa.net": {
+ "heuristicAction": "allow"
+ },
+ "prixacdn.net": {
+ "heuristicAction": "allow"
+ },
+ "prlog.org": {
+ "heuristicAction": "allow"
+ },
+ "pro-market.net": {
+ "heuristicAction": "block"
+ },
+ "prod-ajc-proxy-connext.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "prod-anchorage-proxy-connext.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "prod-api-funimationnow.dadcdigital.com": {
+ "heuristicAction": "allow"
+ },
+ "prod-cosprings-proxy-connext.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "prod-dfm-proxy-connext.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "prod-mng-proxy-connext.azurewebsites.net": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602184427468
+ },
+ "prod-newsday-proxy-connext.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "prod-review-journal-proxy-connext.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "prod-smi-proxy-connext.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "prod-spokesman-proxy-connext.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "prod-tampabay-proxy-connext.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "prod01.kaxsdc.com": {
+ "heuristicAction": "allow"
+ },
+ "producebreed.com": {
+ "heuristicAction": "allow"
+ },
+ "profiles.tagger.opecloud.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602204757561
+ },
+ "programattik.com": {
+ "heuristicAction": "block"
+ },
+ "project1service.com": {
+ "heuristicAction": "allow"
+ },
+ "prometeo-media-service.com": {
+ "heuristicAction": "allow"
+ },
+ "promos.rtm.com": {
+ "heuristicAction": "allow"
+ },
+ "proofpoint.com": {
+ "heuristicAction": "block"
+ },
+ "propermedia-d.openx.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602016597448
+ },
+ "prosumsit.com": {
+ "heuristicAction": "allow"
+ },
+ "provenexpert.com": {
+ "heuristicAction": "allow"
+ },
+ "provenpixel.com": {
+ "heuristicAction": "allow"
+ },
+ "proxad.net": {
+ "heuristicAction": "allow"
+ },
+ "ps.eyeota.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602203277374
+ },
+ "psakdin.co.il": {
+ "heuristicAction": "allow"
+ },
+ "pswec.com": {
+ "heuristicAction": "allow"
+ },
+ "pt.ispot.tv": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601970044880
+ },
+ "ptgncdn.com": {
+ "heuristicAction": "allow"
+ },
+ "pub.network": {
+ "heuristicAction": "block"
+ },
+ "pubads.g.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602248461999
+ },
+ "pubble.io": {
+ "heuristicAction": "allow"
+ },
+ "public.servenobid.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602008959913
+ },
+ "publicradio.org": {
+ "heuristicAction": "allow"
+ },
+ "publir.com": {
+ "heuristicAction": "allow"
+ },
+ "publishme.se": {
+ "heuristicAction": "allow"
+ },
+ "pubmatic.com": {
+ "heuristicAction": "block"
+ },
+ "pubstack.io": {
+ "heuristicAction": "block"
+ },
+ "pulsembed.eu": {
+ "heuristicAction": "allow"
+ },
+ "purch-match.dotomi.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602362186520
+ },
+ "purch-sync.go.sonobi.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602026135730
+ },
+ "purechat.com": {
+ "heuristicAction": "allow"
+ },
+ "push.world": {
+ "heuristicAction": "allow"
+ },
+ "push.zhanzhang.baidu.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601921035080
+ },
+ "pushbird.com": {
+ "heuristicAction": "allow"
+ },
+ "pushe.co": {
+ "heuristicAction": "allow"
+ },
+ "pushnami.com": {
+ "heuristicAction": "block"
+ },
+ "pvsite.zol.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "pvxt.net": {
+ "heuristicAction": "allow"
+ },
+ "px-cloud.net": {
+ "heuristicAction": "allow"
+ },
+ "px.ads.linkedin.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602329864419
+ },
+ "px.airpr.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602027593662
+ },
+ "px.marchex.io": {
+ "heuristicAction": "allow"
+ },
+ "px.moatads.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602038362789
+ },
+ "px.owneriq.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602141008971
+ },
+ "px.powerlinks.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602344340277
+ },
+ "pxf.io": {
+ "heuristicAction": "allow"
+ },
+ "pymx5.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602165770487
+ },
+ "q.quora.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602370761974
+ },
+ "qchannel03.cn": {
+ "heuristicAction": "allow"
+ },
+ "qds0l.publishers.tremorhub.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602242008241
+ },
+ "qhupdate.com": {
+ "heuristicAction": "allow"
+ },
+ "qiyukf.com": {
+ "heuristicAction": "allow"
+ },
+ "qlitics.com": {
+ "heuristicAction": "allow"
+ },
+ "qoo10.in": {
+ "heuristicAction": "allow"
+ },
+ "qq.com": {
+ "heuristicAction": "block"
+ },
+ "qqjar.ru": {
+ "heuristicAction": "allow"
+ },
+ "qs.com": {
+ "heuristicAction": "allow"
+ },
+ "qsstats.com": {
+ "heuristicAction": "allow"
+ },
+ "qualtrics.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "quantad.io": {
+ "heuristicAction": "allow"
+ },
+ "quantserve.com": {
+ "heuristicAction": "block"
+ },
+ "quantumdex.io": {
+ "heuristicAction": "block"
+ },
+ "quantummetric.com": {
+ "heuristicAction": "block"
+ },
+ "queryly.com": {
+ "heuristicAction": "allow"
+ },
+ "questionpro.com": {
+ "heuristicAction": "allow"
+ },
+ "queue-it.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "quickkoala.io": {
+ "heuristicAction": "allow"
+ },
+ "quiq-api.com": {
+ "heuristicAction": "allow"
+ },
+ "quitzon.net": {
+ "heuristicAction": "allow"
+ },
+ "quora.com": {
+ "heuristicAction": "block"
+ },
+ "qy.net": {
+ "heuristicAction": "allow"
+ },
+ "r-ad.ne.jp": {
+ "heuristicAction": "block"
+ },
+ "r.adrta.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602169293990
+ },
+ "radissonhotels.com": {
+ "heuristicAction": "allow"
+ },
+ "rainbowred.com": {
+ "heuristicAction": "allow"
+ },
+ "rakuten.co.jp": {
+ "heuristicAction": "block"
+ },
+ "rakuten.com": {
+ "heuristicAction": "block"
+ },
+ "rambler.ru": {
+ "heuristicAction": "cookieblock"
+ },
+ "randomhouse.com": {
+ "heuristicAction": "allow"
+ },
+ "rating-widget.com": {
+ "heuristicAction": "allow"
+ },
+ "raxcdn.com": {
+ "heuristicAction": "allow"
+ },
+ "raycommedia.com": {
+ "heuristicAction": "allow"
+ },
+ "razorpay.com": {
+ "heuristicAction": "allow"
+ },
+ "rc.rlcdn.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602042069460
+ },
+ "rcapiuseridexchange.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "rcci.demdex.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602054619490
+ },
+ "rcci.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601927398916
+ },
+ "rcom-eu.dynamicyield.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "rcom.dynamicyield.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "rcrsv.io": {
+ "heuristicAction": "allow"
+ },
+ "rcs.it": {
+ "heuristicAction": "allow"
+ },
+ "rcsmetrics.it": {
+ "heuristicAction": "allow"
+ },
+ "rctiplus.com": {
+ "heuristicAction": "allow"
+ },
+ "rdcdn.com": {
+ "heuristicAction": "allow"
+ },
+ "reachmax.cn": {
+ "heuristicAction": "block"
+ },
+ "reactful.com": {
+ "heuristicAction": "allow"
+ },
+ "realclick.co.kr": {
+ "heuristicAction": "allow"
+ },
+ "realite.id": {
+ "heuristicAction": "block"
+ },
+ "realsrv.com": {
+ "heuristicAction": "block"
+ },
+ "realtime.email": {
+ "heuristicAction": "allow"
+ },
+ "rec-engine.com": {
+ "heuristicAction": "allow"
+ },
+ "recobell.io": {
+ "heuristicAction": "allow"
+ },
+ "recommendationengine.googleapis.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "recreativ.ru": {
+ "heuristicAction": "allow"
+ },
+ "recruitics.com": {
+ "heuristicAction": "allow"
+ },
+ "recv-bak-wd.gridsumdissector.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602272913471
+ },
+ "recv-wd.gridsumdissector.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602380448892
+ },
+ "redbubble.com": {
+ "heuristicAction": "allow"
+ },
+ "redcross.org": {
+ "heuristicAction": "allow"
+ },
+ "reddit.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "redhat.com": {
+ "heuristicAction": "allow"
+ },
+ "redintelligence.net": {
+ "heuristicAction": "allow"
+ },
+ "redlink.com": {
+ "heuristicAction": "allow"
+ },
+ "refocus.ru": {
+ "heuristicAction": "allow"
+ },
+ "registercom.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601942960569
+ },
+ "registercom.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601974777657
+ },
+ "regroup.com": {
+ "heuristicAction": "allow"
+ },
+ "reichelcormier.bid": {
+ "heuristicAction": "block"
+ },
+ "relap.io": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602091447839
+ },
+ "relateddigital.com": {
+ "heuristicAction": "allow"
+ },
+ "remarqable.com": {
+ "heuristicAction": "allow"
+ },
+ "renotifier.miniclippt.com": {
+ "heuristicAction": "allow"
+ },
+ "rentracks.jp": {
+ "heuristicAction": "block"
+ },
+ "report.huatuo.qq.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602298085654
+ },
+ "report.syzs.qq.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602234325378
+ },
+ "republer.com": {
+ "heuristicAction": "block"
+ },
+ "res.qhupdate.com": {
+ "heuristicAction": "allow"
+ },
+ "res.wx.qq.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602342749669
+ },
+ "research-int.se": {
+ "heuristicAction": "block"
+ },
+ "researchintel.com": {
+ "heuristicAction": "allow"
+ },
+ "researchnow.com": {
+ "heuristicAction": "block"
+ },
+ "resniks.pro": {
+ "heuristicAction": "allow"
+ },
+ "reson8.com": {
+ "heuristicAction": "block"
+ },
+ "resources.xg4ken.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602006584530
+ },
+ "retailrocket.net": {
+ "heuristicAction": "block"
+ },
+ "retargetly.com": {
+ "heuristicAction": "block"
+ },
+ "retentioneering.com": {
+ "heuristicAction": "allow"
+ },
+ "rev.uar.hubpd.com": {
+ "heuristicAction": "allow"
+ },
+ "revcontent.com": {
+ "heuristicAction": "block"
+ },
+ "reverb-assets.com": {
+ "heuristicAction": "allow"
+ },
+ "revive-adserver.net": {
+ "heuristicAction": "allow"
+ },
+ "revjet.com": {
+ "heuristicAction": "block"
+ },
+ "rezync.com": {
+ "heuristicAction": "block"
+ },
+ "rferl.org": {
+ "heuristicAction": "allow"
+ },
+ "rfihub.com": {
+ "heuristicAction": "block"
+ },
+ "rfksrv.com": {
+ "heuristicAction": "block"
+ },
+ "rfvk.net": {
+ "heuristicAction": "allow"
+ },
+ "ria.ru": {
+ "heuristicAction": "block"
+ },
+ "richaudience.com": {
+ "heuristicAction": "block"
+ },
+ "richrelevance.com": {
+ "heuristicAction": "block"
+ },
+ "rightinthebox.com": {
+ "heuristicAction": "allow"
+ },
+ "rightmessage.com": {
+ "heuristicAction": "allow"
+ },
+ "rightnowtech.com": {
+ "heuristicAction": "allow"
+ },
+ "rijksoverheid.nl": {
+ "heuristicAction": "allow"
+ },
+ "riotgames.com": {
+ "heuristicAction": "block"
+ },
+ "riskified.com": {
+ "heuristicAction": "block"
+ },
+ "riverhit.com": {
+ "heuristicAction": "block"
+ },
+ "rkdms.com": {
+ "heuristicAction": "block"
+ },
+ "rktch.com": {
+ "heuristicAction": "allow"
+ },
+ "rlcdn.com": {
+ "heuristicAction": "block"
+ },
+ "rmtag.com": {
+ "heuristicAction": "block"
+ },
+ "rmulus.com": {
+ "heuristicAction": "allow"
+ },
+ "rnengage.com": {
+ "heuristicAction": "block"
+ },
+ "rockcontent.com": {
+ "heuristicAction": "allow"
+ },
+ "roku.com": {
+ "heuristicAction": "allow"
+ },
+ "rollingstone.com": {
+ "heuristicAction": "allow"
+ },
+ "rosewe.com": {
+ "heuristicAction": "allow"
+ },
+ "rotita.com": {
+ "heuristicAction": "allow"
+ },
+ "router.infolinks.com": {
+ "heuristicAction": "allow"
+ },
+ "rstbtmd.com": {
+ "heuristicAction": "allow"
+ },
+ "rsz.sk": {
+ "heuristicAction": "allow"
+ },
+ "rt.ru": {
+ "heuristicAction": "allow"
+ },
+ "rtbsuperhub.com": {
+ "heuristicAction": "allow"
+ },
+ "rtd-tm.everesttech.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602180206329
+ },
+ "rtk.io": {
+ "heuristicAction": "block"
+ },
+ "rtm.com": {
+ "heuristicAction": "allow"
+ },
+ "rtmark.net": {
+ "heuristicAction": "block"
+ },
+ "rtr-vesti.ru": {
+ "heuristicAction": "allow"
+ },
+ "rubiconproject.com": {
+ "heuristicAction": "block"
+ },
+ "rum.uptime.com": {
+ "heuristicAction": "block"
+ },
+ "rumble.com": {
+ "heuristicAction": "allow"
+ },
+ "rumiview.com": {
+ "heuristicAction": "block"
+ },
+ "run-syndicate.com": {
+ "heuristicAction": "allow"
+ },
+ "russia.tv": {
+ "heuristicAction": "allow"
+ },
+ "rutarget.ru": {
+ "heuristicAction": "block"
+ },
+ "ryvx.net": {
+ "heuristicAction": "allow"
+ },
+ "rzk-m.com": {
+ "heuristicAction": "allow"
+ },
+ "s-static.ak.facebook.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "s.360.cn": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602190929287
+ },
+ "s.adroll.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602097010606
+ },
+ "s.amazon-adsystem.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602205985632
+ },
+ "s.dpmsrv.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601890500773
+ },
+ "s.salecycle.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602222020792
+ },
+ "s.shld.net": {
+ "heuristicAction": "allow"
+ },
+ "s.skimresources.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602298897231
+ },
+ "s.thebrighttag.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602347555959
+ },
+ "s.tribalfusion.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602178613054
+ },
+ "s1.mediaad.org": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602195611237
+ },
+ "s10.histats.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602067951576
+ },
+ "s1061282284.t.eloqua.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602282129841
+ },
+ "s1411.t.eloqua.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602141596214
+ },
+ "s1583749854.t.eloqua.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601926283321
+ },
+ "s19.cnzz.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602161831981
+ },
+ "s2044559064.t.eloqua.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601939229437
+ },
+ "s21.cnzz.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602307970326
+ },
+ "s23.cnzz.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602087873223
+ },
+ "s3.cheqzone.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602375598844
+ },
+ "s301091484.t.eloqua.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601929872971
+ },
+ "s457207082.t.eloqua.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602171063890
+ },
+ "s5.cnzz.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602111953853
+ },
+ "s5o.ru": {
+ "heuristicAction": "allow"
+ },
+ "s6.cnzz.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602026083580
+ },
+ "s68275882.t.eloqua.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602172314157
+ },
+ "s7.addthis.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602098120848
+ },
+ "s700.t.eloqua.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602361002131
+ },
+ "s9.cnzz.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601889638469
+ },
+ "s95.cnzz.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602055165910
+ },
+ "saas-bbw.userreplay.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602009150007
+ },
+ "sabavision.com": {
+ "heuristicAction": "block"
+ },
+ "sabay.com": {
+ "heuristicAction": "allow"
+ },
+ "sacbee.com": {
+ "heuristicAction": "block"
+ },
+ "sagetalk.io": {
+ "heuristicAction": "allow"
+ },
+ "sajari.com": {
+ "heuristicAction": "allow"
+ },
+ "salecycle.com": {
+ "heuristicAction": "block"
+ },
+ "salemwebnetwork.com": {
+ "heuristicAction": "allow"
+ },
+ "salesforce.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "salesforceliveagent.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "salesiq.zoho.com": {
+ "heuristicAction": "allow"
+ },
+ "salesloft.com": {
+ "heuristicAction": "block"
+ },
+ "samandehi.ir": {
+ "heuristicAction": "block"
+ },
+ "samba.tv": {
+ "heuristicAction": "block"
+ },
+ "sanjagh.com": {
+ "heuristicAction": "block"
+ },
+ "sanoma.fi": {
+ "heuristicAction": "allow"
+ },
+ "sape.ru": {
+ "heuristicAction": "allow"
+ },
+ "sapi.map.baidu.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "sas.com": {
+ "heuristicAction": "allow"
+ },
+ "sb.scorecardresearch.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601877050404
+ },
+ "sbmwmotor.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601900845827
+ },
+ "sc-static.net": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602052112351
+ },
+ "scarabresearch.com": {
+ "heuristicAction": "block"
+ },
+ "scatec.io": {
+ "heuristicAction": "allow"
+ },
+ "scdn.cxense.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602301965255
+ },
+ "scene7.com": {
+ "heuristicAction": "allow"
+ },
+ "scenepass.com": {
+ "heuristicAction": "allow"
+ },
+ "sched.activehosted.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602247108443
+ },
+ "schibsted.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "scholarlyiq.com": {
+ "heuristicAction": "allow"
+ },
+ "sciencedirect.com": {
+ "heuristicAction": "allow"
+ },
+ "sciencemag.org": {
+ "heuristicAction": "allow"
+ },
+ "sciencex.com": {
+ "heuristicAction": "allow"
+ },
+ "scmp.com": {
+ "heuristicAction": "allow"
+ },
+ "scoop.it": {
+ "heuristicAction": "allow"
+ },
+ "scorecardresearch.com": {
+ "heuristicAction": "block"
+ },
+ "scout-cdn.salesloft.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602096978415
+ },
+ "scribblelive.com": {
+ "heuristicAction": "allow"
+ },
+ "script.4dex.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602251014741
+ },
+ "script.dotmetrics.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602278727107
+ },
+ "script.ioam.de": {
+ "heuristicAction": "cookieblock"
+ },
+ "scupio.com": {
+ "heuristicAction": "block"
+ },
+ "sddan.com": {
+ "heuristicAction": "allow"
+ },
+ "sdlcdn.com": {
+ "heuristicAction": "allow"
+ },
+ "se.monetate.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602132174138
+ },
+ "search.spotxchange.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602220572317
+ },
+ "search.yahoo.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "searchforce.net": {
+ "heuristicAction": "allow"
+ },
+ "searchiq.co": {
+ "heuristicAction": "allow"
+ },
+ "sears.demdex.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601898524030
+ },
+ "searsholdings.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602011616601
+ },
+ "seccdn-gl.imrworldwide.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602061719559
+ },
+ "secrank.cn": {
+ "heuristicAction": "allow"
+ },
+ "section.io": {
+ "heuristicAction": "allow"
+ },
+ "secure-assets.rubiconproject.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602059253054
+ },
+ "secure-au.imrworldwide.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602008173018
+ },
+ "secure-dcr.imrworldwide.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602126109095
+ },
+ "secure-ds.serving-sys.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601979038058
+ },
+ "secure-gl.imrworldwide.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602257269255
+ },
+ "secure-nz.imrworldwide.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602238398801
+ },
+ "secure-us.imrworldwide.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601881444709
+ },
+ "secure-web.cisco.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602378055496
+ },
+ "secure.adnxs.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601978353332
+ },
+ "secure.leadback.advertising.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602182833149
+ },
+ "secure.nikonsso.com": {
+ "heuristicAction": "allow"
+ },
+ "secure.quantserve.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602371959433
+ },
+ "secure.statcounter.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601965857326
+ },
+ "secureaddisplay.com": {
+ "heuristicAction": "allow"
+ },
+ "securedtouch.com": {
+ "heuristicAction": "block"
+ },
+ "securedvisit.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602376785866
+ },
+ "securepubads.g.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601888542855
+ },
+ "secureserver.net": {
+ "heuristicAction": "block"
+ },
+ "securetve.com": {
+ "heuristicAction": "allow"
+ },
+ "seedr.com": {
+ "heuristicAction": "block"
+ },
+ "seedtag.com": {
+ "heuristicAction": "block"
+ },
+ "segment.com": {
+ "heuristicAction": "block"
+ },
+ "segment.prod.bidr.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601987753587
+ },
+ "segs.jp": {
+ "heuristicAction": "allow"
+ },
+ "sejs.moatads.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602290278082
+ },
+ "sekindo.com": {
+ "heuristicAction": "block"
+ },
+ "selectmedia.asia": {
+ "heuristicAction": "allow"
+ },
+ "self.com": {
+ "heuristicAction": "block"
+ },
+ "sellpoints.com": {
+ "heuristicAction": "allow"
+ },
+ "semasio.net": {
+ "heuristicAction": "block"
+ },
+ "sembox.it": {
+ "heuristicAction": "allow"
+ },
+ "semrush.com": {
+ "heuristicAction": "allow"
+ },
+ "senseforth.com": {
+ "heuristicAction": "allow"
+ },
+ "sensic.net": {
+ "heuristicAction": "allow"
+ },
+ "sensorsdata.cn": {
+ "heuristicAction": "block"
+ },
+ "sensorsdatavip.com": {
+ "heuristicAction": "allow"
+ },
+ "sep.gob.mx": {
+ "heuristicAction": "allow"
+ },
+ "serasaexperian.demdex.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601881469141
+ },
+ "serve2.cheqzone.com": {
+ "heuristicAction": "block"
+ },
+ "servebom.com": {
+ "heuristicAction": "block"
+ },
+ "servedby.flashtalking.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601986753963
+ },
+ "servedbyadbutler.com": {
+ "heuristicAction": "allow"
+ },
+ "servenobid.com": {
+ "heuristicAction": "block"
+ },
+ "serverbid.com": {
+ "heuristicAction": "block"
+ },
+ "serving-sys.com": {
+ "heuristicAction": "block"
+ },
+ "sessioncam.com": {
+ "heuristicAction": "block"
+ },
+ "seznam.cz": {
+ "heuristicAction": "allow"
+ },
+ "sf14g.com": {
+ "heuristicAction": "block"
+ },
+ "sfegypt.com": {
+ "heuristicAction": "allow"
+ },
+ "sfn.org": {
+ "heuristicAction": "allow"
+ },
+ "sgkrehberi.com": {
+ "heuristicAction": "allow"
+ },
+ "sgsme.sg": {
+ "heuristicAction": "allow"
+ },
+ "shanghai.gov.cn": {
+ "heuristicAction": "allow"
+ },
+ "shaqm.com": {
+ "heuristicAction": "allow"
+ },
+ "shareaholic.com": {
+ "heuristicAction": "allow"
+ },
+ "sharecare.com": {
+ "heuristicAction": "allow"
+ },
+ "sharethis.com": {
+ "heuristicAction": "block"
+ },
+ "sharethrough.com": {
+ "heuristicAction": "block"
+ },
+ "shbdn.com": {
+ "heuristicAction": "allow"
+ },
+ "shinobi.jp": {
+ "heuristicAction": "allow"
+ },
+ "shinystat.com": {
+ "heuristicAction": "allow"
+ },
+ "shld.net": {
+ "heuristicAction": "allow"
+ },
+ "shoagnie.com": {
+ "heuristicAction": "allow"
+ },
+ "shop.app": {
+ "heuristicAction": "allow"
+ },
+ "shop.pe": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602216733235
+ },
+ "shopbop.com": {
+ "heuristicAction": "allow"
+ },
+ "shopclues-log.qoo10.in": {
+ "heuristicAction": "allow"
+ },
+ "shopclues.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602340697713
+ },
+ "shopnetic.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601874192083
+ },
+ "shoprunner.com": {
+ "heuristicAction": "allow"
+ },
+ "shopsocially.com": {
+ "heuristicAction": "allow"
+ },
+ "show-3.mediav.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602326996244
+ },
+ "show-g.mediav.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602320655946
+ },
+ "shuidi.cn": {
+ "heuristicAction": "allow"
+ },
+ "sibautomation.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602063149104
+ },
+ "sift.com": {
+ "heuristicAction": "block"
+ },
+ "siftscience.com": {
+ "heuristicAction": "block"
+ },
+ "signify.com": {
+ "heuristicAction": "allow"
+ },
+ "signifyd.com": {
+ "heuristicAction": "block"
+ },
+ "simility.com": {
+ "heuristicAction": "allow"
+ },
+ "simpli.fi": {
+ "heuristicAction": "block"
+ },
+ "sina.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "sindonews.com": {
+ "heuristicAction": "allow"
+ },
+ "sinoptik.ua": {
+ "heuristicAction": "allow"
+ },
+ "site-api.project1service.com": {
+ "heuristicAction": "allow"
+ },
+ "site24x7rum.com": {
+ "heuristicAction": "block"
+ },
+ "sitecore-prod-cd-westus2.azurewebsites.net": {
+ "heuristicAction": "allow"
+ },
+ "sitedataprocessing.com": {
+ "heuristicAction": "allow"
+ },
+ "siteimproveanalytics.io": {
+ "heuristicAction": "block"
+ },
+ "sitelock.com": {
+ "heuristicAction": "allow"
+ },
+ "sites.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "sitescout.com": {
+ "heuristicAction": "block"
+ },
+ "sjs.bizographics.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602138015634
+ },
+ "skimresources.com": {
+ "heuristicAction": "block"
+ },
+ "skplanet.com": {
+ "heuristicAction": "allow"
+ },
+ "sky.com": {
+ "heuristicAction": "allow"
+ },
+ "sky.it": {
+ "heuristicAction": "allow"
+ },
+ "slashdotmedia.com": {
+ "heuristicAction": "allow"
+ },
+ "smaato.net": {
+ "heuristicAction": "allow"
+ },
+ "smadex.com": {
+ "heuristicAction": "block"
+ },
+ "smartadserver.com": {
+ "heuristicAction": "block"
+ },
+ "smartclick.net": {
+ "heuristicAction": "allow"
+ },
+ "smartlock.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "smartnews-ads.com": {
+ "heuristicAction": "block"
+ },
+ "smartocto.com": {
+ "heuristicAction": "allow"
+ },
+ "smartsurvey.co.uk": {
+ "heuristicAction": "allow"
+ },
+ "smct.co": {
+ "heuristicAction": "allow"
+ },
+ "smi2.net": {
+ "heuristicAction": "block"
+ },
+ "smi2.ru": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601993218631
+ },
+ "smilewanted.com": {
+ "heuristicAction": "allow"
+ },
+ "smithsonian.museum": {
+ "heuristicAction": "allow"
+ },
+ "snapchat.com": {
+ "heuristicAction": "block"
+ },
+ "snapdeal.biz": {
+ "heuristicAction": "allow"
+ },
+ "snapwidget.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602008543867
+ },
+ "snplow.net": {
+ "heuristicAction": "allow"
+ },
+ "snrbox.com": {
+ "heuristicAction": "allow"
+ },
+ "snssdk.com": {
+ "heuristicAction": "block"
+ },
+ "so.com": {
+ "heuristicAction": "allow"
+ },
+ "sobot.com": {
+ "heuristicAction": "block"
+ },
+ "socdm.com": {
+ "heuristicAction": "allow"
+ },
+ "socialintents.com": {
+ "heuristicAction": "allow"
+ },
+ "soflopxl.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602194257939
+ },
+ "softspace.mobi": {
+ "heuristicAction": "allow"
+ },
+ "sogei.it": {
+ "heuristicAction": "allow"
+ },
+ "sogou.com": {
+ "heuristicAction": "allow"
+ },
+ "sohu.com": {
+ "heuristicAction": "allow"
+ },
+ "sojern.com": {
+ "heuristicAction": "block"
+ },
+ "sol-data.com": {
+ "heuristicAction": "allow"
+ },
+ "solarwinds.com": {
+ "heuristicAction": "allow"
+ },
+ "solarwinds.demdex.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602166679164
+ },
+ "solarwinds.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602113549041
+ },
+ "solarwindscom.postaffiliatepro.com": {
+ "heuristicAction": "allow"
+ },
+ "solosegment.com": {
+ "heuristicAction": "block"
+ },
+ "solvemedia.com": {
+ "heuristicAction": "block"
+ },
+ "somoydigital.com": {
+ "heuristicAction": "allow"
+ },
+ "sonobi.com": {
+ "heuristicAction": "block"
+ },
+ "sonygs.112.2o7.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "soundcloud.com": {
+ "heuristicAction": "block"
+ },
+ "soundestlink.com": {
+ "heuristicAction": "allow"
+ },
+ "sp-prod.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "sp-trk.com": {
+ "heuristicAction": "allow"
+ },
+ "sp.analytics.yahoo.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601888585928
+ },
+ "sp0.baidu.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602012667372
+ },
+ "speakol.com": {
+ "heuristicAction": "allow"
+ },
+ "spectate.com": {
+ "heuristicAction": "block"
+ },
+ "speee-ad.jp": {
+ "heuristicAction": "allow"
+ },
+ "sphereup.com": {
+ "heuristicAction": "block"
+ },
+ "sphlabs.com": {
+ "heuristicAction": "allow"
+ },
+ "spiceworks.com": {
+ "heuristicAction": "block"
+ },
+ "spider.af": {
+ "heuristicAction": "allow"
+ },
+ "spir.hit.gemius.pl": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602356071152
+ },
+ "spl.zeotap.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602230859226
+ },
+ "spokenlayer.com": {
+ "heuristicAction": "block"
+ },
+ "sportradarserving.com": {
+ "heuristicAction": "allow"
+ },
+ "sportrecs.com": {
+ "heuristicAction": "allow"
+ },
+ "spot.im": {
+ "heuristicAction": "cookieblock"
+ },
+ "spoteffects.net": {
+ "heuristicAction": "allow"
+ },
+ "spotify.com": {
+ "heuristicAction": "block"
+ },
+ "spotim.market": {
+ "heuristicAction": "allow"
+ },
+ "spotxchange.com": {
+ "heuristicAction": "block"
+ },
+ "spreadsheets.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "spreadshirt.net": {
+ "heuristicAction": "allow"
+ },
+ "spreaker.com": {
+ "heuristicAction": "allow"
+ },
+ "springserve.com": {
+ "heuristicAction": "block"
+ },
+ "sputnik.ru": {
+ "heuristicAction": "block"
+ },
+ "square-enix.com": {
+ "heuristicAction": "allow"
+ },
+ "squren.com": {
+ "heuristicAction": "allow"
+ },
+ "srv-2020-10-04-06.pixel.parsely.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602239681633
+ },
+ "srv.stackadapt.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601966386714
+ },
+ "srvtrck.com": {
+ "heuristicAction": "allow"
+ },
+ "srx.com.sg": {
+ "heuristicAction": "allow"
+ },
+ "ssc-cms.33across.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601968622566
+ },
+ "ssc.33across.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602321438876
+ },
+ "ssense.com": {
+ "heuristicAction": "allow"
+ },
+ "ssg.com": {
+ "heuristicAction": "allow"
+ },
+ "ssl.cdne.cpmstar.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602114651275
+ },
+ "ssl.google-analytics.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602191047157
+ },
+ "ssl.kaptcha.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602011610707
+ },
+ "ssl.widgets.webengage.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602089786764
+ },
+ "sslwidget.criteo.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602331309444
+ },
+ "sspinc.io": {
+ "heuristicAction": "allow"
+ },
+ "ssum-sec.casalemedia.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602269984446
+ },
+ "st-eu.dynamicyield.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "st.dynamicyield.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "st.top100.ru": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601954453930
+ },
+ "st1.dialogtech.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601931908696
+ },
+ "st8fm.com": {
+ "heuristicAction": "allow"
+ },
+ "stack-sonar.com": {
+ "heuristicAction": "block"
+ },
+ "stackadapt.com": {
+ "heuristicAction": "block"
+ },
+ "stackoverflow.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "stackpathcdn.com": {
+ "heuristicAction": "allow"
+ },
+ "stags.bluekai.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602198869250
+ },
+ "stat-rock.com": {
+ "heuristicAction": "allow"
+ },
+ "stat.58che.com": {
+ "heuristicAction": "allow"
+ },
+ "stat.media": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602131719057
+ },
+ "stat.sputnik.ru": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602117670479
+ },
+ "statad.ru": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602117681549
+ },
+ "statcounter.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601910681132
+ },
+ "state.nj.us": {
+ "heuristicAction": "allow"
+ },
+ "static.adman.gr": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602370657040
+ },
+ "static.adzerk.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602027101651
+ },
+ "static.anquan.org": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602192886104
+ },
+ "static.atgsvcs.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601965606799
+ },
+ "static.criteo.com": {
+ "dnt": true,
+ "heuristicAction": "",
+ "nextUpdateTime": 1602329585428
+ },
+ "static.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602248519672
+ },
+ "static.dynamicyield.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "static.hubspot.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "static.mediav.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602007569080
+ },
+ "static.mixi.media": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602399010417
+ },
+ "static.pushe.co": {
+ "heuristicAction": "allow"
+ },
+ "static.queue-it.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "static.site24x7rum.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602328359757
+ },
+ "static.smi2.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602103616945
+ },
+ "static6.smi2.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602072012352
+ },
+ "static8.smi2.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602142620511
+ },
+ "staticcache.org": {
+ "heuristicAction": "allow"
+ },
+ "staticw2.yotpo.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "staticworld.net": {
+ "heuristicAction": "allow"
+ },
+ "staticxx.facebook.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "statistiek.rijksoverheid.nl": {
+ "heuristicAction": "allow"
+ },
+ "stats.g.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601923572193
+ },
+ "stats.monohost.com": {
+ "heuristicAction": "block"
+ },
+ "stats1.wpmudev.com": {
+ "heuristicAction": "allow"
+ },
+ "statse.webtrendslive.com": {
+ "heuristicAction": "allow"
+ },
+ "statsy.net": {
+ "heuristicAction": "allow"
+ },
+ "statuspage.io": {
+ "heuristicAction": "allow"
+ },
+ "stdout.cz": {
+ "heuristicAction": "allow"
+ },
+ "steelcentral.net": {
+ "heuristicAction": "allow"
+ },
+ "steelhousemedia.com": {
+ "heuristicAction": "block"
+ },
+ "stepstone.d3.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602104373051
+ },
+ "stickyadstv.com": {
+ "heuristicAction": "block"
+ },
+ "stockdio.com": {
+ "heuristicAction": "allow"
+ },
+ "storage.googleapis.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "stores-bloomingdales.com": {
+ "heuristicAction": "allow"
+ },
+ "storygize.net": {
+ "heuristicAction": "allow"
+ },
+ "stream.ne.jp": {
+ "heuristicAction": "allow"
+ },
+ "streamingddigital.com": {
+ "heuristicAction": "allow"
+ },
+ "streamtheworld.com": {
+ "heuristicAction": "block"
+ },
+ "stripchat.com": {
+ "heuristicAction": "allow"
+ },
+ "stripe.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "stripe.network": {
+ "heuristicAction": "block"
+ },
+ "stripst.com": {
+ "heuristicAction": "allow"
+ },
+ "striveme.com": {
+ "heuristicAction": "allow"
+ },
+ "stucki.io": {
+ "heuristicAction": "allow"
+ },
+ "studybreakmedia.com": {
+ "heuristicAction": "allow"
+ },
+ "stylight.net": {
+ "heuristicAction": "allow"
+ },
+ "subservis.com": {
+ "heuristicAction": "block"
+ },
+ "summerhamster.com": {
+ "heuristicAction": "block"
+ },
+ "sumo.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602058427021
+ },
+ "sumologic.com": {
+ "heuristicAction": "allow"
+ },
+ "sundaysky.com": {
+ "heuristicAction": "block"
+ },
+ "suning.cn": {
+ "heuristicAction": "allow"
+ },
+ "suning.com": {
+ "heuristicAction": "allow"
+ },
+ "sunrtb.com": {
+ "heuristicAction": "allow"
+ },
+ "supplyframe.com": {
+ "heuristicAction": "block"
+ },
+ "surfcountor.com": {
+ "heuristicAction": "allow"
+ },
+ "survata.com": {
+ "heuristicAction": "allow"
+ },
+ "survey.g.doubleclick.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602253622049
+ },
+ "svd.se": {
+ "heuristicAction": "allow"
+ },
+ "svtrd.com": {
+ "heuristicAction": "allow"
+ },
+ "swiftype.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "swisscom.ch": {
+ "heuristicAction": "allow"
+ },
+ "swisspass.ch": {
+ "heuristicAction": "allow"
+ },
+ "sy.guanjia.qq.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602035908444
+ },
+ "symantec.com": {
+ "heuristicAction": "allow"
+ },
+ "sync.adkernel.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602147540313
+ },
+ "sync.adtelligent.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602344399831
+ },
+ "sync.bfmio.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601957569574
+ },
+ "sync.go.sonobi.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602165653499
+ },
+ "sync.search.spotxchange.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602297085040
+ },
+ "sync.serverbid.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602263991929
+ },
+ "sync.smartadserver.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601920071914
+ },
+ "sync.teads.tv": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602089032828
+ },
+ "synchrobox.adswizz.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602249689678
+ },
+ "synchronycredit.com": {
+ "heuristicAction": "allow"
+ },
+ "syndication.realsrv.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601877720294
+ },
+ "syndication.twitter.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "syndigo.cloud": {
+ "heuristicAction": "allow"
+ },
+ "synopsys.demdex.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601946573109
+ },
+ "synopsysinc.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601918215528
+ },
+ "syr.edu": {
+ "heuristicAction": "allow"
+ },
+ "syuh.net": {
+ "heuristicAction": "allow"
+ },
+ "szzbmy.com": {
+ "heuristicAction": "allow"
+ },
+ "t-mobilemoney.com": {
+ "heuristicAction": "allow"
+ },
+ "t-x.io": {
+ "heuristicAction": "allow"
+ },
+ "t.castle.io": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602064467886
+ },
+ "t.co": {
+ "heuristicAction": "allow"
+ },
+ "t.contentsquare.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602381942912
+ },
+ "t.leady.com": {
+ "heuristicAction": "allow"
+ },
+ "t.riverhit.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602098817755
+ },
+ "t.teads.tv": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602161626412
+ },
+ "taboola.com": {
+ "heuristicAction": "block"
+ },
+ "tacdn.com": {
+ "heuristicAction": "allow"
+ },
+ "tag.bounceexchange.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602181163845
+ },
+ "tag.contextweb.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601898720765
+ },
+ "tag.crsspxl.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602288014371
+ },
+ "tag.getdrip.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602154134775
+ },
+ "tag.mtrcs.samba.tv": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602228110240
+ },
+ "tag.researchnow.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602170632966
+ },
+ "tag.simpli.fi": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602029023410
+ },
+ "tag.yieldoptimizer.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602184388193
+ },
+ "tag4arm.com": {
+ "heuristicAction": "allow"
+ },
+ "tagboard.com": {
+ "heuristicAction": "block"
+ },
+ "tagcommander.com": {
+ "heuristicAction": "allow"
+ },
+ "tagger.opecloud.com": {
+ "dnt": true,
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602091653338
+ },
+ "tags.bluekai.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602323631748
+ },
+ "tags.crwdcntrl.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602155643109
+ },
+ "tags.growingio.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602063727145
+ },
+ "tags.srv.stackadapt.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602017121231
+ },
+ "tags.w55c.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601879168059
+ },
+ "tagtic.cn": {
+ "heuristicAction": "allow"
+ },
+ "tailtarget.com": {
+ "heuristicAction": "block"
+ },
+ "taj1.ebis.ne.jp": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602143174257
+ },
+ "taj2.ebis.ne.jp": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602379219814
+ },
+ "tajs.qq.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602311333065
+ },
+ "talkable.com": {
+ "heuristicAction": "allow"
+ },
+ "talkgadget.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "tam.by": {
+ "heuristicAction": "allow"
+ },
+ "tamedia.com.tw": {
+ "heuristicAction": "allow"
+ },
+ "tamgrt.com": {
+ "heuristicAction": "block"
+ },
+ "tanx.com": {
+ "heuristicAction": "allow"
+ },
+ "taobao.com": {
+ "heuristicAction": "allow"
+ },
+ "tap-cdn.rubiconproject.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602248889731
+ },
+ "tapad.com": {
+ "heuristicAction": "block"
+ },
+ "taplytics.com": {
+ "heuristicAction": "allow"
+ },
+ "tapnative.com": {
+ "heuristicAction": "allow"
+ },
+ "target.mixi.media": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602180846089
+ },
+ "targetspot.com": {
+ "heuristicAction": "block"
+ },
+ "tavoos.net": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601918424570
+ },
+ "tawk.to": {
+ "heuristicAction": "cookieblock"
+ },
+ "taylorandfrancis.com": {
+ "heuristicAction": "allow"
+ },
+ "tazabek.kg": {
+ "heuristicAction": "allow"
+ },
+ "tchibo.de": {
+ "heuristicAction": "allow"
+ },
+ "tctm.co": {
+ "heuristicAction": "allow"
+ },
+ "tdefender.net": {
+ "heuristicAction": "allow"
+ },
+ "teads.tv": {
+ "heuristicAction": "block"
+ },
+ "tealiumiq.com": {
+ "heuristicAction": "block"
+ },
+ "techlab-cdn.com": {
+ "heuristicAction": "block"
+ },
+ "technical-service.net": {
+ "heuristicAction": "block"
+ },
+ "technologyadvice.com": {
+ "heuristicAction": "allow"
+ },
+ "technoratimedia.com": {
+ "heuristicAction": "block"
+ },
+ "techonline.com": {
+ "heuristicAction": "allow"
+ },
+ "techtarget.com": {
+ "heuristicAction": "block"
+ },
+ "techweb.com": {
+ "heuristicAction": "block"
+ },
+ "teenvogue.com": {
+ "heuristicAction": "block"
+ },
+ "telekom.de": {
+ "heuristicAction": "allow"
+ },
+ "telem.highlow.net": {
+ "heuristicAction": "allow"
+ },
+ "teleport.media": {
+ "heuristicAction": "allow"
+ },
+ "televebion.net": {
+ "heuristicAction": "allow"
+ },
+ "tend-table.com": {
+ "heuristicAction": "allow"
+ },
+ "tenmax.io": {
+ "heuristicAction": "allow"
+ },
+ "terminus.services": {
+ "heuristicAction": "block"
+ },
+ "tessabititalia01.wt-eu02.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601940644127
+ },
+ "tfaforms.net": {
+ "heuristicAction": "block"
+ },
+ "theadex.com": {
+ "heuristicAction": "block"
+ },
+ "thebrighttag.com": {
+ "heuristicAction": "block"
+ },
+ "theglobeandmail.ca": {
+ "heuristicAction": "allow"
+ },
+ "thehindu.com": {
+ "heuristicAction": "allow"
+ },
+ "theice.com": {
+ "heuristicAction": "allow"
+ },
+ "thejobnetwork.com": {
+ "heuristicAction": "allow"
+ },
+ "them.us": {
+ "heuristicAction": "block"
+ },
+ "themarker.com": {
+ "heuristicAction": "allow"
+ },
+ "thenewstribune.com": {
+ "heuristicAction": "allow"
+ },
+ "theregister.co.uk": {
+ "heuristicAction": "allow"
+ },
+ "thesame.tv": {
+ "heuristicAction": "allow"
+ },
+ "thesun.co.uk": {
+ "heuristicAction": "allow"
+ },
+ "thinkpad.com": {
+ "heuristicAction": "allow"
+ },
+ "threewave.jp": {
+ "heuristicAction": "allow"
+ },
+ "thron.com": {
+ "heuristicAction": "allow"
+ },
+ "thrtle.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601817960909
+ },
+ "thunderhead.com": {
+ "heuristicAction": "block"
+ },
+ "ti.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "tidaltv.com": {
+ "heuristicAction": "block"
+ },
+ "tie.247-inc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602274672225
+ },
+ "tij.co.jp": {
+ "heuristicAction": "allow"
+ },
+ "timecommerce.net": {
+ "heuristicAction": "block"
+ },
+ "timewarnercable.com": {
+ "heuristicAction": "allow"
+ },
+ "tinkoffinsurance.ru": {
+ "heuristicAction": "allow"
+ },
+ "tinypass.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "tiqcdn.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "titoaktop.com": {
+ "heuristicAction": "allow"
+ },
+ "tkx-acc.apis.anvato.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "tkx.apis.anvato.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "tkx2-prod.anvato.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "tlx.3lift.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602097377602
+ },
+ "tmall.ru": {
+ "heuristicAction": "allow"
+ },
+ "tmobile.com": {
+ "heuristicAction": "allow"
+ },
+ "tns-counter.ru": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602103569233
+ },
+ "tns-cs.net": {
+ "heuristicAction": "allow"
+ },
+ "tns-ua.com": {
+ "heuristicAction": "block"
+ },
+ "toast.com": {
+ "heuristicAction": "block"
+ },
+ "tombot.ai": {
+ "heuristicAction": "allow"
+ },
+ "tomtop.com": {
+ "heuristicAction": "allow"
+ },
+ "tongdun.cn": {
+ "heuristicAction": "allow"
+ },
+ "top-fwz1.mail.ru": {
+ "heuristicAction": "cookieblock"
+ },
+ "top100.ru": {
+ "heuristicAction": "block"
+ },
+ "top4top.io": {
+ "heuristicAction": "allow"
+ },
+ "toplist.cz": {
+ "heuristicAction": "allow"
+ },
+ "tourismnz.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601991925973
+ },
+ "toutapp.com": {
+ "heuristicAction": "allow"
+ },
+ "tpcf.feedify.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602183085925
+ },
+ "tpx.virtuoussoftware.com": {
+ "heuristicAction": "allow"
+ },
+ "tq.cn": {
+ "heuristicAction": "allow"
+ },
+ "tr.hit.gemius.pl": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601903270252
+ },
+ "tr.line.me": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601963397704
+ },
+ "tr.outbrain.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602088464253
+ },
+ "track.adform.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601895353471
+ },
+ "track.hubspot.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602059908134
+ },
+ "track.in.omgpm.com": {
+ "heuristicAction": "allow"
+ },
+ "trackad.cz": {
+ "heuristicAction": "allow"
+ },
+ "trackalyzer.com": {
+ "heuristicAction": "allow"
+ },
+ "tracker.metricool.com": {
+ "heuristicAction": "allow"
+ },
+ "tracking.imspublishergroup.com": {
+ "heuristicAction": "allow"
+ },
+ "tracking.magnetmail.net": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602356020492
+ },
+ "tradablebits.com": {
+ "heuristicAction": "allow"
+ },
+ "tradedoubler.com": {
+ "heuristicAction": "block"
+ },
+ "tradelab.fr": {
+ "heuristicAction": "block"
+ },
+ "tradingview.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "traffic-media.co.uk": {
+ "heuristicAction": "allow"
+ },
+ "trafficbass.com": {
+ "heuristicAction": "block"
+ },
+ "trafficdok.com": {
+ "heuristicAction": "allow"
+ },
+ "trafficgate.net": {
+ "heuristicAction": "allow"
+ },
+ "trafficgateway.research-int.se": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602117570192
+ },
+ "trafficguard.ai": {
+ "heuristicAction": "block"
+ },
+ "trafficjunky.net": {
+ "heuristicAction": "block"
+ },
+ "trafficlide.com": {
+ "heuristicAction": "allow"
+ },
+ "trafficsan.com": {
+ "heuristicAction": "allow"
+ },
+ "trafmag.com": {
+ "heuristicAction": "block"
+ },
+ "transferwise.com": {
+ "heuristicAction": "allow"
+ },
+ "translate.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "travelaudience.com": {
+ "heuristicAction": "allow"
+ },
+ "trbna.com": {
+ "heuristicAction": "allow"
+ },
+ "trc.taboola.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602226893177
+ },
+ "trck.bebi.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601887189692
+ },
+ "treasuredata.com": {
+ "heuristicAction": "block"
+ },
+ "tremorhub.com": {
+ "heuristicAction": "block"
+ },
+ "trendemon.com": {
+ "heuristicAction": "block"
+ },
+ "trendmd.com": {
+ "heuristicAction": "allow"
+ },
+ "trends.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "trends.so.com": {
+ "heuristicAction": "allow"
+ },
+ "tribalfusion.com": {
+ "heuristicAction": "block"
+ },
+ "tribl.io": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602093085208
+ },
+ "trinitymedia.ai": {
+ "heuristicAction": "allow"
+ },
+ "trip.com": {
+ "heuristicAction": "allow"
+ },
+ "tripadvisor.com": {
+ "heuristicAction": "allow"
+ },
+ "tripcdn.com": {
+ "heuristicAction": "allow"
+ },
+ "tritondigitalcom.mpeasylink.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602394073297
+ },
+ "trk.techtarget.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602354783188
+ },
+ "trkn.us": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601938841368
+ },
+ "trs.cn": {
+ "heuristicAction": "allow"
+ },
+ "truefitcorp.com": {
+ "heuristicAction": "allow"
+ },
+ "truehits.in.th": {
+ "heuristicAction": "block"
+ },
+ "truepush.com": {
+ "heuristicAction": "block"
+ },
+ "trumba.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "truoptik.com": {
+ "heuristicAction": "allow"
+ },
+ "trustarc.com": {
+ "heuristicAction": "block"
+ },
+ "trustcommander.net": {
+ "heuristicAction": "allow"
+ },
+ "trustedsite.com": {
+ "heuristicAction": "allow"
+ },
+ "trustivity.es": {
+ "heuristicAction": "allow"
+ },
+ "trustseal.enamad.ir": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601994455536
+ },
+ "trustspot.io": {
+ "heuristicAction": "allow"
+ },
+ "trvl-px.com": {
+ "heuristicAction": "allow"
+ },
+ "trwl1.com": {
+ "heuristicAction": "allow"
+ },
+ "trysera.com": {
+ "heuristicAction": "allow"
+ },
+ "tsyndicate.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601933193114
+ },
+ "tucarro.com.co": {
+ "heuristicAction": "allow"
+ },
+ "tucarro.com.ve": {
+ "heuristicAction": "allow"
+ },
+ "tuinmueble.com.ve": {
+ "heuristicAction": "allow"
+ },
+ "tumoto.com.co": {
+ "heuristicAction": "allow"
+ },
+ "tumoto.com.ve": {
+ "heuristicAction": "allow"
+ },
+ "turn.com": {
+ "heuristicAction": "block"
+ },
+ "tutu.travel": {
+ "heuristicAction": "allow"
+ },
+ "tvinsider.com": {
+ "heuristicAction": "allow"
+ },
+ "tvopen.gr": {
+ "heuristicAction": "allow"
+ },
+ "tvpage.com": {
+ "heuristicAction": "allow"
+ },
+ "tvpixel.com": {
+ "heuristicAction": "block"
+ },
+ "tvsquared.com": {
+ "heuristicAction": "block"
+ },
+ "tw.cx": {
+ "heuristicAction": "allow"
+ },
+ "twcroadrunner.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601893173850
+ },
+ "twimg.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "twitch.tv": {
+ "heuristicAction": "cookieblock"
+ },
+ "twitter.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "twnmm.com": {
+ "heuristicAction": "allow"
+ },
+ "tynt.com": {
+ "heuristicAction": "block"
+ },
+ "typekit.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "u.myopenads.com": {
+ "heuristicAction": "allow"
+ },
+ "u.openx.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602322494313
+ },
+ "u7u9.com": {
+ "heuristicAction": "allow"
+ },
+ "ua.tutu.travel": {
+ "heuristicAction": "allow"
+ },
+ "ua.yektanet.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602163743001
+ },
+ "uadexchange.com": {
+ "heuristicAction": "allow"
+ },
+ "ubic.tech": {
+ "heuristicAction": "allow"
+ },
+ "ubm.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602017368947
+ },
+ "ubmtech.d3.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602299287152
+ },
+ "uc.se": {
+ "heuristicAction": "allow"
+ },
+ "ucfly.com": {
+ "heuristicAction": "allow"
+ },
+ "ucgstatic.eu": {
+ "heuristicAction": "allow"
+ },
+ "uciservice.com": {
+ "heuristicAction": "allow"
+ },
+ "udemy.com": {
+ "heuristicAction": "allow"
+ },
+ "udesk.cn": {
+ "heuristicAction": "block"
+ },
+ "udimg.com": {
+ "heuristicAction": "allow"
+ },
+ "udmserve.net": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602090024562
+ },
+ "ufpcdn.com": {
+ "heuristicAction": "allow"
+ },
+ "ughr.contentexchange.me": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602067823662
+ },
+ "uicdn.net": {
+ "heuristicAction": "block"
+ },
+ "uikc.net": {
+ "heuristicAction": "allow"
+ },
+ "uimserv.net": {
+ "heuristicAction": "allow"
+ },
+ "ukr.net": {
+ "heuristicAction": "allow"
+ },
+ "ukw.jp": {
+ "heuristicAction": "allow"
+ },
+ "ulb.ac.be": {
+ "heuristicAction": "allow"
+ },
+ "ulclick.ru": {
+ "heuristicAction": "allow"
+ },
+ "ulogin.ru": {
+ "heuristicAction": "allow"
+ },
+ "ultainc.com": {
+ "heuristicAction": "allow"
+ },
+ "ultimate-guitar-d.openx.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602167774661
+ },
+ "ultimedia.com": {
+ "heuristicAction": "allow"
+ },
+ "unbxdapi.com": {
+ "heuristicAction": "allow"
+ },
+ "uncn.jp": {
+ "heuristicAction": "allow"
+ },
+ "uncrate.supply": {
+ "heuristicAction": "allow"
+ },
+ "undertone.com": {
+ "heuristicAction": "block"
+ },
+ "uni-frankfurt.de": {
+ "heuristicAction": "allow"
+ },
+ "unicc.org": {
+ "heuristicAction": "allow"
+ },
+ "unidata.ai": {
+ "heuristicAction": "allow"
+ },
+ "unileverna.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602291220552
+ },
+ "unileverna.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602254186366
+ },
+ "unisender.com": {
+ "heuristicAction": "allow"
+ },
+ "unite.com": {
+ "heuristicAction": "allow"
+ },
+ "unsplash.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "uol.com.br": {
+ "heuristicAction": "allow"
+ },
+ "uplift-platform.com": {
+ "heuristicAction": "allow"
+ },
+ "upravel.com": {
+ "heuristicAction": "block"
+ },
+ "ups.analytics.yahoo.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602116844291
+ },
+ "upsellit.com": {
+ "heuristicAction": "allow"
+ },
+ "uptime.com": {
+ "heuristicAction": "block"
+ },
+ "uq.net.au": {
+ "heuristicAction": "allow"
+ },
+ "uqhv.net": {
+ "heuristicAction": "allow"
+ },
+ "urbandictionary.store": {
+ "heuristicAction": "allow"
+ },
+ "urldefense.proofpoint.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602051293160
+ },
+ "us-central1-ah-acemarketingteam.cloudfunctions.net": {
+ "heuristicAction": "allow"
+ },
+ "us-central1-zendesk-functions.cloudfunctions.net": {
+ "heuristicAction": "allow"
+ },
+ "us-u.openx.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601919909061
+ },
+ "us.commitchange.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602236744801
+ },
+ "us.creativecdn.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602342025706
+ },
+ "usaa360.com": {
+ "heuristicAction": "allow"
+ },
+ "useinsider.com": {
+ "heuristicAction": "block"
+ },
+ "user-red.com": {
+ "heuristicAction": "allow"
+ },
+ "usercentrics.eu": {
+ "heuristicAction": "block"
+ },
+ "usergram.info": {
+ "heuristicAction": "block"
+ },
+ "userreplay.net": {
+ "heuristicAction": "block"
+ },
+ "userreport.com": {
+ "heuristicAction": "block"
+ },
+ "uservoice.com": {
+ "heuristicAction": "block"
+ },
+ "userzoom.com": {
+ "heuristicAction": "allow"
+ },
+ "usocial.pro": {
+ "heuristicAction": "allow"
+ },
+ "usonar.jp": {
+ "heuristicAction": "allow"
+ },
+ "uspech.sk": {
+ "heuristicAction": "allow"
+ },
+ "utarget.ru": {
+ "heuristicAction": "allow"
+ },
+ "uuidksinc.net": {
+ "heuristicAction": "allow"
+ },
+ "uxfeedback.ru": {
+ "heuristicAction": "block"
+ },
+ "v1.cnzz.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602306542384
+ },
+ "v2.ferret-one.com": {
+ "heuristicAction": "allow"
+ },
+ "vads.net.vn": {
+ "heuristicAction": "allow"
+ },
+ "valkirum.com": {
+ "heuristicAction": "allow"
+ },
+ "valuecommerce.com": {
+ "heuristicAction": "block"
+ },
+ "valuecommerce.ne.jp": {
+ "heuristicAction": "allow"
+ },
+ "vanityfair.com": {
+ "heuristicAction": "block"
+ },
+ "veinteractive.com": {
+ "heuristicAction": "allow"
+ },
+ "velaro.com": {
+ "heuristicAction": "allow"
+ },
+ "vendemore.com": {
+ "heuristicAction": "allow"
+ },
+ "vergic.com": {
+ "heuristicAction": "allow"
+ },
+ "vertebrae-axis.com": {
+ "heuristicAction": "allow"
+ },
+ "verticalhealth.net": {
+ "heuristicAction": "allow"
+ },
+ "vgtrk.com": {
+ "heuristicAction": "allow"
+ },
+ "vgwort.de": {
+ "heuristicAction": "allow"
+ },
+ "viafoura.co": {
+ "heuristicAction": "block"
+ },
+ "viatorinc.com": {
+ "heuristicAction": "allow"
+ },
+ "vid.springserve.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601943046815
+ },
+ "vidads.gr": {
+ "heuristicAction": "allow"
+ },
+ "vidassets.terminus.services": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602089418705
+ },
+ "vidazoo.com": {
+ "heuristicAction": "allow"
+ },
+ "video-ads.rubiconproject.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602185582359
+ },
+ "video-cdn.net": {
+ "heuristicAction": "allow"
+ },
+ "video.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "videohub.tv": {
+ "heuristicAction": "block"
+ },
+ "vidgrid.com": {
+ "heuristicAction": "allow"
+ },
+ "vidible.tv": {
+ "heuristicAction": "cookieblock"
+ },
+ "vidio.com": {
+ "heuristicAction": "allow"
+ },
+ "vidyard.com": {
+ "heuristicAction": "block"
+ },
+ "vietid.net": {
+ "heuristicAction": "allow"
+ },
+ "vietnamnettv.vn": {
+ "heuristicAction": "allow"
+ },
+ "viglink.com": {
+ "heuristicAction": "block"
+ },
+ "vihub.ru": {
+ "heuristicAction": "block"
+ },
+ "viki.io": {
+ "heuristicAction": "allow"
+ },
+ "vindicosuite.com": {
+ "heuristicAction": "block"
+ },
+ "viostream.com": {
+ "heuristicAction": "allow"
+ },
+ "vip.com": {
+ "heuristicAction": "allow"
+ },
+ "vipstatic.com": {
+ "heuristicAction": "allow"
+ },
+ "viqeo.tv": {
+ "heuristicAction": "allow"
+ },
+ "viralize.tv": {
+ "heuristicAction": "allow"
+ },
+ "virgul.com": {
+ "heuristicAction": "allow"
+ },
+ "virtuoussoftware.com": {
+ "heuristicAction": "allow"
+ },
+ "visa.com": {
+ "heuristicAction": "allow"
+ },
+ "visilabs.net": {
+ "heuristicAction": "allow"
+ },
+ "visitor-service.tealiumiq.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601938774970
+ },
+ "visitor-track.com": {
+ "heuristicAction": "allow"
+ },
+ "visualstudio.com": {
+ "heuristicAction": "block"
+ },
+ "visualwebsiteoptimizer.com": {
+ "heuristicAction": "block"
+ },
+ "vivino.com": {
+ "heuristicAction": "allow"
+ },
+ "vivocha.com": {
+ "heuristicAction": "allow"
+ },
+ "vizergy.com": {
+ "heuristicAction": "allow"
+ },
+ "vizury.com": {
+ "heuristicAction": "allow"
+ },
+ "vk.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601925889427
+ },
+ "vnecdn.net": {
+ "heuristicAction": "allow"
+ },
+ "vodgc.net": {
+ "heuristicAction": "allow"
+ },
+ "vogue.com": {
+ "heuristicAction": "block"
+ },
+ "voidboost.net": {
+ "heuristicAction": "allow"
+ },
+ "volvelle.tech": {
+ "heuristicAction": "allow"
+ },
+ "voxmedia.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "vporn.com": {
+ "heuristicAction": "allow"
+ },
+ "vroom.be": {
+ "heuristicAction": "allow"
+ },
+ "vrtzads.com": {
+ "heuristicAction": "allow"
+ },
+ "vstocklab.com": {
+ "heuristicAction": "allow"
+ },
+ "vt.myvisualiq.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601973714294
+ },
+ "vupulse.com": {
+ "heuristicAction": "allow"
+ },
+ "vzew.net": {
+ "heuristicAction": "allow"
+ },
+ "w.cnzz.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602001681617
+ },
+ "w.estat.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602280601366
+ },
+ "w.soundcloud.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602240076207
+ },
+ "w55c.net": {
+ "heuristicAction": "block"
+ },
+ "w8.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "walkme.com": {
+ "heuristicAction": "allow"
+ },
+ "wallkit.net": {
+ "heuristicAction": "allow"
+ },
+ "wan.liebao.cn": {
+ "heuristicAction": "allow"
+ },
+ "watertu.com": {
+ "heuristicAction": "allow"
+ },
+ "waytogrow-d.openx.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602264248553
+ },
+ "wbtrk.net": {
+ "heuristicAction": "block"
+ },
+ "wcfbc.net": {
+ "heuristicAction": "block"
+ },
+ "wcs.naver.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601931986654
+ },
+ "wdsvc.net": {
+ "heuristicAction": "block"
+ },
+ "web.hb.ad.cpe.dotomi.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602260342262
+ },
+ "webankieta.pl": {
+ "heuristicAction": "allow"
+ },
+ "webantenna.info": {
+ "heuristicAction": "block"
+ },
+ "webengage.com": {
+ "heuristicAction": "block"
+ },
+ "webeyez.com": {
+ "heuristicAction": "allow"
+ },
+ "webforms-here.com": {
+ "heuristicAction": "allow"
+ },
+ "webmd.com": {
+ "heuristicAction": "allow"
+ },
+ "webnode.com": {
+ "heuristicAction": "allow"
+ },
+ "weborama.fr": {
+ "heuristicAction": "block"
+ },
+ "webpubcontent.raycommedia.com": {
+ "heuristicAction": "allow"
+ },
+ "webpush.jp": {
+ "heuristicAction": "block"
+ },
+ "webs.com": {
+ "heuristicAction": "allow"
+ },
+ "websdk.appsflyer.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602309768472
+ },
+ "webspectator.com": {
+ "heuristicAction": "block"
+ },
+ "webterren.com": {
+ "heuristicAction": "block"
+ },
+ "webtracker.jp": {
+ "heuristicAction": "allow"
+ },
+ "webtrafficsource.com": {
+ "heuristicAction": "allow"
+ },
+ "webtrekk.net": {
+ "heuristicAction": "block"
+ },
+ "webtrendslive.com": {
+ "heuristicAction": "allow"
+ },
+ "webturn.ru": {
+ "heuristicAction": "allow"
+ },
+ "webullfintech.com": {
+ "heuristicAction": "allow"
+ },
+ "webvisor.org": {
+ "heuristicAction": "block"
+ },
+ "weekli.de": {
+ "heuristicAction": "allow"
+ },
+ "weibo.com": {
+ "heuristicAction": "block"
+ },
+ "wellsmedia.com": {
+ "heuristicAction": "allow"
+ },
+ "wemfbox.ch": {
+ "heuristicAction": "block"
+ },
+ "wemorefun.com": {
+ "heuristicAction": "allow"
+ },
+ "west.cn": {
+ "heuristicAction": "allow"
+ },
+ "westernsydneyuni.tt.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602391504256
+ },
+ "wgu.demdex.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602230387749
+ },
+ "whistleout.com": {
+ "heuristicAction": "allow"
+ },
+ "wi-fi.ru": {
+ "heuristicAction": "block"
+ },
+ "widengle.com": {
+ "heuristicAction": "allow"
+ },
+ "widget-mediator.zopim.com": {
+ "heuristicAction": "allow"
+ },
+ "widgets.tvinsider.com": {
+ "heuristicAction": "allow"
+ },
+ "wikia-services.com": {
+ "heuristicAction": "allow"
+ },
+ "wikipedia.org": {
+ "heuristicAction": "allow"
+ },
+ "wintechnologies.demdex.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602355945198
+ },
+ "wiqhit.com": {
+ "heuristicAction": "allow"
+ },
+ "wired.com": {
+ "heuristicAction": "block"
+ },
+ "wishabi.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "wisokykulas.bid": {
+ "heuristicAction": "allow"
+ },
+ "wistia.com": {
+ "heuristicAction": "allow"
+ },
+ "wistia.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "wix.com": {
+ "heuristicAction": "allow"
+ },
+ "wkxppshj-qx.global.ssl.fastly.net": {
+ "heuristicAction": "cookieblock"
+ },
+ "wnyc.org": {
+ "heuristicAction": "allow"
+ },
+ "wo-cloud.com": {
+ "heuristicAction": "allow"
+ },
+ "wondershare.com": {
+ "heuristicAction": "allow"
+ },
+ "workplace.tools": {
+ "heuristicAction": "allow"
+ },
+ "worldbankgroup.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602384920990
+ },
+ "wp.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "wpa.b.qq.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602206222609
+ },
+ "wpa.qq.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602217904450
+ },
+ "wpmudev.com": {
+ "heuristicAction": "allow"
+ },
+ "ws.sharethis.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602347496165
+ },
+ "wsod.com": {
+ "heuristicAction": "block"
+ },
+ "wsu.demdex.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601903384315
+ },
+ "wsu.sc.omtrdc.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602190813278
+ },
+ "wt-eu02.net": {
+ "heuristicAction": "block"
+ },
+ "wt.soundestlink.com": {
+ "heuristicAction": "allow"
+ },
+ "wufoo.com": {
+ "heuristicAction": "allow"
+ },
+ "ww1097.smartadserver.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601885701147
+ },
+ "www.aftonbladet.se": {
+ "heuristicAction": "allow"
+ },
+ "www.alsa.org": {
+ "heuristicAction": "allow"
+ },
+ "www.barilliance.net": {
+ "heuristicAction": "allow"
+ },
+ "www.bing.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "www.bizographics.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602336555860
+ },
+ "www.blogsky.com": {
+ "heuristicAction": "allow"
+ },
+ "www.clublibertaddigital.com": {
+ "heuristicAction": "allow"
+ },
+ "www.dataplusmath.com": {
+ "heuristicAction": "allow"
+ },
+ "www.drcareers.ca": {
+ "heuristicAction": "allow"
+ },
+ "www.dropbox.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602396705479
+ },
+ "www.duba.com": {
+ "heuristicAction": "allow"
+ },
+ "www.facebook.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "www.fastcounter.de": {
+ "heuristicAction": "allow"
+ },
+ "www.fresnobee.com": {
+ "heuristicAction": "allow"
+ },
+ "www.gimp.org": {
+ "heuristicAction": "allow"
+ },
+ "www.glassdoor.com": {
+ "heuristicAction": "allow"
+ },
+ "www.google-analytics.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602158166176
+ },
+ "www.google.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "www.i.matheranalytics.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601907374810
+ },
+ "www.lightboxcdn.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602084731122
+ },
+ "www.medtargetsystem.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602161711148
+ },
+ "www.mulesoft.com": {
+ "heuristicAction": "allow"
+ },
+ "www.patreon.com": {
+ "heuristicAction": "allow"
+ },
+ "www.prlog.org": {
+ "heuristicAction": "allow"
+ },
+ "www.rumiview.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602063993962
+ },
+ "www.sacbee.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602137148935
+ },
+ "www.sobot.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602091972046
+ },
+ "www.socialintents.com": {
+ "heuristicAction": "allow"
+ },
+ "www.statcounter.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602158471844
+ },
+ "www.summerhamster.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601997652028
+ },
+ "www.thenewstribune.com": {
+ "heuristicAction": "allow"
+ },
+ "www.tns-counter.ru": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602150975062
+ },
+ "www.ultimedia.com": {
+ "heuristicAction": "allow"
+ },
+ "www.webnode.com": {
+ "heuristicAction": "allow"
+ },
+ "www.whistleout.com": {
+ "heuristicAction": "allow"
+ },
+ "www.wikipedia.org": {
+ "heuristicAction": "allow"
+ },
+ "www.youtube.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "www.youvisit.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602012142114
+ },
+ "wwwimages.adobe.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "wzrkt.com": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602264066531
+ },
+ "x.bidswitch.net": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602218329857
+ },
+ "xesimg.com": {
+ "heuristicAction": "allow"
+ },
+ "xg4ken.com": {
+ "heuristicAction": "block"
+ },
+ "xhr.invl.co": {
+ "heuristicAction": "allow"
+ },
+ "xhuc.net": {
+ "heuristicAction": "allow"
+ },
+ "xinhuanet.com": {
+ "heuristicAction": "allow"
+ },
+ "xinnet.com": {
+ "heuristicAction": "allow"
+ },
+ "xiti.com": {
+ "heuristicAction": "block"
+ },
+ "xiu123.cn": {
+ "heuristicAction": "allow"
+ },
+ "xlisting.jp": {
+ "heuristicAction": "block"
+ },
+ "xsdownload.adobe.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "xspadvertising.com": {
+ "heuristicAction": "block"
+ },
+ "xtremepush.com": {
+ "heuristicAction": "block"
+ },
+ "xuannaer.datasink.sensorsdata.cn": {
+ "heuristicAction": "block"
+ },
+ "xunlei.com": {
+ "heuristicAction": "allow"
+ },
+ "xxxlutz.de": {
+ "heuristicAction": "allow"
+ },
+ "y3.analytics.yahoo.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "yad2.co.il": {
+ "heuristicAction": "allow"
+ },
+ "yadro.ru": {
+ "heuristicAction": "block"
+ },
+ "yads.yahoo.co.jp": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601984011639
+ },
+ "yahoo.co.jp": {
+ "heuristicAction": "block"
+ },
+ "yahoo.com": {
+ "heuristicAction": "block"
+ },
+ "yahoo.net": {
+ "heuristicAction": "allow"
+ },
+ "yandex.ru": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1601896175459
+ },
+ "yapfiles.ru": {
+ "heuristicAction": "allow"
+ },
+ "yccdn.com": {
+ "heuristicAction": "allow"
+ },
+ "yektanet.com": {
+ "heuristicAction": "block"
+ },
+ "yellowblue.io": {
+ "heuristicAction": "allow"
+ },
+ "yiche.com": {
+ "heuristicAction": "allow"
+ },
+ "yieldify.com": {
+ "heuristicAction": "allow"
+ },
+ "yieldlab.net": {
+ "heuristicAction": "block"
+ },
+ "yieldmanager.com": {
+ "heuristicAction": "allow"
+ },
+ "yieldmo.com": {
+ "heuristicAction": "block"
+ },
+ "yieldoptimizer.com": {
+ "heuristicAction": "block"
+ },
+ "yjtag.yahoo.co.jp": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601886321420
+ },
+ "yodasoft.in": {
+ "heuristicAction": "allow"
+ },
+ "yomedia.vn": {
+ "heuristicAction": "allow"
+ },
+ "yonhapnews.co.kr": {
+ "heuristicAction": "allow"
+ },
+ "yoox.it": {
+ "heuristicAction": "block"
+ },
+ "yotpo.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "youdemai.com": {
+ "heuristicAction": "allow"
+ },
+ "youku.com": {
+ "heuristicAction": "allow"
+ },
+ "youplay.se": {
+ "heuristicAction": "allow"
+ },
+ "youtube-nocookie.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "youtube.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "youvisit.com": {
+ "heuristicAction": "block"
+ },
+ "yumpu.com": {
+ "heuristicAction": "allow"
+ },
+ "yunaq.com": {
+ "heuristicAction": "block"
+ },
+ "yystatic.com": {
+ "heuristicAction": "allow"
+ },
+ "z-analytics.net": {
+ "heuristicAction": "allow"
+ },
+ "z-na.amazon-adsystem.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602112943968
+ },
+ "z.moatads.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1601951726373
+ },
+ "z6rjha.net": {
+ "heuristicAction": "allow"
+ },
+ "zadn.vn": {
+ "heuristicAction": "allow"
+ },
+ "zaius.com": {
+ "heuristicAction": "allow"
+ },
+ "zalo.me": {
+ "heuristicAction": "block"
+ },
+ "zaloapp.com": {
+ "heuristicAction": "allow"
+ },
+ "zara.net": {
+ "heuristicAction": "allow"
+ },
+ "zarabotkipro.ru": {
+ "heuristicAction": "allow"
+ },
+ "zdbb.net": {
+ "heuristicAction": "block",
+ "nextUpdateTime": 1602269598152
+ },
+ "zdmimg.com": {
+ "heuristicAction": "allow"
+ },
+ "zdw.w8.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "zdwidget3-bs.sphereup.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602289914755
+ },
+ "zebestof.com": {
+ "heuristicAction": "allow"
+ },
+ "zedo.com": {
+ "heuristicAction": "block"
+ },
+ "zemanta.com": {
+ "heuristicAction": "block"
+ },
+ "zendesk.com": {
+ "heuristicAction": "cookieblock"
+ },
+ "zengenti.com": {
+ "heuristicAction": "allow"
+ },
+ "zeotap.com": {
+ "heuristicAction": "block"
+ },
+ "zergnet.com": {
+ "heuristicAction": "block"
+ },
+ "zero.kz": {
+ "heuristicAction": "allow"
+ },
+ "zeronaught.com": {
+ "heuristicAction": "allow"
+ },
+ "zg-api.com": {
+ "heuristicAction": "allow"
+ },
+ "zhugeapi.net": {
+ "heuristicAction": "allow"
+ },
+ "zhugeio.com": {
+ "heuristicAction": "allow"
+ },
+ "ziffdavis.com": {
+ "heuristicAction": "allow"
+ },
+ "ziftsolutions.com": {
+ "heuristicAction": "allow"
+ },
+ "zimmo.be": {
+ "heuristicAction": "allow"
+ },
+ "zineone.com": {
+ "heuristicAction": "allow"
+ },
+ "zippyfrog.co": {
+ "heuristicAction": "allow"
+ },
+ "zipwiresw.com": {
+ "heuristicAction": "allow"
+ },
+ "znsps-bl6wf.ads.tremorhub.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602031702130
+ },
+ "znsv.baidu.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602132718722
+ },
+ "zoho.com": {
+ "heuristicAction": "allow"
+ },
+ "zoho.in": {
+ "heuristicAction": "allow"
+ },
+ "zol.com.cn": {
+ "heuristicAction": "allow"
+ },
+ "zonebourse.com": {
+ "heuristicAction": "allow"
+ },
+ "zoomanalytics.co": {
+ "heuristicAction": "allow"
+ },
+ "zoominfo.com": {
+ "heuristicAction": "block"
+ },
+ "zoomph.com": {
+ "heuristicAction": "allow"
+ },
+ "zopim.com": {
+ "heuristicAction": "allow"
+ },
+ "zprk.io": {
+ "heuristicAction": "block"
+ },
+ "zs4.cnzz.com": {
+ "heuristicAction": "",
+ "nextUpdateTime": 1602055606931
+ },
+ "ztsrv.com": {
+ "heuristicAction": "allow"
+ },
+ "zucks.net": {
+ "heuristicAction": "allow"
+ }
+ },
+ "snitch_map": {
+ "01net.com": [
+ "liberation.fr"
+ ],
+ "0914.global.ssl.fastly.net": [
+ "etonline.com",
+ "wwe.com"
+ ],
+ "100widgets.com": [
+ "informationweek.com"
+ ],
+ "10hui.es": [
+ "ifvod.tv"
+ ],
+ "110.93.143.144": [
+ "koreaherald.com"
+ ],
+ "11183.com.cn": [
+ "ems.com.cn"
+ ],
+ "120askimages.com": [
+ "120ask.com"
+ ],
+ "123apps.com": [
+ "online-audio-converter.com"
+ ],
+ "126.net": [
+ "lawtime.cn"
+ ],
+ "163.com": [
+ "lawtime.cn",
+ "lofter.com"
+ ],
+ "1dmp.io": [
+ "rambler.ru",
+ "hh.ru",
+ "ivi.tv"
+ ],
+ "247-inc.net": [
+ "marriott.com",
+ "bestbuy.com",
+ "siriusxm.com"
+ ],
+ "24smi.net": [
+ "inosmi.ru",
+ "ng.ru"
+ ],
+ "2checkout.com": [
+ "hola.org",
+ "wps.com"
+ ],
+ "2o7.net": [
+ "flickr.com",
+ "usnews.com",
+ "prnewswire.com",
+ "crainsnewyork.com",
+ "sony.co.jp"
+ ],
+ "2t23.net": [
+ "homedepot.ca"
+ ],
+ "33across.com": [
+ "w3schools.com",
+ "ask.com",
+ "op.gg"
+ ],
+ "360.cn": [
+ "so.com",
+ "jc35.com",
+ "koolearn.com"
+ ],
+ "360yield.com": [
+ "okezone.com",
+ "dailymotion.com",
+ "youm7.com"
+ ],
+ "3conline.com": [
+ "pcbaby.com.cn",
+ "pchouse.com.cn",
+ "pcauto.com.cn"
+ ],
+ "3ds.com": [
+ "solidworks.com"
+ ],
+ "3gl.net": [
+ "investopedia.com",
+ "thoughtco.com",
+ "bhphotovideo.com"
+ ],
+ "3lift.com": [
+ "msn.com",
+ "okezone.com",
+ "sourceforge.net"
+ ],
+ "40nuggets.com": [
+ "jewishvirtuallibrary.org"
+ ],
+ "4dex.io": [
+ "lepoint.fr",
+ "wiocha.pl",
+ "pressherald.com"
+ ],
+ "4paradigm.com": [
+ "2345.com",
+ "duba.com"
+ ],
+ "4pda.to": [
+ "4pda.ru"
+ ],
+ "4strokemedia.com": [
+ "tiscali.it",
+ "ilmeteo.it"
+ ],
+ "50bang.org": [
+ "2345.com",
+ "mydrivers.com",
+ "6789.com"
+ ],
+ "51.la": [
+ "haoyer.com",
+ "312168.com",
+ "foodmate.net"
+ ],
+ "53kf.com": [
+ "300.cn",
+ "liuxue86.com"
+ ],
+ "58.com": [
+ "anjuke.com"
+ ],
+ "58.com.cn": [
+ "anjuke.com"
+ ],
+ "58cdn.com.cn": [
+ "anjuke.com"
+ ],
+ "58che.com": [
+ "cnmo.com"
+ ],
+ "6noy.net": [
+ "goop.com"
+ ],
+ "6sc.co": [
+ "opendns.com",
+ "criteo.com",
+ "hootsuite.com"
+ ],
+ "71360.com": [
+ "sina.com.cn"
+ ],
+ "7eer.net": [
+ "shutterstock.com",
+ "networksolutions.com",
+ "linksys.com"
+ ],
+ "7gra.us": [
+ "todamateria.com.br"
+ ],
+ "7xbid.com": [
+ "jawapos.com"
+ ],
+ "8v4lqg.net": [
+ "avid.com"
+ ],
+ "a-mo.net": [
+ "9to5mac.com",
+ "electrek.co",
+ "9to5google.com"
+ ],
+ "aafp.net": [
+ "aafp.org"
+ ],
+ "aamsitecertifier.com": [
+ "bizjournals.com",
+ "reviewjournal.com",
+ "postandcourier.com"
+ ],
+ "aan.com": [
+ "neurology.org"
+ ],
+ "aasaam.com": [
+ "borna.news",
+ "rokna.net",
+ "shomanews.com"
+ ],
+ "aau-search-web-prod.azurewebsites.net": [
+ "aau.dk"
+ ],
+ "aau-search-webservice-v1-prod.azurewebsites.net": [
+ "aau.dk"
+ ],
+ "aaxads.com": [
+ "reddit.com",
+ "forbes.com",
+ "mashable.com"
+ ],
+ "about.co.kr": [
+ "gmarket.co.kr",
+ "auction.co.kr"
+ ],
+ "abtasty.com": [
+ "christianitytoday.com"
+ ],
+ "abtshield.com": [
+ "gazeta.pl"
+ ],
+ "acast.cloud": [
+ "acast.com"
+ ],
+ "acast.com": [
+ "newstatesman.com",
+ "bloody-disgusting.com"
+ ],
+ "accesstrade.net": [
+ "moppy.jp"
+ ],
+ "accorhotels.com": [
+ "accor.com",
+ "fairmont.com"
+ ],
+ "accorhotels.ws": [
+ "accor.com"
+ ],
+ "accu-web-raine.azurewebsites.net": [
+ "accuweather.com"
+ ],
+ "acint.net": [
+ "aif.ru"
+ ],
+ "acpm.fr": [
+ "lefigaro.fr",
+ "lequipe.fr",
+ "lexpress.fr"
+ ],
+ "acquia.com": [
+ "panasonic.com",
+ "iop.org",
+ "ama-assn.org"
+ ],
+ "acstat.com": [
+ "alfabank.ru",
+ "eldorado.ru"
+ ],
+ "actionnetwork.org": [
+ "dailykos.com"
+ ],
+ "activecalendar.com": [
+ "villanova.edu"
+ ],
+ "activehosted.com": [
+ "makezine.com",
+ "adsoftheworld.com",
+ "admedo.com"
+ ],
+ "activetrail.com": [
+ "mako.co.il"
+ ],
+ "acuityplatform.com": [
+ "fool.com",
+ "medscape.com",
+ "spreaker.com"
+ ],
+ "acyzh.com": [
+ "fx678.com"
+ ],
+ "ad-lancers.jp": [
+ "lancers.jp"
+ ],
+ "ad-plus.cn": [
+ "sohu.com"
+ ],
+ "ad-score.com": [
+ "ettoday.net",
+ "mentalfloss.com",
+ "metacafe.com"
+ ],
+ "ad-srv.net": [
+ "swarovski.com"
+ ],
+ "ad-stir.com": [
+ "lolipop.jp",
+ "suumo.jp",
+ "syosetu.com"
+ ],
+ "ad-survey.com": [
+ "huanqiu.com"
+ ],
+ "ad-track.jp": [
+ "moppy.jp"
+ ],
+ "ad.gt": [
+ "dailymotion.com",
+ "fandom.com",
+ "wired.com"
+ ],
+ "ad.org.vn": [
+ "thethao247.vn"
+ ],
+ "ad1x.com": [
+ "saksfifthavenue.com"
+ ],
+ "adalliance.io": [
+ "n-tv.de",
+ "stern.de",
+ "rtl.de"
+ ],
+ "adalyser.com": [
+ "duolingo.com",
+ "etoro.com",
+ "totaljobs.com"
+ ],
+ "adaptiveads.com": [
+ "fark.com"
+ ],
+ "adaraanalytics.com": [
+ "australia.com"
+ ],
+ "adbinead.com": [
+ "koreatimes.co.kr"
+ ],
+ "adbox.lv": [
+ "inbox.lv"
+ ],
+ "adcampo.com": [
+ "flvto.biz",
+ "2conv.com"
+ ],
+ "adda247.in": [
+ "adda247.com"
+ ],
+ "addevent.com": [
+ "clickfunnels.com"
+ ],
+ "addthis.com": [
+ "who.int",
+ "worldometers.info",
+ "columbia.edu"
+ ],
+ "adentifi.com": [
+ "cancer.org",
+ "lastpass.com",
+ "metmuseum.org"
+ ],
+ "adform.net": [
+ "yahoo.com",
+ "amazon.com",
+ "msn.com"
+ ],
+ "adfox.ru": [
+ "livejournal.com",
+ "rambler.ru",
+ "gismeteo.ru"
+ ],
+ "adgeek.net": [
+ "shutterstock.com",
+ "msi.com"
+ ],
+ "adhaven.com": [
+ "youm7.com",
+ "nerdwallet.com"
+ ],
+ "adhigh.net": [
+ "lenta.ru",
+ "ozon.ru",
+ "kp.ru"
+ ],
+ "adinc.kr": [
+ "donga.com"
+ ],
+ "adingo.jp": [
+ "suumo.jp",
+ "sony.jp"
+ ],
+ "adition.com": [
+ "okezone.com",
+ "imgur.com",
+ "t-online.de"
+ ],
+ "adjetter.com": [
+ "adda247.com"
+ ],
+ "adkernel.com": [
+ "techradar.com",
+ "livescience.com",
+ "howtogeek.com"
+ ],
+ "adlmerge.com": [
+ "aif.ru"
+ ],
+ "adman.gr": [
+ "newsit.gr",
+ "gazzetta.gr",
+ "liberal.gr"
+ ],
+ "admaster.com.cn": [
+ "lianjia.com"
+ ],
+ "admatic.com.tr": [
+ "memurlar.net"
+ ],
+ "admatrix.jp": [
+ "appier.com",
+ "shop-pro.jp"
+ ],
+ "admedia.com": [
+ "dx.com"
+ ],
+ "admedo.com": [
+ "theregister.com",
+ "topuniversities.com",
+ "bristol.ac.uk"
+ ],
+ "admetrica.ru": [
+ "yandex.ru",
+ "yandex.com",
+ "yandex.by"
+ ],
+ "admicro.vn": [
+ "laodong.vn",
+ "vtv.vn",
+ "kenh14.vn"
+ ],
+ "admission.net": [
+ "chevrolet.com"
+ ],
+ "admithub.com": [
+ "uwyo.edu"
+ ],
+ "admixer.net": [
+ "khaberni.com",
+ "alwakeelnews.com",
+ "i.ua"
+ ],
+ "admost.com": [
+ "ensonhaber.com",
+ "yeniakit.com.tr",
+ "haberler.com"
+ ],
+ "adnuntius.com": [
+ "milliyet.com.tr",
+ "alwakeelnews.com",
+ "ahlmasrnews.com"
+ ],
+ "adnxs.com": [
+ "microsoft.com",
+ "yahoo.com",
+ "amazon.com"
+ ],
+ "adnz.co": [
+ "nzz.ch"
+ ],
+ "adobe.com": [
+ "espn.com",
+ "marriott.com",
+ "history.com"
+ ],
+ "adobecqms.net": [
+ "grainger.com"
+ ],
+ "adocean.pl": [
+ "gemius.pl",
+ "tvp.pl",
+ "blic.rs"
+ ],
+ "adop.cc": [
+ "ruliweb.com",
+ "pojoksatu.id",
+ "kyobobook.co.kr"
+ ],
+ "adotmob.com": [
+ "okezone.com",
+ "imgur.com",
+ "liberation.fr"
+ ],
+ "adpnut.com": [
+ "koreaherald.com"
+ ],
+ "adpushup.com": [
+ "geeksforgeeks.org",
+ "india.com",
+ "bollywoodshaadis.com"
+ ],
+ "adpxl.co": [
+ "instabug.com"
+ ],
+ "adrecover.com": [
+ "geeksforgeeks.org",
+ "india.com"
+ ],
+ "adriver.ru": [
+ "aliexpress.ru",
+ "banggood.com",
+ "kp.ru"
+ ],
+ "adroll.com": [
+ "sourceforge.net",
+ "cloudflare.com",
+ "rakuten.co.jp"
+ ],
+ "adrta.com": [
+ "redstate.com",
+ "ktvu.com",
+ "hotair.com"
+ ],
+ "adsafeprotected.com": [
+ "allabout.co.jp"
+ ],
+ "adscale.de": [
+ "statista.com",
+ "memurlar.net",
+ "idnes.cz"
+ ],
+ "adschoom.com": [
+ "abril.com.br",
+ "newchic.com"
+ ],
+ "adscience.nl": [
+ "rijksmuseum.nl"
+ ],
+ "adsco.re": [
+ "hoodsite.com",
+ "thepiratebay10.org"
+ ],
+ "adserver.mk": [
+ "time.mk"
+ ],
+ "adsfactor.net": [
+ "aastocks.com"
+ ],
+ "adskeeper.co.uk": [
+ "txxx.com",
+ "y2mate.guru",
+ "dramacool.movie"
+ ],
+ "adskeeper.com": [
+ "fastpic.ru"
+ ],
+ "adsniper.ru": [
+ "aif.ru"
+ ],
+ "adspsp.com": [
+ "yourdictionary.com"
+ ],
+ "adsrv.io": [
+ "thethao247.vn"
+ ],
+ "adsrvr.org": [
+ "amazon.com",
+ "msn.com",
+ "godaddy.com"
+ ],
+ "adswizz.com": [
+ "iheart.com",
+ "tunein.com",
+ "eltiempo.com"
+ ],
+ "adsymptotic.com": [
+ "adobe.com",
+ "amazon.com",
+ "msn.com"
+ ],
+ "adtarget.com.tr": [
+ "memurlar.net",
+ "khaberni.com",
+ "alwakeelnews.com"
+ ],
+ "adtdp.com": [
+ "suumo.jp",
+ "mixi.jp",
+ "sony.jp"
+ ],
+ "adtelli.com": [
+ "ukr.net"
+ ],
+ "adtelligent.com": [
+ "aol.com",
+ "ukr.net",
+ "vanguardngr.com"
+ ],
+ "adtimaserver.vn": [
+ "zingnews.vn",
+ "baomoi.com",
+ "zingmp3.vn"
+ ],
+ "adtlgc.com": [
+ "olx.ro",
+ "delfi.lt"
+ ],
+ "adtng.com": [
+ "pornhub.com",
+ "sxyprn.com",
+ "animeflv.net"
+ ],
+ "adtodate.net": [
+ "hamshahrionline.ir"
+ ],
+ "adtrue.com": [
+ "manganelo.com",
+ "subscene.com",
+ "headlines.pw"
+ ],
+ "adup-tech.com": [
+ "businessinsider.de"
+ ],
+ "advanced-web-analytics.com": [
+ "pnc.com",
+ "allstate.com"
+ ],
+ "advangelists.com": [
+ "tv9telugu.com",
+ "thewire.in",
+ "tv9kannada.com"
+ ],
+ "advertising.com": [
+ "yahoo.com",
+ "amazon.com",
+ "msn.com"
+ ],
+ "advertserve.com": [
+ "yumpu.com",
+ "blackhatworld.com"
+ ],
+ "advg.jp": [
+ "alc.co.jp",
+ "tsite.jp",
+ "4gamer.net"
+ ],
+ "advividnetwork.com": [
+ "chinatimes.com",
+ "newtalk.tw",
+ "businesstoday.com.tw"
+ ],
+ "advsnx.net": [
+ "globes.co.il"
+ ],
+ "adweb.co.kr": [
+ "danawa.com"
+ ],
+ "adwstats.com": [
+ "journaldunet.com"
+ ],
+ "adxadserv.com": [
+ "avgle.com"
+ ],
+ "adxvip.com": [
+ "ifeng.com"
+ ],
+ "adyen.com": [
+ "abril.com.br",
+ "picsart.com"
+ ],
+ "adzerk.net": [
+ "unsplash.com",
+ "united.com",
+ "lwn.net"
+ ],
+ "aetn.com": [
+ "history.com",
+ "biography.com"
+ ],
+ "aetnd.com": [
+ "history.com"
+ ],
+ "af-110.com": [
+ "moppy.jp"
+ ],
+ "af-web-cms-0-prod.azurewebsites.net": [
+ "arthritis.org"
+ ],
+ "affec.tv": [
+ "rmit.edu.au"
+ ],
+ "affirm.com": [
+ "stockx.com",
+ "nest.com",
+ "oakley.com",
+ "comptia.org"
+ ],
+ "afftrack.pro": [
+ "newchic.com"
+ ],
+ "aftonbladet.se": [
+ "svd.se"
+ ],
+ "agenziaentrate.it": [
+ "agenziaentrate.gov.it"
+ ],
+ "agilemeasure.com": [
+ "hpe.com"
+ ],
+ "agilone.com": [
+ "tommy.com",
+ "microcenter.com"
+ ],
+ "agkn.com": [
+ "amazon.com",
+ "msn.com",
+ "godaddy.com"
+ ],
+ "agoda.net": [
+ "agoda.com"
+ ],
+ "agora.pl": [
+ "gazeta.pl",
+ "wyborcza.pl"
+ ],
+ "ahighapi.com": [
+ "bitz.ai"
+ ],
+ "aidata.io": [
+ "ozon.ru",
+ "kp.ru",
+ "khaberni.com"
+ ],
+ "aihelp.net": [
+ "cs30.net"
+ ],
+ "aimediagroup.com": [
+ "panasonic.com",
+ "nova.edu",
+ "hardrock.com"
+ ],
+ "aio.media": [
+ "3dnews.ru"
+ ],
+ "aiproxies.com": [
+ "panasonic.com",
+ "nova.edu",
+ "hardrock.com"
+ ],
+ "airpr.com": [
+ "equifax.com",
+ "savethechildren.org",
+ "solarwinds.com"
+ ],
+ "aismo.ru": [
+ "mosreg.ru"
+ ],
+ "aj1015.online": [
+ "bbb.org"
+ ],
+ "aj1431.online": [
+ "gazetaexpress.com"
+ ],
+ "aj2031.online": [
+ "ap7am.com"
+ ],
+ "aj2208.online": [
+ "filmix.co"
+ ],
+ "ajax.googleapis.com": [
+ "mercurynews.com",
+ "denverpost.com",
+ "ocregister.com"
+ ],
+ "akamaihd.net": [
+ "gizmodo.com",
+ "lifehacker.com",
+ "foxbusiness.com"
+ ],
+ "akamaized.net": [
+ "typeform.com",
+ "ucdavis.edu",
+ "rutgers.edu"
+ ],
+ "akstat.io": [
+ "hotwire.com"
+ ],
+ "albacross.com": [
+ "anydesk.com",
+ "bidtheatre.com",
+ "widespace.com"
+ ],
+ "alcmpn.com": [
+ "consequenceofsound.net",
+ "art.com",
+ "oakley.com"
+ ],
+ "alexametrics.com": [
+ "okezone.com",
+ "bongacams.com",
+ "tianya.cn"
+ ],
+ "alfasense.com": [
+ "tass.ru",
+ "iz.ru",
+ "yaplakal.com"
+ ],
+ "aliapp.org": [
+ "ih5.cn",
+ "ywart.com"
+ ],
+ "alibaba.com": [
+ "informationweek.com",
+ "daraz.pk",
+ "ywart.com"
+ ],
+ "alicdn.com": [
+ "ih5.cn",
+ "informationweek.com",
+ "daraz.pk"
+ ],
+ "aliexpress.com": [
+ "informationweek.com"
+ ],
+ "alifafdlnjeruif.com": [
+ "porntrex.com"
+ ],
+ "alipay.com": [
+ "daraz.pk"
+ ],
+ "aliyun.com": [
+ "gmw.cn",
+ "mojifen.com",
+ "122.gov.cn"
+ ],
+ "aliyuncs.com": [
+ "66law.cn"
+ ],
+ "all-cod.com": [
+ "kinokrad.co"
+ ],
+ "allure.com": [
+ "wired.com",
+ "newyorker.com",
+ "vanityfair.com"
+ ],
+ "almamedia.fi": [
+ "iltalehti.fi"
+ ],
+ "alocdn.com": [
+ "realclearpolitics.com",
+ "euroluxhome.com",
+ "valuewalk.com"
+ ],
+ "alphonso.tv": [
+ "dashlane.com"
+ ],
+ "alsa.org": [
+ "als.org"
+ ],
+ "alwasela.com": [
+ "copts-united.com"
+ ],
+ "am15.net": [
+ "fastpic.ru"
+ ],
+ "amap.com": [
+ "zhaopin.com",
+ "kdslife.com",
+ "tom.com"
+ ],
+ "amazon-adsystem.com": [
+ "amazon.com",
+ "reddit.com",
+ "msn.com"
+ ],
+ "amazon.com": [
+ "gucci.com",
+ "reason.com",
+ "boxofficemojo.com"
+ ],
+ "amazonaws.com": [
+ "abplive.com"
+ ],
+ "amcdn.vn": [
+ "laodong.vn",
+ "vtv.vn",
+ "kenh14.vn"
+ ],
+ "ameba.jp": [
+ "ameblo.jp",
+ "amebaownd.com"
+ ],
+ "amnet.tw": [
+ "thenewslens.com"
+ ],
+ "amunx.de": [
+ "computerbase.de"
+ ],
+ "analytics-egain.com": [
+ "hpe.com",
+ "jcpenney.com",
+ "td.com"
+ ],
+ "analytics-sm.com": [
+ "gotomeeting.com",
+ "monster.com",
+ "hbomax.com"
+ ],
+ "anandabazar.com": [
+ "telegraphindia.com"
+ ],
+ "and.co.uk": [
+ "dailymail.co.uk",
+ "thisismoney.co.uk"
+ ],
+ "andertoons.com": [
+ "washingtonsharedparenting.com"
+ ],
+ "aniview.com": [
+ "rediff.com",
+ "mydramalist.com",
+ "mobafire.com"
+ ],
+ "anm.co.uk": [
+ "dailymail.co.uk"
+ ],
+ "anquan.org": [
+ "afzhan.com",
+ "400.cn",
+ "9r.cn"
+ ],
+ "ansira.com": [
+ "petfinder.com"
+ ],
+ "answerscloud.com": [
+ "barclays.co.uk",
+ "oakley.com"
+ ],
+ "anura.io": [
+ "techtimes.com"
+ ],
+ "anvato.net": [
+ "chinatimes.com",
+ "kxan.com",
+ "ktvu.com"
+ ],
+ "anyclip.com": [
+ "venturebeat.com",
+ "wowhead.com"
+ ],
+ "anz.com": [
+ "anz.com.au"
+ ],
+ "aparat.com": [
+ "agah.com",
+ "tasnimnews.com",
+ "ponisha.ir"
+ ],
+ "apeartalb.site": [
+ "1377x.to"
+ ],
+ "apester.com": [
+ "deadline.com",
+ "indiewire.com",
+ "firstpost.com"
+ ],
+ "apihotels.net": [
+ "hotels.com"
+ ],
+ "app-us1.com": [
+ "seekingalpha.com",
+ "jpost.com",
+ "lse.ac.uk"
+ ],
+ "app.link": [
+ "twitch.tv",
+ "medium.com",
+ "marriott.com"
+ ],
+ "apparmor.com": [
+ "fiu.edu",
+ "dal.ca",
+ "ryerson.ca"
+ ],
+ "appconsent.io": [
+ "lefigaro.fr",
+ "commentcamarche.net",
+ "journaldunet.com"
+ ],
+ "appdynamics.com": [
+ "cisco.com",
+ "jstor.org",
+ "thomsonreuters.com"
+ ],
+ "appier.net": [
+ "kompas.com",
+ "ettoday.net",
+ "grid.id"
+ ],
+ "apple.com": [
+ "apple.news",
+ "wyndhamhotels.com",
+ "minds.com"
+ ],
+ "appmifile.com": [
+ "mi.com"
+ ],
+ "appsflyer.com": [
+ "farfetch.com",
+ "eonline.com",
+ "kitco.com"
+ ],
+ "apvdr.com": [
+ "sportingnews.com",
+ "soccerway.com",
+ "clicrbs.com.br"
+ ],
+ "aralego.com": [
+ "youm7.com",
+ "mydramalist.com",
+ "discuss.com.hk"
+ ],
+ "arc.io": [
+ "animeflv.net",
+ "cuevana3.io"
+ ],
+ "architecturaldigest.com": [
+ "wired.com",
+ "newyorker.com",
+ "vanityfair.com"
+ ],
+ "ard.de": [
+ "ardmediathek.de"
+ ],
+ "arrivalist.com": [
+ "artic.edu"
+ ],
+ "arte.tv": [
+ "politico.eu"
+ ],
+ "artipbox.net": [
+ "globes.co.il"
+ ],
+ "aruba.it": [
+ "pec.it"
+ ],
+ "as.com": [
+ "eluniverso.com"
+ ],
+ "asadcdn.com": [
+ "businessinsider.de",
+ "bild.de",
+ "welt.de"
+ ],
+ "asapp.com": [
+ "spectrum.net",
+ "rcn.com",
+ "verizon.com"
+ ],
+ "ascap.com": [
+ "elgenero.com"
+ ],
+ "ascpqnj-oam.global.ssl.fastly.net": [
+ "harborfreight.com"
+ ],
+ "asianmedia.com": [
+ "ltn.com.tw"
+ ],
+ "ask.com": [
+ "excite.com"
+ ],
+ "askvamygov-ui.azurewebsites.net": [
+ "my.gov.au"
+ ],
+ "aso1.net": [
+ "cima4u.io",
+ "gayboystube.com",
+ "akwam.co"
+ ],
+ "aspencore.com": [
+ "eetimes.com"
+ ],
+ "associates-amazon.com": [
+ "amazon.com",
+ "usatoday.com",
+ "wired.com"
+ ],
+ "asteannunci.it": [
+ "gazzettadelsud.it"
+ ],
+ "atdmt.com": [
+ "facebook.com",
+ "netflix.com",
+ "slack.com"
+ ],
+ "atgsvcs.com": [
+ "mysql.com",
+ "oracle.com",
+ "lenovo.com"
+ ],
+ "ati-host.net": [
+ "huawei.com",
+ "rte.ie",
+ "ovhcloud.com"
+ ],
+ "atlassian.net": [
+ "blackboard.com"
+ ],
+ "atp.io": [
+ "udemy.com",
+ "upwork.com",
+ "aarp.org"
+ ],
+ "atsptp.com": [
+ "nutaku.net",
+ "brazzers.com"
+ ],
+ "att.com": [
+ "yahoo.com"
+ ],
+ "attentivemobile.com": [
+ "artstation.com",
+ "uniqlo.com",
+ "zazzle.com"
+ ],
+ "audiencerun.com": [
+ "unblog.fr"
+ ],
+ "audioboom.com": [
+ "thisismoney.co.uk"
+ ],
+ "audioburst.com": [
+ "sportzbonanza.com"
+ ],
+ "aufp.io": [
+ "dailymotion.com"
+ ],
+ "auone.jp": [
+ "au.com"
+ ],
+ "auth0.com": [
+ "mercurynews.com",
+ "denverpost.com",
+ "makezine.com"
+ ],
+ "authorize.net": [
+ "reason.com"
+ ],
+ "autoimg.cn": [
+ "autohome.com.cn"
+ ],
+ "autonom8.com": [
+ "sandiegozoo.org"
+ ],
+ "autopilothq.com": [
+ "viglink.com",
+ "doodlekit.com",
+ "skimlinks.com"
+ ],
+ "avangate.com": [
+ "hola.org",
+ "wps.com"
+ ],
+ "avantisvideo.com": [
+ "stripes.com",
+ "miaminewtimes.com",
+ "washingtonian.com"
+ ],
+ "avmws.com": [
+ "wondershare.com",
+ "rei.com",
+ "patagonia.com"
+ ],
+ "aweber.com": [
+ "informationweek.com"
+ ],
+ "axisbank.co.in": [
+ "axisbank.com"
+ ],
+ "ayads.co": [
+ "newscientist.com",
+ "lequipe.fr",
+ "cronica.com.ar"
+ ],
+ "ayc0zsm69431gfebd.xyz": [
+ "statesman.com",
+ "oklahoman.com",
+ "pressdemocrat.com"
+ ],
+ "ayo.co.id": [
+ "bola.com"
+ ],
+ "azet.sk": [
+ "aktuality.sk"
+ ],
+ "azureedge.net": [
+ "secureworks.com",
+ "ajc.com",
+ "tampabay.com",
+ "gazette.com"
+ ],
+ "azurefd.net": [
+ "toyota.com"
+ ],
+ "b0e8.com": [
+ "zend.com",
+ "vmware.com",
+ "udel.edu"
+ ],
+ "b1img.com": [
+ "threadless.com",
+ "saatchiart.com"
+ ],
+ "b9i7.net": [
+ "caesars.com"
+ ],
+ "bablic.com": [
+ "nationalgeographic.org",
+ "powtoon.com",
+ "camp-fire.jp"
+ ],
+ "baidu.com": [
+ "sohu.com",
+ "sina.com.cn",
+ "csdn.net"
+ ],
+ "baidustatic.com": [
+ "sina.com.cn"
+ ],
+ "baikalize.com": [
+ "gmarket.co.kr",
+ "auction.co.kr"
+ ],
+ "baixing.net": [
+ "baixing.com"
+ ],
+ "baiying.cn": [
+ "lenovo.com.cn"
+ ],
+ "bam-x.com": [
+ "macys.com",
+ "iherb.com",
+ "yoox.com"
+ ],
+ "bancogalicia.com.ar": [
+ "bancogalicia.com"
+ ],
+ "banggood.com": [
+ "newchic.com"
+ ],
+ "barchart.com": [
+ "kitco.com"
+ ],
+ "barilliance.net": [
+ "euromonitor.com"
+ ],
+ "bashirian.biz": [
+ "filmix.co"
+ ],
+ "basspro.com": [
+ "cabelas.com"
+ ],
+ "bayan.ir": [
+ "blog.ir"
+ ],
+ "baynote.net": [
+ "springer.com",
+ "jcrew.com",
+ "theoutnet.com"
+ ],
+ "bazaarvoice.com": [
+ "lg.com",
+ "lww.com",
+ "discover.com",
+ "bathandbodyworks.com"
+ ],
+ "bbelements.com": [
+ "ceskatelevize.cz"
+ ],
+ "bcicdn.com": [
+ "bongacams.com"
+ ],
+ "bcn.cat": [
+ "barcelona.cat"
+ ],
+ "bd4travel.com": [
+ "emirates.com"
+ ],
+ "bdash-cloud.com": [
+ "onamae.com"
+ ],
+ "bdg-analytics.appspot.com": [
+ "bustle.com",
+ "elitedaily.com",
+ "inverse.com"
+ ],
+ "bebi.com": [
+ "animeflv.net",
+ "gogoanime.so",
+ "igg-games.com"
+ ],
+ "become.co.jp": [
+ "tok2.com"
+ ],
+ "beian.gov.cn": [
+ "gusuwang.com",
+ "chem17.com"
+ ],
+ "benchmarkemail.com": [
+ "helpguide.org"
+ ],
+ "berush.com": [
+ "semrush.com"
+ ],
+ "bestyang.cn": [
+ "9lkandianying.com"
+ ],
+ "betgorebysson.club": [
+ "4anime.to",
+ "opensubtitles.org",
+ "fakaza.com"
+ ],
+ "betweendigital.com": [
+ "aliexpress.ru",
+ "rambler.ru",
+ "gismeteo.ru"
+ ],
+ "bf-tools.net": [
+ "focus.de"
+ ],
+ "bfmio.com": [
+ "techradar.com",
+ "livescience.com",
+ "matterport.com"
+ ],
+ "bhphotovideo.com": [
+ "informationweek.com"
+ ],
+ "bibox360.com": [
+ "bibox.com"
+ ],
+ "bidgear.com": [
+ "manganelo.com",
+ "dramacool.movie",
+ "kickassanime.rs"
+ ],
+ "bidr.io": [
+ "adobe.com",
+ "okezone.com",
+ "digicert.com"
+ ],
+ "bidstreamserver.com": [
+ "spin.com"
+ ],
+ "bidswitch.net": [
+ "amazon.com",
+ "msn.com",
+ "okezone.com"
+ ],
+ "bidvertiser.com": [
+ "washingtonsharedparenting.com"
+ ],
+ "bigmining.com": [
+ "kakaku.com",
+ "tabelog.com",
+ "sony.jp"
+ ],
+ "bigo.tv": [
+ "bigolive.tv"
+ ],
+ "bing.com": [
+ "adobe.com",
+ "godaddy.com",
+ "weebly.com"
+ ],
+ "binstats.com": [
+ "id-binomo.com"
+ ],
+ "bithumb.com": [
+ "mk.co.kr"
+ ],
+ "bitninja.io": [
+ "wendyssubway.com",
+ "lumenlearning.com",
+ "corpscorp.online"
+ ],
+ "bitrix.info": [
+ "timeweb.com",
+ "msu.ru",
+ "bitrix24.ru"
+ ],
+ "bizbuysell.com": [
+ "allbusiness.com"
+ ],
+ "bizfly.vn": [
+ "admicro.vn"
+ ],
+ "bizible.com": [
+ "dropbox.com",
+ "cloudflare.com",
+ "nginx.com"
+ ],
+ "bizibly.com": [
+ "dropbox.com",
+ "cloudflare.com",
+ "nginx.com"
+ ],
+ "bizographics.com": [
+ "opendns.com",
+ "huawei.com",
+ "ox.ac.uk"
+ ],
+ "bizrate.com": [
+ "people.com",
+ "allrecipes.com",
+ "ew.com"
+ ],
+ "bizspring.co.kr": [
+ "dothome.co.kr"
+ ],
+ "bizspring.net": [
+ "dothome.co.kr"
+ ],
+ "bjcathay.com": [
+ "cctv.com"
+ ],
+ "blisspointmedia.com": [
+ "joinhoney.com"
+ ],
+ "blogsky.com": [
+ "picofile.com"
+ ],
+ "bluecava.com": [
+ "rosettastone.com"
+ ],
+ "blueconic.net": [
+ "nationalgeographic.com",
+ "britannica.com",
+ "merriam-webster.com"
+ ],
+ "bluekai.com": [
+ "marketwatch.com",
+ "nypost.com",
+ "thesun.co.uk"
+ ],
+ "bn-web.com": [
+ "barnesandnoble.com"
+ ],
+ "bnidx.com": [
+ "bravenet.com",
+ "jigsy.com"
+ ],
+ "bnpparibas.fr": [
+ "mabanque.bnpparibas"
+ ],
+ "boldchat.com": [
+ "gotomeeting.com",
+ "globalsign.com",
+ "cancer.org"
+ ],
+ "bonappetit.com": [
+ "wired.com",
+ "newyorker.com",
+ "vanityfair.com"
+ ],
+ "bongacams.com": [
+ "informationweek.com"
+ ],
+ "bonnier-subscriptions.com": [
+ "popsci.com"
+ ],
+ "booking.com": [
+ "southwest.com"
+ ],
+ "boostingads.com": [
+ "radikal.ru"
+ ],
+ "bounceexchange.com": [
+ "cnn.com",
+ "cnbc.com",
+ "wired.com"
+ ],
+ "bouncex.net": [
+ "cnn.com",
+ "cnbc.com"
+ ],
+ "boxx.ai": [
+ "thestar.com.my",
+ "100kpj.com"
+ ],
+ "brand-display.com": [
+ "wyndhamhotels.com",
+ "2banh.vn"
+ ],
+ "brandcdn.com": [
+ "appstate.edu",
+ "papajohns.com"
+ ],
+ "brandonsun.com": [
+ "winnipegfreepress.com"
+ ],
+ "brdmin.com": [
+ "kinogo.by",
+ "1plus1tv.ru",
+ "kinogo.zone"
+ ],
+ "breaktime.com.tw": [
+ "newtalk.tw",
+ "businesstoday.com.tw"
+ ],
+ "brightcove.com": [
+ "webex.com",
+ "nike.com",
+ "digitaltrends.com",
+ "rsa.com"
+ ],
+ "brightedge.com": [
+ "vmware.com"
+ ],
+ "broadstreetads.com": [
+ "arthritis.org",
+ "prospect.org",
+ "mondaq.com"
+ ],
+ "brsrvr.com": [
+ "barnesandnoble.com",
+ "shutterfly.com",
+ "farfetch.com"
+ ],
+ "bttrack.com": [
+ "msn.com",
+ "forbes.com",
+ "surveymonkey.com"
+ ],
+ "btttag.com": [
+ "marriott.com",
+ "homedepot.com",
+ "patch.com"
+ ],
+ "buckridge.link": [
+ "filmix.co"
+ ],
+ "bugsnag.com": [
+ "indigo.ca"
+ ],
+ "bullionyield.com": [
+ "porntrex.com"
+ ],
+ "bumlam.com": [
+ "aif.ru",
+ "alfabank.ru"
+ ],
+ "burly.io": [
+ "braze.com"
+ ],
+ "businessclick.com": [
+ "money.pl"
+ ],
+ "businessinsider.com": [
+ "insider.com"
+ ],
+ "buysellads.net": [
+ "dynamicdrive.com"
+ ],
+ "buzzfeed.com": [
+ "buzzfeednews.com"
+ ],
+ "buzzoola.com": [
+ "rambler.ru",
+ "lenta.ru",
+ "gazeta.ru"
+ ],
+ "byteoversea.com": [
+ "tiktok.com"
+ ],
+ "c-ctrip.com": [
+ "qunar.com",
+ "idianfa.com"
+ ],
+ "c212.net": [
+ "prnewswire.com",
+ "prweb.com",
+ "sas.com"
+ ],
+ "c3tag.com": [
+ "shutterstock.com",
+ "panasonic.com",
+ "usbank.com"
+ ],
+ "c8.net.ua": [
+ "yotpo.com"
+ ],
+ "calendly.com": [
+ "n.rich"
+ ],
+ "canliskor.com.tr": [
+ "fanatik.com.tr"
+ ],
+ "capterra.com": [
+ "softwareadvice.com"
+ ],
+ "capturehighered.net": [
+ "sc.edu",
+ "sjsu.edu",
+ "msstate.edu"
+ ],
+ "carfax.com": [
+ "kia.com"
+ ],
+ "caroda.io": [
+ "csfd.cz",
+ "aktualne.cz"
+ ],
+ "casalemedia.com": [
+ "yahoo.com",
+ "amazon.com",
+ "okezone.com"
+ ],
+ "caspio.com": [
+ "wfaa.com",
+ "11alive.com"
+ ],
+ "castbox.fm": [
+ "rosbalt.ru"
+ ],
+ "castle.io": [
+ "trello.com",
+ "farfetch.com",
+ "reverb.com"
+ ],
+ "cbs.com": [
+ "informationweek.com"
+ ],
+ "cbsi.com": [
+ "maxpreps.com"
+ ],
+ "cctv.com": [
+ "hupu.com",
+ "npc.gov.cn"
+ ],
+ "cdeledu.com": [
+ "chinaacc.com"
+ ],
+ "cdn-net.com": [
+ "grubhub.com",
+ "qvc.com"
+ ],
+ "cdn-payscale.com": [
+ "payscale.com"
+ ],
+ "cdninstagram.com": [
+ "sony.com"
+ ],
+ "cdnpub.info": [
+ "iqoption.com"
+ ],
+ "cdnvideo.mobi": [
+ "sexu.com"
+ ],
+ "cdnwidget.com": [
+ "mercari.com",
+ "eset.com",
+ "activecampaign.com"
+ ],
+ "ceet.co": [
+ "eltiempo.com"
+ ],
+ "cengage.com": [
+ "gale.com"
+ ],
+ "center.io": [
+ "leadpages.com",
+ "goodmenproject.com"
+ ],
+ "centerdigitaled.com": [
+ "govtech.com"
+ ],
+ "centrum.cz": [
+ "aktualne.cz"
+ ],
+ "cern.ch": [
+ "home.cern",
+ "zenodo.org"
+ ],
+ "cfzu.net": [
+ "logitech.com",
+ "logitechg.com"
+ ],
+ "channelnewsasia.com": [
+ "todayonline.com"
+ ],
+ "charlotteobserver.com": [
+ "newsobserver.com",
+ "mcclatchydc.com"
+ ],
+ "chartbeat.net": [
+ "nytimes.com",
+ "cnn.com",
+ "forbes.com"
+ ],
+ "chase.com": [
+ "ecwid.com"
+ ],
+ "chatdealer.jp": [
+ "sakura.ne.jp"
+ ],
+ "chatplus.jp": [
+ "lolipop.jp",
+ "kingtime.jp"
+ ],
+ "chatra.io": [
+ "ko-fi.com",
+ "yourbrideglobal.com"
+ ],
+ "chaturbate.com": [
+ "informationweek.com"
+ ],
+ "chegg.com": [
+ "citationmachine.net",
+ "easybib.com"
+ ],
+ "cheqzone.com": [
+ "woolworths.com.au",
+ "newcastle.edu.au",
+ "getyourguide.com"
+ ],
+ "cheyisou.com": [
+ "bitauto.com"
+ ],
+ "childsplayclothing.co.uk": [
+ "next.co.uk"
+ ],
+ "chipweb.azurewebsites.net": [
+ "lacity.org"
+ ],
+ "choozle.com": [
+ "addthis.com",
+ "denverpost.com",
+ "amnh.org"
+ ],
+ "cian.site": [
+ "cian.ru"
+ ],
+ "cint.com": [
+ "mainichi.jp"
+ ],
+ "cintnetworks.com": [
+ "disney.com",
+ "cint.com",
+ "starwars.com"
+ ],
+ "cisco.com": [
+ "webex.com",
+ "duo.com",
+ "netacad.com"
+ ],
+ "citi.com": [
+ "paho.org",
+ "citigroup.com"
+ ],
+ "citiservi.es": [
+ "eleconomista.es"
+ ],
+ "citrix.com": [
+ "sharefile.com"
+ ],
+ "clarivate.com": [
+ "webofknowledge.com"
+ ],
+ "classistatic.com": [
+ "gumtree.co.za"
+ ],
+ "clcknads.pro": [
+ "tubesafari.com"
+ ],
+ "clearbit.com": [
+ "intercom.com",
+ "elastic.co"
+ ],
+ "clerk.io": [
+ "grifo210.com",
+ "alducadaosta.com"
+ ],
+ "clevernt.com": [
+ "makeleio.gr",
+ "sportzwiki.com",
+ "themoscowtimes.com"
+ ],
+ "clickability.com": [
+ "govtech.com",
+ "governing.com"
+ ],
+ "clickagy.com": [
+ "desktopnexus.com"
+ ],
+ "clickcertain.com": [
+ "shapeways.com"
+ ],
+ "clickfuse.com": [
+ "azlyrics.com"
+ ],
+ "clickondetroit.com": [
+ "clickorlando.com"
+ ],
+ "clicktale.net": [
+ "microsoft.com",
+ "intel.com",
+ "gotomeeting.com"
+ ],
+ "clicktripz.com": [
+ "tripadvisor.com",
+ "nypost.com",
+ "tripadvisor.co.uk"
+ ],
+ "clientgear.com": [
+ "dx.com"
+ ],
+ "clinch.co": [
+ "chewy.com",
+ "nespresso.com"
+ ],
+ "clink.cn": [
+ "feishu.cn"
+ ],
+ "clive.cloud": [
+ "ualberta.ca",
+ "nmsu.edu",
+ "umt.edu"
+ ],
+ "clmbtech.com": [
+ "wattpad.com",
+ "hindnow.com",
+ "businessinsider.in"
+ ],
+ "cloob.com": [
+ "mihanblog.com"
+ ],
+ "cloud-iq.com": [
+ "newscientist.com",
+ "empireonline.com"
+ ],
+ "cloudflare.com": [
+ "boohoo.com",
+ "cityheaven.net"
+ ],
+ "clublibertaddigital.com": [
+ "libertaddigital.com"
+ ],
+ "cluep.com": [
+ "penguinrandomhouse.com",
+ "tidal.com"
+ ],
+ "cmanager-prometeo.appspot.com": [
+ "20minutos.es"
+ ],
+ "cnmo-img.com.cn": [
+ "cnmo.com"
+ ],
+ "cnnd.vn": [
+ "vtv.vn"
+ ],
+ "cnrs.fr": [
+ "archives-ouvertes.fr"
+ ],
+ "cntraveler.com": [
+ "wired.com",
+ "newyorker.com",
+ "vanityfair.com"
+ ],
+ "cntv.cn": [
+ "cctv.com"
+ ],
+ "cnyes.cool": [
+ "cnyes.com"
+ ],
+ "cnzz.com": [
+ "huanqiu.com",
+ "jrj.com.cn",
+ "rednet.cn"
+ ],
+ "cobaltgroup.com": [
+ "edmunds.com",
+ "chevrolet.com"
+ ],
+ "coccusadmanlob.com": [
+ "cimaclub.io"
+ ],
+ "codon.vn": [
+ "x2convert.com"
+ ],
+ "coherentpath.com": [
+ "neimanmarcus.com",
+ "llbean.com"
+ ],
+ "cohesionapps.com": [
+ "healthline.com",
+ "medicalnewstoday.com",
+ "frontier.com"
+ ],
+ "coinmama.com": [
+ "informationweek.com"
+ ],
+ "cointiply.com": [
+ "informationweek.com"
+ ],
+ "collectandgather.com": [
+ "williams-sonoma.com",
+ "potterybarn.com",
+ "westelm.com"
+ ],
+ "collegenet.com": [
+ "gmu.edu"
+ ],
+ "colossusssp.com": [
+ "usatoday.com",
+ "azcentral.com",
+ "freep.com"
+ ],
+ "comm100.com": [
+ "a2hosting.com"
+ ],
+ "comm100.io": [
+ "blibli.com"
+ ],
+ "commander1.com": [
+ "yoox.com",
+ "ovh.com",
+ "ovhcloud.com"
+ ],
+ "commitchange.com": [
+ "metrotimes.com",
+ "riverfronttimes.com",
+ "orlandoweekly.com"
+ ],
+ "company-target.com": [
+ "adobe.com",
+ "digicert.com",
+ "ibm.com"
+ ],
+ "complex.com": [
+ "allmusic.com"
+ ],
+ "condenastdigital.com": [
+ "wired.com",
+ "newyorker.com",
+ "arstechnica.com"
+ ],
+ "connatix.com": [
+ "gizmodo.com",
+ "thegatewaypundit.com",
+ "jpost.com"
+ ],
+ "connectad.io": [
+ "w3schools.com",
+ "pastebin.com",
+ "idnes.cz"
+ ],
+ "connecto.io": [
+ "cardekho.com",
+ "zigwheels.com"
+ ],
+ "connexity.net": [
+ "sourceforge.net",
+ "slashdot.org"
+ ],
+ "connextra.com": [
+ "mlb.com",
+ "cbs.com",
+ "nbcsports.com"
+ ],
+ "consent.is": [
+ "bugsnag.com"
+ ],
+ "consentag.eu": [
+ "boohoo.com"
+ ],
+ "constantcontact.com": [
+ "rs6.net"
+ ],
+ "consumerreports.org": [
+ "consumerist.com"
+ ],
+ "contentabc.com": [
+ "bravotube.net"
+ ],
+ "contentexchange.me": [
+ "b92.net",
+ "blic.rs",
+ "dnevnik.hr"
+ ],
+ "contentinsights.com": [
+ "niemanlab.org"
+ ],
+ "contentive.com": [
+ "searchenginewatch.com",
+ "clickz.com"
+ ],
+ "contentsfeed.com": [
+ "asahi.com",
+ "donga.com",
+ "mainichi.jp"
+ ],
+ "contentsquare.net": [
+ "salesforce.com",
+ "shutterstock.com",
+ "bestbuy.com"
+ ],
+ "contextads.live": [
+ "okaz.com.sa",
+ "aawsat.com",
+ "haibunda.com"
+ ],
+ "contextweb.com": [
+ "forbes.com",
+ "sourceforge.net",
+ "imgur.com"
+ ],
+ "contobox.com": [
+ "homedepot.ca"
+ ],
+ "conversantmedia.com": [
+ "epsilon.com"
+ ],
+ "conversionlogic.net": [
+ "rottentomatoes.com"
+ ],
+ "convertkit.com": [
+ "valuewalk.com"
+ ],
+ "convertlanguage.com": [
+ "t-mobile.com"
+ ],
+ "convio.net": [
+ "convio.com",
+ "alsa.org"
+ ],
+ "coremetrics.com": [
+ "ibm.com",
+ "abebooks.com",
+ "thermofisher.com"
+ ],
+ "corus.ca": [
+ "globalnews.ca"
+ ],
+ "costco.com": [
+ "costco.ca"
+ ],
+ "cotsta.ru": [
+ "kino-teatr.ru"
+ ],
+ "coupang.com": [
+ "hani.co.kr"
+ ],
+ "coupons.net": [
+ "coupons.com"
+ ],
+ "coveo.com": [
+ "bell.ca"
+ ],
+ "coxbusiness.com": [
+ "cox.com"
+ ],
+ "cpmstar.com": [
+ "hi.ru",
+ "armorgames.com",
+ "pcgamesn.com"
+ ],
+ "cpx.to": [
+ "dailymotion.com",
+ "livescience.com",
+ "express.co.uk"
+ ],
+ "cquotient.com": [
+ "uniqlo.com",
+ "puma.com",
+ "boohoo.com"
+ ],
+ "creative-serving.com": [
+ "swarovski.com"
+ ],
+ "creativecdn.com": [
+ "msn.com",
+ "booking.com",
+ "tokopedia.com"
+ ],
+ "creativelive.com": [
+ "photo.net"
+ ],
+ "creativemarket.com": [
+ "informationweek.com"
+ ],
+ "crentgate.com": [
+ "livejasmin.com"
+ ],
+ "cretgate.com": [
+ "spankbang.com",
+ "livejasmin.com"
+ ],
+ "criteo.com": [
+ "dropbox.com",
+ "cnn.com",
+ "forbes.com"
+ ],
+ "crsspxl.com": [
+ "sourceforge.net",
+ "slashdot.org",
+ "las2orillas.co"
+ ],
+ "crwdcntrl.net": [
+ "oregonlive.com",
+ "nzherald.co.nz",
+ "umass.edu"
+ ],
+ "cryptobrowser.site": [
+ "cryptotabbrowser.com"
+ ],
+ "cszz.ru": [
+ "drom.ru"
+ ],
+ "ctags.cn": [
+ "bitauto.com"
+ ],
+ "ctnsnet.com": [
+ "reading.ac.uk",
+ "lancaster.ac.uk",
+ "highlow.com"
+ ],
+ "ctrip.com": [
+ "idianfa.com"
+ ],
+ "cuberoot.co": [
+ "indiatoday.in",
+ "aajtak.in"
+ ],
+ "culturaltracking.ru": [
+ "culture.ru"
+ ],
+ "curalate.com": [
+ "jcpenney.com",
+ "crateandbarrel.com",
+ "williams-sonoma.com"
+ ],
+ "custhelp.com": [
+ "lenovo.com"
+ ],
+ "customer.io": [
+ "codecademy.com",
+ "buffer.com",
+ "smore.com"
+ ],
+ "custora.com": [
+ "patagonia.com",
+ "domestika.org",
+ "jcrew.com"
+ ],
+ "cvent.com": [
+ "stlouisfed.org"
+ ],
+ "cvshealth.com": [
+ "cvs.com"
+ ],
+ "cxense.com": [
+ "wsj.com",
+ "businessinsider.com",
+ "independent.co.uk"
+ ],
+ "cyol.net": [
+ "cyol.com"
+ ],
+ "d-bi.fr": [
+ "boohoo.com",
+ "worldoftanks.eu"
+ ],
+ "d-markets.net": [
+ "cityheaven.net"
+ ],
+ "d1af033869koo7.cloudfront.net": [
+ "marriott.com",
+ "bestbuy.com",
+ "siriusxm.com"
+ ],
+ "d1d3jupgwm7m5r.cloudfront.net": [
+ "defensenews.com"
+ ],
+ "d1dns4zpgsd7rz.cloudfront.net": [
+ "rthk.hk"
+ ],
+ "d1epsz32winqbo.cloudfront.net": [
+ "startribune.com"
+ ],
+ "d1rv23qj5kas56.cloudfront.net": [
+ "webnode.com",
+ "webnode.cz"
+ ],
+ "d226aj4ao1t61q.cloudfront.net": [
+ "activecampaign.com"
+ ],
+ "d2t77mnxyo7adj.cloudfront.net": [
+ "trello.com",
+ "saatchiart.com"
+ ],
+ "d32blsbofe2158.cloudfront.net": [
+ "247wallst.com"
+ ],
+ "d32hpx6p5we0tx.cloudfront.net": [
+ "espncricinfo.com"
+ ],
+ "d38xvr37kwwhcm.cloudfront.net": [
+ "anthropologie.com",
+ "fashionnova.com"
+ ],
+ "d395dw5zk780j2.cloudfront.net": [
+ "nationalpost.com",
+ "canada.com",
+ "financialpost.com"
+ ],
+ "d41.co": [
+ "hpe.com",
+ "3m.com",
+ "cio.com"
+ ],
+ "d5nxst8fruw4z.cloudfront.net": [
+ "alexa.com"
+ ],
+ "d9jj3mjthpub.cloudfront.net": [
+ "people.com",
+ "allrecipes.com",
+ "eatthis.com"
+ ],
+ "dable.io": [
+ "ettoday.net",
+ "jpnn.com",
+ "republika.co.id"
+ ],
+ "dadcdigital.com": [
+ "funimation.com"
+ ],
+ "dadicinema.com": [
+ "300.cn"
+ ],
+ "dailymail.co.uk": [
+ "metro.co.uk",
+ "inews.co.uk",
+ "thisismoney.co.uk"
+ ],
+ "dailymotion.com": [
+ "heraldodemexico.com.mx",
+ "01net.com",
+ "asiaone.com"
+ ],
+ "dam-broadcast.com": [
+ "orange.com"
+ ],
+ "danv01ao0kdr2.cloudfront.net": [
+ "jabra.com"
+ ],
+ "dapadobeproxyql.azurewebsites.net": [
+ "microsoft.com"
+ ],
+ "dapadobeproxytest.azurewebsites.net": [
+ "microsoft.com"
+ ],
+ "datamind.ru": [
+ "tinkoff.ru",
+ "skyeng.ru"
+ ],
+ "dataplusmath.com": [
+ "liveramp.com"
+ ],
+ "dataprev.gov.br": [
+ "inss.gov.br"
+ ],
+ "datasteam.io": [
+ "arthritis.org",
+ "oakley.com"
+ ],
+ "dataxpand.com": [
+ "las2orillas.co",
+ "taringa.net",
+ "rpp.pe"
+ ],
+ "daum.net": [
+ "ettoday.net",
+ "tistory.com",
+ "kakaocorp.com"
+ ],
+ "dc-storm.com": [
+ "alibabacloud.com",
+ "udemy.com",
+ "coursera.org"
+ ],
+ "dc-tag.jp": [
+ "navitime.co.jp"
+ ],
+ "dcmn.io": [
+ "idealo.de",
+ "babbel.com"
+ ],
+ "dditscdn.com": [
+ "livejasmin.com"
+ ],
+ "dditservices.com": [
+ "spankbang.com"
+ ],
+ "ddos-guard.net": [
+ "hse.ru",
+ "ngs.ru"
+ ],
+ "deadline.com": [
+ "indiewire.com"
+ ],
+ "deadlinefunnel.com": [
+ "copyblogger.com"
+ ],
+ "dealerinspire.com": [
+ "cars.com"
+ ],
+ "deema.agency": [
+ "khabaronline.ir"
+ ],
+ "deep.bi": [
+ "rappler.com",
+ "sme.sk"
+ ],
+ "deepintent.com": [
+ "wired.com",
+ "patheos.com",
+ "patient.info"
+ ],
+ "dell.com": [
+ "rsa.com",
+ "delltechnologies.com"
+ ],
+ "demdex.net": [
+ "microsoft.com",
+ "linkedin.com",
+ "yahoo.com"
+ ],
+ "denakop.com": [
+ "metropoles.com"
+ ],
+ "denverpost.com": [
+ "bostonherald.com",
+ "twincities.com"
+ ],
+ "deployads.com": [
+ "tinyurl.com",
+ "sciencedaily.com",
+ "myanimelist.net"
+ ],
+ "deqwas.net": [
+ "rakuten.co.jp",
+ "suumo.jp",
+ "syosetu.com"
+ ],
+ "desipearl.com": [
+ "oneindia.com",
+ "filmibeat.com"
+ ],
+ "detik.com": [
+ "cnnindonesia.com",
+ "cnbcindonesia.com",
+ "insertlive.com"
+ ],
+ "dezeenjobs.com": [
+ "dezeen.com"
+ ],
+ "dfapvmql-q.global.ssl.fastly.net": [
+ "zappos.com",
+ "jcpenney.com",
+ "ulta.com"
+ ],
+ "dfcfw.com": [
+ "eastmoney.com"
+ ],
+ "dhgate.com": [
+ "informationweek.com"
+ ],
+ "di-dtaectolog-us-prod-1.appspot.com": [
+ "go.com",
+ "disney.com",
+ "starwars.com"
+ ],
+ "dialogtech.com": [
+ "findlaw.com",
+ "ringcentral.com",
+ "iit.edu"
+ ],
+ "diginetica.net": [
+ "citilink.ru",
+ "eldorado.ru"
+ ],
+ "digitalaudienz.com": [
+ "estadao.com.br"
+ ],
+ "digitalbee.al": [
+ "balkanweb.com"
+ ],
+ "digitalbox.ru": [
+ "zaycev.net"
+ ],
+ "digitalfirstmedia.com": [
+ "bostonherald.com"
+ ],
+ "digitalkites.com": [
+ "bollywoodshaadis.com"
+ ],
+ "digitaloceanspaces.com": [
+ "vox.com"
+ ],
+ "digitalriver.com": [
+ "poly.com"
+ ],
+ "digitaltarget.ru": [
+ "rambler.ru",
+ "iz.ru",
+ "aif.ru"
+ ],
+ "digitru.st": [
+ "imgur.com",
+ "speedtest.net",
+ "op.gg"
+ ],
+ "diqp43fm0w6zs.cloudfront.net": [
+ "wwnorton.com"
+ ],
+ "discord.com": [
+ "bulbagarden.net",
+ "lectortmo.com"
+ ],
+ "districtm.ca": [
+ "royalgazette.com"
+ ],
+ "districtm.io": [
+ "okezone.com",
+ "forbes.com",
+ "imgur.com"
+ ],
+ "djiops.com": [
+ "dji.com"
+ ],
+ "dkuim.de": [
+ "giga.de"
+ ],
+ "dl1d2m8ri9v3j.cloudfront.net": [
+ "smartrecruiters.com"
+ ],
+ "dmgmediaprivacy.co.uk": [
+ "dailymail.co.uk",
+ "metro.co.uk",
+ "inews.co.uk"
+ ],
+ "dmm.com": [
+ "dmm.co.jp"
+ ],
+ "dmpxs.com": [
+ "ktla.com",
+ "wgntv.com",
+ "kdvr.com"
+ ],
+ "dmxleo.com": [
+ "dailymotion.com",
+ "heraldodemexico.com.mx",
+ "01net.com"
+ ],
+ "docomo.ne.jp": [
+ "suumo.jp",
+ "hulu.jp",
+ "allabout.co.jp"
+ ],
+ "doga.cm": [
+ "ferret-plus.com"
+ ],
+ "donorbox.org": [
+ "truthout.org"
+ ],
+ "dotmetrics.net": [
+ "avaz.ba",
+ "scotsman.com",
+ "birminghammail.co.uk"
+ ],
+ "dotomi.com": [
+ "yahoo.com",
+ "okezone.com",
+ "forbes.com"
+ ],
+ "doubleclick.net": [
+ "youtube.com",
+ "linkedin.com",
+ "netflix.com"
+ ],
+ "doublepimp.com": [
+ "spankbang.com",
+ "efukt.com",
+ "gotporn.com"
+ ],
+ "douyucdn.cn": [
+ "douyu.com"
+ ],
+ "dowjoneson.com": [
+ "wsj.com",
+ "marketwatch.com",
+ "dowjones.com"
+ ],
+ "dpgmedia.net": [
+ "dpgmedia.be",
+ "dpgmedia.nl",
+ "volkskrant.nl"
+ ],
+ "dpmsrv.com": [
+ "boston.com",
+ "techtarget.com",
+ "adweek.com"
+ ],
+ "drcareers.ca": [
+ "cmaj.ca"
+ ],
+ "dreamlab.pl": [
+ "onet.pl"
+ ],
+ "dropbox.com": [
+ "smallseotools.com",
+ "tinypng.com",
+ "getcloudapp.com"
+ ],
+ "dropboxusercontent.com": [
+ "rewardstyle.com"
+ ],
+ "dsp.com": [
+ "zhibo8.cc"
+ ],
+ "dsspn.com": [
+ "newchic.com"
+ ],
+ "dtprofit.com": [
+ "drtuber.com"
+ ],
+ "dtscdn.com": [
+ "otvfoco.com.br",
+ "las2orillas.co"
+ ],
+ "dtscout.com": [
+ "alnaharegypt.com",
+ "otvfoco.com.br",
+ "las2orillas.co"
+ ],
+ "dttq.net": [
+ "acehardware.com"
+ ],
+ "duba.com": [
+ "newduba.cn"
+ ],
+ "dugout.com": [
+ "thethao247.vn",
+ "indosport.com"
+ ],
+ "duoyi.com": [
+ "sina.com.cn"
+ ],
+ "dxcdn.com": [
+ "dx.com"
+ ],
+ "dynad.net": [
+ "uol.com.br"
+ ],
+ "dynadot.com": [
+ "informationweek.com"
+ ],
+ "dynamics.com": [
+ "edelman.com"
+ ],
+ "dynamicyield.com": [
+ "washingtonexaminer.com",
+ "urbanoutfitters.com",
+ "dior.com"
+ ],
+ "dyntrk.com": [
+ "imgur.com",
+ "retargetly.com"
+ ],
+ "e-contenta.com": [
+ "ozon.ru"
+ ],
+ "e-himart.co.kr": [
+ "hani.co.kr"
+ ],
+ "e-planning.net": [
+ "youm7.com",
+ "softonic.com",
+ "geeksforgeeks.org"
+ ],
+ "easemob.com": [
+ "iliangcang.com",
+ "loex.io"
+ ],
+ "eb.com": [
+ "britannica.com"
+ ],
+ "ebay.com": [
+ "businessinsider.com.au"
+ ],
+ "ebayimg.com": [
+ "marktplaats.nl"
+ ],
+ "ebis.ne.jp": [
+ "so-net.ne.jp",
+ "thebase.in",
+ "doda.jp"
+ ],
+ "ebu.io": [
+ "dw.com"
+ ],
+ "ecbsn.com": [
+ "rakuten.com"
+ ],
+ "eccmp.com": [
+ "newegg.com",
+ "popsci.com",
+ "cabelas.com"
+ ],
+ "echoban.ru": [
+ "svoboda.org",
+ "ng.ru"
+ ],
+ "ecustomeropinions.com": [
+ "skysports.com"
+ ],
+ "ecwid.ru": [
+ "ecwid.com"
+ ],
+ "edge-cdn.net": [
+ "biomedcentral.com",
+ "springeropen.com"
+ ],
+ "edigitalsurvey.com": [
+ "bbc.com",
+ "formula1.com"
+ ],
+ "editor80.com": [
+ "heraldodemexico.com.mx"
+ ],
+ "editorx.com": [
+ "wix.com"
+ ],
+ "eestatic.com": [
+ "elespanol.com"
+ ],
+ "effectivemeasure.net": [
+ "bbc.com",
+ "manoramaonline.com",
+ "abs-cbn.com"
+ ],
+ "egain.cloud": [
+ "lego.com",
+ "jcpenney.com"
+ ],
+ "el-mundo.net": [
+ "marca.com",
+ "elmundo.es",
+ "expansion.com"
+ ],
+ "eland-tech.com": [
+ "buzzorange.com"
+ ],
+ "elfsight.com": [
+ "afsp.org"
+ ],
+ "elmercurio.com": [
+ "emol.com"
+ ],
+ "eloqua.com": [
+ "alibabacloud.com",
+ "addthis.com",
+ "intel.com"
+ ],
+ "elpais.com": [
+ "as.com",
+ "cadenaser.com"
+ ],
+ "elsevier.com": [
+ "thelancet.com",
+ "ssrn.com",
+ "cell.com"
+ ],
+ "elsevierhealth.com": [
+ "thelancet.com",
+ "cell.com"
+ ],
+ "eltiempo.co": [
+ "eltiempo.com"
+ ],
+ "eltiempo.digital": [
+ "eltiempo.com"
+ ],
+ "embedly.com": [
+ "uservoice.com"
+ ],
+ "emxdgt.com": [
+ "forbes.com",
+ "usatoday.com",
+ "dailymotion.com"
+ ],
+ "enamad.ir": [
+ "digikala.com",
+ "divar.ir",
+ "mofidonline.com"
+ ],
+ "ename.cn": [
+ "ename.com",
+ "ename.net"
+ ],
+ "engageclick.com": [
+ "marriott.com"
+ ],
+ "engageya.com": [
+ "memurlar.net",
+ "sozcu.com.tr",
+ "haberler.com"
+ ],
+ "ens.fr": [
+ "psl.eu"
+ ],
+ "ensighten.com": [
+ "aljazeera.com",
+ "britishairways.com"
+ ],
+ "entertainow.com": [
+ "dailydot.com"
+ ],
+ "entrust.net": [
+ "rkdms.com"
+ ],
+ "envoke.com": [
+ "wildapricot.com"
+ ],
+ "epicurious.com": [
+ "wired.com",
+ "newyorker.com",
+ "vanityfair.com"
+ ],
+ "episerver.net": [
+ "iata.org",
+ "bsigroup.com"
+ ],
+ "eqads.com": [
+ "autotrader.ca"
+ ],
+ "equalstyle.com": [
+ "hubpages.com"
+ ],
+ "erepublic.com": [
+ "govtech.com",
+ "governing.com"
+ ],
+ "essayassist.com": [
+ "eliteessaywriters.com"
+ ],
+ "essayprofit.com": [
+ "masterpapers.com",
+ "payforessay.net",
+ "samedayessay.com"
+ ],
+ "estadao-bi-ga360.appspot.com": [
+ "estadao.com.br"
+ ],
+ "estat.com": [
+ "over-blog.com",
+ "lefigaro.fr",
+ "eklablog.com"
+ ],
+ "etracker.de": [
+ "unibe.ch",
+ "muenchen.de"
+ ],
+ "eum-appdynamics.com": [
+ "webex.com",
+ "intuit.com",
+ "jstor.org"
+ ],
+ "everesttech.net": [
+ "adobe.com",
+ "msn.com",
+ "okezone.com"
+ ],
+ "evergage.com": [
+ "cisco.com",
+ "ti.com",
+ "adorama.com"
+ ],
+ "everyaction.com": [
+ "ewg.org",
+ "ucsusa.org",
+ "audubon.org"
+ ],
+ "everzones.com": [
+ "cleanpng.com"
+ ],
+ "evise.com": [
+ "thelancet.com",
+ "cell.com"
+ ],
+ "evo.company": [
+ "prom.ua",
+ "tiu.ru"
+ ],
+ "evolok.net": [
+ "realclearpolitics.com",
+ "newstatesman.com",
+ "nation.africa"
+ ],
+ "evsuite.com": [
+ "thrivecart.com"
+ ],
+ "ewrvdi.net": [
+ "alamy.com"
+ ],
+ "exactag.com": [
+ "t-online.de",
+ "bahn.de"
+ ],
+ "exacttarget.com": [
+ "uschamber.com"
+ ],
+ "excite.co.jp": [
+ "exblog.jp"
+ ],
+ "exdynsrv.com": [
+ "manganelo.com",
+ "veoh.com",
+ "lectortmo.com"
+ ],
+ "exelator.com": [
+ "amazon.com",
+ "msn.com",
+ "okezone.com"
+ ],
+ "exitintel.com": [
+ "harpercollins.com",
+ "simonandschuster.com"
+ ],
+ "exoclick.com": [
+ "manganelo.com",
+ "txxx.com",
+ "stripchat.com"
+ ],
+ "exosrv.com": [
+ "spankbang.com",
+ "sxyprn.com",
+ "txxx.com"
+ ],
+ "exoticads.com": [
+ "chaturbate.com"
+ ],
+ "expedia.com": [
+ "informationweek.com",
+ "fstoppers.com"
+ ],
+ "expediapartnercentral.com": [
+ "vrbo.com"
+ ],
+ "experiancs.com": [
+ "experian.com"
+ ],
+ "expertrec.com": [
+ "livecareer.com"
+ ],
+ "exponea.com": [
+ "ozon.ru",
+ "id-binomo.com",
+ "patient.info"
+ ],
+ "eyeota.net": [
+ "msn.com",
+ "forbes.com",
+ "detik.com"
+ ],
+ "eyereturn.com": [
+ "thestar.com",
+ "queensu.ca",
+ "eyereturnmarketing.com"
+ ],
+ "ezoic.net": [
+ "smallbiztrends.com",
+ "mensjournal.com",
+ "broadwayworld.com"
+ ],
+ "f1272serve.xyz": [
+ "youporn.com"
+ ],
+ "f5.com": [
+ "nginx.com"
+ ],
+ "fabled.com": [
+ "next.co.uk"
+ ],
+ "facebook.com": [
+ "instagram.com",
+ "netflix.com",
+ "amazon.com"
+ ],
+ "fairfaxregional.com.au": [
+ "canberratimes.com.au"
+ ],
+ "faisys.com": [
+ "qhnmdb.com"
+ ],
+ "fang.com": [
+ "soufun.com"
+ ],
+ "farfetch-contents.com": [
+ "farfetch.com"
+ ],
+ "farfetch.net": [
+ "farfetch.com"
+ ],
+ "faromen.online": [
+ "hclips.com"
+ ],
+ "fastapi.net": [
+ "ifeng.com"
+ ],
+ "fastcounter.de": [
+ "directupload.net"
+ ],
+ "fcglcdn.com": [
+ "firstcry.com"
+ ],
+ "feathr.co": [
+ "asm.org",
+ "nutrition.org",
+ "contentmarketinginstitute.com"
+ ],
+ "feedify.net": [
+ "jagonews24.com",
+ "newstrend.news",
+ "tv9marathi.com"
+ ],
+ "felmat.net": [
+ "techacademy.jp",
+ "lolipop.jp"
+ ],
+ "fengimg.com": [
+ "feng.com"
+ ],
+ "fengkongcloud.com": [
+ "ccidnet.com",
+ "56.com"
+ ],
+ "ferret-one.com": [
+ "ferret-plus.com"
+ ],
+ "ffmapi.com": [
+ "audiomack.com"
+ ],
+ "fieldtest.cc": [
+ "bloody-disgusting.com"
+ ],
+ "filmibeat.com": [
+ "oneindia.com"
+ ],
+ "finam.ru": [
+ "kp.ru"
+ ],
+ "financialjuice.com": [
+ "zerohedge.com"
+ ],
+ "finder.com.au": [
+ "finder.com"
+ ],
+ "firebaselogging.googleapis.com": [
+ "vice.com",
+ "history.com",
+ "hk01.com"
+ ],
+ "firstimpression.io": [
+ "wegotthiscovered.com",
+ "jpost.com",
+ "ynet.co.il"
+ ],
+ "fiverr.com": [
+ "informationweek.com"
+ ],
+ "fivetran.com": [
+ "wistia.com",
+ "kiva.org"
+ ],
+ "fkw.com": [
+ "qhdsny.com",
+ "qhnmdb.com"
+ ],
+ "flashtalking.com": [
+ "adobe.com",
+ "godaddy.com",
+ "dell.com"
+ ],
+ "flipp.com": [
+ "jcpenney.com"
+ ],
+ "flocktory.com": [
+ "farfetch.com",
+ "cian.ru",
+ "mvideo.ru"
+ ],
+ "flowtype.press": [
+ "sciencedaily.com"
+ ],
+ "flw.li": [
+ "project-syndicate.org"
+ ],
+ "focas.jp": [
+ "dlsite.com",
+ "onamae.com"
+ ],
+ "fontplus.jp": [
+ "ntv.co.jp"
+ ],
+ "fooby.ch": [
+ "20min.ch"
+ ],
+ "foodnetwork.com": [
+ "foodnetwork.co.uk"
+ ],
+ "force.com": [
+ "bhphotovideo.com",
+ "akamai.com",
+ "rsa.com"
+ ],
+ "foreks.com": [
+ "liberal.gr"
+ ],
+ "foresee.com": [
+ "qualcomm.com",
+ "ralphlauren.com"
+ ],
+ "formstack.io": [
+ "exploratorium.edu"
+ ],
+ "fospha.com": [
+ "nhm.ac.uk",
+ "mandarinoriental.com"
+ ],
+ "foursquare.com": [
+ "oliveogrill.com"
+ ],
+ "fout.jp": [
+ "moneyforward.com",
+ "wowkorea.jp",
+ "alc.co.jp"
+ ],
+ "fox.com": [
+ "nationalgeographic.com",
+ "foxsports.com"
+ ],
+ "foxycart.com": [
+ "brookings.edu"
+ ],
+ "fppressa.ru": [
+ "cosmo.ru"
+ ],
+ "franecki.net": [
+ "filmix.co",
+ "rezka.ag",
+ "baskino.me"
+ ],
+ "franeski.net": [
+ "hdrezka-ag.com"
+ ],
+ "freelancer.com": [
+ "informationweek.com"
+ ],
+ "freeskreen.com": [
+ "globalnews.ca",
+ "sfweekly.com",
+ "sfexaminer.com"
+ ],
+ "freespee.com": [
+ "plus.net"
+ ],
+ "freevisitorcounters.com": [
+ "prensa-latina.cu"
+ ],
+ "freshchat.com": [
+ "freshdesk.com",
+ "sehatq.com",
+ "upstox.com"
+ ],
+ "freshdesk.com": [
+ "italist.com"
+ ],
+ "freshrelevance.com": [
+ "stltoday.com",
+ "madison.com"
+ ],
+ "fresnobee.com": [
+ "idahostatesman.com"
+ ],
+ "friendbuy.com": [
+ "forever21.com"
+ ],
+ "frosmo.com": [
+ "helsinki.fi"
+ ],
+ "fstrk.net": [
+ "forgeofempires.com"
+ ],
+ "fujitsu-webmart.com": [
+ "moppy.jp"
+ ],
+ "fundraiseup.com": [
+ "heart.org"
+ ],
+ "fwmrm.net": [
+ "geeksforgeeks.org",
+ "foodnetwork.com",
+ "nbc.com"
+ ],
+ "fx678img.com": [
+ "fx678.com"
+ ],
+ "fyi-marketing.com": [
+ "tomanifesto.gr"
+ ],
+ "fyrsbckgi-c.global.ssl.fastly.net": [
+ "lenovo.com",
+ "upwork.com",
+ "asics.com"
+ ],
+ "gamania.com": [
+ "nownews.com"
+ ],
+ "gameanalytics.dev": [
+ "gameanalytics.com"
+ ],
+ "gammaplatform.com": [
+ "baomoi.com",
+ "indosport.com",
+ "2banh.vn"
+ ],
+ "garanti.com.tr": [
+ "garantibbva.com.tr"
+ ],
+ "gator.io": [
+ "webstarts.com"
+ ],
+ "gaug.es": [
+ "crictracker.com"
+ ],
+ "gazeta.pl": [
+ "wyborcza.pl"
+ ],
+ "gcimetrics.com": [
+ "guitarcenter.com"
+ ],
+ "gd.gov.cn": [
+ "gz.gov.cn"
+ ],
+ "gdz.work": [
+ "gdz.ru"
+ ],
+ "geekbuying.com": [
+ "informationweek.com"
+ ],
+ "geetest.com": [
+ "zhaopin.com",
+ "globalsources.com",
+ "fnac.com"
+ ],
+ "geilicdn.com": [
+ "weidian.com"
+ ],
+ "geistm.com": [
+ "msn.com",
+ "dashlane.com",
+ "rosettastone.com"
+ ],
+ "gelbmann.info": [
+ "w3techs.com"
+ ],
+ "geminimedia-eg.com": [
+ "masrawy.com"
+ ],
+ "gemius.pl": [
+ "allegro.pl",
+ "ensonhaber.com",
+ "onet.pl"
+ ],
+ "generaltracking.de": [
+ "check24.de"
+ ],
+ "genieesspv.jp": [
+ "eroterest.net",
+ "jawapos.com"
+ ],
+ "geniusmonkey.com": [
+ "pdx.edu",
+ "fullerton.edu"
+ ],
+ "geofli.com": [
+ "nokia.com"
+ ],
+ "geotrust.com": [
+ "rapidssl.com"
+ ],
+ "get4click.ru": [
+ "skyeng.ru"
+ ],
+ "getadmiral.com": [
+ "bigthink.com",
+ "newatlas.com"
+ ],
+ "getapp.com": [
+ "scoop.it"
+ ],
+ "getblue.io": [
+ "newchic.com",
+ "movavi.com"
+ ],
+ "getblueshift.com": [
+ "slickdeals.net",
+ "udacity.com",
+ "tiki.vn"
+ ],
+ "getclicky.com": [
+ "boutell.co.uk",
+ "kompas.tv",
+ "newatlas.com"
+ ],
+ "getcreditone.com": [
+ "creditonebank.com"
+ ],
+ "getdrip.com": [
+ "socialmediaexaminer.com",
+ "leadpages.com",
+ "thrivecart.com"
+ ],
+ "getletterpress.com": [
+ "casetify.com",
+ "toasttab.com",
+ "stitchfix.com"
+ ],
+ "getnshow.com": [
+ "hani.co.kr"
+ ],
+ "getrockerbox.com": [
+ "codecademy.com",
+ "society6.com",
+ "saatchiart.com"
+ ],
+ "getsmartcontent.com": [
+ "pcworld.com"
+ ],
+ "getway.biz": [
+ "parspack.com"
+ ],
+ "gh-base.com": [
+ "ascii.jp"
+ ],
+ "gigazine.asia": [
+ "gigazine.net"
+ ],
+ "gigya.com": [
+ "abc.net.au",
+ "deloitte.com",
+ "abs-cbn.com"
+ ],
+ "gimp.org": [
+ "flattr.com"
+ ],
+ "giraff.io": [
+ "iz.ru",
+ "vz.ru",
+ "yandex.ru"
+ ],
+ "gitee.com": [
+ "discuz.net"
+ ],
+ "github.com": [
+ "flurry.com",
+ "imagemagick.com"
+ ],
+ "gixioanalytics.com": [
+ "slashgear.com"
+ ],
+ "gjirafa.com": [
+ "gazetaexpress.com"
+ ],
+ "glamour.com": [
+ "wired.com",
+ "newyorker.com",
+ "vanityfair.com"
+ ],
+ "glassboxdigital.io": [
+ "marriott.com",
+ "creditonebank.com",
+ "ritzcarlton.com"
+ ],
+ "glassdoor.com": [
+ "a2hosting.com",
+ "paychex.com"
+ ],
+ "gleam.io": [
+ "macrumors.com",
+ "businessinsider.com.au",
+ "androidauthority.com"
+ ],
+ "global-e.com": [
+ "forever21.com"
+ ],
+ "globalwebindex.net": [
+ "people.com",
+ "ew.com",
+ "travelandleisure.com"
+ ],
+ "globo.com": [
+ "techtudo.com.br"
+ ],
+ "gmossp-sp.jp": [
+ "xrea.com",
+ "tenki.jp",
+ "lolipop.jp"
+ ],
+ "go.com": [
+ "abc7news.com",
+ "abc7chicago.com",
+ "abc13.com"
+ ],
+ "godaddy.com": [
+ "heycould.com",
+ "junwonsil.com",
+ "cdn.house"
+ ],
+ "goepson.com": [
+ "epson.com"
+ ],
+ "gogocdn.net": [
+ "gogoanime.so"
+ ],
+ "goinflow.com": [
+ "tenable.com"
+ ],
+ "goo.ne.jp": [
+ "ocn.ne.jp"
+ ],
+ "google-analytics.com": [
+ "linkedin.com",
+ "google.com",
+ "godaddy.com"
+ ],
+ "google.com": [
+ "linkedin.com",
+ "yahoo.com",
+ "googletagmanager.com"
+ ],
+ "google.com.pk": [
+ "express.pk"
+ ],
+ "googleadservices.com": [
+ "matterport.com"
+ ],
+ "goop.com": [
+ "informationweek.com"
+ ],
+ "gosuslugi.ru": [
+ "mosreg.ru"
+ ],
+ "gotprofits.com": [
+ "gotporn.com"
+ ],
+ "goutee.top": [
+ "allocine.fr"
+ ],
+ "governing.com": [
+ "govtech.com"
+ ],
+ "gq.com": [
+ "wired.com",
+ "newyorker.com",
+ "vanityfair.com"
+ ],
+ "graizoah.com": [
+ "shahid4u.io",
+ "clipconverter.cc"
+ ],
+ "gravito.net": [
+ "iltalehti.fi"
+ ],
+ "grctech.com": [
+ "grc.com"
+ ],
+ "green-red.com": [
+ "jugantor.com"
+ ],
+ "gridsumdissector.com": [
+ "www.gov.cn",
+ "pcauto.com.cn",
+ "cztv.com"
+ ],
+ "groovinads.com": [
+ "cronica.com.ar",
+ "retargetly.com",
+ "perfil.com"
+ ],
+ "group-ib.ru": [
+ "eldorado.ru"
+ ],
+ "groupondata.com": [
+ "groupon.com"
+ ],
+ "growingio.com": [
+ "focus.cn",
+ "53kf.com",
+ "koolearn.com"
+ ],
+ "grumft.com": [
+ "otvfoco.com.br"
+ ],
+ "grupaonet.pl": [
+ "onet.pl"
+ ],
+ "grupapino.pl": [
+ "prv.pl"
+ ],
+ "grupoelcorteingles.es": [
+ "elcorteingles.es"
+ ],
+ "gsoi.fr": [
+ "sudouest.fr"
+ ],
+ "gsspat.jp": [
+ "dmm.co.jp",
+ "lolipop.jp",
+ "wowkorea.jp"
+ ],
+ "gssprt.jp": [
+ "sony.jp",
+ "eroterest.net",
+ "jawapos.com"
+ ],
+ "gtags.net": [
+ "ctrip.com",
+ "suning.com",
+ "idianfa.com"
+ ],
+ "gumgum.com": [
+ "youm7.com",
+ "geeksforgeeks.org",
+ "venturebeat.com"
+ ],
+ "guoshipartners.com": [
+ "hinet.net",
+ "buzzorange.com"
+ ],
+ "gwdg.de": [
+ "uni-goettingen.de"
+ ],
+ "gwmtracking.com": [
+ "norton.com",
+ "proofpoint.com",
+ "blurb.com"
+ ],
+ "haaretz.co.il": [
+ "haaretz.com"
+ ],
+ "hactar.is": [
+ "opendemocracy.net"
+ ],
+ "hainanfp.com": [
+ "hinews.cn"
+ ],
+ "halfclub.com": [
+ "hani.co.kr"
+ ],
+ "hanmaker.com": [
+ "ooopic.com",
+ "58pic.com"
+ ],
+ "hao123.com": [
+ "skycn.com"
+ ],
+ "hao123img.com": [
+ "skycn.com"
+ ],
+ "harrisinteractive.eu": [
+ "olympic.org"
+ ],
+ "hasbroapps.com": [
+ "hasbro.com"
+ ],
+ "hatena.ne.jp": [
+ "hatenablog.com"
+ ],
+ "hbabit.com": [
+ "huobi.com"
+ ],
+ "hbc.com": [
+ "saksfifthavenue.com"
+ ],
+ "hcaptcha.com": [
+ "bahn.de",
+ "cgtrader.com"
+ ],
+ "headbidder.net": [
+ "christianpost.com"
+ ],
+ "healthunlocked.com": [
+ "adaa.org"
+ ],
+ "heapanalytics.com": [
+ "merriam-webster.com",
+ "calendly.com",
+ "slickdeals.net"
+ ],
+ "hellorf.com": [
+ "zcool.com.cn"
+ ],
+ "heraldm.com": [
+ "koreaherald.com"
+ ],
+ "hexagon-analytics.com": [
+ "flickr.com",
+ "udemy.com",
+ "scribd.com"
+ ],
+ "hgbn.network": [
+ "24video.vip"
+ ],
+ "hgtv.com": [
+ "discovery.com",
+ "foodnetwork.com",
+ "diynetwork.com"
+ ],
+ "hhcdn.ru": [
+ "hh.ru"
+ ],
+ "highlow.net": [
+ "highlow.com"
+ ],
+ "highwire.org": [
+ "pnas.org",
+ "diabetesjournals.org",
+ "aacrjournals.org"
+ ],
+ "hihainan.info": [
+ "hinews.cn"
+ ],
+ "hiido.com": [
+ "yy.com",
+ "bigolive.tv",
+ "duowan.com"
+ ],
+ "hilton.com": [
+ "informationweek.com"
+ ],
+ "hindustantimes.com": [
+ "livemint.com",
+ "livehindustan.com",
+ "shine.com"
+ ],
+ "hinet.net": [
+ "xuite.net"
+ ],
+ "histats.com": [
+ "alnaharegypt.com",
+ "sarkariresult.com",
+ "las2orillas.co"
+ ],
+ "hitslink.com": [
+ "webstarts.com"
+ ],
+ "hive.co": [
+ "complex.com"
+ ],
+ "hket.com": [
+ "ulifestyle.com.hk"
+ ],
+ "hketgroup.com": [
+ "hket.com",
+ "ulifestyle.com.hk"
+ ],
+ "hlserve.com": [
+ "bestbuy.com",
+ "dickssportinggoods.com"
+ ],
+ "hmhost.co.uk": [
+ "autocar.co.uk"
+ ],
+ "holder.com.ua": [
+ "i.ua",
+ "bigmir.net",
+ "korrespondent.net"
+ ],
+ "holmesmind.com": [
+ "yahoo.com",
+ "buzzorange.com"
+ ],
+ "homeway.com.cn": [
+ "hexun.com"
+ ],
+ "hosted-inin.com": [
+ "ray-ban.com"
+ ],
+ "hot-mob.com": [
+ "on.cc"
+ ],
+ "hotelscombined.com": [
+ "informationweek.com"
+ ],
+ "hotwire.com": [
+ "informationweek.com"
+ ],
+ "hq3x.com": [
+ "hdsex.org"
+ ],
+ "hsbc.com.hk": [
+ "hangseng.com"
+ ],
+ "htcvive.com": [
+ "htc.com"
+ ],
+ "hton.com.cn": [
+ "workercn.cn"
+ ],
+ "hubpd.com": [
+ "huanqiu.com",
+ "stcn.com"
+ ],
+ "hubspot.com": [
+ "surveymonkey.com",
+ "freepik.com",
+ "disqus.com"
+ ],
+ "hujiang.com": [
+ "hjenglish.com"
+ ],
+ "hulu.com": [
+ "informationweek.com"
+ ],
+ "huluqa.com": [
+ "hilton.com"
+ ],
+ "humcommerce.com": [
+ "cyberchimps.com"
+ ],
+ "hurpass.com": [
+ "hurriyet.com.tr",
+ "hurriyetdailynews.com"
+ ],
+ "hushly.com": [
+ "teamviewer.com",
+ "matterport.com",
+ "onelogin.com"
+ ],
+ "hybrid.ai": [
+ "ozon.ru",
+ "rezka.ag",
+ "drive2.ru"
+ ],
+ "hyros.com": [
+ "clickfunnels.com"
+ ],
+ "i-mobile.co.jp": [
+ "lolipop.jp",
+ "syosetu.com",
+ "dlsite.com"
+ ],
+ "i.ua": [
+ "bigmir.net",
+ "korrespondent.net"
+ ],
+ "i115008.net": [
+ "udacity.com"
+ ],
+ "i347961.net": [
+ "canadiantire.ca"
+ ],
+ "iadvize.com": [
+ "samsung.com",
+ "prestashop.com",
+ "labanquepostale.fr"
+ ],
+ "iasds01.com": [
+ "zingnews.vn",
+ "baomoi.com"
+ ],
+ "ib-ibi.com": [
+ "howstuffworks.com",
+ "mapquest.com"
+ ],
+ "ibclick.stream": [
+ "webmd.com",
+ "medscape.com",
+ "medicinenet.com"
+ ],
+ "ibillboard.com": [
+ "ceskatelevize.cz"
+ ],
+ "ibt.com": [
+ "ibtimes.co.uk"
+ ],
+ "iconnode.com": [
+ "anydesk.com"
+ ],
+ "id5-sync.com": [
+ "okezone.com",
+ "imgur.com",
+ "dailymail.co.uk"
+ ],
+ "idealmedia.io": [
+ "uptodown.com"
+ ],
+ "ideaplus.mk": [
+ "time.mk"
+ ],
+ "idio.co": [
+ "ibm.com",
+ "intel.com",
+ "adp.com"
+ ],
+ "iesnare.com": [
+ "mercari.com",
+ "citi.com",
+ "dyn.com"
+ ],
+ "ign.com": [
+ "videojs.com",
+ "gamespy.com"
+ ],
+ "igodigital.com": [
+ "usatoday.com",
+ "smh.com.au",
+ "lowes.com"
+ ],
+ "iheart.com": [
+ "theblaze.com",
+ "bnnbloomberg.ca"
+ ],
+ "iherb.com": [
+ "informationweek.com"
+ ],
+ "ijento.com": [
+ "searchenginewatch.com",
+ "clickz.com"
+ ],
+ "iljmp.com": [
+ "stocktwits.com"
+ ],
+ "im-apps.net": [
+ "kakaku.com",
+ "biglobe.ne.jp",
+ "nifty.com"
+ ],
+ "imedao.com": [
+ "xueqiu.com"
+ ],
+ "imedia.cz": [
+ "seznam.cz",
+ "idnes.cz",
+ "novinky.cz"
+ ],
+ "imhd.io": [
+ "variety.com",
+ "rollingstone.com",
+ "wwd.com"
+ ],
+ "imi.chat": [
+ "asha.org"
+ ],
+ "impact-ad.jp": [
+ "yahoo.co.jp",
+ "rakuten.co.jp",
+ "nikkei.com"
+ ],
+ "impact.com": [
+ "bestbuy.com"
+ ],
+ "implishing.club": [
+ "shorturl.at",
+ "analdin.com",
+ "xozilla.com"
+ ],
+ "impression.link": [
+ "thetrainline.com"
+ ],
+ "imrworldwide.com": [
+ "yahoo.co.jp",
+ "cnn.com",
+ "twitch.tv"
+ ],
+ "imspublishergroup.com": [
+ "marketbeat.com"
+ ],
+ "in-page-push.com": [
+ "opensubtitles.org",
+ "fakaza.com",
+ "clipconverter.cc"
+ ],
+ "inbenta.com": [
+ "credit-agricole.fr"
+ ],
+ "indacolive.com": [
+ "dezeen.com"
+ ],
+ "indapass.hu": [
+ "index.hu",
+ "blog.hu"
+ ],
+ "indeed.com": [
+ "indeed.co.uk",
+ "wpfr.net"
+ ],
+ "india.com": [
+ "dnaindia.com"
+ ],
+ "indianexpress.com": [
+ "financialexpress.com"
+ ],
+ "indoleads.com": [
+ "newchic.com"
+ ],
+ "infeed.id": [
+ "liputan6.com",
+ "dream.co.id",
+ "bola.com"
+ ],
+ "infinigrow.com": [
+ "similarweb.com"
+ ],
+ "infinity-tracking.net": [
+ "telegraph.co.uk",
+ "gartner.com",
+ "waldenu.edu"
+ ],
+ "infolinks.com": [
+ "prospect.org",
+ "cootekservice.com"
+ ],
+ "informz.net": [
+ "physiology.org",
+ "eatright.org",
+ "adaa.org"
+ ],
+ "infusionsoft.app": [
+ "keap.com"
+ ],
+ "infusionsoft.com": [
+ "keap.com"
+ ],
+ "ingage.tech": [
+ "alternet.org"
+ ],
+ "injapan.com": [
+ "japantoday.com"
+ ],
+ "inmobi.net": [
+ "inmobi.com"
+ ],
+ "inmoment.com": [
+ "golfdigest.com"
+ ],
+ "innity.com": [
+ "liputan6.com",
+ "merdeka.com",
+ "kapanlagi.com"
+ ],
+ "innocraft.cloud": [
+ "thunderbird.net",
+ "bunnycdn.com"
+ ],
+ "innogamescdn.com": [
+ "forgeofempires.com"
+ ],
+ "innologica.com": [
+ "inoreader.com"
+ ],
+ "innovid.com": [
+ "southwest.com",
+ "toyota.com",
+ "bet.com"
+ ],
+ "inpagepush.com": [
+ "y2mate.guru",
+ "shahid4u.io",
+ "4anime.to"
+ ],
+ "inpwrd.net": [
+ "twincities.com",
+ "dice.com"
+ ],
+ "inq.com": [
+ "ups.com",
+ "att.com",
+ "tdameritrade.com"
+ ],
+ "insent.ai": [
+ "sortable.com"
+ ],
+ "inside-graph.com": [
+ "gucci.com",
+ "sephora.com",
+ "valentino.com"
+ ],
+ "insider.com": [
+ "businessinsider.com.au"
+ ],
+ "insightexpressai.com": [
+ "unsplash.com",
+ "experian.com",
+ "thrillist.com"
+ ],
+ "instabot.io": [
+ "arthritis.org"
+ ],
+ "instagram.com": [
+ "arizona.edu",
+ "nokia.com",
+ "tmz.com"
+ ],
+ "insticator.com": [
+ "youm7.com",
+ "mydramalist.com",
+ "alternet.org"
+ ],
+ "insurads.com": [
+ "corriere.it",
+ "abc.es",
+ "vocento.com"
+ ],
+ "intellitxt.com": [
+ "techadvisor.co.uk"
+ ],
+ "intent-apps.com": [
+ "codecademy.com",
+ "zappos.com"
+ ],
+ "intent.ai": [
+ "news.am"
+ ],
+ "intentiq.com": [
+ "usatoday.com",
+ "uptodown.com",
+ "matterport.com"
+ ],
+ "intentmedia.net": [
+ "zappos.com",
+ "hotwire.com",
+ "latam.com"
+ ],
+ "intentsify.io": [
+ "home.neustar"
+ ],
+ "intergient.com": [
+ "collider.com",
+ "infoplease.com",
+ "letterboxd.com"
+ ],
+ "internetbrands.com": [
+ "nolo.com",
+ "avvo.com",
+ "vbulletin.com"
+ ],
+ "investingchannel.com": [
+ "finviz.com",
+ "benzinga.com",
+ "stocktwits.com"
+ ],
+ "investis.com": [
+ "ge.com",
+ "informa.com",
+ "thewaltdisneycompany.com"
+ ],
+ "investorwords.com": [
+ "businessdictionary.com"
+ ],
+ "invl.co": [
+ "goody25.com"
+ ],
+ "invttjs.com.br": [
+ "abril.com.br"
+ ],
+ "ioam.de": [
+ "spiegel.de",
+ "businessinsider.de",
+ "t-online.de"
+ ],
+ "iocnt.net": [
+ "orf.at",
+ "krone.at",
+ "kurier.at"
+ ],
+ "ip-label.net": [
+ "rtve.es"
+ ],
+ "ipchaxun.com": [
+ "ip138.com"
+ ],
+ "iperceptions.com": [
+ "xfinity.com",
+ "adobe.com",
+ "wwe.com"
+ ],
+ "ipgeolocation.io": [
+ "chathamhouse.org"
+ ],
+ "ipify.org": [
+ "threatpost.com"
+ ],
+ "ipinyou.com": [
+ "shangri-la.com",
+ "klook.com"
+ ],
+ "ipredictive.com": [
+ "coinmarketcap.com",
+ "aarp.org",
+ "autozone.com"
+ ],
+ "ipvanish.com": [
+ "informationweek.com"
+ ],
+ "iqoption.com": [
+ "iqbroker.com"
+ ],
+ "irs03.com": [
+ "mgtv.com",
+ "56.com",
+ "pcauto.com.cn"
+ ],
+ "isanook.com": [
+ "sanook.com"
+ ],
+ "islamist-movements.com": [
+ "albawabhnews.com"
+ ],
+ "ispot.tv": [
+ "wayfair.com",
+ "t-mobile.com",
+ "experian.com"
+ ],
+ "issuu.com": [
+ "metrotimes.com",
+ "riverfronttimes.com",
+ "orlandoweekly.com"
+ ],
+ "istruzione.it": [
+ "miur.gov.it"
+ ],
+ "iteratehq.com": [
+ "nytimes.com",
+ "economist.com",
+ "roku.com"
+ ],
+ "itmedia.co.jp": [
+ "atmarkit.co.jp"
+ ],
+ "itmedia.jp": [
+ "itmedia.co.jp",
+ "atmarkit.co.jp"
+ ],
+ "ivcbrasil.org.br": [
+ "campograndenews.com.br",
+ "estadao.com.br",
+ "clicrbs.com.br"
+ ],
+ "ivideosmart.com": [
+ "tribunnews.com",
+ "inquirer.net",
+ "brilio.net"
+ ],
+ "ivx.cn": [
+ "ih5.cn"
+ ],
+ "ixiaa.com": [
+ "aaa.com",
+ "equifax.com"
+ ],
+ "izooto.com": [
+ "moneycontrol.com",
+ "inquirer.net",
+ "jpnn.com"
+ ],
+ "jabmo.app": [
+ "sigmaaldrich.com"
+ ],
+ "jads.co": [
+ "tyker.xyz",
+ "avgle.com"
+ ],
+ "janrainsso.com": [
+ "financialpost.com",
+ "montrealgazette.com",
+ "calgaryherald.com"
+ ],
+ "jassfederal.ch": [
+ "bluewin.ch"
+ ],
+ "jd.com": [
+ "ifeng.com"
+ ],
+ "jhu.edu": [
+ "jhsph.edu"
+ ],
+ "jilt.com": [
+ "famethemes.com",
+ "wpzoom.com"
+ ],
+ "jiosaavn.com": [
+ "jio.com"
+ ],
+ "jivosite.com": [
+ "e-planning.net",
+ "1sept.ru"
+ ],
+ "jixie.io": [
+ "grid.id"
+ ],
+ "jnqsge.net": [
+ "acuityscheduling.com"
+ ],
+ "jobat.be": [
+ "nieuwsblad.be"
+ ],
+ "journalmedia.ie": [
+ "thejournal.ie"
+ ],
+ "jrs5.com": [
+ "newegg.com"
+ ],
+ "jschina.com.cn": [
+ "xhby.net"
+ ],
+ "jsdelivr.net": [
+ "hops.id",
+ "saksfifthavenue.com",
+ "uns.ac.id",
+ "jamesclear.com"
+ ],
+ "jsrdn.com": [
+ "dallasnews.com",
+ "realclearpolitics.com",
+ "sparknotes.com"
+ ],
+ "juicyads.com": [
+ "e-hentai.org",
+ "avgle.com"
+ ],
+ "justpremium.com": [
+ "techradar.com",
+ "inquisitr.com",
+ "pcgamer.com"
+ ],
+ "jwplayer.com": [
+ "theregister.com",
+ "beinsports.com",
+ "stripes.com"
+ ],
+ "jwpltx.com": [
+ "npr.org",
+ "merriam-webster.com",
+ "fastcompany.com"
+ ],
+ "jxtrackers.azurewebsites.net": [
+ "kompas.com",
+ "grid.id",
+ "kompasiana.com"
+ ],
+ "kaipuyun.cn": [
+ "hunan.gov.cn",
+ "hainan.gov.cn",
+ "stdaily.com"
+ ],
+ "kaixin001.com.cn": [
+ "kaixin001.com"
+ ],
+ "kakao.com": [
+ "daum.net",
+ "tistory.com"
+ ],
+ "kameleoon.eu": [
+ "heise.de",
+ "awin.com",
+ "banquepopulaire.fr"
+ ],
+ "kampyle.com": [
+ "lowes.com"
+ ],
+ "kanade-ad.net": [
+ "tenki.jp",
+ "syosetu.com"
+ ],
+ "kaprila.com": [
+ "soft98.ir",
+ "faradars.org",
+ "yasdl.com"
+ ],
+ "kaptcha.com": [
+ "nerdwallet.com",
+ "placeit.net",
+ "everlane.com"
+ ],
+ "kargo.com": [
+ "dailymail.co.uk",
+ "youm7.com",
+ "thehill.com"
+ ],
+ "karpishe.com": [
+ "asriran.com"
+ ],
+ "kartra.com": [
+ "webinarjam.com"
+ ],
+ "kaspersky-labs.com": [
+ "kaspersky.com"
+ ],
+ "kaxsdc.com": [
+ "papajohns.com"
+ ],
+ "kayak.com": [
+ "priceline.com"
+ ],
+ "kcsfile.com": [
+ "kucoin.com"
+ ],
+ "kexin001.com": [
+ "babytree.com"
+ ],
+ "keywee.co": [
+ "nationalgeographic.com",
+ "mashable.com",
+ "nypost.com"
+ ],
+ "kf5.com": [
+ "growingio.com"
+ ],
+ "kinsta.com": [
+ "informationweek.com"
+ ],
+ "kivpro.com": [
+ "yenicag.az"
+ ],
+ "kl-youniverse.com": [
+ "dream.co.id",
+ "bola.com",
+ "fimela.com"
+ ],
+ "klangoo.com": [
+ "globalresearch.ca",
+ "dailyherald.com"
+ ],
+ "klarnaservices.com": [
+ "jbl.com"
+ ],
+ "klarnauserservices.com": [
+ "jbl.com"
+ ],
+ "kleecks.com": [
+ "fendi.com"
+ ],
+ "klick2contact.com": [
+ "thebodyshop.com"
+ ],
+ "knet.cn": [
+ "china.com.cn",
+ "eastday.com",
+ "hexun.com"
+ ],
+ "knnlab.com": [
+ "informaconnect.com"
+ ],
+ "knotch.it": [
+ "aboutamazon.com"
+ ],
+ "koddi.com": [
+ "hilton.com",
+ "wyndhamhotels.com"
+ ],
+ "kompas.com": [
+ "tribunnews.com",
+ "grid.id",
+ "kompasiana.com"
+ ],
+ "kooora.ws": [
+ "kooora.com"
+ ],
+ "kpcdn.net": [
+ "kp.ru"
+ ],
+ "kraken.com": [
+ "informationweek.com"
+ ],
+ "krxd.net": [
+ "time.com",
+ "foxnews.com",
+ "salesforce.com"
+ ],
+ "ksmobile.com": [
+ "duba.com",
+ "newduba.cn"
+ ],
+ "kwanzoo.com": [
+ "treasuredata.com"
+ ],
+ "labocleo.org": [
+ "hypotheses.org",
+ "openedition.org"
+ ],
+ "ladbible.com": [
+ "sportbible.com"
+ ],
+ "ladsp.com": [
+ "syosetu.com",
+ "sony.jp",
+ "sankei.com"
+ ],
+ "lan.com": [
+ "latam.com"
+ ],
+ "landc.co.uk": [
+ "thisismoney.co.uk"
+ ],
+ "latinongroup.com": [
+ "ambito.com"
+ ],
+ "leadexpert.pl": [
+ "gazeta.pl"
+ ],
+ "leadlab.click": [
+ "fraunhofer.de"
+ ],
+ "leadlander.com": [
+ "panasonic.com",
+ "servicenow.com",
+ "cornerstoneondemand.com"
+ ],
+ "leadquizzes.com": [
+ "diariolibre.com"
+ ],
+ "leadspace.com": [
+ "opendns.com"
+ ],
+ "leadsrx.com": [
+ "monster.com"
+ ],
+ "leady.com": [
+ "fieldengineer.com"
+ ],
+ "leafly.ca": [
+ "leafly.com"
+ ],
+ "ledger.com": [
+ "informationweek.com"
+ ],
+ "leju.com": [
+ "7gz.com"
+ ],
+ "lemnisk.co": [
+ "axisbank.com"
+ ],
+ "lennyletter.com": [
+ "wired.com",
+ "newyorker.com",
+ "vanityfair.com"
+ ],
+ "lenovo.com": [
+ "lenovo.com.cn"
+ ],
+ "lentainform.com": [
+ "uptodown.com",
+ "rbc.ru",
+ "idealmedia.io"
+ ],
+ "letv.com": [
+ "le.com"
+ ],
+ "lfeeder.com": [
+ "foxitsoftware.com",
+ "wur.nl"
+ ],
+ "liadm.com": [
+ "bloomberg.com",
+ "cnet.com",
+ "usatoday.com"
+ ],
+ "liebao.cn": [
+ "duba.com",
+ "newduba.cn"
+ ],
+ "lietou-static.com": [
+ "liepin.com"
+ ],
+ "lightboxcdn.com": [
+ "cnet.com",
+ "zdnet.com",
+ "fastcompany.com"
+ ],
+ "lightinthebox.com": [
+ "informationweek.com"
+ ],
+ "lijit.com": [
+ "simpli.fi",
+ "mimecast.com",
+ "iflscience.com"
+ ],
+ "likeevideo.com": [
+ "bigolive.tv"
+ ],
+ "likr.com.tw": [
+ "chinatimes.com",
+ "newtalk.tw",
+ "businesstoday.com.tw"
+ ],
+ "line.me": [
+ "plala.or.jp",
+ "freee.co.jp",
+ "oppo.com"
+ ],
+ "linkconnector.com": [
+ "wondershare.com",
+ "lww.com",
+ "newchic.com"
+ ],
+ "linkedin.com": [
+ "adobe.com",
+ "amazon.com",
+ "msn.com"
+ ],
+ "linker.hr": [
+ "jutarnji.hr",
+ "dnevnik.hr"
+ ],
+ "linkonlineworld.com": [
+ "yallakora.com",
+ "masrawy.com"
+ ],
+ "linkprice.com": [
+ "helpstart.co.kr"
+ ],
+ "linksynergy.com": [
+ "rakuten.co.jp",
+ "alibabacloud.com",
+ "udemy.com"
+ ],
+ "list-manage.com": [
+ "woocommerce.com",
+ "nme.com",
+ "lapatilla.com"
+ ],
+ "listrakbi.com": [
+ "denverpost.com",
+ "almanac.com",
+ "budsgunshop.com"
+ ],
+ "literatumonline.com": [
+ "thelancet.com",
+ "cell.com"
+ ],
+ "liuzhuni.com": [
+ "huim.com"
+ ],
+ "live2support.com": [
+ "proprofs.com",
+ "qualaroo.com"
+ ],
+ "livechatinc.com": [
+ "wpengine.com",
+ "ning.com",
+ "livechat.com",
+ "moo.com"
+ ],
+ "livejasmin.com": [
+ "spankbang.com"
+ ],
+ "liveperson.net": [
+ "godaddy.com",
+ "virginmedia.com",
+ "microsoft.com"
+ ],
+ "livetex.me": [
+ "cntd.ru"
+ ],
+ "livetex.ru": [
+ "timeweb.com",
+ "cntd.ru"
+ ],
+ "lkqd.net": [
+ "youm7.com",
+ "gizmodo.com",
+ "memurlar.net"
+ ],
+ "lmiutil.com": [
+ "lastpass.com",
+ "logmein.com"
+ ],
+ "lndata.com": [
+ "thenewslens.com"
+ ],
+ "loadercdn.net": [
+ "ukr.net",
+ "gismeteo.ua",
+ "sinoptik.ua"
+ ],
+ "loc.gov": [
+ "wdl.org"
+ ],
+ "localytics.com": [
+ "passeidireto.com"
+ ],
+ "lockerdome.com": [
+ "psychcentral.com",
+ "astrologyanswers.com"
+ ],
+ "logger.co.kr": [
+ "dothome.co.kr"
+ ],
+ "loginfra.com": [
+ "webtoons.com",
+ "vlive.tv"
+ ],
+ "loginhood.io": [
+ "bigthink.com",
+ "iflscience.com",
+ "247wallst.com"
+ ],
+ "loginside.co.kr": [
+ "koreaherald.com"
+ ],
+ "logitech.com": [
+ "logitechg.com"
+ ],
+ "logly.co.jp": [
+ "nifty.com",
+ "excite.co.jp",
+ "diamond.jp"
+ ],
+ "logsss.com": [
+ "gearbest.com"
+ ],
+ "loop11.com": [
+ "ato.gov.au",
+ "business.gov.au"
+ ],
+ "loopassets.net": [
+ "uniqlo.com",
+ "coach.com"
+ ],
+ "loopgift.com": [
+ "uniqlo.com",
+ "coach.com",
+ "michaelkors.com"
+ ],
+ "lp4.io": [
+ "nrk.no",
+ "ilsole24ore.com",
+ "bluewin.ch"
+ ],
+ "lpage.co": [
+ "macleans.ca"
+ ],
+ "lpoint.com": [
+ "hani.co.kr"
+ ],
+ "lps.lpages.co": [
+ "leadpages.com"
+ ],
+ "lsurl.cn": [
+ "findlaw.cn"
+ ],
+ "ltwebstatic.com": [
+ "shein.com"
+ ],
+ "lwcal.com": [
+ "rice.edu"
+ ],
+ "lww.com": [
+ "ahajournals.org",
+ "neurology.org",
+ "ovid.com"
+ ],
+ "lytics.io": [
+ "adweek.com",
+ "ancestry.com",
+ "tableau.com"
+ ],
+ "lz-pub-ads.com": [
+ "cronica.com.ar"
+ ],
+ "m6r.eu": [
+ "statista.com",
+ "ceskatelevize.cz"
+ ],
+ "maases.com": [
+ "promodj.com"
+ ],
+ "macromill.com": [
+ "asahi.com",
+ "yomiuri.co.jp",
+ "hotpepper.jp"
+ ],
+ "mad-docs.azurewebsites.net": [
+ "n4g.com"
+ ],
+ "maerskline.com": [
+ "maersk.com"
+ ],
+ "magnetmail.net": [
+ "asm.org",
+ "acog.org",
+ "jbc.org"
+ ],
+ "mail.ru": [
+ "aliexpress.ru",
+ "rambler.ru",
+ "sberbank.ru",
+ "tutu.ru"
+ ],
+ "mailfire.io": [
+ "legit.ng",
+ "tuko.co.ke",
+ "briefly.co.za"
+ ],
+ "mailmunch.co": [
+ "euronews.com"
+ ],
+ "mainetodaymedia.com": [
+ "pressherald.com"
+ ],
+ "mantisadnetwork.com": [
+ "ultimate-guitar.com",
+ "tvtropes.org",
+ "ecowatch.com"
+ ],
+ "mapixl.com": [
+ "coursera.org"
+ ],
+ "mapquestapi.com": [
+ "suntrust.com"
+ ],
+ "marchex.io": [
+ "kia.com",
+ "marist.edu"
+ ],
+ "marinsm.com": [
+ "lucidchart.com",
+ "warriorplus.com",
+ "vistaprint.com"
+ ],
+ "marketdatasystems.com": [
+ "ig.com"
+ ],
+ "marketingautomation.services": [
+ "emxdigital.com"
+ ],
+ "marketlinc.com": [
+ "teamviewer.com",
+ "kaspersky.com",
+ "eset.com"
+ ],
+ "marketo.com": [
+ "appsflyer.com",
+ "verizonmedia.com",
+ "yahoo.com"
+ ],
+ "marketperf.com": [
+ "unblog.fr"
+ ],
+ "marktplaats.net": [
+ "marktplaats.nl"
+ ],
+ "massrelevance.com": [
+ "pgatour.com"
+ ],
+ "matchtv.ru": [
+ "sportbox.ru"
+ ],
+ "mateti.net": [
+ "tiscali.it",
+ "raiplay.it"
+ ],
+ "matheranalytics.com": [
+ "latimes.com",
+ "nypost.com",
+ "chicagotribune.com"
+ ],
+ "mathtag.com": [
+ "yahoo.com",
+ "msn.com",
+ "okezone.com"
+ ],
+ "matomo.cloud": [
+ "getyourguide.com",
+ "crossref.org"
+ ],
+ "maven.io": [
+ "hubpages.com",
+ "si.com",
+ "biography.com"
+ ],
+ "mavencoalition.io": [
+ "hubpages.com",
+ "si.com",
+ "biography.com"
+ ],
+ "maxmind.com": [
+ "mediafire.com"
+ ],
+ "maxymiser.net": [
+ "orange.fr",
+ "kaspersky.com",
+ "logitech.com"
+ ],
+ "mcclatchy.com": [
+ "sacbee.com",
+ "star-telegram.com",
+ "thestate.com"
+ ],
+ "mdgms.com": [
+ "bluewin.ch"
+ ],
+ "mea.gov.in": [
+ "passportindia.gov.in"
+ ],
+ "media.net": [
+ "msn.com",
+ "forbes.com",
+ "reuters.com"
+ ],
+ "media6degrees.com": [
+ "bloomberg.com",
+ "box.com",
+ "acs.org"
+ ],
+ "mediaad.org": [
+ "tejaratnews.com",
+ "parsfootball.com",
+ "rokna.net"
+ ],
+ "mediacategory.com": [
+ "joins.com",
+ "zum.com"
+ ],
+ "mediacdn.vn": [
+ "soha.vn"
+ ],
+ "mediacorp.sg": [
+ "channelnewsasia.com",
+ "todayonline.com"
+ ],
+ "mediaforge.com": [
+ "newegg.com"
+ ],
+ "mediafuse.com": [
+ "foreignaffairs.com",
+ "digitalcommerce360.com",
+ "allbusiness.com"
+ ],
+ "mediaset.net": [
+ "mediaset.it"
+ ],
+ "mediav.com": [
+ "so.com",
+ "ctrip.com",
+ "duba.com"
+ ],
+ "mediavine.com": [
+ "cnsnews.com"
+ ],
+ "mediawallahscript.com": [
+ "sourceforge.net",
+ "slashdot.org",
+ "gopro.com"
+ ],
+ "mediawayss.com": [
+ "korrespondent.net"
+ ],
+ "mediaweaver.jp": [
+ "toyokeizai.net",
+ "diamond.jp"
+ ],
+ "medium.al": [
+ "panorama.com.al",
+ "balkanweb.com",
+ "syri.net"
+ ],
+ "medium.com": [
+ "towardsdatascience.com"
+ ],
+ "medtargetsystem.com": [
+ "wired.com",
+ "mayoclinic.org",
+ "sciencedaily.com"
+ ],
+ "meiqia.com": [
+ "ywart.com",
+ "guifun.com",
+ "koolearn.com"
+ ],
+ "meizu.cn": [
+ "meizu.com"
+ ],
+ "mellowads.com": [
+ "moonbit.co.in",
+ "moonliteco.in",
+ "moondoge.co.in"
+ ],
+ "mercadopago.cl": [
+ "mercadolibre.cl"
+ ],
+ "meredithcorp.io": [
+ "people.com",
+ "southernliving.com"
+ ],
+ "metricool.com": [
+ "ancient.eu"
+ ],
+ "metroscubicos.com": [
+ "mercadolibre.com.mx"
+ ],
+ "mfadsrvr.com": [
+ "msn.com",
+ "forbes.com",
+ "thehill.com"
+ ],
+ "mgid.com": [
+ "uptodown.com",
+ "liveinternet.ru",
+ "memurlar.net"
+ ],
+ "mhtr.be": [
+ "independent.ie"
+ ],
+ "mia-chat.com": [
+ "payforessay.net",
+ "papernow.org"
+ ],
+ "miamiherald.com": [
+ "mcclatchydc.com"
+ ],
+ "miaozhen.com": [
+ "cnbeta.com",
+ "autohome.com.cn",
+ "pchouse.com.cn"
+ ],
+ "mib.gov.in": [
+ "parivahan.gov.in",
+ "up.gov.in"
+ ],
+ "micpn.com": [
+ "lenovo.com",
+ "barnesandnoble.com",
+ "nbcsports.com"
+ ],
+ "microad.jp": [
+ "rakuten.co.jp",
+ "hatena.ne.jp",
+ "tenki.jp"
+ ],
+ "microadinc.com": [
+ "lolipop.jp",
+ "syosetu.com",
+ "moppy.jp"
+ ],
+ "microcontenidos.com": [
+ "excelsior.com.mx"
+ ],
+ "microsoft.com": [
+ "quizizz.com",
+ "minecraft.net",
+ "flipgrid.com"
+ ],
+ "microsofttranslator.com": [
+ "iyiou.com"
+ ],
+ "midas-network.com": [
+ "b92.net"
+ ],
+ "mimilcnf.pro": [
+ "hdsex.org"
+ ],
+ "mindbox.cloud": [
+ "semrush.com"
+ ],
+ "mindbox.ru": [
+ "citilink.ru",
+ "cosmo.ru",
+ "vseinstrumenti.ru"
+ ],
+ "minibc.com": [
+ "euroluxhome.com"
+ ],
+ "miniclip.com": [
+ "agar.io"
+ ],
+ "miniclippt.com": [
+ "agar.io"
+ ],
+ "miniinthebox.com": [
+ "informationweek.com"
+ ],
+ "mirror.co.uk": [
+ "dailystar.co.uk",
+ "manchestereveningnews.co.uk",
+ "dailyrecord.co.uk"
+ ],
+ "mituo.cn": [
+ "metinfo.cn"
+ ],
+ "mixcloud.com": [
+ "b92.net"
+ ],
+ "mixi.media": [
+ "realclearpolitics.com",
+ "newsmax.com",
+ "valuewalk.com"
+ ],
+ "mktoresp.com": [
+ "taboola.com",
+ "mimecast.com",
+ "topuniversities.com"
+ ],
+ "ml314.com": [
+ "cnn.com",
+ "forbes.com",
+ "sourceforge.net"
+ ],
+ "mlsys.xyz": [
+ "inquisitr.com"
+ ],
+ "mmonline.io": [
+ "manoramaonline.com"
+ ],
+ "mmstat.com": [
+ "sohu.com",
+ "sina.com.cn",
+ "huanqiu.com"
+ ],
+ "mmtro.com": [
+ "lacoste.com"
+ ],
+ "moatads.com": [
+ "forbes.com",
+ "bloomberg.com",
+ "cnet.com"
+ ],
+ "mobizone.mobi": [
+ "almasryalyoum.com"
+ ],
+ "mobvista.com": [
+ "rayjump.com"
+ ],
+ "modlily.com": [
+ "informationweek.com"
+ ],
+ "moe.video": [
+ "yaplakal.com"
+ ],
+ "moevideo.biz": [
+ "yaplakal.com"
+ ],
+ "monetate.net": [
+ "nationalgeographic.com",
+ "marriott.com",
+ "newegg.com"
+ ],
+ "monohost.com": [
+ "pdf2doc.com",
+ "compressjpeg.com",
+ "jpg2pdf.com"
+ ],
+ "monsido.com": [
+ "uga.edu",
+ "utk.edu",
+ "nature.org"
+ ],
+ "mookie1.com": [
+ "newsweek.com",
+ "howstuffworks.com",
+ "in.gr"
+ ],
+ "moovit.com": [
+ "undip.ac.id"
+ ],
+ "mopinion.com": [
+ "tomtom.com",
+ "sncf.com"
+ ],
+ "motorsport.com": [
+ "motor1.com"
+ ],
+ "mox.tv": [
+ "filgoal.com"
+ ],
+ "moxielinks.com": [
+ "banggood.com"
+ ],
+ "mpeasylink.com": [
+ "t-mobile.com",
+ "ford.com",
+ "cox.com"
+ ],
+ "mpianalytics.com": [
+ "subito.it",
+ "milanuncios.com",
+ "willhaben.at"
+ ],
+ "mpio.io": [
+ "art.com"
+ ],
+ "mpshark.com": [
+ "9anime.to"
+ ],
+ "mrelko.com": [
+ "rutor.info"
+ ],
+ "mrpfd.com": [
+ "citrix.com"
+ ],
+ "mrtnsvr.com": [
+ "thebodyshop.com"
+ ],
+ "msgapp.com": [
+ "post-gazette.com"
+ ],
+ "msn.com": [
+ "wsj.com",
+ "ninemsn.com.au"
+ ],
+ "mtgroup.kr": [
+ "mt.co.kr"
+ ],
+ "mtmo.cc": [
+ "flvto.biz",
+ "2conv.com"
+ ],
+ "mts.ru": [
+ "aliexpress.ru",
+ "rambler.ru",
+ "lenta.ru"
+ ],
+ "mtvnservices.com": [
+ "nick.com",
+ "bet.com",
+ "cc.com"
+ ],
+ "muji.net": [
+ "muji.com"
+ ],
+ "mulesoft.com": [
+ "programmableweb.com"
+ ],
+ "musthird.com": [
+ "airbnb.com",
+ "airbnb.co.uk",
+ "airbnb.ca"
+ ],
+ "mxapis.com": [
+ "localbitcoins.com"
+ ],
+ "mxplay.com": [
+ "mxplayer.in"
+ ],
+ "myfinance.com": [
+ "moneycrashers.com"
+ ],
+ "mykhel.com": [
+ "oneindia.com"
+ ],
+ "myopenads.com": [
+ "channelmyanmar.org"
+ ],
+ "myshopify.com": [
+ "eero.com",
+ "iqair.com"
+ ],
+ "myvisualiq.net": [
+ "amazon.com",
+ "samsung.com",
+ "walmart.com"
+ ],
+ "myvoicenation.com": [
+ "miaminewtimes.com",
+ "westword.com"
+ ],
+ "n1272serv.xyz": [
+ "youporn.com"
+ ],
+ "n2.hk": [
+ "discuss.com.hk"
+ ],
+ "nakamasweb.com": [
+ "lectortmo.com"
+ ],
+ "nakanohito.jp": [
+ "backlog.com",
+ "freee.co.jp",
+ "diamond.jp"
+ ],
+ "namebrightstatic.com": [
+ "namebright.com"
+ ],
+ "nanda.vn": [
+ "zingnews.vn",
+ "laodong.vn",
+ "vtv.vn"
+ ],
+ "nanigans.com": [
+ "llbean.com",
+ "snhu.edu"
+ ],
+ "nanorep.co": [
+ "icicibank.com",
+ "lastpass.com",
+ "nordvpn.com"
+ ],
+ "nanosemantics.ru": [
+ "hh.ru"
+ ],
+ "narrative.io": [
+ "bigthink.com",
+ "iflscience.com",
+ "247wallst.com"
+ ],
+ "nativendo.de": [
+ "freenet.de",
+ "giga.de",
+ "morgenpost.de"
+ ],
+ "nativeroll.tv": [
+ "yaplakal.com",
+ "adme.ru",
+ "brightside.me"
+ ],
+ "navdmp.com": [
+ "magazineluiza.com.br",
+ "techtudo.com.br",
+ "thenewslens.com"
+ ],
+ "naver.com": [
+ "op.gg",
+ "unity.com",
+ "flaticon.com"
+ ],
+ "nbc.com": [
+ "bravotv.com"
+ ],
+ "nbcuni.com": [
+ "cnbc.com",
+ "nbcnews.com",
+ "today.com"
+ ],
+ "nc0.co": [
+ "ensighten.com",
+ "williamhill.com"
+ ],
+ "nch.com.au": [
+ "nchsoftware.com"
+ ],
+ "neodatagroup.com": [
+ "ilfattoquotidiano.it"
+ ],
+ "neppa-dsp-ad.com": [
+ "cityheaven.net"
+ ],
+ "netdna-ssl.com": [
+ "dazeddigital.com"
+ ],
+ "netmng.com": [
+ "lowes.com",
+ "mimecast.com",
+ "geotrust.com"
+ ],
+ "netrk.net": [
+ "dkb.de"
+ ],
+ "networkad.net": [
+ "eksisozluk.com"
+ ],
+ "newaircloud.com": [
+ "workercn.cn"
+ ],
+ "newmedia.az": [
+ "oxu.az",
+ "qafqazinfo.az",
+ "report.az"
+ ],
+ "newrelic.com": [
+ "afternic.com"
+ ],
+ "news-network.ru": [
+ "vazhno.ru"
+ ],
+ "news.cn": [
+ "xinhuanet.com"
+ ],
+ "newscgp.com": [
+ "marketwatch.com",
+ "nypost.com",
+ "thesun.co.uk"
+ ],
+ "newshub.id": [
+ "liputan6.com"
+ ],
+ "newsmaxwidget.com": [
+ "thehill.com",
+ "newsmax.com"
+ ],
+ "newsmemory.com": [
+ "abqjournal.com"
+ ],
+ "newsobserver.com": [
+ "mcclatchydc.com"
+ ],
+ "newyorker.com": [
+ "wired.com",
+ "vanityfair.com",
+ "vogue.com"
+ ],
+ "newzit.com": [
+ "dailymail.co.uk",
+ "metro.co.uk"
+ ],
+ "nextclick.pl": [
+ "joemonster.org"
+ ],
+ "nextelection.app": [
+ "scoop.co.nz"
+ ],
+ "ngpvan.com": [
+ "ewg.org",
+ "ucsusa.org",
+ "audubon.org"
+ ],
+ "ngs.ru": [
+ "fontanka.ru"
+ ],
+ "nicequest.com": [
+ "cadenaser.com"
+ ],
+ "nikon-cdn.com": [
+ "nikonusa.com"
+ ],
+ "nikonsso.com": [
+ "nikonusa.com"
+ ],
+ "nimbleswan.io": [
+ "sharethis.com",
+ "skimlinks.com"
+ ],
+ "ninahale.net": [
+ "uhc.com"
+ ],
+ "nine.com.au": [
+ "smh.com.au",
+ "theage.com.au",
+ "businessinsider.com.au"
+ ],
+ "njih.net": [
+ "adidas.com"
+ ],
+ "norstatsurveys.com": [
+ "vg.no"
+ ],
+ "norton.com": [
+ "informationweek.com"
+ ],
+ "nosto.com": [
+ "gymshark.com",
+ "fashionnova.com",
+ "jomashop.com"
+ ],
+ "notifyvisitors.com": [
+ "axisbank.com",
+ "1mg.com"
+ ],
+ "noxgroup.com": [
+ "bignox.com"
+ ],
+ "nperf.com": [
+ "ovh.net"
+ ],
+ "npo.nl": [
+ "nos.nl"
+ ],
+ "npohosting.nl": [
+ "nos.nl"
+ ],
+ "nr-data.net": [
+ "chaturbate.com",
+ "instructure.com",
+ "sciencedirect.com"
+ ],
+ "nsaudience.pl": [
+ "interia.pl"
+ ],
+ "ntnu.edu": [
+ "ntnu.no"
+ ],
+ "ntvk1.ru": [
+ "aif.ru"
+ ],
+ "nuggad.net": [
+ "iefimerida.gr"
+ ],
+ "nxtck.com": [
+ "newegg.com"
+ ],
+ "o-s.io": [
+ "souq.com",
+ "daraz.pk"
+ ],
+ "o333o.com": [
+ "hdsex.org"
+ ],
+ "oadz.com": [
+ "qiku.com"
+ ],
+ "ocdn.eu": [
+ "onet.pl",
+ "blic.rs"
+ ],
+ "octclck.xyz": [
+ "radikal.ru"
+ ],
+ "octivid.com": [
+ "alaraby.co.uk"
+ ],
+ "oddcast.com": [
+ "washingtonsharedparenting.com"
+ ],
+ "odoocdn.com": [
+ "odoo.com"
+ ],
+ "offlinx.com": [
+ "indigo.ca"
+ ],
+ "ojrq.net": [
+ "shutterstock.com",
+ "lenovo.com",
+ "hostgator.com"
+ ],
+ "ok.ru": [
+ "narod.ru",
+ "iz.ru",
+ "labirint.ru"
+ ],
+ "okccdn.com": [
+ "okcupid.com"
+ ],
+ "okezone.com": [
+ "sindonews.com"
+ ],
+ "okt.to": [
+ "globalsign.com",
+ "cvent.com",
+ "anu.edu.au"
+ ],
+ "okta.com": [
+ "servicenow.com",
+ "bcg.com",
+ "mgmresorts.com"
+ ],
+ "olark.com": [
+ "matterport.com",
+ "microsoft.com",
+ "cloudinary.com"
+ ],
+ "olnl.net": [
+ "kino-teatr.ru"
+ ],
+ "olx-st.com": [
+ "olx.pl",
+ "olx.ua",
+ "olx.in"
+ ],
+ "omchanseyr.com": [
+ "4anime.to"
+ ],
+ "omgpm.com": [
+ "gradeup.co"
+ ],
+ "omguk.com": [
+ "banggood.com",
+ "newchic.com"
+ ],
+ "omniscientai.com": [
+ "edh.tw"
+ ],
+ "omnitagjs.com": [
+ "imgur.com",
+ "dailymail.co.uk",
+ "salon.com"
+ ],
+ "omny.fm": [
+ "foxnews.com",
+ "haaretz.com",
+ "geekwire.com"
+ ],
+ "omtrdc.net": [
+ "amazon.com",
+ "virginmedia.com",
+ "digicert.com"
+ ],
+ "onaudience.com": [
+ "khaberni.com",
+ "alwakeelnews.com"
+ ],
+ "oncueapp.appspot.com": [
+ "pewtrusts.org"
+ ],
+ "one.gov.hk": [
+ "www.gov.hk"
+ ],
+ "onecms.io": [
+ "eatingwell.com"
+ ],
+ "onecount.net": [
+ "newrepublic.com",
+ "triblive.com"
+ ],
+ "oneindia.com": [
+ "filmibeat.com",
+ "goodreturns.in"
+ ],
+ "onelink.me": [
+ "appsflyer.com",
+ "farfetch.com"
+ ],
+ "onesignal.com": [
+ "elconfidencial.com"
+ ],
+ "onet.pl": [
+ "blic.rs"
+ ],
+ "onevision.com.tw": [
+ "ltn.com.tw",
+ "chinatimes.com",
+ "hinet.net"
+ ],
+ "online-metrix.net": [
+ "fidelity.com",
+ "citi.com",
+ "discover.com"
+ ],
+ "onlyred.net": [
+ "rednet.cn"
+ ],
+ "onrcx.com": [
+ "intel.com"
+ ],
+ "onsugar.com": [
+ "popsugar.com"
+ ],
+ "onthe.io": [
+ "inquirer.net",
+ "express.co.uk",
+ "rbc.ru"
+ ],
+ "ooyala.com": [
+ "dalet.com"
+ ],
+ "opecloud.com": [
+ "businessinsider.de",
+ "sabq.org",
+ "kooora.com"
+ ],
+ "open.com.cn": [
+ "imooc.com"
+ ],
+ "openstat.net": [
+ "aif.ru"
+ ],
+ "openx.net": [
+ "yahoo.com",
+ "amazon.com",
+ "msn.com"
+ ],
+ "opinionstage.com": [
+ "nobelprize.org"
+ ],
+ "optaim.com": [
+ "sohu.com"
+ ],
+ "optimahub.com": [
+ "aaa.com"
+ ],
+ "optimix.cn": [
+ "bshare.cn",
+ "foodmate.net",
+ "xhby.net"
+ ],
+ "optimizely.com": [
+ "bbc.com",
+ "bitly.com",
+ "xbox.com"
+ ],
+ "optimove.events": [
+ "jdsports.com"
+ ],
+ "oracle.com": [
+ "addthis.com",
+ "moat.com",
+ "dyn.com"
+ ],
+ "oraclecloud.com": [
+ "nationalacademies.org"
+ ],
+ "oracleimg.com": [
+ "oracle.com",
+ "moat.com",
+ "dyn.com"
+ ],
+ "orange-business.com": [
+ "orange.com"
+ ],
+ "orangeads.fr": [
+ "orange.fr"
+ ],
+ "orbita.cloud": [
+ "redcrossblood.org"
+ ],
+ "oreillystatic.com": [
+ "oreilly.com"
+ ],
+ "osano.com": [
+ "ocregister.com",
+ "figma.com",
+ "dailynews.com"
+ ],
+ "otaserve.net": [
+ "sankakucomplex.com"
+ ],
+ "otm-r.com": [
+ "liveinternet.ru",
+ "kp.ru",
+ "rg.ru"
+ ],
+ "outbrain.com": [
+ "msn.com",
+ "cnn.com",
+ "sourceforge.net"
+ ],
+ "outlookhindi.com": [
+ "outlookindia.com"
+ ],
+ "outstream.today": [
+ "academic.ru"
+ ],
+ "ow5a.net": [
+ "norton.com"
+ ],
+ "owneriq.net": [
+ "lycos.com",
+ "msi.com",
+ "scholastic.com"
+ ],
+ "ownpage.fr": [
+ "20minutes.fr"
+ ],
+ "paddle.com": [
+ "snapwidget.com"
+ ],
+ "padletcdn.com": [
+ "padlet.com"
+ ],
+ "pages02.net": [
+ "prestashop.com",
+ "bbt.com"
+ ],
+ "pages03.net": [
+ "smithsonianmag.com",
+ "turkishairlines.com",
+ "marketingprofs.com"
+ ],
+ "pages04.net": [
+ "scientificamerican.com",
+ "techsmith.com"
+ ],
+ "pages06.net": [
+ "ibtimes.co.uk"
+ ],
+ "pages07.net": [
+ "asahi.com"
+ ],
+ "pages08.net": [
+ "military.com"
+ ],
+ "panet.eu": [
+ "panet.co.il"
+ ],
+ "pardot.com": [
+ "cpanel.net",
+ "slack.com",
+ "tandfonline.com"
+ ],
+ "parsely.com": [
+ "bloomberg.com",
+ "usatoday.com",
+ "cnbc.com"
+ ],
+ "parsons.edu": [
+ "newschool.edu"
+ ],
+ "particularaudience.com": [
+ "jbhifi.com.au"
+ ],
+ "patreon.com": [
+ "warcraftlogs.com"
+ ],
+ "paxful.com": [
+ "informationweek.com"
+ ],
+ "paycom.com": [
+ "paycomonline.com"
+ ],
+ "paypal.com": [
+ "mercari.com",
+ "smashballoon.com",
+ "doxygen.nl"
+ ],
+ "pb.ua": [
+ "privat24.ua"
+ ],
+ "pbbl.co": [
+ "hilton.com",
+ "chron.com",
+ "fool.com"
+ ],
+ "pbstck.com": [
+ "ldoceonline.com"
+ ],
+ "pc.com.cn": [
+ "pcauto.com.cn"
+ ],
+ "pcmag.com": [
+ "techspot.com",
+ "slashgear.com",
+ "betanews.com"
+ ],
+ "pconline.com.cn": [
+ "pcbaby.com.cn",
+ "pchouse.com.cn",
+ "pcauto.com.cn"
+ ],
+ "pdvacde.com": [
+ "rezka.ag",
+ "baskino.me"
+ ],
+ "pelcro.com": [
+ "insidehighered.com",
+ "miaminewtimes.com"
+ ],
+ "pelmorex.com": [
+ "theweathernetwork.com"
+ ],
+ "pendo.io": [
+ "sciencedirect.com",
+ "thelancet.com",
+ "cell.com"
+ ],
+ "people.com.cn": [
+ "people.cn",
+ "peopledaily.com.cn"
+ ],
+ "percycle.com": [
+ "magazineluiza.com.br"
+ ],
+ "performancefirst.jp": [
+ "moppy.jp"
+ ],
+ "performi.com": [
+ "fitsmallbusiness.com"
+ ],
+ "permutive.app": [
+ "theverge.com",
+ "vox.com",
+ "nymag.com"
+ ],
+ "petametrics.com": [
+ "telegraph.co.uk",
+ "scmp.com",
+ "thestar.com"
+ ],
+ "pgtb.me": [
+ "hawaiinewsnow.com"
+ ],
+ "philips.co.uk": [
+ "philips.com"
+ ],
+ "philips.com": [
+ "philips-hue.com"
+ ],
+ "photorank.me": [
+ "vistaprint.com",
+ "jdsports.com",
+ "coach.com"
+ ],
+ "piano.io": [
+ "japantimes.co.jp",
+ "canberratimes.com.au"
+ ],
+ "pinduoduo.com": [
+ "yangkeduo.com"
+ ],
+ "pingan.com": [
+ "autohome.com.cn"
+ ],
+ "pinterest.com": [
+ "godaddy.com",
+ "spotify.com",
+ "etsy.com"
+ ],
+ "piri.net": [
+ "yenisafak.com"
+ ],
+ "pitchfork.com": [
+ "wired.com",
+ "newyorker.com",
+ "vanityfair.com"
+ ],
+ "piwik.pro": [
+ "aarp.org",
+ "xs4all.nl",
+ "simplesite.com"
+ ],
+ "pixlee.co": [
+ "puma.com",
+ "michaels.com"
+ ],
+ "pixlee.com": [
+ "puma.com",
+ "michaels.com",
+ "forever21.com"
+ ],
+ "pixnet.cc": [
+ "pixnet.net"
+ ],
+ "placed.com": [
+ "simon.com"
+ ],
+ "planalto.gov.br": [
+ "www.gov.br"
+ ],
+ "playbuzz.com": [
+ "perezhilton.com"
+ ],
+ "playreplay.me": [
+ "yaplakal.com"
+ ],
+ "playreplay.net": [
+ "yaplakal.com"
+ ],
+ "plezi.co": [
+ "we-are-adot.com"
+ ],
+ "plista.com": [
+ "freenet.de",
+ "9news.com.au",
+ "nine.com.au"
+ ],
+ "poemsdeucewee.com": [
+ "kickasstorrents.to"
+ ],
+ "pointmediatracker.com": [
+ "udemy.com",
+ "nerdwallet.com",
+ "squareup.com"
+ ],
+ "polarbyte.com": [
+ "collinsdictionary.com"
+ ],
+ "poll-maker.com": [
+ "eztv.io"
+ ],
+ "poll.fm": [
+ "crowdsignal.com"
+ ],
+ "poool.fr": [
+ "ladepeche.fr",
+ "sudouest.fr"
+ ],
+ "popin.cc": [
+ "idntimes.com",
+ "itmedia.co.jp",
+ "edh.tw"
+ ],
+ "popt.in": [
+ "poynter.org",
+ "alphonso.tv"
+ ],
+ "port.hu": [
+ "index.hu"
+ ],
+ "portalinmobiliario.com": [
+ "mercadolibre.cl"
+ ],
+ "postaffiliatepro.com": [
+ "pandasecurity.com",
+ "solarwinds.com"
+ ],
+ "postrelease.com": [
+ "reuters.com",
+ "usnews.com",
+ "sfgate.com"
+ ],
+ "powerlinks.com": [
+ "msn.com",
+ "digicert.com",
+ "imgur.com"
+ ],
+ "powerreviews.com": [
+ "citi.com"
+ ],
+ "pplive.com": [
+ "pptv.com"
+ ],
+ "prcdn.co": [
+ "nationalpost.com",
+ "pressreader.com",
+ "vancouversun.com"
+ ],
+ "prensaiberica.es": [
+ "sport.es",
+ "elperiodico.com"
+ ],
+ "prfct.co": [
+ "theglobeandmail.com",
+ "lifehack.org",
+ "artnet.com"
+ ],
+ "priceline.com": [
+ "informationweek.com"
+ ],
+ "primead.jp": [
+ "allabout.co.jp"
+ ],
+ "primecaster.net": [
+ "tenki.jp",
+ "infoseek.co.jp"
+ ],
+ "printful.com": [
+ "informationweek.com"
+ ],
+ "prisasd.com": [
+ "elpais.com"
+ ],
+ "prismamedia.com": [
+ "programme-tv.net"
+ ],
+ "privacymanager.io": [
+ "theodysseyonline.com",
+ "diepresse.com"
+ ],
+ "privally.io": [
+ "colaboraread.com.br"
+ ],
+ "privymktg.com": [
+ "myfonts.com",
+ "arabnews.com",
+ "macleans.ca"
+ ],
+ "prixa.net": [
+ "ratopati.com"
+ ],
+ "prixacdn.net": [
+ "ratopati.com"
+ ],
+ "prlog.org": [
+ "markethive.com"
+ ],
+ "pro-market.net": [
+ "sourceforge.net",
+ "time.com",
+ "slashdot.org"
+ ],
+ "prod-ajc-proxy-connext.azurewebsites.net": [
+ "ajc.com",
+ "daytondailynews.com"
+ ],
+ "prod-anchorage-proxy-connext.azurewebsites.net": [
+ "adn.com"
+ ],
+ "prod-cosprings-proxy-connext.azurewebsites.net": [
+ "gazette.com"
+ ],
+ "prod-dfm-proxy-connext.azurewebsites.net": [
+ "mercurynews.com",
+ "denverpost.com"
+ ],
+ "prod-mng-proxy-connext.azurewebsites.net": [
+ "ocregister.com",
+ "bostonherald.com",
+ "twincities.com"
+ ],
+ "prod-newsday-proxy-connext.azurewebsites.net": [
+ "newsday.com"
+ ],
+ "prod-review-journal-proxy-connext.azurewebsites.net": [
+ "reviewjournal.com"
+ ],
+ "prod-smi-proxy-connext.azurewebsites.net": [
+ "pressdemocrat.com"
+ ],
+ "prod-spokesman-proxy-connext.azurewebsites.net": [
+ "spokesman.com"
+ ],
+ "prod-tampabay-proxy-connext.azurewebsites.net": [
+ "tampabay.com"
+ ],
+ "producebreed.com": [
+ "1377x.to"
+ ],
+ "programattik.com": [
+ "hurriyet.com.tr",
+ "milliyet.com.tr",
+ "memurlar.net"
+ ],
+ "project1service.com": [
+ "brazzers.com"
+ ],
+ "prometeo-media-service.com": [
+ "20minutos.es"
+ ],
+ "proofpoint.com": [
+ "gulfnews.com",
+ "unh.edu",
+ "weightwatchers.com"
+ ],
+ "prosumsit.com": [
+ "songatak.com"
+ ],
+ "provenexpert.com": [
+ "wbs-law.de"
+ ],
+ "provenpixel.com": [
+ "shopify.com"
+ ],
+ "proxad.net": [
+ "free.fr"
+ ],
+ "psakdin.co.il": [
+ "mako.co.il"
+ ],
+ "pswec.com": [
+ "medscape.com"
+ ],
+ "ptgncdn.com": [
+ "spankbang.com"
+ ],
+ "pub.network": [
+ "aljazeera.com",
+ "boingboing.net",
+ "realclearpolitics.com"
+ ],
+ "pubble.io": [
+ "teamwork.com"
+ ],
+ "publicradio.org": [
+ "marketplace.org"
+ ],
+ "publir.com": [
+ "bizpacreview.com"
+ ],
+ "publishme.se": [
+ "blogg.se"
+ ],
+ "pubmatic.com": [
+ "amazon.com",
+ "okezone.com",
+ "forbes.com"
+ ],
+ "pubstack.io": [
+ "laposte.fr",
+ "ccm.net",
+ "ldoceonline.com"
+ ],
+ "pulsembed.eu": [
+ "blic.rs"
+ ],
+ "purechat.com": [
+ "wwd.com"
+ ],
+ "push.world": [
+ "banggood.com"
+ ],
+ "pushbird.com": [
+ "sammobile.com"
+ ],
+ "pushe.co": [
+ "digiato.com",
+ "mediaad.org"
+ ],
+ "pushnami.com": [
+ "ibtimes.com",
+ "metacafe.com",
+ "alternet.org"
+ ],
+ "pvxt.net": [
+ "stockx.com"
+ ],
+ "px-cloud.net": [
+ "homedepot.com"
+ ],
+ "pxf.io": [
+ "fanduel.com"
+ ],
+ "pymx5.com": [
+ "thedenverchannel.com",
+ "spokesman.com",
+ "abc15.com"
+ ],
+ "qchannel03.cn": [
+ "ximalaya.com"
+ ],
+ "qhupdate.com": [
+ "so.com",
+ "360kuai.com"
+ ],
+ "qiyukf.com": [
+ "to8to.com",
+ "smzdm.com"
+ ],
+ "qlitics.com": [
+ "prothomalo.com",
+ "bloombergquint.com"
+ ],
+ "qoo10.in": [
+ "shopclues.com"
+ ],
+ "qq.com": [
+ "heytapmobi.com",
+ "douyu.com",
+ "heytapdownload.com"
+ ],
+ "qqjar.ru": [
+ "manganelo.com",
+ "gogoanime.so"
+ ],
+ "qs.com": [
+ "topuniversities.com"
+ ],
+ "qsstats.com": [
+ "webopedia.com",
+ "eweek.com"
+ ],
+ "qualtrics.com": [
+ "realtor.com",
+ "autodesk.com",
+ "unity.com"
+ ],
+ "quantad.io": [
+ "gmarket.co.kr",
+ "auction.co.kr"
+ ],
+ "quantserve.com": [
+ "reddit.com",
+ "msn.com",
+ "okezone.com"
+ ],
+ "quantumdex.io": [
+ "legit.ng",
+ "tuko.co.ke",
+ "briefly.co.za"
+ ],
+ "quantummetric.com": [
+ "homedepot.com",
+ "att.com",
+ "xfinity.com"
+ ],
+ "queryly.com": [
+ "postandcourier.com"
+ ],
+ "questionpro.com": [
+ "mta.info"
+ ],
+ "queue-it.net": [
+ "bestbuy.ca",
+ "swarovski.com",
+ "next.co.uk",
+ "kmart.com.au",
+ "doterra.com"
+ ],
+ "quickkoala.io": [
+ "viglink.com",
+ "1stdibs.com"
+ ],
+ "quiq-api.com": [
+ "westelm.com"
+ ],
+ "quitzon.net": [
+ "filmix.co"
+ ],
+ "quora.com": [
+ "bloomberg.com",
+ "latimes.com",
+ "shopify.com"
+ ],
+ "qy.net": [
+ "iqiyi.com"
+ ],
+ "r-ad.ne.jp": [
+ "hotpepper.jp",
+ "jalan.net",
+ "suumo.jp"
+ ],
+ "radissonhotels.com": [
+ "radissonblu.com"
+ ],
+ "rainbowred.com": [
+ "realme.com"
+ ],
+ "rakuten.co.jp": [
+ "rakuten.com",
+ "rakuten-sec.co.jp",
+ "rakuten-card.co.jp"
+ ],
+ "rakuten.com": [
+ "hilton.com",
+ "newegg.com",
+ "teespring.com"
+ ],
+ "rambler.ru": [
+ "livejournal.com",
+ "lenta.ru",
+ "gazeta.ru"
+ ],
+ "randomhouse.com": [
+ "penguinrandomhouse.com"
+ ],
+ "rating-widget.com": [
+ "bilasport.net"
+ ],
+ "raxcdn.com": [
+ "japantoday.com"
+ ],
+ "raycommedia.com": [
+ "hawaiinewsnow.com"
+ ],
+ "razorpay.com": [
+ "bloombergquint.com"
+ ],
+ "rcapiuseridexchange.azurewebsites.net": [
+ "radio-canada.ca"
+ ],
+ "rcrsv.io": [
+ "tdameritrade.com"
+ ],
+ "rcs.it": [
+ "corriere.it"
+ ],
+ "rcsmetrics.it": [
+ "corriere.it",
+ "gazzetta.it"
+ ],
+ "rctiplus.com": [
+ "okezone.com",
+ "inews.id"
+ ],
+ "rdcdn.com": [
+ "weightwatchers.com"
+ ],
+ "reachmax.cn": [
+ "bshare.cn",
+ "foodmate.net",
+ "xhby.net"
+ ],
+ "reactful.com": [
+ "brightcove.com",
+ "zscaler.com"
+ ],
+ "realclick.co.kr": [
+ "hani.co.kr"
+ ],
+ "realite.id": [
+ "brilio.net",
+ "bola.net",
+ "dream.co.id"
+ ],
+ "realsrv.com": [
+ "spankbang.com",
+ "manganelo.com",
+ "eporner.com"
+ ],
+ "realtime.email": [
+ "autismspeaks.org"
+ ],
+ "rec-engine.com": [
+ "paychex.com"
+ ],
+ "recobell.io": [
+ "hani.co.kr"
+ ],
+ "recommendationengine.googleapis.com": [
+ "newsweek.com",
+ "g2a.com",
+ "saatchiart.com"
+ ],
+ "recreativ.ru": [
+ "ukr.net",
+ "meta.ua"
+ ],
+ "recruitics.com": [
+ "governmentjobs.com"
+ ],
+ "redbubble.com": [
+ "informationweek.com"
+ ],
+ "redcross.org": [
+ "redcrossblood.org"
+ ],
+ "reddit.com": [
+ "godaddy.com",
+ "spotify.com",
+ "bloomberg.com",
+ "hudl.com"
+ ],
+ "redhat.com": [
+ "opensource.com"
+ ],
+ "redintelligence.net": [
+ "swarovski.com"
+ ],
+ "redlink.com": [
+ "ahajournals.org",
+ "annualreviews.org"
+ ],
+ "refocus.ru": [
+ "eldorado.ru"
+ ],
+ "regroup.com": [
+ "csus.edu"
+ ],
+ "reichelcormier.bid": [
+ "filmix.co",
+ "rezka.ag",
+ "baskino.me"
+ ],
+ "relap.io": [
+ "mail.ru",
+ "ria.ru",
+ "tass.ru"
+ ],
+ "relateddigital.com": [
+ "ntv.com.tr",
+ "kariyer.net"
+ ],
+ "remarqable.com": [
+ "ahajournals.org"
+ ],
+ "rentracks.jp": [
+ "techacademy.jp",
+ "lolipop.jp",
+ "ocnk.net"
+ ],
+ "republer.com": [
+ "khaberni.com",
+ "alwakeelnews.com",
+ "aif.ru"
+ ],
+ "research-int.se": [
+ "aftonbladet.se",
+ "svt.se",
+ "expressen.se"
+ ],
+ "researchintel.com": [
+ "intel.com"
+ ],
+ "researchnow.com": [
+ "go.com",
+ "disney.com",
+ "starwars.com"
+ ],
+ "resniks.pro": [
+ "sexu.com"
+ ],
+ "reson8.com": [
+ "nydailynews.com",
+ "startribune.com",
+ "baltimoresun.com"
+ ],
+ "retailrocket.net": [
+ "eldorado.ru",
+ "dns-shop.ru",
+ "vseinstrumenti.ru"
+ ],
+ "retargetly.com": [
+ "perfil.com",
+ "excelsior.com.mx",
+ "ambito.com"
+ ],
+ "retentioneering.com": [
+ "eldorado.ru"
+ ],
+ "revcontent.com": [
+ "thegatewaypundit.com",
+ "tampabay.com",
+ "nationalreview.com"
+ ],
+ "reverb-assets.com": [
+ "reverb.com"
+ ],
+ "revive-adserver.net": [
+ "indiebound.org",
+ "defimedia.info"
+ ],
+ "revjet.com": [
+ "businessinsider.com",
+ "homedepot.com",
+ "yahoo.com"
+ ],
+ "rezync.com": [
+ "williams-sonoma.com",
+ "spectrum.com",
+ "potterybarn.com"
+ ],
+ "rferl.org": [
+ "svoboda.org"
+ ],
+ "rfihub.com": [
+ "usatoday.com",
+ "dailymotion.com",
+ "youm7.com"
+ ],
+ "rfksrv.com": [
+ "ulta.com",
+ "bloomingdales.com",
+ "tommy.com"
+ ],
+ "rfvk.net": [
+ "adorama.com"
+ ],
+ "ria.ru": [
+ "sputniknews.com",
+ "rian.ru",
+ "inosmi.ru"
+ ],
+ "richaudience.com": [
+ "softonic.com",
+ "marca.com",
+ "las2orillas.co"
+ ],
+ "richrelevance.com": [
+ "rei.com",
+ "saksfifthavenue.com",
+ "williams-sonoma.com"
+ ],
+ "rightinthebox.com": [
+ "lightinthebox.com"
+ ],
+ "rightmessage.com": [
+ "problogger.com"
+ ],
+ "rightnowtech.com": [
+ "lenovo.com"
+ ],
+ "rijksoverheid.nl": [
+ "rivm.nl"
+ ],
+ "riotgames.com": [
+ "op.gg",
+ "u.gg",
+ "mobalytics.gg"
+ ],
+ "riskified.com": [
+ "wayfair.com",
+ "zara.com",
+ "farfetch.com"
+ ],
+ "riverhit.com": [
+ "xozilla.com",
+ "sexu.com",
+ "hdsex.org"
+ ],
+ "rkdms.com": [
+ "cnn.com",
+ "washingtonpost.com",
+ "wsj.com"
+ ],
+ "rktch.com": [
+ "aif.ru",
+ "vfsglobal.com"
+ ],
+ "rlcdn.com": [
+ "godaddy.com",
+ "digicert.com",
+ "tandfonline.com"
+ ],
+ "rmtag.com": [
+ "udemy.com",
+ "coursera.org",
+ "hulu.com"
+ ],
+ "rmulus.com": [
+ "juniper.net"
+ ],
+ "rnengage.com": [
+ "mysql.com",
+ "rightnow.com",
+ "chewy.com"
+ ],
+ "rockcontent.com": [
+ "comcasttechnologysolutions.com"
+ ],
+ "roku.com": [
+ "experian.com"
+ ],
+ "rollingstone.com": [
+ "indiewire.com"
+ ],
+ "rosewe.com": [
+ "informationweek.com"
+ ],
+ "rotita.com": [
+ "informationweek.com"
+ ],
+ "rstbtmd.com": [
+ "rezka.ag",
+ "hdrezka-ag.com"
+ ],
+ "rsz.sk": [
+ "aktuality.sk"
+ ],
+ "rt.ru": [
+ "aif.ru"
+ ],
+ "rtbsuperhub.com": [
+ "cam4.com"
+ ],
+ "rtk.io": [
+ "post-gazette.com",
+ "elwatannews.com",
+ "dostor.org"
+ ],
+ "rtm.com": [
+ "landsend.com"
+ ],
+ "rtmark.net": [
+ "4shared.com",
+ "wplay.co",
+ "manganelo.com"
+ ],
+ "rtr-vesti.ru": [
+ "vesti.ru",
+ "russia.tv"
+ ],
+ "rubiconproject.com": [
+ "yahoo.com",
+ "amazon.com",
+ "msn.com"
+ ],
+ "rumble.com": [
+ "makeleio.gr"
+ ],
+ "rumiview.com": [
+ "asm.org",
+ "greenhouse.io",
+ "comptia.org"
+ ],
+ "run-syndicate.com": [
+ "manganelo.com"
+ ],
+ "russia.tv": [
+ "vesti.ru"
+ ],
+ "rutarget.ru": [
+ "aliexpress.ru",
+ "rambler.ru",
+ "sberbank.ru"
+ ],
+ "ryvx.net": [
+ "dickssportinggoods.com"
+ ],
+ "rzk-m.com": [
+ "rozetka.com.ua"
+ ],
+ "s5o.ru": [
+ "sports.ru"
+ ],
+ "sabavision.com": [
+ "aparat.com",
+ "asriran.com",
+ "parsfootball.com"
+ ],
+ "sabay.com": [
+ "sabay.com.kh"
+ ],
+ "sacbee.com": [
+ "kansascity.com",
+ "charlotteobserver.com",
+ "newsobserver.com"
+ ],
+ "sagetalk.io": [
+ "rosettastone.com"
+ ],
+ "sajari.com": [
+ "lockheedmartin.com",
+ "activecampaign.com"
+ ],
+ "salecycle.com": [
+ "qatarairways.com",
+ "bestwestern.com",
+ "valentino.com"
+ ],
+ "salemwebnetwork.com": [
+ "biblestudytools.com"
+ ],
+ "salesforce.com": [
+ "bestbuy.ca",
+ "anthropologie.com",
+ "michaels.com"
+ ],
+ "salesforceliveagent.com": [
+ "digicert.com",
+ "prnewswire.com",
+ "constantcontact.com"
+ ],
+ "salesloft.com": [
+ "wpengine.com",
+ "newrelic.com",
+ "upwork.com"
+ ],
+ "samandehi.ir": [
+ "digikala.com",
+ "divar.ir",
+ "beytoote.com"
+ ],
+ "samba.tv": [
+ "theverge.com",
+ "vox.com",
+ "xfinity.com"
+ ],
+ "sanjagh.com": [
+ "rokna.net",
+ "tarafdari.com",
+ "khabaronline.ir"
+ ],
+ "sanoma.fi": [
+ "nu.nl"
+ ],
+ "sape.ru": [
+ "aif.ru"
+ ],
+ "sas.com": [
+ "next.co.uk"
+ ],
+ "sc-static.net": [
+ "spotify.com",
+ "bloomberg.com",
+ "booking.com"
+ ],
+ "scarabresearch.com": [
+ "bitdefender.com",
+ "tate.org.uk",
+ "puma.com"
+ ],
+ "scatec.io": [
+ "pitchbook.com"
+ ],
+ "scene7.com": [
+ "pnc.com",
+ "poly.com"
+ ],
+ "scenepass.com": [
+ "gayboystube.com"
+ ],
+ "schibsted.com": [
+ "vg.no",
+ "aftonbladet.se",
+ "finn.no"
+ ],
+ "scholarlyiq.com": [
+ "oup.com"
+ ],
+ "sciencedirect.com": [
+ "thelancet.com",
+ "cell.com"
+ ],
+ "sciencemag.org": [
+ "aaas.org"
+ ],
+ "sciencex.com": [
+ "phys.org",
+ "medicalxpress.com"
+ ],
+ "scmp.com": [
+ "alanba.com.kw"
+ ],
+ "scoop.it": [
+ "psl.eu"
+ ],
+ "scorecardresearch.com": [
+ "linkedin.com",
+ "yahoo.com",
+ "reddit.com"
+ ],
+ "scribblelive.com": [
+ "ctvnews.ca",
+ "startribune.com"
+ ],
+ "scupio.com": [
+ "shopee.tw",
+ "udn.com",
+ "shopee.com"
+ ],
+ "sddan.com": [
+ "europe1.fr"
+ ],
+ "sdlcdn.com": [
+ "snapdeal.com"
+ ],
+ "searchforce.net": [
+ "ecwid.com"
+ ],
+ "searchiq.co": [
+ "comingsoon.net"
+ ],
+ "secrank.cn": [
+ "www.edu.cn"
+ ],
+ "section.io": [
+ "yourtango.com"
+ ],
+ "secureaddisplay.com": [
+ "newadvent.org"
+ ],
+ "securedtouch.com": [
+ "asos.com",
+ "wish.com",
+ "agoda.com"
+ ],
+ "securedvisit.com": [
+ "homedepot.com",
+ "cafepress.com",
+ "peta.org"
+ ],
+ "secureserver.net": [
+ "afternic.com",
+ "gamessu.com",
+ "sucuri.net"
+ ],
+ "securetve.com": [
+ "tsn.ca",
+ "bnnbloomberg.ca"
+ ],
+ "seedr.com": [
+ "gazeta.ru",
+ "championat.com",
+ "yaplakal.com"
+ ],
+ "seedtag.com": [
+ "ccm.net",
+ "milenio.com",
+ "elperiodico.com"
+ ],
+ "segment.com": [
+ "travelandleisure.com",
+ "angel.co",
+ "marthastewart.com"
+ ],
+ "segs.jp": [
+ "cybozu.com",
+ "valuecommerce.ne.jp"
+ ],
+ "sekindo.com": [
+ "mako.co.il",
+ "ynetnews.com",
+ "primis.tech"
+ ],
+ "selectmedia.asia": [
+ "onegreenplanet.org"
+ ],
+ "self.com": [
+ "wired.com",
+ "newyorker.com",
+ "vanityfair.com"
+ ],
+ "sellpoints.com": [
+ "costco.com",
+ "costco.ca"
+ ],
+ "semasio.net": [
+ "yahoo.com",
+ "lifo.gr",
+ "eksisozluk.com"
+ ],
+ "sembox.it": [
+ "italist.com"
+ ],
+ "semrush.com": [
+ "informationweek.com"
+ ],
+ "senseforth.com": [
+ "hdfcbank.com"
+ ],
+ "sensic.net": [
+ "krone.at"
+ ],
+ "sensorsdata.cn": [
+ "36kr.com",
+ "iliangcang.com",
+ "zhaoshang.net"
+ ],
+ "sensorsdatavip.com": [
+ "canva.cn"
+ ],
+ "sep.gob.mx": [
+ "www.gob.mx"
+ ],
+ "servebom.com": [
+ "techradar.com",
+ "livescience.com",
+ "howtogeek.com"
+ ],
+ "servedbyadbutler.com": [
+ "vanguardngr.com"
+ ],
+ "servenobid.com": [
+ "geeksforgeeks.org",
+ "mathrubhumi.com",
+ "sakshi.com"
+ ],
+ "serverbid.com": [
+ "usatoday.com",
+ "vox.com",
+ "ask.com"
+ ],
+ "serving-sys.com": [
+ "dropbox.com",
+ "news.com.au",
+ "asu.edu"
+ ],
+ "sessioncam.com": [
+ "hootsuite.com",
+ "braze.com",
+ "ama-assn.org"
+ ],
+ "seznam.cz": [
+ "idnes.cz"
+ ],
+ "sf14g.com": [
+ "panasonic.com",
+ "cornerstoneondemand.com",
+ "freshbooks.com"
+ ],
+ "sfegypt.com": [
+ "elfagr.com"
+ ],
+ "sfn.org": [
+ "jneurosci.org"
+ ],
+ "sgkrehberi.com": [
+ "memurlar.net"
+ ],
+ "sgsme.sg": [
+ "businesstimes.com.sg"
+ ],
+ "shanghai.gov.cn": [
+ "sh.gov.cn"
+ ],
+ "shaqm.com": [
+ "mop.com"
+ ],
+ "shareaholic.com": [
+ "worldstarhiphop.com",
+ "earthsky.org"
+ ],
+ "sharecare.com": [
+ "dailystrength.org"
+ ],
+ "sharethis.com": [
+ "unicef.org",
+ "businessnewsdaily.com",
+ "freeimages.com"
+ ],
+ "sharethrough.com": [
+ "msn.com",
+ "forbes.com",
+ "webmd.com"
+ ],
+ "shbdn.com": [
+ "sahibinden.com"
+ ],
+ "shinobi.jp": [
+ "ninja.co.jp",
+ "cityheaven.net"
+ ],
+ "shinystat.com": [
+ "dezeen.com",
+ "sworld.co.uk"
+ ],
+ "shld.net": [
+ "kmart.com"
+ ],
+ "shoagnie.com": [
+ "clipconverter.cc"
+ ],
+ "shop.app": [
+ "fashionnova.com"
+ ],
+ "shop.pe": [
+ "casetify.com",
+ "digitalcommerce360.com",
+ "jabra.com"
+ ],
+ "shopbop.com": [
+ "informationweek.com"
+ ],
+ "shopnetic.com": [
+ "rambler.ru",
+ "lenta.ru",
+ "ozon.ru"
+ ],
+ "shoprunner.com": [
+ "saksfifthavenue.com"
+ ],
+ "shopsocially.com": [
+ "score.org"
+ ],
+ "shuidi.cn": [
+ "xuexila.com"
+ ],
+ "sibautomation.com": [
+ "yektanet.com",
+ "dndbeyond.com",
+ "simplecast.com"
+ ],
+ "sift.com": [
+ "udemy.com",
+ "meetup.com",
+ "wish.com"
+ ],
+ "siftscience.com": [
+ "flickr.com",
+ "scribd.com",
+ "shutterstock.com"
+ ],
+ "signify.com": [
+ "philips-hue.com"
+ ],
+ "signifyd.com": [
+ "ssense.com",
+ "colourpop.com",
+ "fashionnova.com"
+ ],
+ "simility.com": [
+ "offerup.com"
+ ],
+ "simpli.fi": [
+ "okezone.com",
+ "matterport.com",
+ "rakuten.com"
+ ],
+ "sina.com.cn": [
+ "cnad.com",
+ "ccidnet.com"
+ ],
+ "sindonews.com": [
+ "okezone.com",
+ "inews.id"
+ ],
+ "sinoptik.ua": [
+ "ukr.net"
+ ],
+ "site24x7rum.com": [
+ "myfonts.com",
+ "cambridgeenglish.org",
+ "celine.com"
+ ],
+ "sitecore-prod-cd-westus2.azurewebsites.net": [
+ "alaskaair.com"
+ ],
+ "sitedataprocessing.com": [
+ "clickagy.com"
+ ],
+ "siteimproveanalytics.io": [
+ "mailchimp.com",
+ "opendns.com",
+ "berkeley.edu"
+ ],
+ "sitelock.com": [
+ "rapidgator.net",
+ "centos-webpanel.com"
+ ],
+ "sitescout.com": [
+ "okezone.com",
+ "imgur.com",
+ "aol.com"
+ ],
+ "skimresources.com": [
+ "businessinsider.com",
+ "dailymail.co.uk",
+ "nbcnews.com"
+ ],
+ "skplanet.com": [
+ "11st.co.kr",
+ "dothome.co.kr"
+ ],
+ "sky.com": [
+ "skysports.com"
+ ],
+ "sky.it": [
+ "tiscali.it"
+ ],
+ "slashdotmedia.com": [
+ "sourceforge.net",
+ "slashdot.org"
+ ],
+ "smaato.net": [
+ "imgur.com"
+ ],
+ "smadex.com": [
+ "realtor.com",
+ "taringa.net",
+ "rpp.pe"
+ ],
+ "smartadserver.com": [
+ "okezone.com",
+ "imgur.com",
+ "dailymotion.com"
+ ],
+ "smartclick.net": [
+ "bravotube.net"
+ ],
+ "smartnews-ads.com": [
+ "rakuten.co.jp",
+ "moneyforward.com",
+ "freee.co.jp"
+ ],
+ "smartocto.com": [
+ "tweakers.net",
+ "volkskrant.nl"
+ ],
+ "smartsurvey.co.uk": [
+ "fifa.com"
+ ],
+ "smct.co": [
+ "rhs.org.uk"
+ ],
+ "smi2.net": [
+ "rbc.ru",
+ "kp.ru",
+ "vz.ru"
+ ],
+ "smi2.ru": [
+ "kp.ru",
+ "kommersant.ru",
+ "iz.ru"
+ ],
+ "smilewanted.com": [
+ "caradisiac.com"
+ ],
+ "smithsonian.museum": [
+ "si.edu",
+ "smithsonianmag.com"
+ ],
+ "snapchat.com": [
+ "spotify.com",
+ "bloomberg.com",
+ "booking.com"
+ ],
+ "snapdeal.biz": [
+ "snapdeal.com"
+ ],
+ "snapwidget.com": [
+ "unh.edu",
+ "tulane.edu",
+ "theoatmeal.com"
+ ],
+ "snplow.net": [
+ "lapresse.ca"
+ ],
+ "snrbox.com": [
+ "onaudience.com"
+ ],
+ "snssdk.com": [
+ "toutiao.com",
+ "ixigua.com",
+ "bytedance.com"
+ ],
+ "so.com": [
+ "360kuai.com"
+ ],
+ "sobot.com": [
+ "shimo.im",
+ "51cto.com",
+ "jinshuju.net"
+ ],
+ "socdm.com": [
+ "au.com"
+ ],
+ "socialintents.com": [
+ "alphonso.tv"
+ ],
+ "soflopxl.com": [
+ "webcrawler.com",
+ "dogpile.com",
+ "info.com"
+ ],
+ "softspace.mobi": [
+ "analdin.com",
+ "xozilla.com"
+ ],
+ "sogei.it": [
+ "agenziaentrate.gov.it"
+ ],
+ "sogou.com": [
+ "soso.com",
+ "ifeng.com"
+ ],
+ "sohu.com": [
+ "56.com",
+ "yicai.com"
+ ],
+ "sojern.com": [
+ "marriott.com",
+ "metmuseum.org",
+ "wyndhamhotels.com"
+ ],
+ "sol-data.com": [
+ "seek.com.au"
+ ],
+ "solarwinds.com": [
+ "pingdom.com"
+ ],
+ "solosegment.com": [
+ "ul.com",
+ "asme.org",
+ "deere.com"
+ ],
+ "solvemedia.com": [
+ "moonbit.co.in",
+ "moonliteco.in",
+ "moondoge.co.in"
+ ],
+ "somoydigital.com": [
+ "somoynews.tv"
+ ],
+ "sonobi.com": [
+ "cnet.com",
+ "usatoday.com",
+ "dailymotion.com"
+ ],
+ "soundcloud.com": [
+ "ucl.ac.uk",
+ "irishtimes.com",
+ "seriouseats.com"
+ ],
+ "soundestlink.com": [
+ "cettire.com"
+ ],
+ "sp-prod.net": [
+ "businessinsider.com",
+ "gizmodo.com",
+ "lifehacker.com"
+ ],
+ "sp-trk.com": [
+ "lolipop.jp"
+ ],
+ "speakol.com": [
+ "dostor.org",
+ "almasryalyoum.com"
+ ],
+ "spectate.com": [
+ "emory.edu",
+ "nova.edu",
+ "utsa.edu"
+ ],
+ "speee-ad.jp": [
+ "alc.co.jp"
+ ],
+ "sphereup.com": [
+ "abs-cbn.com",
+ "venturebeat.com",
+ "jpost.com"
+ ],
+ "sphlabs.com": [
+ "zaobao.com.sg",
+ "businesstimes.com.sg"
+ ],
+ "spiceworks.com": [
+ "slack.com",
+ "sophos.com",
+ "seagate.com"
+ ],
+ "spider.af": [
+ "jalan.net"
+ ],
+ "spokenlayer.com": [
+ "dailyherald.com",
+ "mcall.com",
+ "pilotonline.com"
+ ],
+ "sportradarserving.com": [
+ "bet9ja.com"
+ ],
+ "sportrecs.com": [
+ "championat.com"
+ ],
+ "spot.im": [
+ "aol.com",
+ "realclearpolitics.com",
+ "elespanol.com"
+ ],
+ "spoteffects.net": [
+ "123milhas.com",
+ "ionos.fr"
+ ],
+ "spotify.com": [
+ "hurriyet.com.tr",
+ "biobiochile.cl",
+ "premierleague.com"
+ ],
+ "spotim.market": [
+ "aol.com"
+ ],
+ "spotxchange.com": [
+ "tribunnews.com",
+ "tinyurl.com",
+ "dailymail.co.uk"
+ ],
+ "spreadshirt.net": [
+ "spreadshirt.com"
+ ],
+ "spreaker.com": [
+ "eltiempo.com",
+ "ellitoral.com"
+ ],
+ "springserve.com": [
+ "venturebeat.com",
+ "wowhead.com",
+ "nexusmods.com"
+ ],
+ "sputnik.ru": [
+ "pochta.ru",
+ "1sept.ru",
+ "permkrai.ru"
+ ],
+ "square-enix.com": [
+ "square-enix-games.com"
+ ],
+ "squren.com": [
+ "gayboystube.com"
+ ],
+ "srvtrck.com": [
+ "commentcamarche.net",
+ "linternaute.com"
+ ],
+ "srx.com.sg": [
+ "straitstimes.com",
+ "businesstimes.com.sg"
+ ],
+ "ssense.com": [
+ "informationweek.com"
+ ],
+ "ssg.com": [
+ "hani.co.kr"
+ ],
+ "sspinc.io": [
+ "nordstromrack.com",
+ "ssense.com"
+ ],
+ "st8fm.com": [
+ "statefarm.com"
+ ],
+ "stack-sonar.com": [
+ "entrepreneur.com",
+ "venturebeat.com",
+ "slashdot.org"
+ ],
+ "stackadapt.com": [
+ "dropbox.com",
+ "youm7.com",
+ "hbr.org"
+ ],
+ "stackoverflow.com": [
+ "askubuntu.com",
+ "serverfault.com",
+ "codinghorror.com"
+ ],
+ "stackpathcdn.com": [
+ "telugustop.com"
+ ],
+ "stat-rock.com": [
+ "elwatannews.com"
+ ],
+ "stat.media": [
+ "kp.ru",
+ "gazeta.ru",
+ "realclearpolitics.com"
+ ],
+ "statad.ru": [
+ "sberbank.ru",
+ "hh.ru",
+ "labirint.ru"
+ ],
+ "statcounter.com": [
+ "freepik.com",
+ "hugedomains.com",
+ "flaticon.com"
+ ],
+ "state.nj.us": [
+ "nj.gov"
+ ],
+ "staticcache.org": [
+ "williamhill.com"
+ ],
+ "staticworld.net": [
+ "csoonline.com"
+ ],
+ "statsy.net": [
+ "rarbg.to"
+ ],
+ "statuspage.io": [
+ "ghost.org",
+ "postman.com"
+ ],
+ "stdout.cz": [
+ "aktualne.cz"
+ ],
+ "steelcentral.net": [
+ "wireshark.org"
+ ],
+ "steelhousemedia.com": [
+ "salesforce.com",
+ "stockx.com",
+ "careerbuilder.com"
+ ],
+ "stickyadstv.com": [
+ "okezone.com",
+ "aol.com",
+ "youm7.com"
+ ],
+ "stockdio.com": [
+ "newsbeast.gr"
+ ],
+ "storage.googleapis.com": [
+ "reviewjournal.com",
+ "campograndenews.com.br",
+ "clicrbs.com.br",
+ "texasmonthly.com"
+ ],
+ "stores-bloomingdales.com": [
+ "bloomingdales.com"
+ ],
+ "storygize.net": [
+ "bostonglobe.com",
+ "heart.org"
+ ],
+ "stream.ne.jp": [
+ "yomiuri.co.jp"
+ ],
+ "streamingddigital.com": [
+ "bbva.es"
+ ],
+ "streamtheworld.com": [
+ "spreaker.com",
+ "eltiempo.com",
+ "cadenaser.com"
+ ],
+ "stripchat.com": [
+ "informationweek.com"
+ ],
+ "stripe.com": [
+ "npr.org",
+ "feedly.com",
+ "newsweek.com"
+ ],
+ "stripe.network": [
+ "feedly.com",
+ "artstation.com",
+ "stitcher.com"
+ ],
+ "stripst.com": [
+ "xhamsterlive.com",
+ "stripchat.com"
+ ],
+ "striveme.com": [
+ "kooora.com"
+ ],
+ "stucki.io": [
+ "unibas.ch"
+ ],
+ "studybreakmedia.com": [
+ "citationmachine.net",
+ "easybib.com"
+ ],
+ "stylight.net": [
+ "yoox.com"
+ ],
+ "subservis.com": [
+ "hurriyet.com.tr",
+ "milliyet.com.tr",
+ "cnnturk.com"
+ ],
+ "summerhamster.com": [
+ "cnn.com",
+ "weather.com",
+ "zdnet.com"
+ ],
+ "sumo.com": [
+ "freshdesk.com",
+ "popsugar.com",
+ "thrillist.com"
+ ],
+ "sumologic.com": [
+ "levi.com"
+ ],
+ "sundaysky.com": [
+ "dell.com",
+ "cox.com",
+ "staples.com"
+ ],
+ "suning.cn": [
+ "pptv.com"
+ ],
+ "suning.com": [
+ "pptv.com"
+ ],
+ "sunrtb.com": [
+ "eccn.com"
+ ],
+ "supplyframe.com": [
+ "arduino.cc",
+ "ti.com",
+ "hackaday.com"
+ ],
+ "surfcountor.com": [
+ "kenh14.vn"
+ ],
+ "survata.com": [
+ "tripadvisor.com"
+ ],
+ "svd.se": [
+ "aftonbladet.se"
+ ],
+ "svtrd.com": [
+ "tnt.com"
+ ],
+ "swiftype.com": [
+ "adage.com",
+ "techsmith.com",
+ "indiewire.com"
+ ],
+ "swisscom.ch": [
+ "bluewin.ch"
+ ],
+ "swisspass.ch": [
+ "sbb.ch"
+ ],
+ "symantec.com": [
+ "budsgunshop.com",
+ "jbl.com"
+ ],
+ "synchronycredit.com": [
+ "carecredit.com"
+ ],
+ "syndigo.cloud": [
+ "costco.com",
+ "costco.ca"
+ ],
+ "syr.edu": [
+ "syracuse.edu"
+ ],
+ "syuh.net": [
+ "squarespace.com"
+ ],
+ "szzbmy.com": [
+ "rabbitpre.com"
+ ],
+ "t-mobilemoney.com": [
+ "t-mobile.com"
+ ],
+ "t-x.io": [
+ "livenation.com"
+ ],
+ "t.co": [
+ "wsj.com"
+ ],
+ "taboola.com": [
+ "msn.com",
+ "okezone.com",
+ "sourceforge.net"
+ ],
+ "tacdn.com": [
+ "visitlondon.com"
+ ],
+ "tag4arm.com": [
+ "stockx.com",
+ "web.com"
+ ],
+ "tagboard.com": [
+ "ucsd.edu",
+ "activision.com",
+ "scu.edu"
+ ],
+ "tagcommander.com": [
+ "hotels.com",
+ "yoox.com"
+ ],
+ "tagtic.cn": [
+ "a9vg.com"
+ ],
+ "tailtarget.com": [
+ "uol.com.br",
+ "globo.com",
+ "metropoles.com"
+ ],
+ "talkable.com": [
+ "blurb.com",
+ "society6.com"
+ ],
+ "tam.by": [
+ "tut.by"
+ ],
+ "tamedia.com.tw": [
+ "momoshop.com.tw"
+ ],
+ "tamgrt.com": [
+ "wyndhamhotels.com",
+ "priceline.com",
+ "bestwestern.com"
+ ],
+ "tanx.com": [
+ "sohu.com"
+ ],
+ "taobao.com": [
+ "sm.cn"
+ ],
+ "tapad.com": [
+ "amazon.com",
+ "godaddy.com",
+ "okezone.com"
+ ],
+ "taplytics.com": [
+ "foxnews.com",
+ "foxbusiness.com"
+ ],
+ "tapnative.com": [
+ "dailystrength.org"
+ ],
+ "targetspot.com": [
+ "spreaker.com",
+ "eltiempo.com",
+ "ellitoral.com"
+ ],
+ "tavoos.net": [
+ "parsfootball.com",
+ "shomanews.com",
+ "rasadeghtesadi.com"
+ ],
+ "tawk.to": [
+ "affordable-papers.net",
+ "essayswriting.org",
+ "cba.pl"
+ ],
+ "taylorandfrancis.com": [
+ "tandfonline.com"
+ ],
+ "tazabek.kg": [
+ "akipress.org"
+ ],
+ "tchibo.de": [
+ "t-online.de"
+ ],
+ "tctm.co": [
+ "tapjoy.com"
+ ],
+ "tdefender.net": [
+ "canadiantire.ca"
+ ],
+ "teads.tv": [
+ "grid.id",
+ "tokopedia.com",
+ "theatlantic.com"
+ ],
+ "tealiumiq.com": [
+ "cnet.com",
+ "ibm.com",
+ "shopify.com"
+ ],
+ "techlab-cdn.com": [
+ "yoox.com",
+ "gucci.com",
+ "mxc.com"
+ ],
+ "technical-service.net": [
+ "stern.de",
+ "rtl.de",
+ "chefkoch.de"
+ ],
+ "technologyadvice.com": [
+ "serverwatch.com"
+ ],
+ "technoratimedia.com": [
+ "youm7.com",
+ "ask.com",
+ "venturebeat.com"
+ ],
+ "techonline.com": [
+ "eetimes.com"
+ ],
+ "techtarget.com": [
+ "slack.com",
+ "newrelic.com",
+ "gotomeeting.com"
+ ],
+ "techweb.com": [
+ "informationweek.com",
+ "gamasutra.com",
+ "darkreading.com"
+ ],
+ "teenvogue.com": [
+ "wired.com",
+ "newyorker.com",
+ "vanityfair.com"
+ ],
+ "telekom.de": [
+ "telekom.com"
+ ],
+ "teleport.media": [
+ "vesti.ru",
+ "russia.tv"
+ ],
+ "televebion.net": [
+ "telewebion.com"
+ ],
+ "tend-table.com": [
+ "donga.com",
+ "koreaherald.com"
+ ],
+ "tenmax.io": [
+ "ruten.com.tw",
+ "xuite.net"
+ ],
+ "terminus.services": [
+ "wpengine.com",
+ "unity.com",
+ "gotomeeting.com"
+ ],
+ "tfaforms.net": [
+ "teamusa.org",
+ "und.edu",
+ "aamc.org"
+ ],
+ "theadex.com": [
+ "t-online.de",
+ "mobile.de",
+ "messefrankfurt.com"
+ ],
+ "thebrighttag.com": [
+ "kohls.com",
+ "sephora.com",
+ "gopro.com"
+ ],
+ "theglobeandmail.ca": [
+ "theglobeandmail.com"
+ ],
+ "thehindu.com": [
+ "thehindubusinessline.com"
+ ],
+ "theice.com": [
+ "nyse.com"
+ ],
+ "thejobnetwork.com": [
+ "timesfreepress.com"
+ ],
+ "them.us": [
+ "wired.com",
+ "newyorker.com",
+ "vanityfair.com"
+ ],
+ "themarker.com": [
+ "haaretz.com"
+ ],
+ "thenewstribune.com": [
+ "idahostatesman.com"
+ ],
+ "theregister.co.uk": [
+ "theregister.com"
+ ],
+ "thesame.tv": [
+ "yaplakal.com"
+ ],
+ "thesun.co.uk": [
+ "talksport.com"
+ ],
+ "thinkpad.com": [
+ "lenovo.com.cn"
+ ],
+ "threewave.jp": [
+ "moppy.jp"
+ ],
+ "thron.com": [
+ "ferrari.com"
+ ],
+ "thrtle.com": [
+ "variety.com",
+ "rollingstone.com",
+ "medscape.com"
+ ],
+ "thunderhead.com": [
+ "forever21.com",
+ "telstra.com.au",
+ "banco.bradesco"
+ ],
+ "ti.com.cn": [
+ "ti.com"
+ ],
+ "tidaltv.com": [
+ "okezone.com",
+ "imgur.com",
+ "geeksforgeeks.org"
+ ],
+ "tij.co.jp": [
+ "ti.com"
+ ],
+ "timecommerce.net": [
+ "people.com",
+ "allrecipes.com",
+ "ew.com"
+ ],
+ "timewarnercable.com": [
+ "spectrumlocalnews.com",
+ "ny1.com"
+ ],
+ "tinkoffinsurance.ru": [
+ "tinkoff.ru"
+ ],
+ "tinypass.com": [
+ "forbes.com",
+ "reuters.com",
+ "bloomberg.com"
+ ],
+ "tiqcdn.com": [
+ "marketwatch.com",
+ "wsj.com",
+ "oakley.com"
+ ],
+ "titoaktop.com": [
+ "kickasstorrents.to"
+ ],
+ "tmall.ru": [
+ "aliexpress.com"
+ ],
+ "tmobile.com": [
+ "t-mobile.com"
+ ],
+ "tns-counter.ru": [
+ "vk.com",
+ "mail.ru",
+ "ok.ru"
+ ],
+ "tns-cs.net": [
+ "nrk.no",
+ "yr.no"
+ ],
+ "tns-ua.com": [
+ "i.ua",
+ "ria.com",
+ "bigmir.net"
+ ],
+ "toast.com": [
+ "ettoday.net",
+ "jpnn.com",
+ "dothome.co.kr"
+ ],
+ "tombot.ai": [
+ "rosettastone.com"
+ ],
+ "tomtop.com": [
+ "informationweek.com"
+ ],
+ "tongdun.cn": [
+ "tongdun.net"
+ ],
+ "top100.ru": [
+ "livejournal.com",
+ "rambler.ru",
+ "lenta.ru"
+ ],
+ "top4top.io": [
+ "cutt.us"
+ ],
+ "toplist.cz": [
+ "opensubtitles.org"
+ ],
+ "toutapp.com": [
+ "newswire.com"
+ ],
+ "tq.cn": [
+ "idianfa.com"
+ ],
+ "trackad.cz": [
+ "idnes.cz",
+ "aktualne.cz"
+ ],
+ "trackalyzer.com": [
+ "servicenow.com"
+ ],
+ "tradablebits.com": [
+ "sundance.org"
+ ],
+ "tradedoubler.com": [
+ "marca.com",
+ "elmundo.es",
+ "expansion.com"
+ ],
+ "tradelab.fr": [
+ "eklablog.com",
+ "canalblog.com",
+ "icrc.org"
+ ],
+ "tradingview.com": [
+ "investopedia.com",
+ "entrepreneur.com",
+ "kitco.com"
+ ],
+ "traffic-media.co.uk": [
+ "kinokrad.co",
+ "1plus1tv.ru"
+ ],
+ "trafficbass.com": [
+ "filmix.co",
+ "radikal.ru",
+ "1plus1tv.ru"
+ ],
+ "trafficdok.com": [
+ "filmix.co"
+ ],
+ "trafficgate.net": [
+ "rakuten.co.jp"
+ ],
+ "trafficguard.ai": [
+ "nerdwallet.com",
+ "westernunion.com",
+ "williamhill.com"
+ ],
+ "trafficjunky.net": [
+ "pornhub.com",
+ "redtube.com",
+ "nhentai.net"
+ ],
+ "trafficlide.com": [
+ "filmix.co"
+ ],
+ "trafficsan.com": [
+ "kickassanime.rs"
+ ],
+ "trafmag.com": [
+ "rezka.ag",
+ "ukr.net",
+ "prom.ua"
+ ],
+ "transferwise.com": [
+ "informationweek.com"
+ ],
+ "travelaudience.com": [
+ "thetrainline.com"
+ ],
+ "trbna.com": [
+ "sports.ru"
+ ],
+ "treasuredata.com": [
+ "goo.ne.jp",
+ "kakaku.com",
+ "asahi.com"
+ ],
+ "tremorhub.com": [
+ "dailymail.co.uk",
+ "aol.com",
+ "youm7.com"
+ ],
+ "trendemon.com": [
+ "tenable.com",
+ "walkme.com",
+ "panasonic.jp"
+ ],
+ "trendmd.com": [
+ "sciencedaily.com"
+ ],
+ "tribalfusion.com": [
+ "walmart.com",
+ "realtor.com",
+ "xe.com"
+ ],
+ "tribl.io": [
+ "ada.support",
+ "meltwater.com",
+ "jobvite.com"
+ ],
+ "trinitymedia.ai": [
+ "stripes.com"
+ ],
+ "trip.com": [
+ "informationweek.com"
+ ],
+ "tripadvisor.com": [
+ "radissonblu.com"
+ ],
+ "tripcdn.com": [
+ "trip.com"
+ ],
+ "trkn.us": [
+ "unsplash.com",
+ "newyorker.com",
+ "usps.com"
+ ],
+ "trs.cn": [
+ "gxzf.gov.cn",
+ "xhby.net"
+ ],
+ "truefitcorp.com": [
+ "landsend.com"
+ ],
+ "truehits.in.th": [
+ "sanook.com",
+ "kapook.com",
+ "thairath.co.th"
+ ],
+ "truepush.com": [
+ "eenadu.net",
+ "3isk.tv",
+ "sarvgyan.com"
+ ],
+ "trumba.com": [
+ "ucdavis.edu",
+ "okstate.edu",
+ "royalgazette.com"
+ ],
+ "truoptik.com": [
+ "wowhead.com"
+ ],
+ "trustarc.com": [
+ "redhat.com",
+ "medscape.com",
+ "philips.com"
+ ],
+ "trustcommander.net": [
+ "mytheresa.com",
+ "lcl.fr"
+ ],
+ "trustedsite.com": [
+ "myus.com"
+ ],
+ "trustivity.es": [
+ "movistar.es"
+ ],
+ "trustspot.io": [
+ "cognitoforms.com"
+ ],
+ "trvl-px.com": [
+ "hotels.com",
+ "vrbo.com"
+ ],
+ "trwl1.com": [
+ "avgle.com"
+ ],
+ "trysera.com": [
+ "realclearpolitics.com",
+ "adorama.com"
+ ],
+ "tsyndicate.com": [
+ "drtuber.com",
+ "stripchat.com",
+ "xhamster.desi"
+ ],
+ "tucarro.com.co": [
+ "mercadolibre.com.co"
+ ],
+ "tucarro.com.ve": [
+ "mercadolibre.com.ve"
+ ],
+ "tuinmueble.com.ve": [
+ "mercadolibre.com.ve"
+ ],
+ "tumoto.com.co": [
+ "mercadolibre.com.co"
+ ],
+ "tumoto.com.ve": [
+ "mercadolibre.com.ve"
+ ],
+ "turn.com": [
+ "okezone.com",
+ "forbes.com",
+ "sourceforge.net"
+ ],
+ "tutu.travel": [
+ "tutu.ru"
+ ],
+ "tvinsider.com": [
+ "gazette.com"
+ ],
+ "tvopen.gr": [
+ "ethnos.gr"
+ ],
+ "tvpage.com": [
+ "bedbathandbeyond.com"
+ ],
+ "tvpixel.com": [
+ "nbcnews.com",
+ "vmware.com",
+ "today.com"
+ ],
+ "tvsquared.com": [
+ "godaddy.com",
+ "coursera.org",
+ "hulu.com"
+ ],
+ "tw.cx": [
+ "justwatch.com"
+ ],
+ "twimg.com": [
+ "epfl.ch",
+ "nice.org.uk",
+ "royalsociety.org"
+ ],
+ "twitch.tv": [
+ "xataka.com",
+ "dndbeyond.com",
+ "fextralife.com"
+ ],
+ "twitter.com": [
+ "linkedin.com",
+ "amazon.com",
+ "adobe.com"
+ ],
+ "twnmm.com": [
+ "theweathernetwork.com"
+ ],
+ "tynt.com": [
+ "ettoday.net",
+ "inquirer.net",
+ "alnaharegypt.com"
+ ],
+ "typekit.net": [
+ "illinois.edu",
+ "acs.org",
+ "jotform.com",
+ "pixar.com"
+ ],
+ "u7u9.com": [
+ "sina.com.cn"
+ ],
+ "uadexchange.com": [
+ "uzone.id"
+ ],
+ "ubic.tech": [
+ "mos.ru"
+ ],
+ "uc.se": [
+ "jalbum.net"
+ ],
+ "ucfly.com": [
+ "9game.cn"
+ ],
+ "ucgstatic.eu": [
+ "unicredit.it"
+ ],
+ "uciservice.com": [
+ "hotels.com",
+ "hotwire.com"
+ ],
+ "udemy.com": [
+ "informationweek.com"
+ ],
+ "udesk.cn": [
+ "kuaidi100.com",
+ "zb.com",
+ "bitz.ai"
+ ],
+ "udimg.com": [
+ "urbandictionary.com"
+ ],
+ "udmserve.net": [
+ "timesofisrael.com",
+ "nationalinterest.org",
+ "freebeacon.com"
+ ],
+ "ufpcdn.com": [
+ "eztv.io"
+ ],
+ "uicdn.net": [
+ "ionos.com",
+ "ionos.de",
+ "ionos.fr"
+ ],
+ "uikc.net": [
+ "qvc.com"
+ ],
+ "uimserv.net": [
+ "ionos.com",
+ "ionos.fr"
+ ],
+ "ukr.net": [
+ "sinoptik.ua"
+ ],
+ "ukw.jp": [
+ "peatix.com"
+ ],
+ "ulb.ac.be": [
+ "ulb.be"
+ ],
+ "ulclick.ru": [
+ "aif.ru",
+ "revopush.com"
+ ],
+ "ulogin.ru": [
+ "aif.ru",
+ "revopush.com"
+ ],
+ "ultainc.com": [
+ "ulta.com"
+ ],
+ "ultimedia.com": [
+ "lesoir.be",
+ "libertaddigital.com"
+ ],
+ "unbxdapi.com": [
+ "hsn.com"
+ ],
+ "uncn.jp": [
+ "hulu.jp"
+ ],
+ "uncrate.supply": [
+ "uncrate.com"
+ ],
+ "undertone.com": [
+ "variety.com",
+ "rollingstone.com",
+ "lastpass.com"
+ ],
+ "uni-frankfurt.de": [
+ "goethe-university-frankfurt.de"
+ ],
+ "unicc.org": [
+ "ohchr.org"
+ ],
+ "unidata.ai": [
+ "storm.mg"
+ ],
+ "unisender.com": [
+ "hse.ru",
+ "forbes.ru"
+ ],
+ "unite.com": [
+ "freedownloadmanager.org"
+ ],
+ "unsplash.com": [
+ "pinterest.com",
+ "pinimg.com",
+ "pinterest.ca"
+ ],
+ "uol.com.br": [
+ "magazineluiza.com.br"
+ ],
+ "uplift-platform.com": [
+ "caesars.com"
+ ],
+ "upravel.com": [
+ "kp.ru",
+ "aif.ru",
+ "citilink.ru"
+ ],
+ "upsellit.com": [
+ "ccleaner.com"
+ ],
+ "uptime.com": [
+ "thingiverse.com",
+ "storyblocks.com",
+ "weedmaps.com"
+ ],
+ "uq.net.au": [
+ "uq.edu.au"
+ ],
+ "uqhv.net": [
+ "hsn.com"
+ ],
+ "urbandictionary.store": [
+ "urbandictionary.com"
+ ],
+ "us-central1-ah-acemarketingteam.cloudfunctions.net": [
+ "acehardware.com"
+ ],
+ "us-central1-zendesk-functions.cloudfunctions.net": [
+ "yubico.com"
+ ],
+ "usaa360.com": [
+ "usaa.com"
+ ],
+ "useinsider.com": [
+ "idntimes.com",
+ "mynet.com",
+ "blibli.com"
+ ],
+ "user-red.com": [
+ "alfabank.ru"
+ ],
+ "usercentrics.eu": [
+ "adac.de",
+ "sennheiser.com",
+ "steinberg.net"
+ ],
+ "usergram.info": [
+ "ocn.ne.jp",
+ "sony.jp",
+ "hulu.jp"
+ ],
+ "userreplay.net": [
+ "containerstore.com",
+ "papajohns.com",
+ "bathandbodyworks.com"
+ ],
+ "userreport.com": [
+ "memurlar.net",
+ "blogg.se",
+ "iltalehti.fi"
+ ],
+ "uservoice.com": [
+ "scoop.it",
+ "adobe.com",
+ "slader.com"
+ ],
+ "userzoom.com": [
+ "statefarm.com"
+ ],
+ "usocial.pro": [
+ "narod.ru"
+ ],
+ "usonar.jp": [
+ "sakura.ne.jp",
+ "sakura.ad.jp"
+ ],
+ "uspech.sk": [
+ "sme.sk"
+ ],
+ "utarget.ru": [
+ "radikal.ru",
+ "utarget.pro"
+ ],
+ "uuidksinc.net": [
+ "rezka.ag",
+ "aif.ru"
+ ],
+ "uxfeedback.ru": [
+ "cian.ru",
+ "mvideo.ru",
+ "eldorado.ru"
+ ],
+ "vads.net.vn": [
+ "vietnamnet.vn"
+ ],
+ "valkirum.com": [
+ "kinogo.zone"
+ ],
+ "valuecommerce.com": [
+ "hotpepper.jp",
+ "alc.co.jp",
+ "techacademy.jp"
+ ],
+ "valuecommerce.ne.jp": [
+ "moppy.jp"
+ ],
+ "vanityfair.com": [
+ "wired.com",
+ "newyorker.com",
+ "vogue.com"
+ ],
+ "veinteractive.com": [
+ "lesoir.be"
+ ],
+ "velaro.com": [
+ "adp.com"
+ ],
+ "vendemore.com": [
+ "suse.com",
+ "splunk.com"
+ ],
+ "vergic.com": [
+ "aicpa.org"
+ ],
+ "vertebrae-axis.com": [
+ "coach.com"
+ ],
+ "verticalhealth.net": [
+ "psychcentral.com"
+ ],
+ "vgtrk.com": [
+ "vesti.ru",
+ "russia.tv"
+ ],
+ "vgwort.de": [
+ "wbs-law.de"
+ ],
+ "viafoura.co": [
+ "cbc.ca",
+ "mirror.co.uk",
+ "mercurynews.com"
+ ],
+ "viatorinc.com": [
+ "viator.com"
+ ],
+ "vidads.gr": [
+ "newsbeast.gr"
+ ],
+ "vidazoo.com": [
+ "washingtonian.com"
+ ],
+ "video-cdn.net": [
+ "messefrankfurt.com"
+ ],
+ "videohub.tv": [
+ "colorado.edu",
+ "wsj.com",
+ "dashlane.com"
+ ],
+ "vidgrid.com": [
+ "paylocity.com"
+ ],
+ "vidible.tv": [
+ "huffpost.com",
+ "huffingtonpost.ca",
+ "edh.tw"
+ ],
+ "vidio.com": [
+ "liputan6.com",
+ "bola.net"
+ ],
+ "vidyard.com": [
+ "izooto.com",
+ "ultimatesoftware.com",
+ "clarivate.com"
+ ],
+ "vietid.net": [
+ "soha.vn"
+ ],
+ "vietnamnettv.vn": [
+ "vietnamnet.vn"
+ ],
+ "viglink.com": [
+ "cnet.com",
+ "zdnet.com",
+ "techrepublic.com"
+ ],
+ "vihub.ru": [
+ "rezka.ag",
+ "baskino.me",
+ "litres.ru"
+ ],
+ "viki.io": [
+ "viki.com"
+ ],
+ "vindicosuite.com": [
+ "jpost.com",
+ "zappos.com",
+ "medallia.com"
+ ],
+ "viostream.com": [
+ "ato.gov.au"
+ ],
+ "vip.com": [
+ "idianfa.com"
+ ],
+ "vipstatic.com": [
+ "vip.com"
+ ],
+ "viqeo.tv": [
+ "rg.ru"
+ ],
+ "viralize.tv": [
+ "ilfattoquotidiano.it"
+ ],
+ "virgul.com": [
+ "yemek.com",
+ "tureng.com"
+ ],
+ "virtuoussoftware.com": [
+ "lifesitenews.com"
+ ],
+ "visa.com": [
+ "authorize.net",
+ "cybersource.com"
+ ],
+ "visilabs.net": [
+ "kariyer.net"
+ ],
+ "visitor-track.com": [
+ "hivestreaming.com",
+ "prnewswire.com"
+ ],
+ "visualstudio.com": [
+ "dior.com",
+ "seriouseats.com",
+ "techopedia.com"
+ ],
+ "visualwebsiteoptimizer.com": [
+ "instructure.com",
+ "okta.com",
+ "plesk.com"
+ ],
+ "vivino.com": [
+ "informationweek.com"
+ ],
+ "vivocha.com": [
+ "insee.fr"
+ ],
+ "vizergy.com": [
+ "hardrock.com"
+ ],
+ "vizury.com": [
+ "adorama.com"
+ ],
+ "vk.com": [
+ "livejournal.com",
+ "aliexpress.ru",
+ "asos.com"
+ ],
+ "vnecdn.net": [
+ "vnexpress.net"
+ ],
+ "vodgc.net": [
+ "tn.com.ar"
+ ],
+ "vogue.com": [
+ "wired.com",
+ "newyorker.com",
+ "vanityfair.com"
+ ],
+ "voidboost.net": [
+ "baskino.me"
+ ],
+ "volvelle.tech": [
+ "lesoir.be"
+ ],
+ "voxmedia.com": [
+ "theverge.com",
+ "vox.com",
+ "polygon.com"
+ ],
+ "vporn.com": [
+ "pornone.com"
+ ],
+ "vroom.be": [
+ "standaard.be"
+ ],
+ "vrtzads.com": [
+ "thehindu.com"
+ ],
+ "vstocklab.com": [
+ "hani.co.kr"
+ ],
+ "vupulse.com": [
+ "dailywire.com"
+ ],
+ "vzew.net": [
+ "lenovo.com"
+ ],
+ "w55c.net": [
+ "forbes.com",
+ "addthis.com",
+ "pbs.org"
+ ],
+ "w8.com.cn": [
+ "zol.com.cn",
+ "cnmo.com"
+ ],
+ "walkme.com": [
+ "moodys.com"
+ ],
+ "wallkit.net": [
+ "thewrap.com"
+ ],
+ "watertu.com": [
+ "gusuwang.com"
+ ],
+ "wbtrk.net": [
+ "goethe.de",
+ "telekom.com",
+ "swissinfo.ch"
+ ],
+ "wcfbc.net": [
+ "repubblica.it",
+ "telekom.com",
+ "messefrankfurt.com"
+ ],
+ "wdsvc.net": [
+ "alz.org",
+ "nature.org",
+ "taxfoundation.org"
+ ],
+ "webankieta.pl": [
+ "certum.pl"
+ ],
+ "webantenna.info": [
+ "coconala.com",
+ "hulu.jp",
+ "onamae.com"
+ ],
+ "webengage.com": [
+ "testbook.com",
+ "deccanherald.com",
+ "angelbroking.com"
+ ],
+ "webeyez.com": [
+ "similarweb.com"
+ ],
+ "webforms-here.com": [
+ "here.com"
+ ],
+ "webmd.com": [
+ "avvo.com"
+ ],
+ "webnode.com": [
+ "webnode.cz"
+ ],
+ "weborama.fr": [
+ "ivi.tv",
+ "kino-teatr.ru",
+ "aif.ru"
+ ],
+ "webpush.jp": [
+ "asahi.com",
+ "sankei.com",
+ "sponichi.co.jp"
+ ],
+ "webs.com": [
+ "freewebs.com"
+ ],
+ "webspectator.com": [
+ "metropoles.com",
+ "goal.com",
+ "otvfoco.com.br"
+ ],
+ "webterren.com": [
+ "china.com.cn",
+ "eastday.com",
+ "rednet.cn"
+ ],
+ "webtracker.jp": [
+ "ascii.jp",
+ "famitsu.com"
+ ],
+ "webtrafficsource.com": [
+ "newchic.com",
+ "dx.com"
+ ],
+ "webtrekk.net": [
+ "springer.com",
+ "hepsiburada.com",
+ "goethe.de"
+ ],
+ "webtrendslive.com": [
+ "aaa.com",
+ "ingrammicro.com"
+ ],
+ "webturn.ru": [
+ "domclick.ru"
+ ],
+ "webullfintech.com": [
+ "webull.com"
+ ],
+ "webvisor.org": [
+ "tribunnews.com",
+ "inquirer.net",
+ "narod.ru"
+ ],
+ "weekli.de": [
+ "rp-online.de"
+ ],
+ "weibo.com": [
+ "cnad.com",
+ "ccidnet.com",
+ "19888.tv"
+ ],
+ "wellsmedia.com": [
+ "insurancejournal.com"
+ ],
+ "wemfbox.ch": [
+ "swissinfo.ch",
+ "nzz.ch",
+ "20min.ch"
+ ],
+ "wemorefun.com": [
+ "appgame.com"
+ ],
+ "west.cn": [
+ "idianfa.com"
+ ],
+ "whistleout.com": [
+ "dslreports.com"
+ ],
+ "wi-fi.ru": [
+ "ntv.ru",
+ "yaplakal.com",
+ "zaycev.net"
+ ],
+ "widengle.com": [
+ "caesars.com"
+ ],
+ "wikia-services.com": [
+ "gamepedia.com"
+ ],
+ "wikipedia.org": [
+ "flattr.com"
+ ],
+ "wiqhit.com": [
+ "eur.nl"
+ ],
+ "wired.com": [
+ "newyorker.com",
+ "vanityfair.com",
+ "vogue.com"
+ ],
+ "wishabi.com": [
+ "globalnews.ca",
+ "nationalpost.com",
+ "baltimoresun.com",
+ "edmontonjournal.com"
+ ],
+ "wisokykulas.bid": [
+ "filmix.co"
+ ],
+ "wistia.com": [
+ "magento.com",
+ "getflywheel.com"
+ ],
+ "wistia.net": [
+ "uservoice.com",
+ "pendo.io",
+ "pardot.com"
+ ],
+ "wix.com": [
+ "deviantart.com"
+ ],
+ "wkxppshj-qx.global.ssl.fastly.net": [
+ "jcpenney.com",
+ "ulta.com",
+ "argos.co.uk"
+ ],
+ "wnyc.org": [
+ "newyorker.com"
+ ],
+ "wo-cloud.com": [
+ "wetteronline.de"
+ ],
+ "wondershare.com": [
+ "wondershare.net"
+ ],
+ "workplace.tools": [
+ "workplace.com"
+ ],
+ "wp.com": [
+ "akismet.com",
+ "jetpack.com",
+ "crowdsignal.com"
+ ],
+ "wpmudev.com": [
+ "curtin.edu.au",
+ "familydoctor.org"
+ ],
+ "wsod.com": [
+ "reuters.com",
+ "cnbc.com",
+ "ft.com"
+ ],
+ "wt-eu02.net": [
+ "libero.it",
+ "virgilio.it",
+ "telekom.com"
+ ],
+ "wufoo.com": [
+ "redcrossblood.org"
+ ],
+ "wzrkt.com": [
+ "indianexpress.com",
+ "thehindu.com",
+ "espncricinfo.com"
+ ],
+ "xesimg.com": [
+ "xueersi.com"
+ ],
+ "xg4ken.com": [
+ "williams-sonoma.com",
+ "courier-journal.com",
+ "logitech.com"
+ ],
+ "xhuc.net": [
+ "cabelas.com"
+ ],
+ "xinhuanet.com": [
+ "news.cn"
+ ],
+ "xinnet.com": [
+ "idianfa.com"
+ ],
+ "xiti.com": [
+ "dw.com",
+ "accor.com",
+ "ovh.com"
+ ],
+ "xiu123.cn": [
+ "6.cn"
+ ],
+ "xlisting.jp": [
+ "rakuten.co.jp",
+ "goo.ne.jp",
+ "ocn.ne.jp"
+ ],
+ "xspadvertising.com": [
+ "sourceforge.net",
+ "deloitte.com",
+ "knowyourmeme.com"
+ ],
+ "xtremepush.com": [
+ "digikala.com",
+ "rte.ie",
+ "premierbet.co.ao"
+ ],
+ "xunlei.com": [
+ "sandai.net"
+ ],
+ "xxxlutz.de": [
+ "t-online.de"
+ ],
+ "yad2.co.il": [
+ "walla.co.il"
+ ],
+ "yadro.ru": [
+ "mail.ru",
+ "ok.ru",
+ "rt.com"
+ ],
+ "yahoo.co.jp": [
+ "dropbox.com",
+ "rakuten.co.jp",
+ "slack.com"
+ ],
+ "yahoo.com": [
+ "amazon.com",
+ "tumblr.com",
+ "msn.com"
+ ],
+ "yahoo.net": [
+ "paulgraham.com"
+ ],
+ "yandex.ru": [
+ "tribunnews.com",
+ "mail.ru",
+ "aparat.com"
+ ],
+ "yapfiles.ru": [
+ "yaplakal.com"
+ ],
+ "yccdn.com": [
+ "bitauto.com"
+ ],
+ "yektanet.com": [
+ "varzesh3.com",
+ "donya-e-eqtesad.com",
+ "tejaratnews.com"
+ ],
+ "yellowblue.io": [
+ "aol.com"
+ ],
+ "yiche.com": [
+ "bitauto.com"
+ ],
+ "yieldify.com": [
+ "teespring.com"
+ ],
+ "yieldlab.net": [
+ "okezone.com",
+ "statista.com",
+ "businessinsider.de"
+ ],
+ "yieldmanager.com": [
+ "ipage.com",
+ "tsite.jp"
+ ],
+ "yieldmo.com": [
+ "foreignpolicy.com",
+ "mobafire.com",
+ "woot.com"
+ ],
+ "yieldoptimizer.com": [
+ "marriott.com",
+ "united.com",
+ "fourseasons.com"
+ ],
+ "yodasoft.in": [
+ "sakshi.com"
+ ],
+ "yomedia.vn": [
+ "thethao247.vn"
+ ],
+ "yonhapnews.co.kr": [
+ "yna.co.kr"
+ ],
+ "yoox.it": [
+ "yoox.com",
+ "mrporter.com",
+ "theoutnet.com"
+ ],
+ "yotpo.com": [
+ "threadless.com",
+ "colourpop.com",
+ "splice.com"
+ ],
+ "youdemai.com": [
+ "lenovo.com.cn"
+ ],
+ "youku.com": [
+ "bshare.cn"
+ ],
+ "youplay.se": [
+ "thelocal.se"
+ ],
+ "youtube-nocookie.com": [
+ "drupal.org",
+ "last.fm",
+ "tmz.com"
+ ],
+ "youtube.com": [
+ "apache.org",
+ "github.com",
+ "who.int",
+ "jabra.com",
+ "hirufm.lk"
+ ],
+ "youvisit.com": [
+ "fsu.edu",
+ "uh.edu",
+ "vcu.edu"
+ ],
+ "yumpu.com": [
+ "vanguardngr.com"
+ ],
+ "yunaq.com": [
+ "eqxiu.com",
+ "bt.cn",
+ "youzan.com"
+ ],
+ "yystatic.com": [
+ "yy.com"
+ ],
+ "z-analytics.net": [
+ "zmags.com"
+ ],
+ "z6rjha.net": [
+ "techsmith.com"
+ ],
+ "zadn.vn": [
+ "zingnews.vn"
+ ],
+ "zaius.com": [
+ "sothebys.com"
+ ],
+ "zalo.me": [
+ "zingnews.vn",
+ "baomoi.com",
+ "zingmp3.vn"
+ ],
+ "zaloapp.com": [
+ "zingnews.vn",
+ "baomoi.com"
+ ],
+ "zara.net": [
+ "zara.com"
+ ],
+ "zarabotkipro.ru": [
+ "vz.ru"
+ ],
+ "zdbb.net": [
+ "speedtest.net",
+ "mashable.com",
+ "pcmag.com"
+ ],
+ "zdmimg.com": [
+ "smzdm.com"
+ ],
+ "zebestof.com": [
+ "webself.net",
+ "journaldunet.com"
+ ],
+ "zedo.com": [
+ "alwafd.news",
+ "thehindu.com",
+ "indiatoday.in"
+ ],
+ "zemanta.com": [
+ "thehill.com",
+ "farfetch.com",
+ "newsmax.com"
+ ],
+ "zendesk.com": [
+ "neilpatel.com",
+ "bugsnag.com",
+ "folgory.com"
+ ],
+ "zengenti.com": [
+ "nottingham.ac.uk"
+ ],
+ "zeotap.com": [
+ "amazon.com",
+ "geeksforgeeks.org",
+ "skyrock.com"
+ ],
+ "zergnet.com": [
+ "marketwatch.com",
+ "wegotthiscovered.com",
+ "knowyourmeme.com"
+ ],
+ "zero.kz": [
+ "kundelik.kz",
+ "egov.kz"
+ ],
+ "zeronaught.com": [
+ "chipotle.com"
+ ],
+ "zg-api.com": [
+ "trulia.com"
+ ],
+ "zhugeapi.net": [
+ "processon.com"
+ ],
+ "zhugeio.com": [
+ "tmtpost.com"
+ ],
+ "ziffdavis.com": [
+ "extremetech.com"
+ ],
+ "ziftsolutions.com": [
+ "netacad.com"
+ ],
+ "zimmo.be": [
+ "nieuwsblad.be",
+ "standaard.be"
+ ],
+ "zineone.com": [
+ "kohls.com"
+ ],
+ "zippyfrog.co": [
+ "bitly.com"
+ ],
+ "zipwiresw.com": [
+ "metopera.org"
+ ],
+ "zoho.com": [
+ "runsignup.com",
+ "xmission.com"
+ ],
+ "zoho.in": [
+ "zoho.com"
+ ],
+ "zol.com.cn": [
+ "cnmo.com"
+ ],
+ "zonebourse.com": [
+ "marketscreener.com"
+ ],
+ "zoomanalytics.co": [
+ "technion.ac.il"
+ ],
+ "zoominfo.com": [
+ "appsflyer.com",
+ "eset.com",
+ "onelogin.com"
+ ],
+ "zoomph.com": [
+ "uga.edu",
+ "eatright.org"
+ ],
+ "zopim.com": [
+ "clockify.me"
+ ],
+ "zprk.io": [
+ "straitstimes.com",
+ "oneindia.com",
+ "thewrap.com"
+ ],
+ "ztsrv.com": [
+ "fullerton.edu"
+ ],
+ "zucks.net": [
+ "au.com"
+ ]
+ },
+ "version": "2020.10.2"
+} \ No newline at end of file
diff --git a/src/data/socialwidgets.json b/src/data/socialwidgets.json
new file mode 100644
index 0000000..a09893e
--- /dev/null
+++ b/src/data/socialwidgets.json
@@ -0,0 +1,266 @@
+{
+ "AddThis": {
+ "domain": "s7.addthis.com",
+ "buttonSelectors": [
+ "div.addthis_toolbox:not(:empty)"
+ ],
+ "replacementButton": {
+ "details": "<!-- AddThis Button BEGIN --> <div class='addthis_toolbox addthis_default_style addthis_32x32_style'> <a class='addthis_button_preferred_1'></a> <a class='addthis_button_preferred_2'></a> <a class='addthis_button_preferred_3'></a> <a class='addthis_button_preferred_4'></a> <a class='addthis_button_compact'></a> <a class='addthis_counter addthis_bubble_style'></a> </div> <script type='text/javascript'>var addthis_config = {'data_track_addressbar':true};</script> <script type='text/javascript' src='//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-522d600d3b535ebf'></script> <!-- AddThis Button END -->",
+ "unblockDomains": [
+ "s7.addthis.com",
+ "ct1.addthis.com",
+ "api-public.addthis.com"
+ ],
+ "imagePath": "AddThis.svg",
+ "type": 2
+ }
+ },
+ "Coub Player": {
+ "domain": "coub.com",
+ "buttonSelectors": [
+ "iframe[src^='//coub.com/embed/']"
+ ],
+ "replacementButton": {
+ "unblockDomains": [
+ "coub.com"
+ ],
+ "type": 3
+ }
+ },
+ "Digg": {
+ "domain": "widgets.digg.com",
+ "buttonSelectors": [
+ ".DiggThisButton"
+ ],
+ "replacementButton": {
+ "details": "http://www.digg.com/submit?url=",
+ "imagePath": "Digg.svg",
+ "type": 0
+ }
+ },
+ "Disqus": {
+ "domains": [
+ "disqus.com",
+ "*.disqus.com"
+ ],
+ "buttonSelectors": [
+ "div#disqus_thread"
+ ],
+ "scriptSelectors": [
+ "script[src*='.disqus.com/embed.js']"
+ ],
+ "replacementButton": {
+ "unblockDomains": [
+ "*.disqus.com",
+ "disqus.com"
+ ],
+ "type": 4
+ }
+ },
+ "Facebook Comments": {
+ "domain": "www.facebook.com",
+ "buttonSelectors": [
+ "div.fb-comments.fb_iframe_widget"
+ ],
+ "replacementButton": {
+ "unblockDomains": [
+ "www.facebook.com"
+ ],
+ "type": 3
+ }
+ },
+ "Facebook Like": {
+ "domain": "www.facebook.com",
+ "buttonSelectors": [
+ "fb\\:like",
+ "iframe[src*='://www.facebook.com/plugins/like.php']",
+ "iframe[src*='://www.facebook.com/v2.0/plugins/like.php']",
+ ".fb-like"
+ ],
+ "replacementButton": {
+ "details": "https://www.facebook.com/plugins/like.php?href=",
+ "unblockDomains": [
+ "www.facebook.com"
+ ],
+ "imagePath": "FacebookLike.svg",
+ "type": 1
+ }
+ },
+ "Facebook Share": {
+ "domain": "www.facebook.com",
+ "buttonSelectors": [
+ "fb\\:share_button",
+ "iframe[src*='://www.facebook.com/plugins/share_button.php']",
+ "iframe[src*='://www.facebook.com/v2.0/plugins/share_button.php']",
+ ".fb-share-button"
+ ],
+ "replacementButton": {
+ "details": "https://www.facebook.com/plugins/share_button.php?href=",
+ "unblockDomains": [
+ "www.facebook.com"
+ ],
+ "imagePath": "FacebookShare.svg",
+ "type": 1
+ }
+ },
+ "Facebook Video": {
+ "domain": "www.facebook.com",
+ "buttonSelectors": [
+ "iframe[src^='https://www.facebook.com/plugins/video.php?']"
+ ],
+ "replacementButton": {
+ "unblockDomains": [
+ "www.facebook.com"
+ ],
+ "type": 3
+ }
+ },
+ "Google reCAPTCHA": {
+ "domains": [
+ "google.com",
+ "www.google.com"
+ ],
+ "buttonSelectors": [
+ "div.g-recaptcha",
+ "div#g-recaptcha",
+ "fieldset#g-recaptcha"
+ ],
+ "scriptSelectors": [
+ "script[src^='//google.com/recaptcha/api.js']",
+ "script[src^='https://google.com/recaptcha/api.js']",
+ "script[src^='https://www.google.com/recaptcha/api.js']"
+ ],
+ "fallbackScriptUrl": "//google.com/recaptcha/api.js",
+ "replacementButton": {
+ "unblockDomains": [
+ "google.com",
+ "www.google.com"
+ ],
+ "type": 4
+ }
+ },
+ "LinkedIn": {
+ "domain": "platform.linkedin.com",
+ "buttonSelectors": [
+ "script[type='in/share']"
+ ],
+ "replacementButton": {
+ "details": "http://www.linkedin.com/shareArticle?mini=true&url=",
+ "imagePath": "LinkedIn.svg",
+ "type": 0
+ }
+ },
+ "Pinterest": {
+ "domain": "assets.pinterest.com",
+ "buttonSelectors": [
+ "script[src='//assets.pinterest.com/js/pinit.js']",
+ ".pin-it-button"
+ ],
+ "replacementButton": {
+ "details": "http://pinterest.com/pin/create/button/?url=",
+ "imagePath": "Pinterest.svg",
+ "type": 0
+ }
+ },
+ "SoundCloud": {
+ "domain": "w.soundcloud.com",
+ "buttonSelectors": [
+ "iframe[src^='https://w.soundcloud.com/player']"
+ ],
+ "replacementButton": {
+ "unblockDomains": [
+ "w.soundcloud.com"
+ ],
+ "type": 3
+ }
+ },
+ "Spotify Player": {
+ "domains": [
+ "embed.spotify.com",
+ "open.spotify.com"
+ ],
+ "buttonSelectors": [
+ "iframe[src^='https://embed.spotify.com/']",
+ "iframe[src^='https://open.spotify.com/embed']"
+ ],
+ "replacementButton": {
+ "unblockDomains": [
+ "embed.spotify.com",
+ "open.spotify.com"
+ ],
+ "type": 3
+ }
+ },
+ "Streamable Player": {
+ "domain": "streamable.com",
+ "buttonSelectors": [
+ "iframe[src^='https://streamable.com/']"
+ ],
+ "replacementButton": {
+ "unblockDomains": [
+ "streamable.com"
+ ],
+ "type": 3
+ }
+ },
+ "Twitch Player": {
+ "domain": "player.twitch.tv",
+ "buttonSelectors": [
+ "iframe[src^='https://player.twitch.tv/']",
+ "iframe[src^='//player.twitch.tv/']"
+ ],
+ "replacementButton": {
+ "unblockDomains": [
+ "player.twitch.tv"
+ ],
+ "type": 3
+ }
+ },
+ "Twitter": {
+ "domain": "platform.twitter.com",
+ "buttonSelectors": [
+ ".twitter-share-button"
+ ],
+ "replacementButton": {
+ "details": "https://twitter.com/intent/tweet?url=",
+ "imagePath": "Twitter.svg",
+ "type": 0
+ }
+ },
+ "Vimeo": {
+ "domain": "player.vimeo.com",
+ "buttonSelectors": [
+ "iframe[src^='https://player.vimeo.com/video/']:not([src*='background=1'])",
+ "iframe[src^='//player.vimeo.com/video/']:not([src*='background=1'])"
+ ],
+ "replacementButton": {
+ "unblockDomains": [
+ "player.vimeo.com"
+ ],
+ "type": 3
+ }
+ },
+ "YouTube": {
+ "domains": [
+ "youtube.com",
+ "www.youtube.com",
+ "www.youtube-nocookie.com"
+ ],
+ "buttonSelectors": [
+ "iframe[src^='//www.youtube.com/embed/']",
+ "iframe[src^='http://www.youtube.com/embed/']",
+ "iframe[src^='https://www.youtube.com/embed/']",
+ "iframe[src^='https://youtube.com/embed/']",
+ "iframe[src^='//www.youtube-nocookie.com/embed/']",
+ "iframe[src^='https://www.youtube-nocookie.com/embed/']"
+ ],
+ "replacementButton": {
+ "unblockDomains": [
+ "youtube.com",
+ "www.youtube.com",
+ "www.youtube-nocookie.com"
+ ],
+ "type": 3
+ }
+ }
+}
diff --git a/src/data/surrogates.js b/src/data/surrogates.js
new file mode 100644
index 0000000..eb46d1b
--- /dev/null
+++ b/src/data/surrogates.js
@@ -0,0 +1,474 @@
+/*
+ *
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2016 Electronic Frontier Foundation
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+require.scopes.surrogatedb = (function() {
+
+/**
+ * A hostname can have one or more surrogate scripts.
+ *
+ * "hostnames" maps hostnames to surrogate pattern tokens.
+ *
+ * Surrogate pattern tokens are used to look up the actual
+ * surrogate script code (stored in "surrogates" object below).
+ *
+ * There are currently two types of surrogate pattern tokens:
+ *
+ * - {Array} one or more suffix tokens:
+ * Does the script URL (querystring excluded) end with the token?
+ *
+ * - {String} wildcard token:
+ * Matches any script URL for the hostname.
+ */
+const hostnames = {
+ 'b.scorecardresearch.com': [
+ '/beacon.js',
+ '/c2/plugins/streamsense_plugin_html5.js',
+ ],
+ 'sb.scorecardresearch.com': [
+ '/beacon.js',
+ '/c2/plugins/streamsense_plugin_html5.js',
+ ],
+ 'ssl.google-analytics.com': [
+ '/ga.js',
+ '/analytics.js',
+ ],
+ 'www.google-analytics.com': [
+ '/analytics.js',
+ '/ga.js',
+ ],
+ 'www.googletagservices.com': [
+ '/gpt.js',
+ ],
+ 'api.youneeq.ca': [
+ '/app/yqmin',
+ ],
+ 'cdn.krxd.net': 'noopjs',
+ 'widgets.outbrain.com': '/outbrain.js',
+};
+
+/**
+ * "surrogates" maps surrogate pattern tokens to surrogate script code.
+ */
+const surrogates = {
+ /* eslint-disable no-extra-semi, space-in-parens */
+
+ // Google Analytics (legacy ga.js)
+ //
+ // sourced from https://github.com/uBlockOrigin/uAssets/ under GPLv3
+ // https://github.com/uBlockOrigin/uAssets/blob/2dfeece7cfe671e93573db6d176901cf2df37623/filters/resources.txt#L162-L260
+ //
+ // test cases:
+ // http://checkin.avianca.com/
+ // https://www.vmware.com/support/pubs/ws_pubs.html (release notes links)
+ //
+ // API reference:
+ // https://developers.google.com/analytics/devguides/collection/gajs/methods/
+ '/ga.js': '(' +
+ function() {
+ var noopfn = function() {
+ ;
+ };
+ //
+ var Gaq = function() {
+ ;
+ };
+ Gaq.prototype.Na = noopfn;
+ Gaq.prototype.O = noopfn;
+ Gaq.prototype.Sa = noopfn;
+ Gaq.prototype.Ta = noopfn;
+ Gaq.prototype.Va = noopfn;
+ Gaq.prototype._createAsyncTracker = noopfn;
+ Gaq.prototype._getAsyncTracker = noopfn;
+ Gaq.prototype._getPlugin = noopfn;
+ Gaq.prototype.push = function(a) {
+ if ( typeof a === 'function' ) {
+ a(); return;
+ }
+ if ( Array.isArray(a) === false ) {
+ return;
+ }
+ // https://twitter.com/catovitch/status/776442930345218048
+ // https://developers.google.com/analytics/devguides/collection/gajs/methods/gaJSApiDomainDirectory#_gat.GA_Tracker_._link
+ if ( a[0] === '_link' && typeof a[1] === 'string' ) {
+ window.location.assign(a[1]);
+ }
+ // https://github.com/gorhill/uBlock/issues/2162
+ if ( a[0] === '_set' && a[1] === 'hitCallback' && typeof a[2] === 'function' ) {
+ a[2]();
+ }
+ };
+ //
+ var tracker = (function() {
+ var out = {};
+ var api = [
+ '_addIgnoredOrganic _addIgnoredRef _addItem _addOrganic',
+ '_addTrans _clearIgnoredOrganic _clearIgnoredRef _clearOrganic',
+ '_cookiePathCopy _deleteCustomVar _getName _setAccount',
+ '_getAccount _getClientInfo _getDetectFlash _getDetectTitle',
+ '_getLinkerUrl _getLocalGifPath _getServiceMode _getVersion',
+ '_getVisitorCustomVar _initData _link _linkByPost',
+ '_setAllowAnchor _setAllowHash _setAllowLinker _setCampContentKey',
+ '_setCampMediumKey _setCampNameKey _setCampNOKey _setCampSourceKey',
+ '_setCampTermKey _setCampaignCookieTimeout _setCampaignTrack _setClientInfo',
+ '_setCookiePath _setCookiePersistence _setCookieTimeout _setCustomVar',
+ '_setDetectFlash _setDetectTitle _setDomainName _setLocalGifPath',
+ '_setLocalRemoteServerMode _setLocalServerMode _setReferrerOverride _setRemoteServerMode',
+ '_setSampleRate _setSessionTimeout _setSiteSpeedSampleRate _setSessionCookieTimeout',
+ '_setVar _setVisitorCookieTimeout _trackEvent _trackPageLoadTime',
+ '_trackPageview _trackSocial _trackTiming _trackTrans',
+ '_visitCode'
+ ].join(' ').split(/\s+/);
+ var i = api.length;
+ while ( i-- ) {
+ out[api[i]] = noopfn;
+ }
+ out._getLinkerUrl = function(a) {
+ return a;
+ };
+ return out;
+ })();
+ //
+ var Gat = function() {
+ ;
+ };
+ Gat.prototype._anonymizeIP = noopfn;
+ Gat.prototype._createTracker = noopfn;
+ Gat.prototype._forceSSL = noopfn;
+ Gat.prototype._getPlugin = noopfn;
+ Gat.prototype._getTracker = function() {
+ return tracker;
+ };
+ Gat.prototype._getTrackerByName = function() {
+ return tracker;
+ };
+ Gat.prototype._getTrackers = noopfn;
+ Gat.prototype.aa = noopfn;
+ Gat.prototype.ab = noopfn;
+ Gat.prototype.hb = noopfn;
+ Gat.prototype.la = noopfn;
+ Gat.prototype.oa = noopfn;
+ Gat.prototype.pa = noopfn;
+ Gat.prototype.u = noopfn;
+ var gat = new Gat();
+ window._gat = gat;
+ //
+ var gaq = new Gaq();
+ (function() {
+ var aa = window._gaq || [];
+ if ( Array.isArray(aa) ) {
+ while ( aa[0] ) {
+ gaq.push(aa.shift());
+ }
+ }
+ })();
+ window._gaq = gaq.qf = gaq;
+ } + ')();',
+
+ // https://github.com/gorhill/uBlock/issues/1265
+ // https://github.com/uBlockOrigin/uAssets/blob/581f2c93eeca0e55991aa331721b6942f3162615/filters/resources.txt#L736-L746
+ /* eslint-disable no-undef */
+ '/beacon.js': '(' +
+ function() {
+ window.COMSCORE = {
+ purge: function() {
+ _comscore = [];
+ },
+ beacon: function() {
+ ;
+ }
+ };
+ } + ')();',
+ /* eslint-enable no-undef */
+
+ // http://www.dplay.se/ett-jobb-for-berg/ (videos)
+ '/c2/plugins/streamsense_plugin_html5.js': '(' +
+ function() {
+ } + ')();',
+
+ // https://github.com/EFForg/privacybadger/issues/993
+ // https://github.com/uBlockOrigin/uAssets/blob/2bc97541b3b9a9380b3ce8bd2242375925df293c/filters/resources.txt#L436-L567
+ /* eslint-disable no-empty */
+ '/gpt.js': '(' +
+ function() {
+ var p;
+ // https://developers.google.com/doubleclick-gpt/reference
+ var noopfn = function() {
+ ;
+ }.bind();
+ var noopthisfn = function() {
+ return this;
+ };
+ var noopnullfn = function() {
+ return null;
+ };
+ var nooparrayfn = function() {
+ return [];
+ };
+ var noopstrfn = function() {
+ return '';
+ };
+ //
+ var companionAdsService = {
+ addEventListener: noopthisfn,
+ enableSyncLoading: noopfn,
+ setRefreshUnfilledSlots: noopfn
+ };
+ var contentService = {
+ addEventListener: noopthisfn,
+ setContent: noopfn
+ };
+ var PassbackSlot = function() {
+ ;
+ };
+ p = PassbackSlot.prototype;
+ p.display = noopfn;
+ p.get = noopnullfn;
+ p.set = noopthisfn;
+ p.setClickUrl = noopthisfn;
+ p.setTagForChildDirectedTreatment = noopthisfn;
+ p.setTargeting = noopthisfn;
+ p.updateTargetingFromMap = noopthisfn;
+ var pubAdsService = {
+ addEventListener: noopthisfn,
+ clear: noopfn,
+ clearCategoryExclusions: noopthisfn,
+ clearTagForChildDirectedTreatment: noopthisfn,
+ clearTargeting: noopthisfn,
+ collapseEmptyDivs: noopfn,
+ defineOutOfPagePassback: function() { return new PassbackSlot(); },
+ definePassback: function() { return new PassbackSlot(); },
+ disableInitialLoad: noopfn,
+ display: noopfn,
+ enableAsyncRendering: noopfn,
+ enableSingleRequest: noopfn,
+ enableSyncRendering: noopfn,
+ enableVideoAds: noopfn,
+ get: noopnullfn,
+ getAttributeKeys: nooparrayfn,
+ getTargeting: noopfn,
+ getTargetingKeys: nooparrayfn,
+ getSlots: nooparrayfn,
+ refresh: noopfn,
+ set: noopthisfn,
+ setCategoryExclusion: noopthisfn,
+ setCentering: noopfn,
+ setCookieOptions: noopthisfn,
+ setForceSafeFrame: noopthisfn,
+ setLocation: noopthisfn,
+ setPublisherProvidedId: noopthisfn,
+ setRequestNonPersonalizedAds: noopthisfn,
+ setSafeFrameConfig: noopthisfn,
+ setTagForChildDirectedTreatment: noopthisfn,
+ setTargeting: noopthisfn,
+ setVideoContent: noopthisfn,
+ updateCorrelator: noopfn
+ };
+ var SizeMappingBuilder = function() {
+ ;
+ };
+ p = SizeMappingBuilder.prototype;
+ p.addSize = noopthisfn;
+ p.build = noopnullfn;
+ var Slot = function() {
+ ;
+ };
+ p = Slot.prototype;
+ p.addService = noopthisfn;
+ p.clearCategoryExclusions = noopthisfn;
+ p.clearTargeting = noopthisfn;
+ p.defineSizeMapping = noopthisfn;
+ p.get = noopnullfn;
+ p.getAdUnitPath = nooparrayfn;
+ p.getAttributeKeys = nooparrayfn;
+ p.getCategoryExclusions = nooparrayfn;
+ p.getDomId = noopstrfn;
+ p.getSlotElementId = noopstrfn;
+ p.getSlotId = noopthisfn;
+ p.getTargeting = nooparrayfn;
+ p.getTargetingKeys = nooparrayfn;
+ p.set = noopthisfn;
+ p.setCategoryExclusion = noopthisfn;
+ p.setClickUrl = noopthisfn;
+ p.setCollapseEmptyDiv = noopthisfn;
+ p.setTargeting = noopthisfn;
+ //
+ var gpt = window.googletag || {};
+ var cmd = gpt.cmd || [];
+ gpt.apiReady = true;
+ gpt.cmd = [];
+ gpt.cmd.push = function(a) {
+ try {
+ a();
+ } catch (ex) {
+ }
+ return 1;
+ };
+ gpt.companionAds = function() { return companionAdsService; };
+ gpt.content = function() { return contentService; };
+ gpt.defineOutOfPageSlot = function() { return new Slot(); };
+ gpt.defineSlot = function() { return new Slot(); };
+ gpt.destroySlots = noopfn;
+ gpt.disablePublisherConsole = noopfn;
+ gpt.display = noopfn;
+ gpt.enableServices = noopfn;
+ gpt.getVersion = noopstrfn;
+ gpt.pubads = function() { return pubAdsService; };
+ gpt.pubadsReady = true;
+ gpt.setAdIframeTitle = noopfn;
+ gpt.sizeMapping = function() { return new SizeMappingBuilder(); };
+ window.googletag = gpt;
+ while ( cmd.length !== 0 ) {
+ gpt.cmd.push(cmd.shift());
+ }
+ } + ')();',
+ /* eslint-enable no-empty */
+
+ // https://github.com/EFForg/privacybadger/issues/1014
+ /* eslint-disable no-unused-expressions */
+ '/app/yqmin': '(' +
+ function() {
+ var noopfn = function() {
+ ;
+ };
+ function YqClass() {
+ this.observe = noopfn;
+ this.observeMin = noopfn;
+ this.scroll_event = noopfn;
+ this.onready = noopfn;
+ this.yq_panel_click = noopfn;
+ this.titleTrim = noopfn;
+ }
+ window.Yq || (window.Yq = new YqClass);
+ } + ')();',
+ /* eslint-enable no-unused-expressions */
+
+ // https://github.com/uBlockOrigin/uAssets/blob/0e225402b40db0983faf8b4ce13c73d57fb257d7/filters/resources.txt#L354-L403
+ /* eslint-disable no-empty */
+ '/analytics.js': '(' +
+ function() {
+ // https://developers.google.com/analytics/devguides/collection/analyticsjs/
+ var noopfn = function() {
+ ;
+ };
+ var noopnullfn = function() {
+ return null;
+ };
+ //
+ var Tracker = function() {
+ ;
+ };
+ var p = Tracker.prototype;
+ p.get = noopfn;
+ p.set = noopfn;
+ p.send = noopfn;
+ //
+ var w = window,
+ gaName = w.GoogleAnalyticsObject || 'ga';
+ var ga = function() {
+ var len = arguments.length;
+ if ( len === 0 ) {
+ return;
+ }
+ var f = arguments[len-1];
+ if ( typeof f !== 'object' || f === null || typeof f.hitCallback !== 'function' ) {
+ return;
+ }
+ try {
+ f.hitCallback();
+ } catch (ex) {
+ }
+ };
+ ga.create = function() {
+ return new Tracker();
+ };
+ ga.getByName = noopnullfn;
+ ga.getAll = function() {
+ return [];
+ };
+ ga.remove = noopfn;
+ // https://github.com/uBlockOrigin/uAssets/issues/2107
+ ga.loaded = true;
+ w[gaName] = ga;
+ // https://github.com/gorhill/uBlock/issues/3075
+ var dl = w.dataLayer;
+ if ( dl instanceof Object && dl.hide instanceof Object && typeof dl.hide.end === 'function' ) {
+ dl.hide.end();
+ }
+ } + ')();',
+ /* eslint-enable no-empty */
+
+ // https://github.com/uBlockOrigin/uAssets/blob/d7d4836638dcf227938b4cead66ad9d01b6166ba/filters/resources.txt#L843-L868
+ '/outbrain.js': '(' +
+ function() {
+ var noopfn = function() {
+ ;
+ };
+ var obr = {};
+ var methods = [
+ 'callClick', 'callLoadMore', 'callRecs', 'callUserZapping',
+ 'callWhatIs', 'cancelRecommendation', 'cancelRecs', 'closeCard',
+ 'closeModal', 'closeTbx', 'errorInjectionHandler', 'getCountOfRecs',
+ 'getStat', 'imageError', 'manualVideoClicked', 'onOdbReturn',
+ 'onVideoClick', 'pagerLoad', 'recClicked', 'refreshSpecificWidget',
+ 'refreshWidget', 'reloadWidget', 'researchWidget', 'returnedError',
+ 'returnedHtmlData', 'returnedIrdData', 'returnedJsonData', 'scrollLoad',
+ 'showDescription', 'showRecInIframe', 'userZappingMessage', 'zappingFormAction'
+ ];
+ obr.extern = {
+ video: {
+ getVideoRecs: noopfn,
+ videoClicked: noopfn
+ }
+ };
+ methods.forEach(function(a) {
+ obr.extern[a] = noopfn;
+ });
+ window.OBR = window.OBR || obr;
+ } + ')();',
+
+ // https://github.com/uBlockOrigin/uAssets/blob/0efcadb2ecc2a9f0daa5a1df79841d794b83860f/filters/resources.txt#L38-L41
+ 'noopjs': '(' +
+ function() {
+ ;
+ } + ')();',
+
+ /* eslint-enable no-extra-semi, space-in-parens */
+};
+
+// aliases
+// for example:
+// surrogates['/JS/socialize.js'] = surrogates['/JS/gigya.js'] = surrogates['/js/gigya.js'];
+
+// reformat surrogate strings to exactly match formatting in uAssets
+Object.keys(surrogates).forEach(key => {
+ surrogates[key] = surrogates[key]
+ // remove space from anon function if present
+ .replace(/^\(function \(/, '(function(')
+ // fix indentation
+ .split(/[\r\n]/).map(str => str.replace(/^ {4}/, '')).join('\n')
+ // replace spaces by tabs
+ .replace(/ {2}/g, '\t');
+});
+
+const exports = {
+ hostnames: hostnames,
+ surrogates: surrogates,
+};
+
+return exports;
+})();
diff --git a/src/data/yellowlist.txt b/src/data/yellowlist.txt
new file mode 100644
index 0000000..935a75c
--- /dev/null
+++ b/src/data/yellowlist.txt
@@ -0,0 +1,788 @@
+nosdn.127.net
+bnet.163.com
+122.2o7.net
+112.2o7.net
+acast.com
+accuweather.com
+actionnetwork.org
+imagesrv.adition.com
+auth.adobe.com
+wwwimages.adobe.com
+xsdownload.adobe.com
+assets.adobedtm.com
+adyen.com
+affirm.com
+akamai.net
+akamaihd.net
+akamaized.net
+alexa.com
+alicdn.com
+ally.com
+amazon.com
+s3.amazonaws.com
+amazonaws.com
+coin.amazonpay.com
+coin-eu.amazonpay.com
+americanexpress.com
+amuniversal.com
+ancestry.com
+angularjs.org
+up.anv.bz
+anvato.net
+tkx-acc.apis.anvato.net
+cdn.anvato.net
+tkx2-prod.anvato.net
+mcp-media5.anvato.net
+aol.com
+aolcdn.com
+ap.org
+apnewsregistry.com
+apple.com
+hiroservers.appspot.com
+snapabug.appspot.com
+appspot.com
+arcgis.com
+arcgisonline.com
+archive.org
+secure5.arcot.com
+arcot.com
+arcpublishing.com
+arkoselabs.com
+cdn.arstechnica.net
+art19.com
+aspnetcdn.com
+c64.assets-yammer.com
+assetfiles.com
+assets-cdk.com
+auth0.com
+authorize.net
+azureedge.net
+bac-assets.com
+hiphotos.baidu.com
+imgsa.baidu.com
+imgsrc.baidu.com
+api.map.baidu.com
+sapi.map.baidu.com
+bandcamp.com
+bankid.no
+bankrate.com
+secure.barclaycard.co.uk
+verifiedbyvisa.barclays.co.uk
+bazaarvoice.com
+bcbits.com
+maponline0.bdimg.com
+maponline1.bdimg.com
+maponline2.bdimg.com
+maponline3.bdimg.com
+betterttv.net
+static.beyondmenu.com
+www.beyondmenu.com
+bigcommerce.com
+www.bing.com
+bit.ly
+bizrate.com
+blockstack.org
+blogblog.com
+blogger.com
+blogspot.com
+bp.blogspot.com
+bloxcms.com
+boldchat.com
+bootstrapcdn.com
+braintreegateway.com
+brcdn.com
+breakingburner.com
+brightcove.com
+players.brightcove.net
+bungie.net
+buzzfed.com
+buzzfeed.com
+cachefly.net
+calendly.com
+cardinalcommerce.com
+cbsi.com
+cbsimg.net
+cbsistatic.com
+cdninstagram.com
+cdnpk.com
+cern.ch
+ceros.com
+charter.com
+pwc.chase.com
+civicscience.com
+cleanprint.net
+cleveland.com
+cloudflare.com
+cloudfront.net
+cloudinary.com
+bbb.org
+bbc.co.uk
+bbci.co.uk
+w.graphiq.com
+s.graphiq.com
+s2.graphiq.com
+s3.graphiq.com
+files.graphiq.com
+gr-assets.com
+guardian.co.uk
+media-imdb.com
+mediaworks.co.nz
+cc.cnetcontent.com
+cdn.cnetcontent.com
+ws.cnetcontent.com
+codepen.io
+codesandbox.io
+cloudplatform.coveo.com
+platform.cloud.coveo.com
+static.cloud.coveo.com
+creativecommons.org
+cstv.com
+cursecdn.com
+custhelp.com
+d3js.org
+dailymotion.com
+danid.dk
+dealer.com
+dealerinspire.com
+delicious.com
+delvenetworks.com
+deviantart.com
+deviantart.net
+digitalriver.com
+digitalrivercontent.net
+cdn.discourse.org
+discovery.com
+disquscdn.com
+dmcdn.net
+dmcdn.com
+screendoor.dobt.co
+documentcloud.org
+donorbox.org
+cdn.dopc.cz
+dotsub.com
+dl.dropboxusercontent.com
+dumpert.nl
+duosecurity.com
+cdn.dynamicyield.com
+cdn-eu.dynamicyield.com
+rcom.dynamicyield.com
+rcom-eu.dynamicyield.com
+static.dynamicyield.com
+st.dynamicyield.com
+st-eu.dynamicyield.com
+ebay.com
+ebayimg.com
+ebayrtm.com
+ebaystatic.com
+ecwid.com
+edgecastcdn.net
+edgefcs.net
+edgekey.net
+editmysite.com
+files.edx.org
+ehc.com
+elasticbeanstalk.com
+eltrafiko.com
+api-cdn.embed.ly
+api.embed.ly
+cdn.embed.ly
+cdn.embedly.com
+i-cdn.embed.ly
+i.embed.ly
+pp.ephapay.net
+epoch.com
+epoq.de
+et4.de
+ethn.io
+evcdn.com
+eventbrite.com
+everyaction.com
+s-static.ak.facebook.com
+staticxx.facebook.com
+www.facebook.com
+fansonly.com
+travis-ci-org.global.ssl.fastly.net
+fastly.net
+fbcdn.net
+attachment.fbsbx.com
+feedburner.com
+filepicker.io
+filestackapi.com
+financialcontent.com
+findnsave.com
+firstlook.org
+flipcause.com
+framasoft.org
+frankerfacez.com
+freshchat.com
+frz.io
+build.origami.ft.com
+fz.io
+fzcdn.net
+hello.firefox.com
+flattr.com
+flickr.com
+fling.com
+flo.uri.sh
+flowplayer.org
+flyertown.ca
+adm.fwmrm.net
+fontawesome.com
+fontdeck.com
+fonts.com
+fonts.net
+force.com
+formstack.com
+fuseservice.com
+140cc.v.fwmrm.net
+fyre.co
+gannett-cdn.com
+gannettonline.com
+gannett-tv.com
+gasbuddy.com
+geenstijl.nl
+geetest.com
+geoplugin.net
+geotrust.com
+getpocket.com
+giant.gfycat.com
+gfycat.com
+ggpht.com
+gigya.com
+giphy.com
+gitbook.com
+github.com
+githubusercontent.com
+gmodules.com
+godatafeed.com
+gogousenet.com
+accounts.google.com
+apis.google.com
+books.google.com
+calendar.google.com
+checkout.google.com
+clients1.google.com
+clients6.google.com
+consent.google.com
+cse.google.com
+datastudio.google.com
+developers.google.com
+docs.google.com
+drive.google.com
+feedburner.google.com
+feedproxy.google.com
+fonts.google.com
+fusiontables.google.com
+groups.google.com
+kh.google.com
+khms0.google.com
+khms1.google.com
+khms2.google.com
+khms3.google.com
+khms4.google.com
+labs.google.com
+maps-api-ssl.google.com
+mapsengine.google.com
+maps.google.com
+mt0.google.com
+mt1.google.com
+mts0.google.com
+mts1.google.com
+mw1.google.com
+mw2.google.com
+pay.google.com
+picasaweb.google.com
+play.google.com
+sites.google.com
+smartlock.google.com
+spreadsheets.google.com
+talkgadget.google.com
+translate.google.com
+trends.google.com
+video.google.com
+www.google.com
+ajax.googleapis.com
+storage.googleapis.com
+googleapis.com
+googlecode.com
+googlecommerce.com
+googletagservices.com
+cdn.leafletjs.com
+lh4.googleusercontent.com
+googleusercontent.com
+googlevideo.com
+governmentjobs.com
+gravatar.com
+greenhouse.io
+rest.growinginteractive.com
+gscdn.nl
+gstatic.com
+guildwars2.com
+hackerone-user-content.com
+hcaptcha.com
+helium.com
+herokuapp.com
+code.highcharts.com
+homestead.com
+cdn.hometogo.net
+cdn2.hometogo.net
+hootsuite.com
+api.hubspot.com
+app.hubspot.com
+cta-service-cms2.hubspot.com
+forms.hubspot.com
+js.hubspot.com
+meetings.hubspot.com
+no-cache.hubspot.com
+static.hubspot.com
+cdn2.hubspot.net
+humblebundle.com
+hwcdn.net
+hypothes.is
+ibsys.com
+icbdr.com
+mpsnare.iesnare.com
+imagecorn.com
+imageg.net
+imagehost123.com
+images-amazon.com
+imageshack.us
+imagetwist.com
+imagevenue.com
+imbox.io
+www.img-bahn.de
+imgchili.com
+imgfarm.com
+imgspice.com
+imgur.com
+imgix.net
+imshopping.com
+inergizedigital.com
+inq.com
+inscloudgate.net
+instagram.com
+instantservice.com
+instapaper.com
+instructure.com
+intellicast.com
+intensedebate.com
+intercom.io
+members.internetdefenseleague.org
+investingchannel.com
+script.ioam.de
+issuu.com
+iubenda.com
+janrain.com
+jquery.com
+jquerytools.org
+jsdelivr.net
+jsonip.com
+jtvnw.net
+justin.tv
+jwpcdn.com
+content.jwplatform.com
+cdn.jwplayer.com
+entitlements.jwplayer.com
+jwpltx.com
+jwpsrv.com
+cdnapi.kaltura.com
+cdnapisec.kaltura.com
+cdnbakmi.kaltura.com
+cdnsecakmi.kaltura.com
+cfvod.kaltura.com
+www.kaltura.com
+kampyle.com
+kataweb.it
+kickapps.com
+kickstarter.com
+kickstatic.com
+kingfeatures.com
+kinja.com
+kinja-static.com
+klarna.com
+klarnacdn.net
+klm.com
+kxcdn.com
+ddragon.leagueoflegends.com
+libsyn.com
+licdn.com
+licensebuttons.net
+addon.lidl.de
+media.lidl.com
+linkwithin.com
+list-manage.com
+i.lithium.com
+messenger.live.com
+officeapps.live.com
+onedrive.live.com
+livechatinc.com
+livefyre.com
+livehelpnow.net
+liveperson.net
+livestream.com
+llnwd.net
+loggly.com
+logos.com
+lphbs.com
+mail.ru
+mailchimp.com
+mapbox.com
+mapquestapi.com
+marketo.com
+masslive.com
+mathjax.org
+matterport.com
+maxmind.com
+mcclatchyinteractive.com
+meebocdn.net
+megaphone.fm
+mfstatic.cz
+microsoft.com
+microsoftonline.com
+microsofttranslator.com
+mixcloud.com
+mlive.com
+mncdn.com
+mobify.com
+verify.monzo.com
+loop.services.mozilla.com
+mozilla.net
+mozilla.org
+mozu.com
+mqcdn.com
+msecnd.net
+msn.com
+mtv.com
+mtvnservices.com
+mycapture.com
+myportfolio.com
+myshopify.com
+mzstatic.com
+nanorep.co
+nationbuilder.com
+nationalgeographic.com
+nbcuni.com
+neighborsink.com
+netdna-cdn.com
+netdna-ssl.com
+nos.netease.com
+netflix.com
+networksolutions.com
+newsinc.com
+newslook.com
+newstogram.com
+nextcloud.com
+nextopiasoftware.com
+nfl.com
+nflcdn.com
+assets.nflxext.com
+cdn3.nflxext.com
+nflxext.com
+ngfiles.com
+ngpvan.com
+nj.com
+nmcdn.us
+nola.com
+npmcdn.com
+nrcdn.com
+nsimg.net
+media.nu.nl
+nyt.com
+nytimes.com
+c.o0bg.com
+ocdn.eu
+ocsn.com
+okta.com
+olark.com
+omroep.nl
+amazoncustomerservice.d2.sc.omtrdc.net
+omny.fm
+attservicesinc.tt.omtrdc.net
+dsw.tt.omtrdc.net
+onswipe.com
+api.ooyala.com
+c.ooyala.com
+l.ooyala.com
+opf.ooyala.com
+player.ooyala.com
+secure-cf-c.ooyala.com
+tile.opencyclemap.org
+tile2.opencyclemap.org
+opendesktop.org
+openlayers.org
+openlibrary.org
+openload.co
+tile.openstreetmap.fr
+openstreetmap.org
+optimizely.com
+oregonlive.com
+outlook.com
+paddle.com
+pandacommerce.net
+parastorage.com
+passwordbox.com
+payments-amazon.com
+paypal.com
+paypalobjects.com
+pdf.yt
+pennlive.com
+performgroup.com
+pgcdn.com
+phncdn.com
+photobucket.com
+phplist.com
+piclens.com
+pinimg.com
+piratebay.org
+pistachio-cdn.graze.com
+pixietrixcomix.com
+plex.tv
+pling.com
+plot.ly
+web.poecdn.com
+poll.fm
+polldaddy.com
+postimg.cc
+postimg.org
+powerreviews.com
+pricegrabber.com
+printfriendly.com
+prismic.io
+providesupport.com
+psswrdbx.com
+publiekeomroep.nl
+img.purch.com
+captcha.qq.com
+photo.store.qq.com
+qualtrics.com
+queue-it.net
+quotemedia.com
+api.razorpay.com
+checkout.razorpay.com
+razorpay.com
+rackcdn.com
+rackspacecloud.com
+radikal.ru
+radiofrance.fr
+rambler.ru
+images.rapgenius.com
+readability.com
+readthedocs.org
+recaptcha.net
+recurly.com
+redcdn.pl
+reddit.com
+redditmedia.com
+redditstatic.com
+redefine.pl
+cdngeneral.rentcafe.com
+resultspage.com
+rewardstyle.com
+rpxnow.com
+rssinclude.com
+sagepay.com
+salesforce.com
+salesforceliveagent.com
+salsalabs.com
+salsalabs.org
+sbnation.com
+scene7.com
+schd.ws
+sched.org
+schibsted.com
+schibsted.io
+schibsted.no
+schibsted.tech
+scribblelive.com
+scribd.com
+scribdassets.com
+www.searchanise.com
+securesuite.co.uk
+securitymetrics.com
+seeclickfix.com
+sgizmo.com
+shopify.com
+shopping.com
+shop-pro.jp
+shoprunner.com
+sidearmsports.com
+siteimprove.com
+shield.sitelock.com
+sketchfab.com
+slidedeck.com
+public.slidesharecdn.com
+s-msft.com
+s-msn.com
+smugmug.com
+snapengage.com
+sndcdn.com
+snipcart.com
+auth.api.sonyentertainmentnetwork.com
+cdn-a.sonyentertainmentnetwork.com
+api.soundcloud.com
+feeds.soundcloud.com
+sp-prod.net
+spot.im
+springboardplatform.com
+squarespace.com
+squareup.com
+squirt.io
+ssl-images-amazon.com
+cdn.sstatic.net
+sstatic.net
+stackexchange.com
+stackoverflow.com
+staticamzn.com
+cdn.static-economist.com
+staticflickr.com
+steampowered.com
+store.akamai.steamstatic.com
+steamusercontent.com
+stripe.com
+m.stripe.network
+stripecdn.com
+surveygizmo.com
+surveymonkey.com
+swiftype.com
+public.tableau.com
+public.tableausoftware.com
+c.tadst.com
+taleo.net
+uploads.tapatalk-cdn.com
+targetimg1.com
+targetimg2.com
+tawk.to
+technorati.com
+tegna-media.com
+textalk.se
+theplatform.com
+tile.thunderforest.com
+timeinc.net
+tinypass.com
+tinypic.com
+tinyurl.com
+tiqcdn.com
+torbit.com
+townnews.com
+cookieblock.trackersimulate.org
+tradingview.com
+trb.com
+trbimg.com
+trumba.com
+privacy-policy.truste.com
+trustkeeper.net
+trustpilot.com
+trustwave.com
+ttvnw.net
+tumblr.com
+turner.com
+turnto.com
+twimg.com
+api.twisto.cz
+static.twisto.cz
+api.twisto.pl
+twitch.tv
+twitter.com
+platform.twitter.com
+syndication.twitter.com
+typeform.com
+typekit.com
+typekit.net
+typepad.com
+typography.com
+assets.ubuntu.com
+uicdn.com
+ui-portal.de
+ultimedia.com
+ultraimg.com
+unicornmedia.com
+unsplash.com
+uplynk.com
+usa.gov
+viafoura.net
+viddler.com
+videobash.com
+videodelivery.net
+vidible.tv
+viduki.com
+vidyard.com
+vimeo.com
+vimeocdn.com
+virtualearth.net
+visa.com
+vmixcore.com
+voxmedia.com
+vox-cdn.com
+w3.org
+wallst.com
+weather.com
+weather.gov
+weatherbug.com
+weathernationtv.com
+weatherzone.com.au
+webflow.com
+webs.com
+websimages.com
+website-start.de
+webtype.com
+weebly.com
+where.com
+widgetserver.com
+wikidata.org
+wikimedia.org
+wikipedia.org
+wildapricot.org
+windows.net
+windy.com
+wishabi.com
+wistia.net
+wistia.com
+wix.com
+wixapps.net
+gatherer.wizards.com
+s.w.org
+ts.w.org
+ps.w.org
+wnyc.org
+woosmap.com
+wordpress.com
+worldnow.com
+wp.com
+wpengine.com
+wufoo.com
+wxc.com
+wxug.com
+y3.analytics.yahoo.com
+pipes.yahoo.com
+search.yahoo.com
+yahoo.net
+yahooapis.com
+api-maps.yandex.ru
+img-fotki.yandex.ru
+yardbarker.com
+yastatic.net
+yellowpages.com
+seatme.yelp.com
+yelpcdn.com
+yimg.com
+yimg.jp
+yotpo.com
+yottaa.net
+youku.com
+youtube.com
+youtube-nocookie.com
+youwatch.org
+ytimg.com
+zdassets.com
+zencdn.net
+zendesk.com
+ziplist.com
+zlcdn.com
+zoho.com
+zoho.eu
+zohopublic.com
+zohostatic.com
+zombaio.com
+zope.net
+zopim.com
+zvents.com
diff --git a/src/icons/UI-icons-green.svg b/src/icons/UI-icons-green.svg
new file mode 100644
index 0000000..222a17c
--- /dev/null
+++ b/src/icons/UI-icons-green.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!-- Generator: Sketch 41.2 (35397) - http://www.bohemiancoding.com/sketch -->
+ <title>UI-icons-green</title>
+ <desc>Created with Sketch.</desc>
+ <defs></defs>
+ <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <path d="M19.646945,7.3567547 C19.8771137,8.19873229 20,9.08501533 20,10 C20,15.5228475 15.5228475,20 10,20 C4.4771525,20 0,15.5228475 0,10 C0,4.4771525 4.4771525,0 10,0 C13.3226641,0 16.2668405,1.62049863 18.0853086,4.11427536 L10.6900172,11.5095667 L6.78667323,7.60622275 L4.38461538,10.0082806 L10.6900172,16.3136824 L19.646945,7.3567547 Z" id="UI-icons-green" fill="#66CC00"></path>
+ </g>
+</svg> \ No newline at end of file
diff --git a/src/icons/UI-icons-red.svg b/src/icons/UI-icons-red.svg
new file mode 100644
index 0000000..5f4a6c3
--- /dev/null
+++ b/src/icons/UI-icons-red.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!-- Generator: Sketch 41.2 (35397) - http://www.bohemiancoding.com/sketch -->
+ <title>UI-icons-red</title>
+ <desc>Created with Sketch.</desc>
+ <defs></defs>
+ <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <path d="M15.9510545,6.31240144 C16.6160131,7.3832392 17,8.64677713 17,10 C17,13.8659932 13.8659932,17 10,17 C8.64677713,17 7.3832392,16.6160131 6.31240144,15.9510545 L15.9510545,6.31240144 Z M13.8607755,4.16003976 C12.7540831,3.42693796 11.4268999,3 10,3 C6.13400675,3 3,6.13400675 3,10 C3,11.4268999 3.42693796,12.7540831 4.16003976,13.8607755 L13.8607755,4.16003976 Z M10,20 C15.5228475,20 20,15.5228475 20,10 C20,4.4771525 15.5228475,0 10,0 C4.4771525,0 0,4.4771525 0,10 C0,15.5228475 4.4771525,20 10,20 Z" id="UI-icons-red" fill="#EC1C23"></path>
+ </g>
+</svg> \ No newline at end of file
diff --git a/src/icons/UI-icons-yellow.svg b/src/icons/UI-icons-yellow.svg
new file mode 100644
index 0000000..820b289
--- /dev/null
+++ b/src/icons/UI-icons-yellow.svg
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!-- Generator: Sketch 41.2 (35397) - http://www.bohemiancoding.com/sketch -->
+ <title>UI-icons-yellow</title>
+ <desc>Created with Sketch.</desc>
+ <defs></defs>
+ <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <g id="UI-icons-yellow" transform="translate(0.000000, -2.000000)">
+ <path d="M19.8857582,10.4835307 C19.9609891,10.9780483 20,11.4844684 20,12 C20,17.5228475 15.5228475,22 10,22 C4.4771525,22 0,17.5228475 0,12 C0,6.4771525 4.4771525,2 10,2 C10.5155316,2 11.0219517,2.03901093 11.5164693,2.11424183 C9.99308495,3.20235678 9,4.98520468 9,7 C9,10.3137085 11.6862915,13 15,13 C17.0147953,13 18.7976432,12.0069151 19.8857582,10.4835307 Z" id="Combined-Shape" fill="#CC9933"></path>
+ <circle id="Oval-5" fill="#100C04" cx="3.5" cy="10.5" r="1.5"></circle>
+ <circle id="Oval-5-Copy" fill="#100C04" cx="13.5" cy="18.5" r="1.5"></circle>
+ <circle id="Oval-5-Copy-2" fill="#100C04" cx="9.5" cy="13.5" r="1.5"></circle>
+ <circle id="Oval-5-Copy-3" fill="#100C04" cx="5.5" cy="16.5" r="1.5"></circle>
+ <polygon id="Combined-Shape" fill="#EC1C23" transform="translate(15.363961, 6.363961) rotate(-315.000000) translate(-15.363961, -6.363961) " points="14.363961 5.36396103 10.863961 5.36396103 10.863961 7.36396103 14.363961 7.36396103 14.363961 10.863961 16.363961 10.863961 16.363961 7.36396103 19.863961 7.36396103 19.863961 5.36396103 16.363961 5.36396103 16.363961 1.86396103 14.363961 1.86396103"></polygon>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/src/icons/badger-128.png b/src/icons/badger-128.png
new file mode 100644
index 0000000..e64b654
--- /dev/null
+++ b/src/icons/badger-128.png
Binary files differ
diff --git a/src/icons/badger-16.png b/src/icons/badger-16.png
new file mode 100644
index 0000000..d884068
--- /dev/null
+++ b/src/icons/badger-16.png
Binary files differ
diff --git a/src/icons/badger-19-disabled.png b/src/icons/badger-19-disabled.png
new file mode 100644
index 0000000..1f0ba91
--- /dev/null
+++ b/src/icons/badger-19-disabled.png
Binary files differ
diff --git a/src/icons/badger-19.png b/src/icons/badger-19.png
new file mode 100644
index 0000000..f4febe4
--- /dev/null
+++ b/src/icons/badger-19.png
Binary files differ
diff --git a/src/icons/badger-38-disabled.png b/src/icons/badger-38-disabled.png
new file mode 100644
index 0000000..ca84697
--- /dev/null
+++ b/src/icons/badger-38-disabled.png
Binary files differ
diff --git a/src/icons/badger-38.png b/src/icons/badger-38.png
new file mode 100644
index 0000000..e839104
--- /dev/null
+++ b/src/icons/badger-38.png
Binary files differ
diff --git a/src/icons/badger-48.png b/src/icons/badger-48.png
new file mode 100644
index 0000000..57ba776
--- /dev/null
+++ b/src/icons/badger-48.png
Binary files differ
diff --git a/src/icons/badger-64.png b/src/icons/badger-64.png
new file mode 100644
index 0000000..f51708a
--- /dev/null
+++ b/src/icons/badger-64.png
Binary files differ
diff --git a/src/icons/badger-bw-noborder.svg b/src/icons/badger-bw-noborder.svg
new file mode 100644
index 0000000..799daef
--- /dev/null
+++ b/src/icons/badger-bw-noborder.svg
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 23.0.6, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ viewBox="0 0 477.1 342.4" style="enable-background:new 0 0 477.1 342.4;" xml:space="preserve">
+<style type="text/css">
+ .st0{fill:none;}
+ .st1{fill:#FFFFFF;}
+</style>
+<g id="XMLID_67_">
+ <path id="XMLID_90_" class="st0" d="M466,233.6c-8-3.9-21-7.9-31.7-7.8C445.1,226.1,458.3,229.8,466,233.6z"/>
+ <path id="XMLID_89_" class="st1" d="M206.2,49.9c-1-8.3-4.1-20.2-13.5-22.5c-14.7-3.7-27.9,5.9-24.2,18.4
+ c1.9,6.6,6.1,11.7,9.6,15.1c0.2-0.1,0.4-0.2,0.6-0.3C187.4,56.6,196.6,53,206.2,49.9z"/>
+ <path id="XMLID_88_" class="st1" d="M404.1,94.3c2.4-0.7,5.1-1.4,8.3-2.1c21.3-5.1,30.8-15.4,28.6-23.5
+ c-2.2-8.1-17.6-14.7-32.3-5.9c-7.6,4.6-14.6,11.3-19.6,16.7C394.5,84.1,399.5,89.1,404.1,94.3z"/>
+ <path id="XMLID_87_" class="st1" d="M173.3,311.8c0.1,0,5.8,0.7,14.7,0.7c5.6,0,12.9-0.3,21.1-1.3l-8.6-10
+ c-10.1,5-19.8,8.5-28.2,10.9L173.3,311.8z"/>
+ <path id="XMLID_86_" class="st1" d="M215.9,310.2c3.3-0.6,6.7-1.2,10.1-2.1c8.3-2,15.3-4.9,21-8.1l-19-16.4
+ c-7.2,5.9-14.7,10.7-22.2,14.8L215.9,310.2z"/>
+ <path id="XMLID_85_" class="st1" d="M142.4,93.2c-13.9,18.4-22.8,38.7-22.8,38.7l12.7-1.7c-33.5,58.6-74,86.4-84.8,94.8
+ c16.4-0.6,31.6,3.3,42.6,8.5c2.4,1.1,4.7,2.6,6.9,4.2c9.7-7.4,55.7-42.9,75.8-68.7c22.6-29,35.9-39.4,35.9-39.4l3.5,15.6
+ c0,0,66.1-68.4,123.4-64.9c0,0-7.5,4.6-11.6,16.8c0,0,38.9-9.9,78.2,9.5c-6.7-8.3-14.4-16.1-22.8-22.9
+ c-26.9-22-61.5-33.3-93.2-35.9c-59,16.6-128.5,91-128.5,91s9.3-16.9,28.7-42c15.6-20.3,37.5-39.3,46.8-47.1
+ c-21,3.4-39,9.8-55.8,17.6C162.8,74.2,151.6,82.9,142.4,93.2z"/>
+ <path id="XMLID_84_" class="st1" d="M265.4,283.1c1.6-3.1,2.1-6,1.3-8c-1.5-3.8-4.5-5.7-9.1-5.7c-4.5,0-12.3,1.5-24,9.9l19.5,16.8
+ C259.3,291.7,263.4,287,265.4,283.1z"/>
+ <path id="XMLID_83_" class="st1" d="M47.7,248.9c0,4.3,8.3,7.7,18.5,7.7s18.5-3.5,18.5-7.7c0-4.3-8.3-7.7-18.5-7.7
+ S47.7,244.7,47.7,248.9z"/>
+ <path id="XMLID_82_" d="M240.9,255.1l0.8,0.4c10.5-4.9,33.2-5.4,42.5,4.6c11.6,12.5,1.1,28.2-1.5,30.9h0.8
+ c7.7-3.9,12.1-8.7,13.5-15.1c1.9-8.2,0.9-14.2-4.6-20.8C281.8,242.8,257.9,241.6,240.9,255.1z"/>
+ <path id="XMLID_79_" class="st1" d="M430.2,173v-0.6c-1.2-1.1-15.8-14.6-38-18.3l0,0c-16-2.6-35.3-0.6-55.3,13.1
+ c0,0,33.6-2.9,51.6,14.5c0,0-24.9-6.4-45.8,4.6s-48.1,46.4-100.8,44c-44.1-1.9-56.2-4.6-81.7,5.2c-16.5,6.4-37.7,17.1-50.8,23.9
+ c-0.3,7.5-5.2,15.1-17.6,21.2c-19.7,9.6-43.2,10.9-60.9,6.9c19.4,20.6,60.2,23.8,83.6,23.8c16.4,0,28.5-1.5,28.6-1.5h0.4l1.1,0.1
+ l4-0.6c0.4-0.1,43.6-6.9,75.2-31.2c13.4-10.4,24.8-15.6,33.8-15.6c7.4,0,13,3.7,15.6,10.1c1.5,4,1,8.7-1.6,13.7
+ c-6.5,12.4-23.7,23.6-44,28.6c-14.8,3.6-28.8,4.5-38.4,4.6c5.8,5.1,13.8,8.1,23.1,9.1c13.6,1.4,24.4-3.4,24.5-3.4l1.3-0.4l0,0
+ c4.4-1.7,18.7-9.8,18.7-9.8s-5.7,9.2-11,12.7c15,4.4,23.5,5.3,38.8,5.3c44,0,98.6-27.9,122.6-68.7c0.1-0.2,0.2-0.4,0.3-0.5v0.1
+ c18.9-6.7,31.9-0.9,39.1,3.5c-6.3-24.2-18.2-36.2-18.4-36.3l-4.8-4.6l5.2-0.6c1.8-0.2,3.8-0.2,5.8-0.2c10.7-0.1,23.7,3.9,31.7,7.8
+ C455.4,195,430.5,173.3,430.2,173z M296.9,276c-1.4,6.3-5.8,11.2-13.5,15.1h-0.8c2.7-2.7,13.1-18.4,1.5-30.9
+ c-9.3-10-32-9.6-42.5-4.6l-0.8-0.4c17-13.5,40.9-12.3,51.4,0.1C297.8,261.8,298.8,267.8,296.9,276z"/>
+ <path id="XMLID_68_" d="M477.1,247.8l-2.1-8.2c-10.6-40.8-38.9-68.6-40.1-69.7l0,0c-0.2-0.2-0.4-0.4-0.7-0.7
+ c-0.4-22-7.2-42.2-18.6-59.8c6.2-1.1,13.6-2.5,22.1-3.9l-2.1-12l16.7,7.2c20-11.9,27.3-36.5,14.2-57.4
+ c-11.1-17.6-48.7-21.6-69.5-10.8c-11.7,6.1-23.7,19.5-32,30.1c-24.6-14.1-53.6-22.5-83.2-23.3c-17.1-0.5-33.3,0.9-48.7,3.8
+ c-1.6-20.1-14.9-41.8-39.4-43c-30.1-1.5-46.4,18.5-45.6,37.9c0.4,10.8,9.3,21.9,17.1,29.5c-28.9,16.4-50.9,39.6-65.6,69.1
+ c-28.9,58.3-66.2,83.4-78.4,91.7c-2.8,1.9-4.4,2.9-5.2,4c-18.6,8.6-20,26.9-9.3,42.1c2.3,3.3,6.1,6.2,10.8,8.5
+ c1.1,2,2.3,3.9,3.7,5.8c19.2,25.4,61.3,30.7,93.3,30.7c15.4,0,26.8-1.2,29.2-1.5l35.7,2.9c7.4,9.1,19.2,15.2,33,15.9
+ c12.2,0.6,21.6-3.5,24.6-4.3c17.7,5.5,29,10,46.9,10c29,0,59.2-6.8,84.2-20.5c21.6-11.8,38.8-31,48.7-47.8c0.5-0.9,1-1.7,1.5-2.6
+ c20.8-5.2,33.7,6.7,33.8,6.8l6.6,4.8l-1.5-8.5c-3.9-20.7-11.7-33.3-17.6-40.8c14.1,1.2,30.2,9.5,30.4,9.7L477.1,247.8z M408.7,62.8
+ c14.7-8.8,30.1-2.2,32.3,5.9c2.2,8.1-7.3,18.4-28.6,23.5c-3.1,0.8-5.9,1.5-8.3,2.1c-4.6-5.2-9.6-10.2-15-14.8
+ C394.1,74.1,401.1,67.4,408.7,62.8z M233.4,49.7c-9.3,7.7-31.2,26.8-46.8,47.1c-19.4,25.2-28.7,42-28.7,42s69.5-74.4,128.5-91
+ c31.7,2.6,66.3,14,93.2,35.9c8.4,6.9,16.1,14.6,22.8,22.9c-39.2-19.4-78.2-9.5-78.2-9.5c4.1-12.2,11.6-16.8,11.6-16.8
+ c-57.4-3.5-123.4,64.9-123.4,64.9l-3.5-15.6c0,0-13.3,10.4-35.9,39.4c-20.1,25.8-66.1,61.3-75.8,68.7c-2.2-1.6-4.5-3.1-6.9-4.2
+ c-11-5.3-26.2-9.2-42.6-8.5c10.8-8.4,51.2-36.2,84.8-94.8l-12.7,1.7c0,0,8.9-20.3,22.8-38.7c9.2-10.3,20.4-19,35.2-25.8
+ C194.3,59.6,212.3,53.2,233.4,49.7z M84.8,248.9c0,4.3-8.3,7.7-18.5,7.7s-18.5-3.5-18.5-7.7c0-4.3,8.3-7.7,18.5-7.7
+ S84.8,244.7,84.8,248.9z M168.5,45.7c-3.7-12.5,9.5-22,24.2-18.4c9.4,2.3,12.5,14.2,13.5,22.5c-9.6,3-18.7,6.6-27.4,10.6
+ c-0.2,0.1-0.4,0.2-0.6,0.3C174.6,57.5,170.4,52.3,168.5,45.7z M253.1,296.1l-19.5-16.8c11.7-8.4,19.6-9.9,24-9.9
+ c4.5,0,7.6,1.9,9.1,5.7c0.8,2,0.3,4.8-1.3,8C263.4,287,259.3,291.7,253.1,296.1z M228,283.6l19,16.4c-5.7,3.2-12.7,6.1-21,8.1
+ c-3.4,0.8-6.8,1.5-10.1,2.1l-10.1-11.8C213.3,294.4,220.8,289.5,228,283.6z M200.5,301.2l8.6,10c-8.2,1-15.6,1.3-21.1,1.3
+ c-8.8,0-14.6-0.7-14.7-0.7l-1,0.3C180.7,309.7,190.5,306.2,200.5,301.2z M434.3,225.8c-2-0.1-4,0-5.8,0.2l-5.2,0.6l4.8,4.6
+ c0.2,0.2,12,12.2,18.4,36.3c-7.1-4.4-20.2-10.3-39.1-3.5v-0.1c-0.1,0.2-0.2,0.4-0.3,0.5c-24,40.7-78.5,68.7-122.6,68.7
+ c-15.3,0-23.8-1-38.8-5.3c5.4-3.6,11-12.7,11-12.7s-14.3,8.1-18.7,9.8l0,0l-1.3,0.4c-0.1,0-10.9,4.9-24.5,3.4
+ c-9.3-1-17.2-4.1-23.1-9.1c9.5-0.1,23.6-1,38.4-4.6c20.2-5,37.5-16.2,44-28.6c2.6-5,3.2-9.7,1.6-13.7c-2.5-6.4-8.2-10.1-15.6-10.1
+ c-9,0-20.4,5.2-33.8,15.6c-31.6,24.3-74.8,31.1-75.2,31.2l-4,0.6l-1.1-0.1H143c-0.1,0-12.2,1.5-28.6,1.5
+ c-23.4,0-64.1-3.2-83.6-23.8c17.7,4,41.2,2.7,60.9-6.9c12.4-6.1,17.4-13.7,17.6-21.2c13-6.8,34.3-17.5,50.8-23.9
+ c25.5-9.9,37.6-7.2,81.7-5.2c52.7,2.3,80-33,100.8-44c20.9-11,45.8-4.6,45.8-4.6c-18-17.4-51.6-14.5-51.6-14.5
+ c20-13.7,39.4-15.6,55.3-13.1l0,0c22.1,3.6,36.8,17.2,38,18.3v0.6c0.3,0.3,25.2,22,35.8,60.6C458.3,229.8,445.1,226.1,434.3,225.8z
+ "/>
+</g>
+<path id="XMLID_59_" d="M259.8,158.4c-11.2,0-20.3,9.1-20.3,20.3c0,11.2,9.1,20.3,20.3,20.3c10.6,0,19.2-8.1,20.2-18.4l-20.2-1.8
+ l12.5-15.9C268.9,160,264.6,158.4,259.8,158.4z"/>
+<path id="XMLID_60_" class="st1" d="M224.8,178.6c0,19.4,15.7,35.1,35.1,35.1S295,198,295,178.6s-15.7-35.1-35.1-35.1
+ S224.8,159.2,224.8,178.6z M280,180.4c-0.9,10.3-9.6,18.4-20.2,18.4c-11.2,0-20.3-9.1-20.3-20.3c0-11.2,9.1-20.3,20.3-20.3
+ c4.7,0,9.1,1.6,12.5,4.3l-12.5,15.9L280,180.4z"/>
+</svg>
diff --git a/src/icons/badger-pin.png b/src/icons/badger-pin.png
new file mode 100644
index 0000000..cbfe7ec
--- /dev/null
+++ b/src/icons/badger-pin.png
Binary files differ
diff --git a/src/icons/dnt-16.png b/src/icons/dnt-16.png
new file mode 100644
index 0000000..840b047
--- /dev/null
+++ b/src/icons/dnt-16.png
Binary files differ
diff --git a/src/icons/help.svg b/src/icons/help.svg
new file mode 100644
index 0000000..e034e5e
--- /dev/null
+++ b/src/icons/help.svg
@@ -0,0 +1,3 @@
+<svg id="Page-1" xmlns="http://www.w3.org/2000/svg" width="99.032" height="99.033" viewBox="0 0 99.032 99.033">
+ <path id="help" d="M49.516,99.033A49.516,49.516,0,1,0,0,49.516,49.516,49.516,0,0,0,49.516,99.033Zm-6.386-40.6a13.661,13.661,0,0,1,.761-4.849,10.06,10.06,0,0,1,2.567-3.708q2.662-2.567,4.9-4.468t3.85-3.565a18.482,18.482,0,0,0,2.519-3.137,5.825,5.825,0,0,0,.9-3.09,6.258,6.258,0,0,0-1.949-4.9,7.033,7.033,0,0,0-4.9-1.759q-4.468,0-6.8,2.472a9.6,9.6,0,0,0-2.614,5.989l-14.641-.951Q28.775,26.4,35.145,21.122T51.5,15.845a27.739,27.739,0,0,1,8.224,1.188,20.193,20.193,0,0,1,6.8,3.565,17.037,17.037,0,0,1,4.659,5.894,18.251,18.251,0,0,1,1.711,8.081,20.192,20.192,0,0,1-.57,4.991,15.466,15.466,0,0,1-1.949,4.421,25.781,25.781,0,0,1-3.613,4.421A61.283,61.283,0,0,1,61.1,53.3a9.835,9.835,0,0,0-2.947,3.327,7.535,7.535,0,0,0-.761,3.232V62.62H43.131ZM41.514,76.691a8.9,8.9,0,0,1,.666-3.423,8.407,8.407,0,0,1,4.658-4.659,9.134,9.134,0,0,1,6.845,0,8.407,8.407,0,0,1,4.658,4.659,9.134,9.134,0,0,1,0,6.845,8.407,8.407,0,0,1-4.658,4.658,9.134,9.134,0,0,1-6.845,0,8.407,8.407,0,0,1-4.658-4.658A8.9,8.9,0,0,1,41.514,76.691Z" fill-rule="evenodd"/>
+</svg>
diff --git a/src/icons/options.svg b/src/icons/options.svg
new file mode 100644
index 0000000..6d0ca67
--- /dev/null
+++ b/src/icons/options.svg
@@ -0,0 +1,3 @@
+<svg id="Page-1" xmlns="http://www.w3.org/2000/svg" width="99.032" height="99.033" viewBox="0 0 99.032 99.033">
+ <path id="options" d="M44.025,0H55.008L59.86,13.849a37.137,37.137,0,0,1,7.564,3.133L80.647,10.62l7.766,7.766L82.051,31.609a37.138,37.138,0,0,1,3.133,7.564l13.849,4.852V55.008L85.184,59.86a37.138,37.138,0,0,1-3.133,7.564l6.361,13.223-7.766,7.766L67.423,82.051a37.138,37.138,0,0,1-7.564,3.133L55.008,99.033H44.025L39.173,85.184a37.138,37.138,0,0,1-7.564-3.133L18.386,88.413,10.62,80.647l6.361-13.223a37.137,37.137,0,0,1-3.133-7.564L0,55.008V44.025l13.849-4.852a37.137,37.137,0,0,1,3.133-7.564L10.62,18.386l7.766-7.766,13.223,6.361a37.137,37.137,0,0,1,7.564-3.133Zm5.491,26.306A23.211,23.211,0,1,0,72.727,49.516,23.211,23.211,0,0,0,49.516,26.306Z" fill-rule="evenodd"/>
+</svg>
diff --git a/src/icons/share.svg b/src/icons/share.svg
new file mode 100644
index 0000000..8b26a62
--- /dev/null
+++ b/src/icons/share.svg
@@ -0,0 +1,3 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="71.304" height="78.909" viewBox="0 0 71.304 78.909">
+ <path id="share" d="M62.42,57.775a11.535,11.535,0,0,0-7.764,3.05L26.411,44.386a12.967,12.967,0,0,0,.357-2.773,12.967,12.967,0,0,0-.357-2.773L54.339,22.559a11.857,11.857,0,1,0-3.8-8.675,12.967,12.967,0,0,0,.357,2.773L22.965,32.938a11.884,11.884,0,1,0,0,17.351l28.2,16.479a11.176,11.176,0,0,0-.317,2.575A11.567,11.567,0,1,0,62.42,57.775Z" transform="translate(-3 -2)"/>
+</svg>
diff --git a/src/js/background.js b/src/js/background.js
new file mode 100644
index 0000000..6cdee4c
--- /dev/null
+++ b/src/js/background.js
@@ -0,0 +1,1148 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2014 Electronic Frontier Foundation
+ *
+ * Derived from Adblock Plus
+ * Copyright (C) 2006-2013 Eyeo GmbH
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* globals log:false */
+
+var utils = require("utils");
+var constants = require("constants");
+var pbStorage = require("storage");
+
+var HeuristicBlocking = require("heuristicblocking");
+var FirefoxAndroid = require("firefoxandroid");
+var webrequest = require("webrequest");
+var widgetLoader = require("widgetloader");
+
+var Migrations = require("migrations").Migrations;
+var incognito = require("incognito");
+
+/**
+ * Privacy Badger initializer.
+ */
+function Badger() {
+ let self = this;
+
+ self.isFirstRun = false;
+ self.isUpdate = false;
+
+ self.webRTCAvailable = checkWebRTCBrowserSupport();
+ self.firstPartyDomainPotentiallyRequired = testCookiesFirstPartyDomain();
+
+ self.widgetList = [];
+ let widgetListPromise = widgetLoader.loadWidgetsFromFile(
+ "data/socialwidgets.json").catch(console.error);
+ widgetListPromise.then(widgets => {
+ self.widgetList = widgets;
+ });
+
+ self.storage = new pbStorage.BadgerPen(async function (thisStorage) {
+ self.initializeSettings();
+ // Privacy Badger settings are now fully ready
+
+ self.setPrivacyOverrides();
+
+ self.heuristicBlocking = new HeuristicBlocking.HeuristicBlocker(thisStorage);
+
+ // TODO there are async migrations
+ // TODO is this the right place for migrations?
+ self.runMigrations();
+
+ // kick off async initialization steps
+ let seedDataPromise = self.loadFirstRunSeedData().catch(console.error),
+ ylistPromise = self.initializeYellowlist().catch(console.error),
+ dntHashesPromise = self.initializeDnt().catch(console.error),
+ tabDataPromise = self.updateTabList().catch(console.error);
+
+ // set badge text color to white in Firefox 63+
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1474110
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1424620
+ if (chrome.browserAction.hasOwnProperty('setBadgeTextColor')) {
+ chrome.browserAction.setBadgeTextColor({ color: "#fff" });
+ }
+
+ // Show icon as page action for all tabs that already exist
+ chrome.tabs.query({}, function (tabs) {
+ for (let i = 0; i < tabs.length; i++) {
+ let tab = tabs[i];
+ self.updateIcon(tab.id, tab.url);
+ }
+ });
+
+ // wait for async functions (seed data, yellowlist, ...) to resolve
+ await widgetListPromise;
+ await seedDataPromise;
+ await ylistPromise;
+ await dntHashesPromise;
+ await tabDataPromise;
+
+ // block all widget domains
+ // only need to do this when the widget list could have gotten updated
+ if (badger.isFirstRun || badger.isUpdate) {
+ self.blockWidgetDomains();
+ }
+
+ // start the listeners
+ incognito.startListeners();
+ webrequest.startListeners();
+ HeuristicBlocking.startListeners();
+ FirefoxAndroid.startListeners();
+ startBackgroundListeners();
+
+ console.log("Privacy Badger is ready to rock!");
+ console.log("Set DEBUG=1 to view console messages.");
+ self.INITIALIZED = true;
+
+ // get the latest yellowlist from eff.org
+ self.updateYellowlist(err => {
+ if (err) {
+ console.error(err);
+ }
+ });
+ // set up periodic fetching of the yellowlist from eff.org
+ setInterval(self.updateYellowlist.bind(self), utils.oneDay());
+
+ // get the latest DNT policy hashes from eff.org
+ self.updateDntPolicyHashes(err => {
+ if (err) {
+ console.error(err);
+ }
+ });
+ // set up periodic fetching of hashes from eff.org
+ setInterval(self.updateDntPolicyHashes.bind(self), utils.oneDay() * 4);
+
+ if (self.isFirstRun) {
+ self.showFirstRunPage();
+ }
+ });
+
+ /**
+ * WebRTC availability check
+ */
+ function checkWebRTCBrowserSupport() {
+ if (!(chrome.privacy && chrome.privacy.network &&
+ chrome.privacy.network.webRTCIPHandlingPolicy)) {
+ return false;
+ }
+
+ var available = true;
+ var connection = null;
+
+ try {
+ var RTCPeerConnection = (
+ window.RTCPeerConnection || window.webkitRTCPeerConnection
+ );
+ if (RTCPeerConnection) {
+ connection = new RTCPeerConnection(null);
+ }
+ } catch (ex) {
+ available = false;
+ }
+
+ if (connection !== null && connection.close) {
+ connection.close();
+ }
+
+ return available;
+ }
+
+ /**
+ * Checks for availability of firstPartyDomain chrome.cookies API parameter.
+ * https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/cookies/getAll#Parameters
+ *
+ * firstPartyDomain is required when privacy.websites.firstPartyIsolate is enabled,
+ * and is in Firefox since Firefox 59. (firstPartyIsolate is in Firefox since 58).
+ *
+ * We don't care whether firstPartyIsolate is enabled, but rather whether
+ * firstPartyDomain is supported. Assuming firstPartyDomain is supported,
+ * setting it to null in chrome.cookies.getAll() produces the same result
+ * regardless of the state of firstPartyIsolate.
+ *
+ * firstPartyDomain is not currently supported in Chrome.
+ */
+ function testCookiesFirstPartyDomain() {
+ try {
+ chrome.cookies.getAll({
+ firstPartyDomain: null
+ }, function () {});
+ } catch (ex) {
+ return false;
+ }
+ return true;
+ }
+
+}
+
+Badger.prototype = {
+ INITIALIZED: false,
+
+ /**
+ * Per-tab data that gets cleaned up on tab closing looks like:
+ tabData = {
+ <tab_id>: {
+ blockedFrameUrls: {
+ <parent_frame_id>: [
+ {String} blocked frame URL,
+ ...
+ ],
+ ...
+ },
+ fpData: {
+ <script_origin>: {
+ canvas: {
+ fingerprinting: boolean,
+ write: boolean
+ }
+ },
+ ...
+ },
+ frames: {
+ <frame_id>: {
+ url: string,
+ host: string,
+ parent: int
+ },
+ ...
+ },
+ origins: {
+ domain.tld: {String} action taken for this domain
+ ...
+ }
+ },
+ ...
+ }
+ */
+ tabData: {},
+
+
+ // Methods
+
+ /**
+ * Sets various browser privacy overrides.
+ */
+ setPrivacyOverrides: function () {
+ if (!chrome.privacy) {
+ return;
+ }
+
+ let self = this;
+
+ /**
+ * Sets a browser setting if Privacy Badger is allowed to set it.
+ */
+ function _set_override(name, api, value) {
+ if (!api) {
+ return;
+ }
+ api.get({}, result => {
+ if (result.levelOfControl != "controllable_by_this_extension") {
+ return;
+ }
+ api.set({
+ value,
+ scope: 'regular'
+ }, () => {
+ if (chrome.runtime.lastError) {
+ console.error("Privacy setting failed:", chrome.runtime.lastError);
+ } else {
+ console.log("Set", name, "to", value);
+ }
+ });
+ });
+ }
+
+ if (self.getSettings().getItem("disableGoogleNavErrorService")) {
+ if (chrome.privacy.services) {
+ _set_override(
+ "alternateErrorPagesEnabled",
+ chrome.privacy.services.alternateErrorPagesEnabled,
+ false
+ );
+ }
+ }
+
+ if (self.getSettings().getItem("disableHyperlinkAuditing")) {
+ if (chrome.privacy.websites) {
+ _set_override(
+ "hyperlinkAuditingEnabled",
+ chrome.privacy.websites.hyperlinkAuditingEnabled,
+ false
+ );
+ }
+ }
+ },
+
+ /**
+ * Loads seed dataset with pre-trained action and snitch maps.
+ * @param {Function} cb callback
+ */
+ loadSeedData: function (cb) {
+ let self = this;
+
+ utils.xhrRequest(constants.SEED_DATA_LOCAL_URL, function (err, response) {
+ if (err) {
+ return cb(new Error("Failed to fetch seed data"));
+ }
+
+ let data;
+ try {
+ data = JSON.parse(response);
+ } catch (e) {
+ console.error(e);
+ return cb(new Error("Failed to parse seed data JSON"));
+ }
+
+ self.mergeUserData(data, true);
+ log("Loaded seed data successfully");
+ return cb(null);
+ });
+ },
+
+ /**
+ * Loads seed data upon first run.
+ *
+ * @returns {Promise}
+ */
+ loadFirstRunSeedData: function () {
+ let self = this;
+
+ return new Promise(function (resolve, reject) {
+ if (!self.isFirstRun) {
+ log("No need to load seed data");
+ return resolve();
+ }
+
+ self.loadSeedData(err => {
+ log("Seed data loaded! (err=%o)", err);
+ return (err ? reject(err) : resolve());
+ });
+ });
+ },
+
+ showFirstRunPage: function() {
+ let settings = this.getSettings();
+ if (settings.getItem("showIntroPage")) {
+ chrome.tabs.create({
+ url: chrome.runtime.getURL("/skin/firstRun.html")
+ });
+ } else {
+ // don't remind users to look at the intro page either
+ settings.setItem("seenComic", true);
+ }
+ },
+
+ /**
+ * Blocks all widget domains
+ * to ensure that all widgets that could get replaced
+ * do get replaced by default for all users.
+ */
+ blockWidgetDomains: function () {
+ let self = this;
+
+ // compile set of widget domains
+ let domains = new Set();
+ for (let widget of self.widgetList) {
+ for (let domain of widget.domains) {
+ if (domain[0] == "*") {
+ domain = domain.slice(2);
+ }
+ domains.add(domain);
+ }
+ }
+
+ // block the domains
+ for (let domain of domains) {
+ self.heuristicBlocking.blocklistOrigin(
+ window.getBaseDomain(domain), domain);
+ }
+ },
+
+ /**
+ * Saves a user preference for an origin, overriding the default setting.
+ *
+ * @param {String} userAction enum of block, cookieblock, noaction
+ * @param {String} origin the third party origin to take action on
+ */
+ saveAction: function(userAction, origin) {
+ var allUserActions = {
+ block: constants.USER_BLOCK,
+ cookieblock: constants.USER_COOKIEBLOCK,
+ allow: constants.USER_ALLOW
+ };
+ this.storage.setupUserAction(origin, allUserActions[userAction]);
+ log("Finished saving action " + userAction + " for " + origin);
+ },
+
+ /**
+ * Populate tabs object with currently open tabs when extension is updated or installed.
+ *
+ * @returns {Promise}
+ */
+ updateTabList: function () {
+ let self = this;
+
+ return new Promise(function (resolve) {
+ chrome.tabs.query({}, tabs => {
+ tabs.forEach(tab => {
+ // don't record on special browser pages
+ if (!utils.isRestrictedUrl(tab.url)) {
+ self.recordFrame(tab.id, 0, tab.url);
+ }
+ });
+ resolve();
+ });
+ });
+ },
+
+ /**
+ * Generate representation in internal data structure for frame
+ *
+ * @param {Integer} tabId ID of the tab
+ * @param {Integer} frameId ID of the frame
+ * @param {String} frameUrl The url of the frame
+ */
+ recordFrame: function(tabId, frameId, frameUrl) {
+ let self = this;
+
+ if (!self.tabData.hasOwnProperty(tabId)) {
+ self.tabData[tabId] = {
+ blockedFrameUrls: {},
+ frames: {},
+ origins: {}
+ };
+ }
+
+ self.tabData[tabId].frames[frameId] = {
+ url: frameUrl,
+ host: window.extractHostFromURL(frameUrl)
+ };
+ },
+
+ /**
+ * Read the frame data from memory
+ *
+ * @param {Integer} tab_id Tab ID to check for
+ * @param {Integer} [frame_id=0] Frame ID to check for.
+ * Optional, defaults to frame 0 (the main document frame).
+ *
+ * @returns {?Object} Frame data object or null
+ */
+ getFrameData: function (tab_id, frame_id) {
+ let self = this;
+
+ frame_id = frame_id || 0;
+
+ if (self.tabData.hasOwnProperty(tab_id)) {
+ if (self.tabData[tab_id].frames.hasOwnProperty(frame_id)) {
+ return self.tabData[tab_id].frames[frame_id];
+ }
+ }
+ return null;
+ },
+
+ /**
+ * Initializes the yellowlist from disk.
+ *
+ * @returns {Promise}
+ */
+ initializeYellowlist: function () {
+ let self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ if (self.storage.getStore('cookieblock_list').keys().length) {
+ log("Yellowlist already initialized from disk");
+ return resolve();
+ }
+
+ // we don't have the yellowlist initialized yet
+ // initialize from disk
+ utils.xhrRequest(constants.YELLOWLIST_LOCAL_URL, (error, response) => {
+ if (error) {
+ console.error(error);
+ return reject(new Error("Failed to fetch local yellowlist"));
+ }
+
+ self.storage.updateYellowlist(response.trim().split("\n"));
+ log("Initialized ylist from disk");
+ return resolve();
+ });
+
+ });
+ },
+
+ /**
+ * Updates to the latest yellowlist from eff.org.
+ * @param {Function} [callback] optional callback
+ */
+ updateYellowlist: function (callback) {
+ let self = this;
+
+ if (!callback) {
+ callback = function () {};
+ }
+
+ utils.xhrRequest(constants.YELLOWLIST_URL, function (err, response) {
+ if (err) {
+ console.error(
+ "Problem fetching yellowlist at",
+ constants.YELLOWLIST_URL,
+ err.status,
+ err.message
+ );
+
+ return callback(new Error("Failed to fetch remote yellowlist"));
+ }
+
+ // handle empty response
+ if (!response.trim()) {
+ return callback(new Error("Empty yellowlist response"));
+ }
+
+ let domains = response.trim().split("\n").map(domain => domain.trim());
+
+ // validate the response
+ if (!domains.every(domain => {
+ // all domains must contain at least one dot
+ if (domain.indexOf('.') == -1) {
+ return false;
+ }
+
+ // validate character set
+ //
+ // regex says:
+ // - domain starts with lowercase English letter or Arabic numeral
+ // - following that, it contains one or more
+ // letter/numeral/dot/dash characters
+ // - following the previous two requirements, domain ends with a letter
+ //
+ // TODO both overly restrictive and inaccurate
+ // but that's OK for now, we manage the list
+ if (!/^[a-z0-9][a-z0-9.-]+[a-z]$/.test(domain)) {
+ return false;
+ }
+
+ return true;
+ })) {
+ return callback(new Error("Invalid yellowlist response"));
+ }
+
+ self.storage.updateYellowlist(domains);
+ log("Updated yellowlist from remote");
+
+ return callback(null);
+ });
+ },
+
+ /**
+ * Initializes DNT policy hashes from disk.
+ *
+ * @returns {Promise}
+ */
+ initializeDnt: function () {
+ let self = this;
+
+ return new Promise(function (resolve, reject) {
+
+ if (self.storage.getStore('dnt_hashes').keys().length) {
+ log("DNT hashes already initialized from disk");
+ return resolve();
+ }
+
+ // we don't have DNT hashes initialized yet
+ // initialize from disk
+ utils.xhrRequest(constants.DNT_POLICIES_LOCAL_URL, (error, response) => {
+ let hashes;
+
+ if (error) {
+ console.error(error);
+ return reject(new Error("Failed to fetch local DNT hashes"));
+ }
+
+ try {
+ hashes = JSON.parse(response);
+ } catch (e) {
+ console.error(e);
+ return reject(new Error("Failed to parse DNT hashes JSON"));
+ }
+
+ self.storage.updateDntHashes(hashes);
+ log("Initialized hashes from disk");
+ return resolve();
+
+ });
+
+ });
+ },
+
+ /**
+ * Fetch acceptable DNT policy hashes from the EFF server
+ * @param {Function} [cb] optional callback
+ */
+ updateDntPolicyHashes: function (cb) {
+ let self = this;
+
+ if (!cb) {
+ cb = function () {};
+ }
+
+ if (!self.isCheckingDNTPolicyEnabled()) {
+ // user has disabled this, we can check when they re-enable
+ setTimeout(function () {
+ return cb(null);
+ }, 0);
+ }
+
+ utils.xhrRequest(constants.DNT_POLICIES_URL, function (err, response) {
+ if (err) {
+ console.error("Problem fetching DNT policy hash list at",
+ constants.DNT_POLICIES_URL, err.status, err.message);
+ return cb(new Error("Failed to fetch remote DNT hashes"));
+ }
+
+ let hashes;
+ try {
+ hashes = JSON.parse(response);
+ } catch (e) {
+ console.error(e);
+ return cb(new Error("Failed to parse DNT hashes JSON"));
+ }
+
+ self.storage.updateDntHashes(hashes);
+ log("Updated hashes from remote");
+ return cb(null);
+ });
+ },
+
+ /**
+ * Checks a domain for the EFF DNT policy.
+ *
+ * @param {String} domain The domain to check
+ * @param {Function} [cb] Callback that receives check status boolean (optional)
+ */
+ checkForDNTPolicy: function (domain, cb) {
+ var self = this,
+ next_update = self.storage.getNextUpdateForDomain(domain);
+
+ if (Date.now() < next_update) {
+ // not yet time
+ return;
+ }
+
+ if (!self.isCheckingDNTPolicyEnabled()) {
+ // user has disabled this check
+ return;
+ }
+
+ log('Checking', domain, 'for DNT policy.');
+
+ // update timestamp first;
+ // avoids queuing the same domain multiple times
+ var recheckTime = _.random(
+ utils.oneDayFromNow(),
+ utils.nDaysFromNow(7)
+ );
+ self.storage.touchDNTRecheckTime(domain, recheckTime);
+
+ self._checkPrivacyBadgerPolicy(domain, function (success) {
+ if (success) {
+ log('It looks like', domain, 'has adopted Do Not Track! I am going to unblock them');
+ self.storage.setupDNT(domain);
+ } else {
+ log('It looks like', domain, 'has NOT adopted Do Not Track');
+ self.storage.revertDNT(domain);
+ }
+ if (typeof cb == "function") {
+ cb(success);
+ }
+ });
+ },
+
+
+ /**
+ * Asyncronously checks if the domain has /.well-known/dnt-policy.txt.
+ *
+ * Rate-limited to at least one second apart.
+ *
+ * @param {String} origin The host to check
+ * @param {Function} callback callback(successStatus)
+ */
+ _checkPrivacyBadgerPolicy: utils.rateLimit(function (origin, callback) {
+ var successStatus = false;
+ var url = "https://" + origin + "/.well-known/dnt-policy.txt";
+ var dnt_hashes = this.storage.getStore('dnt_hashes');
+
+ utils.xhrRequest(url,function(err,response) {
+ if (err) {
+ callback(successStatus);
+ return;
+ }
+ utils.sha1(response, function(hash) {
+ if (dnt_hashes.hasItem(hash)) {
+ successStatus = true;
+ }
+ callback(successStatus);
+ });
+ });
+ }, constants.DNT_POLICY_CHECK_INTERVAL),
+
+ /**
+ * Default Privacy Badger settings
+ */
+ defaultSettings: {
+ checkForDNTPolicy: true,
+ disabledSites: [],
+ disableGoogleNavErrorService: true,
+ disableHyperlinkAuditing: true,
+ hideBlockedElements: true,
+ learnInIncognito: false,
+ learnLocally: false,
+ migrationLevel: 0,
+ seenComic: false,
+ sendDNTSignal: true,
+ showCounter: true,
+ showIntroPage: true,
+ showNonTrackingDomains: false,
+ showTrackingDomains: false,
+ socialWidgetReplacementEnabled: true,
+ widgetReplacementExceptions: [],
+ widgetSiteAllowlist: {},
+ },
+
+ /**
+ * Initializes settings with defaults if needed,
+ * detects whether Badger just got installed or upgraded
+ */
+ initializeSettings: function () {
+ let self = this,
+ settings = self.getSettings();
+
+ for (let key of Object.keys(self.defaultSettings)) {
+ // if this setting is not yet in storage,
+ if (!settings.hasItem(key)) {
+ // set with default value
+ let value = self.defaultSettings[key];
+ log("setting", key, "=", value);
+ settings.setItem(key, value);
+ }
+ }
+
+ let version = chrome.runtime.getManifest().version,
+ privateStore = self.getPrivateSettings(),
+ prev_version = privateStore.getItem("badgerVersion");
+
+ // special case for older badgers that kept isFirstRun in storage
+ if (settings.hasItem("isFirstRun")) {
+ self.isUpdate = true;
+ privateStore.setItem("badgerVersion", version);
+ privateStore.setItem("showLearningPrompt", true);
+ settings.deleteItem("isFirstRun");
+
+ // new install
+ } else if (!prev_version) {
+ self.isFirstRun = true;
+ privateStore.setItem("badgerVersion", version);
+
+ // upgrade
+ } else if (version != prev_version) {
+ self.isUpdate = true;
+ privateStore.setItem("badgerVersion", version);
+ }
+
+ if (!privateStore.hasItem("showLearningPrompt")) {
+ privateStore.setItem("showLearningPrompt", false);
+ }
+ },
+
+ runMigrations: function() {
+ var self = this;
+ var settings = self.getSettings();
+ var migrationLevel = settings.getItem('migrationLevel');
+ // TODO do not remove any migration methods
+ // TODO w/o refactoring migrationLevel handling to work differently
+ var migrations = [
+ Migrations.changePrivacySettings,
+ Migrations.migrateAbpToStorage,
+ Migrations.migrateBlockedSubdomainsToCookieblock,
+ Migrations.migrateLegacyFirefoxData,
+ Migrations.migrateDntRecheckTimes,
+ // Need to run this migration again for everyone to #1181
+ Migrations.migrateDntRecheckTimes2,
+ Migrations.forgetMistakenlyBlockedDomains,
+ Migrations.unblockIncorrectlyBlockedDomains,
+ Migrations.forgetBlockedDNTDomains,
+ Migrations.reapplyYellowlist,
+ Migrations.forgetNontrackingDomains,
+ Migrations.forgetMistakenlyBlockedDomains,
+ Migrations.resetWebRTCIPHandlingPolicy,
+ Migrations.enableShowNonTrackingDomains,
+ Migrations.forgetFirstPartySnitches,
+ Migrations.forgetCloudflare,
+ Migrations.forgetConsensu,
+ Migrations.resetWebRTCIPHandlingPolicy2,
+ ];
+
+ for (var i = migrationLevel; i < migrations.length; i++) {
+ migrations[i].call(Migrations, self);
+ settings.setItem('migrationLevel', i+1);
+ }
+
+ },
+
+ /**
+ * Returns the count of tracking domains for a tab.
+ * @param {Integer} tab_id browser tab ID
+ * @returns {Integer} tracking domains count
+ */
+ getTrackerCount: function (tab_id) {
+ let origins = this.tabData[tab_id].origins,
+ count = 0;
+
+ for (let domain in origins) {
+ let action = origins[domain];
+ if (
+ action == constants.BLOCK ||
+ action == constants.COOKIEBLOCK ||
+ action == constants.USER_BLOCK ||
+ action == constants.USER_COOKIEBLOCK
+ ) {
+ count++;
+ }
+ }
+
+ return count;
+ },
+
+ /**
+ * Update page action badge with current count.
+ * @param {Integer} tab_id browser tab ID
+ */
+ updateBadge: function (tab_id) {
+ if (!FirefoxAndroid.hasBadgeSupport) {
+ return;
+ }
+
+ let self = this;
+
+ chrome.tabs.get(tab_id, function (tab) {
+ if (chrome.runtime.lastError) {
+ // don't set on background (prerendered) tabs to avoid Chrome errors
+ return;
+ }
+
+ if (!tab.active) {
+ // don't set on inactive tabs
+ return;
+ }
+
+ if (self.criticalError) {
+ chrome.browserAction.setBadgeBackgroundColor({tabId: tab_id, color: "#cc0000"});
+ chrome.browserAction.setBadgeText({tabId: tab_id, text: "!"});
+ return;
+ }
+
+ // don't show the counter for any of these:
+ // - the counter is disabled
+ // - we don't have tabData for whatever reason (special browser pages)
+ // - Privacy Badger is disabled on the page
+ if (
+ !self.getSettings().getItem("showCounter") ||
+ !self.tabData.hasOwnProperty(tab_id) ||
+ !self.isPrivacyBadgerEnabled(self.getFrameData(tab_id).host)
+ ) {
+ chrome.browserAction.setBadgeText({tabId: tab_id, text: ""});
+ return;
+ }
+
+ let count = self.getTrackerCount(tab_id);
+
+ if (count === 0) {
+ chrome.browserAction.setBadgeText({tabId: tab_id, text: ""});
+ return;
+ }
+
+ chrome.browserAction.setBadgeBackgroundColor({tabId: tab_id, color: "#ec9329"});
+ chrome.browserAction.setBadgeText({tabId: tab_id, text: count + ""});
+ });
+ },
+
+ /**
+ * Shortcut helper for user-facing settings
+ */
+ getSettings: function () {
+ return this.storage.getStore('settings_map');
+ },
+
+ /**
+ * Shortcut helper for internal settings
+ */
+ getPrivateSettings: function () {
+ return this.storage.getStore('private_storage');
+ },
+
+ /**
+ * Check if privacy badger is enabled, take an origin and
+ * check against the disabledSites list
+ *
+ * @param {String} origin the origin to check
+ * @returns {Boolean} true if enabled
+ */
+ isPrivacyBadgerEnabled: function(origin) {
+ var settings = this.getSettings();
+ var disabledSites = settings.getItem("disabledSites");
+ if (disabledSites && disabledSites.length > 0) {
+ for (var i = 0; i < disabledSites.length; i++) {
+ var site = disabledSites[i];
+
+ if (site.startsWith("*")) {
+ var wildcard = site.slice(1); // remove "*"
+
+ if (origin.endsWith(wildcard)) {
+ return false;
+ }
+ }
+
+ if (disabledSites[i] === origin) {
+ return false;
+ }
+ }
+ }
+ return true;
+ },
+
+ /**
+ * Is local learning generally enabled,
+ * and if tab_id is for an incognito window,
+ * is learning in incognito windows enabled?
+ */
+ isLearningEnabled(tab_id) {
+ return (
+ this.getSettings().getItem("learnLocally") &&
+ incognito.learningEnabled(tab_id)
+ );
+ },
+
+ /**
+ * Check if widget replacement functionality is enabled.
+ */
+ isWidgetReplacementEnabled: function () {
+ return this.getSettings().getItem("socialWidgetReplacementEnabled");
+ },
+
+ isDNTSignalEnabled: function() {
+ return this.getSettings().getItem("sendDNTSignal");
+ },
+
+ isCheckingDNTPolicyEnabled: function() {
+ return this.getSettings().getItem("checkForDNTPolicy");
+ },
+
+ /**
+ * Add an origin to the disabled sites list
+ *
+ * @param {String} origin The origin to disable the PB for
+ */
+ disablePrivacyBadgerForOrigin: function(origin) {
+ var settings = this.getSettings();
+ var disabledSites = settings.getItem('disabledSites');
+ if (disabledSites.indexOf(origin) < 0) {
+ disabledSites.push(origin);
+ settings.setItem("disabledSites", disabledSites);
+ }
+ },
+
+ /**
+ * Returns the current list of disabled sites.
+ *
+ * @returns {Array} site domains where Privacy Badger is disabled
+ */
+ getDisabledSites: function () {
+ return this.getSettings().getItem("disabledSites");
+ },
+
+ /**
+ * Remove an origin from the disabledSites list
+ *
+ * @param {String} origin The origin to disable the PB for
+ */
+ enablePrivacyBadgerForOrigin: function(origin) {
+ var settings = this.getSettings();
+ var disabledSites = settings.getItem("disabledSites");
+ var idx = disabledSites.indexOf(origin);
+ if (idx >= 0) {
+ disabledSites.splice(idx, 1);
+ settings.setItem("disabledSites", disabledSites);
+ }
+ },
+
+ /**
+ * Checks if local storage ( in dict) has any high-entropy keys
+ *
+ * @param {Object} lsItems Local storage dict
+ * @returns {boolean} true if it seems there are supercookies
+ */
+ hasLocalStorageSupercookie: function (lsItems) {
+ var LOCALSTORAGE_ENTROPY_THRESHOLD = 33, // in bits
+ estimatedEntropy = 0,
+ lsKey = "",
+ lsItem = "";
+ for (lsKey in lsItems) {
+ // send both key and value to entropy estimation
+ lsItem = lsItems[lsKey];
+ log("Checking localstorage item", lsKey, lsItem);
+ estimatedEntropy += utils.estimateMaxEntropy(lsKey + lsItem);
+ if (estimatedEntropy > LOCALSTORAGE_ENTROPY_THRESHOLD) {
+ log("Found high-entropy localStorage: ", estimatedEntropy,
+ " bits, key: ", lsKey);
+ return true;
+ }
+ }
+ return false;
+ },
+
+ /**
+ * check if there seems to be any type of Super Cookie
+ *
+ * @param {Object} storageItems Dict with storage items
+ * @returns {Boolean} true if there seems to be any Super cookie
+ */
+ hasSupercookie: function (storageItems) {
+ return (
+ this.hasLocalStorageSupercookie(storageItems.localStorageItems)
+ //|| this.hasLocalStorageSupercookie(storageItems.indexedDBItems)
+ // TODO: See "Reading a directory's contents" on
+ // http://www.html5rocks.com/en/tutorials/file/filesystem/
+ //|| this.hasLocalStorageSupercookie(storageItems.fileSystemAPIItems)
+ );
+ },
+
+ /**
+ * Save third party origins to tabData[tab_id] object for
+ * use in the popup and, if needed, call updateBadge.
+ *
+ * @param {Integer} tab_id the tab we are on
+ * @param {String} fqdn the third party origin to add
+ * @param {String} action the action we are taking
+ */
+ logThirdPartyOriginOnTab: function (tab_id, fqdn, action) {
+ let self = this,
+ is_blocked = (
+ action == constants.BLOCK ||
+ action == constants.COOKIEBLOCK ||
+ action == constants.USER_BLOCK ||
+ action == constants.USER_COOKIEBLOCK
+ ),
+ origins = self.tabData[tab_id].origins,
+ previously_blocked = origins.hasOwnProperty(fqdn) && (
+ origins[fqdn] == constants.BLOCK ||
+ origins[fqdn] == constants.COOKIEBLOCK ||
+ origins[fqdn] == constants.USER_BLOCK ||
+ origins[fqdn] == constants.USER_COOKIEBLOCK
+ );
+
+ origins[fqdn] = action;
+
+ // no need to update badge if not a (cookie)blocked domain,
+ // or if we have already seen it as a (cookie)blocked domain
+ if (!is_blocked || previously_blocked) {
+ return;
+ }
+
+ // don't block critical code paths on updating the badge
+ setTimeout(function () {
+ self.updateBadge(tab_id);
+ }, 0);
+ },
+
+ /**
+ * Enables or disables page action icon according to options.
+ * @param {Integer} tab_id The tab ID to set the badger icon for
+ * @param {String} tab_url The tab URL to set the badger icon for
+ */
+ updateIcon: function (tab_id, tab_url) {
+ if (!tab_id || !tab_url || !FirefoxAndroid.hasPopupSupport) {
+ return;
+ }
+
+ let self = this, iconFilename;
+
+ // TODO grab hostname from tabData instead
+ if (!utils.isRestrictedUrl(tab_url) &&
+ self.isPrivacyBadgerEnabled(window.extractHostFromURL(tab_url))) {
+ iconFilename = {
+ 19: chrome.runtime.getURL("icons/badger-19.png"),
+ 38: chrome.runtime.getURL("icons/badger-38.png")
+ };
+ } else {
+ iconFilename = {
+ 19: chrome.runtime.getURL("icons/badger-19-disabled.png"),
+ 38: chrome.runtime.getURL("icons/badger-38-disabled.png")
+ };
+ }
+
+ chrome.browserAction.setIcon({tabId: tab_id, path: iconFilename});
+ },
+
+ /**
+ * Merge data exported from a different badger into this badger's storage.
+ *
+ * @param {Object} data the user data to merge in
+ * @param {Boolean} [skip_migrations=false] set when running from a migration to avoid infinite loop
+ */
+ mergeUserData: function (data, skip_migrations) {
+ let self = this;
+ // The order of these keys is also the order in which they should be imported.
+ // It's important that snitch_map be imported before action_map (#1972)
+ ["snitch_map", "action_map", "settings_map"].forEach(function (key) {
+ if (data.hasOwnProperty(key)) {
+ self.storage.getStore(key).merge(data[key]);
+ }
+ });
+
+ // for exports from older Privacy Badger versions:
+ // fix yellowlist getting out of sync, remove non-tracking domains, etc.
+ if (!skip_migrations) {
+ self.runMigrations();
+ }
+ }
+
+};
+
+/**************************** Listeners ****************************/
+
+function startBackgroundListeners() {
+ chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
+ if (changeInfo.status == "loading" && tab.url) {
+ badger.updateIcon(tab.id, tab.url);
+ badger.updateBadge(tabId);
+ }
+ });
+
+ // Update icon if a tab is replaced or loaded from cache
+ chrome.tabs.onReplaced.addListener(function(addedTabId/*, removedTabId*/) {
+ chrome.tabs.get(addedTabId, function(tab) {
+ badger.updateIcon(tab.id, tab.url);
+ });
+ });
+
+ chrome.tabs.onActivated.addListener(function (activeInfo) {
+ badger.updateBadge(activeInfo.tabId);
+ });
+}
+
+var badger = window.badger = new Badger();
diff --git a/src/js/bootstrap.js b/src/js/bootstrap.js
new file mode 100644
index 0000000..7d90ef4
--- /dev/null
+++ b/src/js/bootstrap.js
@@ -0,0 +1,37 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2014 Electronic Frontier Foundation
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+window.DEBUG = false;
+window.badger = {};
+
+/**
+* Log a message to the console if debugging is enabled
+*/
+window.log = function (/*...*/) {
+ if (window.DEBUG) {
+ console.log.apply(console, arguments);
+ }
+};
+
+/**
+ * Basic implementation of requirejs
+ * for requiring other javascript files
+ */
+function require(module) {
+ return require.scopes[module];
+}
+require.scopes = {};
diff --git a/src/js/constants.js b/src/js/constants.js
new file mode 100644
index 0000000..5a77d02
--- /dev/null
+++ b/src/js/constants.js
@@ -0,0 +1,54 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2014 Electronic Frontier Foundation
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+require.scopes.constants = (function() {
+
+var exports = {
+
+ // Tracking status constants
+ NO_TRACKING: "noaction",
+ ALLOW: "allow",
+ BLOCK: "block",
+ COOKIEBLOCK: "cookieblock",
+ DNT: "dnt",
+ USER_ALLOW: "user_allow",
+ USER_BLOCK: "user_block",
+ USER_COOKIEBLOCK: "user_cookieblock",
+
+ // URLS
+ DNT_POLICIES_URL: "https://www.eff.org/files/dnt-policies.json",
+ DNT_POLICIES_LOCAL_URL: chrome.runtime.getURL('data/dnt-policies.json'),
+ YELLOWLIST_URL: "https://www.eff.org/files/cookieblocklist_new.txt",
+ YELLOWLIST_LOCAL_URL: chrome.runtime.getURL('data/yellowlist.txt'),
+ SEED_DATA_LOCAL_URL: chrome.runtime.getURL('data/seed.json'),
+
+ // The number of 1st parties a 3rd party can be seen on
+ TRACKING_THRESHOLD: 3,
+ MAX_COOKIE_ENTROPY: 12,
+
+ DNT_POLICY_CHECK_INTERVAL: 1000, // one second
+};
+
+exports.BLOCKED_ACTIONS = new Set([
+ exports.BLOCK,
+ exports.USER_BLOCK,
+ exports.COOKIEBLOCK,
+ exports.USER_COOKIEBLOCK,
+]);
+
+return exports;
+})();
diff --git a/src/js/contentscripts/clobbercookie.js b/src/js/contentscripts/clobbercookie.js
new file mode 100644
index 0000000..402d00e
--- /dev/null
+++ b/src/js/contentscripts/clobbercookie.js
@@ -0,0 +1,60 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2014 Electronic Frontier Foundation
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+(function () {
+
+// don't inject into non-HTML documents (such as XML documents)
+// but do inject into XHTML documents
+if (document instanceof HTMLDocument === false && (
+ document instanceof XMLDocument === false ||
+ document.createElement('div') instanceof HTMLDivElement === false
+)) {
+ return;
+}
+
+// don't bother asking to run when trivially in first-party context
+if (window.top == window) {
+ return;
+}
+
+// TODO race condition; fix waiting on https://crbug.com/478183
+chrome.runtime.sendMessage({
+ type: "checkLocation",
+ frameUrl: window.FRAME_URL
+}, function (blocked) {
+ if (blocked) {
+ var code = '('+ function() {
+ document.__defineSetter__("cookie", function(/*value*/) { });
+ document.__defineGetter__("cookie", function() { return ""; });
+
+ // trim referrer down to origin
+ let referrer = document.referrer;
+ if (referrer) {
+ referrer = referrer.slice(
+ 0,
+ referrer.indexOf('/', referrer.indexOf('://') + 3)
+ ) + '/';
+ }
+ document.__defineGetter__("referrer", function () { return referrer; });
+ } +')();';
+
+ window.injectScript(code);
+ }
+ return true;
+});
+
+}());
diff --git a/src/js/contentscripts/clobberlocalstorage.js b/src/js/contentscripts/clobberlocalstorage.js
new file mode 100644
index 0000000..7ff3528
--- /dev/null
+++ b/src/js/contentscripts/clobberlocalstorage.js
@@ -0,0 +1,94 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2014 Electronic Frontier Foundation
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+(function () {
+
+// don't inject into non-HTML documents (such as XML documents)
+// but do inject into XHTML documents
+if (document instanceof HTMLDocument === false && (
+ document instanceof XMLDocument === false ||
+ document.createElement('div') instanceof HTMLDivElement === false
+)) {
+ return;
+}
+
+// don't bother asking to run when trivially in first-party context
+if (window.top == window) {
+ return;
+}
+
+// TODO race condition; fix waiting on https://crbug.com/478183
+chrome.runtime.sendMessage({
+ type: "checkLocation",
+ frameUrl: window.FRAME_URL
+}, function (blocked) {
+ if (blocked) {
+ // https://stackoverflow.com/questions/49092423/how-to-break-on-localstorage-changes
+ var code =
+ '('+ function() {
+
+ /*
+ * If localStorage is inaccessible, such as when "Block third-party cookies"
+ * in enabled in Chrome or when `dom.storage.enabled` is set to `false` in
+ * Firefox, do not go any further.
+ */
+ try {
+ // No localStorage raises an Exception in Chromium-based browsers, while
+ // it's equal to `null` in Firefox.
+ if (null === localStorage) {
+ throw false;
+ }
+ } catch (ex) {
+ return;
+ }
+
+ let lsProxy = new Proxy(localStorage, {
+ set: function (/*ls, prop, value*/) {
+ return true;
+ },
+ get: function (ls, prop) {
+ if (typeof ls[prop] == 'function') {
+ let fn = function () {};
+ if (prop == 'getItem' || prop == 'key') {
+ fn = function () { return null; };
+ }
+ return fn.bind(ls);
+ } else {
+ if (prop == 'length') {
+ return 0;
+ } else if (prop == '__proto__') {
+ return lsProxy;
+ }
+ return;
+ }
+ }
+ });
+
+ Object.defineProperty(window, 'localStorage', {
+ configurable: true,
+ enumerable: true,
+ value: lsProxy
+ });
+
+ } +')()';
+
+ window.injectScript(code);
+ }
+ return true;
+});
+
+}());
diff --git a/src/js/contentscripts/collapser.js b/src/js/contentscripts/collapser.js
new file mode 100644
index 0000000..968905c
--- /dev/null
+++ b/src/js/contentscripts/collapser.js
@@ -0,0 +1,56 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2020 Electronic Frontier Foundation
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+(function () {
+
+// don't inject into non-HTML documents (such as XML documents)
+// but do inject into XHTML documents
+if (document instanceof HTMLDocument === false && (
+ document instanceof XMLDocument === false ||
+ document.createElement('div') instanceof HTMLDivElement === false
+)) {
+ return;
+}
+
+function hideFrame(url) {
+ let sel = "iframe[src='" + CSS.escape(url) + "']";
+ let el = document.querySelector(sel);
+ if (el) { // el could have gotten replaced since the lookup
+ el.style.setProperty("display", "none", "important");
+ }
+}
+
+chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
+ if (request.hideFrame) {
+ hideFrame(request.url);
+ sendResponse(true);
+ }
+});
+
+// check the page for any frames that were blocked before we got here
+chrome.runtime.sendMessage({
+ type: "getBlockedFrameUrls"
+}, function (frameUrls) {
+ if (!frameUrls) {
+ return;
+ }
+ for (let url of frameUrls) {
+ hideFrame(url);
+ }
+});
+
+}());
diff --git a/src/js/contentscripts/dnt.js b/src/js/contentscripts/dnt.js
new file mode 100644
index 0000000..0584748
--- /dev/null
+++ b/src/js/contentscripts/dnt.js
@@ -0,0 +1,66 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2018 Electronic Frontier Foundation
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+function getPageScript() {
+
+ // code below is not a content script: no chrome.* APIs /////////////////////
+
+ // return a string
+ return "(" + function (NAVIGATOR, OBJECT) {
+
+ OBJECT.defineProperty(OBJECT.getPrototypeOf(NAVIGATOR), "doNotTrack", {
+ get: function doNotTrack() {
+ return "1";
+ }
+ });
+
+ OBJECT.defineProperty(OBJECT.getPrototypeOf(NAVIGATOR), "globalPrivacyControl", {
+ get: function globalPrivacyControl() {
+ return "1";
+ }
+ });
+
+ // save locally to keep from getting overwritten by site code
+ } + "(window.navigator, Object));";
+
+ // code above is not a content script: no chrome.* APIs /////////////////////
+
+}
+
+// END FUNCTION DEFINITIONS ///////////////////////////////////////////////////
+
+(function () {
+
+// don't inject into non-HTML documents (such as XML documents)
+// but do inject into XHTML documents
+if (document instanceof HTMLDocument === false && (
+ document instanceof XMLDocument === false ||
+ document.createElement('div') instanceof HTMLDivElement === false
+)) {
+ return;
+}
+
+// TODO race condition; fix waiting on https://crbug.com/478183
+chrome.runtime.sendMessage({
+ type: "checkDNT"
+}, function (enabled) {
+ if (enabled) {
+ window.injectScript(getPageScript());
+ }
+});
+
+}());
diff --git a/src/js/contentscripts/fingerprinting.js b/src/js/contentscripts/fingerprinting.js
new file mode 100644
index 0000000..0891896
--- /dev/null
+++ b/src/js/contentscripts/fingerprinting.js
@@ -0,0 +1,367 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2015 Electronic Frontier Foundation
+ *
+ * Derived from Chameleon <https://github.com/ghostwords/chameleon>
+ * Copyright (C) 2015 ghostwords
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+function getFpPageScript() {
+
+ // code below is not a content script: no chrome.* APIs /////////////////////
+
+ // return a string
+ return "(" + function (DOCUMENT, dispatchEvent, CUSTOM_EVENT, ERROR, DATE, setTimeout, OBJECT) {
+
+ const V8_STACK_TRACE_API = !!(ERROR && ERROR.captureStackTrace);
+
+ if (V8_STACK_TRACE_API) {
+ ERROR.stackTraceLimit = Infinity; // collect all frames
+ } else {
+ // from https://github.com/csnover/TraceKit/blob/b76ad786f84ed0c94701c83d8963458a8da54d57/tracekit.js#L641
+ var geckoCallSiteRe = /^\s*(.*?)(?:\((.*?)\))?@?((?:file|https?|chrome):.*?):(\d+)(?::(\d+))?\s*$/i;
+ }
+
+ var event_id = DOCUMENT.currentScript.getAttribute('data-event-id');
+
+ // from Underscore v1.6.0
+ function debounce(func, wait, immediate) {
+ var timeout, args, context, timestamp, result;
+
+ var later = function () {
+ var last = DATE.now() - timestamp;
+ if (last < wait) {
+ timeout = setTimeout(later, wait - last);
+ } else {
+ timeout = null;
+ if (!immediate) {
+ result = func.apply(context, args);
+ context = args = null;
+ }
+ }
+ };
+
+ return function () {
+ context = this; // eslint-disable-line consistent-this
+ args = arguments;
+ timestamp = DATE.now();
+ var callNow = immediate && !timeout;
+ if (!timeout) {
+ timeout = setTimeout(later, wait);
+ }
+ if (callNow) {
+ result = func.apply(context, args);
+ context = args = null;
+ }
+
+ return result;
+ };
+ }
+
+ // messages the injected script
+ var send = (function () {
+ var messages = [];
+
+ // debounce sending queued messages
+ var _send = debounce(function () {
+ dispatchEvent.call(DOCUMENT, new CUSTOM_EVENT(event_id, {
+ detail: messages
+ }));
+
+ // clear the queue
+ messages = [];
+ }, 100);
+
+ return function (msg) {
+ // queue the message
+ messages.push(msg);
+
+ _send();
+ };
+ }());
+
+ /**
+ * Gets the stack trace by throwing and catching an exception.
+ * @returns {*} Returns the stack trace
+ */
+ function getStackTraceFirefox() {
+ let stack;
+
+ try {
+ throw new ERROR();
+ } catch (err) {
+ stack = err.stack;
+ }
+
+ return stack.split('\n');
+ }
+
+ /**
+ * Gets the stack trace using the V8 stack trace API:
+ * https://github.com/v8/v8/wiki/Stack-Trace-API
+ * @returns {*} Returns the stack trace
+ */
+ function getStackTrace() {
+ let err = {},
+ origFormatter,
+ stack;
+
+ origFormatter = ERROR.prepareStackTrace;
+ ERROR.prepareStackTrace = function (_, structuredStackTrace) {
+ return structuredStackTrace;
+ };
+
+ ERROR.captureStackTrace(err, getStackTrace);
+ stack = err.stack;
+
+ ERROR.prepareStackTrace = origFormatter;
+
+ return stack;
+ }
+
+ /**
+ * Strip away the line and column number (from stack trace urls)
+ * @param script_url The stack trace url to strip
+ * @returns {String} the pure URL
+ */
+ function stripLineAndColumnNumbers(script_url) {
+ return script_url.replace(/:\d+:\d+$/, '');
+ }
+
+ /**
+ * Parses the stack trace for the originating script URL
+ * without using the V8 stack trace API.
+ * @returns {String} The URL of the originating script
+ */
+ function getOriginatingScriptUrlFirefox() {
+ let trace = getStackTraceFirefox();
+
+ if (trace.length < 4) {
+ return '';
+ }
+
+ // this script is at 0, 1 and 2
+ let callSite = trace[3];
+
+ let scriptUrlMatches = callSite.match(geckoCallSiteRe);
+ return scriptUrlMatches && scriptUrlMatches[3] || '';
+ }
+
+ /**
+ * Parses the stack trace for the originating script URL.
+ * @returns {String} The URL of the originating script
+ */
+ function getOriginatingScriptUrl() {
+ let trace = getStackTrace();
+
+ if (OBJECT.prototype.toString.call(trace) == '[object String]') {
+ // we failed to get a structured stack trace
+ trace = trace.split('\n');
+ // this script is at 0, 1, 2 and 3
+ let script_url_matches = trace[4].match(/\((http.*:\d+:\d+)/);
+ // TODO do we need stripLineAndColumnNumbers (in both places) here?
+ return script_url_matches && stripLineAndColumnNumbers(script_url_matches[1]) || stripLineAndColumnNumbers(trace[4]);
+ }
+
+ if (trace.length < 2) {
+ return '';
+ }
+
+ // this script is at 0 and 1
+ let callSite = trace[2];
+
+ if (callSite.isEval()) {
+ // argh, getEvalOrigin returns a string ...
+ let eval_origin = callSite.getEvalOrigin(),
+ script_url_matches = eval_origin.match(/\((http.*:\d+:\d+)/);
+
+ // TODO do we need stripLineAndColumnNumbers (in both places) here?
+ return script_url_matches && stripLineAndColumnNumbers(script_url_matches[1]) || stripLineAndColumnNumbers(eval_origin);
+ } else {
+ return callSite.getFileName();
+ }
+ }
+
+ /**
+ * Monitor the writes in a canvas instance
+ * @param item special item objects
+ */
+ function trapInstanceMethod(item) {
+ var is_canvas_write = (
+ item.propName == 'fillText' || item.propName == 'strokeText'
+ );
+
+ item.obj[item.propName] = (function (orig) {
+ // set to true after the first write, if the method is not
+ // restorable. Happens if another library also overwrites
+ // this method.
+ var skip_monitoring = false;
+
+ function wrapped() {
+ var args = arguments;
+
+ if (is_canvas_write) {
+ // to avoid false positives,
+ // bail if the text being written is too short,
+ // of if we've already sent a monitoring payload
+ if (skip_monitoring || !args[0] || args[0].length < 5) {
+ return orig.apply(this, args);
+ }
+ }
+
+ var script_url = (
+ V8_STACK_TRACE_API ?
+ getOriginatingScriptUrl() :
+ getOriginatingScriptUrlFirefox()
+ ),
+ msg = {
+ obj: item.objName,
+ prop: item.propName,
+ scriptUrl: script_url
+ };
+
+ if (item.hasOwnProperty('extra')) {
+ msg.extra = item.extra.apply(this, args);
+ }
+
+ send(msg);
+
+ if (is_canvas_write) {
+ // optimization: one canvas write is enough,
+ // restore original write method
+ // to this CanvasRenderingContext2D object instance
+ // Careful! Only restorable if we haven't already been replaced
+ // by another lib, such as the hidpi polyfill
+ if (this[item.propName] === wrapped) {
+ this[item.propName] = orig;
+ } else {
+ skip_monitoring = true;
+ }
+ }
+
+ return orig.apply(this, args);
+ }
+
+ OBJECT.defineProperty(wrapped, "name", { value: orig.name });
+ OBJECT.defineProperty(wrapped, "length", { value: orig.length });
+ OBJECT.defineProperty(wrapped, "toString", { value: orig.toString.bind(orig) });
+
+ return wrapped;
+
+ }(item.obj[item.propName]));
+ }
+
+ var methods = [];
+
+ ['getImageData', 'fillText', 'strokeText'].forEach(function (method) {
+ var item = {
+ objName: 'CanvasRenderingContext2D.prototype',
+ propName: method,
+ obj: CanvasRenderingContext2D.prototype,
+ extra: function () {
+ return {
+ canvas: true
+ };
+ }
+ };
+
+ if (method == 'getImageData') {
+ item.extra = function () {
+ var args = arguments,
+ width = args[2],
+ height = args[3];
+
+ // "this" is a CanvasRenderingContext2D object
+ if (width === undefined) {
+ width = this.canvas.width;
+ }
+ if (height === undefined) {
+ height = this.canvas.height;
+ }
+
+ return {
+ canvas: true,
+ width: width,
+ height: height
+ };
+ };
+ }
+
+ methods.push(item);
+ });
+
+ methods.push({
+ objName: 'HTMLCanvasElement.prototype',
+ propName: 'toDataURL',
+ obj: HTMLCanvasElement.prototype,
+ extra: function () {
+ // "this" is a canvas element
+ return {
+ canvas: true,
+ width: this.width,
+ height: this.height
+ };
+ }
+ });
+
+ methods.forEach(trapInstanceMethod);
+
+ // save locally to keep from getting overwritten by site code
+ } + "(document, document.dispatchEvent, CustomEvent, Error, Date, setTimeout, Object));";
+
+ // code above is not a content script: no chrome.* APIs /////////////////////
+
+}
+
+// END FUNCTION DEFINITIONS ///////////////////////////////////////////////////
+
+(function () {
+
+// don't inject into non-HTML documents (such as XML documents)
+// but do inject into XHTML documents
+if (document instanceof HTMLDocument === false && (
+ document instanceof XMLDocument === false ||
+ document.createElement('div') instanceof HTMLDivElement === false
+)) {
+ return;
+}
+
+// TODO race condition; fix waiting on https://crbug.com/478183
+chrome.runtime.sendMessage({
+ type: "detectFingerprinting"
+}, function (enabled) {
+ if (!enabled) {
+ return;
+ }
+ /**
+ * Communicating to webrequest.js
+ */
+ var event_id = Math.random();
+
+ // listen for messages from the script we are about to insert
+ document.addEventListener(event_id, function (e) {
+ // pass these on to the background page
+ chrome.runtime.sendMessage({
+ type: "fpReport",
+ data: e.detail
+ });
+ });
+
+ window.injectScript(getFpPageScript(), {
+ event_id: event_id
+ });
+});
+
+}());
diff --git a/src/js/contentscripts/socialwidgets.js b/src/js/contentscripts/socialwidgets.js
new file mode 100644
index 0000000..14ae2b3
--- /dev/null
+++ b/src/js/contentscripts/socialwidgets.js
@@ -0,0 +1,641 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2014 Electronic Frontier Foundation
+ * Derived from ShareMeNot
+ * Copyright (C) 2011-2014 University of Washington
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * ShareMeNot is licensed under the MIT license:
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * Copyright (c) 2011-2014 University of Washington
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+// widget data
+let widgetList;
+
+// cached chrome.i18n.getMessage() results
+const TRANSLATIONS = {};
+
+// references to widget page elements
+const WIDGET_ELS = {};
+
+
+/**
+ * @param {Object} response response to checkWidgetReplacementEnabled
+ */
+function initialize(response) {
+ for (const key in response.translations) {
+ TRANSLATIONS[key] = response.translations[key];
+ }
+
+ widgetList = response.widgetList;
+
+ // check for widgets blocked before we got here
+ replaceInitialTrackerButtonsHelper(response.widgetsToReplace);
+
+ // set up listener for dynamically created widgets
+ chrome.runtime.onMessage.addListener(function (request) {
+ if (request.replaceWidget) {
+ replaceSubsequentTrackerButtonsHelper(request.trackerDomain);
+ }
+ });
+}
+
+/**
+ * Creates a replacement placeholder element for the given widget.
+ *
+ * @param {Object} widget the SocialWidget object
+ * @param {Element} trackerElem the button/widget element we are replacing
+ * @param {Function} callback called with the replacement element
+ */
+function createReplacementElement(widget, trackerElem, callback) {
+ let buttonData = widget.replacementButton;
+
+ // no image data to fetch
+ if (!buttonData.hasOwnProperty('imagePath')) {
+ return setTimeout(function () {
+ _createReplacementElementCallback(widget, trackerElem, callback);
+ }, 0);
+ }
+
+ // already have replacement button image URI cached
+ if (buttonData.buttonUrl) {
+ return setTimeout(function () {
+ _createReplacementElementCallback(widget, trackerElem, callback);
+ }, 0);
+ }
+
+ // already messaged for but haven't yet received the image data
+ if (buttonData.loading) {
+ // check back in 10 ms
+ return setTimeout(function () {
+ createReplacementElement(widget, trackerElem, callback);
+ }, 10);
+ }
+
+ // don't have image data cached yet, get it from the background page
+ buttonData.loading = true;
+ chrome.runtime.sendMessage({
+ type: "getReplacementButton",
+ widgetName: widget.name
+ }, function (response) {
+ if (response) {
+ buttonData.buttonUrl = response; // cache image data
+ _createReplacementElementCallback(widget, trackerElem, callback);
+ }
+ });
+}
+
+function _createReplacementElementCallback(widget, trackerElem, callback) {
+ if (widget.replacementButton.buttonUrl) {
+ _createButtonReplacement(widget, callback);
+ } else {
+ _createWidgetReplacement(widget, trackerElem, callback);
+ }
+}
+
+function _createButtonReplacement(widget, callback) {
+ let buttonData = widget.replacementButton,
+ button_type = buttonData.type;
+
+ let button = document.createElement("img");
+ button.setAttribute("src", buttonData.buttonUrl);
+
+ // TODO use custom tooltip to support RTL locales?
+ button.setAttribute(
+ "title",
+ TRANSLATIONS.social_tooltip_pb_has_replaced.replace("XXX", widget.name)
+ );
+
+ let styleAttrs = [
+ "border: none",
+ "cursor: pointer",
+ "height: auto",
+ "width: auto",
+ ];
+ button.setAttribute("style", styleAttrs.join(" !important;") + " !important");
+
+ // normal button type; just open a new window when clicked
+ if (button_type === 0) {
+ let popup_url = buttonData.details + encodeURIComponent(window.location.href);
+
+ button.addEventListener("click", function () {
+ window.open(popup_url);
+ });
+
+ // in place button type; replace the existing button
+ // with an iframe when clicked
+ } else if (button_type == 1) {
+ let iframe_url = buttonData.details + encodeURIComponent(window.location.href);
+
+ button.addEventListener("click", function () {
+ replaceButtonWithIframeAndUnblockTracker(button, widget.name, iframe_url);
+ }, { once: true });
+
+ // in place button type; replace the existing button with code
+ // specified in the widgets JSON
+ } else if (button_type == 2) {
+ button.addEventListener("click", function () {
+ replaceButtonWithHtmlCodeAndUnblockTracker(button, widget.name, buttonData.details);
+ }, { once: true });
+ }
+
+ callback(button);
+}
+
+function _createWidgetReplacement(widget, trackerElem, callback) {
+ let replacementEl;
+
+ // in-place widget type:
+ // reinitialize the widget by reinserting its element's HTML
+ if (widget.replacementButton.type == 3) {
+ replacementEl = createReplacementWidget(
+ widget, trackerElem, reinitializeWidgetAndUnblockTracker);
+
+ // in-place widget type:
+ // reinitialize the widget by reinserting its element's HTML
+ // and activating associated scripts
+ } else if (widget.replacementButton.type == 4) {
+ let activationFn = replaceWidgetAndReloadScripts;
+
+ // if there are no matching script elements
+ if (!document.querySelectorAll(widget.scriptSelectors.join(',')).length) {
+ // and we don't have a fallback script URL
+ if (!widget.fallbackScriptUrl) {
+ // we can't do "in-place" activation; reload the page instead
+ activationFn = function () {
+ unblockTracker(widget.name, function () {
+ location.reload();
+ });
+ };
+ }
+ }
+
+ replacementEl = createReplacementWidget(widget, trackerElem, activationFn);
+ }
+
+ callback(replacementEl);
+}
+
+/**
+ * Unblocks the given widget and replaces the given button with an iframe
+ * pointing to the given URL.
+ *
+ * @param {Element} button the DOM element of the button to replace
+ * @param {String} widget_name the name of the replacement widget
+ * @param {String} iframeUrl the URL of the iframe to replace the button
+ */
+function replaceButtonWithIframeAndUnblockTracker(button, widget_name, iframeUrl) {
+ unblockTracker(widget_name, function () {
+ // check is needed as for an unknown reason this callback function is
+ // executed for buttons that have already been removed; we are trying
+ // to prevent replacing an already removed button
+ if (button.parentNode !== null) {
+ let iframe = document.createElement("iframe");
+
+ iframe.setAttribute("src", iframeUrl);
+ iframe.setAttribute("style", "border: none !important; height: 1.5em !important;");
+
+ button.parentNode.replaceChild(iframe, button);
+ }
+ });
+}
+
+/**
+ * Unblocks the given widget and replaces the given button with the
+ * HTML code defined in the provided SocialWidget object.
+ *
+ * @param {Element} button the DOM element of the button to replace
+ * @param {String} widget_name the name of the replacement widget
+ * @param {String} html the HTML string that should replace the button
+ */
+function replaceButtonWithHtmlCodeAndUnblockTracker(button, widget_name, html) {
+ unblockTracker(widget_name, function () {
+ // check is needed as for an unknown reason this callback function is
+ // executed for buttons that have already been removed; we are trying
+ // to prevent replacing an already removed button
+ if (button.parentNode !== null) {
+ let codeContainer = document.createElement("div");
+ codeContainer.innerHTML = html;
+
+ button.parentNode.replaceChild(codeContainer, button);
+
+ replaceScriptsRecurse(codeContainer);
+ }
+ });
+}
+
+/**
+ * Unblocks the given widget and replaces our replacement placeholder
+ * with the original third-party widget element.
+ *
+ * The teardown to the initialization defined in createReplacementWidget().
+ *
+ * @param {String} name the name/type of this widget (SoundCloud, Vimeo etc.)
+ */
+function reinitializeWidgetAndUnblockTracker(name) {
+ unblockTracker(name, function () {
+ // restore all widgets of this type
+ WIDGET_ELS[name].forEach(data => {
+ data.parent.replaceChild(data.widget, data.replacement);
+ });
+ WIDGET_ELS[name] = [];
+ });
+}
+
+/**
+ * Similar to reinitializeWidgetAndUnblockTracker() above,
+ * but also reruns scripts defined in scriptSelectors.
+ *
+ * @param {String} name the name/type of this widget (Disqus, Google reCAPTCHA)
+ */
+function replaceWidgetAndReloadScripts(name) {
+ unblockTracker(name, function () {
+ // restore all widgets of this type
+ WIDGET_ELS[name].forEach(data => {
+ data.parent.replaceChild(data.widget, data.replacement);
+ reloadScripts(data.scriptSelectors, data.fallbackScriptUrl);
+ });
+ WIDGET_ELS[name] = [];
+ });
+}
+
+/**
+ * Find and replace script elements with their copies to trigger re-running.
+ */
+function reloadScripts(selectors, fallback_script_url) {
+ let scripts = document.querySelectorAll(selectors.join(','));
+
+ // if there are no matches, try a known script URL
+ if (!scripts.length && fallback_script_url) {
+ let parent = document.documentElement,
+ replacement = document.createElement("script");
+ replacement.src = fallback_script_url;
+ parent.insertBefore(replacement, parent.firstChild);
+ return;
+ }
+
+ for (let scriptEl of scripts) {
+ // reinsert script elements only
+ if (!scriptEl.nodeName || scriptEl.nodeName.toLowerCase() != 'script') {
+ continue;
+ }
+
+ let replacement = document.createElement("script");
+ for (let attr of scriptEl.attributes) {
+ replacement.setAttribute(attr.nodeName, attr.value);
+ }
+ scriptEl.parentNode.replaceChild(replacement, scriptEl);
+ // reinsert one script and quit
+ break;
+ }
+}
+
+/**
+ * Dumping scripts into innerHTML won't execute them, so replace them
+ * with executable scripts.
+ */
+function replaceScriptsRecurse(node) {
+ if (node.nodeName && node.nodeName.toLowerCase() == 'script' &&
+ node.getAttribute && node.getAttribute("type") == "text/javascript") {
+ let script = document.createElement("script");
+ script.text = node.innerHTML;
+ script.src = node.src;
+ node.parentNode.replaceChild(script, node);
+ } else {
+ let i = 0,
+ children = node.childNodes;
+ while (i < children.length) {
+ replaceScriptsRecurse(children[i]);
+ i++;
+ }
+ }
+ return node;
+}
+
+
+/**
+ * Replaces all tracker buttons on the current web page with the internal
+ * replacement buttons, respecting the user's blocking settings.
+ *
+ * @param {Array} widgetsToReplace a list of widget names to replace
+ */
+function replaceInitialTrackerButtonsHelper(widgetsToReplace) {
+ widgetList.forEach(function (widget) {
+ if (widgetsToReplace.hasOwnProperty(widget.name)) {
+ replaceIndividualButton(widget);
+ }
+ });
+}
+
+/**
+ * Individually replaces tracker buttons blocked after initial check.
+ */
+function replaceSubsequentTrackerButtonsHelper(tracker_domain) {
+ if (!widgetList) {
+ return;
+ }
+ widgetList.forEach(function (widget) {
+ let replace = widget.domains.some(domain => {
+ if (domain == tracker_domain) {
+ return true;
+ // leading wildcard
+ } else if (domain[0] == "*") {
+ if (tracker_domain.endsWith(domain.slice(1))) {
+ return true;
+ }
+ }
+ return false;
+ });
+ if (replace) {
+ replaceIndividualButton(widget);
+ }
+ });
+}
+
+function _make_id(prefix) {
+ return prefix + "-" + Math.random().toString().replace(".", "");
+}
+
+function createReplacementWidget(widget, elToReplace, activationFn) {
+ let name = widget.name;
+
+ let widgetFrame = document.createElement('iframe');
+
+ // widget replacement frame styles
+ let border_width = 1;
+ let styleAttrs = [
+ "background-color: #fff",
+ "border: " + border_width + "px solid #ec9329",
+ "min-width: 220px",
+ "min-height: 210px",
+ "max-height: 600px",
+ "z-index: 2147483647",
+ ];
+ if (elToReplace.offsetWidth > 0) {
+ styleAttrs.push(`width: ${elToReplace.offsetWidth - 2*border_width}px`);
+ }
+ if (elToReplace.offsetHeight > 0) {
+ styleAttrs.push(`height: ${elToReplace.offsetHeight - 2*border_width}px`);
+ }
+ widgetFrame.style = styleAttrs.join(" !important;") + " !important";
+
+ let widgetDiv = document.createElement('div');
+
+ // parent div styles
+ styleAttrs = [
+ "display: flex",
+ "flex-direction: column",
+ "align-items: center",
+ "justify-content: center",
+ "width: 100%",
+ "height: 100%",
+ ];
+ if (TRANSLATIONS.rtl) {
+ styleAttrs.push("direction: rtl");
+ }
+ widgetDiv.style = styleAttrs.join(" !important;") + " !important";
+
+ // child div styles
+ styleAttrs = [
+ "color: #303030",
+ "font-family: helvetica, arial, sans-serif",
+ "font-size: 16px",
+ "display: flex",
+ "flex-wrap: wrap",
+ "justify-content: center",
+ "text-align: center",
+ "margin: 10px",
+ ];
+
+ let textDiv = document.createElement('div');
+ textDiv.style = styleAttrs.join(" !important;") + " !important";
+ textDiv.appendChild(document.createTextNode(
+ TRANSLATIONS.widget_placeholder_pb_has_replaced.replace("XXX", name)));
+ let infoIcon = document.createElement('a'),
+ info_icon_id = _make_id("ico-help");
+ infoIcon.id = info_icon_id;
+ infoIcon.href = "https://privacybadger.org/#How-does-Privacy-Badger-handle-social-media-widgets";
+ infoIcon.rel = "noreferrer";
+ infoIcon.target = "_blank";
+ textDiv.appendChild(infoIcon);
+ widgetDiv.appendChild(textDiv);
+
+ let buttonDiv = document.createElement('div');
+ styleAttrs.push("width: 100%");
+ buttonDiv.style = styleAttrs.join(" !important;") + " !important";
+
+ // allow once button
+ let button = document.createElement('button'),
+ button_id = _make_id("btn-once");
+ button.id = button_id;
+ styleAttrs = [
+ "transition: background-color 0.25s ease-out, border-color 0.25s ease-out, color 0.25s ease-out",
+ "border-radius: 3px",
+ "cursor: pointer",
+ "font-family: 'Lucida Grande', 'Segoe UI', Tahoma, 'DejaVu Sans', Arial, sans-serif",
+ "font-size: 12px",
+ "font-weight: bold",
+ "line-height: 16px",
+ "padding: 10px",
+ "margin: 4px",
+ "text-align: center",
+ "width: 70%",
+ "max-width: 280px",
+ ];
+ button.style = styleAttrs.join(" !important;") + " !important";
+
+ // allow on this site button
+ let site_button = document.createElement('button'),
+ site_button_id = _make_id("btn-site");
+ site_button.id = site_button_id;
+ site_button.style = styleAttrs.join(" !important;") + " !important";
+
+ button.appendChild(document.createTextNode(TRANSLATIONS.allow_once));
+ site_button.appendChild(document.createTextNode(TRANSLATIONS.allow_on_site));
+
+ buttonDiv.appendChild(button);
+ buttonDiv.appendChild(site_button);
+
+ widgetDiv.appendChild(buttonDiv);
+
+ // save refs. to elements for use in teardown
+ if (!WIDGET_ELS.hasOwnProperty(name)) {
+ WIDGET_ELS[name] = [];
+ }
+ let data = {
+ parent: elToReplace.parentNode,
+ widget: elToReplace,
+ replacement: widgetFrame
+ };
+ if (widget.scriptSelectors) {
+ data.scriptSelectors = widget.scriptSelectors;
+ if (widget.fallbackScriptUrl) {
+ data.fallbackScriptUrl = widget.fallbackScriptUrl;
+ }
+ }
+ WIDGET_ELS[name].push(data);
+
+ // set up click handler
+ widgetFrame.addEventListener('load', function () {
+ let onceButton = widgetFrame.contentDocument.getElementById(button_id),
+ siteButton = widgetFrame.contentDocument.getElementById(site_button_id);
+
+ onceButton.addEventListener("click", function (e) {
+ e.preventDefault();
+ activationFn(name);
+ }, { once: true });
+
+ siteButton.addEventListener("click", function (e) {
+ e.preventDefault();
+
+ // first message the background page to record that
+ // this widget should always be allowed on this site
+ chrome.runtime.sendMessage({
+ type: "allowWidgetOnSite",
+ widgetName: name
+ }, function () {
+ activationFn(name);
+ });
+ }, { once: true });
+
+ }, false); // end of click handler
+
+ let head_styles = `
+html, body {
+ height: 100% !important;
+ overflow: hidden !important;
+}
+#${button_id} {
+ border: 2px solid #f06a0a !important;
+ background-color: #f06a0a !important;
+ color: #fefefe !important;
+}
+#${site_button_id} {
+ border: 2px solid #333 !important;
+ background-color: #fefefe !important;
+ color: #333 !important;
+}
+#${button_id}:hover {
+ background-color: #fefefe !important;
+ color: #333 !important;
+}
+#${site_button_id}:hover {
+ background-color: #fefefe !important;
+ border: 2px solid #f06a0a !important;
+}
+#${info_icon_id} {
+ position: absolute;
+ ${TRANSLATIONS.rtl ? "left" : "right"}: 4px;
+ top: 4px;
+ line-height: 12px;
+ text-decoration: none;
+}
+#${info_icon_id}:before {
+ border: 2px solid;
+ border-radius: 50%;
+ display: inline-block;
+ color: #555;
+ content: '?';
+ font-size: 12px;
+ font-weight: bold;
+ padding: 1px;
+ height: 1em;
+ width: 1em;
+}
+#${info_icon_id}:hover:before {
+ color: #ec9329;
+}
+ `.trim();
+
+ widgetFrame.srcdoc = '<html><head><style>' + head_styles + '</style></head><body style="margin:0">' + widgetDiv.outerHTML + '</body></html>';
+
+ return widgetFrame;
+}
+
+/**
+ * Replaces buttons/widgets in the DOM.
+ */
+function replaceIndividualButton(widget) {
+ let selector = widget.buttonSelectors.join(','),
+ elsToReplace = document.querySelectorAll(selector);
+
+ elsToReplace.forEach(function (el) {
+ createReplacementElement(widget, el, function (replacementEl) {
+ el.parentNode.replaceChild(replacementEl, el);
+ });
+ });
+}
+
+/**
+ * Messages the background page to temporarily allow domains associated with a
+ * given replacement widget.
+ * Calls the provided callback function upon response.
+ *
+ * @param {String} name the name of the replacement widget
+ * @param {Function} callback the callback function
+ */
+function unblockTracker(name, callback) {
+ let request = {
+ type: "unblockWidget",
+ widgetName: name
+ };
+ chrome.runtime.sendMessage(request, callback);
+}
+
+// END FUNCTION DEFINITIONS ///////////////////////////////////////////////////
+
+(function () {
+
+// don't inject into non-HTML documents (such as XML documents)
+// but do inject into XHTML documents
+if (document instanceof HTMLDocument === false && (
+ document instanceof XMLDocument === false ||
+ document.createElement('div') instanceof HTMLDivElement === false
+)) {
+ return;
+}
+
+chrome.runtime.sendMessage({
+ type: "checkWidgetReplacementEnabled"
+}, function (response) {
+ if (!response) {
+ return;
+ }
+ initialize(response);
+});
+
+}());
diff --git a/src/js/contentscripts/supercookie.js b/src/js/contentscripts/supercookie.js
new file mode 100644
index 0000000..0b15211
--- /dev/null
+++ b/src/js/contentscripts/supercookie.js
@@ -0,0 +1,151 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2015 Electronic Frontier Foundation
+ *
+ * Derived from Chameleon <https://github.com/ghostwords/chameleon>
+ * Copyright (C) 2015 ghostwords
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * Generate script to inject into the page
+ *
+ * @returns {string}
+ */
+function getScPageScript() {
+ // code below is not a content script: no chrome.* APIs /////////////////////
+
+ // return a string
+ return "(" + function () {
+
+ /*
+ * If localStorage is inaccessible, such as when "Block third-party cookies"
+ * in enabled in Chrome or when `dom.storage.enabled` is set to `false` in
+ * Firefox, do not go any further.
+ */
+ try {
+ // No localStorage raises an Exception in Chromium-based browsers, while
+ // it's equal to `null` in Firefox.
+ if (null === localStorage) {
+ throw false;
+ }
+ } catch (ex) {
+ return;
+ }
+
+ (function (DOCUMENT, dispatchEvent, CUSTOM_EVENT, LOCAL_STORAGE, OBJECT, keys) {
+
+ var event_id = DOCUMENT.currentScript.getAttribute('data-event-id-super-cookie');
+
+ /**
+ * send message to the content script
+ *
+ * @param {*} message
+ */
+ var send = function (message) {
+ dispatchEvent.call(DOCUMENT, new CUSTOM_EVENT(event_id, {
+ detail: message
+ }));
+ };
+
+ /**
+ * Read HTML5 local storage and return contents
+ * @returns {Object}
+ */
+ let getLocalStorageItems = function () {
+ let lsItems = {};
+ for (let i = 0; i < LOCAL_STORAGE.length; i++) {
+ let key = LOCAL_STORAGE.key(i);
+ lsItems[key] = LOCAL_STORAGE.getItem(key);
+ }
+ return lsItems;
+ };
+
+ if (event_id) { // inserted script may run before the event_id is available
+ let localStorageItems = getLocalStorageItems();
+ if (keys.call(OBJECT, localStorageItems).length) {
+ // send to content script
+ send({ localStorageItems });
+ }
+ }
+
+ // save locally to keep from getting overwritten by site code
+ } (document, document.dispatchEvent, CustomEvent, localStorage, Object, Object.keys));
+
+ } + "());";
+
+ // code above is not a content script: no chrome.* APIs /////////////////////
+
+}
+
+// END FUNCTION DEFINITIONS ///////////////////////////////////////////////////
+
+(function () {
+
+// don't inject into non-HTML documents (such as XML documents)
+// but do inject into XHTML documents
+if (document instanceof HTMLDocument === false && (
+ document instanceof XMLDocument === false ||
+ document.createElement('div') instanceof HTMLDivElement === false
+)) {
+ return;
+}
+
+// don't bother asking to run when trivially in first-party context
+if (window.top == window) {
+ return;
+}
+
+// TODO race condition; fix waiting on https://crbug.com/478183
+
+// TODO here we could also be injected too quickly
+// and miss localStorage setting upon initial page load
+//
+// we should eventually switch injection back to document_start
+// (reverting https://github.com/EFForg/privacybadger/pull/1522),
+// and fix localstorage detection
+// (such as by delaying it or peforming it periodically)
+//
+// could then remove test workarounds like
+// https://github.com/EFForg/privacybadger/commit/39d5d0899e22d1c451d429e44553c5f9cad7fc46
+
+// TODO sometimes contentscripts/utils.js isn't here?!
+// TODO window.FRAME_URL / window.injectScript are undefined ...
+chrome.runtime.sendMessage({
+ type: "inspectLocalStorage",
+ frameUrl: window.FRAME_URL
+}, function (enabledAndThirdParty) {
+ if (!enabledAndThirdParty) {
+ return;
+ }
+
+ var event_id_super_cookie = Math.random();
+
+ // listen for messages from the script we are about to insert
+ document.addEventListener(event_id_super_cookie, function (e) {
+ // pass these on to the background page (handled by webrequest.js)
+ chrome.runtime.sendMessage({
+ type: "supercookieReport",
+ data: e.detail,
+ frameUrl: window.FRAME_URL
+ });
+ });
+
+ window.injectScript(getScPageScript(), {
+ event_id_super_cookie: event_id_super_cookie
+ });
+
+});
+
+}());
diff --git a/src/js/contentscripts/utils.js b/src/js/contentscripts/utils.js
new file mode 100644
index 0000000..9f0a0fa
--- /dev/null
+++ b/src/js/contentscripts/utils.js
@@ -0,0 +1,53 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2018 Electronic Frontier Foundation
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * Executes a script in the page's JavaScript context.
+ *
+ * @param {String} text The content of the script to insert.
+ * @param {Object} data Data attributes to set on the inserted script tag.
+ */
+window.injectScript = function (text, data) {
+ var parent = document.documentElement,
+ script = document.createElement('script');
+
+ script.text = text;
+ script.async = false;
+
+ for (var key in data) {
+ script.setAttribute('data-' + key.replace(/_/g, '-'), data[key]);
+ }
+
+ parent.insertBefore(script, parent.firstChild);
+ parent.removeChild(script);
+};
+
+function getFrameUrl() {
+ let url = document.location.href,
+ parentFrame = (document != window.top) && window.parent;
+ while (parentFrame && url && !url.startsWith("http")) {
+ try {
+ url = parentFrame.document.location.href;
+ } catch (ex) {
+ // ignore 'Blocked a frame with origin "..."
+ // from accessing a cross-origin frame.' exceptions
+ }
+ parentFrame = (parentFrame != window.top) && parentFrame.parent;
+ }
+ return url;
+}
+window.FRAME_URL = getFrameUrl();
diff --git a/src/js/firefoxandroid.js b/src/js/firefoxandroid.js
new file mode 100644
index 0000000..07eeb6a
--- /dev/null
+++ b/src/js/firefoxandroid.js
@@ -0,0 +1,90 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2014 Electronic Frontier Foundation
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Temporary polyfill for firefox android,
+ * while it doesn't support the full browserAction API
+ * Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1330159
+ */
+
+require.scopes.firefoxandroid = (function() {
+var hasPopupSupport = !!(
+ chrome.browserAction.setPopup &&
+ chrome.browserAction.getPopup
+);
+var hasBadgeSupport = !!chrome.browserAction.setBadgeText;
+
+// keeps track of popup id while one is open
+var openPopupId = false;
+var popup_url = chrome.runtime.getManifest().browser_action.default_popup;
+
+// fakes a popup
+function openPopup() {
+ chrome.tabs.query({active: true, lastFocusedWindow: true}, (tabs) => {
+ var url = popup_url + "?tabId=" + tabs[0].id;
+ chrome.tabs.create({url, index: tabs[0].index + 1}, (tab) => {
+ openPopupId = tab.id;
+ });
+ });
+}
+
+// remove the 'popup' when another tab is activated
+function onActivated(activeInfo) {
+ if (openPopupId != false && openPopupId != activeInfo.tabId) {
+ chrome.tabs.remove(openPopupId, () => {
+ openPopupId = false;
+ });
+ }
+}
+
+// forgets the popup when the url is overwritten by the user
+function onUpdated(tabId, changeInfo, tab) {
+ if (tab.url && openPopupId == tabId) {
+ var new_url = new URL(tab.url);
+
+ if (new_url.origin + new_url.pathname != popup_url) {
+ openPopupId = false;
+ }
+ }
+}
+
+// Subscribe to events needed to fake a popup
+function startListeners() {
+ if (!hasPopupSupport) {
+ chrome.browserAction.onClicked.addListener(openPopup);
+ chrome.tabs.onActivated.addListener(onActivated);
+ chrome.tabs.onUpdated.addListener(onUpdated);
+ }
+}
+
+// Used in popup.js, figures out which tab opened the 'fake' popup
+function getParentOfPopup(callback) {
+ chrome.tabs.query({active: true, currentWindow: true}, function(focusedTab) {
+ var parentId = parseInt(new URL(focusedTab[0].url).searchParams.get('tabId'));
+ chrome.tabs.get(parentId, callback);
+ });
+}
+
+/************************************** exports */
+var exports = {};
+exports.startListeners = startListeners;
+exports.hasPopupSupport = hasPopupSupport;
+exports.hasBadgeSupport = hasBadgeSupport;
+exports.getParentOfPopup = getParentOfPopup;
+return exports;
+/************************************** exports */
+})();
diff --git a/src/js/firstparties/facebook.js b/src/js/firstparties/facebook.js
new file mode 100644
index 0000000..2c5d299
--- /dev/null
+++ b/src/js/firstparties/facebook.js
@@ -0,0 +1,56 @@
+/* globals findInAllFrames:false, observeMutations:false */
+// Adapted from https://github.com/mgziminsky/FacebookTrackingRemoval
+// this should only run on facebook.com, messenger.com, and
+// facebookcorewwwi.onion
+let fb_wrapped_link = `a[href*='${document.domain.split(".").slice(-2).join(".")}/l.php?']:not([aria-label])`;
+
+// remove all attributes from a link except for class and ARIA attributes
+function cleanAttrs(elem) {
+ for (let i = elem.attributes.length - 1; i >= 0; --i) {
+ const attr = elem.attributes[i];
+ if (attr.name !== 'class' && !attr.name.startsWith('aria-')) {
+ elem.removeAttribute(attr.name);
+ }
+ }
+}
+
+// Remove excessive attributes and event listeners from link a and replace
+// its destination with href
+function cleanLink(a) {
+ let href = new URL(a.href).searchParams.get('u');
+
+ // If we can't extract a good URL, abort without breaking the links
+ if (!window.isURL(href)) {
+ return;
+ }
+
+ let href_url = new URL(href);
+ href_url.searchParams.delete('fbclid');
+ href = href_url.toString();
+
+ cleanAttrs(a);
+ a.href = href;
+ a.rel = "noreferrer";
+ a.target = "_blank";
+ a.addEventListener("click", function (e) { e.stopImmediatePropagation(); }, true);
+ a.addEventListener("mousedown", function (e) { e.stopImmediatePropagation(); }, true);
+ a.addEventListener("mouseup", function (e) { e.stopImmediatePropagation(); }, true);
+ a.addEventListener("mouseover", function (e) { e.stopImmediatePropagation(); }, true);
+}
+
+// TODO race condition; fix waiting on https://crbug.com/478183
+chrome.runtime.sendMessage({
+ type: "checkEnabled"
+}, function (enabled) {
+ if (!enabled) {
+ return;
+ }
+
+ // unwrap wrapped links in the original page
+ findInAllFrames(fb_wrapped_link).forEach((link) => {
+ cleanLink(link);
+ });
+
+ // Execute redirect unwrapping each time new content is added to the page
+ observeMutations(fb_wrapped_link, cleanLink);
+});
diff --git a/src/js/firstparties/google-search.js b/src/js/firstparties/google-search.js
new file mode 100644
index 0000000..d5eea9a
--- /dev/null
+++ b/src/js/firstparties/google-search.js
@@ -0,0 +1,39 @@
+/* globals findInAllFrames:false */
+// In Firefox, outbound google links have the `rwt(...)` mousedown trigger.
+// In Chrome, they just have a `ping` attribute.
+let trap_link = "a[onmousedown^='return rwt(this,'], a[ping]";
+
+// Remove excessive attributes and event listeners from link a
+function cleanLink(a) {
+ // remove all attributes except for href,
+ // target (to support "Open each selected result in a new browser window"),
+ // class, style and ARIA attributes
+ for (let i = a.attributes.length - 1; i >= 0; --i) {
+ const attr = a.attributes[i];
+ if (attr.name !== 'href' && attr.name !== 'target' &&
+ attr.name !== 'class' && attr.name !== 'style' &&
+ !attr.name.startsWith('aria-')) {
+ a.removeAttribute(attr.name);
+ }
+ }
+ a.rel = "noreferrer noopener";
+
+ // block event listeners on the link
+ a.addEventListener("click", function (e) { e.stopImmediatePropagation(); }, true);
+ a.addEventListener("mousedown", function (e) { e.stopImmediatePropagation(); }, true);
+}
+
+// TODO race condition; fix waiting on https://crbug.com/478183
+chrome.runtime.sendMessage({
+ type: "checkEnabled"
+}, function (enabled) {
+ if (!enabled) {
+ return;
+ }
+
+ // since the page is rendered all at once, no need to set up a
+ // mutationObserver or setInterval
+ findInAllFrames(trap_link).forEach((link) => {
+ cleanLink(link);
+ });
+});
diff --git a/src/js/firstparties/google-static.js b/src/js/firstparties/google-static.js
new file mode 100644
index 0000000..cf73004
--- /dev/null
+++ b/src/js/firstparties/google-static.js
@@ -0,0 +1,41 @@
+let g_wrapped_link = "a[href^='https://www.google.com/url?']";
+
+// Unwrap a Hangouts tracking link
+function unwrapLink(a) {
+ let href = new URL(a.href).searchParams.get('q');
+ if (!window.isURL(href)) {
+ return;
+ }
+
+ // remove all attributes except for target, class, style and aria-*
+ // attributes. This should prevent the script from breaking styles and
+ // features for people with disabilities.
+ for (let i = a.attributes.length - 1; i >= 0; --i) {
+ const attr = a.attributes[i];
+ if (attr.name !== 'target' && attr.name !== 'class' &&
+ attr.name !== 'style' && !attr.name.startsWith('aria-')) {
+ a.removeAttribute(attr.name);
+ }
+ }
+
+ a.rel = "noreferrer";
+ a.href = href;
+}
+
+// Scan the page for all wrapped links
+function unwrapAll() {
+ document.querySelectorAll(g_wrapped_link).forEach((a) => {
+ unwrapLink(a);
+ });
+}
+
+// TODO race condition; fix waiting on https://crbug.com/478183
+chrome.runtime.sendMessage({
+ type: "checkEnabled"
+}, function (enabled) {
+ if (!enabled) {
+ return;
+ }
+ unwrapAll();
+ setInterval(unwrapAll, 2000);
+});
diff --git a/src/js/firstparties/lib/utils.js b/src/js/firstparties/lib/utils.js
new file mode 100644
index 0000000..3edb0c8
--- /dev/null
+++ b/src/js/firstparties/lib/utils.js
@@ -0,0 +1,62 @@
+window.isURL = function(url) {
+ // ensure the URL starts with HTTP or HTTPS; otherwise we might be vulnerable
+ // to XSS attacks
+ return (url && (url.startsWith("https://") || url.startsWith("http://")));
+};
+
+/**
+ * Search a window and all IFrames within it for a query selector, then return a
+ * list of all the elements in any frame that match.
+ */
+window.findInAllFrames = function(query) {
+ let out = [];
+ document.querySelectorAll(query).forEach((node) => {
+ out.push(node);
+ });
+ Array.from(document.getElementsByTagName('iframe')).forEach((iframe) => {
+ try {
+ iframe.contentDocument.querySelectorAll(query).forEach((node) => {
+ out.push(node);
+ });
+ } catch (e) {
+ // pass on cross origin iframe errors
+ }
+ });
+ return out;
+};
+
+/**
+ * Listen for mutations on a page. If any nodes that match `selector` are added
+ * to the page, execute the function `callback` on them.
+ * Used by first-party scripts to listen for new links being added to the page
+ * and strip them of tracking code immediately.
+ */
+window.observeMutations = function(selector, callback) {
+ // Check all new nodes added by a mutation for tracking links and unwrap them
+ function onMutation(mutation) {
+ if (!mutation.addedNodes.length) {
+ return;
+ }
+ for (let node of mutation.addedNodes) {
+ // Only act on element nodes, otherwise querySelectorAll won't work
+ if (node.nodeType != Node.ELEMENT_NODE) {
+ continue;
+ }
+
+ // check all child nodes against the selector first
+ node.querySelectorAll(selector).forEach((element) => {
+ callback(element);
+ });
+
+ // then check the node itself
+ if (node.matches(selector)) {
+ callback(node);
+ }
+ }
+ }
+
+ // Set up a mutation observer with the constructed callback
+ new MutationObserver(function(mutations) {
+ mutations.forEach(onMutation);
+ }).observe(document, {childList: true, subtree: true, attributes: false, characterData: false});
+};
diff --git a/src/js/heuristicblocking.js b/src/js/heuristicblocking.js
new file mode 100644
index 0000000..b0d3bc9
--- /dev/null
+++ b/src/js/heuristicblocking.js
@@ -0,0 +1,557 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2014 Electronic Frontier Foundation
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* globals badger:false, log:false, URI:false */
+
+var constants = require("constants");
+var utils = require("utils");
+
+require.scopes.heuristicblocking = (function() {
+
+
+
+/*********************** heuristicblocking scope **/
+// make heuristic obj with utils and storage properties and put the things on it
+function HeuristicBlocker(pbStorage) {
+ this.storage = pbStorage;
+
+ // TODO roll into tabData? -- 6/10/2019 not for now, since tabData is populated
+ // by the synchronous listeners in webrequests.js and tabOrigins is used by the
+ // async listeners here; there's no way to enforce ordering of requests among
+ // those two. Also, tabData is cleaned up every time a tab is closed, so
+ // dangling requests that don't trigger listeners until after the tab closes are
+ // impossible to attribute to a tab.
+ this.tabOrigins = {};
+ this.tabUrls = {};
+}
+
+HeuristicBlocker.prototype = {
+
+ /**
+ * Blocklists an FQDN/origin:
+ *
+ * - Blocks or cookieblocks an FQDN.
+ * - Blocks or cookieblocks its base domain.
+ * - Cookieblocks any yellowlisted subdomains that share the base domain with the FQDN.
+ *
+ * @param {String} base The base domain (etld+1) to blocklist
+ * @param {String} fqdn The FQDN
+ */
+ blocklistOrigin: function (base, fqdn) {
+ let self = this,
+ ylistStorage = self.storage.getStore("cookieblock_list");
+
+ // cookieblock or block the base domain
+ if (ylistStorage.hasItem(base)) {
+ self.storage.setupHeuristicAction(base, constants.COOKIEBLOCK);
+ } else {
+ self.storage.setupHeuristicAction(base, constants.BLOCK);
+ }
+
+ // cookieblock or block the fqdn
+ //
+ // cookieblock if a "parent" domain of the fqdn is on the yellowlist
+ //
+ // ignore base domains when exploding to work around PSL TLDs:
+ // still want to cookieblock somedomain.googleapis.com with only
+ // googleapis.com (and not somedomain.googleapis.com itself) on the ylist
+ let set = false,
+ subdomains = utils.explodeSubdomains(fqdn, true);
+ for (let i = 0; i < subdomains.length; i++) {
+ if (ylistStorage.hasItem(subdomains[i])) {
+ set = true;
+ break;
+ }
+ }
+ if (set) {
+ self.storage.setupHeuristicAction(fqdn, constants.COOKIEBLOCK);
+ } else {
+ self.storage.setupHeuristicAction(fqdn, constants.BLOCK);
+ }
+
+ // cookieblock any yellowlisted subdomains with the same base domain
+ //
+ // for example, when google.com is blocked,
+ // books.google.com should be cookieblocked
+ let base_with_dot = '.' + base;
+ ylistStorage.keys().forEach(domain => {
+ if (base != domain && domain.endsWith(base_with_dot)) {
+ self.storage.setupHeuristicAction(domain, constants.COOKIEBLOCK);
+ }
+ });
+
+ },
+
+ /**
+ * Wraps _recordPrevalence for use from webRequest listeners.
+ * Use updateTrackerPrevalence for non-webRequest initiated bookkeeping.
+ *
+ * @param {Object} details request/response details
+ */
+ heuristicBlockingAccounting: function (details) {
+ // ignore requests that are outside a tabbed window
+ if (details.tabId < 0 || !badger.isLearningEnabled(details.tabId)) {
+ return {};
+ }
+
+ let self = this,
+ request_host = (new URI(details.url)).host,
+ request_origin = window.getBaseDomain(request_host);
+
+ // if this is a main window request, update tab data and quit
+ if (details.type == "main_frame") {
+ self.tabOrigins[details.tabId] = request_origin;
+ self.tabUrls[details.tabId] = details.url;
+ return {};
+ }
+
+ let tab_origin = self.tabOrigins[details.tabId];
+
+ // ignore first-party requests
+ if (!tab_origin || !utils.isThirdPartyDomain(request_origin, tab_origin)) {
+ return {};
+ }
+
+ // short-circuit if we already observed this origin tracking on this site
+ let firstParties = self.storage.getStore('snitch_map').getItem(request_origin);
+ if (firstParties && firstParties.indexOf(tab_origin) > -1) {
+ return {};
+ }
+
+ // abort if we already made a decision for this FQDN
+ let action = self.storage.getAction(request_host);
+ if (action != constants.NO_TRACKING && action != constants.ALLOW) {
+ return {};
+ }
+
+ // check if there are tracking cookies
+ if (hasCookieTracking(details, request_origin)) {
+ self._recordPrevalence(request_host, request_origin, tab_origin);
+ return {};
+ }
+ },
+
+ /**
+ * Wraps _recordPrevalence for use outside of webRequest listeners.
+ *
+ * @param {String} tracker_fqdn The fully qualified domain name of the tracker
+ * @param {String} tracker_origin Base domain of the third party tracker
+ * @param {String} page_origin Base domain of page where tracking occurred
+ */
+ updateTrackerPrevalence: function (tracker_fqdn, tracker_origin, page_origin) {
+ // abort if we already made a decision for this fqdn
+ let action = this.storage.getAction(tracker_fqdn);
+ if (action != constants.NO_TRACKING && action != constants.ALLOW) {
+ return;
+ }
+
+ this._recordPrevalence(
+ tracker_fqdn,
+ tracker_origin,
+ page_origin
+ );
+ },
+
+ /**
+ * Record HTTP request prevalence. Block a tracker if seen on more
+ * than constants.TRACKING_THRESHOLD pages
+ *
+ * NOTE: This is a private function and should never be called directly.
+ * All calls should be routed through heuristicBlockingAccounting for normal usage
+ * and updateTrackerPrevalence for manual modifications (e.g. importing
+ * tracker lists).
+ *
+ * @param {String} tracker_fqdn The FQDN of the third party tracker
+ * @param {String} tracker_origin Base domain of the third party tracker
+ * @param {String} page_origin Base domain of page where tracking occurred
+ */
+ _recordPrevalence: function (tracker_fqdn, tracker_origin, page_origin) {
+ var snitchMap = this.storage.getStore('snitch_map');
+ var firstParties = [];
+ if (snitchMap.hasItem(tracker_origin)) {
+ firstParties = snitchMap.getItem(tracker_origin);
+ }
+
+ // GDPR Consent Management Provider
+ // https://github.com/EFForg/privacybadger/pull/2245#issuecomment-545545717
+ if (tracker_origin == "consensu.org") {
+ return;
+ }
+
+ if (firstParties.indexOf(page_origin) != -1) {
+ return; // We already know about the presence of this tracker on the given domain
+ }
+
+ // record that we've seen this tracker on this domain (in snitch map)
+ firstParties.push(page_origin);
+ snitchMap.setItem(tracker_origin, firstParties);
+
+ // ALLOW indicates this is a tracker still below TRACKING_THRESHOLD
+ // (vs. NO_TRACKING for resources we haven't seen perform tracking yet).
+ // see https://github.com/EFForg/privacybadger/pull/1145#discussion_r96676710
+ this.storage.setupHeuristicAction(tracker_fqdn, constants.ALLOW);
+ this.storage.setupHeuristicAction(tracker_origin, constants.ALLOW);
+
+ // Blocking based on outbound cookies
+ var httpRequestPrevalence = firstParties.length;
+
+ // block the origin if it has been seen on multiple first party domains
+ if (httpRequestPrevalence >= constants.TRACKING_THRESHOLD) {
+ log('blocklisting origin', tracker_fqdn);
+ this.blocklistOrigin(tracker_origin, tracker_fqdn);
+ }
+ }
+};
+
+
+// This maps cookies to a rough estimate of how many bits of
+// identifying info we might be letting past by allowing them.
+// (map values to lower case before using)
+// TODO: We need a better heuristic
+var lowEntropyCookieValues = {
+ "":3,
+ "nodata":3,
+ "no_data":3,
+ "yes":3,
+ "no":3,
+ "true":3,
+ "false":3,
+ "dnt":3,
+ "opt-out":3,
+ "optout":3,
+ "opt_out":3,
+ "0":4,
+ "1":4,
+ "2":4,
+ "3":4,
+ "4":4,
+ "5":4,
+ "6":4,
+ "7":4,
+ "8":4,
+ "9":4,
+ // ISO 639-1 language codes
+ "aa":8,
+ "ab":8,
+ "ae":8,
+ "af":8,
+ "ak":8,
+ "am":8,
+ "an":8,
+ "ar":8,
+ "as":8,
+ "av":8,
+ "ay":8,
+ "az":8,
+ "ba":8,
+ "be":8,
+ "bg":8,
+ "bh":8,
+ "bi":8,
+ "bm":8,
+ "bn":8,
+ "bo":8,
+ "br":8,
+ "bs":8,
+ "by":8,
+ "ca":8,
+ "ce":8,
+ "ch":8,
+ "co":8,
+ "cr":8,
+ "cs":8,
+ "cu":8,
+ "cv":8,
+ "cy":8,
+ "da":8,
+ "de":8,
+ "dv":8,
+ "dz":8,
+ "ee":8,
+ "el":8,
+ "en":8,
+ "eo":8,
+ "es":8,
+ "et":8,
+ "eu":8,
+ "fa":8,
+ "ff":8,
+ "fi":8,
+ "fj":8,
+ "fo":8,
+ "fr":8,
+ "fy":8,
+ "ga":8,
+ "gd":8,
+ "gl":8,
+ "gn":8,
+ "gu":8,
+ "gv":8,
+ "ha":8,
+ "he":8,
+ "hi":8,
+ "ho":8,
+ "hr":8,
+ "ht":8,
+ "hu":8,
+ "hy":8,
+ "hz":8,
+ "ia":8,
+ "id":8,
+ "ie":8,
+ "ig":8,
+ "ii":8,
+ "ik":8,
+ "in":8,
+ "io":8,
+ "is":8,
+ "it":8,
+ "iu":8,
+ "ja":8,
+ "jv":8,
+ "ka":8,
+ "kg":8,
+ "ki":8,
+ "kj":8,
+ "kk":8,
+ "kl":8,
+ "km":8,
+ "kn":8,
+ "ko":8,
+ "kr":8,
+ "ks":8,
+ "ku":8,
+ "kv":8,
+ "kw":8,
+ "ky":8,
+ "la":8,
+ "lb":8,
+ "lg":8,
+ "li":8,
+ "ln":8,
+ "lo":8,
+ "lt":8,
+ "lu":8,
+ "lv":8,
+ "mg":8,
+ "mh":8,
+ "mi":8,
+ "mk":8,
+ "ml":8,
+ "mn":8,
+ "mr":8,
+ "ms":8,
+ "mt":8,
+ "my":8,
+ "na":8,
+ "nb":8,
+ "nd":8,
+ "ne":8,
+ "ng":8,
+ "nl":8,
+ "nn":8,
+ "nr":8,
+ "nv":8,
+ "ny":8,
+ "oc":8,
+ "of":8,
+ "oj":8,
+ "om":8,
+ "or":8,
+ "os":8,
+ "pa":8,
+ "pi":8,
+ "pl":8,
+ "ps":8,
+ "pt":8,
+ "qu":8,
+ "rm":8,
+ "rn":8,
+ "ro":8,
+ "ru":8,
+ "rw":8,
+ "sa":8,
+ "sc":8,
+ "sd":8,
+ "se":8,
+ "sg":8,
+ "si":8,
+ "sk":8,
+ "sl":8,
+ "sm":8,
+ "sn":8,
+ "so":8,
+ "sq":8,
+ "sr":8,
+ "ss":8,
+ "st":8,
+ "su":8,
+ "sv":8,
+ "sw":8,
+ "ta":8,
+ "te":8,
+ "tg":8,
+ "th":8,
+ "ti":8,
+ "tk":8,
+ "tl":8,
+ "tn":8,
+ "to":8,
+ "tr":8,
+ "ts":8,
+ "tt":8,
+ "tw":8,
+ "ty":8,
+ "ug":8,
+ "uk":8,
+ "ur":8,
+ "uz":8,
+ "ve":8,
+ "vi":8,
+ "vo":8,
+ "wa":8,
+ "wo":8,
+ "xh":8,
+ "yi":8,
+ "yo":8,
+ "za":8,
+ "zh":8,
+ "zu":8
+};
+
+/**
+ * Extract cookies from onBeforeSendHeaders
+ *
+ * @param details Details for onBeforeSendHeaders
+ * @returns {*} an array combining all Cookies
+ */
+function _extractCookies(details) {
+ let cookies = [],
+ headers = [];
+
+ if (details.requestHeaders) {
+ headers = details.requestHeaders;
+ } else if (details.responseHeaders) {
+ headers = details.responseHeaders;
+ }
+
+ for (let i = 0; i < headers.length; i++) {
+ let header = headers[i];
+ if (header.name.toLowerCase() == "cookie" || header.name.toLowerCase() == "set-cookie") {
+ cookies.push(header.value);
+ }
+ }
+
+ return cookies;
+}
+
+/**
+ * Check if page is doing cookie tracking. Doing this by estimating the entropy of the cookies
+ *
+ * @param details details onBeforeSendHeaders details
+ * @param {String} origin URL
+ * @returns {boolean} true if it has cookie tracking
+ */
+function hasCookieTracking(details, origin) {
+ let cookies = _extractCookies(details);
+ if (!cookies.length) {
+ return false;
+ }
+
+ let estimatedEntropy = 0;
+
+ // loop over every cookie
+ for (let i = 0; i < cookies.length; i++) {
+ let cookie = utils.parseCookie(cookies[i], {
+ noDecode: true,
+ skipAttributes: true,
+ skipNonValues: true
+ });
+
+ // loop over every name/value pair in every cookie
+ for (let name in cookie) {
+ if (!cookie.hasOwnProperty(name)) {
+ continue;
+ }
+
+ // ignore CloudFlare
+ // https://support.cloudflare.com/hc/en-us/articles/200170156-Understanding-the-Cloudflare-Cookies
+ if (name == "__cfduid" || name == "__cf_bm") {
+ continue;
+ }
+
+ let value = cookie[name].toLowerCase();
+
+ if (!(value in lowEntropyCookieValues)) {
+ return true;
+ }
+
+ estimatedEntropy += lowEntropyCookieValues[value];
+ }
+ }
+
+ log("All cookies for " + origin + " deemed low entropy...");
+ if (estimatedEntropy > constants.MAX_COOKIE_ENTROPY) {
+ log("But total estimated entropy is " + estimatedEntropy + " bits, so blocking");
+ return true;
+ }
+
+ return false;
+}
+
+function startListeners() {
+ /**
+ * Adds heuristicBlockingAccounting as listened to onBeforeSendHeaders request
+ */
+ let extraInfoSpec = ['requestHeaders'];
+ if (chrome.webRequest.OnBeforeSendHeadersOptions.hasOwnProperty('EXTRA_HEADERS')) {
+ extraInfoSpec.push('extraHeaders');
+ }
+ chrome.webRequest.onBeforeSendHeaders.addListener(function(details) {
+ return badger.heuristicBlocking.heuristicBlockingAccounting(details);
+ }, {urls: ["<all_urls>"]}, extraInfoSpec);
+
+ /**
+ * Adds onResponseStarted listener. Monitor for cookies
+ */
+ extraInfoSpec = ['responseHeaders'];
+ if (chrome.webRequest.OnResponseStartedOptions.hasOwnProperty('EXTRA_HEADERS')) {
+ extraInfoSpec.push('extraHeaders');
+ }
+ chrome.webRequest.onResponseStarted.addListener(function(details) {
+ var hasSetCookie = false;
+ for (var i = 0; i < details.responseHeaders.length; i++) {
+ if (details.responseHeaders[i].name.toLowerCase() == "set-cookie") {
+ hasSetCookie = true;
+ break;
+ }
+ }
+ if (hasSetCookie) {
+ return badger.heuristicBlocking.heuristicBlockingAccounting(details);
+ }
+ },
+ {urls: ["<all_urls>"]}, extraInfoSpec);
+}
+
+/************************************** exports */
+var exports = {};
+exports.HeuristicBlocker = HeuristicBlocker;
+exports.startListeners = startListeners;
+exports.hasCookieTracking = hasCookieTracking;
+return exports;
+/************************************** exports */
+})();
diff --git a/src/js/htmlutils.js b/src/js/htmlutils.js
new file mode 100644
index 0000000..2c015d4
--- /dev/null
+++ b/src/js/htmlutils.js
@@ -0,0 +1,283 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2014 Electronic Frontier Foundation
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+require.scopes.htmlutils = (function() {
+
+const i18n = chrome.i18n;
+const constants = require("constants");
+
+let htmlUtils = {
+
+ // default Tooltipster config
+ TOOLTIPSTER_DEFAULTS: {
+ // allow per-instance option overriding
+ functionInit: function (instance, helper) {
+ let dataOptions = helper.origin.dataset.tooltipster;
+
+ if (dataOptions) {
+ try {
+ dataOptions = JSON.parse(dataOptions);
+ } catch (e) {
+ console.error(e);
+ }
+
+ for (let name in dataOptions) {
+ instance.option(name, dataOptions[name]);
+ }
+ }
+ },
+ },
+
+ // Tooltipster config for domain list tooltips
+ DOMAIN_TOOLTIP_CONF: {
+ delay: 100,
+ side: 'bottom',
+ },
+
+ /**
+ * Gets localized description for given action and origin.
+ *
+ * @param {String} action The action to get description for.
+ * @param {String} origin The origin to get description for.
+ * @returns {String} Localized action description with origin.
+ */
+ getActionDescription: (function () {
+ const messages = {
+ block: i18n.getMessage('badger_status_block', "XXX"),
+ cookieblock: i18n.getMessage('badger_status_cookieblock', "XXX"),
+ noaction: i18n.getMessage('badger_status_noaction', "XXX"),
+ allow: i18n.getMessage('badger_status_allow', "XXX"),
+ dntTooltip: i18n.getMessage('dnt_tooltip')
+ };
+ return function (action, origin) {
+ if (action == constants.DNT) {
+ return messages.dntTooltip;
+ }
+
+ const rv_action = messages[action];
+
+ if (!rv_action) {
+ return origin;
+ }
+
+ return rv_action.replace("XXX", origin);
+ };
+ }()),
+
+ /**
+ * Gets HTML for origin action toggle switch (block, block cookies, allow).
+ *
+ * @param {String} origin Origin to get toggle for.
+ * @param {String} action Current action of given origin.
+ * @returns {String} HTML for toggle switch.
+ */
+ getToggleHtml: (function () {
+
+ function is_checked(input_action, origin_action) {
+ if ((origin_action == constants.NO_TRACKING) || (origin_action == constants.DNT)) {
+ origin_action = constants.ALLOW;
+ }
+ return (input_action === origin_action ? 'checked' : '');
+ }
+
+ let tooltips = {
+ block: i18n.getMessage('domain_slider_block_tooltip'),
+ cookieblock: i18n.getMessage('domain_slider_cookieblock_tooltip'),
+ allow: i18n.getMessage('domain_slider_allow_tooltip')
+ };
+
+ return function (origin, action) {
+ let origin_id = origin.replace(/\./g, '-');
+
+ return `
+<div class="switch-container ${action}">
+ <div class="switch-toggle switch-3 switch-candy">
+ <input id="block-${origin_id}" name="${origin}" value="${constants.BLOCK}" type="radio" ${is_checked(constants.BLOCK, action)}>
+ <label title="${tooltips.block}" class="tooltip" for="block-${origin_id}"></label>
+ <input id="cookieblock-${origin_id}" name="${origin}" value="${constants.COOKIEBLOCK}" type="radio" ${is_checked(constants.COOKIEBLOCK, action)}>
+ <label title="${tooltips.cookieblock}" class="tooltip" for="cookieblock-${origin_id}"></label>
+ <input id="allow-${origin_id}" name="${origin}" value="${constants.ALLOW}" type="radio" ${is_checked(constants.ALLOW, action)}>
+ <label title="${tooltips.allow}" class="tooltip" for="allow-${origin_id}"></label>
+ <a></a>
+ </div>
+</div>
+ `.trim();
+ };
+
+ }()),
+
+ /**
+ * Get HTML for tracker container.
+ *
+ * @returns {String} HTML for empty tracker container.
+ */
+ getTrackerContainerHtml: function() {
+ return `
+<div class="keyContainer">
+ <div class="key">
+ <img src="/icons/UI-icons-red.svg" class="tooltip" title="${i18n.getMessage("tooltip_block")}"><img src="/icons/UI-icons-yellow.svg" class="tooltip" title="${i18n.getMessage("tooltip_cookieblock")}"><img src="/icons/UI-icons-green.svg" class="tooltip" title="${i18n.getMessage("tooltip_allow")}">
+ </div>
+</div>
+<div class="spacer"></div>
+<div id="blockedResourcesInner" class="clickerContainer"></div>
+ `.trim();
+ },
+
+ /**
+ * Generates HTML for given origin.
+ *
+ * @param {String} origin Origin to get HTML for.
+ * @param {String} action Action for given origin.
+ * @param {Boolean} show_breakage_warning
+ * @returns {String} Origin HTML.
+ */
+ getOriginHtml: (function () {
+
+ const breakage_warning_tooltip = i18n.getMessage('breakage_warning_tooltip'),
+ undo_arrow_tooltip = i18n.getMessage('feed_the_badger_title'),
+ dnt_icon_url = chrome.runtime.getURL('/icons/dnt-16.png');
+
+ return function (origin, action, show_breakage_warning) {
+ action = _.escape(action);
+ origin = _.escape(origin);
+
+ // Get classes for main div.
+ let classes = ['clicker'];
+ if (action.startsWith('user')) {
+ classes.push('userset');
+ action = action.slice(5);
+ }
+ // show warning when manually blocking a domain
+ // that would have been cookieblocked otherwise
+ if (show_breakage_warning) {
+ classes.push('show-breakage-warning');
+ }
+
+ // If origin has been whitelisted set text for DNT.
+ let dnt_html = '';
+ if (action == constants.DNT) {
+ dnt_html = `
+<div id="dnt-compliant">
+ <a target=_blank href="https://privacybadger.org/#-I-am-an-online-advertising-tracking-company.--How-do-I-stop-Privacy-Badger-from-blocking-me"><img src="${dnt_icon_url}"></a>
+</div>
+ `.trim();
+ }
+
+ // Construct HTML for origin.
+ let origin_tooltip = htmlUtils.getActionDescription(action, origin);
+ return `
+<div class="${classes.join(' ')}" data-origin="${origin}">
+ <div class="origin">
+ <span class="ui-icon ui-icon-alert tooltip breakage-warning" title="${breakage_warning_tooltip}"></span>
+ <span class="origin-inner tooltip" title="${origin_tooltip}">${dnt_html}${origin}</span>
+ </div>
+ <a href="" class="removeOrigin">&#10006</a>
+ ${htmlUtils.getToggleHtml(origin, action)}
+ <a href="" class="honeybadgerPowered tooltip" title="${undo_arrow_tooltip}"></a>
+</div>
+ `.trim();
+ };
+
+ }()),
+
+ /**
+ * Toggles undo arrows and breakage warnings in domain slider rows.
+ * TODO rename/refactor with updateOrigin()
+ *
+ * @param {jQuery} $clicker
+ * @param {Boolean} userset whether to show a revert control arrow
+ * @param {Boolean} show_breakage_warning whether to show a breakage warning
+ */
+ toggleBlockedStatus: function ($clicker, userset, show_breakage_warning) {
+ $clicker.removeClass([
+ "userset",
+ "show-breakage-warning",
+ ].join(" "));
+
+ // toggles revert control arrow via CSS
+ if (userset) {
+ $clicker.addClass("userset");
+ }
+
+ // show warning when manually blocking a domain
+ // that would have been cookieblocked otherwise
+ if (show_breakage_warning) {
+ $clicker.addClass("show-breakage-warning");
+ }
+ },
+
+ /**
+ * Compare two domains, reversing them to start comparing the least
+ * significant parts (TLD) first.
+ *
+ * @param {Array} domains The domains to sort.
+ * @returns {Array} Sorted domains.
+ */
+ sortDomains: (domains) => {
+ // optimization: cache makeSortable output by walking the array once
+ // to extract the actual values used for sorting into a temporary array
+ return domains.map((domain, i) => {
+ return {
+ index: i,
+ value: htmlUtils.makeSortable(domain)
+ };
+ // sort the temporary array
+ }).sort((a, b) => {
+ if (a.value > b.value) {
+ return 1;
+ }
+ if (a.value < b.value) {
+ return -1;
+ }
+ return 0;
+ // walk the temporary array to achieve the right order
+ }).map(item => domains[item.index]);
+ },
+
+ /**
+ * Reverse order of domain items to have the least exact (TLD) first.
+ *
+ * @param {String} domain The domain to shuffle
+ * @returns {String} The 'reversed' domain
+ */
+ makeSortable: (domain) => {
+ let base = window.getBaseDomain(domain),
+ base_minus_tld = base,
+ dot_index = base.indexOf('.'),
+ rest_of_it_reversed = '';
+
+ if (domain.length > base.length) {
+ rest_of_it_reversed = domain
+ .slice(0, domain.length - base.length - 1)
+ .split('.').reverse().join('.');
+ }
+
+ if (dot_index > -1 && !window.isIPv4(domain) && !window.isIPv6(domain)) {
+ base_minus_tld = base.slice(0, dot_index);
+ }
+
+ return (base_minus_tld + '.' + rest_of_it_reversed);
+ },
+
+};
+
+let exports = {
+ htmlUtils,
+};
+return exports;
+
+})();
diff --git a/src/js/incognito.js b/src/js/incognito.js
new file mode 100644
index 0000000..56d2d93
--- /dev/null
+++ b/src/js/incognito.js
@@ -0,0 +1,49 @@
+/* globals badger:false */
+
+require.scopes.incognito = (function() {
+var tabs = {};
+
+// Get all existing tabs
+chrome.tabs.query({}, function(results) {
+ results.forEach(function(tab) {
+ tabs[tab.id] = tab.incognito;
+ });
+});
+
+// Create tab event listeners
+function onUpdatedListener(tabId, changeInfo, tab) {
+ tabs[tab.id] = tab.incognito;
+}
+
+function onRemovedListener(tabId) {
+ delete tabs[tabId];
+}
+
+// Subscribe to tab events
+function startListeners() {
+ chrome.tabs.onUpdated.addListener(onUpdatedListener);
+ chrome.tabs.onRemoved.addListener(onRemovedListener);
+}
+
+function learningEnabled(tab_id) {
+ if (badger.getSettings().getItem("learnInIncognito")) {
+ // treat all pages as if they're not incognito
+ return true;
+ }
+ // if we don't have incognito data for whatever reason,
+ // default to disabled
+ if (!tabs.hasOwnProperty(tab_id)) {
+ return false;
+ }
+ // else, do not learn in incognito tabs
+ return !tabs[tab_id];
+}
+
+/************************************** exports */
+let exports = {
+ learningEnabled,
+ startListeners,
+};
+return exports;
+/************************************** exports */
+})();
diff --git a/src/js/migrations.js b/src/js/migrations.js
new file mode 100644
index 0000000..cea4d37
--- /dev/null
+++ b/src/js/migrations.js
@@ -0,0 +1,356 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2014 Electronic Frontier Foundation
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+require.scopes.migrations = (function () {
+
+let utils = require("utils");
+let constants = require("constants");
+
+let noop = function () {};
+
+let exports = {};
+
+exports.Migrations= {
+ changePrivacySettings: noop,
+ migrateAbpToStorage: noop,
+
+ migrateBlockedSubdomainsToCookieblock: function(badger) {
+ setTimeout(function() {
+ console.log('MIGRATING BLOCKED SUBDOMAINS THAT ARE ON COOKIE BLOCK LIST');
+ let ylist = badger.storage.getStore('cookieblock_list');
+ badger.storage.getAllDomainsByPresumedAction(constants.BLOCK).forEach(fqdn => {
+ utils.explodeSubdomains(fqdn, true).forEach(domain => {
+ if (ylist.hasItem(domain)) {
+ console.log('moving', fqdn, 'from block to cookie block');
+ badger.storage.setupHeuristicAction(fqdn, constants.COOKIEBLOCK);
+ }
+ });
+ });
+ }, 1000 * 30);
+ },
+
+ migrateLegacyFirefoxData: noop,
+
+ migrateDntRecheckTimes: function(badger) {
+ var action_map = badger.storage.getStore('action_map');
+ for (var domain in action_map.getItemClones()) {
+ if (badger.storage.getNextUpdateForDomain(domain) === 0) {
+ // Recheck at a random time in the next week
+ var recheckTime = _.random(Date.now(), utils.nDaysFromNow(7));
+ badger.storage.touchDNTRecheckTime(domain, recheckTime);
+ }
+ }
+
+ },
+
+ // Fixes https://github.com/EFForg/privacybadger/issues/1181
+ migrateDntRecheckTimes2: function(badger) {
+ console.log('fixing DNT check times');
+ var action_map = badger.storage.getStore('action_map');
+ for (var domain in action_map.getItemClones()) {
+ // Recheck at a random time in the next week
+ var recheckTime = _.random(utils.oneDayFromNow(), utils.nDaysFromNow(7));
+ badger.storage.touchDNTRecheckTime(domain, recheckTime);
+ }
+ },
+
+ forgetMistakenlyBlockedDomains: function (badger) {
+ console.log("Running migration to forget mistakenly flagged domains ...");
+
+ const MISTAKES = new Set([
+ '2mdn.net',
+ 'akamaized.net',
+ 'bootcss.com',
+ 'cloudinary.com',
+ 'edgesuite.net',
+ 'ehowcdn.com',
+ 'ewscloud.com',
+ 'fncstatic.com',
+ 'fontawesome.com',
+ 'hgmsites.net',
+ 'hsforms.net',
+ 'hubspot.com',
+ 'jsdelivr.net',
+ 'jwplayer.com',
+ 'jwpsrv.com',
+ 'kinja-img.com',
+ 'kxcdn.com',
+ 'ldwgroup.com',
+ 'metapix.net',
+ 'optnmstr.com',
+ 'parastorage.com',
+ 'polyfill.io',
+ 'qbox.me',
+ 'rfdcontent.com',
+ 'scene7.com',
+ 'sinaimg.cn',
+ 'slidesharecdn.com',
+ 'staticworld.net',
+ 'taleo.net',
+ 'techhive.com',
+ 'unpkg.com',
+ 'uvcdn.com',
+ 'washingtonpost.com',
+ 'wixstatic.com',
+ 'ykimg.com',
+ ]);
+
+ const actionMap = badger.storage.getStore("action_map"),
+ actions = actionMap.getItemClones(),
+ snitchMap = badger.storage.getStore("snitch_map");
+
+ for (let domain in actions) {
+ const base = window.getBaseDomain(domain);
+
+ if (!MISTAKES.has(base)) {
+ continue;
+ }
+
+ // remove only if
+ // user did not set an override
+ // and domain was seen tracking
+ const map = actions[domain];
+ if (map.userAction != "" || (
+ map.heuristicAction != constants.ALLOW &&
+ map.heuristicAction != constants.BLOCK &&
+ map.heuristicAction != constants.COOKIEBLOCK
+ )) {
+ continue;
+ }
+
+ console.log("Removing %s ...", domain);
+ actionMap.deleteItem(domain);
+ snitchMap.deleteItem(base);
+ }
+ },
+
+ unblockIncorrectlyBlockedDomains: function (badger) {
+ console.log("Running migration to unblock likely incorrectly blocked domains ...");
+
+ let action_map = badger.storage.getStore("action_map"),
+ snitch_map = badger.storage.getStore("snitch_map");
+
+ // for every blocked domain
+ for (let domain in action_map.getItemClones()) {
+ if (action_map.getItem(domain).heuristicAction != constants.BLOCK) {
+ continue;
+ }
+
+ let base_domain = window.getBaseDomain(domain);
+
+ // let's check snitch map
+ // to see what state the blocked domain should be in instead
+ let sites = snitch_map.getItem(base_domain);
+
+ // default to "no tracking"
+ // using "" and not constants.NO_TRACKING to match current behavior
+ let action = "";
+
+ if (sites && sites.length) {
+ if (sites.length >= constants.TRACKING_THRESHOLD) {
+ // tracking domain over threshold, set it to cookieblock or block
+ badger.heuristicBlocking.blocklistOrigin(base_domain, domain);
+ continue;
+
+ } else {
+ // tracking domain below threshold
+ action = constants.ALLOW;
+ }
+ }
+
+ badger.storage.setupHeuristicAction(domain, action);
+ }
+ },
+
+ forgetBlockedDNTDomains: function(badger) {
+ console.log('Running migration to forget mistakenly blocked DNT domains');
+
+ let action_map = badger.storage.getStore("action_map"),
+ snitch_map = badger.storage.getStore("snitch_map"),
+ domainsToFix = new Set(['eff.org', 'medium.com']);
+
+ for (let domain in action_map.getItemClones()) {
+ let base = window.getBaseDomain(domain);
+ if (domainsToFix.has(base)) {
+ action_map.deleteItem(domain);
+ snitch_map.deleteItem(base);
+ }
+ }
+ },
+
+ reapplyYellowlist: function (badger) {
+ console.log("(Re)applying yellowlist ...");
+
+ let blocked = badger.storage.getAllDomainsByPresumedAction(
+ constants.BLOCK);
+
+ // reblock all blocked domains to trigger yellowlist logic
+ for (let i = 0; i < blocked.length; i++) {
+ let domain = blocked[i];
+ badger.heuristicBlocking.blocklistOrigin(
+ window.getBaseDomain(domain), domain);
+ }
+ },
+
+ forgetNontrackingDomains: function (badger) {
+ console.log("Forgetting non-tracking domains ...");
+
+ const actionMap = badger.storage.getStore("action_map"),
+ actions = actionMap.getItemClones();
+
+ for (let domain in actions) {
+ const map = actions[domain];
+ if (map.userAction == "" && map.heuristicAction == "") {
+ actionMap.deleteItem(domain);
+ }
+ }
+ },
+
+ resetWebRTCIPHandlingPolicy: noop,
+
+ enableShowNonTrackingDomains: function (badger) {
+ console.log("Enabling showNonTrackingDomains for some users");
+
+ let actionMap = badger.storage.getStore("action_map"),
+ actions = actionMap.getItemClones();
+
+ // if we have any customized sliders
+ if (Object.keys(actions).some(domain => actions[domain].userAction != "")) {
+ // keep showing non-tracking domains in the popup
+ badger.getSettings().setItem("showNonTrackingDomains", true);
+ }
+ },
+
+ forgetFirstPartySnitches: function (badger) {
+ console.log("Removing first parties from snitch map...");
+ let snitchMap = badger.storage.getStore("snitch_map"),
+ actionMap = badger.storage.getStore("action_map"),
+ snitchClones = snitchMap.getItemClones(),
+ actionClones = actionMap.getItemClones(),
+ correctedSites = {};
+
+ for (let domain in snitchClones) {
+ // creates new array of domains checking against the isThirdParty utility
+ let newSnitches = snitchClones[domain].filter(
+ item => utils.isThirdPartyDomain(item, domain));
+
+ if (newSnitches.length) {
+ correctedSites[domain] = newSnitches;
+ }
+ }
+
+ // clear existing maps and then use mergeUserData to rebuild them
+ actionMap.updateObject({});
+ snitchMap.updateObject({});
+
+ const data = {
+ snitch_map: correctedSites,
+ action_map: actionClones
+ };
+
+ // pass in boolean 2nd parameter to flag that it's run in a migration, preventing infinite loop
+ badger.mergeUserData(data, true);
+ },
+
+ forgetCloudflare: function (badger) {
+ let config = {
+ name: '__cfduid'
+ };
+ if (badger.firstPartyDomainPotentiallyRequired) {
+ config.firstPartyDomain = null;
+ }
+
+ chrome.cookies.getAll(config, function (cookies) {
+ console.log("Forgetting Cloudflare domains ...");
+
+ let actionMap = badger.storage.getStore("action_map"),
+ actionClones = actionMap.getItemClones(),
+ snitchMap = badger.storage.getStore("snitch_map"),
+ snitchClones = snitchMap.getItemClones(),
+ correctedSites = {},
+ // assume the tracking domains seen on these sites are all Cloudflare
+ cfduidFirstParties = new Set();
+
+ cookies.forEach(function (cookie) {
+ // get the base domain (also removes the leading dot)
+ cfduidFirstParties.add(window.getBaseDomain(cookie.domain));
+ });
+
+ for (let domain in snitchClones) {
+ let newSnitches = snitchClones[domain].filter(
+ item => !cfduidFirstParties.has(item));
+
+ if (newSnitches.length) {
+ correctedSites[domain] = newSnitches;
+ }
+ }
+
+ // clear existing maps and then use mergeUserData to rebuild them
+ actionMap.updateObject({});
+ snitchMap.updateObject({});
+
+ const data = {
+ snitch_map: correctedSites,
+ action_map: actionClones
+ };
+
+ // pass in boolean 2nd parameter to flag that it's run in a migration, preventing infinite loop
+ badger.mergeUserData(data, true);
+ });
+ },
+
+ // https://github.com/EFForg/privacybadger/pull/2245#issuecomment-545545717
+ forgetConsensu: (badger) => {
+ console.log("Forgetting consensu.org domains (GDPR consent provider) ...");
+ badger.storage.forget("consensu.org");
+ },
+
+ resetWebRTCIPHandlingPolicy2: function (badger) {
+ if (!badger.webRTCAvailable) {
+ return;
+ }
+
+ const cpn = chrome.privacy.network;
+
+ cpn.webRTCIPHandlingPolicy.get({}, function (result) {
+ if (!result.levelOfControl.endsWith('_by_this_extension')) {
+ return;
+ }
+
+ // migrate default (disabled) setting for old Badger versions
+ // from Mode 3 to Mode 1
+ if (result.value == 'default_public_interface_only') {
+ console.log("Resetting webRTCIPHandlingPolicy ...");
+ cpn.webRTCIPHandlingPolicy.clear({});
+
+ // migrate enabled setting for more recent Badger versions
+ // from Mode 4 to Mode 3
+ } else if (result.value == 'disable_non_proxied_udp') {
+ console.log("Updating WebRTC IP leak protection setting ...");
+ cpn.webRTCIPHandlingPolicy.set({
+ value: 'default_public_interface_only'
+ });
+ }
+ });
+ }
+
+};
+
+
+
+return exports;
+})(); //require scopes
diff --git a/src/js/multiDomainFirstParties.js b/src/js/multiDomainFirstParties.js
new file mode 100644
index 0000000..271d9b8
--- /dev/null
+++ b/src/js/multiDomainFirstParties.js
@@ -0,0 +1,4133 @@
+require.scopes.multiDomainFP = (function () {
+
+/**
+ * 2d array of related domains (etld+1), all domains owned by the same entity go into
+ * an array, this is later transformed for efficient lookups.
+ */
+let multiDomainFirstPartiesArray = [
+ ["1800contacts.com", "800contacts.com"],
+ ["37signals.com", "basecamp.com", "basecamphq.com", "highrisehq.com"],
+ ["9gag.com", "9cache.com"],
+ ["accountonline.com", "citi.com", "citibank.com", "citicards.com", "citibankonline.com"],
+ [
+ "adidas-group.com",
+
+ "adidas.ae",
+ "adidas.at",
+ "adidas.be",
+ "adidas.ca",
+ "adidas.ch",
+ "adidas.cl",
+ "adidas.cn",
+ "adidas.co",
+ "adidas.co.id",
+ "adidas.co.in",
+ "adidas.co.kr",
+ "adidas.com",
+ "adidas.com.ar",
+ "adidas.com.au",
+ "adidas.com.br",
+ "adidas.com.co",
+ "adidas.com.hk",
+ "adidas.com.my",
+ "adidas.com.om",
+ "adidas.com.pe",
+ "adidas.com.ph",
+ "adidas.com.qa",
+ "adidas.com.sa",
+ "adidas.com.sg",
+ "adidas.com.tr",
+ "adidas.com.tw",
+ "adidas.com.vn",
+ "adidas.co.nz",
+ "adidas.co.th",
+ "adidas.co.uk",
+ "adidas.co.za",
+ "adidas.cz",
+ "adidas.de",
+ "adidas.dk",
+ "adidas.es",
+ "adidas.fi",
+ "adidas.fr",
+ "adidas.gr",
+ "adidas.hu",
+ "adidas.ie",
+ "adidas.it",
+ "adidas.jp",
+ "adidas.mx",
+ "adidas.nl",
+ "adidas.no",
+ "adidas.pe",
+ "adidas.pl",
+ "adidas.pt",
+ "adidas.ru",
+ "adidas.se",
+ "adidas.sk",
+ "adidas.us",
+ ],
+ [
+ "adobe.com",
+ "adobeexchange.com",
+ "adobe.io",
+ "adobelogin.com",
+ "behance.net",
+ "mixamo.com",
+ "myportfolio.com",
+ "typekit.com",
+ ],
+ [
+ "airbnb.com",
+
+ "airbnb.ae",
+ "airbnb.al",
+ "airbnb.am",
+ "airbnb.at",
+ "airbnb.az",
+ "airbnb.ba",
+ "airbnb.be",
+ "airbnb.ca",
+ "airbnb.cat",
+ "airbnb.ch",
+ "airbnb.cl",
+ "airbnb.co.cr",
+ "airbnb.co.id",
+ "airbnb.co.il",
+ "airbnb.co.in",
+ "airbnb.co.kr",
+ "airbnb.com.ar",
+ "airbnb.com.au",
+ "airbnb.com.bo",
+ "airbnb.com.br",
+ "airbnb.com.bz",
+ "airbnb.com.co",
+ "airbnb.com.ec",
+ "airbnb.com.ee",
+ "airbnb.com.gt",
+ "airbnb.com.hk",
+ "airbnb.com.hn",
+ "airbnb.com.hr",
+ "airbnb.com.kh",
+ "airbnb.com.mt",
+ "airbnb.com.my",
+ "airbnb.com.ni",
+ "airbnb.com.pa",
+ "airbnb.com.pe",
+ "airbnb.com.ph",
+ "airbnb.com.py",
+ "airbnb.com.ro",
+ "airbnb.com.sg",
+ "airbnb.com.sv",
+ "airbnb.com.tr",
+ "airbnb.com.tw",
+ "airbnb.com.ua",
+ "airbnb.com.vn",
+ "airbnb.co.nz",
+ "airbnb.co.uk",
+ "airbnb.co.ve",
+ "airbnb.co.za",
+ "airbnb.cz",
+ "airbnb.de",
+ "airbnb.dk",
+ "airbnb.es",
+ "airbnb.fi",
+ "airbnb.fr",
+ "airbnb.gr",
+ "airbnb.gy",
+ "airbnb.hu",
+ "airbnb.ie",
+ "airbnb.is",
+ "airbnb.it",
+ "airbnb.jp",
+ "airbnb.la",
+ "airbnb.lt",
+ "airbnb.lu",
+ "airbnb.lv",
+ "airbnb.me",
+ "airbnb.mx",
+ "airbnb.nl",
+ "airbnb.no",
+ "airbnb.pl",
+ "airbnb.pt",
+ "airbnb.rs",
+ "airbnb.ru",
+ "airbnb.se",
+ "airbnb.si",
+
+ "muscache.com",
+ ],
+ [
+ "airfranceklm.com",
+
+ "airfrance.cg",
+ "airfrance.ci",
+ "airfrance.com.cn",
+ "airfrance.com.do",
+ "airfrance.com.gh",
+ "airfrance.dz",
+ "airfrance.id",
+ "airfrance.in",
+ "airfrance.my",
+ "airfrance.ng",
+ "airfrance.pa",
+ "airfrance.tn",
+ "airfrance.vn",
+
+ "klm.ae",
+ "klm.at",
+ "klm.aw",
+ "klm.be",
+ "klm.bg",
+ "klm.by",
+ "klm.bz",
+ "klm.ca",
+ "klm.ch",
+ "klm.cl",
+ "klm.co.ao",
+ "klm.co.cr",
+ "klm.co.id",
+ "klm.co.il",
+ "klm.co.in",
+ "klm.co.jp",
+ "klm.co.ke",
+ "klm.co.kr",
+ "klm.com",
+ "klm.com.ar",
+ "klm.com.au",
+ "klm.com.bh",
+ "klm.com.br",
+ "klm.com.co",
+ "klm.com.cy",
+ "klm.com.ec",
+ "klm.com.eg",
+ "klm.com.gh",
+ "klm.com.hk",
+ "klm.com.mt",
+ "klm.com.mx",
+ "klm.com.my",
+ "klm.com.na",
+ "klm.com.ng",
+ "klm.com.pa",
+ "klm.com.pe",
+ "klm.com.ph",
+ "klm.com.py",
+ "klm.com.qa",
+ "klm.com.tr",
+ "klm.com.tw",
+ "klm.com.uy",
+ "klm.co.nz",
+ "klm.co.th",
+ "klm.co.tz",
+ "klm.co.ug",
+ "klm.co.uk",
+ "klm.co.za",
+ "klm.co.zm",
+ "klm.cw",
+ "klm.cz",
+ "klm.de",
+ "klm.dk",
+ "klm.do",
+ "klm.es",
+ "klm.fi",
+ "klm.fr",
+ "klm.ge",
+ "klm.gr",
+ "klm.hr",
+ "klm.hu",
+ "klm.ie",
+ "klm.it",
+ "klm.kz",
+ "klm.lk",
+ "klm.lt",
+ "klm.lu",
+ "klm.lv",
+ "klm.mu",
+ "klm.mw",
+ "klm.nc",
+ "klm.nl",
+ "klm.no",
+ "klm.pl",
+ "klm.pt",
+ "klm.ro",
+ "klm.ru",
+ "klm.se",
+ "klm.sg",
+ "klm.sk",
+ "klm.sr",
+ "klm.sx",
+ "klm.ua",
+ "klm.us",
+
+ "static-af.com",
+ "static-kl.com",
+ ],
+ [
+ "alibaba.com",
+
+ "1688.com",
+ "95095.com",
+ "9game.cn",
+ "aliapp.org",
+ "alibabacloud.co.in",
+ "alibabacloud.com",
+ "alibabacloud.com.au",
+ "alibabacloud.com.hk",
+ "alibabacloud.com.my",
+ "alibabacloud.com.sg",
+ "alibabacloud.com.tw",
+ "alibabacorp.com",
+ "alibabagroup.com",
+ "alibaba-inc.com",
+ "alicdn.com",
+ "alicdn.net",
+ "alicloud.com",
+ "aliexpress.com",
+ "aliexpress.ru",
+ "alifanyi.com",
+ "aligames.com",
+ "alihealth.cn",
+ "alihive.com",
+ "aliimg.com",
+ "alimama.com",
+ "alimei.com",
+ "aliplus.com",
+ "alitrip.com",
+ "alitrip.hk",
+ "aliyun.com",
+ "aliyuncs.com",
+ "aliyun-iot-share.com",
+ "amap.com",
+ "cainiao.com",
+ "cainiao.com.cn",
+ "cibntv.net",
+ "cnzz.com",
+ "dayu.com",
+ "dingtalkapps.com",
+ "dingtalk.com",
+ "dongting.com",
+ "ele.me",
+ "elenet.me",
+ "etao.com",
+ "feizhu.cn",
+ "feizhu.com",
+ "fliggy.com",
+ "fliggy.hk",
+ "i52hz.com",
+ "jiaoyimao.com",
+ "jingguan.ai",
+ "jiyoujia.com",
+ "juhuasuan.com",
+ "kumiao.com",
+ "laifeng.com",
+ "liangxinyao.com",
+ "mappcloud.com",
+ "mei.com",
+ "mmstat.com",
+ "mobmore.com",
+ "paike.com",
+ "phpwind.com",
+ "phpwind.net",
+ "puata.info",
+ "soku.com",
+ "sparenode.com",
+ "supet.com",
+ "tanx.com",
+ "taobao.com",
+ "taopiaopiao.com",
+ "tbcdn.cn",
+ "tburl.in",
+ "teambitionapis.com",
+ "teambition.com",
+ "teambition.net",
+ "tianchi-global.com",
+ "tmail.com",
+ "tmall.com",
+ "tmall.hk",
+ "ttpod.com",
+ "tudou.com",
+ "uc.cn",
+ "ucweb.com",
+ "um0.cn",
+ "umengcloud.com",
+ "umeng.co",
+ "umeng.com",
+ "umindex.com",
+ "umsns.com",
+ "umtrack.com",
+ "wasu.tv",
+ "whalecloud.com",
+ "www.net.cn",
+ "xiami.com",
+ "ykimg.com",
+ "youku.com",
+ "youkutv.com",
+ "yousuode.cn",
+
+
+ "alipay.com",
+
+ "aliloan.com",
+ "alipay-cloud.com",
+ "alipay.cn",
+ "alipay-eco.com",
+ "alipay.hk",
+ "alipayobjects.com",
+ "alipayplus.com",
+ "ant-biz.com",
+ "ant-financial.com",
+ "antfin.com",
+ "antfin-inc.com",
+ "antfortune.com",
+ "antgroup.com",
+ "ant-open.com",
+ "antsdaq.com",
+ "ebuckler.com",
+ "fund123.cn",
+ "huijucai.com",
+ "koubei.com",
+ "mayiyunbao.com",
+ "mybank.cn",
+ "sinopayment.com.cn",
+ "ssdata.com",
+ "xin.xin",
+ "yidun.com",
+ "zamcs.com",
+ "zhisheng.com",
+ "zmxy.com.cn",
+
+ "lazada.com",
+
+ "lazada.co.id",
+ "lazada.com.my",
+ "lazada.com.ph",
+ "lazada.co.th",
+ "lazada.sg",
+ "lazada.vn",
+ ],
+ ["allstate.com", "myallstate.com"],
+ ["altra.org", "altraonline.org"],
+ [
+ "amazon.com",
+
+ "amazon.ae",
+ "amazon.ca",
+ "amazon.cn",
+ "amazon.co.jp",
+ "amazon.com.au",
+ "amazon.com.br",
+ "amazon.com.mx",
+ "amazon.com.sg",
+ "amazon.com.tr",
+ "amazon.co.uk",
+ "amazon.de",
+ "amazon.es",
+ "amazon.fr",
+ "amazon.in",
+ "amazon.it",
+ "amazon.nl",
+
+ "audible.com",
+ "audible.co.jp",
+ "audible.com.au",
+ "audible.co.uk",
+ "audible.de",
+ "audible.fr",
+ "audible.in",
+ "audible.it",
+
+ "6pm.com",
+ "acx.com",
+ "amazoninspire.com",
+ "aws.training",
+ "brilliancepublishing.com",
+ "comixology.com",
+ "createspace.com",
+ "dpreview.com",
+ "eastdane.com",
+ "fabric.com",
+ "goodreads.com",
+ "imdb.com",
+ "pillpack.com",
+ "primevideo.com",
+ "shopbop.com",
+ "wholefoodsmarket.com",
+ "woot.com",
+ "zappos.com",
+
+ "twitch.tv",
+ "ext-twitch.tv",
+ "jtvnw.net",
+ "ttvnw.net",
+
+ "amazonpay.com",
+ "media-amazon.com",
+ "ssl-images-amazon.com",
+ ],
+ [
+ "americanexpress.com",
+
+ "americanexpress.ca",
+ "americanexpress.ch",
+ "americanexpress.com.au",
+ "americanexpress.co.uk",
+ "americanexpress.no",
+
+ "membershiprewards.ca",
+ "membershiprewards.com.ar",
+ "membershiprewards.com.au",
+ "membershiprewards.com.sg",
+ "membershiprewards.co.uk",
+ "membershiprewards.de",
+
+ "aetclocator.com",
+ "americanexpressfhr.com",
+ "amexnetwork.com",
+ "amextravel.com",
+ "amextravelresources.com",
+ "thecenturionlounge.com",
+ "yourcarrentalclaim.com",
+
+ "aexp-static.com",
+ ],
+ ["ameritrade.com", "tdameritrade.com"],
+ [
+ "ancestry.com",
+
+ "ancestry.ca",
+ "ancestry.com.au",
+ "ancestry.co.uk",
+ "ancestry.de",
+ "ancestry.fr",
+ "ancestry.ie",
+ "ancestry.it",
+ "ancestry.mx",
+ "ancestry.nl",
+ "ancestry.no",
+ "ancestry.pl",
+ "ancestry.se",
+
+ "ancestrylibrary.com",
+ "archives.com",
+ "findagrave.com",
+ "fold3.com",
+ "newspapers.com",
+ "progenealogists.com",
+ "rootsweb.com",
+
+ "ancestrylibrary.ca",
+
+ "mfcreative.com",
+ "ancestrycdn.com",
+ ],
+ ["androidcentral.com", "mobilenations.com"],
+ [
+ "apa.at",
+ "apa-it.at",
+ "apa-defacto.at",
+ "ots.at",
+
+ "orf.at",
+ "oe24.at",
+ "wienerzeitung.at",
+ "kleinezeitung.at",
+ "vn.at",
+ "kurier.at",
+ "schautv.at",
+ "nachrichten.at",
+ "derstandard.at",
+ "sn.at",
+ "volksblatt.at",
+ "neue.at",
+
+ "tt.com",
+ "diepresse.com",
+ ],
+ ["apple.com", "icloud.com", "icloud.com.cn", "cdn-apple.com"],
+ ["applefcu.org", "applefcuonline.org"],
+ ["archive.org", "openlibrary.org"],
+ ["asos.com", "asosservices.com"],
+ [
+ "atlassian.com",
+
+ "atlassian.io",
+ "atlassian.net",
+ "bitbucket.org",
+ "customercase.com",
+ "enso.me",
+ "hipchat.com",
+ "jira.com",
+ "statuspage.io",
+ "stride.com",
+ "trello.com",
+
+ "atl-paas.net",
+ ],
+ [
+ "att.com",
+
+ "att.tv",
+ "atttvnow.com",
+ "attwatchtv.com",
+ "directv.com",
+ "directvnow.com",
+ ],
+ [
+ "autodesk.com",
+
+ "autodesk.io",
+ "autodesk.net",
+ "circuits.io",
+ "tinkercad.com",
+
+ "autodesk.ae",
+ "autodesk.be",
+ "autodesk.ca",
+ "autodesk.ch",
+ "autodesk.co.jp",
+ "autodesk.co.kr",
+ "autodesk.com.au",
+ "autodesk.com.br",
+ "autodesk.com.cn",
+ "autodesk.com.hk",
+ "autodesk.com.my",
+ "autodesk.com.sg",
+ "autodesk.com.tr",
+ "autodesk.com.tw",
+ "autodesk.co.nz",
+ "autodesk.co.uk",
+ "autodesk.co.za",
+ "autodesk.cz",
+ "autodesk.de",
+ "autodesk.dk",
+ "autodesk.es",
+ "autodesk.eu",
+ "autodesk.fi",
+ "autodesk.fr",
+ "autodesk.hu",
+ "autodesk.in",
+ "autodesk.it",
+ "autodesk.mx",
+ "autodesk.nl",
+ "autodesk.no",
+ "autodesk.pl",
+ "autodesk.pt",
+ "autodesk.ru",
+ "autodesk.se",
+ ],
+ ["avito.ru", "avito.st"],
+ ["avon.com", "youravon.com"],
+ [
+ "baidu.com",
+
+ "hao123.com",
+ "tieba.com",
+
+ "baidustatic.com",
+ "bdimg.com",
+ "bdstatic.com",
+ ],
+ ["balsamiq.com", "balsamiq.cloud"],
+ ["bancomer.com", "bancomer.com.mx", "bbvanet.com.mx"],
+ ["bankofamerica.com", "bofa.com", "mbna.com", "usecfo.com"],
+ ["bank-yahav.co.il", "bankhapoalim.co.il"],
+ [
+ "bauermedia.co.uk",
+
+ "carmagazine.co.uk",
+ "motorcyclenews.com",
+ "parkers.co.uk",
+
+ "bauersecure.com",
+ ],
+ ["bbc.co.uk", "bbc.com", "bbci.co.uk"],
+ ["belkin.com", "seedonk.com"],
+ [
+ "bellmedia.ca",
+
+ "9c9media.ca",
+ "9c9media.com",
+ "animalplanet.ca",
+ "bardown.com",
+ "bnnbloomberg.ca",
+ "bnn.ca",
+ "bravo.ca",
+ "canald.com",
+ "canalvie.com",
+ "cinepop.ca",
+ "cmdy.ca",
+ "cookieless.ca",
+ "cp24.com",
+ "crave.ca",
+ "crave.com",
+ "cravetv.ca",
+ "ctv.ca",
+ "ctvdigital.net",
+ "ctvnews.ca",
+ "discovery.ca",
+ "discoveryvelocity.ca",
+ "envedette.ca",
+ "etalk.ca",
+ "fraichementpresse.ca",
+ "investigationdiscovery.ca",
+ "investigationtele.com",
+ "lookdujour.ca",
+ "marilyn.ca",
+ "mtv.ca",
+ "much.ca",
+ "much.com",
+ "muchmusic.com",
+ "muramur.ca",
+ "rds.ca",
+ "sciencechannel.ca",
+ "sego-cdn.com",
+ "space.ca",
+ "superecran.com",
+ "superecrango.com",
+ "sympatico.ca",
+ "thecomedynetwork.ca",
+ "theloop.ca",
+ "thesocial.ca",
+ "tmngo.ca",
+ "tsn.ca",
+ "voyagevoyage.ca",
+ "vrak.tv",
+ "ztele.com",
+ ],
+ ["bhphotovideo.com", "bandh.com", "bhphoto.com", "bnh.com"],
+ ["bilibili.com", "acgvideo.com", "biliapi.net", "biliapi.com", "biligame.com", "hdslb.com"],
+ ["binance.com", "binance.cloud", "binance.vision", "bnbstatic.com"],
+ ["blizzard.com", "battle.net", "worldofwarcraft.com"],
+ ["bloomberg.com", "bbthat.com", "bwbx.io"],
+ ["boardgamearena.com", "boardgamearena.net"],
+ ["booking.com", "bstatic.com"],
+ ["box.com", "boxcdn.net"],
+ [
+ "bustle.company",
+
+ "bustle.com",
+ "elitedaily.com",
+ "inputmag.com",
+ "inverse.com",
+ "mic.com",
+ "nylon.com",
+ "romper.com",
+ "thezoereport.com",
+ ],
+ [
+ "canada.ca",
+
+ "ceaa-acee.gc.ca",
+ "collectionscanada.gc.ca",
+ "cra-arc.gc.ca",
+ "dfo-mpo.gc.ca",
+ "ec.gc.ca",
+ "esdc.gc.ca",
+ "fcac-acfc.gc.ca",
+ "hrdc-drhc.gc.ca",
+ "ic.gc.ca",
+ "jobbank.gc.ca",
+ "labour.gc.ca",
+ "nrcan.gc.ca",
+ "sac-isc.gc.ca",
+ "servicecanada.gc.ca",
+ "services.gc.ca",
+ "statcan.gc.ca",
+ "tbs-sct.gc.ca",
+ "tc.gc.ca",
+ "tpsgc-pwgsc.gc.ca",
+ "weather.gc.ca",
+
+ "archives.ca",
+ "canlearn.ca",
+ "gcsurplus.ca",
+ "letstalktransportation.ca",
+ ],
+ [
+ "canalplus.com",
+
+ "canal.fr",
+ "canalplay.com",
+ "canalplus-bo.net",
+ "canal-plus.com",
+ "canalplus.fr",
+ "canalplusinternational.com",
+ "canal-plus.net",
+ "canal-plus.pro",
+ "canalplus.pro",
+ "canalpro.fr",
+ "clique.tv",
+ "cstar.fr",
+ "mycanal.fr",
+ ],
+ ["capitalone.com", "capitalone360.com"],
+ [
+ "cbs.com",
+
+ "cbsi.com",
+ "cbsig.net",
+ "cbsimg.net",
+ "cbsinteractive.com",
+ "cbsistatic.com",
+ "cbslocal.com",
+ "cbsnews.com",
+ "cbssports.com",
+ "cbsstatic.com",
+ "chow.com",
+ "chowhound.com",
+ "chowmagazine.com",
+ "chowstatic.com",
+ "cnet.com",
+ "cnetcontent.com",
+ "cnettv.com",
+ "collegesports.com",
+ "com.com",
+ "comicvine.com",
+ "download.com",
+ "etonline.com",
+ "fansonly.com",
+ "gamespot.com",
+ "giantbomb.com",
+ "insideedition.com",
+ "last.fm",
+ "metacritic.com",
+ "news.com",
+ "scout.com",
+ "search.com",
+ "sho.com",
+ "sportsline.com",
+ "techrepublic.com",
+ "tv.com",
+ "tvgcdn.net",
+ "tvguide.com",
+ "upload.com",
+ "zdnet.com",
+ ],
+ ["cb2.com", "crateandbarrel.com"],
+ [
+ "ccmbenchmark.com",
+
+ "linternaute.com",
+ "journaldesfemmes.fr",
+ "journaldunet.com",
+ "commentcamarche.net",
+
+ "ccmbg.com",
+ ],
+ ["century21.com", "21online.com"],
+ ["chart.io", "chartio.com"],
+ ["chaturbate.com", "highwebmedia.com"],
+ [
+ "cisco.com",
+
+ "ciscolive.com",
+ "duo.com",
+ "netacad.com",
+ "webex.com",
+
+ "static-cisco.com",
+ ],
+ ["cms.gov", "medicare.gov", "mymedicare.gov"],
+ ["codepen.io", "cdpn.io"],
+ ["concur.com", "concursolutions.com"],
+ [
+ "cornell.edu",
+
+ "birdsna.org",
+ "birdsoftheworld.com",
+ "birdsoftheworld.org",
+ "ebird.org",
+ "hbw.com",
+ "macaulaylibrary.org",
+ ],
+ [
+ "condenast.com",
+
+ "architecturaldigest.com",
+ "arstechnica.com",
+ "bonappetit.com",
+ "cntraveler.com",
+ "epicurious.com",
+ "glamour.com",
+ "gq.com",
+ "lennyletter.com",
+ "newyorker.com",
+ "pitchfork.com",
+ "self.com",
+ "teenvogue.com",
+ "them.us",
+ "vanityfair.com",
+ "vogue.com",
+ "wired.com",
+
+ "condenastdigital.com",
+ ],
+ ["cox.com", "cox.net"],
+ ["cricketwireless.com", "aiowireless.com"],
+ ["ctrip.com", "c-ctrip.com", "trip.com"],
+ ["dcu.org", "dcu-online.org"],
+ ["dictionary.com", "thesaurus.com", "sfdict.com"],
+ [
+ "digikey.com",
+
+ "digikey.ae",
+ "digikey.am",
+ "digikey.at",
+ "digikey.ba",
+ "digikey.be",
+ "digikey.bg",
+ "digikey.bo",
+ "digikey.by",
+ "digikey.ca",
+ "digikey.ch",
+ "digikey.cl",
+ "digikey.cn",
+ "digikey.co.id",
+ "digikey.co.il",
+ "digikey.com.ar",
+ "digikey.com.au",
+ "digikey.com.br",
+ "digikey.com.cn",
+ "digikey.com.co",
+ "digikey.com.cy",
+ "digikey.com.eg",
+ "digikey.com.gt",
+ "digikey.com.hr",
+ "digikey.com.jm",
+ "digikey.com.lb",
+ "digikey.com.mk",
+ "digikey.com.mx",
+ "digikey.com.pa",
+ "digikey.com.tr",
+ "digikey.com.ua",
+ "digikey.com.uy",
+ "digikey.com.ve",
+ "digikey.co.nz",
+ "digikey.co.th",
+ "digikey.co.uk",
+ "digikey.co.za",
+ "digikey.cr",
+ "digikey.cz",
+ "digikey.de",
+ "digikey.dk",
+ "digikey.do",
+ "digikey.ec",
+ "digikey.ee",
+ "digikey.es",
+ "digikey.fi",
+ "digikey.fr",
+ "digikey.gr",
+ "digikey.hk",
+ "digikey.hu",
+ "digikey.ie",
+ "digikey.in",
+ "digikey.is",
+ "digikey.it",
+ "digikey.jp",
+ "digikey.kr",
+ "digikey.lk",
+ "digikey.lt",
+ "digikey.lu",
+ "digikey.lv",
+ "digikey.ma",
+ "digikey.md",
+ "digikey.my",
+ "digikey.nl",
+ "digikey.no",
+ "digikey.pe",
+ "digikey.ph",
+ "digikey.pk",
+ "digikey.pl",
+ "digikey.pr",
+ "digikey.pt",
+ "digikey.ro",
+ "digikey.rs",
+ "digikey.ru",
+ "digikey.se",
+ "digikey.sg",
+ "digikey.si",
+ "digikey.sk",
+ "digikey.tn",
+ "digikey.tw",
+ "digikey.vn",
+ ],
+ [
+ "digitec.ch",
+
+ "galaxus.ch",
+ "galaxus.de",
+ "galaxus.fr",
+
+ "digitecgalaxus.ch",
+ ],
+ [
+ "directferries.com",
+
+ "directferries.at",
+ "directferries.be",
+ "directferries.ca",
+ "directferries.ch",
+ "directferries.cn",
+ "directferries.co.id",
+ "directferries.co.kr",
+ "directferries.com.au",
+ "directferries.com.tr",
+ "directferries.com.ua",
+ "directferries.co.nz",
+ "directferries.co.uk",
+ "directferries.cz",
+ "directferries.de",
+ "directferries.dk",
+ "directferries.es",
+ "directferries.fi",
+ "directferries.fr",
+ "directferries.gr",
+ "directferries.ie",
+ "directferries.it",
+ "directferries.jp",
+ "directferries.kr",
+ "directferries.ma",
+ "directferries.nl",
+ "directferries.no",
+ "directferries.nz",
+ "directferries.pl",
+ "directferries.pt",
+ "directferries.ro",
+ "directferries.ru",
+ "directferries.se",
+ "directferries.sk",
+ "directferries.xyz",
+ ],
+ ["discountbank.co.il", "telebank.co.il"],
+ ["discord.com", "discordapp.com", "discordapp.net"],
+ ["discover.com", "discovercard.com"],
+ ["disqus.com", "disquscdn.com"],
+ [
+ "dmgmedia.co.uk",
+
+ "dailymail.co.uk",
+ "inews.co.uk",
+ "mailonsunday.co.uk",
+ "metro.co.uk",
+ "thisismoney.co.uk",
+
+ "dmgmediaprivacy.co.uk",
+ ],
+ [
+ "dpgmediagroup.com",
+
+ "persgroep.net",
+ "persgroep.cloud",
+
+ "7sur7.be",
+ "ad.nl",
+ "bd.nl",
+ "beursrally.be",
+ "beurswijzer.com",
+ "bndestem.nl",
+ "demorgen.be",
+ "destentor.nl",
+ "dpgmedia.be",
+ "dpgmedia.nl",
+ "ed.nl",
+ "gelderlander.nl",
+ "hln.be",
+ "humo.be",
+ "parool.nl",
+ "persgroepinternational.be",
+ "persgroepinternational.com",
+ "persgroep.nl",
+ "pzc.nl",
+ "tijd.be",
+ "topics.be",
+ "topics.nl",
+ "trouw.nl",
+ "tubantia.nl",
+ "volkskrant.nl",
+ "vtm.be",
+
+ "dpgmedia.net",
+ ],
+ ["dropbox.com", "dropboxstatic.com", "dropboxusercontent.com", "getdropbox.com"],
+ ["d.rip", "kickstarter.com"],
+ [
+ "ea.com",
+
+ "bioware.com",
+ "masseffect.com",
+ "origin.com",
+ "play4free.com",
+ "tiberiumalliance.com",
+ ],
+ [
+ "ebay.com",
+ "ebayinc.com",
+
+ "ebay.at",
+ "ebay.be",
+ "ebay.ca",
+ "ebay.ch",
+ "ebay.com.au",
+ "ebay.com.hk",
+ "ebay.com.my",
+ "ebay.com.sg",
+ "ebay.co.uk",
+ "ebay.de",
+ "ebay.es",
+ "ebay.fr",
+ "ebay.ie",
+ "ebay.in",
+ "ebay.it",
+ "ebay.nl",
+ "ebay.ph",
+ "ebay.pl",
+ "vivanuncios.com.mx",
+
+ "ebaydesc.com",
+ "ebayimg.com",
+ "ebayrtm.com",
+ "ebaystatic.com",
+ "ebay-us.com",
+ ],
+ ["elsevier.com", "sciencedirect.com", "sciencedirectassets.com"],
+ [
+ "enterprise.com",
+
+ "alamo.ca",
+ "alamo.com",
+
+ "autoshare.com",
+ "autoshare.biz",
+ "autoshare.ca",
+ "autoshare.net",
+ "autoshare.org",
+
+ "cars.info",
+ "carsharing.ca",
+ "carsharingtoronto.com",
+ "citer.fr",
+
+ "ehi.com",
+ "ehiaws.com",
+
+ "enterprise.ca",
+ "enterprise.ch",
+ "enterprise.com.jm",
+ "enterprise.co.uk",
+ "enterprise.de",
+ "enterprise.dk",
+ "enterprise.ec",
+ "enterprise.es",
+ "enterprise.fr",
+ "enterprise.gr",
+ "enterprise.hr",
+ "enterprise.hu",
+ "enterprise.ie",
+ "enterprise.lv",
+ "enterprise.nl",
+ "enterprise.no",
+ "enterprise.pt",
+ "enterprise.se",
+
+ "enterprisecarclub.co.uk",
+ "enterprisecarclub.ie",
+
+ "enterprisecarshare.ca",
+ "enterprisecarshare.com",
+ "enterprisecarshare.co.uk",
+
+ "enterpriserideshare.com",
+
+ "enterpriserentacar.at",
+ "enterpriserentacar.be",
+ "enterpriserentacar.bg",
+ "enterpriserentacar.ca",
+ "enterpriserentacar.com.au",
+ "enterpriserentacar.co.nz",
+ "enterpriserentacar.cz",
+ "enterpriserentacar.is",
+ "enterpriserentacar.it",
+ "enterpriserentacar.pl",
+ "enterpriserentacar.se",
+
+ "nationalcar.ca",
+ "nationalcar.com",
+ "nationalcar.co.uk",
+ "nationalcar.de",
+ "nationalcar.es",
+ "nationalcar.fr",
+ "nationalcar.ie",
+ "nationalcar.it",
+ "nationalcar.mobi",
+
+ "onewaygo.de",
+
+ "alamo-np.ca",
+ "alamo-np.com",
+ "alamo-np.co.uk",
+ "alamo-np.de",
+ "alamo-np.es",
+ "alamo-np.fr",
+ "alamo-np.ie",
+ ],
+ ["epicgames.com", "unrealengine.com"],
+ [
+ "eventbrite.com",
+
+ "eventbrite.at",
+ "eventbrite.be",
+ "eventbrite.ca",
+ "eventbrite.ch",
+ "eventbrite.cl",
+ "eventbrite.co",
+ "eventbrite.com.ar",
+ "eventbrite.com.au",
+ "eventbrite.com.br",
+ "eventbrite.com.mx",
+ "eventbrite.com.ng",
+ "eventbrite.com.pe",
+ "eventbrite.co.nz",
+ "eventbrite.co.uk",
+ "eventbrite.co.za",
+ "eventbrite.de",
+ "eventbrite.dk",
+ "eventbrite.es",
+ "eventbrite.fi",
+ "eventbrite.fr",
+ "eventbrite.hk",
+ "eventbrite.ie",
+ "eventbrite.in",
+ "eventbrite.it",
+ "eventbrite.my",
+ "eventbrite.nl",
+ "eventbrite.ph",
+ "eventbrite.pt",
+ "eventbrite.se",
+ "eventbrite.sg",
+
+ "evbstatic.com",
+ "evbuc.com",
+ "eventbriteapi.com",
+ ],
+ [
+ "expedia.com",
+
+ "carrentals.com",
+ "cheaptickets.com",
+ "ebookers.com",
+ "hotels.com",
+ "hotwire.com",
+ "mrjet.se",
+ "orbitz.com",
+ "travelocity.com",
+ "wotif.com",
+
+ "expedia-aarp.com",
+ "expedia-barclays.co.uk",
+ "expedia-cn.com",
+ "expedia.at",
+ "expedia.be",
+ "expedia.ca",
+ "expedia.ch",
+ "expedia.cn",
+ "expedia.co.id",
+ "expedia.co.in",
+ "expedia.co.jp",
+ "expedia.co.kr",
+ "expedia.co.nz",
+ "expedia.co.th",
+ "expedia.co.uk",
+ "expedia.com.ar",
+ "expedia.com.au",
+ "expedia.com.br",
+ "expedia.com.hk",
+ "expedia.com.my",
+ "expedia.com.ph",
+ "expedia.com.sg",
+ "expedia.com.tw",
+ "expedia.com.vn",
+ "expedia.de",
+ "expedia.dk",
+ "expedia.es",
+ "expedia.fi",
+ "expedia.fr",
+ "expedia.ie",
+ "expedia.it",
+ "expedia.mx",
+ "expedia.nl",
+ "expedia.no",
+ "expedia.ru",
+ "expedia.se",
+ "expediacorporate.eu",
+
+ "expedia.net",
+
+ "travel-assets.com",
+ "trvl-media.com",
+
+ "lastminute.com.au",
+ "lastminute.co.nz",
+ "wotif.com.au",
+ "wotif.co.nz",
+
+ "cdn-hotels.com",
+ "hotels.cn",
+
+ "hotwirestatic.com",
+
+ "ebookers.at",
+ "ebookers.be",
+ "ebookers.ch",
+ "ebookers.co.uk",
+ "ebookers.de",
+ "ebookers.fi",
+ "ebookers.fr",
+ "ebookers.ie",
+ "ebookers.nl",
+ "ebookers.no",
+
+ "mrjet.dk",
+
+ "vrbo.com",
+
+ "abritel.fr",
+ "aluguetemporada.com.br",
+ "fewo-direkt.de",
+ "homeaway.at",
+ "homeaway.ca",
+ "homeaway.com",
+ "homeaway.com.au",
+ "homeaway.com.mx",
+ "homeaway.co.nz",
+ "homeaway.co.uk",
+ "homeaway.dk",
+ "homeaway.es",
+ "homeaway.fi",
+ "homeaway.gr",
+ "homeaway.it",
+ "homeaway.nl",
+ "homeaway.no",
+ "homeaway.pl",
+ "homeaway.pt",
+ "homeaway.se",
+ "homelidays.com",
+ "homelidays.es",
+ "homelidays.fr",
+ "homelidays.it",
+ "ownersdirect.co.uk",
+ "stayz.com.au",
+ "vacationrentals.com",
+ ],
+ ["express-scripts.com", "medcohealth.com"],
+ [
+ "facebook.com",
+
+ "messenger.com",
+ "workplace.com",
+
+ "oculus.com",
+ "oculuscdn.com",
+ "oculusrift.com",
+ "oculusvr.com",
+ "powersunitedvr.com",
+
+ "facebook.net",
+ "fbcdn.com",
+ "fbcdn.net",
+ "fbsbx.com",
+ ],
+ [
+ "faithlife.com",
+
+ "biblescreen.com",
+ "biblestudymagazine.com",
+ "biblia.com",
+ "didaktikosjournal.com",
+ "faithlifetv.com",
+ "kirkdalepress.com",
+ "lexhampress.com",
+ "logos.com",
+ "ministrytracker.com",
+ "proclaimonline.com",
+ "verbum.com",
+
+ "bibliacdn.com",
+ "faithlifecdn.com",
+ "faithlifesitescdn.com",
+ "logoscdn.com",
+ ],
+ [
+ "fandom.com",
+ "fandom-dev.pl",
+ "fandom-dev.us",
+ "nocookie.net",
+ "wikia.com",
+ "wikia-dev.com",
+ "wikia-dev.pl",
+ "wikia-dev.us",
+ "wikiafanstudio.com",
+ "wikia-inc.com",
+ "wikia.net",
+ "wikia.org",
+ "wikia-services.com",
+ "wikia-staging.com",
+ ],
+ [
+ "fastcompany.com",
+
+ "fastcocreate.com",
+ "fastcodesign.com",
+ "fastcoexist.com",
+ "fastcolabs.com",
+ "fast-co.net",
+ "fcimpactcouncil.com",
+ "inc.com",
+ "innovationuncensored.com",
+ "mansueto.com",
+ "mvdigitalmedia.com",
+ "mvlicensing.com",
+ "nativguard.com",
+ "retirementcomm.com",
+
+ "fastcompany.net",
+ ],
+ ["fastmail.com", "fastmailusercontent.com"],
+ ["firefox.com", "firefoxusercontent.com", "mozilla.org"],
+ ["foxnews.com", "foxbusiness.com", "fncstatic.com"],
+ [
+ "futureplc.com",
+
+ "creativebloq.com",
+ "cyclingnews.com",
+ "digitalcameraworld.com",
+ "gamesradar.com",
+ "gizmodo.co.uk",
+ "guitarworld.com",
+ "kotaku.co.uk",
+ "laptopmag.com",
+ "lifehacker.co.uk",
+ "livescience.com",
+ "loudersound.com",
+ "musicradar.com",
+ "pcgamer.com",
+ "space.com",
+ "t3.com",
+ "techradar.com",
+ "tomsguide.com",
+ "tomshardware.com",
+ "toptenreviews.com",
+ "whathifi.com",
+
+ "futurecdn.net",
+ "future-fie-assets.co.uk",
+ "future-fie.co.uk",
+ "future.net.uk",
+ ],
+ ["gamestar.de", "gamepro.de", "cgames.de"],
+ [
+ "gap.com",
+
+ "bananarepublic.com",
+ "gapfactory.com",
+ "gapinc.com",
+ "oldnavy.com",
+ "piperlime.com",
+
+ "bananarepublic.ca",
+ "bananarepublic.co.jp",
+ "bananarepublic.co.uk",
+ "bananarepublic.eu",
+ "gapcanada.ca",
+ "gap.co.jp",
+ "gap.co.uk",
+ "gap.eu",
+ "gap.hk",
+ "oldnavy.ca",
+
+ "assets-gap.com",
+ ],
+ [
+ "gedispa.it",
+
+ "capital.it",
+ "deejay.it",
+ "gelocal.it",
+ "ilsecoloxix.it",
+ "kataweb.it",
+ "lastampa.it",
+ "lescienze.it",
+ "limesonline.com",
+ "m2o.it",
+ "mymovies.it",
+ "repubblica.it",
+
+ "gedidigital.it",
+ "repstatic.it",
+ ],
+ [
+ "gettyimages.com",
+
+ "gettyimages.ca",
+ "gettyimages.com.au",
+ "gettyimages.co.uk",
+ "gettyimages.dk",
+ "gettyimages.fi",
+ "gettyimages.nl",
+
+ "istockphoto.com",
+
+ "thinkstockphotos.com",
+ "thinkstockphotos.ca",
+ ],
+ ["gitlab.com", "gitlab-static.net"],
+ [
+ "gizmodo.com",
+
+ "avclub.com",
+ "deadspin.com",
+ "jalopnik.com",
+ "jezebel.com",
+ "kinja.com",
+ "kinja-img.com",
+ "kinja-static.com",
+ "kotaku.com",
+ "lifehacker.com",
+ "technoratimedia.com",
+ "theinventory.com",
+ "theonion.com",
+ "theroot.com",
+ "thetakeout.com",
+ ],
+ [
+ "glassdoor.com",
+
+ "glassdoor.be",
+ "glassdoor.ca",
+ "glassdoor.co.in",
+ "glassdoor.com.au",
+ "glassdoor.co.uk",
+ "glassdoor.de",
+ "glassdoor.fr",
+ "glassdoor.ie",
+ "glassdoor.nl",
+ ],
+ ["gogoair.com", "gogoinflight.com"],
+ [
+ "google.com",
+ "youtube.com",
+ "gmail.com",
+ "blogger.com",
+ "blog.google",
+ "googleblog.com",
+ "chromium.org",
+
+ "ggpht.com",
+ "googleusercontent.com",
+ "googlevideo.com",
+ "gstatic.com",
+ "youtube-nocookie.com",
+ "ytimg.com",
+
+ "google.ad",
+ "google.ae",
+ "google.al",
+ "google.am",
+ "google.as",
+ "google.at",
+ "google.az",
+ "google.ba",
+ "google.be",
+ "google.bf",
+ "google.bg",
+ "google.bi",
+ "google.bj",
+ "google.bs",
+ "google.bt",
+ "google.by",
+ "google.ca",
+ "google.cat",
+ "google.cd",
+ "google.cf",
+ "google.cg",
+ "google.ch",
+ "google.ci",
+ "google.cl",
+ "google.cm",
+ "google.cn",
+ "google.com.af",
+ "google.com.ag",
+ "google.com.ai",
+ "google.com.ar",
+ "google.com.au",
+ "google.com.bd",
+ "google.com.bh",
+ "google.com.bn",
+ "google.com.bo",
+ "google.com.br",
+ "google.com.bz",
+ "google.com.co",
+ "google.com.cu",
+ "google.com.cy",
+ "google.com.do",
+ "google.com.ec",
+ "google.com.eg",
+ "google.com.et",
+ "google.com.fj",
+ "google.com.gh",
+ "google.com.gi",
+ "google.com.gt",
+ "google.com.hk",
+ "google.com.jm",
+ "google.com.kh",
+ "google.com.kw",
+ "google.com.lb",
+ "google.com.ly",
+ "google.com.mm",
+ "google.com.mt",
+ "google.com.mx",
+ "google.com.my",
+ "google.com.na",
+ "google.com.ng",
+ "google.com.ni",
+ "google.com.np",
+ "google.com.om",
+ "google.com.pa",
+ "google.com.pe",
+ "google.com.pg",
+ "google.com.ph",
+ "google.com.pk",
+ "google.com.pr",
+ "google.com.py",
+ "google.com.qa",
+ "google.com.sa",
+ "google.com.sb",
+ "google.com.sg",
+ "google.com.sl",
+ "google.com.sv",
+ "google.com.tj",
+ "google.com.tr",
+ "google.com.tw",
+ "google.com.ua",
+ "google.com.uy",
+ "google.com.vc",
+ "google.com.vn",
+ "google.co.ao",
+ "google.co.bw",
+ "google.co.ck",
+ "google.co.cr",
+ "google.co.id",
+ "google.co.il",
+ "google.co.in",
+ "google.co.jp",
+ "google.co.ke",
+ "google.co.kr",
+ "google.co.ls",
+ "google.co.ma",
+ "google.co.mz",
+ "google.co.nz",
+ "google.co.th",
+ "google.co.tz",
+ "google.co.ug",
+ "google.co.uk",
+ "google.co.uz",
+ "google.co.ve",
+ "google.co.vi",
+ "google.co.za",
+ "google.co.zm",
+ "google.co.zw",
+ "google.cv",
+ "google.cz",
+ "google.de",
+ "google.dj",
+ "google.dk",
+ "google.dm",
+ "google.dz",
+ "google.ee",
+ "google.es",
+ "google.fi",
+ "google.fm",
+ "google.fr",
+ "google.ga",
+ "google.ge",
+ "google.gg",
+ "google.gl",
+ "google.gm",
+ "google.gr",
+ "google.gy",
+ "google.hn",
+ "google.hr",
+ "google.ht",
+ "google.hu",
+ "google.ie",
+ "google.im",
+ "google.iq",
+ "google.is",
+ "google.it",
+ "google.je",
+ "google.jo",
+ "google.kg",
+ "google.ki",
+ "google.kz",
+ "google.la",
+ "google.li",
+ "google.lk",
+ "google.lt",
+ "google.lu",
+ "google.lv",
+ "google.md",
+ "google.me",
+ "google.mg",
+ "google.mk",
+ "google.ml",
+ "google.mn",
+ "google.ms",
+ "google.mu",
+ "google.mv",
+ "google.mw",
+ "google.ne",
+ "google.nl",
+ "google.no",
+ "google.nr",
+ "google.nu",
+ "google.pl",
+ "google.pn",
+ "google.ps",
+ "google.pt",
+ "google.ro",
+ "google.rs",
+ "google.ru",
+ "google.rw",
+ "google.sc",
+ "google.se",
+ "google.sh",
+ "google.si",
+ "google.sk",
+ "google.sm",
+ "google.sn",
+ "google.so",
+ "google.sr",
+ "google.st",
+ "google.td",
+ "google.tg",
+ "google.tl",
+ "google.tm",
+ "google.tn",
+ "google.to",
+ "google.tt",
+ "google.vg",
+ "google.vu",
+ "google.ws",
+
+ "fonts.googleapis.com",
+ "storage.googleapis.com",
+ "www.googleapis.com",
+
+ "nest.com",
+ "codingcompetitions.withgoogle.com",
+ "nestpowerproject.withgoogle.com",
+ ],
+ ["www.gov.uk", "cabinet-office.gov.uk", "publishing.service.gov.uk"],
+ [
+ "gray.tv",
+
+ "1011northplatte.com",
+ "1011now.com",
+ "13abc.com",
+ "26nbc.com",
+ "abc12.com",
+ "blackhillsfox.com",
+ "cbs7.com",
+ "graydc.com",
+ "kalb.com",
+ "kbtx.com",
+ "kcrg.com",
+ "kcwy13.com",
+ "kfyrtv.com",
+ "kgns.tv",
+ "kgwn.tv",
+ "kkco11news.com",
+ "kktv.com",
+ "kmot.com",
+ "kmvt.com",
+ "knoe.com",
+ "knopnews2.com",
+ "kolotv.com",
+ "kotatv.com",
+ "kqcd.com",
+ "ksfy.com",
+ "ksnblocal4.com",
+ "kspr.com",
+ "ktuu.com",
+ "kumv.com",
+ "kwch.com",
+ "kwqc.com",
+ "kwtx.com",
+ "kxii.com",
+ "ky3.com",
+ "nbc15.com",
+ "newsplex.com",
+ "thenewscenter.tv",
+ "uppermichigansource.com",
+ "valleynewslive.com",
+ "wabi.tv",
+ "wagmtv.com",
+ "wbay.com",
+ "wbko.com",
+ "wcax.com",
+ "wcjb.com",
+ "wctv.tv",
+ "wdbj7.com",
+ "wdtv.com",
+ "weau.com",
+ "webcenter11.com",
+ "whsv.com",
+ "wibw.com",
+ "wifr.com",
+ "wilx.com",
+ "witn.com",
+ "wjhg.com",
+ "wkyt.com",
+ "wndu.com",
+ "wowt.com",
+ "wrdw.com",
+ "wsaw.com",
+ "wsaz.com",
+ "wswg.tv",
+ "wtok.com",
+ "wtvy.com",
+ "wvlt.tv",
+ "wymt.com",
+
+ "graytvinc.com",
+ ],
+ ["guardian.co.uk", "guim.co.uk", "guardianapps.co.uk", "theguardian.com", "gu-web.net"],
+ [
+ "habr.com",
+ "habr.ru",
+ "habrahabr.ru",
+ "freelansim.ru",
+ "geektimes.com",
+ "geektimes.ru",
+ "moikrug.ru",
+ "toster.ru",
+
+ "habracdn.net",
+ "habrastorage.org",
+ "hsto.org",
+ ],
+ ["healthfusion.com", "healthfusionclaims.com"],
+ [
+ "hearst.com",
+
+ "25ans.jp",
+ "autoweek.com",
+ "bazaar.com",
+ "beaumontenterprise.com",
+ "bestproducts.com",
+ "bicycling.com",
+ "caranddriver.com",
+ "chron.com",
+ "cosmopolitan.com",
+ "countryliving.com",
+ "crfashionbook.com",
+ "ctnews.com",
+ "ctpost.com",
+ "dariennewsonline.com",
+ "delish.com",
+ "drozthegoodlife.com",
+ "elle.com",
+ "elledecor.com",
+ "esquire.com",
+ "expressnews.com",
+ "fairfieldcitizenonline.com",
+ "foothillstrader.com",
+ "fujingaho.jp",
+ "gametimect.com",
+ "gearpatrol.com",
+ "ghsealapplication.com",
+ "goodhouse.com",
+ "goodhousekeeping.com",
+ "greenwichtime.com",
+ "harpersbazaar.com",
+ "housebeautiful.com",
+ "houstonchronicle.com",
+ "lmtonline.com",
+ "marieclaire.com",
+ "menshealth.com",
+ "michigansthumb.com",
+ "middletownpress.com",
+ "mrt.com",
+ "myjournalcourier.com",
+ "mylo.id",
+ "myplainview.com",
+ "mysanantonio.com",
+ "newcanaannewsonline.com",
+ "newmilfordspectrum.com",
+ "newstimes.com",
+ "nhregister.com",
+ "oprahmag.com",
+ "ourmidland.com",
+ "popularmechanics.com",
+ "prevention.com",
+ "redbookmag.com",
+ "registercitizen.com",
+ "roadandtrack.com",
+ "rodalesorganiclife.com",
+ "runnersworld.com",
+ "seattlepi.com",
+ "seventeen.com",
+ "sfchronicle.com",
+ "sfgate.com",
+ "shondaland.com",
+ "stamfordadvocate.com",
+ "s-w-e-e-t.com",
+ "thehour.com",
+ "theintelligencer.com",
+ "thepioneerwoman.com",
+ "thepioneerwomancooks.com",
+ "thetelegraph.com",
+ "timesunion.com",
+ "todays-rewards.com",
+ "townandcountrymag.com",
+ "veranda.com",
+ "wearesweet.co",
+ "westport-news.com",
+ "womansday.com",
+ "womenshealthmag.com",
+ "yourconroenews.com",
+
+ "h-cdn.co",
+ "hdmtech.net",
+ "hdmtools.com",
+ "hdnux.com",
+ "hearst3pcc.com",
+ "hearstapps.com",
+ "hearstapps.net",
+ "hearstdigitalstudios.com",
+ "hearstdigitalstudios.net",
+ "hearst.io",
+ "hearstlabs.com",
+ "hearstmags.com",
+ "hearstmobile.com",
+ "hearstnp.com",
+ ],
+ [
+ "houzz.com",
+
+ "houzz.at",
+ "houzz.be",
+ "houzz.ca",
+ "houzz.ch",
+ "houzz.co.jp",
+ "houzz.com.au",
+ "houzz.com.sg",
+ "houzz.co.nz",
+ "houzz.co.uk",
+ "houzz.de",
+ "houzz.dk",
+ "houzz.es",
+ "houzz.fi",
+ "houzz.fr",
+ "houzz.ie",
+ "houzz.in",
+ "houzz.it",
+ "houzz.jp",
+ "houzz.no",
+ "houzz.nz",
+ "houzz.pt",
+ "houzz.ru",
+ "houzz.se",
+ "houzz.sg",
+ "houzz.uk",
+
+ "gardenweb.com",
+ "gwhouzz3.com",
+ "gwhouzz.com",
+ "houzz2.com",
+ "houzz2.com.au",
+ "houzz2.co.uk",
+ "houzz3.com",
+ "houzz3.com.au",
+ "houzz3.co.uk",
+ "hzcdn.com",
+ "stghouzz.com",
+ "thathomesite.com",
+ ],
+ [
+ "huobi.com",
+
+ "hbfile.net",
+ "hbg.com",
+ "huobiasia.vip",
+ "huobi.br.com",
+ "huobi.me",
+ ],
+ ["hvfcu.org", "hvfcuonline.org"],
+ [
+ "idealo.de",
+
+ "idealo.at",
+ "idealo.co.uk",
+ "idealo.es",
+ "idealo.fr",
+ "idealo.it",
+ "idealo.com",
+ ],
+ [
+ "ign.fr",
+
+ "cartoradio.fr",
+ "culture.fr",
+ "duministeredelaculture.fr",
+ "gouvernement.fr",
+ "ignrando.fr",
+
+ "ants.gouv.fr",
+ "culture.gouv.fr",
+ "data.gouv.fr",
+ "education.gouv.fr",
+ "etalab.gouv.fr",
+ "geoportail.gouv.fr",
+ "geoportail-urbanisme.gouv.fr",
+ "impots.gouv.fr",
+ "premier-ministre.gouv.fr",
+ "service-civique.gouv.fr",
+ "yvelines.gouv.fr",
+
+ "ac-grenoble.fr",
+ "ac-versailles.fr",
+ "ac-bordeaux.fr",
+ "ac-montpellier.fr",
+ "ac-lille.fr",
+ ],
+ [
+ "impresa.pt",
+
+ "blitz.pt",
+ "expresso.pt",
+ "famashow.pt",
+ "impresamediacriativa.pt",
+ "sapo.pt",
+ "siccaras.pt",
+ "sickapa.pt",
+ "sicmulher.pt",
+ "sicnoticias.pt",
+ "sic.pt",
+ "sicradical.pt",
+ "smack.pt",
+ "tribunaexpresso.pt",
+ "volantesic.pt",
+ ],
+ [
+ "immobilienscout24.de",
+ "static-immobilienscout24.de",
+ ],
+ [
+ "indeed.com",
+
+ "indeed.ae",
+ "indeed.ca",
+ "indeed.ch",
+ "indeed.cl",
+ "indeed.co.in",
+ "indeed.com.au",
+ "indeed.com.br",
+ "indeed.com.co",
+ "indeed.com.mx",
+ "indeed.com.my",
+ "indeed.com.pe",
+ "indeed.com.ph",
+ "indeed.com.pk",
+ "indeed.com.sg",
+ "indeed.co.uk",
+ "indeed.co.ve",
+ "indeed.co.za",
+ "indeed.de",
+ "indeed.es",
+ "indeed.fi",
+ "indeed.fr",
+ "indeed.hk",
+ "indeed.ie",
+ "indeed.jp",
+ "indeed.lu",
+ "indeed.nl",
+ "indeed.pt",
+ ],
+ ["independent.co.uk", "indy100.com"],
+ [
+ "iu.edu",
+
+ "indiana.edu",
+ "iue.edu",
+ "iufw.edu",
+ "iuk.edu",
+ "iun.edu",
+ "iupuc.edu",
+ "iupui.edu",
+ "iusb.edu",
+ "ius.edu",
+ "myiu.org",
+ ],
+ [
+ "jd.com",
+ "3.cn",
+ "360buy.com",
+ "360buyimg.com",
+ "7fresh.com",
+ "baitiao.com",
+ "caiyu.com",
+ "chinabank.com.cn",
+ "jd.co.th",
+ "jd.hk",
+ "jd.id",
+ "jd.ru",
+ "jdpay.com",
+ "jdwl.com",
+ "jdx.com",
+ "jkcsjd.com",
+ "joybuy.com",
+ "joybuy.es",
+ "ocwms.com",
+ "paipai.com",
+ "toplife.com",
+ "wangyin.com",
+ "yhd.com",
+ "yihaodianimg.com",
+ "yiyaojd.com",
+ "yizhitou.com",
+ ],
+ [
+ "jetbrains.com",
+
+ "datalore.io",
+ "intellij.net",
+ "jetbrains.dev",
+ "kotlinconf.com",
+ "kotlinlang.org",
+ "ktor.io",
+ "talkingkotlin.com",
+ ],
+ ["jpmorganchase.com", "jpmorgan.com", "chase.com"],
+ ["jobware.de", "jobware.com", "jobware.net"],
+ ["jotform.com", "jotfor.ms"],
+ [
+ "kayak.com",
+
+ "kayak.ae",
+ "kayak.cat",
+ "kayak.ch",
+ "kayak.cl",
+ "kayak.co.id",
+ "kayak.co.in",
+ "kayak.co.jp",
+ "kayak.co.kr",
+ "kayak.com.ar",
+ "kayak.com.au",
+ "kayak.com.br",
+ "kayak.com.co",
+ "kayak.com.hk",
+ "kayak.com.mx",
+ "kayak.com.my",
+ "kayak.com.pe",
+ "kayak.com.ph",
+ "kayak.com.tr",
+ "kayak.co.th",
+ "kayak.co.uk",
+ "kayak.de",
+ "kayak.dk",
+ "kayak.es",
+ "kayak.eu",
+ "kayak.fr",
+ "kayak.ie",
+ "kayak.it",
+ "kayak.nl",
+ "kayak.no",
+ "kayak.ph",
+ "kayak.pl",
+ "kayak.pt",
+ "kayak.qa",
+ "kayak.ru",
+ "kayak.se",
+ "kayak.sg",
+
+ "checkfelix.com",
+ "checkfelix.co.uk",
+ "checkfelix.es",
+ "checkfelix.fr",
+ "checkfelix.it",
+
+ "momondo.at",
+ "momondo.be",
+ "momondo.by",
+ "momondo.ca",
+ "momondo.ch",
+ "momondo.cl",
+ "momondo.com",
+ "momondo.com.ar",
+ "momondo.com.au",
+ "momondo.com.br",
+ "momondo.com.cn",
+ "momondo.com.co",
+ "momondo.com.pe",
+ "momondo.com.tr",
+ "momondo.co.nz",
+ "momondo.co.uk",
+ "momondo.co.za",
+ "momondo.cz",
+ "momondo.de",
+ "momondo.dk",
+ "momondo.ee",
+ "momondo.es",
+ "momondo.fi",
+ "momondo.fr",
+ "momondogroup.com",
+ "momondo.hk",
+ "momondo.ie",
+ "momondo.in",
+ "momondo.it",
+ "momondo.kz",
+ "momondo.lt",
+ "momondo.mx",
+ "momondo.net",
+ "momondo.nl",
+ "momondo.no",
+ "momondo.pl",
+ "momondo.pro",
+ "momondo.pt",
+ "momondo.ro",
+ "momondo.ru",
+ "momondo.se",
+ "momondo.tw",
+ "momondo.ua",
+
+ "mundi.com.br",
+
+ "speedfares.com",
+
+ "swoodoo.at",
+ "swoodoo.ch",
+ "swoodoo.com",
+
+ "r9cdn.net",
+ ],
+ ["kiwi.com", "skypicker.com"],
+ [
+ "kogan.com",
+
+ "dicksmith.com.au",
+ "dicksmith.co.nz",
+ "koganinternet.com.au",
+ "koganmobile.co.nz",
+ "kogansuper.com.au",
+ "kogantravel.com",
+ "mattblatt.com.au",
+ "tandy.com.au",
+ "zazz.com.au",
+ ],
+ ["linkedin.com", "licdn.com"],
+ ["livejournal.com", "livejournal.net", "lj-toys.com"],
+ ["lnk.to", "tix.to", "tck.to", "ticket.to", "linkfire.com", "assetlab.io", "linkfire.co", "lnkfi.re"],
+ [
+ "logmeininc.com",
+
+ "citrixonline.com",
+ "gotomeeting.com",
+ "gotomeet.me",
+ "gotomypc.com",
+ "gotostage.com",
+ "gotowebinar.com",
+ "logme.in",
+ "logmein.com",
+
+ "getgo.com",
+ ],
+ [
+ "loveholidays.com",
+ "loveholidays.be",
+ "loveholidays.dk",
+ "loveholidays.es",
+ "loveholidays.fi",
+ "loveholidays.fr",
+ "loveholidays.ie",
+ "loveholidays.nl",
+ "loveholidays.no",
+ "loveholidays.co.nz",
+ "loveholidays.pt",
+ "loveholidays.se",
+ "lovevacations.com",
+ ],
+ ["macys.com", "macysassets.com"],
+ [
+ "mafra.cz",
+
+ "idnes.cz",
+ "lidovky.cz",
+ "expres.cz",
+
+ "1gr.cz",
+ ],
+ [
+ "mail.ru",
+ "imgsmail.ru",
+
+ "ok.ru",
+ "mycdn.me",
+ "odnoklassniki.ru",
+ "oklive.app",
+ "ok.me",
+ "tamtam.chat",
+ "tt.me",
+
+ "vk.com",
+ "vk.me",
+ "vkontakte.ru",
+ ],
+ ["mandtbank.com", "mtb.com"],
+ ["mathletics.com", "mathletics.com.au", "mathletics.co.uk"],
+ ["mdsol.com", "imedidata.com"],
+ [
+ "mediamarktsaturn.com",
+
+ "mediamarkt.at",
+ "mediamarkt.be",
+ "mediamarkt.ch",
+ "mediamarkt.com.tr",
+ "mediamarkt.de",
+ "mediamarkt.es",
+ "mediamarkt.gr",
+ "mediamarkt.hu",
+ "mediamarkt.nl",
+ "mediamarkt.se",
+
+ "saturn.at",
+ "saturn.de",
+ "saturn.lu",
+
+ "redblue.de",
+
+ "mediamarkt.pl",
+ "redcoon.pl",
+ "saturn.pl",
+ "ms-online.pl",
+ ],
+ ["meetup.com", "meetupstatic.com"],
+ [
+ "mercadolibre.com",
+
+ "mercadolibre.cl",
+ "mercadolibre.co.cr",
+ "mercadolibre.com.ar",
+ "mercadolibre.com.bo",
+ "mercadolibre.com.co",
+ "mercadolibre.com.do",
+ "mercadolibre.com.ec",
+ "mercadolibre.com.gt",
+ "mercadolibre.com.hn",
+ "mercadolibre.com.mx",
+ "mercadolibre.com.ni",
+ "mercadolibre.com.pa",
+ "mercadolibre.com.pe",
+ "mercadolibre.com.py",
+ "mercadolibre.com.sv",
+ "mercadolibre.com.uy",
+ "mercadolibre.com.ve",
+ "mercadolivre.com",
+ "mercadolivre.com.br",
+
+ "mercadopago.com",
+ "mercadopago.com.ar",
+ "mercadopago.com.br",
+ "mercadopago.com.co",
+ "mercadopago.com.mx",
+
+ "mercadoshops.com",
+ "mercadoshops.cl",
+ "mercadoshops.com.ar",
+ "mercadoshops.com.br",
+ "mercadoshops.com.co",
+ "mercadoshops.com.mx",
+ "mercadoshops.com.ve",
+
+ "mercadoclics.com",
+ "mlstatic.com",
+ ],
+ [
+ "mercedes-benz.com",
+
+ "mercedes-benz-africa.com",
+ "mercedes-benz-asia.com",
+ "mercedes-benz.at",
+ "mercedes-benz.ba",
+ "mercedes-benz.be",
+ "mercedes-benz.bg",
+ "mercedes-benz.ca",
+ "mercedes-benz.ch",
+ "mercedes-benz.cl",
+ "mercedes-benz.co.id",
+ "mercedes-benz.co.in",
+ "mercedes-benz.co.jp",
+ "mercedes-benz.co.kr",
+ "mercedes-benz.com.ar",
+ "mercedes-benz.com.au",
+ "mercedes-benz.com.br",
+ "mercedes-benz.com.cn",
+ "mercedes-benz.com.co",
+ "mercedes-benz.com.cy",
+ "mercedes-benz.com.eg",
+ "mercedes-benz.com.gt",
+ "mercedes-benz.com.hk",
+ "mercedes-benz.com.lk",
+ "mercedes-benz.com.mt",
+ "mercedes-benz.com.mx",
+ "mercedes-benz.com.my",
+ "mercedes-benz.com.pe",
+ "mercedes-benz.com.ph",
+ "mercedes-benz.com.sg",
+ "mercedes-benz.com.tr",
+ "mercedes-benz.com.tt",
+ "mercedes-benz.com.tw",
+ "mercedes-benz.com.uy",
+ "mercedes-benz.com.vn",
+ "mercedes-benz.co.nz",
+ "mercedes-benz.co.th",
+ "mercedes-benz.co.uk",
+ "mercedes-benz.co.ve",
+ "mercedes-benz.co.za",
+ "mercedes-benz.cz",
+ "mercedes-benz.de",
+ "mercedes-benz.dk",
+ "mercedes-benz-eastern-europe.com",
+ "mercedes-benz.ee",
+ "mercedes-benz.es",
+ "mercedes-benz.fi",
+ "mercedes-benz.fr",
+ "mercedes-benz.gr",
+ "mercedes-benz.hr",
+ "mercedes-benz.hu",
+ "mercedes-benz.ie",
+ "mercedes-benz.is",
+ "mercedes-benz.it",
+ "mercedes-benz.li",
+ "mercedes-benz.lt",
+ "mercedes-benz.lu",
+ "mercedes-benz.lv",
+ "mercedes-benz-mena.com",
+ "mercedes-benz.nl",
+ "mercedes-benz.no",
+ "mercedes-benz-north-cyprus.com",
+ "mercedes-benz.pl",
+ "mercedes-benz.pt",
+ "mercedes-benz.ro",
+ "mercedes-benz.rs",
+ "mercedes-benz.ru",
+ "mercedes-benz.se",
+ "mercedes-benz.si",
+ "mercedes-benz.sk",
+ "mercedes-benz.ua",
+ ],
+ ["mi.com", "xiaomi.com"],
+ [
+ "microsoft.com",
+
+ "1drv.ms",
+ "aadrm.com",
+ "acompli.net",
+ "adbureau.net",
+ "adecn.com",
+ "aka.ms",
+ "aquantive.com",
+ "aspnetcdn.com",
+ "assets-yammer.com",
+ "azure.com",
+ "azureedge.net",
+ "azure.net",
+ "azurerms.com",
+ "bing.com",
+ "bing.net",
+ "cloudappsecurity.com",
+ "dynamics.com",
+ "gamesforwindows.com",
+ "getgamesmart.com",
+ "gfx.ms",
+ "healthvault.com",
+ "hockeyapp.net",
+ "hotmail.com",
+ "ieaddons.com",
+ "iegallery.com",
+ "live.com",
+ "live.net",
+ "lync.com",
+ "microsoftalumni.com",
+ "microsoftalumni.org",
+ "microsoftazuread-sso.com",
+ "microsoftedgeinsiders.com",
+ "microsoftonline.com",
+ "microsoftonline-p.com",
+ "microsoftonline-p.net",
+ "microsoftstore.com",
+ "microsoftstream.com",
+ "msads.net",
+ "msappproxy.net",
+ "msauthimages.net",
+ "msecnd.net",
+ "msedge.net",
+ "msftidentity.com",
+ "msft.net",
+ "msidentity.com",
+ "msn.com",
+ "msndirect.com",
+ "msocdn.com",
+ "netconversions.com",
+ "o365weve.com",
+ "oaspapps.com",
+ "office365.com",
+ "office.com",
+ "officelive.com",
+ "office.net",
+ "olsvc.com",
+ "onedrive.com",
+ "onenote.com",
+ "onenote.net",
+ "onestore.ms",
+ "onmicrosoft.com",
+ "outlook.com",
+ "outlookmobile.com",
+ "passport.net",
+ "phonefactor.net",
+ "powerapps.com",
+ "roiservice.com",
+ "sfbassets.com",
+ "sfx.ms",
+ "sharepoint.com",
+ "sharepoint-df.com",
+ "sharept.ms",
+ "skypeassets.com",
+ "skype.com",
+ "skypeforbusiness.com",
+ "s-microsoft.com",
+ "s-msn.com",
+ "staffhub.ms",
+ "svc.ms",
+ "sway-cdn.com",
+ "sway.com",
+ "sway-extensions.com",
+ "trafficmanager.net",
+ "virtualearth.net",
+ "visualstudio.com",
+ "vsallin.net",
+ "vsassets.io",
+ "windowsazure.com",
+ "windows.com",
+ "windows.net",
+ "windowsphone.com",
+ "worldwidetelescope.org",
+ "wunderlist.com",
+ "xbox.com",
+ "xboxlive.com",
+ "yammer.com",
+ "yammerusercontent.com",
+
+ "github.com",
+ "githubapp.com",
+ "githubassets.com",
+ "github.dev",
+
+ "avatars0.githubusercontent.com",
+ "avatars1.githubusercontent.com",
+ "avatars2.githubusercontent.com",
+ "avatars3.githubusercontent.com",
+ "camo.githubusercontent.com",
+ "cloud.githubusercontent.com",
+ "raw.githubusercontent.com",
+ ],
+ ["mobilism.org.in", "mobilism.org"],
+ ["morganstanley.com", "morganstanleyclientserv.com", "stockplanconnect.com", "ms.com"],
+ [
+ "morningstar.com",
+
+ "morningstar.at",
+ "morningstar.be",
+ "morningstarbr.com",
+ "morningstar.ca",
+ "morningstar.ch",
+ "morningstar.cl",
+ "morningstar.co.il",
+ "morningstar.com.mx",
+ "morningstar.co.uk",
+ "morningstar.de",
+ "morningstar.dk",
+ "morningstar.es",
+ "morningstar.fi",
+ "morningstar.fr",
+ "morningstarfunds.ie",
+ "morningstar.it",
+ "morningstar.nl",
+ "morningstar.no",
+ "morningstar.pt",
+ "morningstar.se",
+ "morningstarthailand.com",
+ ],
+ [
+ "mtv.fi",
+
+ "cmore.fi",
+ "lumijapyry.fi",
+ "luukku.com",
+ "mtvuutiset.fi",
+ "salatutelamat.fi",
+ "studio55.fi",
+ "suomiareena.fi",
+ ],
+ ["my-bookings.org", "my-bookings.cc"],
+ [
+ "myheritage.com",
+
+ "myheritageadn.be",
+ "myheritageadn.fr",
+ "myheritageadn.it",
+ "myheritageadn.pt",
+ "myheritage.am",
+ "myheritage.at",
+ "myheritage.be",
+ "myheritage.cat",
+ "myheritage.ch",
+ "myheritage.cn",
+ "myheritage.co.il",
+ "myheritage.co.in",
+ "myheritage.co.kr",
+ "myheritage.com.br",
+ "myheritage.com.hr",
+ "myheritage.com.pt",
+ "myheritage.com.tr",
+ "myheritage.com.ua",
+ "myheritage.cz",
+ "myheritage.de",
+ "myheritage.dk",
+ "myheritagedna.be",
+ "myheritagedna.com",
+ "myheritagedna.fr",
+ "myheritagedna.it",
+ "myheritagedna.pt",
+ "myheritage.ee",
+ "myheritage.es",
+ "myheritage.fi",
+ "myheritage.fr",
+ "myheritage.gr",
+ "myheritage.hu",
+ "myheritage.it",
+ "myheritage.jp",
+ "myheritagelibraryedition.com",
+ "myheritage.lt",
+ "myheritage.lv",
+ "myheritage.mk",
+ "myheritage.nl",
+ "myheritage.no",
+ "myheritage.pl",
+ "myheritage.pt",
+ "myheritage.ro",
+ "myheritage.rs",
+ "myheritage.se",
+ "myheritage.si",
+ "myheritage.sk",
+ "myheritage.tw",
+
+ "dnaquest.org",
+ "familygraph.com",
+ "familygraphql.com",
+ "familytreebuilder.com",
+ "tribalquest.org",
+
+ "mhcache.com",
+ "myheritage-container.com",
+ "myheritagefiles.com",
+ "myheritageimages.com",
+ ],
+ ["mymerrill.com", "ml.com", "merrilledge.com"],
+ ["mynortonaccount.com", "norton.com"],
+ ["mysmartedu.com", "mysmartabc.com"],
+ ["myuv.com", "uvvu.com"],
+ [
+ "naver.com",
+
+ "grafolio.com",
+ "plug.game",
+ "vlive.tv",
+ "webtoons.com",
+
+ "naver.net",
+ "pstatic.net",
+
+ "blog.jp",
+ "blogos.com",
+ "doorblog.jp",
+ "ldblog.jp",
+ "linecorp.com",
+ "line.me",
+ "livedoor.com",
+ "livedoor.jp",
+
+ "blogcms.jp",
+ "blogimg.jp",
+ "blogsys.jp",
+ "line-apps.com",
+ "line.biz",
+ "line-scdn.net",
+ "livedoor.net",
+ "naver.jp",
+ ],
+ [
+ "nbcnews.com",
+
+ "msnbc.com",
+ "today.com",
+
+ "newsvine.com",
+ "s-nbcnews.com",
+ ],
+ ["nefcuonline.com", "nefcu.com"],
+ [
+ "netease.com",
+
+ "126.com",
+ "126.net",
+ "127.net",
+ "163.com",
+
+ "icourse163.org",
+ "kada.com",
+ "kaola.com",
+ "kaola.com.hk",
+ ],
+ ["netflix.com", "nflxext.com", "nflximg.net", "nflxvideo.net"],
+ [
+ "nettix.fi",
+
+ "nettiauto.com",
+ "nettikaravaani.com",
+ "nettikone.com",
+ "nettimarkkina.com",
+ "nettimokki.com",
+ "nettimoto.com",
+ "nettivaraosa.com",
+ "nettivene.com",
+ "nettivuokraus.com",
+ ],
+ ["newegg.com", "neweggbusiness.com", "neweggimages.com", "newegg.ca"],
+ [
+ "newscorpaustralia.com",
+
+ "1degree.com.au",
+ "adelaidenow.com.au",
+ "api.news",
+ "bestrecipes.com.au",
+ "bodyandsoul.com.au",
+ "brisbanenews.com.au",
+ "cairnspost.com.au",
+ "couriermail.com.au",
+ "dailytelegraph.com.au",
+ "delicious.com.au",
+ "escape.com.au",
+ "foxsports.com.au",
+ "geelongadvertiser.com.au",
+ "goldcoastbulletin.com.au",
+ "gq.com.au",
+ "heraldsun.com.au",
+ "homelife.com.au",
+ "insideout.com.au",
+ "kidspot.com.au",
+ "nativeincolour.com.au",
+ "newsadds.com.au",
+ "newsapi.com.au",
+ "newscdn.com.au",
+ "news.com.au",
+ "news.net.au",
+ "newsprestigenetwork.com.au",
+ "newsxtend.com.au",
+ "nlm.io",
+ "ntnews.com.au",
+ "supercoach.com.au",
+ "taste.com.au",
+ "theaustralian.com.au",
+ "themercury.com.au",
+ "townsvillebulletin.com.au",
+ "vogue.com.au",
+ "weeklytimesnow.com.au",
+ "whereilive.com.au",
+ "whimn.com.au",
+ ],
+ [
+ "nintendo.com",
+ "nintendo.net",
+ "nintendo-europe.com",
+ "nintendonyc.com",
+
+ "nintendo.at",
+ "nintendo.be",
+ "nintendo.ch",
+ "nintendo.co.uk",
+ "nintendo.co.za",
+ "nintendo.de",
+ "nintendo.es",
+ "nintendo.eu",
+ "nintendo.fr",
+ "nintendo.it",
+ "nintendo.nl",
+ "nintendo.pt",
+ "nintendo.ru",
+
+ "animal-crossing.com",
+ "smashbros.com",
+ "zelda.com",
+ ],
+ ["norsk-tipping.no", "buypass.no"],
+ [
+ "npo.nl",
+
+ "2doc.nl",
+ "3fm.nl",
+ "avrotros.nl",
+ "bnnvara.nl",
+ "brainwash.nl",
+ "delagarde.nl",
+ "eo.nl",
+ "funx.nl",
+ "human.nl",
+ "jeugdjournaal.nl",
+ "joop.nl",
+ "kro-ncrv.nl",
+ "kro.nl",
+ "npo3fm.nl",
+ "npo3.nl",
+ "npoplus.nl",
+ "nporadio1.nl",
+ "nporadio2.nl",
+ "nporadio4.nl",
+ "nporadio5.nl",
+ "npostart.nl",
+ "ntr.nl",
+ "omroep.nl",
+ "powned.tv",
+ "publiekeomroep.nl",
+ "radio4.nl",
+ "schooltv.nl",
+ "vara.nl",
+ "vpro.nl",
+ "zappelin.nl",
+ "zapp.nl",
+ ],
+ ["nymag.com", "vulture.com", "grubstreet.com", "thecut.com"],
+ [
+ "nypublicradio.org",
+
+ "newsounds.org",
+ "radiolab.org",
+ "thegreenespace.org",
+ "wnycstudios.org",
+ "wqxr.org",
+
+ "wnyc.org",
+ ],
+ ["nytimes.com", "newyorktimes.com", "thewirecutter.com", "nyt.com"],
+ ["nyu.edu", "nyupress.org"],
+ [
+ "nvidia.com",
+
+ "nvidia.at",
+ "nvidia.be",
+ "nvidia.ch",
+ "nvidia.cn",
+ "nvidia.co.at",
+ "nvidia.co.in",
+ "nvidia.co.jp",
+ "nvidia.co.kr",
+ "nvidia.com.au",
+ "nvidia.com.br",
+ "nvidia.com.mx",
+ "nvidia.com.pe",
+ "nvidia.com.pl",
+ "nvidia.com.tr",
+ "nvidia.com.tw",
+ "nvidia.com.ua",
+ "nvidia.com.ve",
+ "nvidia.co.uk",
+ "nvidia.cz",
+ "nvidia.de",
+ "nvidia.dk",
+ "nvidia.es",
+ "nvidia.eu",
+ "nvidia.fi",
+ "nvidia.fr",
+ "nvidia.in",
+ "nvidia.it",
+ "nvidia.jp",
+ "nvidia.lu",
+ "nvidia.mx",
+ "nvidia.nl",
+ "nvidia.no",
+ "nvidia.pl",
+ "nvidia.ro",
+ "nvidia.ru",
+ "nvidia.se",
+ "nvidia.tw",
+
+ "nvidiagrid.net",
+ "nvidia.partners",
+
+ "geforce.com",
+ "geforcenow.com",
+ "gputechconf.com",
+
+ "geforce.cn",
+ "geforce.com.tw",
+ "geforce.co.uk",
+ ],
+ ["onlineatnsb.com", "norwaysavingsbank.com"],
+ ["openstreetmap.org", "osmfoundation.org"],
+ [
+ "oracle.com",
+
+ "ateam-oracle.com",
+ "java.com",
+ "mysql.com",
+
+ "oracleimg.com",
+ ],
+ ["orange.fr", "sosh.fr", "woopic.com"],
+ [
+ "osf.io",
+
+ "agrixiv.org",
+ "arabixiv.org",
+ "eartharxiv.org",
+ "ecsarxiv.org",
+ "engrxiv.org",
+ "frenxiv.org",
+ "marxiv.org",
+ "mindrxiv.org",
+ "paleorxiv.org",
+ "psyarxiv.com",
+ "thesiscommons.org"
+ ],
+ ["osu.edu", "osumc.edu", "ohio-state.edu"],
+ [
+ "ovh.com",
+
+ "kimsufi.com",
+ "ovhcloud.com",
+ "ovhtelecom.fr",
+ "soyoustart.com",
+
+ "ovh.com.au",
+ "ovh.co.uk",
+ "ovh.cz",
+ "ovh.de",
+ "ovh.es",
+ "ovh-hosting.fi",
+ "ovh.ie",
+ "ovh.it",
+ "ovh.lt",
+ "ovh.nl",
+ "ovh.pl",
+ "ovh.pt",
+ "ovh.sn",
+
+ "ovh.net",
+ ],
+ ["paypal.com", "paypal-search.com", "paypalobjects.com"],
+ ["pcworld.com", "staticworld.net", "idg.com", "idg.net", "infoworld.com", "macworld.com", "techhive.com", "idg.tv"],
+ [
+ "pearson.com",
+
+ "connexus.com",
+ "ecollege.com",
+ "english.com",
+ "masteringchemistry.com",
+ "masteringengineering.com",
+ "masteringgeography.com",
+ "masteringhealthandnutrition.com",
+ "masteringphysics.com",
+ "mathxl.com",
+ "mathxlforschool.com",
+ "mypearson.com",
+ "pearsonassessments.com",
+ "pearsoned.com",
+ "pearsonelt.com",
+ "pearsonhighered.com",
+ "pearsonmylabandmastering.com",
+
+ "pearsoncmg.com",
+ ],
+ ["pepco.com", "pepcoholdings.com"],
+ ["philips.com", "philips.nl"],
+ [
+ "pinterest.com",
+
+ "pinterest.at",
+ "pinterest.be",
+ "pinterest.ca",
+ "pinterest.ch",
+ "pinterest.cl",
+ "pinterest.co",
+ "pinterest.co.at",
+ "pinterest.co.in",
+ "pinterest.co.kr",
+ "pinterest.com.au",
+ "pinterest.com.bo",
+ "pinterest.com.ec",
+ "pinterest.com.mx",
+ "pinterest.com.pe",
+ "pinterest.com.py",
+ "pinterest.com.uy",
+ "pinterest.com.vn",
+ "pinterest.co.nz",
+ "pinterest.co.uk",
+ "pinterest.de",
+ "pinterest.dk",
+ "pinterest.ec",
+ "pinterest.engineering",
+ "pinterest.es",
+ "pinterest.fr",
+ "pinterest.hu",
+ "pinterest.id",
+ "pinterest.ie",
+ "pinterest.in",
+ "pinterest.info",
+ "pinterest.it",
+ "pinterest.jp",
+ "pinterest.kr",
+ "pinterestmail.com",
+ "pinterest.mx",
+ "pinterest.nz",
+ "pinterest.pe",
+ "pinterest.ph",
+ "pinterest.pt",
+ "pinterest.ru",
+ "pinterest.se",
+ "pinterest.th",
+ "pinterest.tw",
+ "pinterest.uk",
+ "pinterest.vn",
+
+ "pinimg.com",
+ "pin.it",
+ ],
+ ["plex.tv", "plex.direct"],
+ ["pokemon-gl.com", "pokemon.com"],
+ ["pornhub.com", "phncdn.com"],
+ ["postepay.it", "poste.it"],
+ ["postimees.ee", "city24.ee", "city24.lv", "pmo.ee"],
+ [
+ "pricerunner.com",
+
+ "pricerunner.co.uk",
+ "pricerunner.de",
+ "pricerunner.dk",
+ "pricerunner.net",
+ "pricerunner.se",
+ "pricerunner.uk",
+ ],
+ [
+ "prosiebensat1.de",
+ "prosiebensat1.com",
+
+ "atv.at",
+ "atv2.at",
+ "galileo.tv",
+ "kabeleins.at",
+ "kabeleins.ch",
+ "kabeleins.de",
+ "kabeleinsdoku.at",
+ "kabeleinsdoku.ch",
+ "kabeleinsdoku.de",
+ "prosieben.at",
+ "prosieben.ch",
+ "prosieben.de",
+ "prosiebenmaxx.at",
+ "prosiebenmaxx.ch",
+ "prosiebenmaxx.de",
+ "puls24.at",
+ "puls4.com",
+ "puls8.ch",
+ "ran.de",
+ "sat1.at",
+ "sat1.ch",
+ "sat1.de",
+ "sat1gold.at",
+ "sat1gold.ch",
+ "sat1gold.de",
+ "sixx.at",
+ "sixx.ch",
+ "sixx.de",
+ "the-voice-of-germany.at",
+ "the-voice-of-germany.ch",
+ "the-voice-of-germany.de",
+ "zappn.tv",
+
+ "p7s1.io",
+ ],
+ [
+ "qantas.com",
+
+ "jetstar.com",
+ "qantas.com.au",
+ "qantascourier.com.au",
+ "qantasfutureplanet.com.au",
+ "qantasgrouptravel.com",
+ "qfcrew.com",
+ "qfflightcrew.com",
+
+ "aquire.com.au",
+ "qantasassure.com",
+ "qantasbusinessrewards.com",
+ "qantasbusinessrewards.com.au",
+ "qantasepiqure.com",
+ "qantasepiqure.com.au",
+ "qantasgolfclub.com",
+ "qantasgolfclub.com.au",
+ "qantasloyalty.com",
+ "qantasloyalty.net",
+ "qantasmall.com",
+ "qantasmall.com.au",
+ "qantasmall.co.nz",
+ "qantaspoints.com",
+ "qantaspoints.com.au",
+ "qantasshopping.com",
+ "qantasshopping.com.au",
+ "qantasshopping.co.nz",
+ "qantasstore.com.au",
+ "qantasstore.co.nz",
+ "redplanetgroup.com.au",
+ "redplanetportal.com.au",
+
+ "qantascash.com",
+ "qantascash.com.au",
+ "qantasmoney.com",
+ "qantastravelmoney.com",
+ ],
+ [
+ "qq.com",
+
+ "aitangyou.com",
+ "cdntips.com",
+ "dnspod.cn",
+ "extqq.com",
+ "gdtimg.com",
+ "gtimg.cn",
+ "gtimg.com",
+ "idqqimg.com",
+ "imqq.com",
+ "myapp.com",
+ "myqcloud.com",
+ "qcloud.com",
+ "qpic.cn",
+ "qqmail.com",
+ "qzone.com",
+ "tencent.com",
+ "tenpay.com",
+ "ugdtimg.com",
+ "url.cn",
+ "wechat.com",
+ "wegame.com",
+ "weiyun.com",
+ ],
+ [
+ "rai.it",
+
+ "comunitaitalofona.org",
+ "raicinema.it",
+ "raicultura.it",
+ "raimemo.it",
+ "rainews24.it",
+ "rainews.it",
+ "raiplay.it",
+ "raiplayradio.it",
+ "raiplayyoyo.it",
+ "raipubblicita.it",
+ "raisport.it",
+ "raitalia.it",
+ "rai.tv",
+ "raiway.it",
+ ],
+ ["railnation.ru", "railnation.de", "rail-nation.com", "railnation.gr", "railnation.us", "trucknation.de", "traviangames.com"],
+ ["rakuten.com", "buy.com"],
+ [
+ "realestate.com.au",
+
+ "property.com.au",
+ "realcommercial.com.au",
+ "spacely.com.au",
+
+ "reastatic.net",
+ ],
+ ["reddit.com", "redditmedia.com", "redditstatic.com", "redd.it", "redditenhancementsuite.com", "reddituploads.com", "imgur.com"],
+ ["redhat.com", "openshift.com", "openshift.org", "okd.io"],
+ [
+ "reebok.at",
+ "reebok.be",
+ "reebok.ca",
+ "reebok.ch",
+ "reebok.cl",
+ "reebok.co",
+ "reebok.com",
+ "reebok.com.ar",
+ "reebok.com.br",
+ "reebok.com.tr",
+ "reebok.co.uk",
+ "reebok.cz",
+ "reebok.de",
+ "reebok.dk",
+ "reebok.es",
+ "reebok.fi",
+ "reebok.fr",
+ "reebok.ie",
+ "reebok.it",
+ "reebok.mx",
+ "reebok.nl",
+ "reebok.pe",
+ "reebok.pl",
+ "reebok.ru",
+ "reebok.se",
+ "reebok.sk",
+ ],
+ [
+ "reuters.com",
+ "reuters.tv",
+ "reutersmedia.net",
+ "thomsonreuters.com",
+
+ "reutersagency.cn",
+
+ "thomsonreuters.ca",
+ "thomsonreuters.cn",
+ "thomsonreuters.co.jp",
+ "thomsonreuters.co.kr",
+ "thomsonreuters.com.ar",
+ "thomsonreuters.com.au",
+ "thomsonreuters.com.br",
+ "thomsonreuters.com.hk",
+ "thomsonreuters.com.my",
+ "thomsonreuters.com.pe",
+ "thomsonreuters.com.sg",
+ "thomsonreuters.com.tr",
+ "thomsonreuters.co.uk",
+ "thomsonreuters.es",
+ "thomsonreuters.in",
+ "thomsonreuters.ru",
+ ],
+ [
+ "riotgames.com",
+
+ "leagueoflegends.com",
+ "lolesports.com",
+ "lolstatic.com",
+ "lolusercontent.com",
+
+ "playruneterra.com",
+
+ "riotcdn.net",
+ "rdatasrv.net",
+ ],
+ [
+ "rtl.nl",
+
+ "bright.nl",
+ "buienradar.nl",
+ "healthyfest.nl",
+ "rtlboulevard.nl",
+ "rtllatenight.nl",
+ "rtlnieuws.nl",
+ "rtlxl.nl",
+ "rtlz.nl",
+ "videoland.com",
+ "vtbl.nl",
+ ],
+ [
+ "s-kanava.fi",
+
+ "abcasemat.fi",
+ "raflaamo.fi",
+ "s-mobiili.fi",
+ "sokoshotels.fi",
+ "yhteishyva.fi",
+
+ "sok.fi",
+ "s-palvelut.fi",
+ ],
+ [
+ "salesforce.com",
+
+ "documentforce.com",
+ "einstein.com",
+ "force.com",
+ "pardot.com",
+ "salesforceliveagent.com",
+ "visualforce.com",
+ ],
+ ["sanguosha.com", "bianfeng.com"],
+ ["schwab.com", "schwabplan.com"],
+ ["scmp.com", "i-scmp.com"],
+ ["sears.com", "shld.net"],
+ [
+ "seznam.cz",
+
+ "firmy.cz",
+ "garaz.cz",
+ "kupi.cz",
+ "lide.cz",
+ "mapy.cz",
+ "novinky.cz",
+ "prozeny.cz",
+ "sauto.cz",
+ "sbazar.cz",
+ "sdovolena.cz",
+ "seznamzpravy.cz",
+ "sport.cz",
+ "sreality.cz",
+ "stream.cz",
+ "super.cz",
+ "sweb.cz",
+ "televizeseznam.cz",
+ "volnamista.cz",
+ "zbozi.cz",
+
+ "szn.cz",
+ ],
+ [
+ "shopify.com",
+ "myshopify.com",
+ "shopifycdn.com",
+ "shopifyapps.com",
+ "shopifycloud.com",
+ "shopifyadmin.com",
+ "shopifypreview.com",
+ ],
+ ["siriusxm.com", "sirius.com"],
+ ["skygo.co.nz", "skytv.co.nz"],
+ ["skysports.com", "skybet.com", "skyvegas.com"],
+ ["slashdot.org", "sourceforge.net", "fsdn.com"],
+ ["slickdeals.net", "slickdealscdn.com"],
+ [
+ "smh.com.au",
+
+ "afr.com",
+ "brisbanetimes.com.au",
+ "canberratimes.com.au",
+ "fairfaxmedia.com.au",
+ "theage.com.au",
+ "watoday.com.au",
+
+ "ffx.io",
+ ],
+ ["snapfish.com", "snapfish.ca"],
+ [
+ "sony.com",
+
+ "sonyentertainmentnetwork.com",
+ "sonyrewards.com",
+
+ "playstation.com",
+ "playstation.net",
+
+ "sony-africa.com",
+ "sony-asia.com",
+ "sony.at",
+ "sony.ba",
+ "sony.be",
+ "sony.bg",
+ "sony.ca",
+ "sony.ch",
+ "sony.cl",
+ "sony.co.cr",
+ "sony.co.id",
+ "sony.co.in",
+ "sony.co.kr",
+ "sony.com.ar",
+ "sony.com.au",
+ "sony.com.bo",
+ "sony.com.br",
+ "sony.com.co",
+ "sony.com.do",
+ "sony.com.ec",
+ "sony.com.gt",
+ "sony.com.hk",
+ "sony.com.hn",
+ "sony.com.mk",
+ "sony.com.mx",
+ "sony.com.my",
+ "sony.com.ni",
+ "sony.com.pa",
+ "sony.com.pe",
+ "sony.com.ph",
+ "sony.com.sg",
+ "sony.com.sv",
+ "sony.com.tr",
+ "sony.com.tw",
+ "sony.com.vn",
+ "sony.co.nz",
+ "sony.co.th",
+ "sony.co.uk",
+ "sony.cz",
+ "sony.de",
+ "sony.dk",
+ "sony.ee",
+ "sony.es",
+ "sony.eu",
+ "sony-europe.com",
+ "sony.fi",
+ "sony.fr",
+ "sony.gr",
+ "sony.hr",
+ "sony.hu",
+ "sony.ie",
+ "sony.it",
+ "sony.kz",
+ "sony-latin.com",
+ "sonylatvija.com",
+ "sony.lt",
+ "sony.lu",
+ "sony.lv",
+ "sony-mea.com",
+ "sony.nl",
+ "sony.no",
+ "sony.pl",
+ "sony-promotion.eu",
+ "sony.pt",
+ "sony.ro",
+ "sony.rs",
+ "sony.ru",
+ "sony.se",
+ "sony.si",
+ "sony.sk",
+ "sony.ua",
+
+ "sony.net",
+ ],
+ ["soundcloud.com", "sndcdn.com"],
+ ["soundcu.com", "netteller.com"],
+ ["southerncompany.com", "southernco.com"],
+ ["southparkstudios.com", "cc.com", "comedycentral.com"],
+ ["spiceworks.com", "spiceworksstatic.com"],
+ [
+ "spotify.com",
+
+ "scdn.co",
+ "spotifyforbrands.com",
+ "spotifyforartists.com",
+ "spotify.net",
+ ],
+ [
+ "springernature.com",
+
+ "adis.com",
+ "apress.com",
+ "biomedcentral.com",
+ "bsl.nl",
+ "dgim-eakademie.de",
+ "kardiologie.org",
+ "macmillaneducation.com",
+ "macmillanexplorers.com",
+ "medengine.com",
+ "medicinematters.com",
+ "medicinematters.in",
+ "medwirenews.com",
+ "metzlerverlag.de",
+ "nature.com",
+ "natureindex.com",
+ "palgrave.com",
+ "scientificamerican.com",
+ "springer.com",
+ "springeraesthetik.de",
+ "springerhealthcare.com",
+ "springermedizin.at",
+ "springermedizin.de",
+ "springeropen.com",
+ "springerpflege.de",
+ "springerprofessional.de",
+ ],
+ ["sprint.com", "sprintpcs.com", "nextel.com"],
+ ["squareup.com", "cash.app", "mkt.com", "squarecdn.com"],
+ ["steampowered.com", "steamstatic.com", "steamcommunity.com"],
+ ["suning.com", "suning.cn", "hksuning.com"],
+ ["target.com", "targetimg1.com"],
+ ["techdata.com", "techdata.ch"],
+ ["telegram.org", "telegram.me", "t.me"],
+ ["telekom.com", "t-online.de"],
+ ["tesla.com", "teslamotors.com"],
+ [
+ "toyota.com",
+
+ "lexus.com",
+
+ "toyota.am",
+ "toyota.at",
+ "toyota.az",
+ "toyota.ba",
+ "toyota.be",
+ "toyota.bg",
+ "toyota-canarias.es",
+ "toyotacg.me",
+ "toyota.ch",
+ "toyota.co.il",
+ "toyota.com.cy",
+ "toyota.com.mk",
+ "toyota.com.mt",
+ "toyota.com.tr",
+ "toyota.co.uk",
+ "toyota.cz",
+ "toyota.de",
+ "toyota.dk",
+ "toyota.ee",
+ "toyota.es",
+ "toyota.fi",
+ "toyota.fr",
+ "toyota.ge",
+ "toyota-gib.com",
+ "toyota.gr",
+ "toyota.hr",
+ "toyota.hu",
+ "toyota.ie",
+ "toyota.is",
+ "toyota.it",
+ "toyota-kosovo.com",
+ "toyota.kz",
+ "toyota.lt",
+ "toyota.lu",
+ "toyota.lv",
+ "toyota.md",
+ "toyota.nl",
+ "toyota.no",
+ "toyota.pl",
+ "toyota.pt",
+ "toyota.ro",
+ "toyota.rs",
+ "toyota.ru",
+ "toyota.se",
+ "toyota.si",
+ "toyota.sk",
+ "toyota.ua",
+
+ "toyota-europe.com",
+ ],
+ [
+ "tripadvisor.com",
+
+ "tripadvisor.at",
+ "tripadvisor.be",
+ "tripadvisor.ca",
+ "tripadvisor.ch",
+ "tripadvisor.co.hu",
+ "tripadvisor.co.id",
+ "tripadvisor.com.ar",
+ "tripadvisor.com.au",
+ "tripadvisor.com.br",
+ "tripadvisor.com.gr",
+ "tripadvisor.com.hk",
+ "tripadvisor.com.mx",
+ "tripadvisor.com.my",
+ "tripadvisor.com.pe",
+ "tripadvisor.com.ph",
+ "tripadvisor.com.sg",
+ "tripadvisor.com.tr",
+ "tripadvisor.com.tw",
+ "tripadvisor.co.nz",
+ "tripadvisor.co.uk",
+ "tripadvisor.co.za",
+ "tripadvisor.de",
+ "tripadvisor.dk",
+ "tripadvisor.es",
+ "tripadvisor.fi",
+ "tripadvisor.fr",
+ "tripadvisor.ie",
+ "tripadvisor.in",
+ "tripadvisor.it",
+ "tripadvisor.jp",
+ "tripadvisor.nl",
+ "tripadvisor.pt",
+ "tripadvisor.ru",
+ "tripadvisor.se",
+ "tripadvisor.sk",
+
+ "seatguru.com",
+
+ "tacdn.com",
+ "tamgrt.com",
+ ],
+ [
+ "trivago.com",
+
+ "trivago.ae",
+ "trivago.at",
+ "trivago.be",
+ "trivago.bg",
+ "trivago.ca",
+ "trivago.ch",
+ "trivago.cl",
+ "trivago.co.id",
+ "trivago.co.il",
+ "trivago.co.kr",
+ "trivago.com.ar",
+ "trivago.com.au",
+ "trivago.com.br",
+ "trivago.com.co",
+ "trivago.com.ec",
+ "trivago.com.mx",
+ "trivago.com.my",
+ "trivago.com.ph",
+ "trivago.com.tr",
+ "trivago.com.tw",
+ "trivago.com.uy",
+ "trivago.co.nz",
+ "trivago.co.th",
+ "trivago.co.uk",
+ "trivago.co.za",
+ "trivago.cz",
+ "trivago.dk",
+ "trivago.es",
+ "trivago.fi",
+ "trivago.fr",
+ "trivago.gr",
+ "trivago.hk",
+ "trivago.hr",
+ "trivago.hu",
+ "trivago.ie",
+ "trivago.in",
+ "trivago.it",
+ "trivago.jp",
+ "trivago.nl",
+ "trivago.no",
+ "trivago.pe",
+ "trivago.pl",
+ "trivago.pt",
+ "trivago.ro",
+ "trivago.rs",
+ "trivago.ru",
+ "trivago.se",
+ "trivago.sg",
+ "trivago.si",
+ "trivago.sk",
+ "trivago.vn",
+ "youzhan.com",
+ ],
+ ["trsretire.com", "divinvest.com"],
+ ["turbotax.com", "intuit.com"],
+ [
+ "tvn.pl",
+
+ "player.pl",
+ "tvn24bis.pl",
+ "tvn24.pl",
+
+ "cdntvn.pl",
+ ],
+ ["tvp.pl", "tvp.info"],
+ ["twitter.com", "twimg.com", "t.co", "periscope.tv", "pscp.tv"],
+ ["ua2go.com", "ual.com", "united.com", "unitedwifi.com"],
+ ["ubisoft.com", "ubi.com", "anno-union.com", "thesettlers-alliance.com"],
+ ["ui.com", "ubnt.com"],
+ [
+ "unitedhealthgroup.com",
+
+ "myprotectwell.com",
+ "protectwellapp.com",
+ "protectwell.org",
+ "uhg.com",
+ "unitedhealthgroup.net",
+ "unitedhealthgroup.org",
+ "weprotectwell.com",
+
+ "healthyourway.com",
+ "healthyourwaynow.com",
+ "joinatyourbest.com",
+ "mypersonalizedsupport.com",
+ "myrenewactive.com",
+ "mywellbeingsolution.com",
+ "optummessenger.co",
+ "personalhealthmessagecenter.com",
+ "phs.com",
+ "pwrfitness.com",
+ "takechargeatwork.com",
+ "wellnesscoachingnow.com",
+
+ "aarpmedicareplans.com",
+ "careimprovementplus.com",
+ "health4me.com",
+ "healthsafe-id.com",
+ "myaarpmedicare.com",
+ "myaarpmedicareplans.com",
+ "myaarprenew.com",
+ "myaarprenewma.com",
+ "myaarprenewmapd.com",
+ "myaarprenewpdp.com",
+ "myaarpsupplementalhealthinsurance.com",
+ "mymedicamedicare.com",
+ "mymedicareaccount.com",
+ "mypcpmedicare.com",
+ "myuhc.com",
+ "myuhcdental.com",
+ "myuhcmedicare.com",
+ "uhc.com",
+ "uhcmedicaresolutions.com",
+ "uhcmycarepath.com",
+ "uhcretiree.com",
+ "uhcservices.com",
+ "yourdentalplan.com",
+
+ "werally.com",
+
+ "liveandworkwell.com",
+ "myoptum.com",
+ "optum.com",
+ "optumrx.com",
+ "ppconline.info",
+ "ppconlineinfo.com",
+ "wellbeing-4life.com",
+ ],
+ ["vanguard.com", "investornews.vanguard", "vanguardblog.com", "vanguardcanada.ca", "vanguardinvestor.co.uk", "vgcontent.info"],
+ [
+ "verizonmedia.com",
+
+ "verizon.com",
+ "verizon.net",
+ "verizonwireless.com",
+ "vzw.com",
+
+ "aol.com",
+ "autoblog.com",
+ "engadget.com",
+ "oath.com",
+ "overture.com",
+ "techcrunch.com",
+ "yahoo.com",
+
+ "huffpost.com",
+ "huffingtonpost.ca",
+ "huffingtonpost.com",
+ "huffingtonpost.com.au",
+ "huffingtonpost.com.mx",
+ "huffingtonpost.co.uk",
+ "huffingtonpost.co.za",
+ "huffingtonpost.de",
+ "huffingtonpost.es",
+ "huffingtonpost.fr",
+ "huffingtonpost.gr",
+ "huffingtonpost.in",
+ "huffingtonpost.it",
+ "huffingtonpost.jp",
+ "huffingtonpost.kr",
+ "huffpostarabi.com",
+ "huffpostbrasil.com",
+ "huffpostmaghreb.com",
+
+ "yahooapis.com",
+ "yimg.com",
+ ],
+ ["vimeo.com", "vimeocdn.com"],
+ [
+ "vinted.com",
+
+ "kleiderkreisel.de",
+ "mamikreisel.de",
+
+ "vinted.co.uk",
+ "vinted.cz",
+ "vinted.es",
+ "vinted.fr",
+ "vinted.lt",
+ "vinted.nl",
+ "vinted.pl",
+ ],
+ ["volvooceanrace.com", "virtualregatta.com"],
+ ["vonage.com", "vonagebusiness.com"],
+ [
+ "vrt.be",
+
+ "canvas.be",
+ "een.be",
+ "ketnet.be",
+ "klara.be",
+ "mnm.be",
+ "radio1.be",
+ "radio2.be",
+ "sporza.be",
+ "stubru.be",
+ ],
+ ["wa.gov", "wsdot.com", "wsdot.gov"],
+ ["walmart.com", "wal.co", "walmartimages.com", "walmart.ca"],
+ [
+ "thewaltdisneycompany.com",
+
+ "6abc.com",
+ "abc7.com",
+ "abc7ny.com",
+ "abc.com",
+ "abcnews.com",
+
+ "go.com",
+
+ "espn.com",
+ "espncdn.com",
+
+ "espn.com.au",
+ "espn.com.br",
+ "espn.co.uk",
+
+ "espncricinfo.com",
+
+ "espnfc.com",
+ "espnfc.us",
+
+ "fivethirtyeight.com",
+
+ "babble.com",
+ "dadt.com",
+ "disneybaby.com",
+ "disneyinteractive.com",
+ "disneyinternationalhd.com",
+ "disneymoviesanywhere.com",
+ "disneyplus.com",
+ "ilm.com",
+ "marvel.com",
+ "readriordan.com",
+ "skysound.com",
+ "starwars.com",
+
+ "disney.asia",
+ "disney.be",
+ "disney.bg",
+ "disney.co.il",
+ "disney.com",
+ "disney.com.au",
+ "disney.com.br",
+ "disney.com.hk",
+ "disney.com.tw",
+ "disney.co.th",
+ "disney.co.uk",
+ "disney.co.za",
+ "disney.cz",
+ "disney.de",
+ "disney.dk",
+ "disney.es",
+ "disney.fi",
+ "disney.fr",
+ "disney.gr",
+ "disney.hu",
+ "disney.id",
+ "disney.in",
+ "disney.it",
+ "disneylatino.com",
+ "disneyme.com",
+ "disney.my",
+ "disney.nl",
+ "disney.no",
+ "disney.ph",
+ "disney.pl",
+ "disney.pt",
+ "disney.ro",
+ "disney.se",
+ "disney.sg",
+ "disneyturkiye.com.tr",
+
+ "dilcdn.com",
+ "disney.io",
+ ],
+ [
+ "wargaming.com",
+ "wargaming.net",
+ "worldoftanks.asia",
+ "worldoftanks.com",
+ "worldoftanks.eu",
+ "worldoftanks.kr",
+ "worldoftanks.ru",
+ "worldofwarplanes.com",
+ "worldofwarplanes.eu",
+ "worldofwarplanes.ru",
+ "worldofwarships.com",
+ "worldofwarships.eu",
+ "worldofwarships.ru",
+ "wotblitz.com",
+ ],
+ [
+ "warnermediagroup.com",
+
+ "adultswim.com",
+ "adventuretime.com",
+ "atgamewiz.com",
+ "ben10.com",
+ "bleacherreport.com",
+ "bleacherreportlive.com",
+ "br.live",
+ "brlive.com",
+ "brlive.io",
+ "cartoonnetwork.asia",
+ "cartoonnetworkasia.com",
+ "cartoonnetwork.com",
+ "cartoonnetworkhotel.com",
+ "cartoonnetworkpr.com",
+ "catchsports.com",
+ "chasingthecurelive.com",
+ "cnn.com",
+ "cnn.io",
+ "cnnmoney.ch",
+ "cnn.net",
+ "d2c-ott.com",
+ "d-league.com",
+ "e-league.com",
+ "eleague.com",
+ "filmstruck.com",
+ "greatbig.com",
+ "greatbigstory.com",
+ "hbo.com",
+ "hbogo.com",
+ "hbomax.com",
+ "hbonow.com",
+ "heaveninc.com",
+ "hlntv.com",
+ "iamthenight.com",
+ "juniorrydercup.com",
+ "maxgo.com",
+ "nba.com",
+ "nba.net",
+ "ncaa.com",
+ "ngtv.io",
+ "penis-map.com",
+ "pgachampionship.com",
+ "pga.com",
+ "pga-events.com",
+ "pga.net",
+ "powerpuffgirls.com",
+ "powerpufftheworld.com",
+ "robotunicornattack.com",
+ "rydercup.com",
+ "samanthabee.com",
+ "sambee.com",
+ "shaqtoons.com",
+ "stevenuniverseselfesteem.com",
+ "stevenuniversethemovie.com",
+ "summercampisland.com",
+ "superstation.com",
+ "suspensecollection.com",
+ "tbs.com",
+ "tcm.com",
+ "teamcococdn.com",
+ "thealienist.com",
+ "thesuspensecollection.com",
+ "ti-platform.com",
+ "tntdrama.com",
+ "tnt.tv",
+ "trutv.com",
+ "vgtf.net",
+ "warnermediacdn.com",
+ "warnermediafitnation.com",
+ "warnermediaready.com",
+ "warnermediasupplierdiversity.com",
+ "warnermediaupfront.com",
+ "wbtvd.com",
+ "webarebears.com",
+ "wnba.com",
+ "yzzerdd.com",
+
+ "turner.com",
+ "ugdturner.com",
+ ],
+ [
+ "weather.com",
+ "wunderground.com",
+
+ "imwx.com",
+ "wfxtriggers.com",
+ "wsi.com",
+ "w-x.co",
+ "wxug.com",
+ ],
+ [
+ "webmd.com",
+
+ "emedicinehealth.com",
+ "medicinenet.com",
+ "medscape.com",
+ "medscape.org",
+ "onhealth.com",
+ "rxlist.com",
+
+ "medscapestatic.com",
+ ],
+ ["weebly.com", "editmysite.com"],
+ [
+ "weibo.com",
+
+ "sina.cn",
+ "sina.com",
+ "sina.com.cn",
+ "sinaedge.com",
+ "sinaimg.cn",
+ "sinaimg.com",
+ "sinaimg.com.cn",
+ "sinajs.cn",
+ "sina.net",
+ "wbimg.cn",
+ "wbimg.com",
+ "wcdn.cn",
+ "weibocdn.com",
+ "weibo.cn",
+ "weibopay.com",
+ ],
+ ["wellsfargo.com", "wf.com"],
+ ["wetter.com", "tiempo.es", "wettercomassets.com"],
+ ["wikipedia.org", "wikimedia.org", "wikimediafoundation.org", "wiktionary.org",
+ "wikiquote.org", "wikibooks.org", "wikisource.org", "wikinews.org",
+ "wikiversity.org", "mediawiki.org", "wikidata.org", "wikivoyage.org",
+ "wmfusercontent.org", "tools.wmflabs.org"],
+ ["wisconsin.gov", "wi.gov"],
+ ["wix.com", "wixapps.net", "wixstatic.com", "parastorage.com"],
+ ["wordpress.com", "wp.com"],
+ [
+ "wp.pl",
+
+ "abczdrowie.pl",
+ "allani.pl",
+ "autokult.pl",
+ "dobreprogramy.pl",
+ "domodi.pl",
+ "eholiday.pl",
+ "finansowysupermarket.pl",
+ "fotoblogia.pl",
+ "gadzetomania.pl",
+ "homebook.pl",
+ "jedenwniosek.pl",
+ "komorkomania.pl",
+ "money.pl",
+ "nocowanie.pl",
+ "o2.pl",
+ "open.fm",
+ "parenting.pl",
+ "pudelek.pl",
+ "pudelek.tv",
+ "totalmoney.pl",
+ "wakacje.pl",
+ "wawalove.pl",
+ "wp.tv",
+
+ "wpcdn.pl",
+ "wpimg.pl",
+ ],
+ ["wpcu.coop", "wpcuonline.com"],
+ ["wsj.com", "wsj.net", "barrons.com", "dowjones.com", "dowjoneson.com", "mansionglobal.com", "marketwatch.com"],
+ ["xda-developers.com", "xda-cdn.com"],
+ ["xfinity.com", "comcast.net", "comcast.com"],
+ ["xhamster.com", "xhcdn.com"],
+ ["yahoo.co.jp", "yimg.jp"],
+ [
+ "yandex.com",
+
+ "auto.ru",
+ "beru.ru",
+ "bringly.ru",
+ "kinopoisk.ru",
+ "mykp.ru",
+ "yadi.sk",
+
+ "yandex.net",
+ "yastatic.net",
+
+ "yandex.az",
+ "yandex.by",
+ "yandex.co.il",
+ "yandex.com.am",
+ "yandex.com.ge",
+ "yandex.com.tr",
+ "yandex.com.ua",
+ "yandex.ee",
+ "yandex.fr",
+ "yandex.kg",
+ "yandex.kz",
+ "yandex.lt",
+ "yandex.lv",
+ "yandex.md",
+ "yandex.ru",
+ "yandex.tj",
+ "yandex.tm",
+ "yandex.ua",
+ "yandex.uz",
+ "ya.ru",
+ ],
+ ["yoox.com", "mrporter.com", "theoutnet.com", "yoox.it"],
+ [
+ "sph.com.sg",
+
+ "sphdigital.com",
+
+ "beritaharian.sg",
+ "businesstimes.com.sg",
+ "shinmin.sg",
+ "straitstimes.com",
+ "tabla.com.sg",
+ "tamilmurasu.com.sg",
+ "tnp.sg",
+ "wanbao.com.sg",
+ "zaobao.com",
+ "zaobao.com.sg",
+ "zaobao.sg"
+ ],
+ ["zendesk.com", "zopim.com"],
+ ["zhaopin.com", "zhaopin.cn"],
+ ["zillow.com", "zillowstatic.com", "zillowcloud.com", "zg-api.com"],
+ [
+ "zoho.com",
+
+ "zoho.com.au",
+ "zoho.eu",
+
+ "zohositescontent.com",
+ "zohositescontent.com.au",
+ "zohositescontent.eu",
+
+ "manageengine.com",
+
+ "zohocdn.com",
+ "zohocorp.com",
+ "zohocreator.com",
+ "zohopublic.com",
+ "zohostatic.com",
+ ],
+ ["zonealarm.com", "zonelabs.com"],
+];
+
+/**
+ * Make a data structure for quick lookups of whether two domains are the same first party
+ */
+function makeDomainLookup(mdfpArray) {
+ let out = {},
+ arrLength = mdfpArray.length;
+ for (let i = 0; i < arrLength; i++) {
+ let inner = new Set(mdfpArray[i]);
+ for (let domain of inner) {
+ out[domain] = inner;
+ }
+ }
+ return out;
+}
+
+function makeIsMultiDomainFirstParty(domainLookup) {
+ return function (domain1, domain2) {
+ if (domain1 in domainLookup) {
+ return (domainLookup[domain1].has(domain2));
+ }
+ return false;
+ };
+}
+
+let _domainLookup = makeDomainLookup(multiDomainFirstPartiesArray);
+/**
+ * Check if two domains belong to the same effective first party
+ * @param {String} domain1 a base doamin
+ * @param {String} domain2 a second base doamin
+ *
+ * @return boolean true if the domains are the same first party
+ */
+let isMultiDomainFirstParty = makeIsMultiDomainFirstParty(_domainLookup);
+/************************************** exports */
+return {
+ isMultiDomainFirstParty,
+ makeDomainLookup,
+ makeIsMultiDomainFirstParty,
+ multiDomainFirstPartiesArray,
+};
+})(); //require scopes
diff --git a/src/js/options.js b/src/js/options.js
new file mode 100644
index 0000000..7ca7008
--- /dev/null
+++ b/src/js/options.js
@@ -0,0 +1,976 @@
+/*
+ * This file is part of Adblock Plus <http://adblockplus.org/>,
+ * Copyright (C) 2006-2013 Eyeo GmbH
+ *
+ * Adblock Plus 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.
+ *
+ * Adblock Plus 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 Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+window.OPTIONS_INITIALIZED = false;
+window.SLIDERS_DONE = false;
+
+const TOOLTIP_CONF = {
+ maxWidth: 400
+};
+const USER_DATA_EXPORT_KEYS = ["action_map", "snitch_map", "settings_map"];
+
+let i18n = chrome.i18n;
+
+let constants = require("constants");
+let { getOriginsArray } = require("optionslib");
+let htmlUtils = require("htmlutils").htmlUtils;
+let utils = require("utils");
+
+let OPTIONS_DATA = {};
+
+/*
+ * Loads options from pb storage and sets UI elements accordingly.
+ */
+function loadOptions() {
+ // Set page title to i18n version of "Privacy Badger Options"
+ document.title = i18n.getMessage("options_title");
+
+ // Add event listeners
+ $("#allowlist-form").on("submit", addDisabledSite);
+ $("#remove-disabled-site").on("click", removeDisabledSite);
+ $("#cloud-upload").on("click", uploadCloud);
+ $("#cloud-download").on("click", downloadCloud);
+ $('#importTrackerButton').on("click", loadFileChooser);
+ $('#importTrackers').on("change", importTrackerList);
+ $('#exportTrackers').on("click", exportUserData);
+ $('#resetData').on("click", resetData);
+ $('#removeAllData').on("click", removeAllData);
+
+ if (OPTIONS_DATA.settings.showTrackingDomains) {
+ $('#tracking-domains-overlay').hide();
+ } else {
+ $('#blockedResourcesContainer').hide();
+
+ $('#show-tracking-domains-checkbox').on("click", () => {
+ $('#tracking-domains-overlay').hide();
+ $('#blockedResourcesContainer').show();
+ chrome.runtime.sendMessage({
+ type: "updateSettings",
+ data: {
+ showTrackingDomains: true
+ }
+ });
+ });
+ }
+
+ // Set up input for searching through tracking domains.
+ $("#trackingDomainSearch").on("input", filterTrackingDomains);
+ $("#tracking-domains-type-filter").on("change", filterTrackingDomains);
+ $("#tracking-domains-status-filter").on("change", filterTrackingDomains);
+ $("#tracking-domains-show-not-yet-blocked").on("change", filterTrackingDomains);
+
+ // Add event listeners for origins container.
+ $('#blockedResourcesContainer').on('change', 'input:radio', function () {
+ let $radio = $(this),
+ $clicker = $radio.parents('.clicker').first(),
+ origin = $clicker.data('origin'),
+ action = $radio.val();
+
+ // update domain slider row tooltip/status indicators
+ updateOrigin(origin, action, true);
+
+ // persist the change
+ saveToggle(origin, action);
+ });
+ $('#blockedResourcesContainer').on('click', '.userset .honeybadgerPowered', revertDomainControl);
+ $('#blockedResourcesContainer').on('click', '.removeOrigin', removeOrigin);
+
+ // Display jQuery UI elements
+ $("#tabs").tabs({
+ activate: function (event, ui) {
+ // update options page URL fragment identifier
+ // to preserve selected tab on page reload
+ history.replaceState(null, null, "#" + ui.newPanel.attr('id'));
+ }
+ });
+ $("button").button();
+ $("#add-disabled-site").button("option", "icons", {primary: "ui-icon-plus"});
+ $("#remove-disabled-site").button("option", "icons", {primary: "ui-icon-minus"});
+ $("#cloud-upload").button("option", "icons", {primary: "ui-icon-arrowreturnthick-1-n"});
+ $("#cloud-download").button("option", "icons", {primary: "ui-icon-arrowreturnthick-1-s"});
+ $(".importButton").button("option", "icons", {primary: "ui-icon-plus"});
+ $("#exportTrackers").button("option", "icons", {primary: "ui-icon-extlink"});
+ $("#resetData").button("option", "icons", {primary: "ui-icon-arrowrefresh-1-w"});
+ $("#removeAllData").button("option", "icons", {primary: "ui-icon-closethick"});
+ $("#show_counter_checkbox").on("click", updateShowCounter);
+ $("#show_counter_checkbox").prop("checked", OPTIONS_DATA.settings.showCounter);
+ $("#replace-widgets-checkbox")
+ .on("click", updateWidgetReplacement)
+ .prop("checked", OPTIONS_DATA.isWidgetReplacementEnabled);
+ $("#enable_dnt_checkbox").on("click", updateDNTCheckboxClicked);
+ $("#enable_dnt_checkbox").prop("checked", OPTIONS_DATA.settings.sendDNTSignal);
+ $("#check_dnt_policy_checkbox").on("click", updateCheckingDNTPolicy);
+ $("#check_dnt_policy_checkbox").prop("checked", OPTIONS_DATA.settings.checkForDNTPolicy).prop("disabled", !OPTIONS_DATA.settings.sendDNTSignal);
+
+ // only show the alternateErrorPagesEnabled override if browser supports it
+ if (chrome.privacy && chrome.privacy.services && chrome.privacy.services.alternateErrorPagesEnabled) {
+ $("#privacy-settings-header").show();
+ $("#disable-google-nav-error-service").show();
+ $('#disable-google-nav-error-service-checkbox')
+ .prop("checked", OPTIONS_DATA.settings.disableGoogleNavErrorService)
+ .on("click", overrideAlternateErrorPagesSetting);
+ }
+
+ // only show the hyperlinkAuditingEnabled override if browser supports it
+ if (chrome.privacy && chrome.privacy.websites && chrome.privacy.websites.hyperlinkAuditingEnabled) {
+ $("#privacy-settings-header").show();
+ $("#disable-hyperlink-auditing").show();
+ $("#disable-hyperlink-auditing-checkbox")
+ .prop("checked", OPTIONS_DATA.settings.disableHyperlinkAuditing)
+ .on("click", overrideHyperlinkAuditingSetting);
+ }
+
+ if (OPTIONS_DATA.webRTCAvailable) {
+ $("#webRTCToggle").show();
+ $("#toggle_webrtc_mode").on("click", toggleWebRTCIPProtection);
+
+ chrome.privacy.network.webRTCIPHandlingPolicy.get({}, result => {
+ // auto check the option box if ip leak is already protected at diff levels, via pb or another extension
+ if (result.value == "default_public_interface_only" || result.value == "disable_non_proxied_udp") {
+ $("#toggle_webrtc_mode").prop("checked", true);
+ }
+ });
+ }
+
+ $('#local-learning-checkbox')
+ .prop("checked", OPTIONS_DATA.settings.learnLocally)
+ .on("click", (event) => {
+ const enabled = $(event.currentTarget).prop("checked");
+ chrome.runtime.sendMessage({
+ type: "updateSettings",
+ data: {
+ learnLocally: enabled
+ }
+ }, function () {
+ $("#learn-in-incognito-checkbox")
+ .prop("disabled", (enabled ? false : "disabled"))
+ .prop("checked", (enabled ? OPTIONS_DATA.settings.learnInIncognito : false));
+ $("#show-nontracking-domains-checkbox")
+ .prop("disabled", (enabled ? false : "disabled"))
+ .prop("checked", (enabled ? OPTIONS_DATA.settings.showNonTrackingDomains : false));
+
+ $("#learning-setting-divs").slideToggle(enabled);
+ $("#not-yet-blocked-filter").toggle(enabled);
+ });
+ });
+ if (OPTIONS_DATA.settings.learnLocally) {
+ $("#learning-setting-divs").show();
+ $("#not-yet-blocked-filter").show();
+ }
+
+ $("#learn-in-incognito-checkbox")
+ .prop("disabled", OPTIONS_DATA.settings.learnLocally ? false : "disabled")
+ .prop("checked", (
+ OPTIONS_DATA.settings.learnLocally ?
+ OPTIONS_DATA.settings.learnInIncognito : false
+ ))
+ .on("click", (event) => {
+ const enabled = $(event.currentTarget).prop("checked");
+ chrome.runtime.sendMessage({
+ type: "updateSettings",
+ data: {
+ learnInIncognito: enabled
+ }
+ }, function () {
+ OPTIONS_DATA.settings.learnInIncognito = enabled;
+ });
+ });
+
+ $('#show-nontracking-domains-checkbox')
+ .prop("disabled", OPTIONS_DATA.settings.learnLocally ? false : "disabled")
+ .prop("checked", (
+ OPTIONS_DATA.settings.learnLocally ?
+ OPTIONS_DATA.settings.showNonTrackingDomains : false
+ ))
+ .on("click", (event) => {
+ const enabled = $(event.currentTarget).prop("checked");
+ chrome.runtime.sendMessage({
+ type: "updateSettings",
+ data: {
+ showNonTrackingDomains: enabled
+ }
+ }, function () {
+ OPTIONS_DATA.settings.showNonTrackingDomains = enabled;
+ });
+ });
+
+ const widgetSelector = $("#hide-widgets-select");
+ widgetSelector.prop("disabled",
+ OPTIONS_DATA.isWidgetReplacementEnabled ? false : "disabled");
+
+ $("#replace-widgets-checkbox").change(function () {
+ if ($(this).is(":checked")) {
+ widgetSelector.prop("disabled", false);
+ } else {
+ widgetSelector.prop("disabled", "disabled");
+ }
+ });
+
+ // Initialize Select2 and populate options
+ widgetSelector.select2();
+ OPTIONS_DATA.widgets.forEach(function (key) {
+ const isSelected = OPTIONS_DATA.settings.widgetReplacementExceptions.includes(key);
+ const option = new Option(key, key, false, isSelected);
+ widgetSelector.append(option).trigger("change");
+ });
+
+ widgetSelector.on('select2:select', updateWidgetReplacementExceptions);
+ widgetSelector.on('select2:unselect', updateWidgetReplacementExceptions);
+ widgetSelector.on('select2:clear', updateWidgetReplacementExceptions);
+
+ reloadDisabledSites();
+ reloadTrackingDomainsTab();
+
+ $('html').css({
+ overflow: 'visible',
+ visibility: 'visible'
+ });
+
+ window.OPTIONS_INITIALIZED = true;
+}
+
+/**
+ * Opens the file chooser to allow a user to select
+ * a file to import.
+ */
+function loadFileChooser() {
+ var fileChooser = document.getElementById('importTrackers');
+ fileChooser.click();
+}
+
+/**
+ * Import a list of trackers supplied by the user
+ * NOTE: list must be in JSON format to be parsable
+ */
+function importTrackerList() {
+ var file = this.files[0];
+
+ if (file) {
+ var reader = new FileReader();
+ reader.readAsText(file);
+ reader.onload = function(e) {
+ parseUserDataFile(e.target.result);
+ };
+ } else {
+ var selectFile = i18n.getMessage("import_select_file");
+ confirm(selectFile);
+ }
+
+ document.getElementById("importTrackers").value = '';
+}
+
+/**
+ * Parses Privacy Badger data uploaded by the user.
+ *
+ * @param {String} storageMapsList data from JSON file that user provided
+ */
+function parseUserDataFile(storageMapsList) {
+ let lists;
+
+ try {
+ lists = JSON.parse(storageMapsList);
+ } catch (e) {
+ return confirm(i18n.getMessage("invalid_json"));
+ }
+
+ // validate by checking we have the same keys in the import as in the export
+ if (!_.isEqual(
+ Object.keys(lists).sort(),
+ USER_DATA_EXPORT_KEYS.sort()
+ )) {
+ return confirm(i18n.getMessage("invalid_json"));
+ }
+
+ // check for webrtc setting in the imported settings map
+ if (lists.settings_map.preventWebRTCIPLeak) {
+ // verify that the user hasn't already enabled this option
+ if (!$("#toggle_webrtc_mode").prop("checked")) {
+ toggleWebRTCIPProtection();
+ }
+ // this browser-controlled setting doesn't belong in Badger's settings object
+ delete lists.settings_map.preventWebRTCIPLeak;
+ }
+
+ chrome.runtime.sendMessage({
+ type: "mergeUserData",
+ data: lists
+ }, (response) => {
+ OPTIONS_DATA.settings.disabledSites = response.disabledSites;
+ OPTIONS_DATA.origins = response.origins;
+
+ reloadDisabledSites();
+ reloadTrackingDomainsTab();
+ // TODO general settings are not updated
+
+ confirm(i18n.getMessage("import_successful"));
+ });
+}
+
+function resetData() {
+ var resetWarn = i18n.getMessage("reset_data_confirm");
+ if (confirm(resetWarn)) {
+ chrome.runtime.sendMessage({type: "resetData"}, () => {
+ // reload page to refresh tracker list
+ location.reload();
+ });
+ }
+}
+
+function removeAllData() {
+ var removeWarn = i18n.getMessage("remove_all_data_confirm");
+ if (confirm(removeWarn)) {
+ chrome.runtime.sendMessage({type: "removeAllData"}, () => {
+ location.reload();
+ });
+ }
+}
+
+function downloadCloud() {
+ chrome.runtime.sendMessage({type: "downloadCloud"},
+ function (response) {
+ if (response.success) {
+ alert(i18n.getMessage("download_cloud_success"));
+ OPTIONS_DATA.settings.disabledSites = response.disabledSites;
+ reloadDisabledSites();
+ } else {
+ console.error("Cloud sync error:", response.message);
+ if (response.message === i18n.getMessage("download_cloud_no_data")) {
+ alert(response.message);
+ } else {
+ alert(i18n.getMessage("download_cloud_failure"));
+ }
+ }
+ }
+ );
+}
+
+function uploadCloud() {
+ chrome.runtime.sendMessage({type: "uploadCloud"},
+ function (status) {
+ if (status.success) {
+ alert(i18n.getMessage("upload_cloud_success"));
+ } else {
+ console.error("Cloud sync error:", status.message);
+ alert(i18n.getMessage("upload_cloud_failure"));
+ }
+ }
+ );
+}
+
+/**
+ * Export the user's data, including their list of trackers from
+ * action_map and snitch_map, along with their settings.
+ * List will be in JSON format that can be edited and reimported
+ * in another instance of Privacy Badger.
+ */
+function exportUserData() {
+ chrome.storage.local.get(USER_DATA_EXPORT_KEYS, function (maps) {
+
+ // exports the user's prevent webrtc leak setting if it's checked
+ if ($("#toggle_webrtc_mode").prop("checked")) {
+ maps.settings_map.preventWebRTCIPLeak = true;
+ }
+
+ let mapJSON = JSON.stringify(maps);
+
+ // Append the formatted date to the exported file name
+ let currDate = new Date().toLocaleString();
+ let escapedDate = currDate
+ // illegal filename charset regex from
+ // https://github.com/parshap/node-sanitize-filename/blob/ef1e8ad58e95eb90f8a01f209edf55cd4176e9c8/index.js
+ .replace(/[\/\?<>\\:\*\|"]/g, '_') /* eslint no-useless-escape:off */
+ // also collapse-replace commas and spaces
+ .replace(/[, ]+/g, '_');
+ let filename = 'PrivacyBadger_user_data-' + escapedDate + '.json';
+
+ // Download workaround taken from uBlock Origin
+ // https://github.com/gorhill/uBlock/blob/40a85f8c04840ae5f5875c1e8b5fa17578c5bd1a/platform/chromium/vapi-common.js
+ let a = document.createElement('a');
+ a.setAttribute('download', filename || '');
+
+ let blob = new Blob([mapJSON], { type: 'application/json' }); // pass a useful mime type here
+ a.href = URL.createObjectURL(blob);
+
+ function clickBlobLink() {
+ a.dispatchEvent(new MouseEvent('click'));
+ URL.revokeObjectURL(blob);
+ }
+
+ /**
+ * Firefox workaround to insert the blob link in an iFrame
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=1420419#c18
+ */
+ function addBlobWorkAroundForFirefox() {
+ // Create or use existing iframe for the blob 'a' element
+ let iframe = document.getElementById('exportUserDataIframe');
+ if (!iframe) {
+ iframe = document.createElement('iframe');
+ iframe.id = "exportUserDataIframe";
+ iframe.setAttribute("style", "visibility: hidden; height: 0; width: 0");
+ document.getElementById('export').appendChild(iframe);
+
+ iframe.contentWindow.document.open();
+ iframe.contentWindow.document.write('<html><head></head><body></body></html>');
+ iframe.contentWindow.document.close();
+ } else {
+ // Remove the old 'a' element from the iframe
+ let oldElement = iframe.contentWindow.document.body.lastChild;
+ iframe.contentWindow.document.body.removeChild(oldElement);
+ }
+ iframe.contentWindow.document.body.appendChild(a);
+ }
+
+ // TODO remove browser check and simplify code once Firefox 58 goes away
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1420419
+ if (chrome.runtime.getBrowserInfo) {
+ chrome.runtime.getBrowserInfo((info) => {
+ if (info.name == "Firefox" || info.name == "Waterfox") {
+ addBlobWorkAroundForFirefox();
+ }
+ clickBlobLink();
+ });
+ } else {
+ clickBlobLink();
+ }
+ });
+}
+
+/**
+ * Update setting for whether or not to show counter on Privacy Badger badge.
+ */
+function updateShowCounter() {
+ const showCounter = $("#show_counter_checkbox").prop("checked");
+
+ chrome.runtime.sendMessage({
+ type: "updateSettings",
+ data: { showCounter }
+ }, () => {
+ // Refresh display for each tab's PB badge.
+ chrome.tabs.query({}, function(tabs) {
+ tabs.forEach(function(tab) {
+ chrome.runtime.sendMessage({
+ type: "updateBadge",
+ tab_id: tab.id
+ });
+ });
+ });
+ });
+}
+
+/**
+ * Update setting for whether or not to replace
+ * social buttons/video players/commenting widgets.
+ */
+function updateWidgetReplacement() {
+ const socialWidgetReplacementEnabled = $("#replace-widgets-checkbox").prop("checked");
+
+ chrome.runtime.sendMessage({
+ type: "updateSettings",
+ data: { socialWidgetReplacementEnabled }
+ });
+}
+
+/**
+ * Update DNT checkbox clicked
+ */
+function updateDNTCheckboxClicked() {
+ const enabled = $("#enable_dnt_checkbox").prop("checked");
+
+ chrome.runtime.sendMessage({
+ type: "updateSettings",
+ data: {
+ sendDNTSignal: enabled
+ }
+ });
+
+ $("#check_dnt_policy_checkbox").prop("checked", enabled).prop("disabled", !enabled);
+ updateCheckingDNTPolicy();
+}
+
+function updateCheckingDNTPolicy() {
+ const enabled = $("#check_dnt_policy_checkbox").prop("checked");
+
+ chrome.runtime.sendMessage({
+ type: "updateSettings",
+ data: {
+ checkForDNTPolicy: enabled
+ }
+ });
+}
+
+function reloadDisabledSites() {
+ let sites = OPTIONS_DATA.settings.disabledSites,
+ $select = $('#allowlist-select');
+
+ // sort disabled sites the same way blocked sites are sorted
+ sites = htmlUtils.sortDomains(sites);
+
+ $select.empty();
+ for (let i = 0; i < sites.length; i++) {
+ $('<option>').text(sites[i]).appendTo($select);
+ }
+}
+
+function addDisabledSite(event) {
+ event.preventDefault();
+
+ let domain = utils.getHostFromDomainInput(
+ document.getElementById("new-disabled-site-input").value.replace(/\s/g, "")
+ );
+
+ if (!domain) {
+ return confirm(i18n.getMessage("invalid_domain"));
+ }
+
+ chrome.runtime.sendMessage({
+ type: "disablePrivacyBadgerForOrigin",
+ domain
+ }, (response) => {
+ OPTIONS_DATA.settings.disabledSites = response.disabledSites;
+ reloadDisabledSites();
+ document.getElementById("new-disabled-site-input").value = "";
+ });
+}
+
+function removeDisabledSite(event) {
+ event.preventDefault();
+
+ let domains = [];
+ let $selected = $("#allowlist-select option:selected");
+ for (let i = 0; i < $selected.length; i++) {
+ domains.push($selected[i].text);
+ }
+
+ chrome.runtime.sendMessage({
+ type: "enablePrivacyBadgerForOriginList",
+ domains
+ }, (response) => {
+ OPTIONS_DATA.settings.disabledSites = response.disabledSites;
+ reloadDisabledSites();
+ });
+}
+
+// Tracking Domains slider functions
+
+/**
+ * Gets action for given origin.
+ * @param {String} origin - Origin to get action for.
+ */
+function getOriginAction(origin) {
+ return OPTIONS_DATA.origins[origin];
+}
+
+function revertDomainControl(event) {
+ event.preventDefault();
+
+ let origin = $(event.target).parent().data('origin');
+
+ chrome.runtime.sendMessage({
+ type: "revertDomainControl",
+ origin
+ }, (response) => {
+ // update any sliders that changed as a result
+ updateSliders(response.origins);
+ // update cached domain data
+ OPTIONS_DATA.origins = response.origins;
+ });
+}
+
+/**
+ * Displays list of all tracking domains along with toggle controls.
+ */
+function updateSummary() {
+ // if there are no tracking domains
+ let allTrackingDomains = Object.keys(OPTIONS_DATA.origins);
+ if (!allTrackingDomains || !allTrackingDomains.length) {
+ // hide the number of trackers and slider instructions message
+ $("#options_domain_list_trackers").hide();
+
+ // show "no trackers" message
+ $("#options_domain_list_no_trackers").show();
+ $("#blockedResources").html('');
+ $("#tracking-domains-div").hide();
+
+ // activate tooltips
+ $('.tooltip:not(.tooltipstered)').tooltipster(TOOLTIP_CONF);
+
+ return;
+ }
+
+ // reloadTrackingDomainsTab can be called multiple times, needs to be reversible
+ $("#options_domain_list_no_trackers").hide();
+ $("#tracking-domains-div").show();
+
+ // count unique (cookie)blocked tracking base domains
+ let blockedDomains = getOriginsArray(OPTIONS_DATA.origins, null, null, null, false);
+ let baseDomains = new Set(blockedDomains.map(d => window.getBaseDomain(d)));
+ $("#options_domain_list_trackers").html(i18n.getMessage(
+ "options_domain_list_trackers", [
+ baseDomains.size,
+ "<a target='_blank' title='" + _.escape(i18n.getMessage("what_is_a_tracker")) + "' class='tooltip' href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ ]
+ )).show();
+}
+
+/**
+ * Displays list of all tracking domains along with toggle controls.
+ */
+function reloadTrackingDomainsTab() {
+ updateSummary();
+
+ // Get containing HTML for domain list along with toggle legend icons.
+ $("#blockedResources")[0].innerHTML = htmlUtils.getTrackerContainerHtml();
+
+ // activate tooltips
+ $('.tooltip:not(.tooltipstered)').tooltipster(TOOLTIP_CONF);
+
+ // Display tracking domains.
+ showTrackingDomains(
+ getOriginsArray(
+ OPTIONS_DATA.origins,
+ $("#trackingDomainSearch").val(),
+ $('#tracking-domains-type-filter').val(),
+ $('#tracking-domains-status-filter').val(),
+ $('#tracking-domains-show-not-yet-blocked').prop('checked')
+ )
+ );
+}
+
+/**
+ * Displays filtered list of tracking domains based on user input.
+ */
+function filterTrackingDomains() {
+ const $searchFilter = $('#trackingDomainSearch'),
+ $typeFilter = $('#tracking-domains-type-filter'),
+ $statusFilter = $('#tracking-domains-status-filter');
+
+ if ($typeFilter.val() == "dnt") {
+ $statusFilter.prop("disabled", true).val("");
+ } else {
+ $statusFilter.prop("disabled", false);
+ }
+
+ let search_update = (this == $searchFilter[0]),
+ initial_search_text = $searchFilter.val().toLowerCase(),
+ time_to_wait = 0,
+ callback = function () {};
+
+ // If we are here because the search filter got updated,
+ // wait a short period of time and see if search text has changed.
+ // If so it means user is still typing so hold off on filtering.
+ if (search_update) {
+ time_to_wait = 500;
+ callback = function () {
+ $searchFilter.focus();
+ };
+ }
+
+ setTimeout(function () {
+ // check search text
+ let search_text = $searchFilter.val().toLowerCase();
+ if (search_text != initial_search_text) {
+ return;
+ }
+
+ // show filtered origins
+ let filteredOrigins = getOriginsArray(
+ OPTIONS_DATA.origins,
+ search_text,
+ $typeFilter.val(),
+ $statusFilter.val(),
+ $('#tracking-domains-show-not-yet-blocked').prop('checked')
+ );
+ showTrackingDomains(filteredOrigins, callback);
+
+ }, time_to_wait);
+}
+
+/**
+ * Renders the list of tracking domains.
+ *
+ * @param {Array} domains
+ * @param {Function} cb callback
+ */
+function showTrackingDomains(domains, cb) {
+ if (!cb) {
+ cb = function () {};
+ }
+
+ window.SLIDERS_DONE = false;
+ $('#tracking-domains-div').css('visibility', 'hidden');
+ $('#tracking-domains-loader').show();
+
+ domains = htmlUtils.sortDomains(domains);
+
+ let out = [];
+ for (let domain of domains) {
+ let action = getOriginAction(domain);
+ if (action) {
+ let show_breakage_warning = (
+ action == constants.USER_BLOCK &&
+ OPTIONS_DATA.cookieblocked.hasOwnProperty(domain)
+ );
+ out.push(htmlUtils.getOriginHtml(domain, action, show_breakage_warning));
+ }
+ }
+
+ function renderDomains() {
+ const CHUNK = 100;
+
+ let $printable = $(out.splice(0, CHUNK).join(""));
+
+ $printable.appendTo('#blockedResourcesInner');
+
+ // activate tooltips
+ // TODO disabled for performance reasons
+ //$('#blockedResourcesInner .tooltip:not(.tooltipstered)').tooltipster(
+ // htmlUtils.DOMAIN_TOOLTIP_CONF);
+
+ if (out.length) {
+ requestAnimationFrame(renderDomains);
+ } else {
+ $('#tracking-domains-loader').hide();
+ $('#tracking-domains-div').css('visibility', 'visible');
+ window.SLIDERS_DONE = true;
+ cb();
+ }
+ }
+
+ $('#blockedResourcesInner').empty();
+
+ if (out.length) {
+ requestAnimationFrame(renderDomains);
+ } else {
+ $('#tracking-domains-loader').hide();
+ $('#tracking-domains-div').css('visibility', 'visible');
+ window.SLIDERS_DONE = true;
+ cb();
+ }
+}
+
+/**
+ * https://tools.ietf.org/html/draft-ietf-rtcweb-ip-handling-01#page-5
+ *
+ * Toggle WebRTC IP address leak protection setting.
+ *
+ * When enabled, policy is set to Mode 3 (default_public_interface_only).
+ */
+function toggleWebRTCIPProtection() {
+ // Return early with non-supporting browsers
+ if (!OPTIONS_DATA.webRTCAvailable) {
+ return;
+ }
+
+ let cpn = chrome.privacy.network;
+
+ cpn.webRTCIPHandlingPolicy.get({}, function (result) {
+ // Update new value to be opposite of current browser setting
+ if (result.value == 'default_public_interface_only') {
+ cpn.webRTCIPHandlingPolicy.clear({});
+ } else {
+ cpn.webRTCIPHandlingPolicy.set({
+ value: 'default_public_interface_only'
+ });
+ }
+ });
+}
+
+// handles overriding the alternateErrorPagesEnabled setting
+function overrideAlternateErrorPagesSetting() {
+ const checked = $("#disable-google-nav-error-service-checkbox").prop("checked");
+
+ // update Badger settings so that we know to reapply the browser setting on startup
+ chrome.runtime.sendMessage({
+ type: "updateSettings",
+ data: {
+ disableGoogleNavErrorService: checked
+ }
+ });
+
+ // update the browser setting
+ if (checked) {
+ chrome.privacy.services.alternateErrorPagesEnabled.set({
+ value: false
+ });
+ } else {
+ chrome.privacy.services.alternateErrorPagesEnabled.clear({});
+ }
+}
+
+// handles overriding the hyperlinkAuditingEnabled setting
+function overrideHyperlinkAuditingSetting() {
+ const checked = $("#disable-hyperlink-auditing-checkbox").prop("checked");
+
+ // update Badger settings so that we know to reapply the browser setting on startup
+ chrome.runtime.sendMessage({
+ type: "updateSettings",
+ data: {
+ disableHyperlinkAuditing: checked
+ }
+ });
+
+ // update the browser setting
+ if (checked) {
+ chrome.privacy.websites.hyperlinkAuditingEnabled.set({
+ value: false
+ });
+ } else {
+ chrome.privacy.websites.hyperlinkAuditingEnabled.clear({});
+ }
+}
+
+/**
+ * Updates domain tooltip, slider color.
+ * Also toggles status indicators like breakage warnings.
+ */
+function updateOrigin(origin, action, userset) {
+ let $clicker = $('#blockedResourcesInner div.clicker[data-origin="' + origin + '"]'),
+ $switchContainer = $clicker.find('.switch-container').first();
+
+ // update slider color via CSS
+ $switchContainer.removeClass([
+ constants.BLOCK,
+ constants.COOKIEBLOCK,
+ constants.ALLOW,
+ constants.NO_TRACKING].join(" ")).addClass(action);
+
+ let show_breakage_warning = (
+ action == constants.BLOCK &&
+ OPTIONS_DATA.cookieblocked.hasOwnProperty(origin)
+ );
+
+ htmlUtils.toggleBlockedStatus($clicker, userset, show_breakage_warning);
+
+ // reinitialize the domain tooltip
+ // TODO disabled for performance reasons
+ //$clicker.find('.origin-inner').tooltipster('destroy');
+ //$clicker.find('.origin-inner').attr(
+ // 'title', htmlUtils.getActionDescription(action, origin));
+ //$clicker.find('.origin-inner').tooltipster(htmlUtils.DOMAIN_TOOLTIP_CONF);
+}
+
+/**
+ * Updates the list of tracking domains in response to user actions.
+ *
+ * For example, moving the slider for example.com should move the sliders
+ * for www.example.com and cdn.example.com
+ */
+function updateSliders(updatedOriginData) {
+ let updated_domains = Object.keys(updatedOriginData);
+
+ // update any sliders that changed
+ for (let domain of updated_domains) {
+ let action = updatedOriginData[domain];
+ if (action == OPTIONS_DATA.origins[domain]) {
+ continue;
+ }
+
+ let userset = false;
+ if (action.startsWith('user')) {
+ userset = true;
+ action = action.slice(5);
+ }
+
+ // update slider position
+ let $radios = $('#blockedResourcesInner div.clicker[data-origin="' + domain + '"] input'),
+ selected_val = (action == constants.DNT ? constants.ALLOW : action);
+ // update the radio group without triggering a change event
+ // https://stackoverflow.com/a/22635728
+ $radios.val([selected_val]);
+
+ // update domain slider row tooltip/status indicators
+ updateOrigin(domain, action, userset);
+ }
+
+ // remove sliders that are no longer present
+ let removed = Object.keys(OPTIONS_DATA.origins).filter(
+ x => !updated_domains.includes(x));
+ for (let domain of removed) {
+ let $clicker = $('#blockedResourcesInner div.clicker[data-origin="' + domain + '"]');
+ $clicker.remove();
+ }
+}
+
+/**
+ * Save the user setting for a domain by messaging the background page.
+ */
+function saveToggle(origin, action) {
+ chrome.runtime.sendMessage({
+ type: "saveOptionsToggle",
+ origin,
+ action
+ }, (response) => {
+ // first update the cache for the slider
+ // that was just changed by the user
+ // to avoid redundantly updating it below
+ OPTIONS_DATA.origins[origin] = response.origins[origin];
+ // update any sliders that changed as a result
+ updateSliders(response.origins);
+ // update cached domain data
+ OPTIONS_DATA.origins = response.origins;
+ });
+}
+
+/**
+ * Remove origin from Privacy Badger.
+ * @param {Event} event Click event triggered by user.
+ */
+function removeOrigin(event) {
+ event.preventDefault();
+
+ // confirm removal before proceeding
+ if (!confirm(i18n.getMessage("options_remove_origin_confirm"))) {
+ return;
+ }
+
+ let origin = $(event.target).parent().data('origin');
+
+ chrome.runtime.sendMessage({
+ type: "removeOrigin",
+ origin
+ }, (response) => {
+ // remove rows that are no longer here
+ updateSliders(response.origins);
+ // update cached domain data
+ OPTIONS_DATA.origins = response.origins;
+ // if we removed domains, the summary text may have changed
+ updateSummary();
+ });
+}
+
+/**
+ * Update which widgets should be blocked instead of replaced
+ * @param {Event} event The DOM event triggered by selecting an option
+ */
+function updateWidgetReplacementExceptions() {
+ const widgetReplacementExceptions = $('#hide-widgets-select').select2('data').map(({ id }) => id);
+ chrome.runtime.sendMessage({
+ type: "updateSettings",
+ data: { widgetReplacementExceptions }
+ });
+}
+
+$(function () {
+ $.tooltipster.setDefaults(htmlUtils.TOOLTIPSTER_DEFAULTS);
+
+ chrome.runtime.sendMessage({
+ type: "getOptionsData",
+ }, (response) => {
+ OPTIONS_DATA = response;
+ loadOptions();
+ });
+});
diff --git a/src/js/popup.js b/src/js/popup.js
new file mode 100644
index 0000000..7e02e23
--- /dev/null
+++ b/src/js/popup.js
@@ -0,0 +1,723 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2014 Electronic Frontier Foundation
+ * Derived from Adblock Plus
+ * Copyright (C) 2006-2013 Eyeo GmbH
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+window.POPUP_INITIALIZED = false;
+window.SLIDERS_DONE = false;
+
+var constants = require("constants");
+var FirefoxAndroid = require("firefoxandroid");
+var htmlUtils = require("htmlutils").htmlUtils;
+
+let POPUP_DATA = {};
+
+/* if they aint seen the comic*/
+function showNagMaybe() {
+ var $nag = $("#instruction");
+ var $outer = $("#instruction-outer");
+ let intro_page_url = chrome.runtime.getURL("/skin/firstRun.html");
+
+ function _setSeenComic(cb) {
+ chrome.runtime.sendMessage({
+ type: "seenComic"
+ }, cb);
+ }
+
+ function _setSeenLearningPrompt(cb) {
+ chrome.runtime.sendMessage({
+ type: "seenLearningPrompt"
+ }, cb);
+ }
+
+ function _hideNag() {
+ $nag.fadeOut();
+ $outer.fadeOut();
+ }
+
+ function _showNag() {
+ $nag.show();
+ $outer.show();
+ // Attach event listeners
+ $('#fittslaw').on("click", function (e) {
+ e.preventDefault();
+ _setSeenComic(() => {
+ _hideNag();
+ });
+ });
+ $("#intro-reminder-btn").on("click", function () {
+ // If there is a firstRun.html tab, switch to the tab.
+ // Otherwise, create a new tab
+ chrome.tabs.query({url: intro_page_url}, function (tabs) {
+ if (tabs.length == 0) {
+ chrome.tabs.create({
+ url: intro_page_url
+ });
+ } else {
+ chrome.tabs.update(tabs[0].id, {active: true}, function (tab) {
+ chrome.windows.update(tab.windowId, {focused: true});
+ });
+ }
+ _setSeenComic(() => {
+ window.close();
+ });
+ });
+ });
+ }
+
+ function _showError(error_text) {
+ $('#instruction-text').hide();
+ $('#error-text').show().find('a')
+ .attr('id', 'critical-error-link')
+ .css({
+ padding: '5px',
+ display: 'inline-block',
+ width: 'auto',
+ });
+ $('#error-message').text(error_text);
+
+ $('#fittslaw').on("click", function (e) {
+ e.preventDefault();
+ _hideNag();
+ });
+
+ $nag.show();
+ $outer.show();
+ }
+
+ function _showLearningPrompt() {
+ $('#instruction-text').hide();
+
+ $("#learning-prompt-btn").on("click", function () {
+ chrome.tabs.create({
+ url: "https://www.eff.org/badger-evolution"
+ });
+ _setSeenLearningPrompt(function () {
+ window.close();
+ });
+ });
+
+ $('#fittslaw').on("click", function (e) {
+ e.preventDefault();
+ _setSeenLearningPrompt(function () {
+ _hideNag();
+ });
+ });
+
+ $('#learning-prompt-div').show();
+ $nag.show();
+ $outer.show();
+ }
+
+ if (POPUP_DATA.showLearningPrompt) {
+ _showLearningPrompt();
+
+ } else if (!POPUP_DATA.seenComic) {
+ chrome.tabs.query({active: true, currentWindow: true}, function (focusedTab) {
+ // Show the popup instruction if the active tab is not firstRun.html page
+ if (!focusedTab[0].url.startsWith(intro_page_url)) {
+ _showNag();
+ }
+ });
+
+ } else if (POPUP_DATA.criticalError) {
+ _showError(POPUP_DATA.criticalError);
+ }
+}
+
+/**
+ * Init function. Showing/hiding popup.html elements and setting up event handler
+ */
+function init() {
+ showNagMaybe();
+
+ $("#activate_site_btn").on("click", activateOnSite);
+ $("#deactivate_site_btn").on("click", deactivateOnSite);
+ $("#donate").on("click", function() {
+ chrome.tabs.create({
+ url: "https://supporters.eff.org/donate/support-privacy-badger"
+ });
+ });
+
+ $('#error_input').on('input propertychange', function() {
+ // No easy way of sending message on popup close, send message for every change
+ chrome.runtime.sendMessage({
+ type: 'saveErrorText',
+ tabId: POPUP_DATA.tabId,
+ errorText: $("#error_input").val()
+ });
+ });
+
+ let overlay = $('#overlay');
+
+ // show error layout if the user was writing an error report
+ if (POPUP_DATA.hasOwnProperty('errorText') && POPUP_DATA.errorText) {
+ overlay.toggleClass('active');
+ }
+
+ $("#error").on("click", function() {
+ overlay.toggleClass('active');
+ });
+ $("#report-cancel").on("click", function() {
+ clearSavedErrorText();
+ closeOverlay();
+ });
+ $("#report-button").on("click", function() {
+ $(this).prop("disabled", true);
+ $("#report-cancel").prop("disabled", true);
+ send_error($("#error_input").val());
+ });
+ $("#report_close").on("click", function (e) {
+ e.preventDefault();
+ clearSavedErrorText();
+ closeOverlay();
+ });
+ $('#blockedResourcesContainer').on('change', 'input:radio', updateOrigin);
+ $('#blockedResourcesContainer').on('click', '.userset .honeybadgerPowered', revertDomainControl);
+
+ $("#version").text(
+ chrome.i18n.getMessage("version", chrome.runtime.getManifest().version)
+ );
+
+ // improve on Firefox's built-in options opening logic
+ if (typeof browser == "object" && typeof browser.runtime.getBrowserInfo == "function") {
+ browser.runtime.getBrowserInfo().then(function (info) {
+ if (info.name == "Firefox") {
+ $("#options").on("click", function (e) {
+ e.preventDefault();
+ openPage(chrome.runtime.getURL("/skin/options.html"));
+ });
+ $("#help").on("click", function (e) {
+ e.preventDefault();
+ openPage(this.getAttribute('href'));
+ });
+ }
+ });
+ }
+
+ $("#share").on("click", function (e) {
+ e.preventDefault();
+ share();
+ });
+ $("#share_close").on("click", function (e) {
+ e.preventDefault();
+ $("#share_overlay").toggleClass('active', false);
+ });
+ $("#copy-button").on("click", function() {
+ $("#share_output").select();
+ document.execCommand('copy');
+ $(this).text(chrome.i18n.getMessage("copy_button_copied"));
+ });
+
+ window.POPUP_INITIALIZED = true;
+}
+
+function openPage(url) {
+ // first get the active tab
+ chrome.tabs.query({ active: true, lastFocusedWindow: true }, (tabs) => {
+ let activeTab = tabs[0],
+ tabProps = {
+ url,
+ windowId: activeTab.windowId,
+ active: true,
+ index: activeTab.index + 1,
+ openerTabId: activeTab.id
+ };
+
+ // create the new tab
+ try {
+ chrome.tabs.create(tabProps);
+ } catch (e) {
+ // TODO workaround for pre-57 Firefox
+ delete tabProps.openerTabId;
+ chrome.tabs.create(tabProps);
+ }
+
+ window.close();
+ });
+}
+
+function clearSavedErrorText() {
+ chrome.runtime.sendMessage({
+ type: 'removeErrorText',
+ tabId: POPUP_DATA.tabId
+ });
+}
+
+/**
+ * Close the error reporting overlay
+ */
+function closeOverlay() {
+ $('#overlay').toggleClass('active', false);
+ $("#report-success").hide();
+ $("#report-fail").hide();
+ $("#error_input").val("");
+}
+
+/**
+ * Send errors to PB error reporting server
+ *
+ * @param {String} message The message to send
+ */
+function send_error(message) {
+ // get the latest domain list from the background page
+ chrome.runtime.sendMessage({
+ type: "getPopupData",
+ tabId: POPUP_DATA.tabId,
+ tabUrl: POPUP_DATA.tabUrl
+ }, (response) => {
+ const origins = response.origins;
+
+ if (!origins) {
+ return;
+ }
+
+ let out = {
+ browser: window.navigator.userAgent,
+ fqdn: response.tabHost,
+ message: message,
+ url: response.tabUrl,
+ version: chrome.runtime.getManifest().version
+ };
+
+ for (let origin in origins) {
+ let action = origins[origin];
+
+ // adjust action names for error reporting
+ if (action == constants.USER_ALLOW) {
+ action = "usernoaction";
+ } else if (action == constants.USER_BLOCK) {
+ action = "userblock";
+ } else if (action == constants.USER_COOKIEBLOCK) {
+ action = "usercookieblock";
+ } else if (action == constants.ALLOW) {
+ action = "noaction";
+ } else if (action == constants.BLOCK || action == constants.COOKIEBLOCK) {
+ // no need to adjust action
+ } else if (action == constants.DNT || action == constants.NO_TRACKING) {
+ action = "notracking";
+ }
+
+ if (out[action]) {
+ out[action] += ","+origin;
+ } else {
+ out[action] = origin;
+ }
+ }
+
+ var sendReport = $.ajax({
+ type: "POST",
+ url: "https://privacybadger.org/reporting",
+ data: JSON.stringify(out),
+ contentType: "application/json"
+ });
+
+ sendReport.done(function() {
+ $("#error_input").val("");
+ $("#report-success").slideDown();
+
+ clearSavedErrorText();
+
+ setTimeout(function() {
+ $("#report-button").prop("disabled", false);
+ $("#report-cancel").prop("disabled", false);
+ closeOverlay();
+ }, 3000);
+ });
+
+ sendReport.fail(function() {
+ $("#report-fail").slideDown();
+
+ setTimeout(function() {
+ $("#report-button").prop("disabled", false);
+ $("#report-cancel").prop("disabled", false);
+ $("#report-fail").slideUp();
+ }, 3000);
+ });
+ });
+}
+
+/**
+ * activate PB for site event handler
+ */
+function activateOnSite() {
+ $("#activate_site_btn").toggle();
+ $("#deactivate_site_btn").toggle();
+ $("#blockedResourcesContainer").show();
+
+ chrome.runtime.sendMessage({
+ type: "activateOnSite",
+ tabHost: POPUP_DATA.tabHost,
+ tabId: POPUP_DATA.tabId,
+ tabUrl: POPUP_DATA.tabUrl
+ }, () => {
+ chrome.tabs.reload(POPUP_DATA.tabId);
+ window.close();
+ });
+}
+
+/**
+ * de-activate PB for site event handler
+ */
+function deactivateOnSite() {
+ $("#activate_site_btn").toggle();
+ $("#deactivate_site_btn").toggle();
+ $("#blockedResourcesContainer").hide();
+
+ chrome.runtime.sendMessage({
+ type: "deactivateOnSite",
+ tabHost: POPUP_DATA.tabHost,
+ tabId: POPUP_DATA.tabId,
+ tabUrl: POPUP_DATA.tabUrl
+ }, () => {
+ chrome.tabs.reload(POPUP_DATA.tabId);
+ window.close();
+ });
+}
+
+/**
+ * Open the share overlay
+ */
+function share() {
+ $("#share_overlay").toggleClass('active');
+ let share_msg = chrome.i18n.getMessage("share_base_message");
+
+ // only add language about found trackers if we actually found trackers
+ // (but regardless of whether we are actually blocking them)
+ if (POPUP_DATA.noTabData) {
+ $("#share_output").val(share_msg);
+ return;
+ }
+
+ let origins = POPUP_DATA.origins;
+ let originsArr = [];
+ if (origins) {
+ originsArr = Object.keys(origins);
+ }
+
+ if (!originsArr.length) {
+ $("#share_output").val(share_msg);
+ return;
+ }
+
+ originsArr = htmlUtils.sortDomains(originsArr);
+ let tracking = [];
+
+ for (let origin of originsArr) {
+ let action = origins[origin];
+
+ if (action == constants.BLOCK || action == constants.COOKIEBLOCK) {
+ tracking.push(origin);
+ }
+ }
+
+ if (tracking.length) {
+ share_msg += "\n\n";
+ share_msg += chrome.i18n.getMessage(
+ "share_tracker_header", [tracking.length, POPUP_DATA.tabHost]);
+ share_msg += "\n\n";
+ share_msg += tracking.join("\n");
+ }
+ $("#share_output").val(share_msg);
+}
+
+/**
+ * Handler to undo user selection for a tracker
+ */
+function revertDomainControl(event) {
+ event.preventDefault();
+
+ let origin = $(event.target).parent().data('origin');
+
+ chrome.runtime.sendMessage({
+ type: "revertDomainControl",
+ origin: origin
+ }, () => {
+ chrome.tabs.reload(POPUP_DATA.tabId);
+ window.close();
+ });
+}
+
+/**
+ * Refresh the content of the popup window
+ *
+ * @param {Integer} tabId The id of the tab
+ */
+function refreshPopup() {
+ window.SLIDERS_DONE = false;
+
+ // must be a special browser page,
+ if (POPUP_DATA.noTabData) {
+ // show the "nothing to do here" message
+ $('#blockedResourcesContainer').hide();
+ $('#special-browser-page').show();
+
+ // hide inapplicable buttons
+ $('#deactivate_site_btn').hide();
+ $('#error').hide();
+
+ // activate tooltips
+ $('.tooltip').tooltipster();
+
+ window.SLIDERS_DONE = true;
+
+ return;
+ }
+
+ // revert any hiding/showing above for cases when refreshPopup gets called
+ // more than once for the same popup, such as during functional testing
+ $('#blockedResourcesContainer').show();
+ $('#special-browser-page').hide();
+ $('#deactivate_site_btn').show();
+ $('#error').show();
+
+ // toggle activation buttons if privacy badger is not enabled for current url
+ if (!POPUP_DATA.enabled) {
+ $("#blockedResourcesContainer").hide();
+ $("#activate_site_btn").show();
+ $("#deactivate_site_btn").hide();
+ $("#disabled-site-message").show();
+ $("#title").addClass("faded-bw-color-scheme");
+ }
+
+ // if there is any saved error text, fill the error input with it
+ if (POPUP_DATA.hasOwnProperty('errorText')) {
+ $("#error_input").val(POPUP_DATA.errorText);
+ }
+
+ let origins = POPUP_DATA.origins;
+ let originsArr = [];
+ if (origins) {
+ originsArr = Object.keys(origins);
+ }
+
+ if (!originsArr.length) {
+ // hide the number of trackers and slider instructions message
+ // if no sliders will be displayed
+ $("#instructions-many-trackers").hide();
+
+ // show "no trackers" message
+ $("#instructions-no-trackers").show();
+
+ if (POPUP_DATA.learnLocally && POPUP_DATA.showNonTrackingDomains) {
+ // show the "no third party resources on this site" message
+ $("#no-third-parties").show();
+ }
+
+ // activate tooltips
+ $('.tooltip').tooltipster();
+
+ window.SLIDERS_DONE = true;
+
+ return;
+ }
+
+ let printable = [];
+ let unblockedTrackers = [];
+ let nonTracking = [];
+ originsArr = htmlUtils.sortDomains(originsArr);
+
+ for (let origin of originsArr) {
+ let action = origins[origin];
+
+ if (action == constants.NO_TRACKING) {
+ nonTracking.push(origin);
+ } else if (action == constants.ALLOW) {
+ unblockedTrackers.push(origin);
+ } else {
+ let show_breakage_warning = (
+ action == constants.USER_BLOCK &&
+ POPUP_DATA.cookieblocked.hasOwnProperty(origin)
+ );
+ printable.push(
+ htmlUtils.getOriginHtml(origin, action, show_breakage_warning)
+ );
+ }
+ }
+
+ if (POPUP_DATA.learnLocally && unblockedTrackers.length) {
+ printable.push(
+ '<div class="clicker tooltip" id="not-yet-blocked-header" title="' +
+ chrome.i18n.getMessage("intro_not_an_adblocker_paragraph") +
+ '" data-tooltipster=\'{"side":"top"}\'>' +
+ chrome.i18n.getMessage("not_yet_blocked_header") +
+ '</div>'
+ );
+ unblockedTrackers.forEach(domain => {
+ printable.push(
+ htmlUtils.getOriginHtml(domain, constants.ALLOW)
+ );
+ });
+
+ // reduce margin if we have hasn't-decided-yet-to-block domains to show
+ $("#instructions-no-trackers").css("margin", "10px 0");
+ }
+
+ if (POPUP_DATA.learnLocally && POPUP_DATA.showNonTrackingDomains && nonTracking.length) {
+ printable.push(
+ '<div class="clicker tooltip" id="non-trackers-header" title="' +
+ chrome.i18n.getMessage("non_tracker_tip") +
+ '" data-tooltipster=\'{"side":"top"}\'>' +
+ chrome.i18n.getMessage("non_tracker") +
+ '</div>'
+ );
+ for (let i = 0; i < nonTracking.length; i++) {
+ printable.push(
+ htmlUtils.getOriginHtml(nonTracking[i], constants.NO_TRACKING)
+ );
+ }
+
+ // reduce margin if we have non-tracking domains to show
+ $("#instructions-no-trackers").css("margin", "10px 0");
+ }
+
+ if (printable.length) {
+ // get containing HTML for domain list along with toggle legend icons
+ $("#blockedResources")[0].innerHTML = htmlUtils.getTrackerContainerHtml();
+ }
+
+ // activate tooltips
+ $('.tooltip').tooltipster();
+
+ if (POPUP_DATA.trackerCount === 0) {
+ // hide multiple trackers message
+ $("#instructions-many-trackers").hide();
+
+ // show "no trackers" message
+ $("#instructions-no-trackers").show();
+
+ } else {
+ $('#instructions-many-trackers').html(chrome.i18n.getMessage(
+ "popup_instructions", [
+ POPUP_DATA.trackerCount,
+ "<a target='_blank' title='" + _.escape(chrome.i18n.getMessage("what_is_a_tracker")) + "' class='tooltip' href='https://privacybadger.org/#What-is-a-third-party-tracker'>"
+ ]
+ )).find(".tooltip").tooltipster();
+ }
+
+ function renderDomains() {
+ const CHUNK = 1;
+
+ let $printable = $(printable.splice(0, CHUNK).join(""));
+
+ // Hide elements for removing origins (controlled from the options page).
+ // Popup shows what's loaded for the current page so it doesn't make sense
+ // to have removal ability here.
+ $printable.find('.removeOrigin').hide();
+
+ $printable.appendTo('#blockedResourcesInner');
+
+ // activate tooltips
+ $('#blockedResourcesInner .tooltip:not(.tooltipstered)').tooltipster(
+ htmlUtils.DOMAIN_TOOLTIP_CONF);
+
+ if (printable.length) {
+ requestAnimationFrame(renderDomains);
+ } else {
+ window.SLIDERS_DONE = true;
+ }
+ }
+
+ if (printable.length) {
+ requestAnimationFrame(renderDomains);
+ } else {
+ window.SLIDERS_DONE = true;
+ }
+}
+
+/**
+ * Update the user preferences displayed in the domain list for this origin.
+ * These UI changes will later be used to update user preferences data.
+ *
+ * @param {Event} event Click event triggered by user.
+ */
+function updateOrigin() {
+ // get the origin and new action for it
+ let $radio = $(this),
+ action = $radio.val(),
+ $switchContainer = $radio.parents('.switch-container').first();
+
+ // update slider color via CSS
+ $switchContainer.removeClass([
+ constants.BLOCK,
+ constants.COOKIEBLOCK,
+ constants.ALLOW,
+ constants.NO_TRACKING].join(" ")).addClass(action);
+
+ let $clicker = $radio.parents('.clicker').first(),
+ origin = $clicker.data('origin'),
+ show_breakage_warning = (
+ action == constants.BLOCK &&
+ POPUP_DATA.cookieblocked.hasOwnProperty(origin)
+ );
+
+ htmlUtils.toggleBlockedStatus($clicker, true, show_breakage_warning);
+
+ // reinitialize the domain tooltip
+ $clicker.find('.origin-inner').tooltipster('destroy');
+ $clicker.find('.origin-inner').attr(
+ 'title', htmlUtils.getActionDescription(action, origin));
+ $clicker.find('.origin-inner').tooltipster(htmlUtils.DOMAIN_TOOLTIP_CONF);
+
+ // persist the change
+ saveToggle(origin, action);
+}
+
+/**
+ * Save the user setting for a domain by messaging the background page.
+ */
+function saveToggle(origin, action) {
+ chrome.runtime.sendMessage({
+ type: "savePopupToggle",
+ origin,
+ action,
+ tabId: POPUP_DATA.tabId
+ });
+}
+
+function getTab(callback) {
+ // Temporary fix for Firefox Android
+ if (!FirefoxAndroid.hasPopupSupport) {
+ FirefoxAndroid.getParentOfPopup(callback);
+ return;
+ }
+
+ chrome.tabs.query({active: true, lastFocusedWindow: true}, function(t) { callback(t[0]); });
+}
+
+/**
+ * Workaround for geckodriver being unable to modify page globals.
+ */
+function setPopupData(data) {
+ POPUP_DATA = data;
+}
+
+$(function () {
+ $.tooltipster.setDefaults(htmlUtils.TOOLTIPSTER_DEFAULTS);
+
+ getTab(function (tab) {
+ chrome.runtime.sendMessage({
+ type: "getPopupData",
+ tabId: tab.id,
+ tabUrl: tab.url
+ }, (response) => {
+ setPopupData(response);
+ refreshPopup();
+ init();
+ });
+ });
+});
diff --git a/src/js/socialwidgetloader.js b/src/js/socialwidgetloader.js
new file mode 100644
index 0000000..11f9bce
--- /dev/null
+++ b/src/js/socialwidgetloader.js
@@ -0,0 +1,133 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2014 Electronic Frontier Foundation
+ * Derived from ShareMeNot
+ * Copyright (C) 2011-2014 University of Washington
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * ShareMeNot is licensed under the MIT license:
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * Copyright (c) 2011-2014 University of Washington
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+/* globals log:false */
+
+require.scopes.widgetloader = (function () {
+
+let utils = require('utils');
+
+let exports = {
+ initializeWidgets,
+ loadWidgetsFromFile,
+};
+
+/**
+ * Returns the contents of the file at filePath.
+ *
+ * @param {String} filePath the path to the file
+ * @param {Function} callback callback(responseText)
+ */
+function getFileContents(filePath, callback) {
+ let url = chrome.runtime.getURL(filePath);
+ utils.xhrRequest(url, function (err, responseText) {
+ if (err) {
+ console.error(
+ "Problem fetching contents of file at",
+ filePath,
+ err.status,
+ err.message
+ );
+ } else {
+ callback(responseText);
+ }
+ });
+}
+
+/**
+ * @param {String} file_path the path to the JSON file
+ * @returns {Promise} resolved with an array of SocialWidget objects
+ */
+function loadWidgetsFromFile(file_path) {
+ return new Promise(function (resolve) {
+ getFileContents(file_path, function (contents) {
+ let widgets = initializeWidgets(JSON.parse(contents));
+ log("Initialized widgets from disk");
+ resolve(widgets);
+ });
+ });
+}
+
+/**
+ * @param {Object} widgetsJson widget data
+ * @returns {Array} array of SocialWidget objects
+ */
+function initializeWidgets(widgetsJson) {
+ let widgets = [];
+
+ // loop over each widget, making a SocialWidget object
+ for (let widget_name in widgetsJson) {
+ let widgetProperties = widgetsJson[widget_name];
+ let widget = new SocialWidget(widget_name, widgetProperties);
+ widgets.push(widget);
+ }
+
+ return widgets;
+}
+
+/**
+ * Constructs a SocialWidget with the given name and properties.
+ *
+ * @param {String} name the name of the socialwidget
+ * @param {Object} properties the properties of the socialwidget
+ */
+function SocialWidget(name, properties) {
+ let self = this;
+
+ self.name = name;
+
+ for (let property in properties) {
+ self[property] = properties[property];
+ }
+
+ // standardize on "domains"
+ if (self.domain) {
+ self.domains = [self.domain];
+ }
+}
+
+return exports;
+
+}()); //require scopes
diff --git a/src/js/storage.js b/src/js/storage.js
new file mode 100644
index 0000000..9074a41
--- /dev/null
+++ b/src/js/storage.js
@@ -0,0 +1,707 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2014 Electronic Frontier Foundation
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* globals badger:false, log:false */
+
+var constants = require("constants");
+var utils = require("utils");
+
+require.scopes.storage = (function() {
+
+
+/**
+ * # Storage Objects
+ *
+ * snitch_map is our collection of potential tracking base_domains.
+ * The key is a base domain (ETLD+1) and the value is an array of first
+ * party domains on which this tracker has been seen.
+ * it looks like this:
+ * {
+ * "third-party.com": ["a.com", "b.com", "c.com"],
+ * "eviltracker.net": ["eff.org", "a.com"]
+ * }
+ *
+ * action_map is where we store the action for each domain that we have
+ * decided on an action for. Each subdomain gets its own entry. For example:
+ * {
+ * "google.com": { heuristicAction: "block", dnt: false, userAction: ""}
+ * "fonts.google.com": { heuristicAction: "cookieblock", dnt: false, userAction: ""}
+ * "apis.google.com": { heuristicAction: "cookieblock", dnt: false, userAction: "user_block"}
+ * "widget.eff.org": { heuristicAction: "block", dnt: true, userAction: ""}
+ * }
+ *
+ * cookieblock_list is where we store the current yellowlist as
+ * downloaded from eff.org. The keys are the domains which should be "cookieblocked".
+ * The values are simply 'true'. For example:
+ * {
+ * "maps.google.com": true,
+ * "creativecommons.org": true,
+ * }
+ *
+ */
+
+function BadgerPen(callback) {
+ let self = this;
+
+ if (!callback) {
+ callback = function () {};
+ }
+
+ // initialize from extension local storage
+ chrome.storage.local.get(self.KEYS, function (store) {
+ self.KEYS.forEach(key => {
+ if (store.hasOwnProperty(key)) {
+ self[key] = new BadgerStorage(key, store[key]);
+ } else {
+ let storageObj = new BadgerStorage(key, {});
+ self[key] = storageObj;
+ _syncStorage(storageObj);
+ }
+ });
+
+ if (!chrome.storage.managed) {
+ callback(self);
+ return;
+ }
+
+ // see if we have any enterprise/admin/group policy overrides
+ chrome.storage.managed.get(null, function (managedStore) {
+ if (chrome.runtime.lastError) {
+ // ignore "Managed storage manifest not found" errors in Firefox
+ }
+
+ if (_.isObject(managedStore)) {
+ let settings = {};
+ for (let key in badger.defaultSettings) {
+ if (managedStore.hasOwnProperty(key)) {
+ settings[key] = managedStore[key];
+ }
+ }
+ self.settings_map.merge(settings);
+ }
+
+ callback(self);
+ });
+ });
+}
+
+BadgerPen.prototype = {
+ KEYS: [
+ "snitch_map",
+ "action_map",
+ "cookieblock_list",
+ "dnt_hashes",
+ "settings_map",
+ "private_storage", // misc. utility settings, not for export
+ ],
+
+ getStore: function (key) {
+ if (this.hasOwnProperty(key)) {
+ return this[key];
+ }
+ console.error("Can't initialize cache from getStore. You are using this API improperly");
+ },
+
+ /**
+ * Reset the snitch map and action map, forgetting all data the badger has
+ * learned from browsing.
+ */
+ clearTrackerData: function () {
+ let self = this;
+ ['snitch_map', 'action_map'].forEach(key => {
+ self.getStore(key).updateObject({});
+ });
+ },
+
+ /**
+ * Get the current presumed action for a specific fully qualified domain name (FQDN),
+ * ignoring any rules for subdomains below or above it
+ *
+ * @param {(Object|String)} domain domain object from action_map
+ * @param {Boolean} [ignoreDNT] whether to ignore DNT status
+ * @returns {String} the presumed action for this FQDN
+ */
+ getAction: function (domain, ignoreDNT) {
+ if (!badger.isCheckingDNTPolicyEnabled()) {
+ ignoreDNT = true;
+ }
+
+ if (_.isString(domain)) {
+ domain = this.getStore('action_map').getItem(domain) || {};
+ }
+ if (domain.userAction) { return domain.userAction; }
+ if (domain.dnt && !ignoreDNT) { return constants.DNT; }
+ if (domain.heuristicAction) { return domain.heuristicAction; }
+ return constants.NO_TRACKING;
+ },
+
+ touchDNTRecheckTime: function(domain, time) {
+ this._setupDomainAction(domain, time, "nextUpdateTime");
+ },
+
+ getNextUpdateForDomain: function(domain) {
+ var action_map = this.getStore('action_map');
+ if (action_map.hasItem(domain)) {
+ return action_map.getItem(domain).nextUpdateTime;
+ } else {
+ return 0;
+ }
+ },
+
+ /**
+ * Updates the yellowlist to the provided array of domains.
+ *
+ * For each added domain, sets it to be cookieblocked
+ * if its parent domain is set to be blocked.
+ *
+ * @param {Array} newDomains domains to use for the new yellowlist
+ */
+ updateYellowlist: function (newDomains) {
+ let self = this,
+ actionMap = self.getStore('action_map'),
+ ylistStorage = self.getStore('cookieblock_list'),
+ oldDomains = ylistStorage.keys();
+
+ let addedDomains = _.difference(newDomains, oldDomains),
+ removedDomains = _.difference(oldDomains, newDomains);
+
+ log('removing from cookie blocklist:', removedDomains);
+ removedDomains.forEach(function (domain) {
+ ylistStorage.deleteItem(domain);
+
+ const base = window.getBaseDomain(domain);
+ // "subdomains" include the domain itself
+ for (const subdomain of actionMap.keys()) {
+ if (window.getBaseDomain(subdomain) == base) {
+ if (self.getAction(subdomain) != constants.NO_TRACKING) {
+ badger.heuristicBlocking.blocklistOrigin(base, subdomain);
+ }
+ }
+ }
+ });
+
+ log('adding to cookie blocklist:', addedDomains);
+ addedDomains.forEach(function (domain) {
+ ylistStorage.setItem(domain, true);
+
+ const base = window.getBaseDomain(domain);
+ if (actionMap.hasItem(base)) {
+ const action = actionMap.getItem(base).heuristicAction;
+ // if the domain's base domain is marked for blocking
+ if (action == constants.BLOCK || action == constants.COOKIEBLOCK) {
+ // cookieblock the domain
+ self.setupHeuristicAction(domain, constants.COOKIEBLOCK);
+ }
+ }
+ });
+ },
+
+ /**
+ * Update DNT policy hashes
+ */
+ updateDntHashes: function (hashes) {
+ var dnt_hashes = this.getStore('dnt_hashes');
+ dnt_hashes.updateObject(_.invert(hashes));
+ },
+
+ /**
+ * Looks up whether an FQDN would get cookieblocked,
+ * ignoring user overrides and the FQDN's current status.
+ *
+ * @param {String} fqdn the FQDN we want to look up
+ *
+ * @return {Boolean}
+ */
+ wouldGetCookieblocked: function (fqdn) {
+ // cookieblock if a "parent" domain of the fqdn is on the yellowlist
+ let set = false,
+ ylistStorage = this.getStore('cookieblock_list'),
+ // ignore base domains when exploding to work around PSL TLDs:
+ // still want to cookieblock somedomain.googleapis.com with only
+ // googleapis.com (and not somedomain.googleapis.com itself) on the ylist
+ subdomains = utils.explodeSubdomains(fqdn, true);
+
+ for (let i = 0; i < subdomains.length; i++) {
+ if (ylistStorage.hasItem(subdomains[i])) {
+ set = true;
+ break;
+ }
+ }
+
+ return set;
+ },
+
+ /**
+ * Find the best action to take for an FQDN, assuming it is third party and
+ * Privacy Badger is enabled. Traverse the action list for the FQDN and each
+ * of its subdomains and then takes the most appropriate action
+ *
+ * @param {String} fqdn the FQDN we want to determine the action for
+ * @returns {String} the best action for the FQDN
+ */
+ getBestAction: function (fqdn) {
+ let best_action = constants.NO_TRACKING;
+ let subdomains = utils.explodeSubdomains(fqdn);
+ let action_map = this.getStore('action_map');
+
+ function getScore(action) {
+ switch (action) {
+ case constants.NO_TRACKING:
+ return 0;
+ case constants.ALLOW:
+ return 1;
+ case constants.BLOCK:
+ return 2;
+ case constants.COOKIEBLOCK:
+ return 3;
+ case constants.DNT:
+ return 4;
+ case constants.USER_ALLOW:
+ case constants.USER_BLOCK:
+ case constants.USER_COOKIEBLOCK:
+ return 5;
+ }
+ }
+
+ // Loop through each subdomain we have a rule for
+ // from least (base domain) to most (FQDN) specific
+ // and keep the one which has the best score.
+ for (let i = subdomains.length; i >= 0; i--) {
+ let domain = subdomains[i];
+ if (action_map.hasItem(domain)) {
+ let action = this.getAction(
+ action_map.getItem(domain),
+ // ignore DNT unless it's directly on the FQDN being checked
+ domain != fqdn
+ );
+ if (getScore(action) >= getScore(best_action)) {
+ best_action = action;
+ }
+ }
+ }
+
+ return best_action;
+ },
+
+ /**
+ * Find every domain in the action_map where the presumed action would be {selector}
+ *
+ * @param {String} selector the action to select by
+ * @return {Array} an array of FQDN strings
+ */
+ getAllDomainsByPresumedAction: function (selector) {
+ var action_map = this.getStore('action_map');
+ var relevantDomains = [];
+ for (var domain in action_map.getItemClones()) {
+ if (selector == this.getAction(domain)) {
+ relevantDomains.push(domain);
+ }
+ }
+ return relevantDomains;
+ },
+
+ /**
+ * Get all tracking domains from action_map.
+ *
+ * @return {Object} An object with domains as keys and actions as values.
+ */
+ getTrackingDomains: function () {
+ let action_map = this.getStore('action_map');
+ let origins = {};
+
+ for (let domain in action_map.getItemClones()) {
+ let action = badger.storage.getBestAction(domain);
+ if (action != constants.NO_TRACKING) {
+ origins[domain] = action;
+ }
+ }
+
+ return origins;
+ },
+
+ /**
+ * Set up an action for a domain of the given action type in action_map
+ *
+ * @param {String} domain the domain to set the action for
+ * @param {String} action the action to take e.g. BLOCK || COOKIEBLOCK || DNT
+ * @param {String} actionType the type of action we are setting, one of "userAction", "heuristicAction", "dnt"
+ * @private
+ */
+ _setupDomainAction: function (domain, action, actionType) {
+ let msg = "action_map['%s'].%s = %s",
+ action_map = this.getStore("action_map"),
+ actionObj = {};
+
+ if (action_map.hasItem(domain)) {
+ actionObj = action_map.getItem(domain);
+ msg = "Updating " + msg;
+ } else {
+ actionObj = _newActionMapObject();
+ msg = "Initializing " + msg;
+ }
+ actionObj[actionType] = action;
+
+ if (window.DEBUG) { // to avoid needless JSON.stringify calls
+ log(msg, domain, actionType, JSON.stringify(action));
+ }
+ action_map.setItem(domain, actionObj);
+ },
+
+ /**
+ * Add a heuristic action for a domain
+ *
+ * @param {String} domain Domain to add
+ * @param {String} action The heuristic action to take
+ */
+ setupHeuristicAction: function(domain, action) {
+ this._setupDomainAction(domain, action, "heuristicAction");
+ },
+
+ /**
+ * Set up a domain for DNT
+ *
+ * @param {String} domain Domain to add
+ */
+ setupDNT: function(domain) {
+ this._setupDomainAction(domain, true, "dnt");
+ },
+
+ /**
+ * Remove DNT setting from a domain*
+ * @param {String} domain FQDN string
+ */
+ revertDNT: function(domain) {
+ this._setupDomainAction(domain, false, "dnt");
+ },
+
+ /**
+ * Add a heuristic action for a domain
+ *
+ * @param {String} domain Domain to add
+ * @param {String} action The heuristic action to take
+ */
+ setupUserAction: function(domain, action) {
+ this._setupDomainAction(domain, action, "userAction");
+ },
+
+ /**
+ * Remove user set action from a domain
+ * @param {String} domain FQDN string
+ */
+ revertUserAction: function(domain) {
+ this._setupDomainAction(domain, "", "userAction");
+
+ // if Privacy Badger never recorded tracking for this domain,
+ // remove the domain's entry from Privacy Badger's database
+ const actionMap = this.getStore("action_map");
+ if (actionMap.getItem(domain).heuristicAction == "") {
+ log("Removing %s from action_map", domain);
+ actionMap.deleteItem(domain);
+ }
+ },
+
+ /**
+ * Removes a base domain and its subdomains from snitch and action maps.
+ * Preserves action map entries with user overrides.
+ *
+ * @param {String} base_domain
+ */
+ forget: function (base_domain) {
+ let self = this,
+ dot_base = '.' + base_domain,
+ actionMap = self.getStore('action_map'),
+ actions = actionMap.getItemClones(),
+ snitchMap = self.getStore('snitch_map');
+
+ if (snitchMap.getItem(base_domain)) {
+ log("Removing %s from snitch_map", base_domain);
+ badger.storage.getStore("snitch_map").deleteItem(base_domain);
+ }
+
+ for (let domain in actions) {
+ if (domain == base_domain || domain.endsWith(dot_base)) {
+ if (actions[domain].userAction == "") {
+ log("Removing %s from action_map", domain);
+ actionMap.deleteItem(domain);
+ }
+ }
+ }
+ }
+};
+
+/**
+ * @returns {{userAction: null, dnt: null, heuristicAction: null}}
+ * @private
+ */
+var _newActionMapObject = function() {
+ return {
+ userAction: "",
+ dnt: false,
+ heuristicAction: "",
+ nextUpdateTime: 0
+ };
+};
+
+/**
+ * Privacy Badger Storage Object. Has methods for getting, setting and deleting
+ * should be used for all storage needs, transparently handles data presistence
+ * syncing and private browsing.
+ * Usage:
+ * example_map = getStore('example_map');
+ * # instance of BadgerStorage
+ * example_map.setItem('foo', 'bar')
+ * # null
+ * example_map
+ * # { foo: "bar" }
+ * example_map.hasItem('foo')
+ * # true
+ * example_map.getItem('foo');
+ * # 'bar'
+ * example_map.getItem('not_real');
+ * # undefined
+ * example_map.deleteItem('foo');
+ * # null
+ * example_map.hasItem('foo');
+ * # false
+ *
+ */
+
+/**
+ * BadgerStorage constructor
+ * *DO NOT USE DIRECTLY* Instead call `getStore(name)`
+ * @param {String} name - the name of the storage object
+ * @param {Object} seed - the base object which we are instantiating from
+ */
+var BadgerStorage = function(name, seed) {
+ this.name = name;
+ this._store = seed;
+};
+
+BadgerStorage.prototype = {
+ /**
+ * Check if this storage object has an item
+ *
+ * @param {String} key - the key for the item
+ * @return {Boolean}
+ */
+ hasItem: function(key) {
+ var self = this;
+ return self._store.hasOwnProperty(key);
+ },
+
+ /**
+ * Get an item
+ *
+ * @param {String} key - the key for the item
+ * @return {?*} the value for that key or null
+ */
+ getItem: function(key) {
+ var self = this;
+ if (self.hasItem(key)) {
+ return self._store[key];
+ } else {
+ return null;
+ }
+ },
+
+ /**
+ * Get all items in the object as a copy
+ *
+ * @return {*} the items in badgerObject
+ */
+ getItemClones: function() {
+ var self = this;
+ return JSON.parse(JSON.stringify(self._store));
+ },
+
+ /**
+ * Set an item
+ *
+ * @param {String} key - the key for the item
+ * @param {*} value - the new value
+ */
+ setItem: function(key,value) {
+ var self = this;
+ self._store[key] = value;
+ // Async call to syncStorage.
+ setTimeout(function() {
+ _syncStorage(self);
+ }, 0);
+ },
+
+ /**
+ * Delete an item
+ *
+ * @param {String} key - the key for the item
+ */
+ deleteItem: function(key) {
+ var self = this;
+ delete self._store[key];
+ // Async call to syncStorage.
+ setTimeout(function() {
+ _syncStorage(self);
+ }, 0);
+ },
+
+ /**
+ * Update the entire object that this instance is storing
+ */
+ updateObject: function(object) {
+ var self = this;
+ self._store = object;
+ // Async call to syncStorage.
+ setTimeout(function() {
+ _syncStorage(self);
+ }, 0);
+ },
+
+ /**
+ * @returns {Array} this storage object's store keys
+ */
+ keys: function () {
+ return Object.keys(this._store);
+ },
+
+ /**
+ * When a user imports a tracker and settings list via the Import function,
+ * we want to overwrite any existing settings, while simultaneously merging
+ * in any new information (i.e. the list of disabled site domains). In order
+ * to do this, we need different logic for each of the storage maps based on
+ * their internal structure. The three cases in this function handle each of
+ * the three storage maps that can be exported.
+ *
+ * @param {Object} mapData The object containing storage map data to merge
+ */
+ merge: function (mapData) {
+ const self = this;
+
+ if (self.name == "settings_map") {
+ for (let prop in mapData) {
+ // combine array settings via intersection/union
+ if (prop == "disabledSites" || prop == "widgetReplacementExceptions") {
+ self._store[prop] = _.union(self._store[prop], mapData[prop]);
+
+ // string/array map
+ } else if (prop == "widgetSiteAllowlist") {
+ // for every site host in the import
+ for (let site in mapData[prop]) {
+ // combine exception arrays
+ self._store[prop][site] = _.union(
+ self._store[prop][site],
+ mapData[prop][site]
+ );
+ }
+
+ // default: overwrite existing setting with setting from import
+ } else {
+ if (prop != "isFirstRun") {
+ self._store[prop] = mapData[prop];
+ }
+ }
+ }
+
+ } else if (self.name == "action_map") {
+ for (let domain in mapData) {
+ let action = mapData[domain];
+
+ // Copy over any user settings from the merged-in data
+ if (action.userAction) {
+ if (self._store.hasOwnProperty(domain)) {
+ self._store[domain].userAction = action.userAction;
+ } else {
+ self._store[domain] = Object.assign(_newActionMapObject(), action);
+ }
+ }
+
+ // handle Do Not Track
+ if (self._store.hasOwnProperty(domain)) {
+ // Merge DNT settings if the imported data has a more recent update
+ if (action.nextUpdateTime > self._store[domain].nextUpdateTime) {
+ self._store[domain].nextUpdateTime = action.nextUpdateTime;
+ self._store[domain].dnt = action.dnt;
+ }
+ } else {
+ // Import action map entries for new DNT-compliant domains
+ if (action.dnt) {
+ self._store[domain] = Object.assign(_newActionMapObject(), action);
+ }
+ }
+ }
+
+ } else if (self.name == "snitch_map") {
+ for (let tracker_origin in mapData) {
+ let firstPartyOrigins = mapData[tracker_origin];
+ for (let i = 0; i < firstPartyOrigins.length; i++) {
+ badger.heuristicBlocking.updateTrackerPrevalence(
+ tracker_origin,
+ tracker_origin,
+ firstPartyOrigins[i]
+ );
+ }
+ }
+ }
+
+ // Async call to syncStorage.
+ setTimeout(function () {
+ _syncStorage(self);
+ }, 0);
+ }
+};
+
+var _syncStorage = (function () {
+ var debouncedFuncs = {};
+
+ function cb() {
+ if (chrome.runtime.lastError) {
+ let err = chrome.runtime.lastError.message;
+ if (!err.startsWith("IO error:") && !err.startsWith("Corruption:")
+ && !err.startsWith("InvalidStateError:") && !err.startsWith("AbortError:")
+ && !err.startsWith("QuotaExceededError:")
+ ) {
+ badger.criticalError = err;
+ }
+ console.error("Error writing to chrome.storage.local:", err);
+ }
+ }
+
+ function sync(badgerStorage) {
+ var obj = {};
+ obj[badgerStorage.name] = badgerStorage._store;
+ chrome.storage.local.set(obj, cb);
+ }
+
+ // Creates debounced versions of "sync" function,
+ // one for each distinct badgerStorage value.
+ return function (badgerStorage) {
+ if (!debouncedFuncs.hasOwnProperty(badgerStorage.name)) {
+ // call sync at most once every two seconds
+ debouncedFuncs[badgerStorage.name] = _.debounce(function () {
+ sync(badgerStorage);
+ }, 2000);
+ }
+ debouncedFuncs[badgerStorage.name]();
+ };
+}());
+
+/************************************** exports */
+var exports = {};
+
+exports.BadgerPen = BadgerPen;
+
+return exports;
+/************************************** exports */
+}());
diff --git a/src/js/surrogates.js b/src/js/surrogates.js
new file mode 100644
index 0000000..5389afd
--- /dev/null
+++ b/src/js/surrogates.js
@@ -0,0 +1,87 @@
+/*
+ *
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2016 Electronic Frontier Foundation
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+require.scopes.surrogates = (function() {
+
+const db = require('surrogatedb');
+
+/**
+ * Blocking tracking scripts (trackers) can cause parts of webpages to break.
+ * Surrogate scripts are dummy pieces of JavaScript meant to supply just enough
+ * of the original tracker's functionality to allow pages to continue working.
+ *
+ * This method gets called within request-blocking listeners:
+ * It needs to be fast!
+ *
+ * @param {String} script_url The full URL of the script resource being requested.
+ *
+ * @param {String} script_hostname The hostname component of the script_url
+ * parameter. This is an optimization: the calling context should already have
+ * this information.
+ *
+ * @return {(String|Boolean)} The surrogate script as a data URI when there is a
+ * match, or boolean false when there is no match.
+ */
+function getSurrogateURI(script_url, script_hostname) {
+ // do we have an entry for the script hostname?
+ if (db.hostnames.hasOwnProperty(script_hostname)) {
+ const tokens = db.hostnames[script_hostname];
+
+ // it's a wildcard token
+ if (_.isString(tokens)) {
+ if (db.surrogates.hasOwnProperty(tokens)) {
+ // return the surrogate code
+ return 'data:application/javascript;base64,' + btoa(db.surrogates[tokens]);
+ }
+ }
+
+ // must be an array of suffix tokens
+ const qs_start = script_url.indexOf('?');
+
+ for (let i = 0; i < tokens.length; i++) {
+ // do any of the suffix tokens match the script URL?
+ const token = tokens[i];
+
+ let match = false;
+
+ if (qs_start == -1) {
+ if (script_url.endsWith(token)) {
+ match = true;
+ }
+ } else {
+ if (script_url.endsWith(token, qs_start)) {
+ match = true;
+ }
+ }
+
+ if (match) {
+ // there is a match, return the surrogate code
+ return 'data:application/javascript;base64,' + btoa(db.surrogates[token]);
+ }
+ }
+ }
+
+ return false;
+}
+
+const exports = {
+ getSurrogateURI: getSurrogateURI,
+};
+
+return exports;
+})();
diff --git a/src/js/utils.js b/src/js/utils.js
new file mode 100644
index 0000000..1072935
--- /dev/null
+++ b/src/js/utils.js
@@ -0,0 +1,445 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2014 Electronic Frontier Foundation
+ *
+ * Derived from Adblock Plus
+ * Copyright (C) 2006-2013 Eyeo GmbH
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* globals URI:false */
+
+require.scopes.utils = (function() {
+
+let mdfp = require("multiDomainFP");
+
+/**
+ * Generic interface to make an XHR request
+ *
+ * @param {String} url The url to get
+ * @param {Function} callback The callback to call after request has finished
+ * @param {String} method GET/POST
+ * @param {Object} opts XMLHttpRequest options
+ */
+function xhrRequest(url, callback, method, opts) {
+ if (!method) {
+ method = "GET";
+ }
+ if (!opts) {
+ opts = {};
+ }
+
+ let xhr = new XMLHttpRequest();
+
+ for (let key in opts) {
+ if (opts.hasOwnProperty(key)) {
+ xhr[key] = opts[key];
+ }
+ }
+
+ xhr.onload = function () {
+ if (xhr.status == 200) {
+ callback(null, xhr.response);
+ } else {
+ let error = {
+ status: xhr.status,
+ message: xhr.response,
+ object: xhr
+ };
+ callback(error, error.message);
+ }
+ };
+
+ // triggered by network problems
+ xhr.onerror = function () {
+ callback({ status: 0, message: "", object: xhr }, "");
+ };
+
+ xhr.open(method, url, true);
+ xhr.send();
+}
+
+/**
+ * Converts binary data to base64-encoded text suitable for use in data URIs.
+ *
+ * Adapted from https://stackoverflow.com/a/9458996.
+ *
+ * @param {ArrayBuffer} buffer binary data
+ *
+ * @returns {String} base64-encoded text
+ */
+function arrayBufferToBase64(buffer) {
+ var binary = '';
+ var bytes = new Uint8Array(buffer);
+ var len = bytes.byteLength;
+ for (var i = 0; i < len; i++) {
+ binary += String.fromCharCode(bytes[i]);
+ }
+ return btoa(binary);
+}
+
+/**
+ * Return an array of all subdomains in an FQDN, ordered from the FQDN to the
+ * eTLD+1. e.g. [a.b.eff.org, b.eff.org, eff.org]
+ * if 'all' is passed in then the array will include all domain levels, not
+ * just down to the base domain
+ * @param {String} fqdn the domain to split
+ * @param {boolean} all whether to include all domain levels
+ * @returns {Array} the subdomains
+ */
+function explodeSubdomains(fqdn, all) {
+ var baseDomain;
+ if (all) {
+ baseDomain = fqdn.split('.').pop();
+ } else {
+ baseDomain = window.getBaseDomain(fqdn);
+ }
+ var baseLen = baseDomain.split('.').length;
+ var parts = fqdn.split('.');
+ var numLoops = parts.length - baseLen;
+ var subdomains = [];
+ for (var i=0; i<=numLoops; i++) {
+ subdomains.push(parts.slice(i).join('.'));
+ }
+ return subdomains;
+}
+
+/*
+ * Estimates the max possible entropy of string.
+ *
+ * @param {String} str the string to compute entropy for
+ * @returns {Integer} bits of entropy
+ */
+function estimateMaxEntropy(str) {
+ // Don't process strings longer than MAX_LS_LEN_FOR_ENTROPY_EST.
+ // Note that default quota for local storage is 5MB and
+ // storing fonts, scripts or images in for local storage for
+ // performance is not uncommon. We wouldn't want to estimate entropy
+ // for 5M chars.
+ const MAX_LS_LEN_FOR_ENTROPY_EST = 256;
+
+ // common classes of characters that a string might belong to
+ const SEPS = "._-x";
+ const BIN = "01";
+ const DEC = "0123456789";
+
+ // these classes are case-insensitive
+ const HEX = "abcdef" + DEC;
+ const ALPHA = "abcdefghijklmnopqrstuvwxyz";
+ const ALPHANUM = ALPHA + DEC;
+
+ // these classes are case-sensitive
+ const B64 = ALPHANUM + ALPHA.toUpperCase() + "/+";
+ const URL = ALPHANUM + ALPHA.toUpperCase() + "~%";
+
+ if (str.length > MAX_LS_LEN_FOR_ENTROPY_EST) {
+ // Just return a higher-than-threshold entropy estimate.
+ // We assume 1 bit per char, which will be well over the
+ // threshold (33 bits).
+ return str.length;
+ }
+
+ let max_symbols;
+
+ // If all characters are upper or lower case, don't consider case when
+ // computing entropy.
+ let sameCase = (str.toLowerCase() == str) || (str.toUpperCase() == str);
+ if (sameCase) {
+ str = str.toLowerCase();
+ }
+
+ // If all the characters come from one of these common character groups,
+ // assume that the group is the domain of possible characters.
+ for (let chr_class of [BIN, DEC, HEX, ALPHA, ALPHANUM, B64, URL]) {
+ let group = chr_class + SEPS;
+ // Ignore separator characters when computing entropy. For example, Google
+ // Analytics IDs look like "14103492.1964907".
+
+ // flag to check if each character of input string belongs to the group in question
+ let each_char_in_group = true;
+
+ for (let ch of str) {
+ if (!group.includes(ch)) {
+ each_char_in_group = false;
+ break;
+ }
+ }
+
+ // if the flag resolves to true, we've found our culprit and can break out of the loop
+ if (each_char_in_group) {
+ max_symbols = chr_class.length;
+ break;
+ }
+ }
+
+ // If there's not an obvious class of characters, use the heuristic
+ // "max char code - min char code"
+ if (!max_symbols) {
+ let charCodes = Array.prototype.map.call(str, function (ch) {
+ return String.prototype.charCodeAt.apply(ch);
+ });
+ let min_char_code = Math.min.apply(Math, charCodes);
+ let max_char_code = Math.max.apply(Math, charCodes);
+ max_symbols = max_char_code - min_char_code + 1;
+ }
+
+ // the entropy is (entropy per character) * (number of characters)
+ let max_bits = (Math.log(max_symbols) / Math.LN2) * str.length;
+
+ return max_bits;
+}
+
+function oneSecond() {
+ return 1000;
+}
+
+function oneMinute() {
+ return oneSecond() * 60;
+}
+
+function oneHour() {
+ return oneMinute() * 60;
+}
+
+function oneDay() {
+ return oneHour() * 24;
+}
+
+function nDaysFromNow(n) {
+ return Date.now() + (oneDay() * n);
+}
+
+function oneDayFromNow() {
+ return nDaysFromNow(1);
+}
+
+/**
+ * Creates a rate-limited function that delays invoking `fn` until after
+ * `interval` milliseconds have elapsed since the last time the rate-limited
+ * function was invoked.
+ *
+ * Does not drop invocations (lossless), unlike `_.throttle`.
+ *
+ * Adapted from
+ * http://stackoverflow.com/questions/23072815/throttle-javascript-function-calls-but-with-queuing-dont-discard-calls
+ *
+ * @param {Function} fn The function to rate-limit.
+ * @param {number} interval The number of milliseconds to rate-limit invocations to.
+ * @param {Object} context The context object (optional).
+ * @returns {Function} Returns the new rate-limited function.
+ */
+function rateLimit(fn, interval, context) {
+ let canInvoke = true,
+ queue = [],
+ timer_id,
+ limited = function () {
+ queue.push({
+ context: context || this,
+ arguments: Array.prototype.slice.call(arguments)
+ });
+ if (canInvoke) {
+ canInvoke = false;
+ timeEnd();
+ }
+ };
+
+ function timeEnd() {
+ let item;
+ if (queue.length) {
+ item = queue.splice(0, 1)[0];
+ fn.apply(item.context, item.arguments); // invoke fn
+ timer_id = window.setTimeout(timeEnd, interval);
+ } else {
+ canInvoke = true;
+ }
+ }
+
+ // useful for debugging
+ limited.cancel = function () {
+ window.clearTimeout(timer_id);
+ queue = [];
+ canInvoke = true;
+ };
+
+ return limited;
+}
+
+function buf2hex(buffer) { // buffer is an ArrayBuffer
+ return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
+}
+
+function sha1(input, callback) {
+ return window.crypto.subtle.digest(
+ { name: "SHA-1", },
+ new TextEncoder().encode(input)
+ ).then(hashed => {
+ return callback(buf2hex(hashed));
+ });
+}
+
+function parseCookie(str, opts) {
+ if (!str) {
+ return {};
+ }
+
+ opts = opts || {};
+
+ let COOKIE_ATTRIBUTES = [
+ "domain",
+ "expires",
+ "httponly",
+ "max-age",
+ "path",
+ "samesite",
+ "secure",
+ ];
+
+ let parsed = {},
+ cookies = str.replace(/\n/g, ";").split(";");
+
+ for (let i = 0; i < cookies.length; i++) {
+ let cookie = cookies[i],
+ name,
+ value,
+ cut = cookie.indexOf("=");
+
+ // it's a key=value pair
+ if (cut != -1) {
+ name = cookie.slice(0, cut).trim();
+ value = cookie.slice(cut + 1).trim();
+
+ // handle value quoting
+ if (value[0] == '"') {
+ value = value.slice(1, -1);
+ }
+
+ // not a key=value pair
+ } else {
+ if (opts.skipNonValues) {
+ continue;
+ }
+ name = cookie.trim();
+ value = "";
+ }
+
+ if (opts.skipAttributes &&
+ COOKIE_ATTRIBUTES.indexOf(name.toLowerCase()) != -1) {
+ continue;
+ }
+
+ if (!opts.noDecode) {
+ let decode = opts.decode || decodeURIComponent;
+ try {
+ name = decode(name);
+ } catch (e) {
+ // invalid URL encoding probably (URIError: URI malformed)
+ if (opts.skipInvalid) {
+ continue;
+ }
+ }
+ if (value) {
+ try {
+ value = decode(value);
+ } catch (e) {
+ // ditto
+ if (opts.skipInvalid) {
+ continue;
+ }
+ }
+ }
+ }
+
+ if (!opts.noOverwrite || !parsed.hasOwnProperty(name)) {
+ parsed[name] = value;
+ }
+ }
+
+ return parsed;
+}
+
+function getHostFromDomainInput(input) {
+ if (!input.startsWith("http")) {
+ input = "http://" + input;
+ }
+
+ if (!input.endsWith("/")) {
+ input += "/";
+ }
+
+ try {
+ var uri = new URI(input);
+ } catch (err) {
+ return false;
+ }
+
+ return uri.host;
+}
+
+/**
+ * check if a domain is third party
+ * @param {String} domain1 an fqdn
+ * @param {String} domain2 a second fqdn
+ *
+ * @return {Boolean} true if the domains are third party
+ */
+function isThirdPartyDomain(domain1, domain2) {
+ if (window.isThirdParty(domain1, domain2)) {
+ return !mdfp.isMultiDomainFirstParty(
+ window.getBaseDomain(domain1),
+ window.getBaseDomain(domain2)
+ );
+ }
+ return false;
+}
+
+
+/**
+ * Checks whether a given URL is a special browser page.
+ * TODO account for browser-specific pages:
+ * https://github.com/hackademix/noscript/blob/a8b35486571933043bb62e90076436dff2a34cd2/src/lib/restricted.js
+ *
+ * @param {String} url
+ *
+ * @return {Boolean} whether the URL is restricted
+ */
+function isRestrictedUrl(url) {
+ // permitted schemes from
+ // https://developer.chrome.com/extensions/match_patterns
+ return !(
+ url.startsWith('http') || url.startsWith('file') || url.startsWith('ftp')
+ );
+}
+
+/************************************** exports */
+let exports = {
+ arrayBufferToBase64,
+ estimateMaxEntropy,
+ explodeSubdomains,
+ getHostFromDomainInput,
+ isRestrictedUrl,
+ isThirdPartyDomain,
+ nDaysFromNow,
+ oneDay,
+ oneDayFromNow,
+ oneHour,
+ oneMinute,
+ oneSecond,
+ parseCookie,
+ rateLimit,
+ sha1,
+ xhrRequest,
+};
+return exports;
+/************************************** exports */
+})(); //require scopes
diff --git a/src/js/webrequest.js b/src/js/webrequest.js
new file mode 100644
index 0000000..bb7469b
--- /dev/null
+++ b/src/js/webrequest.js
@@ -0,0 +1,1293 @@
+/*
+ *
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2016 Electronic Frontier Foundation
+ *
+ * Derived from Adblock Plus
+ * Copyright (C) 2006-2013 Eyeo GmbH
+ *
+ * Derived from Chameleon <https://github.com/ghostwords/chameleon>
+ * Copyright (C) 2015 ghostwords
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* globals badger:false, log:false */
+
+require.scopes.webrequest = (function () {
+
+/*********************** webrequest scope **/
+
+let constants = require("constants"),
+ getSurrogateURI = require("surrogates").getSurrogateURI,
+ incognito = require("incognito"),
+ utils = require("utils");
+
+/************ Local Variables *****************/
+let tempAllowlist = {};
+
+/***************** Blocking Listener Functions **************/
+
+/**
+ * Event handling of http requests, main logic to collect data what to block
+ *
+ * @param {Object} details The event details
+ * @returns {Object} Can cancel requests
+ */
+function onBeforeRequest(details) {
+ let frame_id = details.frameId,
+ tab_id = details.tabId,
+ type = details.type,
+ url = details.url;
+
+ if (type == "main_frame") {
+ let oldTabData = badger.getFrameData(tab_id),
+ is_reload = oldTabData && oldTabData.url == url;
+ forgetTab(tab_id, is_reload);
+ badger.recordFrame(tab_id, frame_id, url);
+ initializeAllowedWidgets(tab_id, badger.getFrameData(tab_id).host);
+ return {};
+ }
+
+ if (type == "sub_frame") {
+ badger.recordFrame(tab_id, frame_id, url);
+ }
+
+ // Block ping requests sent by navigator.sendBeacon (see, #587)
+ // tabId for pings are always -1 due to Chrome bugs #522124 and #522129
+ // Once these bugs are fixed, PB will treat pings as any other request
+ if (type == "ping" && tab_id < 0) {
+ return {cancel: true};
+ }
+
+ if (_isTabChromeInternal(tab_id)) {
+ return {};
+ }
+
+ let tab_host = getHostForTab(tab_id);
+ let request_host = window.extractHostFromURL(url);
+
+ if (!utils.isThirdPartyDomain(request_host, tab_host)) {
+ return {};
+ }
+
+ let action = checkAction(tab_id, request_host, frame_id);
+ if (!action) {
+ return {};
+ }
+
+ badger.logThirdPartyOriginOnTab(tab_id, request_host, action);
+
+ if (!badger.isPrivacyBadgerEnabled(tab_host)) {
+ return {};
+ }
+
+ if (action != constants.BLOCK && action != constants.USER_BLOCK) {
+ return {};
+ }
+
+ if (type == 'script') {
+ let surrogate = getSurrogateURI(url, request_host);
+ if (surrogate) {
+ return {redirectUrl: surrogate};
+ }
+ }
+
+ // notify the widget replacement content script
+ chrome.tabs.sendMessage(tab_id, {
+ replaceWidget: true,
+ trackerDomain: request_host
+ });
+
+ // if this is a heuristically- (not user-) blocked domain
+ if (action == constants.BLOCK && incognito.learningEnabled(tab_id)) {
+ // check for DNT policy asynchronously
+ setTimeout(function () {
+ badger.checkForDNTPolicy(request_host);
+ }, 0);
+ }
+
+ if (type == 'sub_frame') {
+ setTimeout(function () {
+ hideBlockedFrame(tab_id, details.parentFrameId, url, request_host);
+ }, 0);
+ }
+
+ return {cancel: true};
+}
+
+/**
+ * Filters outgoing cookies and referer
+ * Injects DNT
+ *
+ * @param {Object} details Event details
+ * @returns {Object} modified headers
+ */
+function onBeforeSendHeaders(details) {
+ let frame_id = details.frameId,
+ tab_id = details.tabId,
+ type = details.type,
+ url = details.url;
+
+ if (_isTabChromeInternal(tab_id)) {
+ // DNT policy requests: strip cookies
+ if (type == "xmlhttprequest" && url.endsWith("/.well-known/dnt-policy.txt")) {
+ // remove Cookie headers
+ let newHeaders = [];
+ for (let i = 0, count = details.requestHeaders.length; i < count; i++) {
+ let header = details.requestHeaders[i];
+ if (header.name.toLowerCase() != "cookie") {
+ newHeaders.push(header);
+ }
+ }
+ return {
+ requestHeaders: newHeaders
+ };
+ }
+
+ return {};
+ }
+
+ let tab_host = getHostForTab(tab_id);
+ let request_host = window.extractHostFromURL(url);
+
+ if (!utils.isThirdPartyDomain(request_host, tab_host)) {
+ if (badger.isPrivacyBadgerEnabled(tab_host)) {
+ // Still sending Do Not Track even if HTTP and cookie blocking are disabled
+ if (badger.isDNTSignalEnabled()) {
+ details.requestHeaders.push({name: "DNT", value: "1"}, {name: "Sec-GPC", value: "1"});
+ }
+ return {requestHeaders: details.requestHeaders};
+ } else {
+ return {};
+ }
+ }
+
+ let action = checkAction(tab_id, request_host, frame_id);
+
+ if (action) {
+ badger.logThirdPartyOriginOnTab(tab_id, request_host, action);
+ }
+
+ if (!badger.isPrivacyBadgerEnabled(tab_host)) {
+ return {};
+ }
+
+ // handle cookieblocked requests
+ if (action == constants.COOKIEBLOCK || action == constants.USER_COOKIEBLOCK) {
+ let newHeaders;
+
+ // GET requests: remove cookie headers, reduce referrer header to origin
+ if (details.method == "GET") {
+ newHeaders = details.requestHeaders.filter(header => {
+ return (header.name.toLowerCase() != "cookie");
+ }).map(header => {
+ if (header.name.toLowerCase() == "referer") {
+ header.value = header.value.slice(
+ 0,
+ header.value.indexOf('/', header.value.indexOf('://') + 3)
+ ) + '/';
+ }
+ return header;
+ });
+
+ // remove cookie and referrer headers otherwise
+ } else {
+ newHeaders = details.requestHeaders.filter(header => {
+ return (header.name.toLowerCase() != "cookie" && header.name.toLowerCase() != "referer");
+ });
+ }
+
+ // add DNT header
+ if (badger.isDNTSignalEnabled()) {
+ newHeaders.push({name: "DNT", value: "1"}, {name: "Sec-GPC", value: "1"});
+ }
+
+ return {requestHeaders: newHeaders};
+ }
+
+ // if we are here, we're looking at a third-party request
+ // that's not yet blocked or cookieblocked
+ if (badger.isDNTSignalEnabled()) {
+ details.requestHeaders.push({name: "DNT", value: "1"}, {name: "Sec-GPC", value: "1"});
+ }
+ return {requestHeaders: details.requestHeaders};
+}
+
+/**
+ * Filters incoming cookies out of the response header
+ *
+ * @param {Object} details The event details
+ * @returns {Object} The new response headers
+ */
+function onHeadersReceived(details) {
+ let tab_id = details.tabId,
+ url = details.url;
+
+ if (_isTabChromeInternal(tab_id)) {
+ // DNT policy responses: strip cookies, reject redirects
+ if (details.type == "xmlhttprequest" && url.endsWith("/.well-known/dnt-policy.txt")) {
+ // if it's a redirect, cancel it
+ if (details.statusCode >= 300 && details.statusCode < 400) {
+ return {
+ cancel: true
+ };
+ }
+
+ // remove Set-Cookie headers
+ let headers = details.responseHeaders,
+ newHeaders = [];
+ for (let i = 0, count = headers.length; i < count; i++) {
+ if (headers[i].name.toLowerCase() != "set-cookie") {
+ newHeaders.push(headers[i]);
+ }
+ }
+ return {
+ responseHeaders: newHeaders
+ };
+ }
+
+ return {};
+ }
+
+ let tab_host = getHostForTab(tab_id);
+ let response_host = window.extractHostFromURL(url);
+
+ if (!utils.isThirdPartyDomain(response_host, tab_host)) {
+ return {};
+ }
+
+ let action = checkAction(tab_id, response_host, details.frameId);
+ if (!action) {
+ return {};
+ }
+
+ badger.logThirdPartyOriginOnTab(tab_id, response_host, action);
+
+ if (!badger.isPrivacyBadgerEnabled(tab_host)) {
+ return {};
+ }
+
+ if (action == constants.COOKIEBLOCK || action == constants.USER_COOKIEBLOCK) {
+ let newHeaders = details.responseHeaders.filter(function(header) {
+ return (header.name.toLowerCase() != "set-cookie");
+ });
+ return {responseHeaders: newHeaders};
+ }
+}
+
+/*************** Non-blocking listener functions ***************/
+
+/**
+ * Event handler when a tab gets removed
+ *
+ * @param {Integer} tabId Id of the tab
+ */
+function onTabRemoved(tabId) {
+ forgetTab(tabId);
+}
+
+/**
+ * Update internal db on tabs when a tab gets replaced
+ * due to prerendering or instant search.
+ *
+ * @param {Integer} addedTabId The new tab id that replaces
+ * @param {Integer} removedTabId The tab id that gets removed
+ */
+function onTabReplaced(addedTabId, removedTabId) {
+ forgetTab(removedTabId);
+ // Update the badge of the added tab, which was probably used for prerendering.
+ badger.updateBadge(addedTabId);
+}
+
+/**
+ * We don't always get a "main_frame" details object in onBeforeRequest,
+ * so we need a fallback for (re)initializing tabData.
+ */
+function onNavigate(details) {
+ const tab_id = details.tabId,
+ url = details.url;
+
+ // main (top-level) frames only
+ if (details.frameId !== 0) {
+ return;
+ }
+
+ let oldTabData = badger.getFrameData(tab_id),
+ is_reload = oldTabData && oldTabData.url == url;
+
+ forgetTab(tab_id, is_reload);
+
+ // forget but don't initialize on special browser/extension pages
+ if (utils.isRestrictedUrl(url)) {
+ return;
+ }
+
+ badger.recordFrame(tab_id, 0, url);
+
+ let tab_host = badger.getFrameData(tab_id).host;
+
+ initializeAllowedWidgets(tab_id, tab_host);
+
+ // initialize tab data bookkeeping used by heuristicBlockingAccounting()
+ // to avoid missing or misattributing learning
+ // when there is no "main_frame" webRequest callback
+ // (such as on Service Worker pages)
+ //
+ // see the tabOrigins TODO in heuristicblocking.js
+ // as to why we don't just use tabData
+ let base = window.getBaseDomain(tab_host);
+ badger.heuristicBlocking.tabOrigins[tab_id] = base;
+ badger.heuristicBlocking.tabUrls[tab_id] = url;
+}
+
+/******** Utility Functions **********/
+
+/**
+ * Messages collapser.js content script to hide blocked frames.
+ */
+function hideBlockedFrame(tab_id, parent_frame_id, frame_url, frame_host) {
+ // don't hide if hiding is disabled
+ if (!badger.getSettings().getItem('hideBlockedElements')) {
+ return;
+ }
+
+ // don't hide widget frames
+ if (badger.isWidgetReplacementEnabled()) {
+ let exceptions = badger.getSettings().getItem('widgetReplacementExceptions');
+ for (let widget of badger.widgetList) {
+ if (exceptions.includes(widget.name)) {
+ continue;
+ }
+ for (let domain of widget.domains) {
+ if (domain == frame_host) {
+ return;
+ } else if (domain[0] == "*") { // leading wildcard domain
+ if (frame_host.endsWith(domain.slice(1))) {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ // message content script
+ chrome.tabs.sendMessage(tab_id, {
+ hideFrame: true,
+ url: frame_url
+ }, {
+ frameId: parent_frame_id
+ }, function (response) {
+ if (response) {
+ // content script was ready and received our message
+ return;
+ }
+ // content script was not ready
+ if (chrome.runtime.lastError) {
+ // ignore
+ }
+ // record frame_url and parent_frame_id
+ // for when content script becomes ready
+ let tabData = badger.tabData[tab_id];
+ if (!tabData.blockedFrameUrls.hasOwnProperty(parent_frame_id)) {
+ tabData.blockedFrameUrls[parent_frame_id] = [];
+ }
+ tabData.blockedFrameUrls[parent_frame_id].push(frame_url);
+ });
+}
+
+/**
+ * Gets the host name for a given tab id
+ * @param {Integer} tabId chrome tab id
+ * @return {String} the host name for the tab
+ */
+function getHostForTab(tabId) {
+ let mainFrameIdx = 0;
+ if (!badger.tabData[tabId]) {
+ return '';
+ }
+ // TODO what does this actually do?
+ // meant to address https://github.com/EFForg/privacybadger/issues/136
+ if (_isTabAnExtension(tabId)) {
+ // If the tab is an extension get the url of the first frame for its implied URL
+ // since the url of frame 0 will be the hash of the extension key
+ mainFrameIdx = Object.keys(badger.tabData[tabId].frames)[1] || 0;
+ }
+ let frameData = badger.getFrameData(tabId, mainFrameIdx);
+ if (!frameData) {
+ return '';
+ }
+ return frameData.host;
+}
+
+/**
+ * Record "supercookie" tracking
+ *
+ * @param {Integer} tab_id browser tab ID
+ * @param {String} frame_url URL of the frame with supercookie
+ */
+function recordSupercookie(tab_id, frame_url) {
+ const frame_host = window.extractHostFromURL(frame_url),
+ page_host = badger.getFrameData(tab_id).host;
+
+ if (!utils.isThirdPartyDomain(frame_host, page_host)) {
+ // Only happens on the start page for google.com
+ return;
+ }
+
+ badger.heuristicBlocking.updateTrackerPrevalence(
+ frame_host,
+ window.getBaseDomain(frame_host),
+ window.getBaseDomain(page_host)
+ );
+}
+
+/**
+ * Record canvas fingerprinting
+ *
+ * @param {Integer} tabId the tab ID
+ * @param {Object} msg specific fingerprinting data
+ */
+function recordFingerprinting(tabId, msg) {
+ // Abort if we failed to determine the originating script's URL
+ // TODO find and fix where this happens
+ if (!msg.scriptUrl) {
+ return;
+ }
+
+ // Ignore first-party scripts
+ let script_host = window.extractHostFromURL(msg.scriptUrl),
+ document_host = badger.getFrameData(tabId).host;
+ if (!utils.isThirdPartyDomain(script_host, document_host)) {
+ return;
+ }
+
+ let CANVAS_WRITE = {
+ fillText: true,
+ strokeText: true
+ };
+ let CANVAS_READ = {
+ getImageData: true,
+ toDataURL: true
+ };
+
+ if (!badger.tabData[tabId].hasOwnProperty('fpData')) {
+ badger.tabData[tabId].fpData = {};
+ }
+
+ let script_origin = window.getBaseDomain(script_host);
+
+ // Initialize script TLD-level data
+ if (!badger.tabData[tabId].fpData.hasOwnProperty(script_origin)) {
+ badger.tabData[tabId].fpData[script_origin] = {
+ canvas: {
+ fingerprinting: false,
+ write: false
+ }
+ };
+ }
+ let scriptData = badger.tabData[tabId].fpData[script_origin];
+
+ if (msg.extra.hasOwnProperty('canvas')) {
+ if (scriptData.canvas.fingerprinting) {
+ return;
+ }
+
+ // If this script already had a canvas write...
+ if (scriptData.canvas.write) {
+ // ...and if this is a canvas read...
+ if (CANVAS_READ.hasOwnProperty(msg.prop)) {
+ // ...and it got enough data...
+ if (msg.extra.width > 16 && msg.extra.height > 16) {
+ // ...we will classify it as fingerprinting
+ scriptData.canvas.fingerprinting = true;
+ log(script_host, 'caught fingerprinting on', document_host);
+
+ // Mark this as a strike
+ badger.heuristicBlocking.updateTrackerPrevalence(
+ script_host, script_origin, window.getBaseDomain(document_host));
+ }
+ }
+ // This is a canvas write
+ } else if (CANVAS_WRITE.hasOwnProperty(msg.prop)) {
+ scriptData.canvas.write = true;
+ }
+ }
+}
+
+/**
+ * Cleans up tab-specific data.
+ *
+ * @param {Integer} tab_id the ID of the tab
+ * @param {Boolean} is_reload whether the page is simply being reloaded
+ */
+function forgetTab(tab_id, is_reload) {
+ delete badger.tabData[tab_id];
+ if (!is_reload) {
+ delete tempAllowlist[tab_id];
+ }
+}
+
+/**
+ * Determines the action to take on a specific FQDN.
+ *
+ * @param {Integer} tabId The relevant tab
+ * @param {String} requestHost The FQDN
+ * @param {Integer} frameId The id of the frame
+ * @returns {(String|Boolean)} false or the action to take
+ */
+function checkAction(tabId, requestHost, frameId) {
+ // Ignore requests from temporarily unblocked widgets.
+ // Someone clicked the widget, so let it load.
+ if (allowedOnTab(tabId, requestHost, frameId)) {
+ return false;
+ }
+
+ // Ignore requests from private domains.
+ if (window.isPrivateDomain(requestHost)) {
+ return false;
+ }
+
+ return badger.storage.getBestAction(requestHost);
+}
+
+/**
+ * Checks if the tab is chrome internal
+ *
+ * @param {Integer} tabId Id of the tab to test
+ * @returns {boolean} Returns true if the tab is chrome internal
+ * @private
+ */
+function _isTabChromeInternal(tabId) {
+ if (tabId < 0) {
+ return true;
+ }
+
+ let frameData = badger.getFrameData(tabId);
+ if (!frameData || !frameData.url.startsWith("http")) {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Checks if the tab is a chrome-extension tab
+ *
+ * @param {Integer} tabId Id of the tab to test
+ * @returns {boolean} Returns true if the tab is from a chrome-extension
+ * @private
+ */
+function _isTabAnExtension(tabId) {
+ let frameData = badger.getFrameData(tabId);
+ return (frameData && (
+ frameData.url.startsWith("chrome-extension://") ||
+ frameData.url.startsWith("moz-extension://")
+ ));
+}
+
+/**
+ * Provides the widget replacing content script with list of widgets to replace.
+ *
+ * @param {Integer} tab_id the ID of the tab we're replacing widgets in
+ *
+ * @returns {Object} dict containing the complete list of widgets
+ * as well as a mapping to indicate which ones should be replaced
+ */
+let getWidgetList = (function () {
+ // cached translations
+ let translations;
+
+ // inputs to chrome.i18n.getMessage()
+ const widgetTranslations = [
+ {
+ key: "social_tooltip_pb_has_replaced",
+ placeholders: ["XXX"]
+ },
+ {
+ key: "widget_placeholder_pb_has_replaced",
+ placeholders: ["XXX"]
+ },
+ { key: "allow_once" },
+ { key: "allow_on_site" },
+ ];
+
+ return function (tab_id) {
+ // an object with keys set to widget names that should be replaced
+ let widgetsToReplace = {},
+ widgetList = [],
+ tabData = badger.tabData[tab_id],
+ tabOrigins = tabData && tabData.origins && Object.keys(tabData.origins),
+ exceptions = badger.getSettings().getItem('widgetReplacementExceptions');
+
+ // optimize translation lookups by doing them just once,
+ // the first time they are needed
+ if (!translations) {
+ translations = widgetTranslations.reduce((memo, data) => {
+ memo[data.key] = chrome.i18n.getMessage(data.key, data.placeholders);
+ return memo;
+ }, {});
+
+ // TODO duplicated in src/lib/i18n.js
+ const RTL_LOCALES = ['ar', 'he', 'fa'],
+ UI_LOCALE = chrome.i18n.getMessage('@@ui_locale');
+ translations.rtl = RTL_LOCALES.indexOf(UI_LOCALE) > -1;
+ }
+
+ for (let widget of badger.widgetList) {
+ // replace only if the widget is not on the 'do not replace' list
+ // also don't send widget data used later for dynamic replacement
+ if (exceptions.includes(widget.name)) {
+ continue;
+ }
+
+ widgetList.push(widget);
+
+ // replace only if at least one of the associated domains was blocked
+ if (!tabOrigins || !tabOrigins.length) {
+ continue;
+ }
+ let replace = widget.domains.some(domain => {
+ // leading wildcard domain
+ if (domain[0] == "*") {
+ domain = domain.slice(1);
+ // get all domains in tabData.origins that end with this domain
+ let matches = tabOrigins.filter(origin => {
+ return origin.endsWith(domain);
+ });
+ // do we have any matches and are they all blocked?
+ return matches.length && matches.every(origin => {
+ const action = tabData.origins[origin];
+ return (
+ action == constants.BLOCK ||
+ action == constants.USER_BLOCK
+ );
+ });
+ }
+
+ // regular, non-leading wildcard domain
+ if (!tabData.origins.hasOwnProperty(domain)) {
+ return false;
+ }
+ const action = tabData.origins[domain];
+ return (
+ action == constants.BLOCK ||
+ action == constants.USER_BLOCK
+ );
+
+ });
+ if (replace) {
+ widgetsToReplace[widget.name] = true;
+ }
+ }
+
+ return {
+ translations,
+ widgetList,
+ widgetsToReplace
+ };
+ };
+}());
+
+/**
+ * Checks if given request FQDN is temporarily unblocked on a tab.
+ *
+ * The request is allowed if any of the following is true:
+ *
+ * - 1a) Request FQDN matches an entry on the exception list for the tab
+ * - 1b) Request FQDN ends with a wildcard entry from the exception list
+ * - 2a) Request is from a subframe whose FQDN matches an entry on the list
+ * - 2b) Same but subframe's FQDN ends with a wildcard entry
+ *
+ * @param {Integer} tab_id the ID of the tab to check
+ * @param {String} request_host the request FQDN to check
+ * @param {Integer} frame_id the frame ID to check
+ *
+ * @returns {Boolean} true if FQDN is on the temporary allow list
+ */
+function allowedOnTab(tab_id, request_host, frame_id) {
+ if (!tempAllowlist.hasOwnProperty(tab_id)) {
+ return false;
+ }
+
+ let exceptions = tempAllowlist[tab_id];
+
+ for (let exception of exceptions) {
+ if (exception == request_host) {
+ return true; // 1a
+ // leading wildcard
+ } else if (exception[0] == "*") {
+ if (request_host.endsWith(exception.slice(1))) {
+ return true; // 1b
+ }
+ }
+ }
+
+ if (!frame_id) {
+ return false;
+ }
+ let frameData = badger.getFrameData(tab_id, frame_id);
+ if (!frameData || !frameData.host) {
+ return false;
+ }
+
+ let frame_host = frameData.host;
+ for (let exception of exceptions) {
+ if (exception == frame_host) {
+ return true; // 2a
+ // leading wildcard
+ } else if (exception[0] == "*") {
+ if (frame_host.endsWith(exception.slice(1))) {
+ return true; // 2b
+ }
+ }
+ }
+
+ return false;
+}
+
+/**
+ * @returns {Array|Boolean} the list of associated domains or false
+ */
+function getWidgetDomains(widget_name) {
+ let widgetData = badger.widgetList.find(
+ widget => widget.name == widget_name);
+
+ if (!widgetData ||
+ !widgetData.hasOwnProperty("replacementButton") ||
+ !widgetData.replacementButton.unblockDomains) {
+ return false;
+ }
+
+ return widgetData.replacementButton.unblockDomains;
+}
+
+/**
+ * Marks a set of (widget) domains to be (temporarily) allowed on a tab.
+ *
+ * @param {Integer} tab_id the ID of the tab
+ * @param {Array} domains the domains
+ */
+function allowOnTab(tab_id, domains) {
+ if (!tempAllowlist.hasOwnProperty(tab_id)) {
+ tempAllowlist[tab_id] = [];
+ }
+ for (let domain of domains) {
+ if (!tempAllowlist[tab_id].includes(domain)) {
+ tempAllowlist[tab_id].push(domain);
+ }
+ }
+}
+
+/**
+ * Called upon navigation to prepopulate the temporary allowlist
+ * with domains for widgets marked as always allowed on a given site.
+ */
+function initializeAllowedWidgets(tab_id, tab_host) {
+ let allowedWidgets = badger.getSettings().getItem('widgetSiteAllowlist');
+ if (allowedWidgets.hasOwnProperty(tab_host)) {
+ for (let widget_name of allowedWidgets[tab_host]) {
+ let widgetDomains = getWidgetDomains(widget_name);
+ if (widgetDomains) {
+ allowOnTab(tab_id, widgetDomains);
+ }
+ }
+ }
+}
+
+// NOTE: sender.tab is available for content script (not popup) messages only
+function dispatcher(request, sender, sendResponse) {
+
+ // messages from content scripts are to be treated with greater caution:
+ // https://groups.google.com/a/chromium.org/d/msg/chromium-extensions/0ei-UCHNm34/lDaXwQhzBAAJ
+ if (!sender.url.startsWith(chrome.runtime.getURL(""))) {
+ // reject unless it's a known content script message
+ const KNOWN_CONTENT_SCRIPT_MESSAGES = [
+ "allowWidgetOnSite",
+ "checkDNT",
+ "checkEnabled",
+ "checkLocation",
+ "checkWidgetReplacementEnabled",
+ "detectFingerprinting",
+ "fpReport",
+ "getBlockedFrameUrls",
+ "getReplacementButton",
+ "inspectLocalStorage",
+ "supercookieReport",
+ "unblockWidget",
+ ];
+ if (!KNOWN_CONTENT_SCRIPT_MESSAGES.includes(request.type)) {
+ console.error("Rejected unknown message %o from %s", request, sender.url);
+ return sendResponse();
+ }
+ }
+
+ switch (request.type) {
+
+ case "checkEnabled": {
+ sendResponse(badger.isPrivacyBadgerEnabled(
+ window.extractHostFromURL(sender.tab.url)
+ ));
+
+ break;
+ }
+
+ case "checkLocation": {
+ if (!badger.isPrivacyBadgerEnabled(window.extractHostFromURL(sender.tab.url))) {
+ return sendResponse();
+ }
+
+ // Ignore requests from internal Chrome tabs.
+ if (_isTabChromeInternal(sender.tab.id)) {
+ return sendResponse();
+ }
+
+ let frame_host = window.extractHostFromURL(request.frameUrl),
+ tab_host = window.extractHostFromURL(sender.tab.url);
+
+ // Ignore requests that aren't from a third party.
+ if (!frame_host || !utils.isThirdPartyDomain(frame_host, tab_host)) {
+ return sendResponse();
+ }
+
+ let action = checkAction(sender.tab.id, frame_host);
+ sendResponse(action == constants.COOKIEBLOCK || action == constants.USER_COOKIEBLOCK);
+
+ break;
+ }
+
+ case "getBlockedFrameUrls": {
+ if (!badger.isPrivacyBadgerEnabled(window.extractHostFromURL(sender.tab.url))) {
+ return sendResponse();
+ }
+ let tab_id = sender.tab.id,
+ frame_id = sender.frameId,
+ tabData = badger.tabData.hasOwnProperty(tab_id) && badger.tabData[tab_id],
+ blockedFrameUrls = tabData &&
+ tabData.blockedFrameUrls.hasOwnProperty(frame_id) &&
+ tabData.blockedFrameUrls[frame_id];
+ sendResponse(blockedFrameUrls);
+ break;
+ }
+
+ case "unblockWidget": {
+ let widgetDomains = getWidgetDomains(request.widgetName);
+ if (!widgetDomains) {
+ return sendResponse();
+ }
+ allowOnTab(sender.tab.id, widgetDomains);
+ sendResponse();
+ break;
+ }
+
+ case "allowWidgetOnSite": {
+ // record that we always want to activate this widget on this site
+ let tab_host = window.extractHostFromURL(sender.tab.url),
+ allowedWidgets = badger.getSettings().getItem('widgetSiteAllowlist');
+ if (!allowedWidgets.hasOwnProperty(tab_host)) {
+ allowedWidgets[tab_host] = [];
+ }
+ if (!allowedWidgets[tab_host].includes(request.widgetName)) {
+ allowedWidgets[tab_host].push(request.widgetName);
+ badger.getSettings().setItem('widgetSiteAllowlist', allowedWidgets);
+ }
+ sendResponse();
+ break;
+ }
+
+ case "getReplacementButton": {
+ let widgetData = badger.widgetList.find(
+ widget => widget.name == request.widgetName);
+ if (!widgetData ||
+ !widgetData.hasOwnProperty("replacementButton") ||
+ !widgetData.replacementButton.imagePath) {
+ return sendResponse();
+ }
+
+ let button_path = chrome.runtime.getURL(
+ "skin/socialwidgets/" + widgetData.replacementButton.imagePath);
+
+ let image_type = button_path.slice(button_path.lastIndexOf('.') + 1);
+
+ let xhrOptions = {};
+ if (image_type != "svg") {
+ xhrOptions.responseType = "arraybuffer";
+ }
+
+ // fetch replacement button image data
+ utils.xhrRequest(button_path, function (err, response) {
+ // one data URI for SVGs
+ if (image_type == "svg") {
+ return sendResponse('data:image/svg+xml;charset=utf-8,' + encodeURIComponent(response));
+ }
+
+ // another data URI for all other image formats
+ sendResponse(
+ 'data:image/' + image_type + ';base64,' +
+ utils.arrayBufferToBase64(response)
+ );
+ }, "GET", xhrOptions);
+
+ // indicate this is an async response to chrome.runtime.onMessage
+ return true;
+ }
+
+ case "fpReport": {
+ if (Array.isArray(request.data)) {
+ request.data.forEach(function (msg) {
+ recordFingerprinting(sender.tab.id, msg);
+ });
+ } else {
+ recordFingerprinting(sender.tab.id, request.data);
+ }
+
+ break;
+ }
+
+ case "supercookieReport": {
+ if (request.frameUrl && badger.hasSupercookie(request.data)) {
+ recordSupercookie(sender.tab.id, request.frameUrl);
+ }
+ break;
+ }
+
+ case "inspectLocalStorage": {
+ let tab_host = window.extractHostFromURL(sender.tab.url),
+ frame_host = window.extractHostFromURL(request.frameUrl);
+
+ sendResponse(frame_host &&
+ badger.isLearningEnabled(sender.tab.id) &&
+ badger.isPrivacyBadgerEnabled(tab_host) &&
+ utils.isThirdPartyDomain(frame_host, tab_host));
+
+ break;
+ }
+
+ case "detectFingerprinting": {
+ let tab_host = window.extractHostFromURL(sender.tab.url);
+
+ sendResponse(
+ badger.isLearningEnabled(sender.tab.id) &&
+ badger.isPrivacyBadgerEnabled(tab_host));
+
+ break;
+ }
+
+ case "checkWidgetReplacementEnabled": {
+ let response = false,
+ tab_host = window.extractHostFromURL(sender.tab.url);
+
+ if (badger.isPrivacyBadgerEnabled(tab_host) &&
+ badger.isWidgetReplacementEnabled()) {
+ response = getWidgetList(sender.tab.id);
+ }
+
+ sendResponse(response);
+
+ break;
+ }
+
+ case "getPopupData": {
+ let tab_id = request.tabId;
+
+ if (!badger.tabData.hasOwnProperty(tab_id)) {
+ sendResponse({
+ criticalError: badger.criticalError,
+ noTabData: true,
+ seenComic: true,
+ });
+ break;
+ }
+
+ let tab_host = window.extractHostFromURL(request.tabUrl),
+ origins = badger.tabData[tab_id].origins,
+ cookieblocked = {};
+
+ for (let origin in origins) {
+ // see if origin would be cookieblocked if not for user override
+ if (badger.storage.wouldGetCookieblocked(origin)) {
+ cookieblocked[origin] = true;
+ }
+ }
+
+ sendResponse({
+ cookieblocked,
+ criticalError: badger.criticalError,
+ enabled: badger.isPrivacyBadgerEnabled(tab_host),
+ errorText: badger.tabData[tab_id].errorText,
+ learnLocally: badger.getSettings().getItem("learnLocally"),
+ noTabData: false,
+ origins,
+ seenComic: badger.getSettings().getItem("seenComic"),
+ showLearningPrompt: badger.getPrivateSettings().getItem("showLearningPrompt"),
+ showNonTrackingDomains: badger.getSettings().getItem("showNonTrackingDomains"),
+ tabHost: tab_host,
+ tabId: tab_id,
+ tabUrl: request.tabUrl,
+ trackerCount: badger.getTrackerCount(tab_id)
+ });
+
+ break;
+ }
+
+ case "getOptionsData": {
+ let origins = badger.storage.getTrackingDomains();
+
+ let cookieblocked = {};
+ for (let origin in origins) {
+ // see if origin would be cookieblocked if not for user override
+ if (badger.storage.wouldGetCookieblocked(origin)) {
+ cookieblocked[origin] = true;
+ }
+ }
+
+ sendResponse({
+ cookieblocked,
+ isWidgetReplacementEnabled: badger.isWidgetReplacementEnabled(),
+ origins,
+ settings: badger.getSettings().getItemClones(),
+ webRTCAvailable: badger.webRTCAvailable,
+ widgets: badger.widgetList.map(widget => widget.name),
+ });
+
+ break;
+ }
+
+ case "resetData": {
+ badger.storage.clearTrackerData();
+ badger.loadSeedData(err => {
+ if (err) {
+ console.error(err);
+ }
+ badger.blockWidgetDomains();
+ sendResponse();
+ });
+ // indicate this is an async response to chrome.runtime.onMessage
+ return true;
+ }
+
+ case "removeAllData": {
+ badger.storage.clearTrackerData();
+ sendResponse();
+ break;
+ }
+
+ case "seenComic": {
+ badger.getSettings().setItem("seenComic", true);
+ sendResponse();
+ break;
+ }
+
+ case "seenLearningPrompt": {
+ badger.getPrivateSettings().setItem("showLearningPrompt", false);
+ sendResponse();
+ break;
+ }
+
+ case "activateOnSite": {
+ badger.enablePrivacyBadgerForOrigin(request.tabHost);
+ badger.updateIcon(request.tabId, request.tabUrl);
+ sendResponse();
+ break;
+ }
+
+ case "deactivateOnSite": {
+ badger.disablePrivacyBadgerForOrigin(request.tabHost);
+ badger.updateIcon(request.tabId, request.tabUrl);
+ sendResponse();
+ break;
+ }
+
+ case "revertDomainControl": {
+ badger.storage.revertUserAction(request.origin);
+ sendResponse({
+ origins: badger.storage.getTrackingDomains()
+ });
+ break;
+ }
+
+ case "downloadCloud": {
+ chrome.storage.sync.get("disabledSites", function (store) {
+ if (chrome.runtime.lastError) {
+ sendResponse({success: false, message: chrome.runtime.lastError.message});
+ } else if (store.hasOwnProperty("disabledSites")) {
+ let disabledSites = _.union(
+ badger.getDisabledSites(),
+ store.disabledSites
+ );
+ badger.getSettings().setItem("disabledSites", disabledSites);
+ sendResponse({
+ success: true,
+ disabledSites
+ });
+ } else {
+ sendResponse({
+ success: false,
+ message: chrome.i18n.getMessage("download_cloud_no_data")
+ });
+ }
+ });
+
+ // indicate this is an async response to chrome.runtime.onMessage
+ return true;
+ }
+
+ case "uploadCloud": {
+ let obj = {};
+ obj.disabledSites = badger.getDisabledSites();
+ chrome.storage.sync.set(obj, function () {
+ if (chrome.runtime.lastError) {
+ sendResponse({success: false, message: chrome.runtime.lastError.message});
+ } else {
+ sendResponse({success: true});
+ }
+ });
+ // indicate this is an async response to chrome.runtime.onMessage
+ return true;
+ }
+
+ case "savePopupToggle": {
+ let domain = request.origin,
+ action = request.action;
+
+ badger.saveAction(action, domain);
+
+ // update cached tab data so that a reopened popup displays correct state
+ badger.tabData[request.tabId].origins[domain] = "user_" + action;
+
+ break;
+ }
+
+ case "saveOptionsToggle": {
+ // called when the user manually sets a slider on the options page
+ badger.saveAction(request.action, request.origin);
+ sendResponse({
+ origins: badger.storage.getTrackingDomains()
+ });
+ break;
+ }
+
+ case "mergeUserData": {
+ // called when a user uploads data exported from another Badger instance
+ badger.mergeUserData(request.data);
+ badger.blockWidgetDomains();
+ sendResponse({
+ disabledSites: badger.getDisabledSites(),
+ origins: badger.storage.getTrackingDomains(),
+ });
+ break;
+ }
+
+ case "updateSettings": {
+ const settings = badger.getSettings();
+ for (let key in request.data) {
+ if (badger.defaultSettings.hasOwnProperty(key)) {
+ settings.setItem(key, request.data[key]);
+ } else {
+ console.error("Unknown Badger setting:", key);
+ }
+ }
+ sendResponse();
+ break;
+ }
+
+ case "updateBadge": {
+ let tab_id = request.tab_id;
+ badger.updateBadge(tab_id);
+ sendResponse();
+ break;
+ }
+
+ case "disablePrivacyBadgerForOrigin": {
+ badger.disablePrivacyBadgerForOrigin(request.domain);
+ sendResponse({
+ disabledSites: badger.getDisabledSites()
+ });
+ break;
+ }
+
+ case "enablePrivacyBadgerForOriginList": {
+ request.domains.forEach(function (domain) {
+ badger.enablePrivacyBadgerForOrigin(domain);
+ });
+ sendResponse({
+ disabledSites: badger.getDisabledSites()
+ });
+ break;
+ }
+
+ case "removeOrigin": {
+ badger.storage.getStore("snitch_map").deleteItem(request.origin);
+ badger.storage.getStore("action_map").deleteItem(request.origin);
+ sendResponse({
+ origins: badger.storage.getTrackingDomains()
+ });
+ break;
+ }
+
+ case "saveErrorText": {
+ let activeTab = badger.tabData[request.tabId];
+ activeTab.errorText = request.errorText;
+ break;
+ }
+
+ case "removeErrorText": {
+ let activeTab = badger.tabData[request.tabId];
+ delete activeTab.errorText;
+ break;
+ }
+
+ case "checkDNT": {
+ // called from contentscripts/dnt.js to check if we should enable it
+ sendResponse(
+ badger.isDNTSignalEnabled()
+ && badger.isPrivacyBadgerEnabled(
+ window.extractHostFromURL(sender.tab.url)
+ )
+ );
+ break;
+ }
+
+ }
+}
+
+/*************** Event Listeners *********************/
+function startListeners() {
+ chrome.webNavigation.onBeforeNavigate.addListener(onNavigate);
+
+ chrome.webRequest.onBeforeRequest.addListener(onBeforeRequest, {urls: ["http://*/*", "https://*/*"]}, ["blocking"]);
+
+ let extraInfoSpec = ['requestHeaders', 'blocking'];
+ if (chrome.webRequest.OnBeforeSendHeadersOptions.hasOwnProperty('EXTRA_HEADERS')) {
+ extraInfoSpec.push('extraHeaders');
+ }
+ chrome.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, {urls: ["http://*/*", "https://*/*"]}, extraInfoSpec);
+
+ extraInfoSpec = ['responseHeaders', 'blocking'];
+ if (chrome.webRequest.OnHeadersReceivedOptions.hasOwnProperty('EXTRA_HEADERS')) {
+ extraInfoSpec.push('extraHeaders');
+ }
+ chrome.webRequest.onHeadersReceived.addListener(onHeadersReceived, {urls: ["<all_urls>"]}, extraInfoSpec);
+
+ chrome.tabs.onRemoved.addListener(onTabRemoved);
+ chrome.tabs.onReplaced.addListener(onTabReplaced);
+ chrome.runtime.onMessage.addListener(dispatcher);
+}
+
+/************************************** exports */
+let exports = {
+ startListeners
+};
+return exports;
+/************************************** exports */
+})();
diff --git a/src/lib/basedomain.js b/src/lib/basedomain.js
new file mode 100644
index 0000000..32e8768
--- /dev/null
+++ b/src/lib/basedomain.js
@@ -0,0 +1,319 @@
+/*!
+ * Parts of original code from ipv6.js <https://github.com/beaugunderson/javascript-ipv6>
+ * Copyright 2011 Beau Gunderson
+ * Available under MIT license <http://mths.be/mit>
+ */
+
+/* globals punycode:false */
+
+const RE_V4 = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|0x[0-9a-f][0-9a-f]?|0[0-7]{3})\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|0x[0-9a-f][0-9a-f]?|0[0-7]{3})$/i;
+const RE_V4_HEX = /^0x([0-9a-f]{8})$/i;
+const RE_V4_NUMERIC = /^[0-9]+$/;
+const RE_V4inV6 = /(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
+
+const RE_BAD_CHARACTERS = /([^0-9a-f:])/i;
+const RE_BAD_ADDRESS = /([0-9a-f]{5,}|:{3,}|[^:]:$|^:[^:]$)/i;
+
+function isIPv4(address) {
+ if (RE_V4.test(address)) {
+ return true;
+ }
+ if (RE_V4_HEX.test(address)) {
+ return true;
+ }
+ if (RE_V4_NUMERIC.test(address)) {
+ return true;
+ }
+ return false;
+}
+
+function isIPv6(address) {
+ var a4addon = 0;
+ var address4 = address.match(RE_V4inV6);
+ if (address4) {
+ var temp4 = address4[0].split('.');
+ for (var i = 0; i < 4; i++) {
+ if (/^0[0-9]+/.test(temp4[i])) {
+ return false;
+ }
+ }
+ address = address.replace(RE_V4inV6, '');
+ if (/[0-9]$/.test(address)) {
+ return false;
+ }
+
+ address = address + temp4.join(':');
+ a4addon = 2;
+ }
+
+ if (RE_BAD_CHARACTERS.test(address)) {
+ return false;
+ }
+
+ if (RE_BAD_ADDRESS.test(address)) {
+ return false;
+ }
+
+ function count(string, substring) {
+ return (string.length - string.replace(new RegExp(substring,"g"), '').length) / substring.length;
+ }
+
+ var halves = count(address, '::');
+ if (halves == 1 && count(address, ':') <= 6 + 2 + a4addon) {
+ return true;
+ }
+ if (halves == 0 && count(address, ':') == 7 + a4addon) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Returns base domain for specified host based on Public Suffix List.
+ * @param {String} hostname The name of the host to get the base domain for
+ */
+function getBaseDomain(/**String*/ hostname) /**String*/ {
+ // remove trailing dot(s)
+ hostname = hostname.replace(/\.+$/, '');
+
+ // return IP address untouched
+ if (isIPv6(hostname) || isIPv4(hostname)) {
+ return hostname;
+ }
+
+ // decode punycode if exists
+ if (hostname.indexOf('xn--') >= 0) {
+ hostname = punycode.toUnicode(hostname);
+ }
+
+ // search through PSL
+ var prevDomains = [];
+ var curDomain = hostname;
+ var nextDot = curDomain.indexOf('.');
+ var tld = 0;
+
+ for (;;) {
+ var suffix = window.publicSuffixes[curDomain];
+ if (typeof suffix != 'undefined') {
+ tld = suffix;
+ break;
+ }
+
+ if (nextDot < 0) {
+ tld = 1;
+ break;
+ }
+
+ prevDomains.push(curDomain.substring(0,nextDot));
+ curDomain = curDomain.substring(nextDot+1);
+ nextDot = curDomain.indexOf('.');
+ }
+
+ while (tld > 0 && prevDomains.length > 0) {
+ curDomain = prevDomains.pop() + '.' + curDomain;
+ tld--;
+ }
+
+ return curDomain;
+}
+
+/**
+ * Converts an IP address to a number. If given input is not a valid IP address
+ * then 0 is returned.
+ * @param {String} ip The IP address to convert
+ * @returns {Integer}
+ */
+function ipAddressToNumber(ip) {
+ // Separate IP address into octets, make sure there are four.
+ var octets = ip.split(".");
+ if (octets.length !== 4) {
+ return 0;
+ }
+
+ var result = 0;
+ var maxOctetIndex = 3;
+ for (var i = maxOctetIndex; i >= 0; i--) {
+ var octet = parseInt(octets[maxOctetIndex - i], 10);
+
+ // If octet is invalid return early, no need to continue.
+ if (Number.isNaN(octet) || octet < 0 || octet > 255) {
+ return 0;
+ }
+
+ // Use bit shifting to store each octet for result.
+ result |= octet << (i * 8); // eslint-disable-line no-bitwise
+ }
+
+ // Results of bitwise operations in JS are interpreted as signed
+ // so use zero-fill right shift to return unsigned number.
+ return result >>> 0; // eslint-disable-line no-bitwise
+}
+
+/**
+ * Determines if domain is private, that is localhost or the IP address spaces
+ * specified by RFC 1918.
+ * @param {String} domain The domain to check
+ * @returns {Boolean}
+ */
+function isPrivateDomain(domain) { // eslint-disable-line no-unused-vars
+ // Check for localhost match.
+ if (domain === "localhost") {
+ return true;
+ }
+
+ // Check for private IP match.
+ var ipNumber = ipAddressToNumber(domain);
+ var privateIpMasks = {
+ "127.0.0.0": "255.0.0.0",
+ "10.0.0.0": "255.0.0.0",
+ "172.16.0.0": "255.240.0.0",
+ "192.168.0.0": "255.255.0.0",
+ };
+ for (var ip in privateIpMasks) {
+ // Ignore object properties.
+ if (!privateIpMasks.hasOwnProperty(ip)) {
+ continue;
+ }
+
+ // Compare given IP value to private IP value using bitwise AND.
+ // Make sure result of AND is unsigned by using zero-fill right shift.
+ var privateIpNumber = ipAddressToNumber(ip);
+ var privateMaskNumber = ipAddressToNumber(privateIpMasks[ip]);
+ if (((ipNumber & privateMaskNumber) >>> 0) === privateIpNumber) { // eslint-disable-line no-bitwise
+ return true;
+ }
+ }
+
+ // Getting here means given host didn't match localhost
+ // or other private addresses so return false.
+ return false;
+}
+
+/**
+ * Checks whether a request is third party for the given document, uses
+ * information from the public suffix list to determine the effective domain
+ * name for the document.
+ * @param {String} requestHost The host of the 3rd party request
+ * @param {String} documentHost The host of the document
+ */
+function isThirdParty(/**String*/ requestHost, /**String*/ documentHost) { // eslint-disable-line no-unused-vars
+ // Remove trailing dots
+ requestHost = requestHost.replace(/\.+$/, "");
+ documentHost = documentHost.replace(/\.+$/, "");
+
+ // Extract domain name - leave IP addresses unchanged, otherwise leave only base domain
+ var documentDomain = getBaseDomain(documentHost);
+ if (requestHost.length > documentDomain.length) {
+ return (requestHost.substr(requestHost.length - documentDomain.length - 1) != "." + documentDomain);
+ } else {
+ return (requestHost != documentDomain);
+ }
+}
+
+/**
+ * Extracts host name from a URL.
+ */
+function extractHostFromURL(/**String*/ url) { // eslint-disable-line no-unused-vars
+ if (url && extractHostFromURL._lastURL == url) {
+ return extractHostFromURL._lastDomain;
+ }
+
+ var host = "";
+ try {
+ host = new URI(url).host;
+ } catch (e) {
+ // Keep the empty string for invalid URIs.
+ }
+
+ extractHostFromURL._lastURL = url;
+ extractHostFromURL._lastDomain = host;
+ return host;
+}
+
+/**
+ * Parses URLs and provides an interface similar to nsIURI in Gecko, see
+ * https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIURI.
+ * TODO: Make sure the parsing actually works the same as nsStandardURL.
+ * @constructor
+ */
+function URI(/**String*/ spec) {
+ this.spec = spec;
+ this._schemeEnd = spec.indexOf(":");
+ if (this._schemeEnd < 0) {
+ throw new Error("Invalid URI scheme");
+ }
+
+ if (spec.substr(this._schemeEnd + 1, 2) != "//") {
+ // special case for filesystem, blob URIs
+ if (this.scheme === "filesystem" || this.scheme === "blob") {
+ this._schemeEnd = spec.indexOf(":", this._schemeEnd + 1);
+ if (spec.substr(this._schemeEnd + 1, 2) != "//") {
+ throw new Error("Unexpected URI structure");
+ }
+ } else {
+ throw new Error("Unexpected URI structure");
+ }
+ }
+
+ this._hostPortStart = this._schemeEnd + 3;
+ this._hostPortEnd = spec.indexOf("/", this._hostPortStart);
+ if (this._hostPortEnd < 0) {
+ throw new Error("Invalid URI host");
+ }
+
+ var authEnd = spec.indexOf("@", this._hostPortStart);
+ if (authEnd >= 0 && authEnd < this._hostPortEnd) {
+ this._hostPortStart = authEnd + 1;
+ }
+
+ this._portStart = -1;
+ this._hostEnd = spec.indexOf("]", this._hostPortStart + 1);
+ if (spec[this._hostPortStart] == "[" && this._hostEnd >= 0 && this._hostEnd < this._hostPortEnd) {
+ // The host is an IPv6 literal
+ this._hostStart = this._hostPortStart + 1;
+ if (spec[this._hostEnd + 1] == ":") {
+ this._portStart = this._hostEnd + 2;
+ }
+ } else {
+ this._hostStart = this._hostPortStart;
+ this._hostEnd = spec.indexOf(":", this._hostStart);
+ if (this._hostEnd >= 0 && this._hostEnd < this._hostPortEnd) {
+ this._portStart = this._hostEnd + 1;
+ } else {
+ this._hostEnd = this._hostPortEnd;
+ }
+ }
+}
+URI.prototype = {
+ spec: null,
+ get scheme() {
+ return this.spec.substring(0, this._schemeEnd).toLowerCase();
+ },
+ get host() {
+ return this.spec.substring(this._hostStart, this._hostEnd);
+ },
+ get asciiHost() {
+ var host = this.host;
+ if (/^[\x00-\x7F]+$/.test(host)) { // eslint-disable-line no-control-regex
+ return host;
+ } else {
+ return punycode.toASCII(host);
+ }
+ },
+ get hostPort() {
+ return this.spec.substring(this._hostPortStart, this._hostPortEnd);
+ },
+ get port() {
+ if (this._portStart < 0) {
+ return -1;
+ } else {
+ return parseInt(this.spec.substring(this._portStart, this._hostPortEnd), 10);
+ }
+ },
+ get path() {
+ return this.spec.substring(this._hostPortEnd);
+ },
+ get prePath() {
+ return this.spec.substring(0, this._hostPortEnd);
+ }
+};
diff --git a/src/lib/i18n.js b/src/lib/i18n.js
new file mode 100644
index 0000000..11ef67c
--- /dev/null
+++ b/src/lib/i18n.js
@@ -0,0 +1,151 @@
+/*
+ * This file is part of Adblock Plus <http://adblockplus.org/>,
+ * Copyright (C) 2006-2013 Eyeo GmbH
+ *
+ * Adblock Plus 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.
+ *
+ * Adblock Plus 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 Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+(function () {
+
+const LOCALE = chrome.i18n.getMessage('@@ui_locale'),
+ ON_POPUP = (document.location.pathname == "/skin/popup.html");
+
+function localizeFaqLink() {
+ const LOCALIZED_HOMEPAGE_LOCALES = ['es'];
+ if (ON_POPUP && LOCALIZED_HOMEPAGE_LOCALES.includes(LOCALE)) {
+ // update FAQ link to point to localized version
+ $('#help').prop('href', `https://privacybadger.org/${LOCALE}/#faq`);
+ }
+}
+
+function setTextDirection() {
+ function toggle_css_value(selector, property, from, to) {
+ let $els = $(selector);
+ $els.each(i => {
+ let $el = $($els[i]);
+ if ($el.css(property) === from) {
+ $el.css(property, to);
+ }
+ });
+ }
+
+ // https://www.w3.org/International/questions/qa-scripts#examples
+ // https://developer.chrome.com/webstore/i18n?csw=1#localeTable
+ // TODO duplicated in src/js/webrequest.js
+ const RTL_LOCALES = ['ar', 'he', 'fa'];
+ if (!RTL_LOCALES.includes(LOCALE)) {
+ return;
+ }
+
+ // set body text direction
+ document.body.setAttribute("dir", "rtl");
+
+ // popup page
+ if (ON_POPUP) {
+ // fix floats
+ ['#privacyBadgerHeader img', '#header-image-stack', '#version'].forEach((selector) => {
+ toggle_css_value(selector, "float", "left", "right");
+ });
+ ['#fittslaw', '#options', '#help', '#share', '.overlay_close'].forEach((selector) => {
+ toggle_css_value(selector, "float", "right", "left");
+ });
+
+ // options page
+ } else if (document.location.pathname == "/skin/options.html") {
+ // apply RTL workaround for jQuery UI tabs
+ // https://zoomicon.wordpress.com/2009/10/15/how-to-use-jqueryui-tabs-in-right-to-left-layout/
+ let css = document.createElement("style");
+ css.type = "text/css";
+ css.textContent = `
+.ui-tabs { direction: rtl; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected,
+ .ui-tabs .ui-tabs-nav li.ui-state-default { float: right; }
+.ui-tabs .ui-tabs-nav li a { float: right; }
+`;
+ document.body.appendChild(css);
+
+ // fix floats
+ ['.btn-silo', '.btn-silo div', '#allowlist-form > div > div > div'].forEach((selector) => {
+ toggle_css_value(selector, "float", "left", "right");
+ });
+ }
+}
+
+/**
+ * Loads and inserts i18n strings into matching elements.
+ */
+function loadI18nStrings() {
+ let els = document.querySelectorAll("[class^='i18n_']");
+
+ // replace element contents by their class names
+ for (let el of els) {
+ const key = el.className.split(/\s/)[0].slice(5),
+ prop = ("innerHTML" in el ? "innerHTML" : "textContent");
+
+ // get chrome.i18n placeholders, if any
+ let placeholders = el.dataset.i18n_contents_placeholders;
+ placeholders = (placeholders ? placeholders.split("@@") : []);
+
+ // replace contents
+ el[prop] = chrome.i18n.getMessage(key, placeholders);
+ }
+
+ // also replace alt, placeholder and title attributes
+ const ATTRS = [
+ 'alt',
+ 'placeholder',
+ 'title',
+ ];
+
+ // get all the elements that contain one or more of these attributes
+ els = document.querySelectorAll(
+ // for example: "[placeholder^='i18n_'], [title^='i18n_']"
+ "[" + ATTRS.join("^='i18n_'], [") + "^='i18n_']"
+ );
+
+ // for each element
+ for (let el of els) {
+ // for each attribute
+ for (let attr_type of ATTRS) {
+ // get the translation message key
+ let key = el.getAttribute(attr_type);
+
+ // attribute exists
+ if (key) {
+ // remove the i18n_ prefix
+ key = key.startsWith("i18n_") && key.slice(5);
+ }
+
+ if (!key) {
+ continue;
+ }
+
+ // get chrome.i18n placeholders, if any
+ // TODO multiple attributes are not supported
+ let placeholders = el.dataset.i18n_attribute_placeholders;
+ placeholders = (placeholders ? placeholders.split("@@") : []);
+
+ // update the attribute with the result of a translation lookup by KEY
+ el.setAttribute(attr_type, chrome.i18n.getMessage(key, placeholders));
+ }
+ }
+}
+
+// Fill in the strings as soon as possible
+window.addEventListener("DOMContentLoaded", function () {
+ localizeFaqLink();
+ setTextDirection();
+ loadI18nStrings();
+}, true);
+
+}());
diff --git a/src/lib/options.js b/src/lib/options.js
new file mode 100644
index 0000000..8e6bec7
--- /dev/null
+++ b/src/lib/options.js
@@ -0,0 +1,120 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2018 Electronic Frontier Foundation
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+require.scopes.optionslib = (function () {
+
+/**
+ * Gets array of encountered origins.
+ *
+ * @param {Object} origins The starting set of domains to be filtered.
+ * @param {String} [filter_text] Text to filter origins with.
+ * @param {String} [type_filter] Type: user-controlled/DNT-compliant
+ * @param {String} [status_filter] Status: blocked/cookieblocked/allowed
+ * @param {Boolean} [show_not_yet_blocked] Whether to show domains your Badger
+ * hasn't yet learned to block.
+ *
+ * @return {Array} The array of origins.
+ */
+function getOriginsArray(origins, filter_text, type_filter, status_filter, show_not_yet_blocked) {
+ // Make sure filter_text is lower case for case-insensitive matching.
+ if (filter_text) {
+ filter_text = filter_text.toLowerCase();
+ } else {
+ filter_text = "";
+ }
+
+ /**
+ * @param {String} origin The origin to test.
+ * @return {Boolean} Does the origin pass filters?
+ */
+ function matchesFormFilters(origin) {
+ const value = origins[origin];
+
+ if (!show_not_yet_blocked) {
+ // hide the not-yet-seen-on-enough-sites potential trackers
+ if (value == "allow") {
+ return false;
+ }
+ }
+
+ // filter by type
+ if (type_filter) {
+ if (type_filter == "user") {
+ if (!value.startsWith("user")) {
+ return false;
+ }
+ } else {
+ if (value != type_filter) {
+ return false;
+ }
+ }
+ }
+
+ // filter by status
+ if (status_filter) {
+ if (status_filter != value.replace("user_", "") && !(
+ status_filter == "allow" && value == "dnt"
+ )) {
+ return false;
+ }
+ }
+
+ // filter by search text
+ // treat spaces as OR operators
+ // treat "-" prefixes as NOT operators
+ let textFilters = filter_text.split(" ").filter(i=>i); // remove empties
+
+ // no text filters, we have a match
+ if (!textFilters.length) {
+ return true;
+ }
+
+ let positiveFilters = textFilters.filter(i => i[0] != "-"),
+ lorigin = origin.toLowerCase();
+
+ // if we have any positive filters, and we don't match any,
+ // don't bother checking negative filters
+ if (positiveFilters.length) {
+ let result = positiveFilters.some(text => {
+ return lorigin.indexOf(text) != -1;
+ });
+ if (!result) {
+ return false;
+ }
+ }
+
+ // we either matched a positive filter,
+ // or we don't have any positive filters
+
+ // if we match any negative filters, discard the match
+ return textFilters.every(text => {
+ if (text[0] != "-" || text == "-") {
+ return true;
+ }
+ return lorigin.indexOf(text.slice(1)) == -1;
+ });
+ }
+
+ // Include only origins that match given filters.
+ return Object.keys(origins).filter(matchesFormFilters);
+}
+
+return {
+ getOriginsArray,
+};
+
+}()); // end of require.scopes
diff --git a/src/lib/publicSuffixList.js b/src/lib/publicSuffixList.js
new file mode 100644
index 0000000..548b768
--- /dev/null
+++ b/src/lib/publicSuffixList.js
@@ -0,0 +1,7497 @@
+window.publicSuffixes = {
+ "0.bg": 1,
+ "001www.com": 1,
+ "0e.vc": 1,
+ "0emm.com": 2,
+ "1.bg": 1,
+ "12hp.at": 1,
+ "12hp.ch": 1,
+ "12hp.de": 1,
+ "1337.pictures": 1,
+ "16-b.it": 1,
+ "1kapp.com": 1,
+ "2.bg": 1,
+ "2000.hu": 1,
+ "2038.io": 1,
+ "2ix.at": 1,
+ "2ix.ch": 1,
+ "2ix.de": 1,
+ "3.bg": 1,
+ "32-b.it": 1,
+ "3utilities.com": 1,
+ "4.bg": 1,
+ "4lima.at": 1,
+ "4lima.ch": 1,
+ "4lima.de": 1,
+ "4u.com": 1,
+ "5.bg": 1,
+ "6.bg": 1,
+ "611.to": 1,
+ "64-b.it": 1,
+ "7.bg": 1,
+ "8.bg": 1,
+ "9.bg": 1,
+ "9guacu.br": 1,
+ "a.bg": 1,
+ "a.prod.fastly.net": 1,
+ "a.run.app": 1,
+ "a.se": 1,
+ "a.ssl.fastly.net": 1,
+ "aa.no": 1,
+ "aaa.pro": 1,
+ "aarborte.no": 1,
+ "ab.ca": 1,
+ "abashiri.hokkaido.jp": 1,
+ "abc.br": 1,
+ "abeno.osaka.jp": 1,
+ "abiko.chiba.jp": 1,
+ "abira.hokkaido.jp": 1,
+ "abkhazia.su": 1,
+ "abo.pa": 1,
+ "abr.it": 1,
+ "abruzzo.it": 1,
+ "abu.yamaguchi.jp": 1,
+ "ac.ae": 1,
+ "ac.at": 1,
+ "ac.be": 1,
+ "ac.ci": 1,
+ "ac.cn": 1,
+ "ac.cr": 1,
+ "ac.cy": 1,
+ "ac.fj": 1,
+ "ac.gn": 1,
+ "ac.gov.br": 1,
+ "ac.id": 1,
+ "ac.il": 1,
+ "ac.im": 1,
+ "ac.in": 1,
+ "ac.ir": 1,
+ "ac.jp": 1,
+ "ac.ke": 1,
+ "ac.kr": 1,
+ "ac.leg.br": 1,
+ "ac.lk": 1,
+ "ac.ls": 1,
+ "ac.ma": 1,
+ "ac.me": 1,
+ "ac.mu": 1,
+ "ac.mw": 1,
+ "ac.mz": 1,
+ "ac.ni": 1,
+ "ac.nz": 1,
+ "ac.pa": 1,
+ "ac.pr": 1,
+ "ac.rs": 1,
+ "ac.ru": 1,
+ "ac.rw": 1,
+ "ac.se": 1,
+ "ac.sz": 1,
+ "ac.th": 1,
+ "ac.tj": 1,
+ "ac.tz": 1,
+ "ac.ug": 1,
+ "ac.uk": 1,
+ "ac.vn": 1,
+ "ac.za": 1,
+ "ac.zm": 1,
+ "ac.zw": 1,
+ "aca.pro": 1,
+ "academia.bo": 1,
+ "academy.museum": 1,
+ "accesscam.org": 1,
+ "accident-investigation.aero": 1,
+ "accident-prevention.aero": 1,
+ "acct.pro": 1,
+ "achi.nagano.jp": 1,
+ "act.au": 1,
+ "act.edu.au": 1,
+ "ad.jp": 1,
+ "adachi.tokyo.jp": 1,
+ "adm.br": 1,
+ "adobeaemcloud.com": 1,
+ "adobeaemcloud.net": 1,
+ "adult.ht": 1,
+ "adv.br": 1,
+ "adv.mz": 1,
+ "advisor.ws": 2,
+ "adygeya.ru": 1,
+ "adygeya.su": 1,
+ "ae.org": 1,
+ "aejrie.no": 1,
+ "aero.mv": 1,
+ "aero.tt": 1,
+ "aerobatic.aero": 1,
+ "aeroclub.aero": 1,
+ "aerodrome.aero": 1,
+ "aeroport.fr": 1,
+ "afjord.no": 1,
+ "africa.com": 1,
+ "ag.it": 1,
+ "aga.niigata.jp": 1,
+ "agano.niigata.jp": 1,
+ "agdenes.no": 1,
+ "agematsu.nagano.jp": 1,
+ "agents.aero": 1,
+ "agr.br": 1,
+ "agrar.hu": 1,
+ "agric.za": 1,
+ "agriculture.museum": 1,
+ "agrigento.it": 1,
+ "agrinet.tn": 1,
+ "agro.bo": 1,
+ "agro.pl": 1,
+ "aguni.okinawa.jp": 1,
+ "ah.cn": 1,
+ "ah.no": 1,
+ "aibetsu.hokkaido.jp": 1,
+ "aichi.jp": 1,
+ "aid.pl": 1,
+ "aikawa.kanagawa.jp": 1,
+ "ainan.ehime.jp": 1,
+ "aioi.hyogo.jp": 1,
+ "aip.ee": 1,
+ "air-surveillance.aero": 1,
+ "air-traffic-control.aero": 1,
+ "air.museum": 1,
+ "aircraft.aero": 1,
+ "airguard.museum": 1,
+ "airline.aero": 1,
+ "airport.aero": 1,
+ "airtraffic.aero": 1,
+ "aisai.aichi.jp": 1,
+ "aisho.shiga.jp": 1,
+ "aizubange.fukushima.jp": 1,
+ "aizumi.tokushima.jp": 1,
+ "aizumisato.fukushima.jp": 1,
+ "aizuwakamatsu.fukushima.jp": 1,
+ "aju.br": 1,
+ "ak.us": 1,
+ "akabira.hokkaido.jp": 1,
+ "akagi.shimane.jp": 1,
+ "akaiwa.okayama.jp": 1,
+ "akashi.hyogo.jp": 1,
+ "aki.kochi.jp": 1,
+ "akiruno.tokyo.jp": 1,
+ "akishima.tokyo.jp": 1,
+ "akita.akita.jp": 1,
+ "akita.jp": 1,
+ "akkeshi.hokkaido.jp": 1,
+ "aknoluokta.no": 1,
+ "ako.hyogo.jp": 1,
+ "akrehamn.no": 1,
+ "aktyubinsk.su": 1,
+ "akune.kagoshima.jp": 1,
+ "al.eu.org": 1,
+ "al.gov.br": 1,
+ "al.it": 1,
+ "al.leg.br": 1,
+ "al.no": 1,
+ "al.us": 1,
+ "alabama.museum": 1,
+ "alaheadju.no": 1,
+ "aland.fi": 1,
+ "alaska.museum": 1,
+ "alces.network": 2,
+ "alessandria.it": 1,
+ "alesund.no": 1,
+ "algard.no": 1,
+ "algorithmia.com": 2,
+ "alpha-myqnapcloud.com": 1,
+ "alpha.bounty-full.com": 1,
+ "alstahaug.no": 1,
+ "alt.za": 1,
+ "alta.no": 1,
+ "altervista.org": 1,
+ "alto-adige.it": 1,
+ "altoadige.it": 1,
+ "alvdal.no": 1,
+ "alwaysdata.net": 1,
+ "am.br": 1,
+ "am.gov.br": 1,
+ "am.leg.br": 1,
+ "ama.aichi.jp": 1,
+ "ama.shimane.jp": 1,
+ "amagasaki.hyogo.jp": 1,
+ "amakusa.kumamoto.jp": 1,
+ "amami.kagoshima.jp": 1,
+ "amber.museum": 1,
+ "ambulance.aero": 1,
+ "ambulance.museum": 1,
+ "american.museum": 1,
+ "americana.museum": 1,
+ "americanantiques.museum": 1,
+ "americanart.museum": 1,
+ "ami.ibaraki.jp": 1,
+ "amli.no": 1,
+ "amot.no": 1,
+ "amsterdam.museum": 1,
+ "amsw.nl": 1,
+ "amusement.aero": 1,
+ "an.it": 1,
+ "anamizu.ishikawa.jp": 1,
+ "anan.nagano.jp": 1,
+ "anan.tokushima.jp": 1,
+ "anani.br": 1,
+ "ancona.it": 1,
+ "and.mom": 1,
+ "and.museum": 1,
+ "andasuolo.no": 1,
+ "andebu.no": 1,
+ "ando.nara.jp": 1,
+ "andoy.no": 1,
+ "andria-barletta-trani.it": 1,
+ "andria-trani-barletta.it": 1,
+ "andriabarlettatrani.it": 1,
+ "andriatranibarletta.it": 1,
+ "and\u00f8y.no": 1,
+ "anjo.aichi.jp": 1,
+ "ann-arbor.mi.us": 1,
+ "annaka.gunma.jp": 1,
+ "annefrank.museum": 1,
+ "anpachi.gifu.jp": 1,
+ "anthro.museum": 1,
+ "anthropology.museum": 1,
+ "antiques.museum": 1,
+ "ao.it": 1,
+ "aogaki.hyogo.jp": 1,
+ "aogashima.tokyo.jp": 1,
+ "aoki.nagano.jp": 1,
+ "aomori.aomori.jp": 1,
+ "aomori.jp": 1,
+ "aosta-valley.it": 1,
+ "aosta.it": 1,
+ "aostavalley.it": 1,
+ "aoste.it": 1,
+ "ap-northeast-1.elasticbeanstalk.com": 1,
+ "ap-northeast-2.elasticbeanstalk.com": 1,
+ "ap-northeast-3.elasticbeanstalk.com": 1,
+ "ap-south-1.elasticbeanstalk.com": 1,
+ "ap-southeast-1.elasticbeanstalk.com": 1,
+ "ap-southeast-2.elasticbeanstalk.com": 1,
+ "ap.gov.br": 1,
+ "ap.gov.pl": 1,
+ "ap.it": 1,
+ "ap.leg.br": 1,
+ "aparecida.br": 1,
+ "api.stdlib.com": 1,
+ "apigee.io": 1,
+ "app.banzaicloud.io": 1,
+ "app.br": 1,
+ "app.gp": 1,
+ "app.lmpm.com": 1,
+ "app.os.fedoraproject.org": 1,
+ "app.os.stg.fedoraproject.org": 1,
+ "app.render.com": 1,
+ "appchizi.com": 1,
+ "appengine.flow.ch": 1,
+ "applicationcloud.io": 1,
+ "applinzi.com": 1,
+ "apps.fbsbx.com": 1,
+ "apps.lair.io": 1,
+ "appspot.com": 1,
+ "aprendemas.cl": 1,
+ "aq.it": 1,
+ "aquarium.museum": 1,
+ "aquila.it": 1,
+ "ar.com": 1,
+ "ar.it": 1,
+ "ar.us": 1,
+ "arai.shizuoka.jp": 1,
+ "arakawa.saitama.jp": 1,
+ "arakawa.tokyo.jp": 1,
+ "arao.kumamoto.jp": 1,
+ "arboretum.museum": 1,
+ "archaeological.museum": 1,
+ "archaeology.museum": 1,
+ "architecture.museum": 1,
+ "ardal.no": 1,
+ "aremark.no": 1,
+ "arendal.no": 1,
+ "arezzo.it": 1,
+ "ariake.saga.jp": 1,
+ "arida.wakayama.jp": 1,
+ "aridagawa.wakayama.jp": 1,
+ "arita.saga.jp": 1,
+ "arkhangelsk.su": 1,
+ "armenia.su": 1,
+ "arna.no": 1,
+ "arq.br": 1,
+ "art.br": 1,
+ "art.do": 1,
+ "art.dz": 1,
+ "art.ht": 1,
+ "art.museum": 1,
+ "art.pl": 1,
+ "art.sn": 1,
+ "artanddesign.museum": 1,
+ "artcenter.museum": 1,
+ "artdeco.museum": 1,
+ "arte.bo": 1,
+ "arteducation.museum": 1,
+ "artgallery.museum": 1,
+ "arts.co": 1,
+ "arts.museum": 1,
+ "arts.nf": 1,
+ "arts.ro": 1,
+ "arts.ve": 1,
+ "artsandcrafts.museum": 1,
+ "arvo.network": 1,
+ "as.us": 1,
+ "asago.hyogo.jp": 1,
+ "asahi.chiba.jp": 1,
+ "asahi.ibaraki.jp": 1,
+ "asahi.mie.jp": 1,
+ "asahi.nagano.jp": 1,
+ "asahi.toyama.jp": 1,
+ "asahi.yamagata.jp": 1,
+ "asahikawa.hokkaido.jp": 1,
+ "asaka.saitama.jp": 1,
+ "asakawa.fukushima.jp": 1,
+ "asakuchi.okayama.jp": 1,
+ "asaminami.hiroshima.jp": 1,
+ "ascoli-piceno.it": 1,
+ "ascolipiceno.it": 1,
+ "aseral.no": 1,
+ "ashgabad.su": 1,
+ "ashibetsu.hokkaido.jp": 1,
+ "ashikaga.tochigi.jp": 1,
+ "ashiya.fukuoka.jp": 1,
+ "ashiya.hyogo.jp": 1,
+ "ashoro.hokkaido.jp": 1,
+ "asker.no": 1,
+ "askim.no": 1,
+ "askoy.no": 1,
+ "askvoll.no": 1,
+ "ask\u00f8y.no": 1,
+ "asmatart.museum": 1,
+ "asn.au": 1,
+ "asn.lv": 1,
+ "asnes.no": 1,
+ "aso.kumamoto.jp": 1,
+ "ass.km": 1,
+ "assabu.hokkaido.jp": 1,
+ "assassination.museum": 1,
+ "assisi.museum": 1,
+ "assn.lk": 1,
+ "asso.bj": 1,
+ "asso.ci": 1,
+ "asso.dz": 1,
+ "asso.eu.org": 1,
+ "asso.fr": 1,
+ "asso.gp": 1,
+ "asso.ht": 1,
+ "asso.km": 1,
+ "asso.mc": 1,
+ "asso.nc": 1,
+ "asso.re": 1,
+ "association.aero": 1,
+ "association.museum": 1,
+ "asti.it": 1,
+ "astronomy.museum": 1,
+ "asuke.aichi.jp": 1,
+ "at-band-camp.net": 1,
+ "at.eu.org": 1,
+ "at.it": 1,
+ "at.md": 1,
+ "at.vg": 1,
+ "atami.shizuoka.jp": 1,
+ "ath.cx": 1,
+ "atlanta.museum": 1,
+ "atm.pl": 1,
+ "ato.br": 1,
+ "atsugi.kanagawa.jp": 1,
+ "atsuma.hokkaido.jp": 1,
+ "au.eu.org": 1,
+ "audnedaln.no": 1,
+ "augustow.pl": 1,
+ "aukra.no": 1,
+ "aure.no": 1,
+ "aurland.no": 1,
+ "aurskog-holand.no": 1,
+ "aurskog-h\u00f8land.no": 1,
+ "aus.basketball": 1,
+ "austevoll.no": 1,
+ "austin.museum": 1,
+ "australia.museum": 1,
+ "austrheim.no": 1,
+ "author.aero": 1,
+ "auto.pl": 1,
+ "automotive.museum": 1,
+ "av.it": 1,
+ "av.tr": 1,
+ "avellino.it": 1,
+ "averoy.no": 1,
+ "aver\u00f8y.no": 1,
+ "aviation.museum": 1,
+ "avocat.fr": 1,
+ "avocat.pro": 1,
+ "avoues.fr": 1,
+ "awaji.hyogo.jp": 1,
+ "awdev.ca": 2,
+ "awsmppl.com": 1,
+ "axis.museum": 1,
+ "aya.miyazaki.jp": 1,
+ "ayabe.kyoto.jp": 1,
+ "ayagawa.kagawa.jp": 1,
+ "ayase.kanagawa.jp": 1,
+ "az.us": 1,
+ "azerbaijan.su": 1,
+ "azimuth.network": 1,
+ "azumino.nagano.jp": 1,
+ "azure-mobile.net": 1,
+ "azurecontainer.io": 2,
+ "azurewebsites.net": 1,
+ "a\u00e9roport.ci": 1,
+ "b-data.io": 1,
+ "b.bg": 1,
+ "b.br": 1,
+ "b.se": 1,
+ "b.ssl.fastly.net": 1,
+ "ba.gov.br": 1,
+ "ba.it": 1,
+ "ba.leg.br": 1,
+ "babia-gora.pl": 1,
+ "backplaneapp.io": 1,
+ "backyards.banzaicloud.io": 2,
+ "badaddja.no": 1,
+ "badajoz.museum": 1,
+ "baghdad.museum": 1,
+ "bahcavuotna.no": 1,
+ "bahccavuotna.no": 1,
+ "bahn.museum": 1,
+ "baidar.no": 1,
+ "bajddar.no": 1,
+ "balashov.su": 1,
+ "balat.no": 1,
+ "bale.museum": 1,
+ "balena-devices.com": 1,
+ "balestrand.no": 1,
+ "ballangen.no": 1,
+ "ballooning.aero": 1,
+ "balsan-sudtirol.it": 1,
+ "balsan-suedtirol.it": 1,
+ "balsan-s\u00fcdtirol.it": 1,
+ "balsan.it": 1,
+ "balsfjord.no": 1,
+ "baltimore.museum": 1,
+ "bamble.no": 1,
+ "bandai.fukushima.jp": 1,
+ "bando.ibaraki.jp": 1,
+ "banzai.cloud": 2,
+ "bar.pro": 1,
+ "bar0.net": 1,
+ "bar1.net": 1,
+ "bar2.net": 1,
+ "barcelona.museum": 1,
+ "bardu.no": 1,
+ "bari.it": 1,
+ "barletta-trani-andria.it": 1,
+ "barlettatraniandria.it": 1,
+ "barreau.bj": 1,
+ "barrel-of-knowledge.info": 1,
+ "barrell-of-knowledge.info": 1,
+ "barsy.bg": 1,
+ "barsy.ca": 1,
+ "barsy.club": 1,
+ "barsy.co.uk": 1,
+ "barsy.de": 1,
+ "barsy.eu": 1,
+ "barsy.in": 1,
+ "barsy.info": 1,
+ "barsy.io": 1,
+ "barsy.me": 1,
+ "barsy.menu": 1,
+ "barsy.mobi": 1,
+ "barsy.net": 1,
+ "barsy.online": 1,
+ "barsy.org": 1,
+ "barsy.pro": 1,
+ "barsy.pub": 1,
+ "barsy.shop": 1,
+ "barsy.site": 1,
+ "barsy.support": 1,
+ "barsy.uk": 1,
+ "barsycenter.com": 1,
+ "barsyonline.co.uk": 1,
+ "barsyonline.com": 1,
+ "barueri.br": 1,
+ "barum.no": 1,
+ "bas.it": 1,
+ "baseball.museum": 1,
+ "basel.museum": 1,
+ "bashkiria.ru": 1,
+ "bashkiria.su": 1,
+ "basicserver.io": 1,
+ "basilicata.it": 1,
+ "baths.museum": 1,
+ "bato.tochigi.jp": 1,
+ "batsfjord.no": 1,
+ "bauern.museum": 1,
+ "bbs.tr": 1,
+ "bc.ca": 1,
+ "bc.platform.sh": 1,
+ "bci.dnstrace.pro": 1,
+ "bd": 2,
+ "bd.se": 1,
+ "be.ax": 1,
+ "be.eu.org": 1,
+ "be.gy": 1,
+ "bearalvahki.no": 1,
+ "bearalv\u00e1hki.no": 1,
+ "beardu.no": 1,
+ "beauxarts.museum": 1,
+ "bedzin.pl": 1,
+ "beeldengeluid.museum": 1,
+ "beep.pl": 1,
+ "beiarn.no": 1,
+ "bel.tr": 1,
+ "belau.pw": 1,
+ "belem.br": 1,
+ "bellevue.museum": 1,
+ "belluno.it": 1,
+ "benevento.it": 1,
+ "beppu.oita.jp": 1,
+ "berg.no": 1,
+ "bergamo.it": 1,
+ "bergbau.museum": 1,
+ "bergen.no": 1,
+ "berkeley.museum": 1,
+ "berlevag.no": 1,
+ "berlev\u00e5g.no": 1,
+ "berlin.museum": 1,
+ "bern.museum": 1,
+ "beskidy.pl": 1,
+ "beta.bounty-full.com": 1,
+ "betainabox.com": 1,
+ "better-than.tv": 1,
+ "bg.eu.org": 1,
+ "bg.it": 1,
+ "bhz.br": 1,
+ "bi.it": 1,
+ "bialowieza.pl": 1,
+ "bialystok.pl": 1,
+ "bib.br": 1,
+ "bibai.hokkaido.jp": 1,
+ "bible.museum": 1,
+ "biei.hokkaido.jp": 1,
+ "bielawa.pl": 1,
+ "biella.it": 1,
+ "bieszczady.pl": 1,
+ "bievat.no": 1,
+ "biev\u00e1t.no": 1,
+ "bifuka.hokkaido.jp": 1,
+ "bihoro.hokkaido.jp": 1,
+ "bilbao.museum": 1,
+ "bill.museum": 1,
+ "bindal.no": 1,
+ "bio.br": 1,
+ "bip.sh": 1,
+ "bir.ru": 1,
+ "biratori.hokkaido.jp": 1,
+ "birdart.museum": 1,
+ "birkenes.no": 1,
+ "birthplace.museum": 1,
+ "bitbridge.net": 1,
+ "biz.at": 1,
+ "biz.az": 1,
+ "biz.bb": 1,
+ "biz.cy": 1,
+ "biz.dk": 1,
+ "biz.et": 1,
+ "biz.fj": 1,
+ "biz.gl": 1,
+ "biz.id": 1,
+ "biz.ki": 1,
+ "biz.ls": 1,
+ "biz.mv": 1,
+ "biz.mw": 1,
+ "biz.ni": 1,
+ "biz.nr": 1,
+ "biz.pk": 1,
+ "biz.pl": 1,
+ "biz.pr": 1,
+ "biz.ss": 1,
+ "biz.tj": 1,
+ "biz.tr": 1,
+ "biz.tt": 1,
+ "biz.ua": 1,
+ "biz.vn": 1,
+ "biz.zm": 1,
+ "bizen.okayama.jp": 1,
+ "bj.cn": 1,
+ "bjarkoy.no": 1,
+ "bjark\u00f8y.no": 1,
+ "bjerkreim.no": 1,
+ "bjugn.no": 1,
+ "bl.it": 1,
+ "blackbaudcdn.net": 1,
+ "blog.bo": 1,
+ "blog.br": 1,
+ "blog.gt": 1,
+ "blog.kg": 1,
+ "blog.vu": 1,
+ "blogdns.com": 1,
+ "blogdns.net": 1,
+ "blogdns.org": 1,
+ "blogsite.org": 1,
+ "blogsite.xyz": 1,
+ "blogspot.ae": 1,
+ "blogspot.al": 1,
+ "blogspot.am": 1,
+ "blogspot.ba": 1,
+ "blogspot.be": 1,
+ "blogspot.bg": 1,
+ "blogspot.bj": 1,
+ "blogspot.ca": 1,
+ "blogspot.cf": 1,
+ "blogspot.ch": 1,
+ "blogspot.cl": 1,
+ "blogspot.co.at": 1,
+ "blogspot.co.id": 1,
+ "blogspot.co.il": 1,
+ "blogspot.co.ke": 1,
+ "blogspot.co.nz": 1,
+ "blogspot.co.uk": 1,
+ "blogspot.co.za": 1,
+ "blogspot.com": 1,
+ "blogspot.com.ar": 1,
+ "blogspot.com.au": 1,
+ "blogspot.com.br": 1,
+ "blogspot.com.by": 1,
+ "blogspot.com.co": 1,
+ "blogspot.com.cy": 1,
+ "blogspot.com.ee": 1,
+ "blogspot.com.eg": 1,
+ "blogspot.com.es": 1,
+ "blogspot.com.mt": 1,
+ "blogspot.com.ng": 1,
+ "blogspot.com.tr": 1,
+ "blogspot.com.uy": 1,
+ "blogspot.cv": 1,
+ "blogspot.cz": 1,
+ "blogspot.de": 1,
+ "blogspot.dk": 1,
+ "blogspot.fi": 1,
+ "blogspot.fr": 1,
+ "blogspot.gr": 1,
+ "blogspot.hk": 1,
+ "blogspot.hr": 1,
+ "blogspot.hu": 1,
+ "blogspot.ie": 1,
+ "blogspot.in": 1,
+ "blogspot.is": 1,
+ "blogspot.it": 1,
+ "blogspot.jp": 1,
+ "blogspot.kr": 1,
+ "blogspot.li": 1,
+ "blogspot.lt": 1,
+ "blogspot.lu": 1,
+ "blogspot.md": 1,
+ "blogspot.mk": 1,
+ "blogspot.mr": 1,
+ "blogspot.mx": 1,
+ "blogspot.my": 1,
+ "blogspot.nl": 1,
+ "blogspot.no": 1,
+ "blogspot.pe": 1,
+ "blogspot.pt": 1,
+ "blogspot.qa": 1,
+ "blogspot.re": 1,
+ "blogspot.ro": 1,
+ "blogspot.rs": 1,
+ "blogspot.ru": 1,
+ "blogspot.se": 1,
+ "blogspot.sg": 1,
+ "blogspot.si": 1,
+ "blogspot.sk": 1,
+ "blogspot.sn": 1,
+ "blogspot.td": 1,
+ "blogspot.tw": 1,
+ "blogspot.ug": 1,
+ "blogspot.vn": 1,
+ "blogsyte.com": 1,
+ "bloxcms.com": 1,
+ "bmd.br": 1,
+ "bmoattachments.org": 1,
+ "bn.it": 1,
+ "bnr.la": 1,
+ "bo.it": 1,
+ "bo.nordland.no": 1,
+ "bo.telemark.no": 1,
+ "boavista.br": 1,
+ "bodo.no": 1,
+ "bod\u00f8.no": 1,
+ "bokn.no": 1,
+ "boldlygoingnowhere.org": 1,
+ "boleslawiec.pl": 1,
+ "bolivia.bo": 1,
+ "bologna.it": 1,
+ "bolt.hu": 1,
+ "bolzano-altoadige.it": 1,
+ "bolzano.it": 1,
+ "bomlo.no": 1,
+ "bonn.museum": 1,
+ "boomla.net": 1,
+ "boston.museum": 1,
+ "botanical.museum": 1,
+ "botanicalgarden.museum": 1,
+ "botanicgarden.museum": 1,
+ "botany.museum": 1,
+ "bounceme.net": 1,
+ "bounty-full.com": 1,
+ "boxfuse.io": 1,
+ "bozen-sudtirol.it": 1,
+ "bozen-suedtirol.it": 1,
+ "bozen-s\u00fcdtirol.it": 1,
+ "bozen.it": 1,
+ "bpl.biz": 1,
+ "bplaced.com": 1,
+ "bplaced.de": 1,
+ "bplaced.net": 1,
+ "br.com": 1,
+ "br.it": 1,
+ "brand.se": 1,
+ "brandywinevalley.museum": 1,
+ "brasil.museum": 1,
+ "brasilia.me": 1,
+ "bremanger.no": 1,
+ "brescia.it": 1,
+ "brindisi.it": 1,
+ "bristol.museum": 1,
+ "british.museum": 1,
+ "britishcolumbia.museum": 1,
+ "broadcast.museum": 1,
+ "broke-it.net": 1,
+ "broker.aero": 1,
+ "bronnoy.no": 1,
+ "bronnoysund.no": 1,
+ "browsersafetymark.io": 1,
+ "brumunddal.no": 1,
+ "brunel.museum": 1,
+ "brussel.museum": 1,
+ "brussels.museum": 1,
+ "bruxelles.museum": 1,
+ "bryansk.su": 1,
+ "bryne.no": 1,
+ "br\u00f8nn\u00f8y.no": 1,
+ "br\u00f8nn\u00f8ysund.no": 1,
+ "bs.it": 1,
+ "bsb.br": 1,
+ "bss.design": 1,
+ "bt.it": 1,
+ "bu.no": 1,
+ "budejju.no": 1,
+ "building.museum": 1,
+ "builtwithdark.com": 1,
+ "bukhara.su": 1,
+ "bulsan-sudtirol.it": 1,
+ "bulsan-suedtirol.it": 1,
+ "bulsan-s\u00fcdtirol.it": 1,
+ "bulsan.it": 1,
+ "bungoono.oita.jp": 1,
+ "bungotakada.oita.jp": 1,
+ "bunkyo.tokyo.jp": 1,
+ "burghof.museum": 1,
+ "bus.museum": 1,
+ "busan.kr": 1,
+ "bushey.museum": 1,
+ "buyshouses.net": 1,
+ "buzen.fukuoka.jp": 1,
+ "bydgoszcz.pl": 1,
+ "byen.site": 1,
+ "bygland.no": 1,
+ "bykle.no": 1,
+ "bytom.pl": 1,
+ "bz.it": 1,
+ "bzz.dapps.earth": 2,
+ "b\u00e1hcavuotna.no": 1,
+ "b\u00e1hccavuotna.no": 1,
+ "b\u00e1id\u00e1r.no": 1,
+ "b\u00e1jddar.no": 1,
+ "b\u00e1l\u00e1t.no": 1,
+ "b\u00e5d\u00e5ddj\u00e5.no": 1,
+ "b\u00e5tsfjord.no": 1,
+ "b\u00e6rum.no": 1,
+ "b\u00f8.nordland.no": 1,
+ "b\u00f8.telemark.no": 1,
+ "b\u00f8mlo.no": 1,
+ "c.bg": 1,
+ "c.cdn77.org": 1,
+ "c.la": 1,
+ "c.se": 1,
+ "c66.me": 1,
+ "ca-central-1.elasticbeanstalk.com": 1,
+ "ca.eu.org": 1,
+ "ca.it": 1,
+ "ca.na": 1,
+ "ca.us": 1,
+ "caa.aero": 1,
+ "caa.li": 1,
+ "cable-modem.org": 1,
+ "cadaques.museum": 1,
+ "cagliari.it": 1,
+ "cahcesuolo.no": 1,
+ "cal.it": 1,
+ "calabria.it": 1,
+ "california.museum": 1,
+ "caltanissetta.it": 1,
+ "cam.it": 1,
+ "cambridge.museum": 1,
+ "camdvr.org": 1,
+ "campania.it": 1,
+ "campidano-medio.it": 1,
+ "campidanomedio.it": 1,
+ "campinagrande.br": 1,
+ "campinas.br": 1,
+ "campobasso.it": 1,
+ "can.museum": 1,
+ "canada.museum": 1,
+ "capebreton.museum": 1,
+ "carbonia-iglesias.it": 1,
+ "carboniaiglesias.it": 1,
+ "cargo.aero": 1,
+ "carrara-massa.it": 1,
+ "carraramassa.it": 1,
+ "carrd.co": 1,
+ "carrier.museum": 1,
+ "cartoonart.museum": 1,
+ "casacam.net": 1,
+ "casadelamoneda.museum": 1,
+ "caserta.it": 1,
+ "casino.hu": 1,
+ "castle.museum": 1,
+ "castres.museum": 1,
+ "cat.ax": 1,
+ "catania.it": 1,
+ "catanzaro.it": 1,
+ "catering.aero": 1,
+ "catholic.edu.au": 1,
+ "caxias.br": 1,
+ "cb.it": 1,
+ "cbg.ru": 1,
+ "cc.ak.us": 1,
+ "cc.al.us": 1,
+ "cc.ar.us": 1,
+ "cc.as.us": 1,
+ "cc.az.us": 1,
+ "cc.ca.us": 1,
+ "cc.co.us": 1,
+ "cc.ct.us": 1,
+ "cc.dc.us": 1,
+ "cc.de.us": 1,
+ "cc.fl.us": 1,
+ "cc.ga.us": 1,
+ "cc.gu.us": 1,
+ "cc.hi.us": 1,
+ "cc.hn": 1,
+ "cc.ia.us": 1,
+ "cc.id.us": 1,
+ "cc.il.us": 1,
+ "cc.in.us": 1,
+ "cc.ks.us": 1,
+ "cc.ky.us": 1,
+ "cc.la.us": 1,
+ "cc.ma.us": 1,
+ "cc.md.us": 1,
+ "cc.me.us": 1,
+ "cc.mi.us": 1,
+ "cc.mn.us": 1,
+ "cc.mo.us": 1,
+ "cc.ms.us": 1,
+ "cc.mt.us": 1,
+ "cc.na": 1,
+ "cc.nc.us": 1,
+ "cc.nd.us": 1,
+ "cc.ne.us": 1,
+ "cc.nh.us": 1,
+ "cc.nj.us": 1,
+ "cc.nm.us": 1,
+ "cc.nv.us": 1,
+ "cc.ny.us": 1,
+ "cc.oh.us": 1,
+ "cc.ok.us": 1,
+ "cc.or.us": 1,
+ "cc.pa.us": 1,
+ "cc.pr.us": 1,
+ "cc.ri.us": 1,
+ "cc.sc.us": 1,
+ "cc.sd.us": 1,
+ "cc.tn.us": 1,
+ "cc.tx.us": 1,
+ "cc.ua": 1,
+ "cc.ut.us": 1,
+ "cc.va.us": 1,
+ "cc.vi.us": 1,
+ "cc.vt.us": 1,
+ "cc.wa.us": 1,
+ "cc.wi.us": 1,
+ "cc.wv.us": 1,
+ "cc.wy.us": 1,
+ "cci.fr": 1,
+ "cd.eu.org": 1,
+ "cdn77-ssl.net": 1,
+ "ce.gov.br": 1,
+ "ce.it": 1,
+ "ce.leg.br": 1,
+ "cechire.com": 1,
+ "celtic.museum": 1,
+ "center.museum": 1,
+ "certification.aero": 1,
+ "certmgr.org": 1,
+ "cesena-forli.it": 1,
+ "cesena-forl\u00ec.it": 1,
+ "cesenaforli.it": 1,
+ "cesenaforl\u00ec.it": 1,
+ "ch.eu.org": 1,
+ "ch.it": 1,
+ "ch.tc": 1,
+ "chambagri.fr": 1,
+ "championship.aero": 1,
+ "channelsdvr.net": 1,
+ "charter.aero": 1,
+ "chattanooga.museum": 1,
+ "cheltenham.museum": 1,
+ "cherkassy.ua": 1,
+ "cherkasy.ua": 1,
+ "chernigov.ua": 1,
+ "chernihiv.ua": 1,
+ "chernivtsi.ua": 1,
+ "chernovtsy.ua": 1,
+ "chesapeakebay.museum": 1,
+ "chiba.jp": 1,
+ "chicago.museum": 1,
+ "chichibu.saitama.jp": 1,
+ "chieti.it": 1,
+ "chigasaki.kanagawa.jp": 1,
+ "chihayaakasaka.osaka.jp": 1,
+ "chijiwa.nagasaki.jp": 1,
+ "chikugo.fukuoka.jp": 1,
+ "chikuho.fukuoka.jp": 1,
+ "chikuhoku.nagano.jp": 1,
+ "chikujo.fukuoka.jp": 1,
+ "chikuma.nagano.jp": 1,
+ "chikusei.ibaraki.jp": 1,
+ "chikushino.fukuoka.jp": 1,
+ "chikuzen.fukuoka.jp": 1,
+ "children.museum": 1,
+ "childrens.museum": 1,
+ "childrensgarden.museum": 1,
+ "chimkent.su": 1,
+ "chino.nagano.jp": 1,
+ "chippubetsu.hokkaido.jp": 1,
+ "chiropractic.museum": 1,
+ "chirurgiens-dentistes-en-france.fr": 1,
+ "chirurgiens-dentistes.fr": 1,
+ "chiryu.aichi.jp": 1,
+ "chita.aichi.jp": 1,
+ "chitose.hokkaido.jp": 1,
+ "chiyoda.gunma.jp": 1,
+ "chiyoda.tokyo.jp": 1,
+ "chizu.tottori.jp": 1,
+ "chocolate.museum": 1,
+ "chofu.tokyo.jp": 1,
+ "chonan.chiba.jp": 1,
+ "chosei.chiba.jp": 1,
+ "choshi.chiba.jp": 1,
+ "choyo.kumamoto.jp": 1,
+ "christiansburg.museum": 1,
+ "chtr.k12.ma.us": 1,
+ "chungbuk.kr": 1,
+ "chungnam.kr": 1,
+ "chuo.chiba.jp": 1,
+ "chuo.fukuoka.jp": 1,
+ "chuo.osaka.jp": 1,
+ "chuo.tokyo.jp": 1,
+ "chuo.yamanashi.jp": 1,
+ "ci.it": 1,
+ "ciencia.bo": 1,
+ "cieszyn.pl": 1,
+ "cim.br": 1,
+ "cincinnati.museum": 1,
+ "cinema.museum": 1,
+ "circus.museum": 1,
+ "ciscofreak.com": 1,
+ "cistron.nl": 1,
+ "city.hu": 1,
+ "city.kawasaki.jp": 0,
+ "city.kitakyushu.jp": 0,
+ "city.kobe.jp": 0,
+ "city.nagoya.jp": 0,
+ "city.sapporo.jp": 0,
+ "city.sendai.jp": 0,
+ "city.yokohama.jp": 0,
+ "civilaviation.aero": 1,
+ "civilisation.museum": 1,
+ "civilization.museum": 1,
+ "civilwar.museum": 1,
+ "ck": 2,
+ "ck.ua": 1,
+ "cl.it": 1,
+ "clan.rip": 1,
+ "cleverapps.io": 1,
+ "clic2000.net": 1,
+ "clinton.museum": 1,
+ "clock.museum": 1,
+ "cloud.fedoraproject.org": 1,
+ "cloud.goog": 1,
+ "cloud.metacentrum.cz": 2,
+ "cloud66.ws": 1,
+ "cloud66.zone": 1,
+ "cloudaccess.host": 1,
+ "cloudaccess.net": 1,
+ "cloudapp.net": 1,
+ "cloudapps.digital": 1,
+ "cloudcontrolapp.com": 1,
+ "cloudcontrolled.com": 1,
+ "cloudeity.net": 1,
+ "cloudera.site": 1,
+ "cloudfront.net": 1,
+ "cloudfunctions.net": 1,
+ "cloudjiffy.net": 1,
+ "cloudns.asia": 1,
+ "cloudns.biz": 1,
+ "cloudns.cc": 1,
+ "cloudns.club": 1,
+ "cloudns.eu": 1,
+ "cloudns.in": 1,
+ "cloudns.info": 1,
+ "cloudns.org": 1,
+ "cloudns.pro": 1,
+ "cloudns.pw": 1,
+ "cloudns.us": 1,
+ "cloudycluster.net": 1,
+ "club.aero": 1,
+ "club.tw": 1,
+ "cn-north-1.eb.amazonaws.com.cn": 1,
+ "cn-northwest-1.eb.amazonaws.com.cn": 1,
+ "cn.com": 1,
+ "cn.eu.org": 1,
+ "cn.it": 1,
+ "cn.ua": 1,
+ "cn.vu": 1,
+ "cng.br": 1,
+ "cnpy.gdn": 1,
+ "cns.joyent.com": 2,
+ "cnt.br": 1,
+ "co.ae": 1,
+ "co.ag": 1,
+ "co.am": 1,
+ "co.ao": 1,
+ "co.at": 1,
+ "co.bb": 1,
+ "co.bi": 1,
+ "co.bn": 1,
+ "co.business": 1,
+ "co.bw": 1,
+ "co.ca": 1,
+ "co.ci": 1,
+ "co.cl": 1,
+ "co.cm": 1,
+ "co.com": 1,
+ "co.cr": 1,
+ "co.cz": 1,
+ "co.dk": 1,
+ "co.education": 1,
+ "co.events": 1,
+ "co.financial": 1,
+ "co.gg": 1,
+ "co.gl": 1,
+ "co.gy": 1,
+ "co.hu": 1,
+ "co.id": 1,
+ "co.il": 1,
+ "co.im": 1,
+ "co.in": 1,
+ "co.ir": 1,
+ "co.it": 1,
+ "co.je": 1,
+ "co.jp": 1,
+ "co.ke": 1,
+ "co.kr": 1,
+ "co.krd": 1,
+ "co.lc": 1,
+ "co.ls": 1,
+ "co.ma": 1,
+ "co.me": 1,
+ "co.mg": 1,
+ "co.mu": 1,
+ "co.mw": 1,
+ "co.mz": 1,
+ "co.na": 1,
+ "co.network": 1,
+ "co.ni": 1,
+ "co.nl": 1,
+ "co.no": 1,
+ "co.nz": 1,
+ "co.om": 1,
+ "co.pl": 1,
+ "co.place": 1,
+ "co.pn": 1,
+ "co.pw": 1,
+ "co.ro": 1,
+ "co.rs": 1,
+ "co.rw": 1,
+ "co.st": 1,
+ "co.sz": 1,
+ "co.technology": 1,
+ "co.th": 1,
+ "co.tj": 1,
+ "co.tm": 1,
+ "co.tt": 1,
+ "co.tz": 1,
+ "co.ua": 1,
+ "co.ug": 1,
+ "co.uk": 1,
+ "co.us": 1,
+ "co.uz": 1,
+ "co.ve": 1,
+ "co.vi": 1,
+ "co.za": 1,
+ "co.zm": 1,
+ "co.zw": 1,
+ "coal.museum": 1,
+ "coastaldefence.museum": 1,
+ "codespot.com": 1,
+ "cody.museum": 1,
+ "cog.mi.us": 1,
+ "col.ng": 1,
+ "coldwar.museum": 1,
+ "collection.museum": 1,
+ "collegefan.org": 1,
+ "colonialwilliamsburg.museum": 1,
+ "coloradoplateau.museum": 1,
+ "columbia.museum": 1,
+ "columbus.museum": 1,
+ "com.ac": 1,
+ "com.af": 1,
+ "com.ag": 1,
+ "com.ai": 1,
+ "com.al": 1,
+ "com.am": 1,
+ "com.ar": 1,
+ "com.au": 1,
+ "com.aw": 1,
+ "com.az": 1,
+ "com.ba": 1,
+ "com.bb": 1,
+ "com.bh": 1,
+ "com.bi": 1,
+ "com.bm": 1,
+ "com.bn": 1,
+ "com.bo": 1,
+ "com.br": 1,
+ "com.bs": 1,
+ "com.bt": 1,
+ "com.by": 1,
+ "com.bz": 1,
+ "com.ci": 1,
+ "com.cm": 1,
+ "com.cn": 1,
+ "com.co": 1,
+ "com.cu": 1,
+ "com.cw": 1,
+ "com.cy": 1,
+ "com.de": 1,
+ "com.dm": 1,
+ "com.do": 1,
+ "com.dz": 1,
+ "com.ec": 1,
+ "com.ee": 1,
+ "com.eg": 1,
+ "com.es": 1,
+ "com.et": 1,
+ "com.fj": 1,
+ "com.fm": 1,
+ "com.fr": 1,
+ "com.ge": 1,
+ "com.gh": 1,
+ "com.gi": 1,
+ "com.gl": 1,
+ "com.gn": 1,
+ "com.gp": 1,
+ "com.gr": 1,
+ "com.gt": 1,
+ "com.gu": 1,
+ "com.gy": 1,
+ "com.hk": 1,
+ "com.hn": 1,
+ "com.hr": 1,
+ "com.ht": 1,
+ "com.im": 1,
+ "com.io": 1,
+ "com.iq": 1,
+ "com.is": 1,
+ "com.jo": 1,
+ "com.kg": 1,
+ "com.ki": 1,
+ "com.km": 1,
+ "com.kp": 1,
+ "com.kw": 1,
+ "com.ky": 1,
+ "com.kz": 1,
+ "com.la": 1,
+ "com.lb": 1,
+ "com.lc": 1,
+ "com.lk": 1,
+ "com.lr": 1,
+ "com.lv": 1,
+ "com.ly": 1,
+ "com.mg": 1,
+ "com.mk": 1,
+ "com.ml": 1,
+ "com.mo": 1,
+ "com.ms": 1,
+ "com.mt": 1,
+ "com.mu": 1,
+ "com.mv": 1,
+ "com.mw": 1,
+ "com.mx": 1,
+ "com.my": 1,
+ "com.na": 1,
+ "com.nf": 1,
+ "com.ng": 1,
+ "com.ni": 1,
+ "com.nr": 1,
+ "com.om": 1,
+ "com.pa": 1,
+ "com.pe": 1,
+ "com.pf": 1,
+ "com.ph": 1,
+ "com.pk": 1,
+ "com.pl": 1,
+ "com.pr": 1,
+ "com.ps": 1,
+ "com.pt": 1,
+ "com.py": 1,
+ "com.qa": 1,
+ "com.re": 1,
+ "com.ro": 1,
+ "com.ru": 1,
+ "com.sa": 1,
+ "com.sb": 1,
+ "com.sc": 1,
+ "com.sd": 1,
+ "com.se": 1,
+ "com.sg": 1,
+ "com.sh": 1,
+ "com.sl": 1,
+ "com.sn": 1,
+ "com.so": 1,
+ "com.ss": 1,
+ "com.st": 1,
+ "com.sv": 1,
+ "com.sy": 1,
+ "com.tj": 1,
+ "com.tm": 1,
+ "com.tn": 1,
+ "com.to": 1,
+ "com.tr": 1,
+ "com.tt": 1,
+ "com.tw": 1,
+ "com.ua": 1,
+ "com.ug": 1,
+ "com.uy": 1,
+ "com.uz": 1,
+ "com.vc": 1,
+ "com.ve": 1,
+ "com.vi": 1,
+ "com.vn": 1,
+ "com.vu": 1,
+ "com.ws": 1,
+ "com.zm": 1,
+ "commune.am": 1,
+ "communication.museum": 1,
+ "communications.museum": 1,
+ "community-pro.de": 1,
+ "community-pro.net": 1,
+ "community.museum": 1,
+ "como.it": 1,
+ "compute-1.amazonaws.com": 2,
+ "compute.amazonaws.com": 2,
+ "compute.amazonaws.com.cn": 2,
+ "compute.estate": 2,
+ "computer.museum": 1,
+ "computerhistory.museum": 1,
+ "comunica\u00e7\u00f5es.museum": 1,
+ "conf.au": 1,
+ "conf.lv": 1,
+ "conf.se": 1,
+ "conference.aero": 1,
+ "conn.uk": 1,
+ "consulado.st": 1,
+ "consultant.aero": 1,
+ "consulting.aero": 1,
+ "contagem.br": 1,
+ "contemporary.museum": 1,
+ "contemporaryart.museum": 1,
+ "control.aero": 1,
+ "convent.museum": 1,
+ "coop.br": 1,
+ "coop.ht": 1,
+ "coop.km": 1,
+ "coop.mv": 1,
+ "coop.mw": 1,
+ "coop.py": 1,
+ "coop.rw": 1,
+ "coop.tt": 1,
+ "cooperativa.bo": 1,
+ "copenhagen.museum": 1,
+ "copro.uk": 1,
+ "corporation.museum": 1,
+ "correios-e-telecomunica\u00e7\u00f5es.museum": 1,
+ "corvette.museum": 1,
+ "cosenza.it": 1,
+ "costume.museum": 1,
+ "couchpotatofries.org": 1,
+ "couk.me": 1,
+ "council.aero": 1,
+ "countryestate.museum": 1,
+ "county.museum": 1,
+ "coz.br": 1,
+ "cpa.pro": 1,
+ "cq.cn": 1,
+ "cr.it": 1,
+ "cr.ua": 1,
+ "crafting.xyz": 1,
+ "crafts.museum": 1,
+ "cranbrook.museum": 1,
+ "crd.co": 1,
+ "creation.museum": 1,
+ "cremona.it": 1,
+ "crew.aero": 1,
+ "cri.br": 1,
+ "cri.nz": 1,
+ "crimea.ua": 1,
+ "crotone.it": 1,
+ "cryptonomic.net": 2,
+ "cs.it": 1,
+ "csx.cc": 1,
+ "ct.it": 1,
+ "ct.us": 1,
+ "cuiaba.br": 1,
+ "cultural.museum": 1,
+ "culturalcenter.museum": 1,
+ "culture.museum": 1,
+ "cuneo.it": 1,
+ "cupcake.is": 1,
+ "curitiba.br": 1,
+ "curv.dev": 1,
+ "cust.dev.thingdust.io": 1,
+ "cust.disrec.thingdust.io": 1,
+ "cust.prod.thingdust.io": 1,
+ "cust.retrosnub.co.uk": 1,
+ "cust.testing.thingdust.io": 1,
+ "custom.metacentrum.cz": 1,
+ "customer-oci.com": 2,
+ "customer.enonic.io": 1,
+ "customer.mythic-beasts.com": 1,
+ "customer.speedpartner.de": 1,
+ "cv.ua": 1,
+ "cx.ua": 1,
+ "cy.eu.org": 1,
+ "cya.gg": 1,
+ "cyber.museum": 1,
+ "cymru.museum": 1,
+ "cyon.link": 1,
+ "cyon.site": 1,
+ "cz.eu.org": 1,
+ "cz.it": 1,
+ "czeladz.pl": 1,
+ "czest.pl": 1,
+ "d.bg": 1,
+ "d.gv.vc": 1,
+ "d.se": 1,
+ "daegu.kr": 1,
+ "daejeon.kr": 1,
+ "daemon.panel.gg": 1,
+ "dagestan.ru": 1,
+ "dagestan.su": 1,
+ "daigo.ibaraki.jp": 1,
+ "daisen.akita.jp": 1,
+ "daito.osaka.jp": 1,
+ "daiwa.hiroshima.jp": 1,
+ "dali.museum": 1,
+ "dallas.museum": 1,
+ "damnserver.com": 1,
+ "daplie.me": 1,
+ "dapps.earth": 2,
+ "database.museum": 1,
+ "date.fukushima.jp": 1,
+ "date.hokkaido.jp": 1,
+ "dattolocal.com": 1,
+ "dattolocal.net": 1,
+ "dattorelay.com": 1,
+ "dattoweb.com": 1,
+ "davvenjarga.no": 1,
+ "davvenj\u00e1rga.no": 1,
+ "davvesiida.no": 1,
+ "dazaifu.fukuoka.jp": 1,
+ "dc.us": 1,
+ "dd-dns.de": 1,
+ "ddns.me": 1,
+ "ddns.net": 1,
+ "ddnsfree.com": 1,
+ "ddnsgeek.com": 1,
+ "ddnsking.com": 1,
+ "ddnslive.com": 1,
+ "ddnss.de": 1,
+ "ddnss.org": 1,
+ "ddr.museum": 1,
+ "de.com": 1,
+ "de.cool": 1,
+ "de.eu.org": 1,
+ "de.gt": 1,
+ "de.ls": 1,
+ "de.md": 1,
+ "de.us": 1,
+ "deatnu.no": 1,
+ "debian.net": 1,
+ "decorativearts.museum": 1,
+ "dedyn.io": 1,
+ "def.br": 1,
+ "defense.tn": 1,
+ "definima.io": 1,
+ "definima.net": 1,
+ "delaware.museum": 1,
+ "dell-ogliastra.it": 1,
+ "dellogliastra.it": 1,
+ "delmenhorst.museum": 1,
+ "demo.jelastic.com": 1,
+ "democracia.bo": 1,
+ "demon.nl": 1,
+ "denmark.museum": 1,
+ "dep.no": 1,
+ "deporte.bo": 1,
+ "depot.museum": 1,
+ "des.br": 1,
+ "desa.id": 1,
+ "design.aero": 1,
+ "design.museum": 1,
+ "det.br": 1,
+ "detroit.museum": 1,
+ "dev-myqnapcloud.com": 1,
+ "dev.adobeaemcloud.com": 2,
+ "dev.br": 1,
+ "dev.static.land": 1,
+ "dev.vu": 1,
+ "development.run": 1,
+ "devices.resinstaging.io": 1,
+ "df.gov.br": 1,
+ "df.leg.br": 1,
+ "dgca.aero": 1,
+ "dh.bytemark.co.uk": 1,
+ "dielddanuorri.no": 1,
+ "dinosaur.museum": 1,
+ "direct.quickconnect.to": 1,
+ "discourse.group": 1,
+ "discourse.team": 1,
+ "discovery.museum": 1,
+ "diskstation.eu": 1,
+ "diskstation.me": 1,
+ "diskstation.org": 1,
+ "diskussionsbereich.de": 1,
+ "ditchyourip.com": 1,
+ "divtasvuodna.no": 1,
+ "divttasvuotna.no": 1,
+ "dk.eu.org": 1,
+ "dlugoleka.pl": 1,
+ "dn.ua": 1,
+ "dnepropetrovsk.ua": 1,
+ "dni.us": 1,
+ "dnipropetrovsk.ua": 1,
+ "dnsalias.com": 1,
+ "dnsalias.net": 1,
+ "dnsalias.org": 1,
+ "dnsdojo.com": 1,
+ "dnsdojo.net": 1,
+ "dnsdojo.org": 1,
+ "dnsfor.me": 1,
+ "dnshome.de": 1,
+ "dnsiskinky.com": 1,
+ "dnsking.ch": 1,
+ "dnsup.net": 1,
+ "dnsupdate.info": 1,
+ "dnsupdater.de": 1,
+ "does-it.net": 1,
+ "doesntexist.com": 1,
+ "doesntexist.org": 1,
+ "dolls.museum": 1,
+ "donetsk.ua": 1,
+ "donna.no": 1,
+ "donostia.museum": 1,
+ "dontexist.com": 1,
+ "dontexist.net": 1,
+ "dontexist.org": 1,
+ "doomdns.com": 1,
+ "doomdns.org": 1,
+ "dopaas.com": 1,
+ "doshi.yamanashi.jp": 1,
+ "dovre.no": 1,
+ "dp.ua": 1,
+ "dr.na": 1,
+ "dr.tr": 1,
+ "drammen.no": 1,
+ "drangedal.no": 1,
+ "dray-dns.de": 1,
+ "drayddns.com": 1,
+ "draydns.de": 1,
+ "dreamhosters.com": 1,
+ "drobak.no": 1,
+ "drud.io": 1,
+ "drud.us": 1,
+ "dr\u00f8bak.no": 1,
+ "dscloud.biz": 1,
+ "dscloud.me": 1,
+ "dscloud.mobi": 1,
+ "dsmynas.com": 1,
+ "dsmynas.net": 1,
+ "dsmynas.org": 1,
+ "dst.mi.us": 1,
+ "duckdns.org": 1,
+ "durham.museum": 1,
+ "dvrcam.info": 1,
+ "dvrdns.org": 1,
+ "dweb.link": 2,
+ "dy.fi": 1,
+ "dyn-berlin.de": 1,
+ "dyn-ip24.de": 1,
+ "dyn-o-saur.com": 1,
+ "dyn-vpn.de": 1,
+ "dyn.cosidns.de": 1,
+ "dyn.ddnss.de": 1,
+ "dyn.home-webserver.de": 1,
+ "dyn53.io": 1,
+ "dynalias.com": 1,
+ "dynalias.net": 1,
+ "dynalias.org": 1,
+ "dynamic-dns.info": 1,
+ "dynamisches-dns.de": 1,
+ "dynathome.net": 1,
+ "dyndns-at-home.com": 1,
+ "dyndns-at-work.com": 1,
+ "dyndns-blog.com": 1,
+ "dyndns-free.com": 1,
+ "dyndns-home.com": 1,
+ "dyndns-ip.com": 1,
+ "dyndns-mail.com": 1,
+ "dyndns-office.com": 1,
+ "dyndns-pics.com": 1,
+ "dyndns-remote.com": 1,
+ "dyndns-server.com": 1,
+ "dyndns-web.com": 1,
+ "dyndns-wiki.com": 1,
+ "dyndns-work.com": 1,
+ "dyndns.biz": 1,
+ "dyndns.dappnode.io": 1,
+ "dyndns.ddnss.de": 1,
+ "dyndns.info": 1,
+ "dyndns.org": 1,
+ "dyndns.tv": 1,
+ "dyndns.ws": 1,
+ "dyndns1.de": 1,
+ "dynns.com": 1,
+ "dynserv.org": 1,
+ "dynu.net": 1,
+ "dynv6.net": 1,
+ "dynvpn.de": 1,
+ "dyroy.no": 1,
+ "dyr\u00f8y.no": 1,
+ "d\u00f8nna.no": 1,
+ "e.bg": 1,
+ "e.se": 1,
+ "e12.ve": 1,
+ "e164.arpa": 1,
+ "e4.cz": 1,
+ "east-kazakhstan.su": 1,
+ "eastafrica.museum": 1,
+ "eastcoast.museum": 1,
+ "eating-organic.net": 1,
+ "eaton.mi.us": 1,
+ "ebetsu.hokkaido.jp": 1,
+ "ebina.kanagawa.jp": 1,
+ "ebino.miyazaki.jp": 1,
+ "ebiz.tw": 1,
+ "echizen.fukui.jp": 1,
+ "ecn.br": 1,
+ "eco.br": 1,
+ "ecologia.bo": 1,
+ "economia.bo": 1,
+ "ed.ao": 1,
+ "ed.ci": 1,
+ "ed.cr": 1,
+ "ed.jp": 1,
+ "ed.pw": 1,
+ "edgeapp.net": 1,
+ "edgestack.me": 1,
+ "edogawa.tokyo.jp": 1,
+ "edu.ac": 1,
+ "edu.af": 1,
+ "edu.al": 1,
+ "edu.ar": 1,
+ "edu.au": 1,
+ "edu.az": 1,
+ "edu.ba": 1,
+ "edu.bb": 1,
+ "edu.bh": 1,
+ "edu.bi": 1,
+ "edu.bm": 1,
+ "edu.bn": 1,
+ "edu.bo": 1,
+ "edu.br": 1,
+ "edu.bs": 1,
+ "edu.bt": 1,
+ "edu.bz": 1,
+ "edu.ci": 1,
+ "edu.cn": 1,
+ "edu.co": 1,
+ "edu.cu": 1,
+ "edu.cw": 1,
+ "edu.dm": 1,
+ "edu.do": 1,
+ "edu.dz": 1,
+ "edu.ec": 1,
+ "edu.ee": 1,
+ "edu.eg": 1,
+ "edu.es": 1,
+ "edu.et": 1,
+ "edu.eu.org": 1,
+ "edu.fm": 1,
+ "edu.gd": 1,
+ "edu.ge": 1,
+ "edu.gh": 1,
+ "edu.gi": 1,
+ "edu.gl": 1,
+ "edu.gn": 1,
+ "edu.gp": 1,
+ "edu.gr": 1,
+ "edu.gt": 1,
+ "edu.gu": 1,
+ "edu.gy": 1,
+ "edu.hk": 1,
+ "edu.hn": 1,
+ "edu.ht": 1,
+ "edu.in": 1,
+ "edu.iq": 1,
+ "edu.is": 1,
+ "edu.it": 1,
+ "edu.jo": 1,
+ "edu.kg": 1,
+ "edu.ki": 1,
+ "edu.km": 1,
+ "edu.kn": 1,
+ "edu.kp": 1,
+ "edu.krd": 1,
+ "edu.kw": 1,
+ "edu.ky": 1,
+ "edu.kz": 1,
+ "edu.la": 1,
+ "edu.lb": 1,
+ "edu.lc": 1,
+ "edu.lk": 1,
+ "edu.lr": 1,
+ "edu.ls": 1,
+ "edu.lv": 1,
+ "edu.ly": 1,
+ "edu.me": 1,
+ "edu.mg": 1,
+ "edu.mk": 1,
+ "edu.ml": 1,
+ "edu.mn": 1,
+ "edu.mo": 1,
+ "edu.ms": 1,
+ "edu.mt": 1,
+ "edu.mv": 1,
+ "edu.mw": 1,
+ "edu.mx": 1,
+ "edu.my": 1,
+ "edu.mz": 1,
+ "edu.ng": 1,
+ "edu.ni": 1,
+ "edu.nr": 1,
+ "edu.om": 1,
+ "edu.pa": 1,
+ "edu.pe": 1,
+ "edu.pf": 1,
+ "edu.ph": 1,
+ "edu.pk": 1,
+ "edu.pl": 1,
+ "edu.pn": 1,
+ "edu.pr": 1,
+ "edu.ps": 1,
+ "edu.pt": 1,
+ "edu.py": 1,
+ "edu.qa": 1,
+ "edu.rs": 1,
+ "edu.ru": 1,
+ "edu.sa": 1,
+ "edu.sb": 1,
+ "edu.sc": 1,
+ "edu.sd": 1,
+ "edu.sg": 1,
+ "edu.sl": 1,
+ "edu.sn": 1,
+ "edu.so": 1,
+ "edu.ss": 1,
+ "edu.st": 1,
+ "edu.sv": 1,
+ "edu.sy": 1,
+ "edu.tj": 1,
+ "edu.tm": 1,
+ "edu.to": 1,
+ "edu.tr": 1,
+ "edu.tt": 1,
+ "edu.tw": 1,
+ "edu.ua": 1,
+ "edu.uy": 1,
+ "edu.vc": 1,
+ "edu.ve": 1,
+ "edu.vn": 1,
+ "edu.vu": 1,
+ "edu.ws": 1,
+ "edu.za": 1,
+ "edu.zm": 1,
+ "education.museum": 1,
+ "educational.museum": 1,
+ "educator.aero": 1,
+ "edugit.org": 1,
+ "edunet.tn": 1,
+ "ee.eu.org": 1,
+ "egersund.no": 1,
+ "egyptian.museum": 1,
+ "ehime.jp": 1,
+ "eid.no": 1,
+ "eidfjord.no": 1,
+ "eidsberg.no": 1,
+ "eidskog.no": 1,
+ "eidsvoll.no": 1,
+ "eigersund.no": 1,
+ "eiheiji.fukui.jp": 1,
+ "eisenbahn.museum": 1,
+ "ekloges.cy": 1,
+ "elasticbeanstalk.com": 1,
+ "elb.amazonaws.com": 2,
+ "elb.amazonaws.com.cn": 2,
+ "elblag.pl": 1,
+ "elburg.museum": 1,
+ "elk.pl": 1,
+ "elvendrell.museum": 1,
+ "elverum.no": 1,
+ "emb.kw": 1,
+ "embaixada.st": 1,
+ "embetsu.hokkaido.jp": 1,
+ "embroidery.museum": 1,
+ "emergency.aero": 1,
+ "emilia-romagna.it": 1,
+ "emiliaromagna.it": 1,
+ "emp.br": 1,
+ "empresa.bo": 1,
+ "emr.it": 1,
+ "en-root.fr": 1,
+ "en.it": 1,
+ "ena.gifu.jp": 1,
+ "encyclopedic.museum": 1,
+ "endofinternet.net": 1,
+ "endofinternet.org": 1,
+ "endoftheinternet.org": 1,
+ "enebakk.no": 1,
+ "enf.br": 1,
+ "eng.br": 1,
+ "eng.pro": 1,
+ "engerdal.no": 1,
+ "engine.aero": 1,
+ "engineer.aero": 1,
+ "england.museum": 1,
+ "eniwa.hokkaido.jp": 1,
+ "enna.it": 1,
+ "enonic.io": 1,
+ "ens.tn": 1,
+ "ent.platform.sh": 1,
+ "enterprisecloud.nu": 1,
+ "entertainment.aero": 1,
+ "entomology.museum": 1,
+ "environment.museum": 1,
+ "environmentalconservation.museum": 1,
+ "epilepsy.museum": 1,
+ "equipment.aero": 1,
+ "er": 2,
+ "erimo.hokkaido.jp": 1,
+ "erotica.hu": 1,
+ "erotika.hu": 1,
+ "es.ax": 1,
+ "es.eu.org": 1,
+ "es.gov.br": 1,
+ "es.kr": 1,
+ "es.leg.br": 1,
+ "esan.hokkaido.jp": 1,
+ "esashi.hokkaido.jp": 1,
+ "esp.br": 1,
+ "essex.museum": 1,
+ "est-a-la-maison.com": 1,
+ "est-a-la-masion.com": 1,
+ "est-le-patron.com": 1,
+ "est-mon-blogueur.com": 1,
+ "est.pr": 1,
+ "estate.museum": 1,
+ "etajima.hiroshima.jp": 1,
+ "etc.br": 1,
+ "ethnology.museum": 1,
+ "eti.br": 1,
+ "etne.no": 1,
+ "etnedal.no": 1,
+ "eu-1.evennode.com": 1,
+ "eu-2.evennode.com": 1,
+ "eu-3.evennode.com": 1,
+ "eu-4.evennode.com": 1,
+ "eu-central-1.elasticbeanstalk.com": 1,
+ "eu-west-1.elasticbeanstalk.com": 1,
+ "eu-west-2.elasticbeanstalk.com": 1,
+ "eu-west-3.elasticbeanstalk.com": 1,
+ "eu.ax": 1,
+ "eu.com": 1,
+ "eu.int": 1,
+ "eu.meteorapp.com": 1,
+ "eu.org": 1,
+ "eu.platform.sh": 1,
+ "eun.eg": 1,
+ "evenassi.no": 1,
+ "evenes.no": 1,
+ "even\u00e1\u0161\u0161i.no": 1,
+ "evje-og-hornnes.no": 1,
+ "ex.futurecms.at": 2,
+ "ex.ortsinfo.at": 2,
+ "exchange.aero": 1,
+ "exeter.museum": 1,
+ "exhibition.museum": 1,
+ "exnet.su": 1,
+ "experts-comptables.fr": 1,
+ "express.aero": 1,
+ "f.bg": 1,
+ "f.se": 1,
+ "fam.pk": 1,
+ "family.museum": 1,
+ "familyds.com": 1,
+ "familyds.net": 1,
+ "familyds.org": 1,
+ "fantasyleague.cc": 1,
+ "far.br": 1,
+ "farm.museum": 1,
+ "farmequipment.museum": 1,
+ "farmers.museum": 1,
+ "farmstead.museum": 1,
+ "farsund.no": 1,
+ "fastly-terrarium.com": 1,
+ "fastlylb.net": 1,
+ "fastvps-server.com": 1,
+ "fastvps.host": 1,
+ "fastvps.site": 1,
+ "fauske.no": 1,
+ "fbx-os.fr": 1,
+ "fbxos.fr": 1,
+ "fc.it": 1,
+ "fe.it": 1,
+ "fed.us": 1,
+ "federation.aero": 1,
+ "fedje.no": 1,
+ "fedorainfracloud.org": 1,
+ "fedorapeople.org": 1,
+ "feira.br": 1,
+ "fermo.it": 1,
+ "ferrara.it": 1,
+ "feste-ip.net": 1,
+ "fet.no": 1,
+ "fetsund.no": 1,
+ "fg.it": 1,
+ "fh.se": 1,
+ "fhapp.xyz": 1,
+ "fhs.no": 1,
+ "fhsk.se": 1,
+ "fhv.se": 1,
+ "fi.cloudplatform.fi": 1,
+ "fi.cr": 1,
+ "fi.eu.org": 1,
+ "fi.it": 1,
+ "fie.ee": 1,
+ "field.museum": 1,
+ "figueres.museum": 1,
+ "filatelia.museum": 1,
+ "filegear-au.me": 1,
+ "filegear-de.me": 1,
+ "filegear-gb.me": 1,
+ "filegear-ie.me": 1,
+ "filegear-jp.me": 1,
+ "filegear-sg.me": 1,
+ "filegear.me": 1,
+ "film.hu": 1,
+ "film.museum": 1,
+ "fin.ci": 1,
+ "fin.ec": 1,
+ "fin.tn": 1,
+ "fineart.museum": 1,
+ "finearts.museum": 1,
+ "finland.museum": 1,
+ "finnoy.no": 1,
+ "finn\u00f8y.no": 1,
+ "firebaseapp.com": 1,
+ "firenet.ch": 2,
+ "firenze.it": 1,
+ "firewall-gateway.com": 1,
+ "firewall-gateway.de": 1,
+ "firewall-gateway.net": 1,
+ "firm.co": 1,
+ "firm.dk": 1,
+ "firm.ht": 1,
+ "firm.in": 1,
+ "firm.nf": 1,
+ "firm.ng": 1,
+ "firm.ro": 1,
+ "firm.ve": 1,
+ "fitjar.no": 1,
+ "fj.cn": 1,
+ "fjaler.no": 1,
+ "fjell.no": 1,
+ "fk": 2,
+ "fl.us": 1,
+ "fla.no": 1,
+ "flakstad.no": 1,
+ "flanders.museum": 1,
+ "flatanger.no": 1,
+ "flekkefjord.no": 1,
+ "flesberg.no": 1,
+ "flight.aero": 1,
+ "flog.br": 1,
+ "flora.no": 1,
+ "florence.it": 1,
+ "florida.museum": 1,
+ "floripa.br": 1,
+ "floro.no": 1,
+ "flor\u00f8.no": 1,
+ "flt.cloud.muni.cz": 1,
+ "fly.dev": 1,
+ "flynnhosting.net": 1,
+ "fl\u00e5.no": 1,
+ "fm.br": 1,
+ "fm.it": 1,
+ "fm.no": 1,
+ "fnd.br": 1,
+ "fnwk.site": 1,
+ "foggia.it": 1,
+ "folionetwork.site": 1,
+ "folkebibl.no": 1,
+ "folldal.no": 1,
+ "for-better.biz": 1,
+ "for-more.biz": 1,
+ "for-our.info": 1,
+ "for-some.biz": 1,
+ "for-the.biz": 1,
+ "for.men": 1,
+ "for.mom": 1,
+ "for.one": 1,
+ "for.sale": 1,
+ "force.museum": 1,
+ "forde.no": 1,
+ "forgot.her.name": 1,
+ "forgot.his.name": 1,
+ "forli-cesena.it": 1,
+ "forlicesena.it": 1,
+ "forl\u00ec-cesena.it": 1,
+ "forl\u00eccesena.it": 1,
+ "forsand.no": 1,
+ "fortal.br": 1,
+ "forte.id": 1,
+ "fortmissoula.museum": 1,
+ "fortworth.museum": 1,
+ "forum.hu": 1,
+ "forumz.info": 1,
+ "fosnes.no": 1,
+ "fot.br": 1,
+ "foundation.museum": 1,
+ "foz.br": 1,
+ "fr.eu.org": 1,
+ "fr.it": 1,
+ "frana.no": 1,
+ "francaise.museum": 1,
+ "frankfurt.museum": 1,
+ "franziskaner.museum": 1,
+ "fredrikstad.no": 1,
+ "free.hr": 1,
+ "freebox-os.com": 1,
+ "freebox-os.fr": 1,
+ "freeboxos.com": 1,
+ "freeboxos.fr": 1,
+ "freeddns.org": 1,
+ "freeddns.us": 1,
+ "freedesktop.org": 1,
+ "freemasonry.museum": 1,
+ "freesite.host": 1,
+ "freetls.fastly.net": 1,
+ "frei.no": 1,
+ "freiburg.museum": 1,
+ "fribourg.museum": 1,
+ "friuli-v-giulia.it": 1,
+ "friuli-ve-giulia.it": 1,
+ "friuli-vegiulia.it": 1,
+ "friuli-venezia-giulia.it": 1,
+ "friuli-veneziagiulia.it": 1,
+ "friuli-vgiulia.it": 1,
+ "friuliv-giulia.it": 1,
+ "friulive-giulia.it": 1,
+ "friulivegiulia.it": 1,
+ "friulivenezia-giulia.it": 1,
+ "friuliveneziagiulia.it": 1,
+ "friulivgiulia.it": 1,
+ "frog.museum": 1,
+ "frogn.no": 1,
+ "froland.no": 1,
+ "from-ak.com": 1,
+ "from-al.com": 1,
+ "from-ar.com": 1,
+ "from-az.net": 1,
+ "from-ca.com": 1,
+ "from-co.net": 1,
+ "from-ct.com": 1,
+ "from-dc.com": 1,
+ "from-de.com": 1,
+ "from-fl.com": 1,
+ "from-ga.com": 1,
+ "from-hi.com": 1,
+ "from-ia.com": 1,
+ "from-id.com": 1,
+ "from-il.com": 1,
+ "from-in.com": 1,
+ "from-ks.com": 1,
+ "from-ky.com": 1,
+ "from-la.net": 1,
+ "from-ma.com": 1,
+ "from-md.com": 1,
+ "from-me.org": 1,
+ "from-mi.com": 1,
+ "from-mn.com": 1,
+ "from-mo.com": 1,
+ "from-ms.com": 1,
+ "from-mt.com": 1,
+ "from-nc.com": 1,
+ "from-nd.com": 1,
+ "from-ne.com": 1,
+ "from-nh.com": 1,
+ "from-nj.com": 1,
+ "from-nm.com": 1,
+ "from-nv.com": 1,
+ "from-ny.net": 1,
+ "from-oh.com": 1,
+ "from-ok.com": 1,
+ "from-or.com": 1,
+ "from-pa.com": 1,
+ "from-pr.com": 1,
+ "from-ri.com": 1,
+ "from-sc.com": 1,
+ "from-sd.com": 1,
+ "from-tn.com": 1,
+ "from-tx.com": 1,
+ "from-ut.com": 1,
+ "from-va.com": 1,
+ "from-vt.com": 1,
+ "from-wa.com": 1,
+ "from-wi.com": 1,
+ "from-wv.com": 1,
+ "from-wy.com": 1,
+ "from.hr": 1,
+ "frosinone.it": 1,
+ "frosta.no": 1,
+ "froya.no": 1,
+ "fr\u00e6na.no": 1,
+ "fr\u00f8ya.no": 1,
+ "fst.br": 1,
+ "ftpaccess.cc": 1,
+ "fuchu.hiroshima.jp": 1,
+ "fuchu.tokyo.jp": 1,
+ "fuchu.toyama.jp": 1,
+ "fudai.iwate.jp": 1,
+ "fuefuki.yamanashi.jp": 1,
+ "fuel.aero": 1,
+ "fuettertdasnetz.de": 1,
+ "fuji.shizuoka.jp": 1,
+ "fujieda.shizuoka.jp": 1,
+ "fujiidera.osaka.jp": 1,
+ "fujikawa.shizuoka.jp": 1,
+ "fujikawa.yamanashi.jp": 1,
+ "fujikawaguchiko.yamanashi.jp": 1,
+ "fujimi.nagano.jp": 1,
+ "fujimi.saitama.jp": 1,
+ "fujimino.saitama.jp": 1,
+ "fujinomiya.shizuoka.jp": 1,
+ "fujioka.gunma.jp": 1,
+ "fujisato.akita.jp": 1,
+ "fujisawa.iwate.jp": 1,
+ "fujisawa.kanagawa.jp": 1,
+ "fujishiro.ibaraki.jp": 1,
+ "fujiyoshida.yamanashi.jp": 1,
+ "fukagawa.hokkaido.jp": 1,
+ "fukaya.saitama.jp": 1,
+ "fukuchi.fukuoka.jp": 1,
+ "fukuchiyama.kyoto.jp": 1,
+ "fukudomi.saga.jp": 1,
+ "fukui.fukui.jp": 1,
+ "fukui.jp": 1,
+ "fukumitsu.toyama.jp": 1,
+ "fukuoka.jp": 1,
+ "fukuroi.shizuoka.jp": 1,
+ "fukusaki.hyogo.jp": 1,
+ "fukushima.fukushima.jp": 1,
+ "fukushima.hokkaido.jp": 1,
+ "fukushima.jp": 1,
+ "fukuyama.hiroshima.jp": 1,
+ "funabashi.chiba.jp": 1,
+ "funagata.yamagata.jp": 1,
+ "funahashi.toyama.jp": 1,
+ "fundacio.museum": 1,
+ "fuoisku.no": 1,
+ "fuossko.no": 1,
+ "furano.hokkaido.jp": 1,
+ "furniture.museum": 1,
+ "furubira.hokkaido.jp": 1,
+ "furudono.fukushima.jp": 1,
+ "furukawa.miyagi.jp": 1,
+ "fusa.no": 1,
+ "fuso.aichi.jp": 1,
+ "fussa.tokyo.jp": 1,
+ "futaba.fukushima.jp": 1,
+ "futsu.nagasaki.jp": 1,
+ "futtsu.chiba.jp": 1,
+ "futurecms.at": 2,
+ "futurehosting.at": 1,
+ "futuremailing.at": 1,
+ "fvg.it": 1,
+ "fylkesbibl.no": 1,
+ "fyresdal.no": 1,
+ "f\u00f8rde.no": 1,
+ "g.bg": 1,
+ "g.se": 1,
+ "g.vbrplsbx.io": 1,
+ "g12.br": 1,
+ "ga.us": 1,
+ "gaivuotna.no": 1,
+ "gallery.museum": 1,
+ "galsa.no": 1,
+ "gamagori.aichi.jp": 1,
+ "game-host.org": 1,
+ "game-server.cc": 1,
+ "game.tw": 1,
+ "games.hu": 1,
+ "gamo.shiga.jp": 1,
+ "gamvik.no": 1,
+ "gangaviika.no": 1,
+ "gangwon.kr": 1,
+ "garden.museum": 1,
+ "gateway.museum": 1,
+ "gaular.no": 1,
+ "gausdal.no": 1,
+ "gb.com": 1,
+ "gb.net": 1,
+ "gc.ca": 1,
+ "gd.cn": 1,
+ "gda.pl": 1,
+ "gdansk.pl": 1,
+ "gdynia.pl": 1,
+ "ge.it": 1,
+ "geek.nz": 1,
+ "geekgalaxy.com": 1,
+ "geelvinck.museum": 1,
+ "gehirn.ne.jp": 1,
+ "geisei.kochi.jp": 1,
+ "gemological.museum": 1,
+ "gen.in": 1,
+ "gen.mi.us": 1,
+ "gen.ng": 1,
+ "gen.nz": 1,
+ "gen.tr": 1,
+ "genkai.saga.jp": 1,
+ "genoa.it": 1,
+ "genova.it": 1,
+ "gentapps.com": 1,
+ "gentlentapis.com": 1,
+ "geo.br": 1,
+ "geology.museum": 1,
+ "geometre-expert.fr": 1,
+ "georgia.museum": 1,
+ "georgia.su": 1,
+ "getmyip.com": 1,
+ "gets-it.net": 1,
+ "gg.ax": 1,
+ "ggf.br": 1,
+ "giehtavuoatna.no": 1,
+ "giessen.museum": 1,
+ "gifu.gifu.jp": 1,
+ "gifu.jp": 1,
+ "giize.com": 1,
+ "gildeskal.no": 1,
+ "gildesk\u00e5l.no": 1,
+ "ginan.gifu.jp": 1,
+ "ginowan.okinawa.jp": 1,
+ "ginoza.okinawa.jp": 1,
+ "giske.no": 1,
+ "git-pages.rit.edu": 1,
+ "git-repos.de": 1,
+ "gitapp.si": 1,
+ "github.io": 1,
+ "githubusercontent.com": 1,
+ "gitlab.io": 1,
+ "gitpage.si": 1,
+ "gjemnes.no": 1,
+ "gjerdrum.no": 1,
+ "gjerstad.no": 1,
+ "gjesdal.no": 1,
+ "gjovik.no": 1,
+ "gj\u00f8vik.no": 1,
+ "glas.museum": 1,
+ "glass.museum": 1,
+ "gleeze.com": 1,
+ "gliding.aero": 1,
+ "glitch.me": 1,
+ "gliwice.pl": 1,
+ "global.prod.fastly.net": 1,
+ "global.ssl.fastly.net": 1,
+ "glogow.pl": 1,
+ "gloppen.no": 1,
+ "glug.org.uk": 1,
+ "gmina.pl": 1,
+ "gniezno.pl": 1,
+ "go.ci": 1,
+ "go.cr": 1,
+ "go.dyndns.org": 1,
+ "go.gov.br": 1,
+ "go.id": 1,
+ "go.it": 1,
+ "go.jp": 1,
+ "go.ke": 1,
+ "go.kr": 1,
+ "go.leg.br": 1,
+ "go.pw": 1,
+ "go.th": 1,
+ "go.tj": 1,
+ "go.tz": 1,
+ "go.ug": 1,
+ "gob.ar": 1,
+ "gob.bo": 1,
+ "gob.cl": 1,
+ "gob.do": 1,
+ "gob.ec": 1,
+ "gob.es": 1,
+ "gob.gt": 1,
+ "gob.hn": 1,
+ "gob.mx": 1,
+ "gob.ni": 1,
+ "gob.pa": 1,
+ "gob.pe": 1,
+ "gob.pk": 1,
+ "gob.sv": 1,
+ "gob.ve": 1,
+ "gobo.wakayama.jp": 1,
+ "godo.gifu.jp": 1,
+ "goiania.br": 1,
+ "goip.de": 1,
+ "gojome.akita.jp": 1,
+ "gok.pk": 1,
+ "gokase.miyazaki.jp": 1,
+ "gol.no": 1,
+ "golffan.us": 1,
+ "gon.pk": 1,
+ "gonohe.aomori.jp": 1,
+ "googleapis.com": 1,
+ "googlecode.com": 1,
+ "gop.pk": 1,
+ "gorge.museum": 1,
+ "gorizia.it": 1,
+ "gorlice.pl": 1,
+ "gos.pk": 1,
+ "gose.nara.jp": 1,
+ "gosen.niigata.jp": 1,
+ "goshiki.hyogo.jp": 1,
+ "gotdns.ch": 1,
+ "gotdns.com": 1,
+ "gotdns.org": 1,
+ "gotemba.shizuoka.jp": 1,
+ "goto.nagasaki.jp": 1,
+ "gotpantheon.com": 1,
+ "gotsu.shimane.jp": 1,
+ "gouv.bj": 1,
+ "gouv.ci": 1,
+ "gouv.fr": 1,
+ "gouv.ht": 1,
+ "gouv.km": 1,
+ "gouv.ml": 1,
+ "gouv.sn": 1,
+ "gov.ac": 1,
+ "gov.ae": 1,
+ "gov.af": 1,
+ "gov.al": 1,
+ "gov.ar": 1,
+ "gov.as": 1,
+ "gov.au": 1,
+ "gov.az": 1,
+ "gov.ba": 1,
+ "gov.bb": 1,
+ "gov.bf": 1,
+ "gov.bh": 1,
+ "gov.bm": 1,
+ "gov.bn": 1,
+ "gov.br": 1,
+ "gov.bs": 1,
+ "gov.bt": 1,
+ "gov.by": 1,
+ "gov.bz": 1,
+ "gov.cd": 1,
+ "gov.cl": 1,
+ "gov.cm": 1,
+ "gov.cn": 1,
+ "gov.co": 1,
+ "gov.cu": 1,
+ "gov.cx": 1,
+ "gov.cy": 1,
+ "gov.dm": 1,
+ "gov.do": 1,
+ "gov.dz": 1,
+ "gov.ec": 1,
+ "gov.ee": 1,
+ "gov.eg": 1,
+ "gov.et": 1,
+ "gov.fj": 1,
+ "gov.gd": 1,
+ "gov.ge": 1,
+ "gov.gh": 1,
+ "gov.gi": 1,
+ "gov.gn": 1,
+ "gov.gr": 1,
+ "gov.gu": 1,
+ "gov.gy": 1,
+ "gov.hk": 1,
+ "gov.ie": 1,
+ "gov.il": 1,
+ "gov.in": 1,
+ "gov.iq": 1,
+ "gov.ir": 1,
+ "gov.is": 1,
+ "gov.it": 1,
+ "gov.jo": 1,
+ "gov.kg": 1,
+ "gov.ki": 1,
+ "gov.km": 1,
+ "gov.kn": 1,
+ "gov.kp": 1,
+ "gov.kw": 1,
+ "gov.ky": 1,
+ "gov.kz": 1,
+ "gov.la": 1,
+ "gov.lb": 1,
+ "gov.lc": 1,
+ "gov.lk": 1,
+ "gov.lr": 1,
+ "gov.ls": 1,
+ "gov.lt": 1,
+ "gov.lv": 1,
+ "gov.ly": 1,
+ "gov.ma": 1,
+ "gov.me": 1,
+ "gov.mg": 1,
+ "gov.mk": 1,
+ "gov.ml": 1,
+ "gov.mn": 1,
+ "gov.mo": 1,
+ "gov.mr": 1,
+ "gov.ms": 1,
+ "gov.mu": 1,
+ "gov.mv": 1,
+ "gov.mw": 1,
+ "gov.my": 1,
+ "gov.mz": 1,
+ "gov.nc.tr": 1,
+ "gov.ng": 1,
+ "gov.nr": 1,
+ "gov.om": 1,
+ "gov.ph": 1,
+ "gov.pk": 1,
+ "gov.pl": 1,
+ "gov.pn": 1,
+ "gov.pr": 1,
+ "gov.ps": 1,
+ "gov.pt": 1,
+ "gov.py": 1,
+ "gov.qa": 1,
+ "gov.rs": 1,
+ "gov.ru": 1,
+ "gov.rw": 1,
+ "gov.sa": 1,
+ "gov.sb": 1,
+ "gov.sc": 1,
+ "gov.scot": 1,
+ "gov.sd": 1,
+ "gov.sg": 1,
+ "gov.sh": 1,
+ "gov.sl": 1,
+ "gov.so": 1,
+ "gov.ss": 1,
+ "gov.st": 1,
+ "gov.sx": 1,
+ "gov.sy": 1,
+ "gov.tj": 1,
+ "gov.tl": 1,
+ "gov.tm": 1,
+ "gov.tn": 1,
+ "gov.to": 1,
+ "gov.tr": 1,
+ "gov.tt": 1,
+ "gov.tw": 1,
+ "gov.ua": 1,
+ "gov.uk": 1,
+ "gov.vc": 1,
+ "gov.ve": 1,
+ "gov.vn": 1,
+ "gov.ws": 1,
+ "gov.za": 1,
+ "gov.zm": 1,
+ "gov.zw": 1,
+ "government.aero": 1,
+ "govt.nz": 1,
+ "gr.com": 1,
+ "gr.eu.org": 1,
+ "gr.it": 1,
+ "gr.jp": 1,
+ "grajewo.pl": 1,
+ "gran.no": 1,
+ "grandrapids.museum": 1,
+ "grane.no": 1,
+ "granvin.no": 1,
+ "graphox.us": 1,
+ "gratangen.no": 1,
+ "graz.museum": 1,
+ "greta.fr": 1,
+ "grimstad.no": 1,
+ "griw.gov.pl": 1,
+ "groks-the.info": 1,
+ "groks-this.info": 1,
+ "grondar.za": 1,
+ "grong.no": 1,
+ "grosseto.it": 1,
+ "groundhandling.aero": 1,
+ "group.aero": 1,
+ "grozny.ru": 1,
+ "grozny.su": 1,
+ "grp.lk": 1,
+ "gru.br": 1,
+ "grue.no": 1,
+ "gs.aa.no": 1,
+ "gs.ah.no": 1,
+ "gs.bu.no": 1,
+ "gs.cn": 1,
+ "gs.fm.no": 1,
+ "gs.hl.no": 1,
+ "gs.hm.no": 1,
+ "gs.jan-mayen.no": 1,
+ "gs.mr.no": 1,
+ "gs.nl.no": 1,
+ "gs.nt.no": 1,
+ "gs.of.no": 1,
+ "gs.ol.no": 1,
+ "gs.oslo.no": 1,
+ "gs.rl.no": 1,
+ "gs.sf.no": 1,
+ "gs.st.no": 1,
+ "gs.svalbard.no": 1,
+ "gs.tm.no": 1,
+ "gs.tr.no": 1,
+ "gs.va.no": 1,
+ "gs.vf.no": 1,
+ "gsj.bz": 1,
+ "gsm.pl": 1,
+ "gu.us": 1,
+ "guam.gu": 1,
+ "gub.uy": 1,
+ "guernsey.museum": 1,
+ "gujo.gifu.jp": 1,
+ "gulen.no": 1,
+ "gunma.jp": 1,
+ "guovdageaidnu.no": 1,
+ "gushikami.okinawa.jp": 1,
+ "gv.ao": 1,
+ "gv.at": 1,
+ "gv.vc": 1,
+ "gwangju.kr": 1,
+ "gwiddle.co.uk": 1,
+ "gx.cn": 1,
+ "gyeongbuk.kr": 1,
+ "gyeonggi.kr": 1,
+ "gyeongnam.kr": 1,
+ "gyokuto.kumamoto.jp": 1,
+ "gz.cn": 1,
+ "g\u00e1ivuotna.no": 1,
+ "g\u00e1ls\u00e1.no": 1,
+ "g\u00e1\u014bgaviika.no": 1,
+ "h.bg": 1,
+ "h.se": 1,
+ "ha.cn": 1,
+ "ha.no": 1,
+ "habikino.osaka.jp": 1,
+ "habmer.no": 1,
+ "haboro.hokkaido.jp": 1,
+ "hachijo.tokyo.jp": 1,
+ "hachinohe.aomori.jp": 1,
+ "hachioji.tokyo.jp": 1,
+ "hachirogata.akita.jp": 1,
+ "hadano.kanagawa.jp": 1,
+ "hadsel.no": 1,
+ "haebaru.okinawa.jp": 1,
+ "haga.tochigi.jp": 1,
+ "hagebostad.no": 1,
+ "hagi.yamaguchi.jp": 1,
+ "haibara.shizuoka.jp": 1,
+ "hakata.fukuoka.jp": 1,
+ "hakodate.hokkaido.jp": 1,
+ "hakone.kanagawa.jp": 1,
+ "hakuba.nagano.jp": 1,
+ "hakui.ishikawa.jp": 1,
+ "hakusan.ishikawa.jp": 1,
+ "halden.no": 1,
+ "half.host": 1,
+ "halloffame.museum": 1,
+ "halsa.no": 1,
+ "ham-radio-op.net": 1,
+ "hamada.shimane.jp": 1,
+ "hamamatsu.shizuoka.jp": 1,
+ "hamar.no": 1,
+ "hamaroy.no": 1,
+ "hamatama.saga.jp": 1,
+ "hamatonbetsu.hokkaido.jp": 1,
+ "hamburg.museum": 1,
+ "hammarfeasta.no": 1,
+ "hammerfest.no": 1,
+ "hamura.tokyo.jp": 1,
+ "hanamaki.iwate.jp": 1,
+ "hanamigawa.chiba.jp": 1,
+ "hanawa.fukushima.jp": 1,
+ "handa.aichi.jp": 1,
+ "handson.museum": 1,
+ "hanggliding.aero": 1,
+ "hannan.osaka.jp": 1,
+ "hanno.saitama.jp": 1,
+ "hanyu.saitama.jp": 1,
+ "hapmir.no": 1,
+ "happou.akita.jp": 1,
+ "hara.nagano.jp": 1,
+ "haram.no": 1,
+ "hareid.no": 1,
+ "harima.hyogo.jp": 1,
+ "harstad.no": 1,
+ "harvestcelebration.museum": 1,
+ "hasama.oita.jp": 1,
+ "hasami.nagasaki.jp": 1,
+ "hashbang.sh": 1,
+ "hashikami.aomori.jp": 1,
+ "hashima.gifu.jp": 1,
+ "hashimoto.wakayama.jp": 1,
+ "hasuda.saitama.jp": 1,
+ "hasura-app.io": 1,
+ "hasura.app": 1,
+ "hasvik.no": 1,
+ "hatogaya.saitama.jp": 1,
+ "hatoyama.saitama.jp": 1,
+ "hatsukaichi.hiroshima.jp": 1,
+ "hattfjelldal.no": 1,
+ "haugesund.no": 1,
+ "hawaii.museum": 1,
+ "hayakawa.yamanashi.jp": 1,
+ "hayashima.okayama.jp": 1,
+ "hazu.aichi.jp": 1,
+ "hb.cldmail.ru": 1,
+ "hb.cn": 1,
+ "he.cn": 1,
+ "health-carereform.com": 1,
+ "health.museum": 1,
+ "health.nz": 1,
+ "health.vn": 1,
+ "heguri.nara.jp": 1,
+ "heimatunduhren.museum": 1,
+ "hekinan.aichi.jp": 1,
+ "hellas.museum": 1,
+ "helsinki.museum": 1,
+ "hembygdsforbund.museum": 1,
+ "hemne.no": 1,
+ "hemnes.no": 1,
+ "hemsedal.no": 1,
+ "hepforge.org": 1,
+ "herad.no": 1,
+ "here-for-more.info": 1,
+ "heritage.museum": 1,
+ "herokuapp.com": 1,
+ "herokussl.com": 1,
+ "heroy.more-og-romsdal.no": 1,
+ "heroy.nordland.no": 1,
+ "her\u00f8y.m\u00f8re-og-romsdal.no": 1,
+ "her\u00f8y.nordland.no": 1,
+ "hi.cn": 1,
+ "hi.us": 1,
+ "hicam.net": 1,
+ "hichiso.gifu.jp": 1,
+ "hida.gifu.jp": 1,
+ "hidaka.hokkaido.jp": 1,
+ "hidaka.kochi.jp": 1,
+ "hidaka.saitama.jp": 1,
+ "hidaka.wakayama.jp": 1,
+ "hidora.com": 1,
+ "higashi.fukuoka.jp": 1,
+ "higashi.fukushima.jp": 1,
+ "higashi.okinawa.jp": 1,
+ "higashiagatsuma.gunma.jp": 1,
+ "higashichichibu.saitama.jp": 1,
+ "higashihiroshima.hiroshima.jp": 1,
+ "higashiizu.shizuoka.jp": 1,
+ "higashiizumo.shimane.jp": 1,
+ "higashikagawa.kagawa.jp": 1,
+ "higashikagura.hokkaido.jp": 1,
+ "higashikawa.hokkaido.jp": 1,
+ "higashikurume.tokyo.jp": 1,
+ "higashimatsushima.miyagi.jp": 1,
+ "higashimatsuyama.saitama.jp": 1,
+ "higashimurayama.tokyo.jp": 1,
+ "higashinaruse.akita.jp": 1,
+ "higashine.yamagata.jp": 1,
+ "higashiomi.shiga.jp": 1,
+ "higashiosaka.osaka.jp": 1,
+ "higashishirakawa.gifu.jp": 1,
+ "higashisumiyoshi.osaka.jp": 1,
+ "higashitsuno.kochi.jp": 1,
+ "higashiura.aichi.jp": 1,
+ "higashiyama.kyoto.jp": 1,
+ "higashiyamato.tokyo.jp": 1,
+ "higashiyodogawa.osaka.jp": 1,
+ "higashiyoshino.nara.jp": 1,
+ "hiji.oita.jp": 1,
+ "hikari.yamaguchi.jp": 1,
+ "hikawa.shimane.jp": 1,
+ "hikimi.shimane.jp": 1,
+ "hikone.shiga.jp": 1,
+ "himeji.hyogo.jp": 1,
+ "himeshima.oita.jp": 1,
+ "himi.toyama.jp": 1,
+ "hino.tokyo.jp": 1,
+ "hino.tottori.jp": 1,
+ "hinode.tokyo.jp": 1,
+ "hinohara.tokyo.jp": 1,
+ "hioki.kagoshima.jp": 1,
+ "hirado.nagasaki.jp": 1,
+ "hiraizumi.iwate.jp": 1,
+ "hirakata.osaka.jp": 1,
+ "hiranai.aomori.jp": 1,
+ "hirara.okinawa.jp": 1,
+ "hirata.fukushima.jp": 1,
+ "hiratsuka.kanagawa.jp": 1,
+ "hiraya.nagano.jp": 1,
+ "hirogawa.wakayama.jp": 1,
+ "hirokawa.fukuoka.jp": 1,
+ "hirono.fukushima.jp": 1,
+ "hirono.iwate.jp": 1,
+ "hiroo.hokkaido.jp": 1,
+ "hirosaki.aomori.jp": 1,
+ "hiroshima.jp": 1,
+ "hisayama.fukuoka.jp": 1,
+ "histoire.museum": 1,
+ "historical.museum": 1,
+ "historicalsociety.museum": 1,
+ "historichouses.museum": 1,
+ "historisch.museum": 1,
+ "historisches.museum": 1,
+ "history.museum": 1,
+ "historyofscience.museum": 1,
+ "hita.oita.jp": 1,
+ "hitachi.ibaraki.jp": 1,
+ "hitachinaka.ibaraki.jp": 1,
+ "hitachiomiya.ibaraki.jp": 1,
+ "hitachiota.ibaraki.jp": 1,
+ "hitra.no": 1,
+ "hizen.saga.jp": 1,
+ "hjartdal.no": 1,
+ "hjelmeland.no": 1,
+ "hk.cn": 1,
+ "hk.com": 1,
+ "hk.org": 1,
+ "hl.cn": 1,
+ "hl.no": 1,
+ "hm.no": 1,
+ "hn.cn": 1,
+ "hobby-site.com": 1,
+ "hobby-site.org": 1,
+ "hobol.no": 1,
+ "hob\u00f8l.no": 1,
+ "hof.no": 1,
+ "hofu.yamaguchi.jp": 1,
+ "hokkaido.jp": 1,
+ "hokksund.no": 1,
+ "hokuryu.hokkaido.jp": 1,
+ "hokuto.hokkaido.jp": 1,
+ "hokuto.yamanashi.jp": 1,
+ "hol.no": 1,
+ "hole.no": 1,
+ "holmestrand.no": 1,
+ "holtalen.no": 1,
+ "holt\u00e5len.no": 1,
+ "home-webserver.de": 1,
+ "home.dyndns.org": 1,
+ "homebuilt.aero": 1,
+ "homedns.org": 1,
+ "homeftp.net": 1,
+ "homeftp.org": 1,
+ "homeip.net": 1,
+ "homelink.one": 1,
+ "homelinux.com": 1,
+ "homelinux.net": 1,
+ "homelinux.org": 1,
+ "homeoffice.gov.uk": 1,
+ "homesecuritymac.com": 1,
+ "homesecuritypc.com": 1,
+ "homeunix.com": 1,
+ "homeunix.net": 1,
+ "homeunix.org": 1,
+ "honai.ehime.jp": 1,
+ "honbetsu.hokkaido.jp": 1,
+ "honefoss.no": 1,
+ "hongo.hiroshima.jp": 1,
+ "honjo.akita.jp": 1,
+ "honjo.saitama.jp": 1,
+ "honjyo.akita.jp": 1,
+ "hopto.me": 1,
+ "hopto.org": 1,
+ "hornindal.no": 1,
+ "horokanai.hokkaido.jp": 1,
+ "horology.museum": 1,
+ "horonobe.hokkaido.jp": 1,
+ "horten.no": 1,
+ "hostedpi.com": 1,
+ "hosting-cluster.nl": 1,
+ "hosting.myjino.ru": 2,
+ "hostyhosting.io": 1,
+ "hotel.hu": 1,
+ "hotel.lk": 1,
+ "hotel.tz": 1,
+ "house.museum": 1,
+ "hoyanger.no": 1,
+ "hoylandet.no": 1,
+ "hr.eu.org": 1,
+ "hs.kr": 1,
+ "hs.run": 1,
+ "hs.zone": 1,
+ "hu.com": 1,
+ "hu.eu.org": 1,
+ "hu.net": 1,
+ "huissier-justice.fr": 1,
+ "humanities.museum": 1,
+ "hurdal.no": 1,
+ "hurum.no": 1,
+ "hvaler.no": 1,
+ "hyllestad.no": 1,
+ "hyogo.jp": 1,
+ "hyuga.miyazaki.jp": 1,
+ "hzc.io": 1,
+ "h\u00e1bmer.no": 1,
+ "h\u00e1mm\u00e1rfeasta.no": 1,
+ "h\u00e1pmir.no": 1,
+ "h\u00e4kkinen.fi": 1,
+ "h\u00e5.no": 1,
+ "h\u00e6gebostad.no": 1,
+ "h\u00f8nefoss.no": 1,
+ "h\u00f8yanger.no": 1,
+ "h\u00f8ylandet.no": 1,
+ "i.bg": 1,
+ "i.ng": 1,
+ "i.ph": 1,
+ "i.se": 1,
+ "i234.me": 1,
+ "ia.us": 1,
+ "iamallama.com": 1,
+ "ibara.okayama.jp": 1,
+ "ibaraki.ibaraki.jp": 1,
+ "ibaraki.jp": 1,
+ "ibaraki.osaka.jp": 1,
+ "ibestad.no": 1,
+ "ibigawa.gifu.jp": 1,
+ "ic.gov.pl": 1,
+ "ichiba.tokushima.jp": 1,
+ "ichihara.chiba.jp": 1,
+ "ichikai.tochigi.jp": 1,
+ "ichikawa.chiba.jp": 1,
+ "ichikawa.hyogo.jp": 1,
+ "ichikawamisato.yamanashi.jp": 1,
+ "ichinohe.iwate.jp": 1,
+ "ichinomiya.aichi.jp": 1,
+ "ichinomiya.chiba.jp": 1,
+ "ichinoseki.iwate.jp": 1,
+ "id.au": 1,
+ "id.ir": 1,
+ "id.lv": 1,
+ "id.ly": 1,
+ "id.us": 1,
+ "ide.kyoto.jp": 1,
+ "idf.il": 1,
+ "idrett.no": 1,
+ "idv.hk": 1,
+ "idv.tw": 1,
+ "ie.eu.org": 1,
+ "if.ua": 1,
+ "iglesias-carbonia.it": 1,
+ "iglesiascarbonia.it": 1,
+ "iheya.okinawa.jp": 1,
+ "iida.nagano.jp": 1,
+ "iide.yamagata.jp": 1,
+ "iijima.nagano.jp": 1,
+ "iitate.fukushima.jp": 1,
+ "iiyama.nagano.jp": 1,
+ "iizuka.fukuoka.jp": 1,
+ "iizuna.nagano.jp": 1,
+ "ikaruga.nara.jp": 1,
+ "ikata.ehime.jp": 1,
+ "ikawa.akita.jp": 1,
+ "ikeda.fukui.jp": 1,
+ "ikeda.gifu.jp": 1,
+ "ikeda.hokkaido.jp": 1,
+ "ikeda.nagano.jp": 1,
+ "ikeda.osaka.jp": 1,
+ "iki.fi": 1,
+ "iki.nagasaki.jp": 1,
+ "ikoma.nara.jp": 1,
+ "ikusaka.nagano.jp": 1,
+ "il.eu.org": 1,
+ "il.us": 1,
+ "ilawa.pl": 1,
+ "illustration.museum": 1,
+ "ilovecollege.info": 1,
+ "im.it": 1,
+ "imabari.ehime.jp": 1,
+ "imageandsound.museum": 1,
+ "imakane.hokkaido.jp": 1,
+ "imari.saga.jp": 1,
+ "imb.br": 1,
+ "imizu.toyama.jp": 1,
+ "imperia.it": 1,
+ "impertrix.com": 1,
+ "impertrixcdn.com": 1,
+ "in-addr.arpa": 1,
+ "in-berlin.de": 1,
+ "in-brb.de": 1,
+ "in-butter.de": 1,
+ "in-dsl.de": 1,
+ "in-dsl.net": 1,
+ "in-dsl.org": 1,
+ "in-the-band.net": 1,
+ "in-vpn.de": 1,
+ "in-vpn.net": 1,
+ "in-vpn.org": 1,
+ "in.eu.org": 1,
+ "in.futurecms.at": 2,
+ "in.london": 1,
+ "in.na": 1,
+ "in.net": 1,
+ "in.ni": 1,
+ "in.rs": 1,
+ "in.th": 1,
+ "in.ua": 1,
+ "in.us": 1,
+ "ina.ibaraki.jp": 1,
+ "ina.nagano.jp": 1,
+ "ina.saitama.jp": 1,
+ "inabe.mie.jp": 1,
+ "inagawa.hyogo.jp": 1,
+ "inagi.tokyo.jp": 1,
+ "inami.toyama.jp": 1,
+ "inami.wakayama.jp": 1,
+ "inashiki.ibaraki.jp": 1,
+ "inatsuki.fukuoka.jp": 1,
+ "inawashiro.fukushima.jp": 1,
+ "inazawa.aichi.jp": 1,
+ "inc.hk": 1,
+ "incheon.kr": 1,
+ "ind.br": 1,
+ "ind.gt": 1,
+ "ind.in": 1,
+ "ind.kw": 1,
+ "ind.tn": 1,
+ "inderoy.no": 1,
+ "inder\u00f8y.no": 1,
+ "indian.museum": 1,
+ "indiana.museum": 1,
+ "indianapolis.museum": 1,
+ "indianmarket.museum": 1,
+ "indie.porn": 1,
+ "indigena.bo": 1,
+ "industria.bo": 1,
+ "ine.kyoto.jp": 1,
+ "inf.br": 1,
+ "inf.cu": 1,
+ "inf.mk": 1,
+ "inf.ua": 1,
+ "info.at": 1,
+ "info.au": 1,
+ "info.az": 1,
+ "info.bb": 1,
+ "info.bo": 1,
+ "info.co": 1,
+ "info.cx": 1,
+ "info.ec": 1,
+ "info.et": 1,
+ "info.fj": 1,
+ "info.gu": 1,
+ "info.ht": 1,
+ "info.hu": 1,
+ "info.ke": 1,
+ "info.ki": 1,
+ "info.la": 1,
+ "info.ls": 1,
+ "info.mv": 1,
+ "info.na": 1,
+ "info.nf": 1,
+ "info.ni": 1,
+ "info.nr": 1,
+ "info.pk": 1,
+ "info.pl": 1,
+ "info.pr": 1,
+ "info.ro": 1,
+ "info.sd": 1,
+ "info.tn": 1,
+ "info.tr": 1,
+ "info.tt": 1,
+ "info.tz": 1,
+ "info.ve": 1,
+ "info.vn": 1,
+ "info.zm": 1,
+ "ing.pa": 1,
+ "ingatlan.hu": 1,
+ "ino.kochi.jp": 1,
+ "instantcloud.cn": 1,
+ "insurance.aero": 1,
+ "int.ar": 1,
+ "int.az": 1,
+ "int.bo": 1,
+ "int.ci": 1,
+ "int.co": 1,
+ "int.eu.org": 1,
+ "int.is": 1,
+ "int.la": 1,
+ "int.lk": 1,
+ "int.mv": 1,
+ "int.mw": 1,
+ "int.ni": 1,
+ "int.pt": 1,
+ "int.ru": 1,
+ "int.tj": 1,
+ "int.tt": 1,
+ "int.ve": 1,
+ "int.vn": 1,
+ "intelligence.museum": 1,
+ "interactive.museum": 1,
+ "internet-dns.de": 1,
+ "intl.tn": 1,
+ "inuyama.aichi.jp": 1,
+ "inzai.chiba.jp": 1,
+ "io.kg": 1,
+ "iobb.net": 1,
+ "ip6.arpa": 1,
+ "ipifony.net": 1,
+ "iraq.museum": 1,
+ "iris.arpa": 1,
+ "iron.museum": 1,
+ "iruma.saitama.jp": 1,
+ "is-a-anarchist.com": 1,
+ "is-a-blogger.com": 1,
+ "is-a-bookkeeper.com": 1,
+ "is-a-bruinsfan.org": 1,
+ "is-a-bulls-fan.com": 1,
+ "is-a-candidate.org": 1,
+ "is-a-caterer.com": 1,
+ "is-a-celticsfan.org": 1,
+ "is-a-chef.com": 1,
+ "is-a-chef.net": 1,
+ "is-a-chef.org": 1,
+ "is-a-conservative.com": 1,
+ "is-a-cpa.com": 1,
+ "is-a-cubicle-slave.com": 1,
+ "is-a-democrat.com": 1,
+ "is-a-designer.com": 1,
+ "is-a-doctor.com": 1,
+ "is-a-financialadvisor.com": 1,
+ "is-a-geek.com": 1,
+ "is-a-geek.net": 1,
+ "is-a-geek.org": 1,
+ "is-a-green.com": 1,
+ "is-a-guru.com": 1,
+ "is-a-hard-worker.com": 1,
+ "is-a-hunter.com": 1,
+ "is-a-knight.org": 1,
+ "is-a-landscaper.com": 1,
+ "is-a-lawyer.com": 1,
+ "is-a-liberal.com": 1,
+ "is-a-libertarian.com": 1,
+ "is-a-linux-user.org": 1,
+ "is-a-llama.com": 1,
+ "is-a-musician.com": 1,
+ "is-a-nascarfan.com": 1,
+ "is-a-nurse.com": 1,
+ "is-a-painter.com": 1,
+ "is-a-patsfan.org": 1,
+ "is-a-personaltrainer.com": 1,
+ "is-a-photographer.com": 1,
+ "is-a-player.com": 1,
+ "is-a-republican.com": 1,
+ "is-a-rockstar.com": 1,
+ "is-a-socialist.com": 1,
+ "is-a-soxfan.org": 1,
+ "is-a-student.com": 1,
+ "is-a-teacher.com": 1,
+ "is-a-techie.com": 1,
+ "is-a-therapist.com": 1,
+ "is-an-accountant.com": 1,
+ "is-an-actor.com": 1,
+ "is-an-actress.com": 1,
+ "is-an-anarchist.com": 1,
+ "is-an-artist.com": 1,
+ "is-an-engineer.com": 1,
+ "is-an-entertainer.com": 1,
+ "is-by.us": 1,
+ "is-certified.com": 1,
+ "is-found.org": 1,
+ "is-gone.com": 1,
+ "is-into-anime.com": 1,
+ "is-into-cars.com": 1,
+ "is-into-cartoons.com": 1,
+ "is-into-games.com": 1,
+ "is-leet.com": 1,
+ "is-lost.org": 1,
+ "is-not-certified.com": 1,
+ "is-saved.org": 1,
+ "is-slick.com": 1,
+ "is-uberleet.com": 1,
+ "is-very-bad.org": 1,
+ "is-very-evil.org": 1,
+ "is-very-good.org": 1,
+ "is-very-nice.org": 1,
+ "is-very-sweet.org": 1,
+ "is-with-theband.com": 1,
+ "is.eu.org": 1,
+ "is.gov.pl": 1,
+ "is.it": 1,
+ "isa-geek.com": 1,
+ "isa-geek.net": 1,
+ "isa-geek.org": 1,
+ "isa-hockeynut.com": 1,
+ "isa.kagoshima.jp": 1,
+ "isa.us": 1,
+ "isahaya.nagasaki.jp": 1,
+ "ise.mie.jp": 1,
+ "isehara.kanagawa.jp": 1,
+ "isen.kagoshima.jp": 1,
+ "isernia.it": 1,
+ "iserv.dev": 1,
+ "isesaki.gunma.jp": 1,
+ "ishigaki.okinawa.jp": 1,
+ "ishikari.hokkaido.jp": 1,
+ "ishikawa.fukushima.jp": 1,
+ "ishikawa.jp": 1,
+ "ishikawa.okinawa.jp": 1,
+ "ishinomaki.miyagi.jp": 1,
+ "isla.pr": 1,
+ "isleofman.museum": 1,
+ "isshiki.aichi.jp": 1,
+ "issmarterthanyou.com": 1,
+ "isteingeek.de": 1,
+ "istmein.de": 1,
+ "isumi.chiba.jp": 1,
+ "it.ao": 1,
+ "it.eu.org": 1,
+ "itabashi.tokyo.jp": 1,
+ "itako.ibaraki.jp": 1,
+ "itakura.gunma.jp": 1,
+ "itami.hyogo.jp": 1,
+ "itano.tokushima.jp": 1,
+ "itayanagi.aomori.jp": 1,
+ "ito.shizuoka.jp": 1,
+ "itoigawa.niigata.jp": 1,
+ "itoman.okinawa.jp": 1,
+ "its.me": 1,
+ "ivano-frankivsk.ua": 1,
+ "ivanovo.su": 1,
+ "iveland.no": 1,
+ "ivgu.no": 1,
+ "iwade.wakayama.jp": 1,
+ "iwafune.tochigi.jp": 1,
+ "iwaizumi.iwate.jp": 1,
+ "iwaki.fukushima.jp": 1,
+ "iwakuni.yamaguchi.jp": 1,
+ "iwakura.aichi.jp": 1,
+ "iwama.ibaraki.jp": 1,
+ "iwamizawa.hokkaido.jp": 1,
+ "iwanai.hokkaido.jp": 1,
+ "iwanuma.miyagi.jp": 1,
+ "iwata.shizuoka.jp": 1,
+ "iwate.iwate.jp": 1,
+ "iwate.jp": 1,
+ "iwatsuki.saitama.jp": 1,
+ "iwi.nz": 1,
+ "iyo.ehime.jp": 1,
+ "iz.hr": 1,
+ "izena.okinawa.jp": 1,
+ "izu.shizuoka.jp": 1,
+ "izumi.kagoshima.jp": 1,
+ "izumi.osaka.jp": 1,
+ "izumiotsu.osaka.jp": 1,
+ "izumisano.osaka.jp": 1,
+ "izumizaki.fukushima.jp": 1,
+ "izumo.shimane.jp": 1,
+ "izumozaki.niigata.jp": 1,
+ "izunokuni.shizuoka.jp": 1,
+ "j.bg": 1,
+ "j.layershift.co.uk": 1,
+ "j.scaleforce.com.cy": 1,
+ "jab.br": 1,
+ "jambyl.su": 1,
+ "jamison.museum": 1,
+ "jampa.br": 1,
+ "jan-mayen.no": 1,
+ "jaworzno.pl": 1,
+ "jcloud.ik-server.com": 1,
+ "jdevcloud.com": 1,
+ "jdf.br": 1,
+ "jefferson.museum": 1,
+ "jeju.kr": 1,
+ "jelastic.dogado.eu": 1,
+ "jelastic.regruhosting.ru": 1,
+ "jelastic.saveincloud.net": 1,
+ "jelastic.team": 1,
+ "jele.cloud": 1,
+ "jele.club": 1,
+ "jele.host": 1,
+ "jele.io": 1,
+ "jele.site": 1,
+ "jelenia-gora.pl": 1,
+ "jeonbuk.kr": 1,
+ "jeonnam.kr": 1,
+ "jerusalem.museum": 1,
+ "jessheim.no": 1,
+ "jevnaker.no": 1,
+ "jewelry.museum": 1,
+ "jewish.museum": 1,
+ "jewishart.museum": 1,
+ "jfk.museum": 1,
+ "jgora.pl": 1,
+ "jinsekikogen.hiroshima.jp": 1,
+ "jl.cn": 1,
+ "jls-sto1.elastx.net": 1,
+ "jm": 2,
+ "joboji.iwate.jp": 1,
+ "jobs.tt": 1,
+ "joetsu.niigata.jp": 1,
+ "jogasz.hu": 1,
+ "johana.toyama.jp": 1,
+ "joinville.br": 1,
+ "jolster.no": 1,
+ "jondal.no": 1,
+ "jor.br": 1,
+ "jorpeland.no": 1,
+ "joso.ibaraki.jp": 1,
+ "journal.aero": 1,
+ "journalism.museum": 1,
+ "journalist.aero": 1,
+ "joyo.kyoto.jp": 1,
+ "jozi.biz": 1,
+ "jp.eu.org": 1,
+ "jp.kg": 1,
+ "jp.md": 1,
+ "jp.net": 1,
+ "jpn.com": 1,
+ "js.cn": 1,
+ "js.org": 1,
+ "js.wpenginepowered.com": 1,
+ "judaica.museum": 1,
+ "judygarland.museum": 1,
+ "juedisches.museum": 1,
+ "juif.museum": 1,
+ "jur.pro": 1,
+ "jus.br": 1,
+ "jx.cn": 1,
+ "j\u00f8lster.no": 1,
+ "j\u00f8rpeland.no": 1,
+ "k.bg": 1,
+ "k.se": 1,
+ "k12.ak.us": 1,
+ "k12.al.us": 1,
+ "k12.ar.us": 1,
+ "k12.as.us": 1,
+ "k12.az.us": 1,
+ "k12.ca.us": 1,
+ "k12.co.us": 1,
+ "k12.ct.us": 1,
+ "k12.dc.us": 1,
+ "k12.de.us": 1,
+ "k12.ec": 1,
+ "k12.fl.us": 1,
+ "k12.ga.us": 1,
+ "k12.gu.us": 1,
+ "k12.ia.us": 1,
+ "k12.id.us": 1,
+ "k12.il": 1,
+ "k12.il.us": 1,
+ "k12.in.us": 1,
+ "k12.ks.us": 1,
+ "k12.ky.us": 1,
+ "k12.la.us": 1,
+ "k12.ma.us": 1,
+ "k12.md.us": 1,
+ "k12.me.us": 1,
+ "k12.mi.us": 1,
+ "k12.mn.us": 1,
+ "k12.mo.us": 1,
+ "k12.ms.us": 1,
+ "k12.mt.us": 1,
+ "k12.nc.us": 1,
+ "k12.ne.us": 1,
+ "k12.nh.us": 1,
+ "k12.nj.us": 1,
+ "k12.nm.us": 1,
+ "k12.nv.us": 1,
+ "k12.ny.us": 1,
+ "k12.oh.us": 1,
+ "k12.ok.us": 1,
+ "k12.or.us": 1,
+ "k12.pa.us": 1,
+ "k12.pr.us": 1,
+ "k12.sc.us": 1,
+ "k12.tn.us": 1,
+ "k12.tr": 1,
+ "k12.tx.us": 1,
+ "k12.ut.us": 1,
+ "k12.va.us": 1,
+ "k12.vi": 1,
+ "k12.vi.us": 1,
+ "k12.vt.us": 1,
+ "k12.wa.us": 1,
+ "k12.wi.us": 1,
+ "k12.wy.us": 1,
+ "kaas.gg": 1,
+ "kadena.okinawa.jp": 1,
+ "kadogawa.miyazaki.jp": 1,
+ "kadoma.osaka.jp": 1,
+ "kafjord.no": 1,
+ "kaga.ishikawa.jp": 1,
+ "kagami.kochi.jp": 1,
+ "kagamiishi.fukushima.jp": 1,
+ "kagamino.okayama.jp": 1,
+ "kagawa.jp": 1,
+ "kagoshima.jp": 1,
+ "kagoshima.kagoshima.jp": 1,
+ "kaho.fukuoka.jp": 1,
+ "kahoku.ishikawa.jp": 1,
+ "kahoku.yamagata.jp": 1,
+ "kai.yamanashi.jp": 1,
+ "kainan.tokushima.jp": 1,
+ "kainan.wakayama.jp": 1,
+ "kaisei.kanagawa.jp": 1,
+ "kaita.hiroshima.jp": 1,
+ "kaizuka.osaka.jp": 1,
+ "kakamigahara.gifu.jp": 1,
+ "kakegawa.shizuoka.jp": 1,
+ "kakinoki.shimane.jp": 1,
+ "kakogawa.hyogo.jp": 1,
+ "kakuda.miyagi.jp": 1,
+ "kalisz.pl": 1,
+ "kalmykia.ru": 1,
+ "kalmykia.su": 1,
+ "kaluga.su": 1,
+ "kamagaya.chiba.jp": 1,
+ "kamaishi.iwate.jp": 1,
+ "kamakura.kanagawa.jp": 1,
+ "kameoka.kyoto.jp": 1,
+ "kameyama.mie.jp": 1,
+ "kami.kochi.jp": 1,
+ "kami.miyagi.jp": 1,
+ "kamiamakusa.kumamoto.jp": 1,
+ "kamifurano.hokkaido.jp": 1,
+ "kamigori.hyogo.jp": 1,
+ "kamiichi.toyama.jp": 1,
+ "kamiizumi.saitama.jp": 1,
+ "kamijima.ehime.jp": 1,
+ "kamikawa.hokkaido.jp": 1,
+ "kamikawa.hyogo.jp": 1,
+ "kamikawa.saitama.jp": 1,
+ "kamikitayama.nara.jp": 1,
+ "kamikoani.akita.jp": 1,
+ "kamimine.saga.jp": 1,
+ "kaminokawa.tochigi.jp": 1,
+ "kaminoyama.yamagata.jp": 1,
+ "kamioka.akita.jp": 1,
+ "kamisato.saitama.jp": 1,
+ "kamishihoro.hokkaido.jp": 1,
+ "kamisu.ibaraki.jp": 1,
+ "kamisunagawa.hokkaido.jp": 1,
+ "kamitonda.wakayama.jp": 1,
+ "kamitsue.oita.jp": 1,
+ "kamo.kyoto.jp": 1,
+ "kamo.niigata.jp": 1,
+ "kamoenai.hokkaido.jp": 1,
+ "kamogawa.chiba.jp": 1,
+ "kanagawa.jp": 1,
+ "kanan.osaka.jp": 1,
+ "kanazawa.ishikawa.jp": 1,
+ "kanegasaki.iwate.jp": 1,
+ "kaneyama.fukushima.jp": 1,
+ "kaneyama.yamagata.jp": 1,
+ "kani.gifu.jp": 1,
+ "kanie.aichi.jp": 1,
+ "kanmaki.nara.jp": 1,
+ "kanna.gunma.jp": 1,
+ "kannami.shizuoka.jp": 1,
+ "kanonji.kagawa.jp": 1,
+ "kanoya.kagoshima.jp": 1,
+ "kanra.gunma.jp": 1,
+ "kanuma.tochigi.jp": 1,
+ "kanzaki.saga.jp": 1,
+ "karacol.su": 1,
+ "karaganda.su": 1,
+ "karasjohka.no": 1,
+ "karasjok.no": 1,
+ "karasuyama.tochigi.jp": 1,
+ "karate.museum": 1,
+ "karatsu.saga.jp": 1,
+ "karelia.su": 1,
+ "karikatur.museum": 1,
+ "kariwa.niigata.jp": 1,
+ "kariya.aichi.jp": 1,
+ "karlsoy.no": 1,
+ "karmoy.no": 1,
+ "karm\u00f8y.no": 1,
+ "karpacz.pl": 1,
+ "kartuzy.pl": 1,
+ "karuizawa.nagano.jp": 1,
+ "karumai.iwate.jp": 1,
+ "kasahara.gifu.jp": 1,
+ "kasai.hyogo.jp": 1,
+ "kasama.ibaraki.jp": 1,
+ "kasamatsu.gifu.jp": 1,
+ "kasaoka.okayama.jp": 1,
+ "kashiba.nara.jp": 1,
+ "kashihara.nara.jp": 1,
+ "kashima.ibaraki.jp": 1,
+ "kashima.saga.jp": 1,
+ "kashiwa.chiba.jp": 1,
+ "kashiwara.osaka.jp": 1,
+ "kashiwazaki.niigata.jp": 1,
+ "kasserver.com": 1,
+ "kasuga.fukuoka.jp": 1,
+ "kasuga.hyogo.jp": 1,
+ "kasugai.aichi.jp": 1,
+ "kasukabe.saitama.jp": 1,
+ "kasumigaura.ibaraki.jp": 1,
+ "kasuya.fukuoka.jp": 1,
+ "kaszuby.pl": 1,
+ "katagami.akita.jp": 1,
+ "katano.osaka.jp": 1,
+ "katashina.gunma.jp": 1,
+ "katori.chiba.jp": 1,
+ "katowice.pl": 1,
+ "katsuragi.nara.jp": 1,
+ "katsuragi.wakayama.jp": 1,
+ "katsushika.tokyo.jp": 1,
+ "katsuura.chiba.jp": 1,
+ "katsuyama.fukui.jp": 1,
+ "kautokeino.no": 1,
+ "kawaba.gunma.jp": 1,
+ "kawachinagano.osaka.jp": 1,
+ "kawagoe.mie.jp": 1,
+ "kawagoe.saitama.jp": 1,
+ "kawaguchi.saitama.jp": 1,
+ "kawahara.tottori.jp": 1,
+ "kawai.iwate.jp": 1,
+ "kawai.nara.jp": 1,
+ "kawajima.saitama.jp": 1,
+ "kawakami.nagano.jp": 1,
+ "kawakami.nara.jp": 1,
+ "kawakita.ishikawa.jp": 1,
+ "kawamata.fukushima.jp": 1,
+ "kawaminami.miyazaki.jp": 1,
+ "kawanabe.kagoshima.jp": 1,
+ "kawanehon.shizuoka.jp": 1,
+ "kawanishi.hyogo.jp": 1,
+ "kawanishi.nara.jp": 1,
+ "kawanishi.yamagata.jp": 1,
+ "kawara.fukuoka.jp": 1,
+ "kawasaki.jp": 2,
+ "kawasaki.miyagi.jp": 1,
+ "kawatana.nagasaki.jp": 1,
+ "kawaue.gifu.jp": 1,
+ "kawazu.shizuoka.jp": 1,
+ "kayabe.hokkaido.jp": 1,
+ "kazimierz-dolny.pl": 1,
+ "kazo.saitama.jp": 1,
+ "kazuno.akita.jp": 1,
+ "keisen.fukuoka.jp": 1,
+ "kembuchi.hokkaido.jp": 1,
+ "kep.tr": 1,
+ "kepno.pl": 1,
+ "ketrzyn.pl": 1,
+ "keymachine.de": 1,
+ "kg.kr": 1,
+ "kh": 2,
+ "kh.ua": 1,
+ "khakassia.su": 1,
+ "kharkiv.ua": 1,
+ "kharkov.ua": 1,
+ "kherson.ua": 1,
+ "khmelnitskiy.ua": 1,
+ "khmelnytskyi.ua": 1,
+ "khplay.nl": 1,
+ "kibichuo.okayama.jp": 1,
+ "kicks-ass.net": 1,
+ "kicks-ass.org": 1,
+ "kids.museum": 1,
+ "kids.us": 1,
+ "kiev.ua": 1,
+ "kiho.mie.jp": 1,
+ "kihoku.ehime.jp": 1,
+ "kijo.miyazaki.jp": 1,
+ "kikonai.hokkaido.jp": 1,
+ "kikuchi.kumamoto.jp": 1,
+ "kikugawa.shizuoka.jp": 1,
+ "kimino.wakayama.jp": 1,
+ "kimitsu.chiba.jp": 1,
+ "kimobetsu.hokkaido.jp": 1,
+ "kin.okinawa.jp": 1,
+ "kinghost.net": 1,
+ "kinko.kagoshima.jp": 1,
+ "kinokawa.wakayama.jp": 1,
+ "kira.aichi.jp": 1,
+ "kirkenes.no": 1,
+ "kirovograd.ua": 1,
+ "kiryu.gunma.jp": 1,
+ "kisarazu.chiba.jp": 1,
+ "kishiwada.osaka.jp": 1,
+ "kiso.nagano.jp": 1,
+ "kisofukushima.nagano.jp": 1,
+ "kisosaki.mie.jp": 1,
+ "kita.kyoto.jp": 1,
+ "kita.osaka.jp": 1,
+ "kita.tokyo.jp": 1,
+ "kitaaiki.nagano.jp": 1,
+ "kitaakita.akita.jp": 1,
+ "kitadaito.okinawa.jp": 1,
+ "kitagata.gifu.jp": 1,
+ "kitagata.saga.jp": 1,
+ "kitagawa.kochi.jp": 1,
+ "kitagawa.miyazaki.jp": 1,
+ "kitahata.saga.jp": 1,
+ "kitahiroshima.hokkaido.jp": 1,
+ "kitakami.iwate.jp": 1,
+ "kitakata.fukushima.jp": 1,
+ "kitakata.miyazaki.jp": 1,
+ "kitakyushu.jp": 2,
+ "kitami.hokkaido.jp": 1,
+ "kitamoto.saitama.jp": 1,
+ "kitanakagusuku.okinawa.jp": 1,
+ "kitashiobara.fukushima.jp": 1,
+ "kitaura.miyazaki.jp": 1,
+ "kitayama.wakayama.jp": 1,
+ "kiwa.mie.jp": 1,
+ "kiwi.nz": 1,
+ "kiyama.saga.jp": 1,
+ "kiyokawa.kanagawa.jp": 1,
+ "kiyosato.hokkaido.jp": 1,
+ "kiyose.tokyo.jp": 1,
+ "kiyosu.aichi.jp": 1,
+ "kizu.kyoto.jp": 1,
+ "klabu.no": 1,
+ "klepp.no": 1,
+ "klodzko.pl": 1,
+ "kl\u00e6bu.no": 1,
+ "km.ua": 1,
+ "kmpsp.gov.pl": 1,
+ "knightpoint.systems": 1,
+ "knowsitall.info": 1,
+ "knx-server.net": 1,
+ "kobayashi.miyazaki.jp": 1,
+ "kobe.jp": 2,
+ "kobierzyce.pl": 1,
+ "kochi.jp": 1,
+ "kochi.kochi.jp": 1,
+ "kodaira.tokyo.jp": 1,
+ "koebenhavn.museum": 1,
+ "koeln.museum": 1,
+ "kofu.yamanashi.jp": 1,
+ "koga.fukuoka.jp": 1,
+ "koga.ibaraki.jp": 1,
+ "koganei.tokyo.jp": 1,
+ "koge.tottori.jp": 1,
+ "koka.shiga.jp": 1,
+ "kokonoe.oita.jp": 1,
+ "kokubunji.tokyo.jp": 1,
+ "kolobrzeg.pl": 1,
+ "komae.tokyo.jp": 1,
+ "komagane.nagano.jp": 1,
+ "komaki.aichi.jp": 1,
+ "komatsu.ishikawa.jp": 1,
+ "komatsushima.tokushima.jp": 1,
+ "komforb.se": 1,
+ "kommunalforbund.se": 1,
+ "kommune.no": 1,
+ "komono.mie.jp": 1,
+ "komoro.nagano.jp": 1,
+ "komvux.se": 1,
+ "konan.aichi.jp": 1,
+ "konan.shiga.jp": 1,
+ "kongsberg.no": 1,
+ "kongsvinger.no": 1,
+ "konin.pl": 1,
+ "konskowola.pl": 1,
+ "konsulat.gov.pl": 1,
+ "konyvelo.hu": 1,
+ "koori.fukushima.jp": 1,
+ "kopervik.no": 1,
+ "koriyama.fukushima.jp": 1,
+ "koryo.nara.jp": 1,
+ "kosai.shizuoka.jp": 1,
+ "kosaka.akita.jp": 1,
+ "kosei.shiga.jp": 1,
+ "koshigaya.saitama.jp": 1,
+ "koshimizu.hokkaido.jp": 1,
+ "koshu.yamanashi.jp": 1,
+ "kosuge.yamanashi.jp": 1,
+ "kota.aichi.jp": 1,
+ "koto.shiga.jp": 1,
+ "koto.tokyo.jp": 1,
+ "kotohira.kagawa.jp": 1,
+ "kotoura.tottori.jp": 1,
+ "kouhoku.saga.jp": 1,
+ "kounosu.saitama.jp": 1,
+ "kouyama.kagoshima.jp": 1,
+ "kouzushima.tokyo.jp": 1,
+ "koya.wakayama.jp": 1,
+ "koza.wakayama.jp": 1,
+ "kozagawa.wakayama.jp": 1,
+ "kozaki.chiba.jp": 1,
+ "kozow.com": 1,
+ "kppsp.gov.pl": 1,
+ "kr.com": 1,
+ "kr.eu.org": 1,
+ "kr.it": 1,
+ "kr.ua": 1,
+ "kraanghke.no": 1,
+ "kragero.no": 1,
+ "krager\u00f8.no": 1,
+ "krakow.pl": 1,
+ "krasnik.pl": 1,
+ "krasnodar.su": 1,
+ "kristiansand.no": 1,
+ "kristiansund.no": 1,
+ "krodsherad.no": 1,
+ "krokstadelva.no": 1,
+ "krym.ua": 1,
+ "kr\u00e5anghke.no": 1,
+ "kr\u00f8dsherad.no": 1,
+ "ks.ua": 1,
+ "ks.us": 1,
+ "kuchinotsu.nagasaki.jp": 1,
+ "kudamatsu.yamaguchi.jp": 1,
+ "kudoyama.wakayama.jp": 1,
+ "kui.hiroshima.jp": 1,
+ "kuji.iwate.jp": 1,
+ "kuju.oita.jp": 1,
+ "kujukuri.chiba.jp": 1,
+ "kuki.saitama.jp": 1,
+ "kumagaya.saitama.jp": 1,
+ "kumakogen.ehime.jp": 1,
+ "kumamoto.jp": 1,
+ "kumamoto.kumamoto.jp": 1,
+ "kumano.hiroshima.jp": 1,
+ "kumano.mie.jp": 1,
+ "kumatori.osaka.jp": 1,
+ "kumejima.okinawa.jp": 1,
+ "kumenan.okayama.jp": 1,
+ "kumiyama.kyoto.jp": 1,
+ "kunden.ortsinfo.at": 2,
+ "kunigami.okinawa.jp": 1,
+ "kunimi.fukushima.jp": 1,
+ "kunisaki.oita.jp": 1,
+ "kunitachi.tokyo.jp": 1,
+ "kunitomi.miyazaki.jp": 1,
+ "kunneppu.hokkaido.jp": 1,
+ "kunohe.iwate.jp": 1,
+ "kunst.museum": 1,
+ "kunstsammlung.museum": 1,
+ "kunstunddesign.museum": 1,
+ "kurashiki.okayama.jp": 1,
+ "kurate.fukuoka.jp": 1,
+ "kure.hiroshima.jp": 1,
+ "kurgan.su": 1,
+ "kuriyama.hokkaido.jp": 1,
+ "kurobe.toyama.jp": 1,
+ "kurogi.fukuoka.jp": 1,
+ "kuroishi.aomori.jp": 1,
+ "kuroiso.tochigi.jp": 1,
+ "kuromatsunai.hokkaido.jp": 1,
+ "kurotaki.nara.jp": 1,
+ "kurume.fukuoka.jp": 1,
+ "kusatsu.gunma.jp": 1,
+ "kusatsu.shiga.jp": 1,
+ "kushima.miyazaki.jp": 1,
+ "kushimoto.wakayama.jp": 1,
+ "kushiro.hokkaido.jp": 1,
+ "kustanai.ru": 1,
+ "kustanai.su": 1,
+ "kusu.oita.jp": 1,
+ "kutchan.hokkaido.jp": 1,
+ "kutno.pl": 1,
+ "kuwana.mie.jp": 1,
+ "kuzumaki.iwate.jp": 1,
+ "kv.ua": 1,
+ "kvafjord.no": 1,
+ "kvalsund.no": 1,
+ "kvam.no": 1,
+ "kvanangen.no": 1,
+ "kvinesdal.no": 1,
+ "kvinnherad.no": 1,
+ "kviteseid.no": 1,
+ "kvitsoy.no": 1,
+ "kvits\u00f8y.no": 1,
+ "kv\u00e6fjord.no": 1,
+ "kv\u00e6nangen.no": 1,
+ "kwp.gov.pl": 1,
+ "kwpsp.gov.pl": 1,
+ "ky.us": 1,
+ "kyiv.ua": 1,
+ "kyonan.chiba.jp": 1,
+ "kyotamba.kyoto.jp": 1,
+ "kyotanabe.kyoto.jp": 1,
+ "kyotango.kyoto.jp": 1,
+ "kyoto.jp": 1,
+ "kyowa.akita.jp": 1,
+ "kyowa.hokkaido.jp": 1,
+ "kyuragi.saga.jp": 1,
+ "k\u00e1r\u00e1\u0161johka.no": 1,
+ "k\u00e5fjord.no": 1,
+ "l-o-g-i-n.de": 1,
+ "l.bg": 1,
+ "l.se": 1,
+ "la-spezia.it": 1,
+ "la.us": 1,
+ "laakesvuemie.no": 1,
+ "lab.ms": 1,
+ "labor.museum": 1,
+ "labour.museum": 1,
+ "lahppi.no": 1,
+ "lajolla.museum": 1,
+ "lakas.hu": 1,
+ "lanbib.se": 1,
+ "lancashire.museum": 1,
+ "land-4-sale.us": 1,
+ "landes.museum": 1,
+ "landing.myjino.ru": 2,
+ "langevag.no": 1,
+ "langev\u00e5g.no": 1,
+ "lans.museum": 1,
+ "lapy.pl": 1,
+ "laquila.it": 1,
+ "lardal.no": 1,
+ "larsson.museum": 1,
+ "larvik.no": 1,
+ "laspezia.it": 1,
+ "latina.it": 1,
+ "lavagis.no": 1,
+ "lavangen.no": 1,
+ "law.pro": 1,
+ "law.za": 1,
+ "laz.it": 1,
+ "lazio.it": 1,
+ "lc.it": 1,
+ "lcl.dev": 2,
+ "lcube-server.de": 1,
+ "le.it": 1,
+ "leadpages.co": 1,
+ "leangaviika.no": 1,
+ "leasing.aero": 1,
+ "lea\u014bgaviika.no": 1,
+ "lebesby.no": 1,
+ "lebork.pl": 1,
+ "lebtimnetz.de": 1,
+ "lecce.it": 1,
+ "lecco.it": 1,
+ "leczna.pl": 1,
+ "leg.br": 1,
+ "legnica.pl": 1,
+ "leikanger.no": 1,
+ "leirfjord.no": 1,
+ "leirvik.no": 1,
+ "leitungsen.de": 1,
+ "leka.no": 1,
+ "leksvik.no": 1,
+ "lel.br": 1,
+ "lelux.site": 1,
+ "lenug.su": 1,
+ "lenvik.no": 1,
+ "lerdal.no": 1,
+ "lesja.no": 1,
+ "levanger.no": 1,
+ "lewismiller.museum": 1,
+ "lezajsk.pl": 1,
+ "lg.jp": 1,
+ "lg.ua": 1,
+ "li.it": 1,
+ "lib.ak.us": 1,
+ "lib.al.us": 1,
+ "lib.ar.us": 1,
+ "lib.as.us": 1,
+ "lib.az.us": 1,
+ "lib.ca.us": 1,
+ "lib.co.us": 1,
+ "lib.ct.us": 1,
+ "lib.dc.us": 1,
+ "lib.de.us": 1,
+ "lib.ee": 1,
+ "lib.fl.us": 1,
+ "lib.ga.us": 1,
+ "lib.gu.us": 1,
+ "lib.hi.us": 1,
+ "lib.ia.us": 1,
+ "lib.id.us": 1,
+ "lib.il.us": 1,
+ "lib.in.us": 1,
+ "lib.ks.us": 1,
+ "lib.ky.us": 1,
+ "lib.la.us": 1,
+ "lib.ma.us": 1,
+ "lib.md.us": 1,
+ "lib.me.us": 1,
+ "lib.mi.us": 1,
+ "lib.mn.us": 1,
+ "lib.mo.us": 1,
+ "lib.ms.us": 1,
+ "lib.mt.us": 1,
+ "lib.nc.us": 1,
+ "lib.nd.us": 1,
+ "lib.ne.us": 1,
+ "lib.nh.us": 1,
+ "lib.nj.us": 1,
+ "lib.nm.us": 1,
+ "lib.nv.us": 1,
+ "lib.ny.us": 1,
+ "lib.oh.us": 1,
+ "lib.ok.us": 1,
+ "lib.or.us": 1,
+ "lib.pa.us": 1,
+ "lib.pr.us": 1,
+ "lib.ri.us": 1,
+ "lib.sc.us": 1,
+ "lib.sd.us": 1,
+ "lib.tn.us": 1,
+ "lib.tx.us": 1,
+ "lib.ut.us": 1,
+ "lib.va.us": 1,
+ "lib.vi.us": 1,
+ "lib.vt.us": 1,
+ "lib.wa.us": 1,
+ "lib.wi.us": 1,
+ "lib.wy.us": 1,
+ "lier.no": 1,
+ "lierne.no": 1,
+ "lig.it": 1,
+ "liguria.it": 1,
+ "likes-pie.com": 1,
+ "likescandy.com": 1,
+ "lillehammer.no": 1,
+ "lillesand.no": 1,
+ "lima-city.at": 1,
+ "lima-city.ch": 1,
+ "lima-city.de": 1,
+ "lima-city.rocks": 1,
+ "lima.zone": 1,
+ "limanowa.pl": 1,
+ "lincoln.museum": 1,
+ "lindas.no": 1,
+ "lindesnes.no": 1,
+ "lind\u00e5s.no": 1,
+ "linkitools.space": 1,
+ "linkyard-cloud.ch": 1,
+ "linkyard.cloud": 1,
+ "linodeobjects.com": 2,
+ "linz.museum": 1,
+ "living.museum": 1,
+ "livinghistory.museum": 1,
+ "livorno.it": 1,
+ "ln.cn": 1,
+ "lo.it": 1,
+ "loabat.no": 1,
+ "loab\u00e1t.no": 1,
+ "localhistory.museum": 1,
+ "localhost.daplie.me": 1,
+ "localzone.xyz": 1,
+ "lodi.it": 1,
+ "lodingen.no": 1,
+ "log.br": 1,
+ "loginline.app": 1,
+ "loginline.dev": 1,
+ "loginline.io": 1,
+ "loginline.services": 1,
+ "loginline.site": 1,
+ "loginto.me": 1,
+ "logistics.aero": 1,
+ "logoip.com": 1,
+ "logoip.de": 1,
+ "lolipop.io": 1,
+ "lom.it": 1,
+ "lom.no": 1,
+ "lombardia.it": 1,
+ "lombardy.it": 1,
+ "lomza.pl": 1,
+ "london.cloudapps.digital": 1,
+ "london.museum": 1,
+ "londrina.br": 1,
+ "loppa.no": 1,
+ "lorenskog.no": 1,
+ "losangeles.museum": 1,
+ "loseyourip.com": 1,
+ "loten.no": 1,
+ "louvre.museum": 1,
+ "lowicz.pl": 1,
+ "loyalist.museum": 1,
+ "lpages.co": 1,
+ "lpusercontent.com": 1,
+ "lt.eu.org": 1,
+ "lt.it": 1,
+ "lt.ua": 1,
+ "ltd.co.im": 1,
+ "ltd.cy": 1,
+ "ltd.gi": 1,
+ "ltd.hk": 1,
+ "ltd.lk": 1,
+ "ltd.ng": 1,
+ "ltd.ua": 1,
+ "ltd.uk": 1,
+ "lu.eu.org": 1,
+ "lu.it": 1,
+ "lubartow.pl": 1,
+ "lubin.pl": 1,
+ "lublin.pl": 1,
+ "lucania.it": 1,
+ "lucca.it": 1,
+ "lucerne.museum": 1,
+ "lug.org.uk": 1,
+ "lugansk.ua": 1,
+ "lugs.org.uk": 1,
+ "lukow.pl": 1,
+ "lund.no": 1,
+ "lunner.no": 1,
+ "luroy.no": 1,
+ "lur\u00f8y.no": 1,
+ "luster.no": 1,
+ "lutsk.ua": 1,
+ "luxembourg.museum": 1,
+ "luzern.museum": 1,
+ "lv.eu.org": 1,
+ "lv.ua": 1,
+ "lviv.ua": 1,
+ "lyngdal.no": 1,
+ "lyngen.no": 1,
+ "lynx.mythic-beasts.com": 1,
+ "l\u00e1hppi.no": 1,
+ "l\u00e4ns.museum": 1,
+ "l\u00e6rdal.no": 1,
+ "l\u00f8dingen.no": 1,
+ "l\u00f8renskog.no": 1,
+ "l\u00f8ten.no": 1,
+ "m.bg": 1,
+ "m.se": 1,
+ "ma.gov.br": 1,
+ "ma.leg.br": 1,
+ "ma.us": 1,
+ "macapa.br": 1,
+ "maceio.br": 1,
+ "macerata.it": 1,
+ "machida.tokyo.jp": 1,
+ "mad.museum": 1,
+ "madrid.museum": 1,
+ "maebashi.gunma.jp": 1,
+ "magazine.aero": 1,
+ "magentosite.cloud": 2,
+ "maibara.shiga.jp": 1,
+ "mail.pl": 1,
+ "maintenance.aero": 1,
+ "maizuru.kyoto.jp": 1,
+ "makinohara.shizuoka.jp": 1,
+ "makurazaki.kagoshima.jp": 1,
+ "malatvuopmi.no": 1,
+ "malbork.pl": 1,
+ "mallorca.museum": 1,
+ "malopolska.pl": 1,
+ "malselv.no": 1,
+ "malvik.no": 1,
+ "mamurogawa.yamagata.jp": 1,
+ "manaus.br": 1,
+ "manchester.museum": 1,
+ "mandal.no": 1,
+ "mangyshlak.su": 1,
+ "maniwa.okayama.jp": 1,
+ "manno.kagawa.jp": 1,
+ "mansion.museum": 1,
+ "mansions.museum": 1,
+ "mantova.it": 1,
+ "manx.museum": 1,
+ "maori.nz": 1,
+ "map.fastly.net": 1,
+ "map.fastlylb.net": 1,
+ "mar.it": 1,
+ "marburg.museum": 1,
+ "marche.it": 1,
+ "marine.ru": 1,
+ "maringa.br": 1,
+ "maritime.museum": 1,
+ "maritimo.museum": 1,
+ "marker.no": 1,
+ "marnardal.no": 1,
+ "marugame.kagawa.jp": 1,
+ "marumori.miyagi.jp": 1,
+ "maryland.museum": 1,
+ "marylhurst.museum": 1,
+ "masaki.ehime.jp": 1,
+ "masfjorden.no": 1,
+ "mashike.hokkaido.jp": 1,
+ "mashiki.kumamoto.jp": 1,
+ "mashiko.tochigi.jp": 1,
+ "masoy.no": 1,
+ "massa-carrara.it": 1,
+ "massacarrara.it": 1,
+ "masuda.shimane.jp": 1,
+ "mat.br": 1,
+ "matera.it": 1,
+ "matsubara.osaka.jp": 1,
+ "matsubushi.saitama.jp": 1,
+ "matsuda.kanagawa.jp": 1,
+ "matsudo.chiba.jp": 1,
+ "matsue.shimane.jp": 1,
+ "matsukawa.nagano.jp": 1,
+ "matsumae.hokkaido.jp": 1,
+ "matsumoto.kagoshima.jp": 1,
+ "matsumoto.nagano.jp": 1,
+ "matsuno.ehime.jp": 1,
+ "matsusaka.mie.jp": 1,
+ "matsushige.tokushima.jp": 1,
+ "matsushima.miyagi.jp": 1,
+ "matsuura.nagasaki.jp": 1,
+ "matsuyama.ehime.jp": 1,
+ "matsuzaki.shizuoka.jp": 1,
+ "matta-varjjat.no": 1,
+ "mayfirst.info": 1,
+ "mayfirst.org": 1,
+ "mazowsze.pl": 1,
+ "mazury.pl": 1,
+ "mb.ca": 1,
+ "mb.it": 1,
+ "mc.ax": 1,
+ "mc.eu.org": 1,
+ "mc.it": 1,
+ "mcdir.ru": 1,
+ "mcpe.me": 1,
+ "md.ci": 1,
+ "md.us": 1,
+ "me.eu.org": 1,
+ "me.it": 1,
+ "me.ke": 1,
+ "me.so": 1,
+ "me.tc": 1,
+ "me.tz": 1,
+ "me.uk": 1,
+ "me.us": 1,
+ "me.vu": 1,
+ "med.br": 1,
+ "med.ec": 1,
+ "med.ee": 1,
+ "med.ht": 1,
+ "med.ly": 1,
+ "med.om": 1,
+ "med.pa": 1,
+ "med.pl": 1,
+ "med.pro": 1,
+ "med.sa": 1,
+ "med.sd": 1,
+ "medecin.fr": 1,
+ "medecin.km": 1,
+ "media.aero": 1,
+ "media.hu": 1,
+ "media.museum": 1,
+ "media.pl": 1,
+ "medical.museum": 1,
+ "medicina.bo": 1,
+ "medio-campidano.it": 1,
+ "mediocampidano.it": 1,
+ "medizinhistorisches.museum": 1,
+ "meeres.museum": 1,
+ "meguro.tokyo.jp": 1,
+ "mein-iserv.de": 1,
+ "mein-vigor.de": 1,
+ "meinforum.net": 1,
+ "meiwa.gunma.jp": 1,
+ "meiwa.mie.jp": 1,
+ "meland.no": 1,
+ "meldal.no": 1,
+ "melhus.no": 1,
+ "meloy.no": 1,
+ "mel\u00f8y.no": 1,
+ "members.linode.com": 1,
+ "memorial.museum": 1,
+ "memset.net": 1,
+ "meraker.no": 1,
+ "merseine.nu": 1,
+ "mer\u00e5ker.no": 1,
+ "mesaverde.museum": 1,
+ "messina.it": 1,
+ "meteorapp.com": 1,
+ "mex.com": 1,
+ "mg.gov.br": 1,
+ "mg.leg.br": 1,
+ "mi.it": 1,
+ "mi.th": 1,
+ "mi.us": 1,
+ "miasa.nagano.jp": 1,
+ "miasta.pl": 1,
+ "mibu.tochigi.jp": 1,
+ "michigan.museum": 1,
+ "microlight.aero": 1,
+ "midatlantic.museum": 1,
+ "midori.chiba.jp": 1,
+ "midori.gunma.jp": 1,
+ "midsund.no": 1,
+ "midtre-gauldal.no": 1,
+ "mie.jp": 1,
+ "mielec.pl": 1,
+ "mielno.pl": 1,
+ "mifune.kumamoto.jp": 1,
+ "mihama.aichi.jp": 1,
+ "mihama.chiba.jp": 1,
+ "mihama.fukui.jp": 1,
+ "mihama.mie.jp": 1,
+ "mihama.wakayama.jp": 1,
+ "mihara.hiroshima.jp": 1,
+ "mihara.kochi.jp": 1,
+ "miharu.fukushima.jp": 1,
+ "miho.ibaraki.jp": 1,
+ "mikasa.hokkaido.jp": 1,
+ "mikawa.yamagata.jp": 1,
+ "miki.hyogo.jp": 1,
+ "mil.ac": 1,
+ "mil.ae": 1,
+ "mil.al": 1,
+ "mil.ar": 1,
+ "mil.az": 1,
+ "mil.ba": 1,
+ "mil.bo": 1,
+ "mil.br": 1,
+ "mil.by": 1,
+ "mil.cl": 1,
+ "mil.cn": 1,
+ "mil.co": 1,
+ "mil.do": 1,
+ "mil.ec": 1,
+ "mil.eg": 1,
+ "mil.fj": 1,
+ "mil.ge": 1,
+ "mil.gh": 1,
+ "mil.gt": 1,
+ "mil.hn": 1,
+ "mil.id": 1,
+ "mil.in": 1,
+ "mil.iq": 1,
+ "mil.jo": 1,
+ "mil.kg": 1,
+ "mil.km": 1,
+ "mil.kr": 1,
+ "mil.kz": 1,
+ "mil.lv": 1,
+ "mil.mg": 1,
+ "mil.mv": 1,
+ "mil.my": 1,
+ "mil.mz": 1,
+ "mil.ng": 1,
+ "mil.ni": 1,
+ "mil.no": 1,
+ "mil.nz": 1,
+ "mil.pe": 1,
+ "mil.ph": 1,
+ "mil.pl": 1,
+ "mil.py": 1,
+ "mil.qa": 1,
+ "mil.ru": 1,
+ "mil.rw": 1,
+ "mil.sh": 1,
+ "mil.st": 1,
+ "mil.sy": 1,
+ "mil.tj": 1,
+ "mil.tm": 1,
+ "mil.to": 1,
+ "mil.tr": 1,
+ "mil.tw": 1,
+ "mil.tz": 1,
+ "mil.uy": 1,
+ "mil.vc": 1,
+ "mil.ve": 1,
+ "mil.za": 1,
+ "mil.zm": 1,
+ "mil.zw": 1,
+ "milan.it": 1,
+ "milano.it": 1,
+ "military.museum": 1,
+ "mill.museum": 1,
+ "mima.tokushima.jp": 1,
+ "mimata.miyazaki.jp": 1,
+ "minakami.gunma.jp": 1,
+ "minamata.kumamoto.jp": 1,
+ "minami-alps.yamanashi.jp": 1,
+ "minami.fukuoka.jp": 1,
+ "minami.kyoto.jp": 1,
+ "minami.tokushima.jp": 1,
+ "minamiaiki.nagano.jp": 1,
+ "minamiashigara.kanagawa.jp": 1,
+ "minamiawaji.hyogo.jp": 1,
+ "minamiboso.chiba.jp": 1,
+ "minamidaito.okinawa.jp": 1,
+ "minamiechizen.fukui.jp": 1,
+ "minamifurano.hokkaido.jp": 1,
+ "minamiise.mie.jp": 1,
+ "minamiizu.shizuoka.jp": 1,
+ "minamimaki.nagano.jp": 1,
+ "minamiminowa.nagano.jp": 1,
+ "minamioguni.kumamoto.jp": 1,
+ "minamisanriku.miyagi.jp": 1,
+ "minamitane.kagoshima.jp": 1,
+ "minamiuonuma.niigata.jp": 1,
+ "minamiyamashiro.kyoto.jp": 1,
+ "minano.saitama.jp": 1,
+ "minato.osaka.jp": 1,
+ "minato.tokyo.jp": 1,
+ "mincom.tn": 1,
+ "mine.nu": 1,
+ "miners.museum": 1,
+ "mining.museum": 1,
+ "miniserver.com": 1,
+ "minnesota.museum": 1,
+ "mino.gifu.jp": 1,
+ "minobu.yamanashi.jp": 1,
+ "minoh.osaka.jp": 1,
+ "minokamo.gifu.jp": 1,
+ "minowa.nagano.jp": 1,
+ "mintere.site": 1,
+ "mircloud.host": 1,
+ "misaki.okayama.jp": 1,
+ "misaki.osaka.jp": 1,
+ "misasa.tottori.jp": 1,
+ "misato.akita.jp": 1,
+ "misato.miyagi.jp": 1,
+ "misato.saitama.jp": 1,
+ "misato.shimane.jp": 1,
+ "misato.wakayama.jp": 1,
+ "misawa.aomori.jp": 1,
+ "misconfused.org": 1,
+ "mishima.fukushima.jp": 1,
+ "mishima.shizuoka.jp": 1,
+ "missile.museum": 1,
+ "missoula.museum": 1,
+ "misugi.mie.jp": 1,
+ "mitaka.tokyo.jp": 1,
+ "mitake.gifu.jp": 1,
+ "mitane.akita.jp": 1,
+ "mito.ibaraki.jp": 1,
+ "mitou.yamaguchi.jp": 1,
+ "mitoyo.kagawa.jp": 1,
+ "mitsue.nara.jp": 1,
+ "mitsuke.niigata.jp": 1,
+ "miura.kanagawa.jp": 1,
+ "miyada.nagano.jp": 1,
+ "miyagi.jp": 1,
+ "miyake.nara.jp": 1,
+ "miyako.fukuoka.jp": 1,
+ "miyako.iwate.jp": 1,
+ "miyakonojo.miyazaki.jp": 1,
+ "miyama.fukuoka.jp": 1,
+ "miyama.mie.jp": 1,
+ "miyashiro.saitama.jp": 1,
+ "miyawaka.fukuoka.jp": 1,
+ "miyazaki.jp": 1,
+ "miyazaki.miyazaki.jp": 1,
+ "miyazu.kyoto.jp": 1,
+ "miyoshi.aichi.jp": 1,
+ "miyoshi.hiroshima.jp": 1,
+ "miyoshi.saitama.jp": 1,
+ "miyoshi.tokushima.jp": 1,
+ "miyota.nagano.jp": 1,
+ "mizuho.tokyo.jp": 1,
+ "mizumaki.fukuoka.jp": 1,
+ "mizunami.gifu.jp": 1,
+ "mizusawa.iwate.jp": 1,
+ "mjondalen.no": 1,
+ "mj\u00f8ndalen.no": 1,
+ "mk.eu.org": 1,
+ "mk.ua": 1,
+ "mlbfan.org": 1,
+ "mm": 2,
+ "mmafan.biz": 1,
+ "mn.it": 1,
+ "mn.us": 1,
+ "mo-i-rana.no": 1,
+ "mo-siemens.io": 1,
+ "mo.cn": 1,
+ "mo.it": 1,
+ "mo.us": 1,
+ "moareke.no": 1,
+ "mobara.chiba.jp": 1,
+ "mobi.gp": 1,
+ "mobi.ke": 1,
+ "mobi.na": 1,
+ "mobi.ng": 1,
+ "mobi.tt": 1,
+ "mobi.tz": 1,
+ "mochizuki.nagano.jp": 1,
+ "mod.gi": 1,
+ "modalen.no": 1,
+ "modelling.aero": 1,
+ "modena.it": 1,
+ "modern.museum": 1,
+ "modum.no": 1,
+ "moka.tochigi.jp": 1,
+ "mol.it": 1,
+ "molde.no": 1,
+ "molise.it": 1,
+ "moma.museum": 1,
+ "mombetsu.hokkaido.jp": 1,
+ "money.museum": 1,
+ "monmouth.museum": 1,
+ "monticello.museum": 1,
+ "montreal.museum": 1,
+ "monza-brianza.it": 1,
+ "monza-e-della-brianza.it": 1,
+ "monza.it": 1,
+ "monzabrianza.it": 1,
+ "monzaebrianza.it": 1,
+ "monzaedellabrianza.it": 1,
+ "moonscale.io": 2,
+ "moonscale.net": 1,
+ "mordovia.ru": 1,
+ "mordovia.su": 1,
+ "morena.br": 1,
+ "moriguchi.osaka.jp": 1,
+ "morimachi.shizuoka.jp": 1,
+ "morioka.iwate.jp": 1,
+ "moriya.ibaraki.jp": 1,
+ "moriyama.shiga.jp": 1,
+ "moriyoshi.akita.jp": 1,
+ "morotsuka.miyazaki.jp": 1,
+ "moroyama.saitama.jp": 1,
+ "moscow.museum": 1,
+ "moseushi.hokkaido.jp": 1,
+ "mosjoen.no": 1,
+ "mosj\u00f8en.no": 1,
+ "moskenes.no": 1,
+ "moss.no": 1,
+ "mosvik.no": 1,
+ "motegi.tochigi.jp": 1,
+ "motobu.okinawa.jp": 1,
+ "motorcycle.museum": 1,
+ "motosu.gifu.jp": 1,
+ "motoyama.kochi.jp": 1,
+ "movimiento.bo": 1,
+ "mozilla-iot.org": 1,
+ "mo\u00e5reke.no": 1,
+ "mp.br": 1,
+ "mr.no": 1,
+ "mragowo.pl": 1,
+ "ms.gov.br": 1,
+ "ms.it": 1,
+ "ms.kr": 1,
+ "ms.leg.br": 1,
+ "ms.us": 1,
+ "msk.ru": 1,
+ "msk.su": 1,
+ "mt.eu.org": 1,
+ "mt.gov.br": 1,
+ "mt.it": 1,
+ "mt.leg.br": 1,
+ "mt.us": 1,
+ "muenchen.museum": 1,
+ "muenster.museum": 1,
+ "mugi.tokushima.jp": 1,
+ "muika.niigata.jp": 1,
+ "mukawa.hokkaido.jp": 1,
+ "muko.kyoto.jp": 1,
+ "mulhouse.museum": 1,
+ "munakata.fukuoka.jp": 1,
+ "muncie.museum": 1,
+ "muni.il": 1,
+ "muosat.no": 1,
+ "muos\u00e1t.no": 1,
+ "mup.gov.pl": 1,
+ "murakami.niigata.jp": 1,
+ "murata.miyagi.jp": 1,
+ "murayama.yamagata.jp": 1,
+ "murmansk.su": 1,
+ "muroran.hokkaido.jp": 1,
+ "muroto.kochi.jp": 1,
+ "mus.br": 1,
+ "mus.mi.us": 1,
+ "musashimurayama.tokyo.jp": 1,
+ "musashino.tokyo.jp": 1,
+ "museet.museum": 1,
+ "museum.mv": 1,
+ "museum.mw": 1,
+ "museum.no": 1,
+ "museum.om": 1,
+ "museum.tt": 1,
+ "museumcenter.museum": 1,
+ "museumvereniging.museum": 1,
+ "music.museum": 1,
+ "musica.ar": 1,
+ "musica.bo": 1,
+ "mutsu.aomori.jp": 1,
+ "mutsuzawa.chiba.jp": 1,
+ "mw.gov.pl": 1,
+ "mx.na": 1,
+ "my-firewall.org": 1,
+ "my-gateway.de": 1,
+ "my-router.de": 1,
+ "my-vigor.de": 1,
+ "my-wan.de": 1,
+ "my.eu.org": 1,
+ "my.id": 1,
+ "myactivedirectory.com": 1,
+ "myasustor.com": 1,
+ "mycd.eu": 1,
+ "mydatto.com": 1,
+ "mydatto.net": 1,
+ "myddns.rocks": 1,
+ "mydissent.net": 1,
+ "mydobiss.com": 1,
+ "mydrobo.com": 1,
+ "myds.me": 1,
+ "myeffect.net": 1,
+ "myfast.host": 1,
+ "myfast.space": 1,
+ "myfirewall.org": 1,
+ "myforum.community": 1,
+ "myfritz.net": 1,
+ "myftp.biz": 1,
+ "myftp.org": 1,
+ "myhome-server.de": 1,
+ "myiphost.com": 1,
+ "myjino.ru": 1,
+ "mykolaiv.ua": 1,
+ "mymailer.com.tw": 1,
+ "mymediapc.net": 1,
+ "myoko.niigata.jp": 1,
+ "mypep.link": 1,
+ "mypets.ws": 1,
+ "myphotos.cc": 1,
+ "mypi.co": 1,
+ "mypsx.net": 1,
+ "myqnapcloud.com": 1,
+ "myravendb.com": 1,
+ "mysecuritycamera.com": 1,
+ "mysecuritycamera.net": 1,
+ "mysecuritycamera.org": 1,
+ "myshopblocks.com": 1,
+ "mytis.ru": 1,
+ "mytuleap.com": 1,
+ "myvnc.com": 1,
+ "mywire.org": 1,
+ "m\u00e1latvuopmi.no": 1,
+ "m\u00e1tta-v\u00e1rjjat.no": 1,
+ "m\u00e5lselv.no": 1,
+ "m\u00e5s\u00f8y.no": 1,
+ "m\u0101ori.nz": 1,
+ "n.bg": 1,
+ "n.se": 1,
+ "n4t.co": 1,
+ "na.it": 1,
+ "na4u.ru": 1,
+ "naamesjevuemie.no": 1,
+ "nabari.mie.jp": 1,
+ "nachikatsuura.wakayama.jp": 1,
+ "nagahama.shiga.jp": 1,
+ "nagai.yamagata.jp": 1,
+ "nagano.jp": 1,
+ "nagano.nagano.jp": 1,
+ "naganohara.gunma.jp": 1,
+ "nagaoka.niigata.jp": 1,
+ "nagaokakyo.kyoto.jp": 1,
+ "nagara.chiba.jp": 1,
+ "nagareyama.chiba.jp": 1,
+ "nagasaki.jp": 1,
+ "nagasaki.nagasaki.jp": 1,
+ "nagasu.kumamoto.jp": 1,
+ "nagato.yamaguchi.jp": 1,
+ "nagatoro.saitama.jp": 1,
+ "nagawa.nagano.jp": 1,
+ "nagi.okayama.jp": 1,
+ "nagiso.nagano.jp": 1,
+ "nago.okinawa.jp": 1,
+ "nagoya.jp": 2,
+ "naha.okinawa.jp": 1,
+ "nahari.kochi.jp": 1,
+ "naie.hokkaido.jp": 1,
+ "naka.hiroshima.jp": 1,
+ "naka.ibaraki.jp": 1,
+ "nakadomari.aomori.jp": 1,
+ "nakagawa.fukuoka.jp": 1,
+ "nakagawa.hokkaido.jp": 1,
+ "nakagawa.nagano.jp": 1,
+ "nakagawa.tokushima.jp": 1,
+ "nakagusuku.okinawa.jp": 1,
+ "nakagyo.kyoto.jp": 1,
+ "nakai.kanagawa.jp": 1,
+ "nakama.fukuoka.jp": 1,
+ "nakamichi.yamanashi.jp": 1,
+ "nakamura.kochi.jp": 1,
+ "nakaniikawa.toyama.jp": 1,
+ "nakano.nagano.jp": 1,
+ "nakano.tokyo.jp": 1,
+ "nakanojo.gunma.jp": 1,
+ "nakanoto.ishikawa.jp": 1,
+ "nakasatsunai.hokkaido.jp": 1,
+ "nakatane.kagoshima.jp": 1,
+ "nakatombetsu.hokkaido.jp": 1,
+ "nakatsugawa.gifu.jp": 1,
+ "nakayama.yamagata.jp": 1,
+ "nakijin.okinawa.jp": 1,
+ "naklo.pl": 1,
+ "nalchik.ru": 1,
+ "nalchik.su": 1,
+ "namdalseid.no": 1,
+ "name.az": 1,
+ "name.cy": 1,
+ "name.eg": 1,
+ "name.et": 1,
+ "name.fj": 1,
+ "name.hr": 1,
+ "name.jo": 1,
+ "name.mk": 1,
+ "name.mv": 1,
+ "name.my": 1,
+ "name.na": 1,
+ "name.ng": 1,
+ "name.pr": 1,
+ "name.qa": 1,
+ "name.tj": 1,
+ "name.tr": 1,
+ "name.tt": 1,
+ "name.vn": 1,
+ "namegata.ibaraki.jp": 1,
+ "namegawa.saitama.jp": 1,
+ "namerikawa.toyama.jp": 1,
+ "namie.fukushima.jp": 1,
+ "namikata.ehime.jp": 1,
+ "namsos.no": 1,
+ "namsskogan.no": 1,
+ "nanae.hokkaido.jp": 1,
+ "nanao.ishikawa.jp": 1,
+ "nanbu.tottori.jp": 1,
+ "nanbu.yamanashi.jp": 1,
+ "nango.fukushima.jp": 1,
+ "nanjo.okinawa.jp": 1,
+ "nankoku.kochi.jp": 1,
+ "nanmoku.gunma.jp": 1,
+ "nannestad.no": 1,
+ "nanporo.hokkaido.jp": 1,
+ "nantan.kyoto.jp": 1,
+ "nanto.toyama.jp": 1,
+ "nanyo.yamagata.jp": 1,
+ "naoshima.kagawa.jp": 1,
+ "naples.it": 1,
+ "napoli.it": 1,
+ "nara.jp": 1,
+ "nara.nara.jp": 1,
+ "narashino.chiba.jp": 1,
+ "narita.chiba.jp": 1,
+ "naroy.no": 1,
+ "narusawa.yamanashi.jp": 1,
+ "naruto.tokushima.jp": 1,
+ "narviika.no": 1,
+ "narvik.no": 1,
+ "nasu.tochigi.jp": 1,
+ "nasushiobara.tochigi.jp": 1,
+ "nat.tn": 1,
+ "natal.br": 1,
+ "national.museum": 1,
+ "nationalfirearms.museum": 1,
+ "nationalheritage.museum": 1,
+ "nativeamerican.museum": 1,
+ "natori.miyagi.jp": 1,
+ "natural.bo": 1,
+ "naturalhistory.museum": 1,
+ "naturalhistorymuseum.museum": 1,
+ "naturalsciences.museum": 1,
+ "naturbruksgymn.se": 1,
+ "nature.museum": 1,
+ "naturhistorisches.museum": 1,
+ "natuurwetenschappen.museum": 1,
+ "naumburg.museum": 1,
+ "naustdal.no": 1,
+ "naval.museum": 1,
+ "navigation.aero": 1,
+ "navoi.su": 1,
+ "navuotna.no": 1,
+ "nayoro.hokkaido.jp": 1,
+ "nb.ca": 1,
+ "nc.tr": 1,
+ "nc.us": 1,
+ "nctu.me": 1,
+ "nd.us": 1,
+ "ne.jp": 1,
+ "ne.ke": 1,
+ "ne.kr": 1,
+ "ne.pw": 1,
+ "ne.tz": 1,
+ "ne.ug": 1,
+ "ne.us": 1,
+ "neat-url.com": 1,
+ "nebraska.museum": 1,
+ "nedre-eiker.no": 1,
+ "neko.am": 1,
+ "nemuro.hokkaido.jp": 1,
+ "nerdpol.ovh": 1,
+ "nerima.tokyo.jp": 1,
+ "nes.akershus.no": 1,
+ "nes.buskerud.no": 1,
+ "nesna.no": 1,
+ "nesodden.no": 1,
+ "nesoddtangen.no": 1,
+ "nesseby.no": 1,
+ "nesset.no": 1,
+ "net-freaks.com": 1,
+ "net.ac": 1,
+ "net.ae": 1,
+ "net.af": 1,
+ "net.ag": 1,
+ "net.ai": 1,
+ "net.al": 1,
+ "net.am": 1,
+ "net.ar": 1,
+ "net.au": 1,
+ "net.az": 1,
+ "net.ba": 1,
+ "net.bb": 1,
+ "net.bh": 1,
+ "net.bm": 1,
+ "net.bn": 1,
+ "net.bo": 1,
+ "net.br": 1,
+ "net.bs": 1,
+ "net.bt": 1,
+ "net.bz": 1,
+ "net.ci": 1,
+ "net.cm": 1,
+ "net.cn": 1,
+ "net.co": 1,
+ "net.cu": 1,
+ "net.cw": 1,
+ "net.cy": 1,
+ "net.dm": 1,
+ "net.do": 1,
+ "net.dz": 1,
+ "net.ec": 1,
+ "net.eg": 1,
+ "net.et": 1,
+ "net.eu.org": 1,
+ "net.fj": 1,
+ "net.fm": 1,
+ "net.ge": 1,
+ "net.gg": 1,
+ "net.gl": 1,
+ "net.gn": 1,
+ "net.gp": 1,
+ "net.gr": 1,
+ "net.gt": 1,
+ "net.gu": 1,
+ "net.gy": 1,
+ "net.hk": 1,
+ "net.hn": 1,
+ "net.ht": 1,
+ "net.id": 1,
+ "net.il": 1,
+ "net.im": 1,
+ "net.in": 1,
+ "net.iq": 1,
+ "net.ir": 1,
+ "net.is": 1,
+ "net.je": 1,
+ "net.jo": 1,
+ "net.kg": 1,
+ "net.ki": 1,
+ "net.kn": 1,
+ "net.kw": 1,
+ "net.ky": 1,
+ "net.kz": 1,
+ "net.la": 1,
+ "net.lb": 1,
+ "net.lc": 1,
+ "net.lk": 1,
+ "net.lr": 1,
+ "net.ls": 1,
+ "net.lv": 1,
+ "net.ly": 1,
+ "net.ma": 1,
+ "net.me": 1,
+ "net.mk": 1,
+ "net.ml": 1,
+ "net.mo": 1,
+ "net.ms": 1,
+ "net.mt": 1,
+ "net.mu": 1,
+ "net.mv": 1,
+ "net.mw": 1,
+ "net.mx": 1,
+ "net.my": 1,
+ "net.mz": 1,
+ "net.nf": 1,
+ "net.ng": 1,
+ "net.ni": 1,
+ "net.nr": 1,
+ "net.nz": 1,
+ "net.om": 1,
+ "net.pa": 1,
+ "net.pe": 1,
+ "net.ph": 1,
+ "net.pk": 1,
+ "net.pl": 1,
+ "net.pn": 1,
+ "net.pr": 1,
+ "net.ps": 1,
+ "net.pt": 1,
+ "net.py": 1,
+ "net.qa": 1,
+ "net.ru": 1,
+ "net.rw": 1,
+ "net.sa": 1,
+ "net.sb": 1,
+ "net.sc": 1,
+ "net.sd": 1,
+ "net.sg": 1,
+ "net.sh": 1,
+ "net.sl": 1,
+ "net.so": 1,
+ "net.ss": 1,
+ "net.st": 1,
+ "net.sy": 1,
+ "net.th": 1,
+ "net.tj": 1,
+ "net.tm": 1,
+ "net.tn": 1,
+ "net.to": 1,
+ "net.tr": 1,
+ "net.tt": 1,
+ "net.tw": 1,
+ "net.ua": 1,
+ "net.uk": 1,
+ "net.uy": 1,
+ "net.uz": 1,
+ "net.vc": 1,
+ "net.ve": 1,
+ "net.vi": 1,
+ "net.vn": 1,
+ "net.vu": 1,
+ "net.ws": 1,
+ "net.za": 1,
+ "net.zm": 1,
+ "netlify.app": 1,
+ "neues.museum": 1,
+ "newhampshire.museum": 1,
+ "newjersey.museum": 1,
+ "newmexico.museum": 1,
+ "newport.museum": 1,
+ "news.hu": 1,
+ "newspaper.museum": 1,
+ "newyork.museum": 1,
+ "neyagawa.osaka.jp": 1,
+ "nf.ca": 1,
+ "nflfan.org": 1,
+ "nfshost.com": 1,
+ "ng.city": 1,
+ "ng.eu.org": 1,
+ "ng.ink": 1,
+ "ng.school": 1,
+ "ngo.lk": 1,
+ "ngo.ng": 1,
+ "ngo.ph": 1,
+ "ngo.za": 1,
+ "ngrok.io": 1,
+ "nh-serv.co.uk": 1,
+ "nh.us": 1,
+ "nhlfan.net": 1,
+ "nhs.uk": 1,
+ "nic.in": 1,
+ "nic.tj": 1,
+ "nic.za": 1,
+ "nichinan.miyazaki.jp": 1,
+ "nichinan.tottori.jp": 1,
+ "nid.io": 1,
+ "niepce.museum": 1,
+ "nieruchomosci.pl": 1,
+ "niigata.jp": 1,
+ "niigata.niigata.jp": 1,
+ "niihama.ehime.jp": 1,
+ "niikappu.hokkaido.jp": 1,
+ "niimi.okayama.jp": 1,
+ "niiza.saitama.jp": 1,
+ "nikaho.akita.jp": 1,
+ "niki.hokkaido.jp": 1,
+ "nikko.tochigi.jp": 1,
+ "nikolaev.ua": 1,
+ "ninohe.iwate.jp": 1,
+ "ninomiya.kanagawa.jp": 1,
+ "nirasaki.yamanashi.jp": 1,
+ "nis.za": 1,
+ "nishi.fukuoka.jp": 1,
+ "nishi.osaka.jp": 1,
+ "nishiaizu.fukushima.jp": 1,
+ "nishiarita.saga.jp": 1,
+ "nishiawakura.okayama.jp": 1,
+ "nishiazai.shiga.jp": 1,
+ "nishigo.fukushima.jp": 1,
+ "nishihara.kumamoto.jp": 1,
+ "nishihara.okinawa.jp": 1,
+ "nishiizu.shizuoka.jp": 1,
+ "nishikata.tochigi.jp": 1,
+ "nishikatsura.yamanashi.jp": 1,
+ "nishikawa.yamagata.jp": 1,
+ "nishimera.miyazaki.jp": 1,
+ "nishinomiya.hyogo.jp": 1,
+ "nishinoomote.kagoshima.jp": 1,
+ "nishinoshima.shimane.jp": 1,
+ "nishio.aichi.jp": 1,
+ "nishiokoppe.hokkaido.jp": 1,
+ "nishitosa.kochi.jp": 1,
+ "nishiwaki.hyogo.jp": 1,
+ "nissedal.no": 1,
+ "nisshin.aichi.jp": 1,
+ "niteroi.br": 1,
+ "nittedal.no": 1,
+ "niyodogawa.kochi.jp": 1,
+ "nj.us": 1,
+ "nl.ca": 1,
+ "nl.ci": 1,
+ "nl.eu.org": 1,
+ "nl.no": 1,
+ "nm.cn": 1,
+ "nm.us": 1,
+ "no-ip.biz": 1,
+ "no-ip.ca": 1,
+ "no-ip.co.uk": 1,
+ "no-ip.info": 1,
+ "no-ip.net": 1,
+ "no-ip.org": 1,
+ "no.com": 1,
+ "no.eu.org": 1,
+ "no.it": 1,
+ "nobeoka.miyazaki.jp": 1,
+ "noboribetsu.hokkaido.jp": 1,
+ "noda.chiba.jp": 1,
+ "noda.iwate.jp": 1,
+ "nodebalancer.linode.com": 2,
+ "nodum.co": 1,
+ "nodum.io": 1,
+ "nogata.fukuoka.jp": 1,
+ "nogi.tochigi.jp": 1,
+ "noheji.aomori.jp": 1,
+ "noho.st": 1,
+ "nohost.me": 1,
+ "noip.me": 1,
+ "noip.us": 1,
+ "nom.ad": 1,
+ "nom.ae": 1,
+ "nom.af": 1,
+ "nom.ag": 1,
+ "nom.ai": 1,
+ "nom.al": 1,
+ "nom.br": 2,
+ "nom.bz": 1,
+ "nom.cl": 1,
+ "nom.co": 1,
+ "nom.es": 1,
+ "nom.fr": 1,
+ "nom.gd": 1,
+ "nom.ge": 1,
+ "nom.gl": 1,
+ "nom.gt": 1,
+ "nom.hn": 1,
+ "nom.im": 1,
+ "nom.ke": 1,
+ "nom.km": 1,
+ "nom.li": 1,
+ "nom.lv": 1,
+ "nom.mg": 1,
+ "nom.mk": 1,
+ "nom.nc": 1,
+ "nom.ni": 1,
+ "nom.nu": 1,
+ "nom.pa": 1,
+ "nom.pe": 1,
+ "nom.pl": 1,
+ "nom.pw": 1,
+ "nom.qa": 1,
+ "nom.re": 1,
+ "nom.ro": 1,
+ "nom.rs": 1,
+ "nom.si": 1,
+ "nom.st": 1,
+ "nom.tj": 1,
+ "nom.tm": 1,
+ "nom.ug": 1,
+ "nom.uy": 1,
+ "nom.vc": 1,
+ "nom.vg": 1,
+ "nom.za": 1,
+ "nombre.bo": 1,
+ "nome.pt": 1,
+ "nomi.ishikawa.jp": 1,
+ "nonoichi.ishikawa.jp": 1,
+ "nord-aurdal.no": 1,
+ "nord-fron.no": 1,
+ "nord-odal.no": 1,
+ "norddal.no": 1,
+ "nordkapp.no": 1,
+ "nordre-land.no": 1,
+ "nordreisa.no": 1,
+ "nore-og-uvdal.no": 1,
+ "norfolk.museum": 1,
+ "north-kazakhstan.su": 1,
+ "north.museum": 1,
+ "nose.osaka.jp": 1,
+ "nosegawa.nara.jp": 1,
+ "noshiro.akita.jp": 1,
+ "not.br": 1,
+ "notaires.fr": 1,
+ "notaires.km": 1,
+ "noticias.bo": 1,
+ "noto.ishikawa.jp": 1,
+ "notodden.no": 1,
+ "notogawa.shiga.jp": 1,
+ "notteroy.no": 1,
+ "nov.ru": 1,
+ "nov.su": 1,
+ "novara.it": 1,
+ "now-dns.net": 1,
+ "now-dns.org": 1,
+ "now-dns.top": 1,
+ "now.sh": 1,
+ "nowaruda.pl": 1,
+ "nozawaonsen.nagano.jp": 1,
+ "np": 2,
+ "nrw.museum": 1,
+ "ns.ca": 1,
+ "nsn.us": 1,
+ "nsupdate.info": 1,
+ "nsw.au": 1,
+ "nsw.edu.au": 1,
+ "nt.au": 1,
+ "nt.ca": 1,
+ "nt.edu.au": 1,
+ "nt.no": 1,
+ "nt.ro": 1,
+ "ntdll.top": 1,
+ "ntr.br": 1,
+ "nu.ca": 1,
+ "nu.it": 1,
+ "numata.gunma.jp": 1,
+ "numata.hokkaido.jp": 1,
+ "numazu.shizuoka.jp": 1,
+ "nuoro.it": 1,
+ "nv.us": 1,
+ "nx.cn": 1,
+ "ny.us": 1,
+ "nyaa.am": 1,
+ "nyan.to": 1,
+ "nyc.mn": 1,
+ "nyc.museum": 1,
+ "nym.by": 1,
+ "nym.bz": 1,
+ "nym.ec": 1,
+ "nym.gr": 1,
+ "nym.gy": 1,
+ "nym.hk": 1,
+ "nym.ie": 1,
+ "nym.kz": 1,
+ "nym.la": 1,
+ "nym.lc": 1,
+ "nym.li": 1,
+ "nym.lt": 1,
+ "nym.lu": 1,
+ "nym.me": 1,
+ "nym.mn": 1,
+ "nym.mx": 1,
+ "nym.nz": 1,
+ "nym.pe": 1,
+ "nym.pt": 1,
+ "nym.ro": 1,
+ "nym.sk": 1,
+ "nym.su": 1,
+ "nym.sx": 1,
+ "nym.tw": 1,
+ "nyny.museum": 1,
+ "nysa.pl": 1,
+ "nyuzen.toyama.jp": 1,
+ "nz.basketball": 1,
+ "nz.eu.org": 1,
+ "n\u00e1vuotna.no": 1,
+ "n\u00e5\u00e5mesjevuemie.no": 1,
+ "n\u00e6r\u00f8y.no": 1,
+ "n\u00f8tter\u00f8y.no": 1,
+ "o.bg": 1,
+ "o.se": 1,
+ "oamishirasato.chiba.jp": 1,
+ "oarai.ibaraki.jp": 1,
+ "obama.fukui.jp": 1,
+ "obama.nagasaki.jp": 1,
+ "obanazawa.yamagata.jp": 1,
+ "obihiro.hokkaido.jp": 1,
+ "obira.hokkaido.jp": 1,
+ "obninsk.su": 1,
+ "obu.aichi.jp": 1,
+ "obuse.nagano.jp": 1,
+ "oceanographic.museum": 1,
+ "oceanographique.museum": 1,
+ "ocelot.mythic-beasts.com": 1,
+ "ochi.kochi.jp": 1,
+ "oci.customer-oci.com": 2,
+ "ocp.customer-oci.com": 2,
+ "ocs.customer-oci.com": 2,
+ "od.ua": 1,
+ "odate.akita.jp": 1,
+ "odawara.kanagawa.jp": 1,
+ "odda.no": 1,
+ "odesa.ua": 1,
+ "odessa.ua": 1,
+ "odo.br": 1,
+ "oe.yamagata.jp": 1,
+ "of.by": 1,
+ "of.fashion": 1,
+ "of.football": 1,
+ "of.london": 1,
+ "of.no": 1,
+ "of.work": 1,
+ "off.ai": 1,
+ "office-on-the.net": 1,
+ "official.academy": 1,
+ "ofunato.iwate.jp": 1,
+ "og.ao": 1,
+ "og.it": 1,
+ "oga.akita.jp": 1,
+ "ogaki.gifu.jp": 1,
+ "ogano.saitama.jp": 1,
+ "ogasawara.tokyo.jp": 1,
+ "ogata.akita.jp": 1,
+ "ogawa.ibaraki.jp": 1,
+ "ogawa.nagano.jp": 1,
+ "ogawa.saitama.jp": 1,
+ "ogawara.miyagi.jp": 1,
+ "ogi.saga.jp": 1,
+ "ogimi.okinawa.jp": 1,
+ "ogliastra.it": 1,
+ "ogori.fukuoka.jp": 1,
+ "ogose.saitama.jp": 1,
+ "oguchi.aichi.jp": 1,
+ "oguni.kumamoto.jp": 1,
+ "oguni.yamagata.jp": 1,
+ "oh.us": 1,
+ "oharu.aichi.jp": 1,
+ "ohda.shimane.jp": 1,
+ "ohi.fukui.jp": 1,
+ "ohira.miyagi.jp": 1,
+ "ohira.tochigi.jp": 1,
+ "ohkura.yamagata.jp": 1,
+ "ohtawara.tochigi.jp": 1,
+ "oi.kanagawa.jp": 1,
+ "oirase.aomori.jp": 1,
+ "oirm.gov.pl": 1,
+ "oishida.yamagata.jp": 1,
+ "oiso.kanagawa.jp": 1,
+ "oita.jp": 1,
+ "oita.oita.jp": 1,
+ "oizumi.gunma.jp": 1,
+ "oji.nara.jp": 1,
+ "ojiya.niigata.jp": 1,
+ "ok.us": 1,
+ "okagaki.fukuoka.jp": 1,
+ "okawa.fukuoka.jp": 1,
+ "okawa.kochi.jp": 1,
+ "okaya.nagano.jp": 1,
+ "okayama.jp": 1,
+ "okayama.okayama.jp": 1,
+ "okazaki.aichi.jp": 1,
+ "okegawa.saitama.jp": 1,
+ "oketo.hokkaido.jp": 1,
+ "oki.fukuoka.jp": 1,
+ "okinawa.jp": 1,
+ "okinawa.okinawa.jp": 1,
+ "okinoshima.shimane.jp": 1,
+ "okoppe.hokkaido.jp": 1,
+ "oksnes.no": 1,
+ "okuizumo.shimane.jp": 1,
+ "okuma.fukushima.jp": 1,
+ "okutama.tokyo.jp": 1,
+ "ol.no": 1,
+ "olawa.pl": 1,
+ "olbia-tempio.it": 1,
+ "olbiatempio.it": 1,
+ "olecko.pl": 1,
+ "olkusz.pl": 1,
+ "olsztyn.pl": 1,
+ "omachi.nagano.jp": 1,
+ "omachi.saga.jp": 1,
+ "omaezaki.shizuoka.jp": 1,
+ "omaha.museum": 1,
+ "omasvuotna.no": 1,
+ "ome.tokyo.jp": 1,
+ "omg.lol": 1,
+ "omi.nagano.jp": 1,
+ "omi.niigata.jp": 1,
+ "omigawa.chiba.jp": 1,
+ "omihachiman.shiga.jp": 1,
+ "omitama.ibaraki.jp": 1,
+ "omiya.saitama.jp": 1,
+ "omniwe.site": 1,
+ "omotego.fukushima.jp": 1,
+ "omura.nagasaki.jp": 1,
+ "omuta.fukuoka.jp": 1,
+ "on-aptible.com": 1,
+ "on-k3s.io": 2,
+ "on-rancher.cloud": 2,
+ "on-rio.io": 2,
+ "on-the-web.tv": 1,
+ "on-web.fr": 1,
+ "on.ca": 1,
+ "on.fashion": 1,
+ "onagawa.miyagi.jp": 1,
+ "onfabrica.com": 1,
+ "ong.br": 1,
+ "onga.fukuoka.jp": 1,
+ "onjuku.chiba.jp": 1,
+ "online.museum": 1,
+ "online.th": 1,
+ "onna.okinawa.jp": 1,
+ "ono.fukui.jp": 1,
+ "ono.fukushima.jp": 1,
+ "ono.hyogo.jp": 1,
+ "onojo.fukuoka.jp": 1,
+ "onomichi.hiroshima.jp": 1,
+ "onred.one": 1,
+ "onrender.com": 1,
+ "ontario.museum": 1,
+ "onthewifi.com": 1,
+ "onza.mythic-beasts.com": 1,
+ "ooguy.com": 1,
+ "ookuwa.nagano.jp": 1,
+ "ooshika.nagano.jp": 1,
+ "openair.museum": 1,
+ "opencraft.hosting": 1,
+ "opensocial.site": 1,
+ "operaunite.com": 1,
+ "opoczno.pl": 1,
+ "opole.pl": 1,
+ "oppdal.no": 1,
+ "oppegard.no": 1,
+ "oppeg\u00e5rd.no": 1,
+ "or.at": 1,
+ "or.bi": 1,
+ "or.ci": 1,
+ "or.cr": 1,
+ "or.id": 1,
+ "or.it": 1,
+ "or.jp": 1,
+ "or.ke": 1,
+ "or.kr": 1,
+ "or.mu": 1,
+ "or.na": 1,
+ "or.pw": 1,
+ "or.th": 1,
+ "or.tz": 1,
+ "or.ug": 1,
+ "or.us": 1,
+ "ora.gunma.jp": 1,
+ "oregon.museum": 1,
+ "oregontrail.museum": 1,
+ "org.ac": 1,
+ "org.ae": 1,
+ "org.af": 1,
+ "org.ag": 1,
+ "org.ai": 1,
+ "org.al": 1,
+ "org.am": 1,
+ "org.ar": 1,
+ "org.au": 1,
+ "org.az": 1,
+ "org.ba": 1,
+ "org.bb": 1,
+ "org.bh": 1,
+ "org.bi": 1,
+ "org.bm": 1,
+ "org.bn": 1,
+ "org.bo": 1,
+ "org.br": 1,
+ "org.bs": 1,
+ "org.bt": 1,
+ "org.bw": 1,
+ "org.bz": 1,
+ "org.ci": 1,
+ "org.cn": 1,
+ "org.co": 1,
+ "org.cu": 1,
+ "org.cw": 1,
+ "org.cy": 1,
+ "org.dm": 1,
+ "org.do": 1,
+ "org.dz": 1,
+ "org.ec": 1,
+ "org.ee": 1,
+ "org.eg": 1,
+ "org.es": 1,
+ "org.et": 1,
+ "org.fj": 1,
+ "org.fm": 1,
+ "org.ge": 1,
+ "org.gg": 1,
+ "org.gh": 1,
+ "org.gi": 1,
+ "org.gl": 1,
+ "org.gn": 1,
+ "org.gp": 1,
+ "org.gr": 1,
+ "org.gt": 1,
+ "org.gu": 1,
+ "org.gy": 1,
+ "org.hk": 1,
+ "org.hn": 1,
+ "org.ht": 1,
+ "org.hu": 1,
+ "org.il": 1,
+ "org.im": 1,
+ "org.in": 1,
+ "org.iq": 1,
+ "org.ir": 1,
+ "org.is": 1,
+ "org.je": 1,
+ "org.jo": 1,
+ "org.kg": 1,
+ "org.ki": 1,
+ "org.km": 1,
+ "org.kn": 1,
+ "org.kp": 1,
+ "org.kw": 1,
+ "org.ky": 1,
+ "org.kz": 1,
+ "org.la": 1,
+ "org.lb": 1,
+ "org.lc": 1,
+ "org.lk": 1,
+ "org.lr": 1,
+ "org.ls": 1,
+ "org.lv": 1,
+ "org.ly": 1,
+ "org.ma": 1,
+ "org.me": 1,
+ "org.mg": 1,
+ "org.mk": 1,
+ "org.ml": 1,
+ "org.mn": 1,
+ "org.mo": 1,
+ "org.ms": 1,
+ "org.mt": 1,
+ "org.mu": 1,
+ "org.mv": 1,
+ "org.mw": 1,
+ "org.mx": 1,
+ "org.my": 1,
+ "org.mz": 1,
+ "org.na": 1,
+ "org.ng": 1,
+ "org.ni": 1,
+ "org.nr": 1,
+ "org.nz": 1,
+ "org.om": 1,
+ "org.pa": 1,
+ "org.pe": 1,
+ "org.pf": 1,
+ "org.ph": 1,
+ "org.pk": 1,
+ "org.pl": 1,
+ "org.pn": 1,
+ "org.pr": 1,
+ "org.ps": 1,
+ "org.pt": 1,
+ "org.py": 1,
+ "org.qa": 1,
+ "org.ro": 1,
+ "org.rs": 1,
+ "org.ru": 1,
+ "org.rw": 1,
+ "org.sa": 1,
+ "org.sb": 1,
+ "org.sc": 1,
+ "org.sd": 1,
+ "org.se": 1,
+ "org.sg": 1,
+ "org.sh": 1,
+ "org.sl": 1,
+ "org.sn": 1,
+ "org.so": 1,
+ "org.ss": 1,
+ "org.st": 1,
+ "org.sv": 1,
+ "org.sy": 1,
+ "org.sz": 1,
+ "org.tj": 1,
+ "org.tm": 1,
+ "org.tn": 1,
+ "org.to": 1,
+ "org.tr": 1,
+ "org.tt": 1,
+ "org.tw": 1,
+ "org.ua": 1,
+ "org.ug": 1,
+ "org.uk": 1,
+ "org.uy": 1,
+ "org.uz": 1,
+ "org.vc": 1,
+ "org.ve": 1,
+ "org.vi": 1,
+ "org.vn": 1,
+ "org.vu": 1,
+ "org.ws": 1,
+ "org.za": 1,
+ "org.zm": 1,
+ "org.zw": 1,
+ "oristano.it": 1,
+ "orkanger.no": 1,
+ "orkdal.no": 1,
+ "orland.no": 1,
+ "orskog.no": 1,
+ "orsta.no": 1,
+ "orx.biz": 1,
+ "os.hedmark.no": 1,
+ "os.hordaland.no": 1,
+ "osaka.jp": 1,
+ "osakasayama.osaka.jp": 1,
+ "osaki.miyagi.jp": 1,
+ "osakikamijima.hiroshima.jp": 1,
+ "osasco.br": 1,
+ "osen.no": 1,
+ "oseto.nagasaki.jp": 1,
+ "oshima.tokyo.jp": 1,
+ "oshima.yamaguchi.jp": 1,
+ "oshino.yamanashi.jp": 1,
+ "oshu.iwate.jp": 1,
+ "oslo.no": 1,
+ "osoyro.no": 1,
+ "osteroy.no": 1,
+ "oster\u00f8y.no": 1,
+ "ostre-toten.no": 1,
+ "ostroda.pl": 1,
+ "ostroleka.pl": 1,
+ "ostrowiec.pl": 1,
+ "ostrowwlkp.pl": 1,
+ "os\u00f8yro.no": 1,
+ "ot.it": 1,
+ "ota.gunma.jp": 1,
+ "ota.tokyo.jp": 1,
+ "otago.museum": 1,
+ "otake.hiroshima.jp": 1,
+ "otaki.chiba.jp": 1,
+ "otaki.nagano.jp": 1,
+ "otaki.saitama.jp": 1,
+ "otama.fukushima.jp": 1,
+ "otap.co": 2,
+ "otari.nagano.jp": 1,
+ "otaru.hokkaido.jp": 1,
+ "other.nf": 1,
+ "oto.fukuoka.jp": 1,
+ "otobe.hokkaido.jp": 1,
+ "otofuke.hokkaido.jp": 1,
+ "otoineppu.hokkaido.jp": 1,
+ "otoyo.kochi.jp": 1,
+ "otsu.shiga.jp": 1,
+ "otsuchi.iwate.jp": 1,
+ "otsuki.kochi.jp": 1,
+ "otsuki.yamanashi.jp": 1,
+ "ouchi.saga.jp": 1,
+ "ouda.nara.jp": 1,
+ "oum.gov.pl": 1,
+ "oumu.hokkaido.jp": 1,
+ "outsystemscloud.com": 1,
+ "overhalla.no": 1,
+ "ovre-eiker.no": 1,
+ "owani.aomori.jp": 1,
+ "owariasahi.aichi.jp": 1,
+ "own.pm": 1,
+ "ownip.net": 1,
+ "ownprovider.com": 1,
+ "owo.codes": 2,
+ "ox.rs": 1,
+ "oxford.museum": 1,
+ "oy.lc": 1,
+ "oya.to": 1,
+ "oyabe.toyama.jp": 1,
+ "oyama.tochigi.jp": 1,
+ "oyamazaki.kyoto.jp": 1,
+ "oyer.no": 1,
+ "oygarden.no": 1,
+ "oyodo.nara.jp": 1,
+ "oystre-slidre.no": 1,
+ "oz.au": 1,
+ "ozora.hokkaido.jp": 1,
+ "ozu.ehime.jp": 1,
+ "ozu.kumamoto.jp": 1,
+ "p.bg": 1,
+ "p.se": 1,
+ "pa.gov.br": 1,
+ "pa.gov.pl": 1,
+ "pa.it": 1,
+ "pa.leg.br": 1,
+ "pa.us": 1,
+ "paas.datacenter.fi": 1,
+ "paas.massivegrid.com": 1,
+ "pacific.museum": 1,
+ "paderborn.museum": 1,
+ "padova.it": 1,
+ "padua.it": 1,
+ "pagefrontapp.com": 1,
+ "pages.dev": 1,
+ "pages.wiardweb.com": 1,
+ "pagespeedmobilizer.com": 1,
+ "pagexl.com": 1,
+ "palace.museum": 1,
+ "paleo.museum": 1,
+ "palermo.it": 1,
+ "palmas.br": 1,
+ "palmsprings.museum": 1,
+ "panama.museum": 1,
+ "panel.gg": 1,
+ "pantheonsite.io": 1,
+ "parachuting.aero": 1,
+ "paragliding.aero": 1,
+ "paris.eu.org": 1,
+ "paris.museum": 1,
+ "parliament.cy": 1,
+ "parliament.nz": 1,
+ "parma.it": 1,
+ "paroch.k12.ma.us": 1,
+ "parti.se": 1,
+ "pasadena.museum": 1,
+ "passenger-association.aero": 1,
+ "patria.bo": 1,
+ "pavia.it": 1,
+ "pb.ao": 1,
+ "pb.gov.br": 1,
+ "pb.leg.br": 1,
+ "pc.it": 1,
+ "pc.pl": 1,
+ "pcloud.host": 1,
+ "pd.it": 1,
+ "pdns.page": 1,
+ "pe.ca": 1,
+ "pe.gov.br": 1,
+ "pe.it": 1,
+ "pe.kr": 1,
+ "pe.leg.br": 1,
+ "penza.su": 1,
+ "per.la": 1,
+ "per.nf": 1,
+ "per.sg": 1,
+ "perso.ht": 1,
+ "perso.sn": 1,
+ "perso.tn": 1,
+ "perspecta.cloud": 1,
+ "perugia.it": 1,
+ "pesaro-urbino.it": 1,
+ "pesarourbino.it": 1,
+ "pescara.it": 1,
+ "pg": 2,
+ "pg.it": 1,
+ "pgafan.net": 1,
+ "pgfog.com": 1,
+ "pharmacien.fr": 1,
+ "pharmaciens.km": 1,
+ "pharmacy.museum": 1,
+ "philadelphia.museum": 1,
+ "philadelphiaarea.museum": 1,
+ "philately.museum": 1,
+ "phoenix.museum": 1,
+ "photography.museum": 1,
+ "pi.gov.br": 1,
+ "pi.it": 1,
+ "pi.leg.br": 1,
+ "piacenza.it": 1,
+ "piedmont.it": 1,
+ "piemonte.it": 1,
+ "pila.pl": 1,
+ "pilot.aero": 1,
+ "pilots.museum": 1,
+ "pimienta.org": 1,
+ "pinb.gov.pl": 1,
+ "pippu.hokkaido.jp": 1,
+ "pisa.it": 1,
+ "pistoia.it": 1,
+ "pisz.pl": 1,
+ "pittsburgh.museum": 1,
+ "piw.gov.pl": 1,
+ "pixolino.com": 1,
+ "pl.eu.org": 1,
+ "pl.ua": 1,
+ "planetarium.museum": 1,
+ "plantation.museum": 1,
+ "plants.museum": 1,
+ "platform0.app": 1,
+ "platformsh.site": 2,
+ "platter-app.com": 1,
+ "platter-app.dev": 1,
+ "platterp.us": 1,
+ "playstation-cloud.com": 1,
+ "plaza.museum": 1,
+ "plc.co.im": 1,
+ "plc.ly": 1,
+ "plc.uk": 1,
+ "plesk.page": 1,
+ "pleskns.com": 1,
+ "plo.ps": 1,
+ "plurinacional.bo": 1,
+ "pmn.it": 1,
+ "pn.it": 1,
+ "po.gov.pl": 1,
+ "po.it": 1,
+ "poa.br": 1,
+ "podhale.pl": 1,
+ "podlasie.pl": 1,
+ "podzone.net": 1,
+ "podzone.org": 1,
+ "point2this.com": 1,
+ "pointto.us": 1,
+ "poivron.org": 1,
+ "pokrovsk.su": 1,
+ "pol.dz": 1,
+ "pol.ht": 1,
+ "pol.tr": 1,
+ "police.uk": 1,
+ "politica.bo": 1,
+ "polkowice.pl": 1,
+ "poltava.ua": 1,
+ "pomorskie.pl": 1,
+ "pomorze.pl": 1,
+ "poniatowa.pl": 1,
+ "ponpes.id": 1,
+ "pony.club": 1,
+ "pordenone.it": 1,
+ "porsanger.no": 1,
+ "porsangu.no": 1,
+ "porsgrunn.no": 1,
+ "pors\u00e1\u014bgu.no": 1,
+ "port.fr": 1,
+ "portal.museum": 1,
+ "portland.museum": 1,
+ "portlligat.museum": 1,
+ "posts-and-telecommunications.museum": 1,
+ "potager.org": 1,
+ "potenza.it": 1,
+ "powiat.pl": 1,
+ "poznan.pl": 1,
+ "pp.az": 1,
+ "pp.ru": 1,
+ "pp.se": 1,
+ "pp.ua": 1,
+ "ppg.br": 1,
+ "pr.gov.br": 1,
+ "pr.it": 1,
+ "pr.leg.br": 1,
+ "pr.us": 1,
+ "prato.it": 1,
+ "prd.fr": 1,
+ "prd.km": 1,
+ "prd.mg": 1,
+ "preservation.museum": 1,
+ "presidio.museum": 1,
+ "press.aero": 1,
+ "press.cy": 1,
+ "press.ma": 1,
+ "press.museum": 1,
+ "press.se": 1,
+ "presse.ci": 1,
+ "presse.km": 1,
+ "presse.ml": 1,
+ "pri.ee": 1,
+ "principe.st": 1,
+ "priv.at": 1,
+ "priv.hu": 1,
+ "priv.me": 1,
+ "priv.no": 1,
+ "priv.pl": 1,
+ "privatizehealthinsurance.net": 1,
+ "pro.az": 1,
+ "pro.br": 1,
+ "pro.cy": 1,
+ "pro.ec": 1,
+ "pro.fj": 1,
+ "pro.ht": 1,
+ "pro.mv": 1,
+ "pro.na": 1,
+ "pro.om": 1,
+ "pro.pr": 1,
+ "pro.tt": 1,
+ "pro.vn": 1,
+ "prochowice.pl": 1,
+ "production.aero": 1,
+ "prof.pr": 1,
+ "profesional.bo": 1,
+ "project.museum": 1,
+ "protonet.io": 1,
+ "pruszkow.pl": 1,
+ "prvcy.page": 1,
+ "przeworsk.pl": 1,
+ "psc.br": 1,
+ "psi.br": 1,
+ "psp.gov.pl": 1,
+ "psse.gov.pl": 1,
+ "pt.eu.org": 1,
+ "pt.it": 1,
+ "ptplus.fit": 1,
+ "pu.it": 1,
+ "pub.sa": 1,
+ "publ.pt": 1,
+ "public.museum": 1,
+ "publishproxy.com": 1,
+ "pubol.museum": 1,
+ "pubtls.org": 1,
+ "pueblo.bo": 1,
+ "pug.it": 1,
+ "puglia.it": 1,
+ "pulawy.pl": 1,
+ "pup.gov.pl": 1,
+ "pv.it": 1,
+ "pvh.br": 1,
+ "pvt.ge": 1,
+ "pvt.k12.ma.us": 1,
+ "pyatigorsk.ru": 1,
+ "pymnt.uk": 1,
+ "pz.it": 1,
+ "q-a.eu.org": 1,
+ "q.bg": 1,
+ "qa2.com": 1,
+ "qbuser.com": 1,
+ "qc.ca": 1,
+ "qc.com": 1,
+ "qcx.io": 1,
+ "qh.cn": 1,
+ "qld.au": 1,
+ "qld.edu.au": 1,
+ "qld.gov.au": 1,
+ "qsl.br": 1,
+ "qualifioapp.com": 1,
+ "quebec.museum": 1,
+ "quicksytes.com": 1,
+ "quipelements.com": 2,
+ "r.appspot.com": 2,
+ "r.bg": 1,
+ "r.cdn77.net": 1,
+ "r.se": 1,
+ "ra.it": 1,
+ "rackmaze.com": 1,
+ "rackmaze.net": 1,
+ "rade.no": 1,
+ "radio.am": 1,
+ "radio.br": 1,
+ "radio.fm": 1,
+ "radom.pl": 1,
+ "radoy.no": 1,
+ "rad\u00f8y.no": 1,
+ "ragusa.it": 1,
+ "rahkkeravju.no": 1,
+ "raholt.no": 1,
+ "railroad.museum": 1,
+ "railway.museum": 1,
+ "raisa.no": 1,
+ "rakkestad.no": 1,
+ "ralingen.no": 1,
+ "rana.no": 1,
+ "randaberg.no": 1,
+ "rankoshi.hokkaido.jp": 1,
+ "ranzan.saitama.jp": 1,
+ "ras.ru": 1,
+ "rauma.no": 1,
+ "ravendb.community": 1,
+ "ravendb.me": 1,
+ "ravendb.run": 1,
+ "ravenna.it": 1,
+ "rawa-maz.pl": 1,
+ "rc.it": 1,
+ "rdv.to": 1,
+ "re.it": 1,
+ "re.kr": 1,
+ "read-books.org": 1,
+ "readmyblog.org": 1,
+ "readthedocs.io": 1,
+ "realestate.pl": 1,
+ "realm.cz": 1,
+ "rebun.hokkaido.jp": 1,
+ "rec.br": 1,
+ "rec.co": 1,
+ "rec.nf": 1,
+ "rec.ro": 1,
+ "rec.ve": 1,
+ "recht.pro": 1,
+ "recife.br": 1,
+ "recreation.aero": 1,
+ "red.sv": 1,
+ "redirectme.net": 1,
+ "reg.dk": 1,
+ "reggio-calabria.it": 1,
+ "reggio-emilia.it": 1,
+ "reggiocalabria.it": 1,
+ "reggioemilia.it": 1,
+ "reklam.hu": 1,
+ "rel.ht": 1,
+ "rel.pl": 1,
+ "remotewd.com": 1,
+ "rendalen.no": 1,
+ "rennebu.no": 1,
+ "rennesoy.no": 1,
+ "rennes\u00f8y.no": 1,
+ "rep.br": 1,
+ "rep.kp": 1,
+ "repbody.aero": 1,
+ "repl.co": 1,
+ "repl.run": 1,
+ "res.aero": 1,
+ "res.in": 1,
+ "research.aero": 1,
+ "research.museum": 1,
+ "resindevice.io": 1,
+ "resistance.museum": 1,
+ "revista.bo": 1,
+ "rg.it": 1,
+ "rhcloud.com": 1,
+ "ri.it": 1,
+ "ri.us": 1,
+ "ribeirao.br": 1,
+ "rieti.it": 1,
+ "rifu.miyagi.jp": 1,
+ "riik.ee": 1,
+ "rikubetsu.hokkaido.jp": 1,
+ "rikuzentakata.iwate.jp": 1,
+ "rimini.it": 1,
+ "rindal.no": 1,
+ "ringebu.no": 1,
+ "ringerike.no": 1,
+ "ringsaker.no": 1,
+ "rio.br": 1,
+ "riobranco.br": 1,
+ "riodejaneiro.museum": 1,
+ "riopreto.br": 1,
+ "rishiri.hokkaido.jp": 1,
+ "rishirifuji.hokkaido.jp": 1,
+ "risor.no": 1,
+ "rissa.no": 1,
+ "ris\u00f8r.no": 1,
+ "ritto.shiga.jp": 1,
+ "rivne.ua": 1,
+ "rj.gov.br": 1,
+ "rj.leg.br": 1,
+ "rl.no": 1,
+ "rm.it": 1,
+ "rn.gov.br": 1,
+ "rn.it": 1,
+ "rn.leg.br": 1,
+ "rnrt.tn": 1,
+ "rns.tn": 1,
+ "rnu.tn": 1,
+ "ro.eu.org": 1,
+ "ro.gov.br": 1,
+ "ro.im": 1,
+ "ro.it": 1,
+ "ro.leg.br": 1,
+ "roan.no": 1,
+ "rochester.museum": 1,
+ "rockart.museum": 1,
+ "rodoy.no": 1,
+ "rokunohe.aomori.jp": 1,
+ "rollag.no": 1,
+ "roma.it": 1,
+ "roma.museum": 1,
+ "rome.it": 1,
+ "romsa.no": 1,
+ "romskog.no": 1,
+ "roros.no": 1,
+ "rost.no": 1,
+ "rotorcraft.aero": 1,
+ "router.management": 1,
+ "rovigo.it": 1,
+ "rovno.ua": 1,
+ "royken.no": 1,
+ "royrvik.no": 1,
+ "rr.gov.br": 1,
+ "rr.leg.br": 1,
+ "rs.gov.br": 1,
+ "rs.leg.br": 1,
+ "rsc.cdn77.org": 1,
+ "ru.com": 1,
+ "ru.eu.org": 1,
+ "ru.net": 1,
+ "run.app": 1,
+ "ruovat.no": 1,
+ "russia.museum": 1,
+ "rv.ua": 1,
+ "rybnik.pl": 1,
+ "rygge.no": 1,
+ "ryokami.saitama.jp": 1,
+ "ryugasaki.ibaraki.jp": 1,
+ "ryuoh.shiga.jp": 1,
+ "rzeszow.pl": 1,
+ "rzgw.gov.pl": 1,
+ "r\u00e1hkker\u00e1vju.no": 1,
+ "r\u00e1isa.no": 1,
+ "r\u00e5de.no": 1,
+ "r\u00e5holt.no": 1,
+ "r\u00e6lingen.no": 1,
+ "r\u00f8d\u00f8y.no": 1,
+ "r\u00f8mskog.no": 1,
+ "r\u00f8ros.no": 1,
+ "r\u00f8st.no": 1,
+ "r\u00f8yken.no": 1,
+ "r\u00f8yrvik.no": 1,
+ "s.bg": 1,
+ "s.se": 1,
+ "s3-ap-northeast-1.amazonaws.com": 1,
+ "s3-ap-northeast-2.amazonaws.com": 1,
+ "s3-ap-south-1.amazonaws.com": 1,
+ "s3-ap-southeast-1.amazonaws.com": 1,
+ "s3-ap-southeast-2.amazonaws.com": 1,
+ "s3-ca-central-1.amazonaws.com": 1,
+ "s3-eu-central-1.amazonaws.com": 1,
+ "s3-eu-west-1.amazonaws.com": 1,
+ "s3-eu-west-2.amazonaws.com": 1,
+ "s3-eu-west-3.amazonaws.com": 1,
+ "s3-external-1.amazonaws.com": 1,
+ "s3-fips-us-gov-west-1.amazonaws.com": 1,
+ "s3-sa-east-1.amazonaws.com": 1,
+ "s3-us-east-2.amazonaws.com": 1,
+ "s3-us-gov-west-1.amazonaws.com": 1,
+ "s3-us-west-1.amazonaws.com": 1,
+ "s3-us-west-2.amazonaws.com": 1,
+ "s3-website-ap-northeast-1.amazonaws.com": 1,
+ "s3-website-ap-southeast-1.amazonaws.com": 1,
+ "s3-website-ap-southeast-2.amazonaws.com": 1,
+ "s3-website-eu-west-1.amazonaws.com": 1,
+ "s3-website-sa-east-1.amazonaws.com": 1,
+ "s3-website-us-east-1.amazonaws.com": 1,
+ "s3-website-us-west-1.amazonaws.com": 1,
+ "s3-website-us-west-2.amazonaws.com": 1,
+ "s3-website.ap-northeast-2.amazonaws.com": 1,
+ "s3-website.ap-south-1.amazonaws.com": 1,
+ "s3-website.ca-central-1.amazonaws.com": 1,
+ "s3-website.eu-central-1.amazonaws.com": 1,
+ "s3-website.eu-west-2.amazonaws.com": 1,
+ "s3-website.eu-west-3.amazonaws.com": 1,
+ "s3-website.us-east-2.amazonaws.com": 1,
+ "s3.amazonaws.com": 1,
+ "s3.ap-northeast-2.amazonaws.com": 1,
+ "s3.ap-south-1.amazonaws.com": 1,
+ "s3.ca-central-1.amazonaws.com": 1,
+ "s3.cn-north-1.amazonaws.com.cn": 1,
+ "s3.dualstack.ap-northeast-1.amazonaws.com": 1,
+ "s3.dualstack.ap-northeast-2.amazonaws.com": 1,
+ "s3.dualstack.ap-south-1.amazonaws.com": 1,
+ "s3.dualstack.ap-southeast-1.amazonaws.com": 1,
+ "s3.dualstack.ap-southeast-2.amazonaws.com": 1,
+ "s3.dualstack.ca-central-1.amazonaws.com": 1,
+ "s3.dualstack.eu-central-1.amazonaws.com": 1,
+ "s3.dualstack.eu-west-1.amazonaws.com": 1,
+ "s3.dualstack.eu-west-2.amazonaws.com": 1,
+ "s3.dualstack.eu-west-3.amazonaws.com": 1,
+ "s3.dualstack.sa-east-1.amazonaws.com": 1,
+ "s3.dualstack.us-east-1.amazonaws.com": 1,
+ "s3.dualstack.us-east-2.amazonaws.com": 1,
+ "s3.eu-central-1.amazonaws.com": 1,
+ "s3.eu-west-2.amazonaws.com": 1,
+ "s3.eu-west-3.amazonaws.com": 1,
+ "s3.us-east-2.amazonaws.com": 1,
+ "s5y.io": 2,
+ "sa-east-1.elasticbeanstalk.com": 1,
+ "sa.au": 1,
+ "sa.com": 1,
+ "sa.cr": 1,
+ "sa.edu.au": 1,
+ "sa.gov.au": 1,
+ "sa.gov.pl": 1,
+ "sa.it": 1,
+ "sabae.fukui.jp": 1,
+ "sado.niigata.jp": 1,
+ "safety.aero": 1,
+ "saga.jp": 1,
+ "saga.saga.jp": 1,
+ "sagae.yamagata.jp": 1,
+ "sagamihara.kanagawa.jp": 1,
+ "saigawa.fukuoka.jp": 1,
+ "saijo.ehime.jp": 1,
+ "saikai.nagasaki.jp": 1,
+ "saiki.oita.jp": 1,
+ "saintlouis.museum": 1,
+ "saitama.jp": 1,
+ "saitama.saitama.jp": 1,
+ "saito.miyazaki.jp": 1,
+ "saka.hiroshima.jp": 1,
+ "sakado.saitama.jp": 1,
+ "sakae.chiba.jp": 1,
+ "sakae.nagano.jp": 1,
+ "sakahogi.gifu.jp": 1,
+ "sakai.fukui.jp": 1,
+ "sakai.ibaraki.jp": 1,
+ "sakai.osaka.jp": 1,
+ "sakaiminato.tottori.jp": 1,
+ "sakaki.nagano.jp": 1,
+ "sakata.yamagata.jp": 1,
+ "sakawa.kochi.jp": 1,
+ "sakegawa.yamagata.jp": 1,
+ "saku.nagano.jp": 1,
+ "sakuho.nagano.jp": 1,
+ "sakura.chiba.jp": 1,
+ "sakura.tochigi.jp": 1,
+ "sakuragawa.ibaraki.jp": 1,
+ "sakurai.nara.jp": 1,
+ "sakyo.kyoto.jp": 1,
+ "salangen.no": 1,
+ "salat.no": 1,
+ "salem.museum": 1,
+ "salerno.it": 1,
+ "saltdal.no": 1,
+ "salud.bo": 1,
+ "salvador.br": 1,
+ "salvadordali.museum": 1,
+ "salzburg.museum": 1,
+ "samegawa.fukushima.jp": 1,
+ "samnanger.no": 1,
+ "sampa.br": 1,
+ "samukawa.kanagawa.jp": 1,
+ "sanagochi.tokushima.jp": 1,
+ "sanda.hyogo.jp": 1,
+ "sandcats.io": 1,
+ "sande.more-og-romsdal.no": 1,
+ "sande.m\u00f8re-og-romsdal.no": 1,
+ "sande.vestfold.no": 1,
+ "sandefjord.no": 1,
+ "sandiego.museum": 1,
+ "sandnes.no": 1,
+ "sandnessjoen.no": 1,
+ "sandnessj\u00f8en.no": 1,
+ "sandoy.no": 1,
+ "sand\u00f8y.no": 1,
+ "sanfrancisco.museum": 1,
+ "sango.nara.jp": 1,
+ "sanjo.niigata.jp": 1,
+ "sannan.hyogo.jp": 1,
+ "sannohe.aomori.jp": 1,
+ "sano.tochigi.jp": 1,
+ "sanok.pl": 1,
+ "santabarbara.museum": 1,
+ "santacruz.museum": 1,
+ "santafe.museum": 1,
+ "santamaria.br": 1,
+ "santoandre.br": 1,
+ "sanuki.kagawa.jp": 1,
+ "saobernardo.br": 1,
+ "saogonca.br": 1,
+ "saotome.st": 1,
+ "sapporo.jp": 2,
+ "sar.it": 1,
+ "sardegna.it": 1,
+ "sardinia.it": 1,
+ "saroma.hokkaido.jp": 1,
+ "sarpsborg.no": 1,
+ "sarufutsu.hokkaido.jp": 1,
+ "sasaguri.fukuoka.jp": 1,
+ "sasayama.hyogo.jp": 1,
+ "sasebo.nagasaki.jp": 1,
+ "saskatchewan.museum": 1,
+ "sassari.it": 1,
+ "satosho.okayama.jp": 1,
+ "satsumasendai.kagoshima.jp": 1,
+ "satte.saitama.jp": 1,
+ "satx.museum": 1,
+ "sauda.no": 1,
+ "sauherad.no": 1,
+ "savannahga.museum": 1,
+ "saves-the-whales.com": 1,
+ "savona.it": 1,
+ "sayama.osaka.jp": 1,
+ "sayama.saitama.jp": 1,
+ "sayo.hyogo.jp": 1,
+ "sb.ua": 1,
+ "sc.cn": 1,
+ "sc.gov.br": 1,
+ "sc.ke": 1,
+ "sc.kr": 1,
+ "sc.leg.br": 1,
+ "sc.ls": 1,
+ "sc.tz": 1,
+ "sc.ug": 1,
+ "sc.us": 1,
+ "scapp.io": 1,
+ "sch.ae": 1,
+ "sch.id": 1,
+ "sch.ir": 1,
+ "sch.jo": 1,
+ "sch.lk": 1,
+ "sch.ly": 1,
+ "sch.ng": 1,
+ "sch.qa": 1,
+ "sch.sa": 1,
+ "sch.so": 1,
+ "sch.uk": 2,
+ "sch.zm": 1,
+ "schlesisches.museum": 1,
+ "schoenbrunn.museum": 1,
+ "schokokeks.net": 1,
+ "schokoladen.museum": 1,
+ "school.museum": 1,
+ "school.na": 1,
+ "school.nz": 1,
+ "school.za": 1,
+ "schools.nsw.edu.au": 1,
+ "schulserver.de": 1,
+ "schweiz.museum": 1,
+ "sci.eg": 1,
+ "science-fiction.museum": 1,
+ "science.museum": 1,
+ "scienceandhistory.museum": 1,
+ "scienceandindustry.museum": 1,
+ "sciencecenter.museum": 1,
+ "sciencecenters.museum": 1,
+ "sciencehistory.museum": 1,
+ "sciences.museum": 1,
+ "sciencesnaturelles.museum": 1,
+ "scientist.aero": 1,
+ "scotland.museum": 1,
+ "scrapper-site.net": 1,
+ "scrapping.cc": 1,
+ "scrysec.com": 1,
+ "sd.cn": 1,
+ "sd.us": 1,
+ "sdn.gov.pl": 1,
+ "se.eu.org": 1,
+ "se.gov.br": 1,
+ "se.leg.br": 1,
+ "se.net": 1,
+ "seaport.museum": 1,
+ "sebastopol.ua": 1,
+ "sec.ps": 1,
+ "securitytactics.com": 1,
+ "seg.br": 1,
+ "seidat.net": 1,
+ "seihi.nagasaki.jp": 1,
+ "seika.kyoto.jp": 1,
+ "seiro.niigata.jp": 1,
+ "seirou.niigata.jp": 1,
+ "seiyo.ehime.jp": 1,
+ "sejny.pl": 1,
+ "seki.gifu.jp": 1,
+ "sekigahara.gifu.jp": 1,
+ "sekikawa.niigata.jp": 1,
+ "sel.no": 1,
+ "selbu.no": 1,
+ "selfip.biz": 1,
+ "selfip.com": 1,
+ "selfip.info": 1,
+ "selfip.net": 1,
+ "selfip.org": 1,
+ "selje.no": 1,
+ "seljord.no": 1,
+ "sells-for-less.com": 1,
+ "sells-for-u.com": 1,
+ "sells-it.net": 1,
+ "sellsyourhome.org": 1,
+ "semboku.akita.jp": 1,
+ "semine.miyagi.jp": 1,
+ "sendai.jp": 2,
+ "sennan.osaka.jp": 1,
+ "senseering.net": 1,
+ "sensiosite.cloud": 2,
+ "seoul.kr": 1,
+ "sera.hiroshima.jp": 1,
+ "seranishi.hiroshima.jp": 1,
+ "servebbs.com": 1,
+ "servebbs.net": 1,
+ "servebbs.org": 1,
+ "servebeer.com": 1,
+ "serveblog.net": 1,
+ "servecounterstrike.com": 1,
+ "serveexchange.com": 1,
+ "serveftp.com": 1,
+ "serveftp.net": 1,
+ "serveftp.org": 1,
+ "servegame.com": 1,
+ "servegame.org": 1,
+ "servehalflife.com": 1,
+ "servehttp.com": 1,
+ "servehumour.com": 1,
+ "serveirc.com": 1,
+ "serveminecraft.net": 1,
+ "servemp3.com": 1,
+ "servep2p.com": 1,
+ "servepics.com": 1,
+ "servequake.com": 1,
+ "servesarcasm.com": 1,
+ "service.gov.uk": 1,
+ "services.aero": 1,
+ "setagaya.tokyo.jp": 1,
+ "seto.aichi.jp": 1,
+ "setouchi.okayama.jp": 1,
+ "settlement.museum": 1,
+ "settlers.museum": 1,
+ "settsu.osaka.jp": 1,
+ "sevastopol.ua": 1,
+ "sex.hu": 1,
+ "sex.pl": 1,
+ "sf.no": 1,
+ "sh.cn": 1,
+ "shacknet.nu": 1,
+ "shakotan.hokkaido.jp": 1,
+ "shari.hokkaido.jp": 1,
+ "shell.museum": 1,
+ "sherbrooke.museum": 1,
+ "shibata.miyagi.jp": 1,
+ "shibata.niigata.jp": 1,
+ "shibecha.hokkaido.jp": 1,
+ "shibetsu.hokkaido.jp": 1,
+ "shibukawa.gunma.jp": 1,
+ "shibuya.tokyo.jp": 1,
+ "shichikashuku.miyagi.jp": 1,
+ "shichinohe.aomori.jp": 1,
+ "shiftedit.io": 1,
+ "shiga.jp": 1,
+ "shiiba.miyazaki.jp": 1,
+ "shijonawate.osaka.jp": 1,
+ "shika.ishikawa.jp": 1,
+ "shikabe.hokkaido.jp": 1,
+ "shikama.miyagi.jp": 1,
+ "shikaoi.hokkaido.jp": 1,
+ "shikatsu.aichi.jp": 1,
+ "shiki.saitama.jp": 1,
+ "shikokuchuo.ehime.jp": 1,
+ "shima.mie.jp": 1,
+ "shimabara.nagasaki.jp": 1,
+ "shimada.shizuoka.jp": 1,
+ "shimamaki.hokkaido.jp": 1,
+ "shimamoto.osaka.jp": 1,
+ "shimane.jp": 1,
+ "shimane.shimane.jp": 1,
+ "shimizu.hokkaido.jp": 1,
+ "shimizu.shizuoka.jp": 1,
+ "shimoda.shizuoka.jp": 1,
+ "shimodate.ibaraki.jp": 1,
+ "shimofusa.chiba.jp": 1,
+ "shimogo.fukushima.jp": 1,
+ "shimoichi.nara.jp": 1,
+ "shimoji.okinawa.jp": 1,
+ "shimokawa.hokkaido.jp": 1,
+ "shimokitayama.nara.jp": 1,
+ "shimonita.gunma.jp": 1,
+ "shimonoseki.yamaguchi.jp": 1,
+ "shimosuwa.nagano.jp": 1,
+ "shimotsuke.tochigi.jp": 1,
+ "shimotsuma.ibaraki.jp": 1,
+ "shinagawa.tokyo.jp": 1,
+ "shinanomachi.nagano.jp": 1,
+ "shingo.aomori.jp": 1,
+ "shingu.fukuoka.jp": 1,
+ "shingu.hyogo.jp": 1,
+ "shingu.wakayama.jp": 1,
+ "shinichi.hiroshima.jp": 1,
+ "shinjo.nara.jp": 1,
+ "shinjo.okayama.jp": 1,
+ "shinjo.yamagata.jp": 1,
+ "shinjuku.tokyo.jp": 1,
+ "shinkamigoto.nagasaki.jp": 1,
+ "shinonsen.hyogo.jp": 1,
+ "shinshinotsu.hokkaido.jp": 1,
+ "shinshiro.aichi.jp": 1,
+ "shinto.gunma.jp": 1,
+ "shintoku.hokkaido.jp": 1,
+ "shintomi.miyazaki.jp": 1,
+ "shinyoshitomi.fukuoka.jp": 1,
+ "shiogama.miyagi.jp": 1,
+ "shiojiri.nagano.jp": 1,
+ "shioya.tochigi.jp": 1,
+ "shirahama.wakayama.jp": 1,
+ "shirakawa.fukushima.jp": 1,
+ "shirakawa.gifu.jp": 1,
+ "shirako.chiba.jp": 1,
+ "shiranuka.hokkaido.jp": 1,
+ "shiraoi.hokkaido.jp": 1,
+ "shiraoka.saitama.jp": 1,
+ "shirataka.yamagata.jp": 1,
+ "shiriuchi.hokkaido.jp": 1,
+ "shiroi.chiba.jp": 1,
+ "shiroishi.miyagi.jp": 1,
+ "shiroishi.saga.jp": 1,
+ "shirosato.ibaraki.jp": 1,
+ "shishikui.tokushima.jp": 1,
+ "shiso.hyogo.jp": 1,
+ "shisui.chiba.jp": 1,
+ "shitara.aichi.jp": 1,
+ "shiwa.iwate.jp": 1,
+ "shizukuishi.iwate.jp": 1,
+ "shizuoka.jp": 1,
+ "shizuoka.shizuoka.jp": 1,
+ "shobara.hiroshima.jp": 1,
+ "shonai.fukuoka.jp": 1,
+ "shonai.yamagata.jp": 1,
+ "shoo.okayama.jp": 1,
+ "shop.ht": 1,
+ "shop.hu": 1,
+ "shop.pl": 1,
+ "shop.ro": 1,
+ "shop.th": 1,
+ "shopitsite.com": 1,
+ "shopware.store": 1,
+ "show.aero": 1,
+ "showa.fukushima.jp": 1,
+ "showa.gunma.jp": 1,
+ "showa.yamanashi.jp": 1,
+ "shunan.yamaguchi.jp": 1,
+ "shw.io": 1,
+ "si.eu.org": 1,
+ "si.it": 1,
+ "sibenik.museum": 1,
+ "sic.it": 1,
+ "sicilia.it": 1,
+ "sicily.it": 1,
+ "siellak.no": 1,
+ "siena.it": 1,
+ "sigdal.no": 1,
+ "siljan.no": 1,
+ "silk.museum": 1,
+ "simple-url.com": 1,
+ "sinaapp.com": 1,
+ "siracusa.it": 1,
+ "sirdal.no": 1,
+ "siteleaf.net": 1,
+ "sites.static.land": 1,
+ "sjc.br": 1,
+ "sk.ca": 1,
+ "sk.eu.org": 1,
+ "skanit.no": 1,
+ "skanland.no": 1,
+ "skaun.no": 1,
+ "skedsmo.no": 1,
+ "skedsmokorset.no": 1,
+ "ski.museum": 1,
+ "ski.no": 1,
+ "skien.no": 1,
+ "skierva.no": 1,
+ "skierv\u00e1.no": 1,
+ "skiptvet.no": 1,
+ "skjak.no": 1,
+ "skjervoy.no": 1,
+ "skjerv\u00f8y.no": 1,
+ "skj\u00e5k.no": 1,
+ "sklep.pl": 1,
+ "sko.gov.pl": 1,
+ "skoczow.pl": 1,
+ "skodje.no": 1,
+ "skole.museum": 1,
+ "skydiving.aero": 1,
+ "skygearapp.com": 1,
+ "sk\u00e1nit.no": 1,
+ "sk\u00e5nland.no": 1,
+ "slask.pl": 1,
+ "slattum.no": 1,
+ "sld.do": 1,
+ "sld.pa": 1,
+ "slg.br": 1,
+ "slupsk.pl": 1,
+ "slz.br": 1,
+ "sm.ua": 1,
+ "small-web.org": 1,
+ "smola.no": 1,
+ "sm\u00f8la.no": 1,
+ "sn.cn": 1,
+ "snaase.no": 1,
+ "snasa.no": 1,
+ "snillfjord.no": 1,
+ "snoasa.no": 1,
+ "sn\u00e5ase.no": 1,
+ "sn\u00e5sa.no": 1,
+ "so.gov.pl": 1,
+ "so.it": 1,
+ "sobetsu.hokkaido.jp": 1,
+ "soc.dz": 1,
+ "soc.lk": 1,
+ "soc.srcf.net": 1,
+ "sochi.su": 1,
+ "society.museum": 1,
+ "sodegaura.chiba.jp": 1,
+ "soeda.fukuoka.jp": 1,
+ "software.aero": 1,
+ "sogndal.no": 1,
+ "sogne.no": 1,
+ "soja.okayama.jp": 1,
+ "soka.saitama.jp": 1,
+ "sokndal.no": 1,
+ "sola.no": 1,
+ "sologne.museum": 1,
+ "solund.no": 1,
+ "soma.fukushima.jp": 1,
+ "somna.no": 1,
+ "sondre-land.no": 1,
+ "sondrio.it": 1,
+ "songdalen.no": 1,
+ "soni.nara.jp": 1,
+ "soo.kagoshima.jp": 1,
+ "sopot.pl": 1,
+ "sor-aurdal.no": 1,
+ "sor-fron.no": 1,
+ "sor-odal.no": 1,
+ "sor-varanger.no": 1,
+ "sorfold.no": 1,
+ "sorocaba.br": 1,
+ "sorreisa.no": 1,
+ "sortland.no": 1,
+ "sorum.no": 1,
+ "sos.pl": 1,
+ "sosa.chiba.jp": 1,
+ "sosnowiec.pl": 1,
+ "soundandvision.museum": 1,
+ "soundcast.me": 1,
+ "southcarolina.museum": 1,
+ "southwest.museum": 1,
+ "sowa.ibaraki.jp": 1,
+ "sp.gov.br": 1,
+ "sp.it": 1,
+ "sp.leg.br": 1,
+ "space-to-rent.com": 1,
+ "space.museum": 1,
+ "spacekit.io": 1,
+ "spb.ru": 1,
+ "spb.su": 1,
+ "spdns.de": 1,
+ "spdns.eu": 1,
+ "spdns.org": 1,
+ "spectrum.myjino.ru": 2,
+ "sphinx.mythic-beasts.com": 1,
+ "spjelkavik.no": 1,
+ "sport.hu": 1,
+ "spy.museum": 1,
+ "spydeberg.no": 1,
+ "square.museum": 1,
+ "square7.ch": 1,
+ "square7.de": 1,
+ "square7.net": 1,
+ "sr.gov.pl": 1,
+ "sr.it": 1,
+ "srv.br": 1,
+ "ss.it": 1,
+ "ssl.origin.cdn77-secure.org": 1,
+ "st.no": 1,
+ "stackhero-network.com": 1,
+ "stadt.museum": 1,
+ "stage.nodeart.io": 1,
+ "staging.onred.one": 1,
+ "stalbans.museum": 1,
+ "stalowa-wola.pl": 1,
+ "stange.no": 1,
+ "starachowice.pl": 1,
+ "stargard.pl": 1,
+ "starnberg.museum": 1,
+ "starostwo.gov.pl": 1,
+ "stat.no": 1,
+ "state.museum": 1,
+ "stateofdelaware.museum": 1,
+ "stathelle.no": 1,
+ "static-access.net": 1,
+ "static.land": 1,
+ "static.observableusercontent.com": 1,
+ "statics.cloud": 2,
+ "station.museum": 1,
+ "stavanger.no": 1,
+ "stavern.no": 1,
+ "steam.museum": 1,
+ "steiermark.museum": 1,
+ "steigen.no": 1,
+ "steinkjer.no": 1,
+ "stg.dev": 2,
+ "sth.ac.at": 1,
+ "stjohn.museum": 1,
+ "stjordal.no": 1,
+ "stjordalshalsen.no": 1,
+ "stj\u00f8rdal.no": 1,
+ "stj\u00f8rdalshalsen.no": 1,
+ "stockholm.museum": 1,
+ "stokke.no": 1,
+ "stolos.io": 2,
+ "stor-elvdal.no": 1,
+ "storage.yandexcloud.net": 1,
+ "stord.no": 1,
+ "stordal.no": 1,
+ "store.bb": 1,
+ "store.dk": 1,
+ "store.nf": 1,
+ "store.ro": 1,
+ "store.st": 1,
+ "store.ve": 1,
+ "storfjord.no": 1,
+ "storj.farm": 1,
+ "stpetersburg.museum": 1,
+ "strand.no": 1,
+ "stranda.no": 1,
+ "stryn.no": 1,
+ "student.aero": 1,
+ "stuff-4-sale.org": 1,
+ "stuff-4-sale.us": 1,
+ "stufftoread.com": 1,
+ "stuttgart.museum": 1,
+ "sue.fukuoka.jp": 1,
+ "suedtirol.it": 1,
+ "suginami.tokyo.jp": 1,
+ "sugito.saitama.jp": 1,
+ "suifu.ibaraki.jp": 1,
+ "suisse.museum": 1,
+ "suita.osaka.jp": 1,
+ "sukagawa.fukushima.jp": 1,
+ "sukumo.kochi.jp": 1,
+ "sula.no": 1,
+ "suldal.no": 1,
+ "suli.hu": 1,
+ "sumida.tokyo.jp": 1,
+ "sumita.iwate.jp": 1,
+ "sumoto.hyogo.jp": 1,
+ "sumoto.kumamoto.jp": 1,
+ "sumy.ua": 1,
+ "sunagawa.hokkaido.jp": 1,
+ "sund.no": 1,
+ "sunndal.no": 1,
+ "surgeonshall.museum": 1,
+ "surnadal.no": 1,
+ "surrey.museum": 1,
+ "susaki.kochi.jp": 1,
+ "susono.shizuoka.jp": 1,
+ "suwa.nagano.jp": 1,
+ "suwalki.pl": 1,
+ "suzaka.nagano.jp": 1,
+ "suzu.ishikawa.jp": 1,
+ "suzuka.mie.jp": 1,
+ "sv.it": 1,
+ "svalbard.no": 1,
+ "svc.firenet.ch": 2,
+ "sveio.no": 1,
+ "svelvik.no": 1,
+ "svizzera.museum": 1,
+ "svn-repos.de": 1,
+ "sweden.museum": 1,
+ "sweetpepper.org": 1,
+ "swidnica.pl": 1,
+ "swidnik.pl": 1,
+ "swiebodzin.pl": 1,
+ "swinoujscie.pl": 1,
+ "sx.cn": 1,
+ "sydney.museum": 1,
+ "sykkylven.no": 1,
+ "syncloud.it": 1,
+ "syno-ds.de": 1,
+ "synology-diskstation.de": 1,
+ "synology-ds.de": 1,
+ "synology.me": 1,
+ "sys.qcx.io": 2,
+ "sytes.net": 1,
+ "szczecin.pl": 1,
+ "szczytno.pl": 1,
+ "szex.hu": 1,
+ "szkola.pl": 1,
+ "s\u00e1lat.no": 1,
+ "s\u00e1l\u00e1t.no": 1,
+ "s\u00f8gne.no": 1,
+ "s\u00f8mna.no": 1,
+ "s\u00f8ndre-land.no": 1,
+ "s\u00f8r-aurdal.no": 1,
+ "s\u00f8r-fron.no": 1,
+ "s\u00f8r-odal.no": 1,
+ "s\u00f8r-varanger.no": 1,
+ "s\u00f8rfold.no": 1,
+ "s\u00f8rreisa.no": 1,
+ "s\u00f8rum.no": 1,
+ "s\u00fcdtirol.it": 1,
+ "t.bg": 1,
+ "t.se": 1,
+ "t3l3p0rt.net": 1,
+ "ta.it": 1,
+ "taa.it": 1,
+ "tabayama.yamanashi.jp": 1,
+ "tabuse.yamaguchi.jp": 1,
+ "tachiarai.fukuoka.jp": 1,
+ "tachikawa.tokyo.jp": 1,
+ "tadaoka.osaka.jp": 1,
+ "tado.mie.jp": 1,
+ "tadotsu.kagawa.jp": 1,
+ "tagajo.miyagi.jp": 1,
+ "tagami.niigata.jp": 1,
+ "tagawa.fukuoka.jp": 1,
+ "tahara.aichi.jp": 1,
+ "taifun-dns.de": 1,
+ "taiji.wakayama.jp": 1,
+ "taiki.hokkaido.jp": 1,
+ "taiki.mie.jp": 1,
+ "tainai.niigata.jp": 1,
+ "taira.toyama.jp": 1,
+ "taishi.hyogo.jp": 1,
+ "taishi.osaka.jp": 1,
+ "taishin.fukushima.jp": 1,
+ "taito.tokyo.jp": 1,
+ "taiwa.miyagi.jp": 1,
+ "tajimi.gifu.jp": 1,
+ "tajiri.osaka.jp": 1,
+ "taka.hyogo.jp": 1,
+ "takagi.nagano.jp": 1,
+ "takahagi.ibaraki.jp": 1,
+ "takahama.aichi.jp": 1,
+ "takahama.fukui.jp": 1,
+ "takaharu.miyazaki.jp": 1,
+ "takahashi.okayama.jp": 1,
+ "takahata.yamagata.jp": 1,
+ "takaishi.osaka.jp": 1,
+ "takamatsu.kagawa.jp": 1,
+ "takamori.kumamoto.jp": 1,
+ "takamori.nagano.jp": 1,
+ "takanabe.miyazaki.jp": 1,
+ "takanezawa.tochigi.jp": 1,
+ "takaoka.toyama.jp": 1,
+ "takarazuka.hyogo.jp": 1,
+ "takasago.hyogo.jp": 1,
+ "takasaki.gunma.jp": 1,
+ "takashima.shiga.jp": 1,
+ "takasu.hokkaido.jp": 1,
+ "takata.fukuoka.jp": 1,
+ "takatori.nara.jp": 1,
+ "takatsuki.osaka.jp": 1,
+ "takatsuki.shiga.jp": 1,
+ "takayama.gifu.jp": 1,
+ "takayama.gunma.jp": 1,
+ "takayama.nagano.jp": 1,
+ "takazaki.miyazaki.jp": 1,
+ "takehara.hiroshima.jp": 1,
+ "taketa.oita.jp": 1,
+ "taketomi.okinawa.jp": 1,
+ "taki.mie.jp": 1,
+ "takikawa.hokkaido.jp": 1,
+ "takino.hyogo.jp": 1,
+ "takinoue.hokkaido.jp": 1,
+ "takko.aomori.jp": 1,
+ "tako.chiba.jp": 1,
+ "taku.saga.jp": 1,
+ "tama.tokyo.jp": 1,
+ "tamakawa.fukushima.jp": 1,
+ "tamaki.mie.jp": 1,
+ "tamamura.gunma.jp": 1,
+ "tamano.okayama.jp": 1,
+ "tamatsukuri.ibaraki.jp": 1,
+ "tamayu.shimane.jp": 1,
+ "tamba.hyogo.jp": 1,
+ "tana.no": 1,
+ "tanabe.kyoto.jp": 1,
+ "tanabe.wakayama.jp": 1,
+ "tanagura.fukushima.jp": 1,
+ "tananger.no": 1,
+ "tank.museum": 1,
+ "tanohata.iwate.jp": 1,
+ "tara.saga.jp": 1,
+ "tarama.okinawa.jp": 1,
+ "taranto.it": 1,
+ "targi.pl": 1,
+ "tarnobrzeg.pl": 1,
+ "tarui.gifu.jp": 1,
+ "tarumizu.kagoshima.jp": 1,
+ "tas.au": 1,
+ "tas.edu.au": 1,
+ "tas.gov.au": 1,
+ "tashkent.su": 1,
+ "tatebayashi.gunma.jp": 1,
+ "tateshina.nagano.jp": 1,
+ "tateyama.chiba.jp": 1,
+ "tateyama.toyama.jp": 1,
+ "tatsuno.hyogo.jp": 1,
+ "tatsuno.nagano.jp": 1,
+ "tawaramoto.nara.jp": 1,
+ "taxi.br": 1,
+ "tc.br": 1,
+ "tcm.museum": 1,
+ "tcp4.me": 1,
+ "te.it": 1,
+ "te.ua": 1,
+ "teaches-yoga.com": 1,
+ "teams.algorithmia.com": 0,
+ "tec.br": 1,
+ "tec.mi.us": 1,
+ "tec.ve": 1,
+ "technology.museum": 1,
+ "tecnologia.bo": 1,
+ "tel.tr": 1,
+ "tele.amune.org": 1,
+ "telebit.app": 1,
+ "telebit.io": 1,
+ "telebit.xyz": 2,
+ "telekommunikation.museum": 1,
+ "television.museum": 1,
+ "temp-dns.com": 1,
+ "tempio-olbia.it": 1,
+ "tempioolbia.it": 1,
+ "tendo.yamagata.jp": 1,
+ "tenei.fukushima.jp": 1,
+ "tenkawa.nara.jp": 1,
+ "tenri.nara.jp": 1,
+ "teo.br": 1,
+ "teramo.it": 1,
+ "termez.su": 1,
+ "terni.it": 1,
+ "ternopil.ua": 1,
+ "teshikaga.hokkaido.jp": 1,
+ "test-iserv.de": 1,
+ "test.algorithmia.com": 0,
+ "test.ru": 1,
+ "test.tj": 1,
+ "texas.museum": 1,
+ "textile.museum": 1,
+ "tgory.pl": 1,
+ "the.br": 1,
+ "theater.museum": 1,
+ "theworkpc.com": 1,
+ "thingdustdata.com": 1,
+ "thruhere.net": 1,
+ "time.museum": 1,
+ "time.no": 1,
+ "timekeeping.museum": 1,
+ "tingvoll.no": 1,
+ "tinn.no": 1,
+ "tj.cn": 1,
+ "tjeldsund.no": 1,
+ "tjome.no": 1,
+ "tj\u00f8me.no": 1,
+ "tksat.bo": 1,
+ "tm.cy": 1,
+ "tm.dz": 1,
+ "tm.fr": 1,
+ "tm.hu": 1,
+ "tm.km": 1,
+ "tm.mc": 1,
+ "tm.mg": 1,
+ "tm.no": 1,
+ "tm.pl": 1,
+ "tm.ro": 1,
+ "tm.se": 1,
+ "tm.za": 1,
+ "tmp.br": 1,
+ "tn.it": 1,
+ "tn.us": 1,
+ "to.gov.br": 1,
+ "to.gt": 1,
+ "to.it": 1,
+ "to.leg.br": 1,
+ "to.md": 1,
+ "to.work": 1,
+ "toba.mie.jp": 1,
+ "tobe.ehime.jp": 1,
+ "tobetsu.hokkaido.jp": 1,
+ "tobishima.aichi.jp": 1,
+ "tochigi.jp": 1,
+ "tochigi.tochigi.jp": 1,
+ "tochio.niigata.jp": 1,
+ "toda.saitama.jp": 1,
+ "toei.aichi.jp": 1,
+ "toga.toyama.jp": 1,
+ "togakushi.nagano.jp": 1,
+ "togane.chiba.jp": 1,
+ "togitsu.nagasaki.jp": 1,
+ "togliatti.su": 1,
+ "togo.aichi.jp": 1,
+ "togura.nagano.jp": 1,
+ "tohma.hokkaido.jp": 1,
+ "tohnosho.chiba.jp": 1,
+ "toho.fukuoka.jp": 1,
+ "tokai.aichi.jp": 1,
+ "tokai.ibaraki.jp": 1,
+ "tokamachi.niigata.jp": 1,
+ "tokashiki.okinawa.jp": 1,
+ "toki.gifu.jp": 1,
+ "tokigawa.saitama.jp": 1,
+ "tokke.no": 1,
+ "tokoname.aichi.jp": 1,
+ "tokorozawa.saitama.jp": 1,
+ "tokushima.jp": 1,
+ "tokushima.tokushima.jp": 1,
+ "tokuyama.yamaguchi.jp": 1,
+ "tokyo.jp": 1,
+ "tolga.no": 1,
+ "tomakomai.hokkaido.jp": 1,
+ "tomari.hokkaido.jp": 1,
+ "tome.miyagi.jp": 1,
+ "tomi.nagano.jp": 1,
+ "tomigusuku.okinawa.jp": 1,
+ "tomika.gifu.jp": 1,
+ "tomioka.gunma.jp": 1,
+ "tomisato.chiba.jp": 1,
+ "tomiya.miyagi.jp": 1,
+ "tomobe.ibaraki.jp": 1,
+ "tonaki.okinawa.jp": 1,
+ "tonami.toyama.jp": 1,
+ "tondabayashi.osaka.jp": 1,
+ "tone.ibaraki.jp": 1,
+ "tono.iwate.jp": 1,
+ "tonosho.kagawa.jp": 1,
+ "tonsberg.no": 1,
+ "toolforge.org": 1,
+ "toon.ehime.jp": 1,
+ "topology.museum": 1,
+ "torahime.shiga.jp": 1,
+ "toride.ibaraki.jp": 1,
+ "torino.it": 1,
+ "torino.museum": 1,
+ "torsken.no": 1,
+ "tos.it": 1,
+ "tosa.kochi.jp": 1,
+ "tosashimizu.kochi.jp": 1,
+ "toscana.it": 1,
+ "toshima.tokyo.jp": 1,
+ "tosu.saga.jp": 1,
+ "tottori.jp": 1,
+ "tottori.tottori.jp": 1,
+ "touch.museum": 1,
+ "tourism.pl": 1,
+ "tourism.tn": 1,
+ "towada.aomori.jp": 1,
+ "town.museum": 1,
+ "townnews-staging.com": 1,
+ "toya.hokkaido.jp": 1,
+ "toyako.hokkaido.jp": 1,
+ "toyama.jp": 1,
+ "toyama.toyama.jp": 1,
+ "toyo.kochi.jp": 1,
+ "toyoake.aichi.jp": 1,
+ "toyohashi.aichi.jp": 1,
+ "toyokawa.aichi.jp": 1,
+ "toyonaka.osaka.jp": 1,
+ "toyone.aichi.jp": 1,
+ "toyono.osaka.jp": 1,
+ "toyooka.hyogo.jp": 1,
+ "toyosato.shiga.jp": 1,
+ "toyota.aichi.jp": 1,
+ "toyota.yamaguchi.jp": 1,
+ "toyotomi.hokkaido.jp": 1,
+ "toyotsu.fukuoka.jp": 1,
+ "toyoura.hokkaido.jp": 1,
+ "tozawa.yamagata.jp": 1,
+ "tozsde.hu": 1,
+ "tp.it": 1,
+ "tr.eu.org": 1,
+ "tr.it": 1,
+ "tr.no": 1,
+ "tra.kp": 1,
+ "trader.aero": 1,
+ "trading.aero": 1,
+ "traeumtgerade.de": 1,
+ "trafficplex.cloud": 1,
+ "trainer.aero": 1,
+ "trana.no": 1,
+ "tranby.no": 1,
+ "trani-andria-barletta.it": 1,
+ "trani-barletta-andria.it": 1,
+ "traniandriabarletta.it": 1,
+ "tranibarlettaandria.it": 1,
+ "tranoy.no": 1,
+ "translate.goog": 1,
+ "transport.museum": 1,
+ "transporte.bo": 1,
+ "transurl.be": 2,
+ "transurl.eu": 2,
+ "transurl.nl": 2,
+ "tran\u00f8y.no": 1,
+ "trapani.it": 1,
+ "travel.pl": 1,
+ "travel.tt": 1,
+ "trd.br": 1,
+ "tree.museum": 1,
+ "trentin-sud-tirol.it": 1,
+ "trentin-sudtirol.it": 1,
+ "trentin-sued-tirol.it": 1,
+ "trentin-suedtirol.it": 1,
+ "trentin-s\u00fcd-tirol.it": 1,
+ "trentin-s\u00fcdtirol.it": 1,
+ "trentino-a-adige.it": 1,
+ "trentino-aadige.it": 1,
+ "trentino-alto-adige.it": 1,
+ "trentino-altoadige.it": 1,
+ "trentino-s-tirol.it": 1,
+ "trentino-stirol.it": 1,
+ "trentino-sud-tirol.it": 1,
+ "trentino-sudtirol.it": 1,
+ "trentino-sued-tirol.it": 1,
+ "trentino-suedtirol.it": 1,
+ "trentino-s\u00fcd-tirol.it": 1,
+ "trentino-s\u00fcdtirol.it": 1,
+ "trentino.it": 1,
+ "trentinoa-adige.it": 1,
+ "trentinoaadige.it": 1,
+ "trentinoalto-adige.it": 1,
+ "trentinoaltoadige.it": 1,
+ "trentinos-tirol.it": 1,
+ "trentinostirol.it": 1,
+ "trentinosud-tirol.it": 1,
+ "trentinosudtirol.it": 1,
+ "trentinosued-tirol.it": 1,
+ "trentinosuedtirol.it": 1,
+ "trentinos\u00fcd-tirol.it": 1,
+ "trentinos\u00fcdtirol.it": 1,
+ "trentinsud-tirol.it": 1,
+ "trentinsudtirol.it": 1,
+ "trentinsued-tirol.it": 1,
+ "trentinsuedtirol.it": 1,
+ "trentins\u00fcd-tirol.it": 1,
+ "trentins\u00fcdtirol.it": 1,
+ "trento.it": 1,
+ "treviso.it": 1,
+ "trieste.it": 1,
+ "triton.zone": 2,
+ "troandin.no": 1,
+ "trogstad.no": 1,
+ "troitsk.su": 1,
+ "trolley.museum": 1,
+ "tromsa.no": 1,
+ "tromso.no": 1,
+ "troms\u00f8.no": 1,
+ "trondheim.no": 1,
+ "trust.museum": 1,
+ "trustee.museum": 1,
+ "trycloudflare.com": 1,
+ "trysil.no": 1,
+ "tr\u00e6na.no": 1,
+ "tr\u00f8gstad.no": 1,
+ "ts.it": 1,
+ "tselinograd.su": 1,
+ "tsk.tr": 1,
+ "tsu.mie.jp": 1,
+ "tsubame.niigata.jp": 1,
+ "tsubata.ishikawa.jp": 1,
+ "tsubetsu.hokkaido.jp": 1,
+ "tsuchiura.ibaraki.jp": 1,
+ "tsuga.tochigi.jp": 1,
+ "tsugaru.aomori.jp": 1,
+ "tsuiki.fukuoka.jp": 1,
+ "tsukigata.hokkaido.jp": 1,
+ "tsukiyono.gunma.jp": 1,
+ "tsukuba.ibaraki.jp": 1,
+ "tsukui.kanagawa.jp": 1,
+ "tsukumi.oita.jp": 1,
+ "tsumagoi.gunma.jp": 1,
+ "tsunan.niigata.jp": 1,
+ "tsuno.kochi.jp": 1,
+ "tsuno.miyazaki.jp": 1,
+ "tsuru.yamanashi.jp": 1,
+ "tsuruga.fukui.jp": 1,
+ "tsurugashima.saitama.jp": 1,
+ "tsurugi.ishikawa.jp": 1,
+ "tsuruoka.yamagata.jp": 1,
+ "tsuruta.aomori.jp": 1,
+ "tsushima.aichi.jp": 1,
+ "tsushima.nagasaki.jp": 1,
+ "tsuwano.shimane.jp": 1,
+ "tsuyama.okayama.jp": 1,
+ "tt.im": 1,
+ "tula.su": 1,
+ "tunk.org": 1,
+ "tur.ar": 1,
+ "tur.br": 1,
+ "turek.pl": 1,
+ "turen.tn": 1,
+ "turin.it": 1,
+ "turystyka.pl": 1,
+ "tuscany.it": 1,
+ "tuva.su": 1,
+ "tuxfamily.org": 1,
+ "tv.bb": 1,
+ "tv.bo": 1,
+ "tv.br": 1,
+ "tv.im": 1,
+ "tv.it": 1,
+ "tv.kg": 1,
+ "tv.na": 1,
+ "tv.sd": 1,
+ "tv.tr": 1,
+ "tv.tz": 1,
+ "tvedestrand.no": 1,
+ "tw.cn": 1,
+ "twmail.cc": 1,
+ "twmail.net": 1,
+ "twmail.org": 1,
+ "tx.us": 1,
+ "tychy.pl": 1,
+ "tydal.no": 1,
+ "tynset.no": 1,
+ "tysfjord.no": 1,
+ "tysnes.no": 1,
+ "tysvar.no": 1,
+ "tysv\u00e6r.no": 1,
+ "t\u00f8nsberg.no": 1,
+ "u.bg": 1,
+ "u.channelsdvr.net": 1,
+ "u.se": 1,
+ "u2-local.xnbay.com": 1,
+ "u2.xnbay.com": 1,
+ "ua.rs": 1,
+ "ube.yamaguchi.jp": 1,
+ "uber.space": 1,
+ "uberspace.de": 2,
+ "uchihara.ibaraki.jp": 1,
+ "uchiko.ehime.jp": 1,
+ "uchinada.ishikawa.jp": 1,
+ "uchinomi.kagawa.jp": 1,
+ "ud.it": 1,
+ "uda.nara.jp": 1,
+ "udi.br": 1,
+ "udine.it": 1,
+ "udono.mie.jp": 1,
+ "ueda.nagano.jp": 1,
+ "ueno.gunma.jp": 1,
+ "uenohara.yamanashi.jp": 1,
+ "ufcfan.org": 1,
+ "ug.gov.pl": 1,
+ "ugim.gov.pl": 1,
+ "uhren.museum": 1,
+ "ui.nabu.casa": 1,
+ "uji.kyoto.jp": 1,
+ "ujiie.tochigi.jp": 1,
+ "ujitawara.kyoto.jp": 1,
+ "uk.com": 1,
+ "uk.eu.org": 1,
+ "uk.kg": 1,
+ "uk.net": 1,
+ "uk0.bigv.io": 1,
+ "ukco.me": 1,
+ "uki.kumamoto.jp": 1,
+ "ukiha.fukuoka.jp": 1,
+ "uklugs.org": 1,
+ "ullensaker.no": 1,
+ "ullensvang.no": 1,
+ "ulm.museum": 1,
+ "ulsan.kr": 1,
+ "ulvik.no": 1,
+ "um.gov.pl": 1,
+ "umaji.kochi.jp": 1,
+ "umb.it": 1,
+ "umbria.it": 1,
+ "umi.fukuoka.jp": 1,
+ "umig.gov.pl": 1,
+ "unazuki.toyama.jp": 1,
+ "undersea.museum": 1,
+ "uni5.net": 1,
+ "union.aero": 1,
+ "univ.sn": 1,
+ "university.museum": 1,
+ "unjarga.no": 1,
+ "unj\u00e1rga.no": 1,
+ "unnan.shimane.jp": 1,
+ "unusualperson.com": 1,
+ "unzen.nagasaki.jp": 1,
+ "uonuma.niigata.jp": 1,
+ "uozu.toyama.jp": 1,
+ "upow.gov.pl": 1,
+ "uppo.gov.pl": 1,
+ "urakawa.hokkaido.jp": 1,
+ "urasoe.okinawa.jp": 1,
+ "urausu.hokkaido.jp": 1,
+ "urawa.saitama.jp": 1,
+ "urayasu.chiba.jp": 1,
+ "urbino-pesaro.it": 1,
+ "urbinopesaro.it": 1,
+ "ureshino.mie.jp": 1,
+ "uri.arpa": 1,
+ "url.tw": 1,
+ "urn.arpa": 1,
+ "urown.cloud": 1,
+ "uruma.okinawa.jp": 1,
+ "uryu.hokkaido.jp": 1,
+ "us-1.evennode.com": 1,
+ "us-2.evennode.com": 1,
+ "us-3.evennode.com": 1,
+ "us-4.evennode.com": 1,
+ "us-east-1.amazonaws.com": 1,
+ "us-east-1.elasticbeanstalk.com": 1,
+ "us-east-2.elasticbeanstalk.com": 1,
+ "us-gov-west-1.elasticbeanstalk.com": 1,
+ "us-west-1.elasticbeanstalk.com": 1,
+ "us-west-2.elasticbeanstalk.com": 1,
+ "us.ax": 1,
+ "us.com": 1,
+ "us.eu.org": 1,
+ "us.gov.pl": 1,
+ "us.kg": 1,
+ "us.na": 1,
+ "us.org": 1,
+ "us.platform.sh": 1,
+ "usa.museum": 1,
+ "usa.oita.jp": 1,
+ "usantiques.museum": 1,
+ "usarts.museum": 1,
+ "uscountryestate.museum": 1,
+ "usculture.museum": 1,
+ "usdecorativearts.museum": 1,
+ "user.aseinet.ne.jp": 1,
+ "user.party.eus": 1,
+ "user.srcf.net": 1,
+ "usercontent.jp": 1,
+ "usgarden.museum": 1,
+ "ushiku.ibaraki.jp": 1,
+ "ushistory.museum": 1,
+ "ushuaia.museum": 1,
+ "uslivinghistory.museum": 1,
+ "usr.cloud.muni.cz": 1,
+ "ustka.pl": 1,
+ "usui.fukuoka.jp": 1,
+ "usuki.oita.jp": 1,
+ "ut.us": 1,
+ "utah.museum": 1,
+ "utashinai.hokkaido.jp": 1,
+ "utazas.hu": 1,
+ "utazu.kagawa.jp": 1,
+ "uto.kumamoto.jp": 1,
+ "utsira.no": 1,
+ "utsunomiya.tochigi.jp": 1,
+ "utwente.io": 1,
+ "uvic.museum": 1,
+ "uw.gov.pl": 1,
+ "uwajima.ehime.jp": 1,
+ "uwu.ai": 1,
+ "uwu.nu": 1,
+ "uy.com": 1,
+ "uz.ua": 1,
+ "uzhgorod.ua": 1,
+ "uzs.gov.pl": 1,
+ "v-info.info": 1,
+ "v.bg": 1,
+ "v.ua": 1,
+ "va.it": 1,
+ "va.no": 1,
+ "va.us": 1,
+ "vaapste.no": 1,
+ "vadso.no": 1,
+ "vads\u00f8.no": 1,
+ "vaga.no": 1,
+ "vagan.no": 1,
+ "vagsoy.no": 1,
+ "vaksdal.no": 1,
+ "val-d-aosta.it": 1,
+ "val-daosta.it": 1,
+ "vald-aosta.it": 1,
+ "valdaosta.it": 1,
+ "valer.hedmark.no": 1,
+ "valer.ostfold.no": 1,
+ "valle-aosta.it": 1,
+ "valle-d-aosta.it": 1,
+ "valle-daosta.it": 1,
+ "valle.no": 1,
+ "valleaosta.it": 1,
+ "valled-aosta.it": 1,
+ "valledaosta.it": 1,
+ "vallee-aoste.it": 1,
+ "vallee-d-aoste.it": 1,
+ "valleeaoste.it": 1,
+ "valleedaoste.it": 1,
+ "valley.museum": 1,
+ "vall\u00e9e-aoste.it": 1,
+ "vall\u00e9e-d-aoste.it": 1,
+ "vall\u00e9eaoste.it": 1,
+ "vall\u00e9edaoste.it": 1,
+ "vang.no": 1,
+ "vantaa.museum": 1,
+ "vanylven.no": 1,
+ "vao.it": 1,
+ "vapor.cloud": 1,
+ "vaporcloud.io": 1,
+ "vardo.no": 1,
+ "vard\u00f8.no": 1,
+ "varese.it": 1,
+ "varggat.no": 1,
+ "varoy.no": 1,
+ "vb.it": 1,
+ "vc.it": 1,
+ "vda.it": 1,
+ "ve.it": 1,
+ "vefsn.no": 1,
+ "vega.no": 1,
+ "vegarshei.no": 1,
+ "veg\u00e5rshei.no": 1,
+ "ven.it": 1,
+ "veneto.it": 1,
+ "venezia.it": 1,
+ "venice.it": 1,
+ "vennesla.no": 1,
+ "verbania.it": 1,
+ "vercel.app": 1,
+ "vercel.dev": 1,
+ "vercelli.it": 1,
+ "verdal.no": 1,
+ "verona.it": 1,
+ "verran.no": 1,
+ "versailles.museum": 1,
+ "vestby.no": 1,
+ "vestnes.no": 1,
+ "vestre-slidre.no": 1,
+ "vestre-toten.no": 1,
+ "vestvagoy.no": 1,
+ "vestv\u00e5g\u00f8y.no": 1,
+ "vet.br": 1,
+ "veterinaire.fr": 1,
+ "veterinaire.km": 1,
+ "vevelstad.no": 1,
+ "vf.no": 1,
+ "vgs.no": 1,
+ "vi.it": 1,
+ "vi.us": 1,
+ "vibo-valentia.it": 1,
+ "vibovalentia.it": 1,
+ "vic.au": 1,
+ "vic.edu.au": 1,
+ "vic.gov.au": 1,
+ "vicenza.it": 1,
+ "video.hu": 1,
+ "vik.no": 1,
+ "viking.museum": 1,
+ "vikna.no": 1,
+ "village.museum": 1,
+ "vindafjord.no": 1,
+ "vinnica.ua": 1,
+ "vinnytsia.ua": 1,
+ "vip.jelastic.cloud": 1,
+ "vipsinaapp.com": 1,
+ "virginia.museum": 1,
+ "virtual-user.de": 1,
+ "virtual.museum": 1,
+ "virtualserver.io": 1,
+ "virtualuser.de": 1,
+ "virtueeldomein.nl": 1,
+ "virtuel.museum": 1,
+ "viterbo.it": 1,
+ "vix.br": 1,
+ "vlaanderen.museum": 1,
+ "vladikavkaz.ru": 1,
+ "vladikavkaz.su": 1,
+ "vladimir.ru": 1,
+ "vladimir.su": 1,
+ "vlog.br": 1,
+ "vm.bytemark.co.uk": 1,
+ "vn.ua": 1,
+ "voagat.no": 1,
+ "volda.no": 1,
+ "volkenkunde.museum": 1,
+ "vologda.su": 1,
+ "volyn.ua": 1,
+ "voorloper.cloud": 1,
+ "voss.no": 1,
+ "vossevangen.no": 1,
+ "vpndns.net": 1,
+ "vpnplus.to": 1,
+ "vps.mcdir.ru": 1,
+ "vps.myjino.ru": 2,
+ "vr.it": 1,
+ "vs.it": 1,
+ "vs.mythic-beasts.com": 1,
+ "vt.it": 1,
+ "vt.us": 1,
+ "vv.it": 1,
+ "vxl.sh": 1,
+ "v\u00e1rgg\u00e1t.no": 1,
+ "v\u00e5gan.no": 1,
+ "v\u00e5gs\u00f8y.no": 1,
+ "v\u00e5g\u00e5.no": 1,
+ "v\u00e5ler.hedmark.no": 1,
+ "v\u00e5ler.\u00f8stfold.no": 1,
+ "v\u00e6r\u00f8y.no": 1,
+ "w.bg": 1,
+ "w.se": 1,
+ "wa.au": 1,
+ "wa.edu.au": 1,
+ "wa.gov.au": 1,
+ "wa.us": 1,
+ "wada.nagano.jp": 1,
+ "wafflecell.com": 1,
+ "wajiki.tokushima.jp": 1,
+ "wajima.ishikawa.jp": 1,
+ "wakasa.fukui.jp": 1,
+ "wakasa.tottori.jp": 1,
+ "wakayama.jp": 1,
+ "wakayama.wakayama.jp": 1,
+ "wake.okayama.jp": 1,
+ "wakkanai.hokkaido.jp": 1,
+ "wakuya.miyagi.jp": 1,
+ "walbrzych.pl": 1,
+ "wales.museum": 1,
+ "wallonie.museum": 1,
+ "wanouchi.gifu.jp": 1,
+ "war.museum": 1,
+ "warabi.saitama.jp": 1,
+ "warmia.pl": 1,
+ "warszawa.pl": 1,
+ "washingtondc.museum": 1,
+ "washtenaw.mi.us": 1,
+ "wassamu.hokkaido.jp": 1,
+ "watarai.mie.jp": 1,
+ "watari.miyagi.jp": 1,
+ "watch-and-clock.museum": 1,
+ "watchandclock.museum": 1,
+ "waw.pl": 1,
+ "wazuka.kyoto.jp": 1,
+ "we.bs": 1,
+ "we.tc": 1,
+ "web.app": 1,
+ "web.bo": 1,
+ "web.co": 1,
+ "web.do": 1,
+ "web.gu": 1,
+ "web.id": 1,
+ "web.in": 1,
+ "web.lk": 1,
+ "web.nf": 1,
+ "web.ni": 1,
+ "web.pk": 1,
+ "web.tj": 1,
+ "web.tr": 1,
+ "web.ve": 1,
+ "web.za": 1,
+ "webhare.dev": 2,
+ "webhop.biz": 1,
+ "webhop.info": 1,
+ "webhop.me": 1,
+ "webhop.net": 1,
+ "webhop.org": 1,
+ "webhosting.be": 1,
+ "webredirect.org": 1,
+ "website.yandexcloud.net": 1,
+ "webspace.rocks": 1,
+ "wedeploy.io": 1,
+ "wedeploy.me": 1,
+ "wedeploy.sh": 1,
+ "wegrow.pl": 1,
+ "wellbeingzone.co.uk": 1,
+ "wellbeingzone.eu": 1,
+ "western.museum": 1,
+ "westfalen.museum": 1,
+ "whaling.museum": 1,
+ "wi.us": 1,
+ "wielun.pl": 1,
+ "wien.funkfeuer.at": 1,
+ "wif.gov.pl": 1,
+ "wiih.gov.pl": 1,
+ "wiki.bo": 1,
+ "wiki.br": 1,
+ "wildlife.museum": 1,
+ "williamsburg.museum": 1,
+ "winb.gov.pl": 1,
+ "windmill.museum": 1,
+ "wios.gov.pl": 1,
+ "witd.gov.pl": 1,
+ "withgoogle.com": 1,
+ "withyoutube.com": 1,
+ "wiw.gov.pl": 1,
+ "wlocl.pl": 1,
+ "wloclawek.pl": 1,
+ "wmcloud.org": 1,
+ "wmflabs.org": 1,
+ "wnext.app": 1,
+ "wodzislaw.pl": 1,
+ "wolomin.pl": 1,
+ "workers.dev": 1,
+ "workinggroup.aero": 1,
+ "workisboring.com": 1,
+ "works.aero": 1,
+ "workshop.museum": 1,
+ "worse-than.tv": 1,
+ "wpdevcloud.com": 1,
+ "wpenginepowered.com": 1,
+ "writesthisblog.com": 1,
+ "wroc.pl": 1,
+ "wroclaw.pl": 1,
+ "ws.na": 1,
+ "wsa.gov.pl": 1,
+ "wskr.gov.pl": 1,
+ "wuoz.gov.pl": 1,
+ "wv.us": 1,
+ "www.ck": 0,
+ "www.ro": 1,
+ "wy.us": 1,
+ "wzmiuw.gov.pl": 1,
+ "x.bg": 1,
+ "x.mythic-beasts.com": 1,
+ "x.se": 1,
+ "x443.pw": 1,
+ "xen.prgmr.com": 1,
+ "xenapponazure.com": 1,
+ "xj.cn": 1,
+ "xnbay.com": 1,
+ "xs4all.space": 1,
+ "xx.gl": 1,
+ "xy.ax": 1,
+ "xz.cn": 1,
+ "y.bg": 1,
+ "y.se": 1,
+ "yabu.hyogo.jp": 1,
+ "yabuki.fukushima.jp": 1,
+ "yachimata.chiba.jp": 1,
+ "yachiyo.chiba.jp": 1,
+ "yachiyo.ibaraki.jp": 1,
+ "yaese.okinawa.jp": 1,
+ "yahaba.iwate.jp": 1,
+ "yahiko.niigata.jp": 1,
+ "yaita.tochigi.jp": 1,
+ "yaizu.shizuoka.jp": 1,
+ "yakage.okayama.jp": 1,
+ "yakumo.hokkaido.jp": 1,
+ "yakumo.shimane.jp": 1,
+ "yali.mythic-beasts.com": 1,
+ "yalta.ua": 1,
+ "yamada.fukuoka.jp": 1,
+ "yamada.iwate.jp": 1,
+ "yamada.toyama.jp": 1,
+ "yamaga.kumamoto.jp": 1,
+ "yamagata.gifu.jp": 1,
+ "yamagata.ibaraki.jp": 1,
+ "yamagata.jp": 1,
+ "yamagata.nagano.jp": 1,
+ "yamagata.yamagata.jp": 1,
+ "yamaguchi.jp": 1,
+ "yamakita.kanagawa.jp": 1,
+ "yamamoto.miyagi.jp": 1,
+ "yamanakako.yamanashi.jp": 1,
+ "yamanashi.jp": 1,
+ "yamanashi.yamanashi.jp": 1,
+ "yamanobe.yamagata.jp": 1,
+ "yamanouchi.nagano.jp": 1,
+ "yamashina.kyoto.jp": 1,
+ "yamato.fukushima.jp": 1,
+ "yamato.kanagawa.jp": 1,
+ "yamato.kumamoto.jp": 1,
+ "yamatokoriyama.nara.jp": 1,
+ "yamatotakada.nara.jp": 1,
+ "yamatsuri.fukushima.jp": 1,
+ "yamazoe.nara.jp": 1,
+ "yame.fukuoka.jp": 1,
+ "yanagawa.fukuoka.jp": 1,
+ "yanaizu.fukushima.jp": 1,
+ "yandexcloud.net": 1,
+ "yao.osaka.jp": 1,
+ "yaotsu.gifu.jp": 1,
+ "yasaka.nagano.jp": 1,
+ "yashio.saitama.jp": 1,
+ "yashiro.hyogo.jp": 1,
+ "yasu.shiga.jp": 1,
+ "yasuda.kochi.jp": 1,
+ "yasugi.shimane.jp": 1,
+ "yasuoka.nagano.jp": 1,
+ "yatomi.aichi.jp": 1,
+ "yatsuka.shimane.jp": 1,
+ "yatsushiro.kumamoto.jp": 1,
+ "yawara.ibaraki.jp": 1,
+ "yawata.kyoto.jp": 1,
+ "yawatahama.ehime.jp": 1,
+ "yazu.tottori.jp": 1,
+ "ybo.faith": 1,
+ "ybo.party": 1,
+ "ybo.review": 1,
+ "ybo.science": 1,
+ "ybo.trade": 1,
+ "ye": 2,
+ "yk.ca": 1,
+ "yn.cn": 1,
+ "yoichi.hokkaido.jp": 1,
+ "yoita.niigata.jp": 1,
+ "yoka.hyogo.jp": 1,
+ "yokaichiba.chiba.jp": 1,
+ "yokawa.hyogo.jp": 1,
+ "yokkaichi.mie.jp": 1,
+ "yokohama.jp": 2,
+ "yokoshibahikari.chiba.jp": 1,
+ "yokosuka.kanagawa.jp": 1,
+ "yokote.akita.jp": 1,
+ "yokoze.saitama.jp": 1,
+ "yolasite.com": 1,
+ "yombo.me": 1,
+ "yomitan.okinawa.jp": 1,
+ "yonabaru.okinawa.jp": 1,
+ "yonago.tottori.jp": 1,
+ "yonaguni.okinawa.jp": 1,
+ "yonezawa.yamagata.jp": 1,
+ "yono.saitama.jp": 1,
+ "yorii.saitama.jp": 1,
+ "york.museum": 1,
+ "yorkshire.museum": 1,
+ "yoro.gifu.jp": 1,
+ "yosemite.museum": 1,
+ "yoshida.saitama.jp": 1,
+ "yoshida.shizuoka.jp": 1,
+ "yoshikawa.saitama.jp": 1,
+ "yoshimi.saitama.jp": 1,
+ "yoshino.nara.jp": 1,
+ "yoshinogari.saga.jp": 1,
+ "yoshioka.gunma.jp": 1,
+ "yotsukaido.chiba.jp": 1,
+ "youth.museum": 1,
+ "yuasa.wakayama.jp": 1,
+ "yufu.oita.jp": 1,
+ "yugawa.fukushima.jp": 1,
+ "yugawara.kanagawa.jp": 1,
+ "yuki.ibaraki.jp": 1,
+ "yukuhashi.fukuoka.jp": 1,
+ "yura.wakayama.jp": 1,
+ "yurihonjo.akita.jp": 1,
+ "yusuhara.kochi.jp": 1,
+ "yusui.kagoshima.jp": 1,
+ "yuu.yamaguchi.jp": 1,
+ "yuza.yamagata.jp": 1,
+ "yuzawa.niigata.jp": 1,
+ "z.bg": 1,
+ "z.se": 1,
+ "za.bz": 1,
+ "za.com": 1,
+ "za.net": 1,
+ "za.org": 1,
+ "zachpomor.pl": 1,
+ "zagan.pl": 1,
+ "zakopane.pl": 1,
+ "zama.kanagawa.jp": 1,
+ "zamami.okinawa.jp": 1,
+ "zao.miyagi.jp": 1,
+ "zaporizhzhe.ua": 1,
+ "zaporizhzhia.ua": 1,
+ "zapto.org": 1,
+ "zapto.xyz": 1,
+ "zarow.pl": 1,
+ "zentsuji.kagawa.jp": 1,
+ "zgora.pl": 1,
+ "zgorzelec.pl": 1,
+ "zhitomir.ua": 1,
+ "zhytomyr.ua": 1,
+ "zj.cn": 1,
+ "zlg.br": 1,
+ "zoological.museum": 1,
+ "zoology.museum": 1,
+ "zp.gov.pl": 1,
+ "zp.ua": 1,
+ "zt.ua": 1,
+ "zushi.kanagawa.jp": 1,
+ "\u00e1k\u014boluokta.no": 1,
+ "\u00e1laheadju.no": 1,
+ "\u00e1lt\u00e1.no": 1,
+ "\u00e5fjord.no": 1,
+ "\u00e5krehamn.no": 1,
+ "\u00e5l.no": 1,
+ "\u00e5lesund.no": 1,
+ "\u00e5lg\u00e5rd.no": 1,
+ "\u00e5mli.no": 1,
+ "\u00e5mot.no": 1,
+ "\u00e5rdal.no": 1,
+ "\u00e5s.no": 1,
+ "\u00e5seral.no": 1,
+ "\u00e5snes.no": 1,
+ "\u00f8ksnes.no": 1,
+ "\u00f8rland.no": 1,
+ "\u00f8rskog.no": 1,
+ "\u00f8rsta.no": 1,
+ "\u00f8stre-toten.no": 1,
+ "\u00f8vre-eiker.no": 1,
+ "\u00f8yer.no": 1,
+ "\u00f8ygarden.no": 1,
+ "\u00f8ystre-slidre.no": 1,
+ "\u010d\u00e1hcesuolo.no": 1,
+ "\u0430\u043a.\u0441\u0440\u0431": 1,
+ "\u0438\u043a\u043e\u043c.museum": 1,
+ "\u043e\u0431\u0440.\u0441\u0440\u0431": 1,
+ "\u043e\u0434.\u0441\u0440\u0431": 1,
+ "\u043e\u0440\u0433.\u0441\u0440\u0431": 1,
+ "\u043f\u0440.\u0441\u0440\u0431": 1,
+ "\u0443\u043f\u0440.\u0441\u0440\u0431": 1,
+ "\u05d9\u05e8\u05d5\u05e9\u05dc\u05d9\u05dd.museum": 1,
+ "\u0627\u064a\u0631\u0627\u0646.ir": 1,
+ "\u0627\u06cc\u0631\u0627\u0646.ir": 1,
+ "\u0e17\u0e2b\u0e32\u0e23.\u0e44\u0e17\u0e22": 1,
+ "\u0e18\u0e38\u0e23\u0e01\u0e34\u0e08.\u0e44\u0e17\u0e22": 1,
+ "\u0e23\u0e31\u0e10\u0e1a\u0e32\u0e25.\u0e44\u0e17\u0e22": 1,
+ "\u0e28\u0e36\u0e01\u0e29\u0e32.\u0e44\u0e17\u0e22": 1,
+ "\u0e2d\u0e07\u0e04\u0e4c\u0e01\u0e23.\u0e44\u0e17\u0e22": 1,
+ "\u0e40\u0e19\u0e47\u0e15.\u0e44\u0e17\u0e22": 1,
+ "\u4e09\u91cd.jp": 1,
+ "\u4e2a\u4eba.hk": 1,
+ "\u4eac\u90fd.jp": 1,
+ "\u4f50\u8cc0.jp": 1,
+ "\u500b\u4eba.hk": 1,
+ "\u500b\u4eba.\u9999\u6e2f": 1,
+ "\u516c\u53f8.cn": 1,
+ "\u516c\u53f8.hk": 1,
+ "\u516c\u53f8.\u9999\u6e2f": 1,
+ "\u5175\u5eab.jp": 1,
+ "\u5317\u6d77\u9053.jp": 1,
+ "\u5343\u8449.jp": 1,
+ "\u548c\u6b4c\u5c71.jp": 1,
+ "\u5546\u696d.tw": 1,
+ "\u57fc\u7389.jp": 1,
+ "\u5927\u5206.jp": 1,
+ "\u5927\u962a.jp": 1,
+ "\u5948\u826f.jp": 1,
+ "\u5bae\u57ce.jp": 1,
+ "\u5bae\u5d0e.jp": 1,
+ "\u5bcc\u5c71.jp": 1,
+ "\u5c71\u53e3.jp": 1,
+ "\u5c71\u5f62.jp": 1,
+ "\u5c71\u68a8.jp": 1,
+ "\u5c90\u961c.jp": 1,
+ "\u5ca1\u5c71.jp": 1,
+ "\u5ca9\u624b.jp": 1,
+ "\u5cf6\u6839.jp": 1,
+ "\u5e83\u5cf6.jp": 1,
+ "\u5fb3\u5cf6.jp": 1,
+ "\u611b\u5a9b.jp": 1,
+ "\u611b\u77e5.jp": 1,
+ "\u653f\u5e9c.hk": 1,
+ "\u653f\u5e9c.\u9999\u6e2f": 1,
+ "\u654e\u80b2.hk": 1,
+ "\u6559\u80b2.hk": 1,
+ "\u6559\u80b2.\u9999\u6e2f": 1,
+ "\u65b0\u6f5f.jp": 1,
+ "\u6771\u4eac.jp": 1,
+ "\u6803\u6728.jp": 1,
+ "\u6c96\u7e04.jp": 1,
+ "\u6ecb\u8cc0.jp": 1,
+ "\u718a\u672c.jp": 1,
+ "\u77f3\u5ddd.jp": 1,
+ "\u795e\u5948\u5ddd.jp": 1,
+ "\u798f\u4e95.jp": 1,
+ "\u798f\u5ca1.jp": 1,
+ "\u798f\u5cf6.jp": 1,
+ "\u79cb\u7530.jp": 1,
+ "\u7b87\u4eba.hk": 1,
+ "\u7d44\u7e54.hk": 1,
+ "\u7d44\u7e54.tw": 1,
+ "\u7d44\u7e54.\u9999\u6e2f": 1,
+ "\u7d44\u7ec7.hk": 1,
+ "\u7db2\u7d61.cn": 1,
+ "\u7db2\u7d61.hk": 1,
+ "\u7db2\u7d61.\u9999\u6e2f": 1,
+ "\u7db2\u7edc.hk": 1,
+ "\u7db2\u8def.tw": 1,
+ "\u7ec4\u7e54.hk": 1,
+ "\u7ec4\u7ec7.hk": 1,
+ "\u7f51\u7d61.hk": 1,
+ "\u7f51\u7edc.cn": 1,
+ "\u7f51\u7edc.hk": 1,
+ "\u7fa4\u99ac.jp": 1,
+ "\u8328\u57ce.jp": 1,
+ "\u9577\u5d0e.jp": 1,
+ "\u9577\u91ce.jp": 1,
+ "\u9752\u68ee.jp": 1,
+ "\u9759\u5ca1.jp": 1,
+ "\u9999\u5ddd.jp": 1,
+ "\u9ad8\u77e5.jp": 1,
+ "\u9ce5\u53d6.jp": 1,
+ "\u9e7f\u5150\u5cf6.jp": 1
+};
diff --git a/src/lib/vendor/jquery-3.5.1.js b/src/lib/vendor/jquery-3.5.1.js
new file mode 100644
index 0000000..5093733
--- /dev/null
+++ b/src/lib/vendor/jquery-3.5.1.js
@@ -0,0 +1,10872 @@
+/*!
+ * jQuery JavaScript Library v3.5.1
+ * https://jquery.com/
+ *
+ * Includes Sizzle.js
+ * https://sizzlejs.com/
+ *
+ * Copyright JS Foundation and other contributors
+ * Released under the MIT license
+ * https://jquery.org/license
+ *
+ * Date: 2020-05-04T22:49Z
+ */
+( function( global, factory ) {
+
+ "use strict";
+
+ if ( typeof module === "object" && typeof module.exports === "object" ) {
+
+ // For CommonJS and CommonJS-like environments where a proper `window`
+ // is present, execute the factory and get jQuery.
+ // For environments that do not have a `window` with a `document`
+ // (such as Node.js), expose a factory as module.exports.
+ // This accentuates the need for the creation of a real `window`.
+ // e.g. var jQuery = require("jquery")(window);
+ // See ticket #14549 for more info.
+ module.exports = global.document ?
+ factory( global, true ) :
+ function( w ) {
+ if ( !w.document ) {
+ throw new Error( "jQuery requires a window with a document" );
+ }
+ return factory( w );
+ };
+ } else {
+ factory( global );
+ }
+
+// Pass this if window is not defined yet
+} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
+
+// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
+// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
+// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
+// enough that all such attempts are guarded in a try block.
+"use strict";
+
+var arr = [];
+
+var getProto = Object.getPrototypeOf;
+
+var slice = arr.slice;
+
+var flat = arr.flat ? function( array ) {
+ return arr.flat.call( array );
+} : function( array ) {
+ return arr.concat.apply( [], array );
+};
+
+
+var push = arr.push;
+
+var indexOf = arr.indexOf;
+
+var class2type = {};
+
+var toString = class2type.toString;
+
+var hasOwn = class2type.hasOwnProperty;
+
+var fnToString = hasOwn.toString;
+
+var ObjectFunctionString = fnToString.call( Object );
+
+var support = {};
+
+var isFunction = function isFunction( obj ) {
+
+ // Support: Chrome <=57, Firefox <=52
+ // In some browsers, typeof returns "function" for HTML <object> elements
+ // (i.e., `typeof document.createElement( "object" ) === "function"`).
+ // We don't want to classify *any* DOM node as a function.
+ return typeof obj === "function" && typeof obj.nodeType !== "number";
+ };
+
+
+var isWindow = function isWindow( obj ) {
+ return obj != null && obj === obj.window;
+ };
+
+
+var document = window.document;
+
+
+
+ var preservedScriptAttributes = {
+ type: true,
+ src: true,
+ nonce: true,
+ noModule: true
+ };
+
+ function DOMEval( code, node, doc ) {
+ doc = doc || document;
+
+ var i, val,
+ script = doc.createElement( "script" );
+
+ script.text = code;
+ if ( node ) {
+ for ( i in preservedScriptAttributes ) {
+
+ // Support: Firefox 64+, Edge 18+
+ // Some browsers don't support the "nonce" property on scripts.
+ // On the other hand, just using `getAttribute` is not enough as
+ // the `nonce` attribute is reset to an empty string whenever it
+ // becomes browsing-context connected.
+ // See https://github.com/whatwg/html/issues/2369
+ // See https://html.spec.whatwg.org/#nonce-attributes
+ // The `node.getAttribute` check was added for the sake of
+ // `jQuery.globalEval` so that it can fake a nonce-containing node
+ // via an object.
+ val = node[ i ] || node.getAttribute && node.getAttribute( i );
+ if ( val ) {
+ script.setAttribute( i, val );
+ }
+ }
+ }
+ doc.head.appendChild( script ).parentNode.removeChild( script );
+ }
+
+
+function toType( obj ) {
+ if ( obj == null ) {
+ return obj + "";
+ }
+
+ // Support: Android <=2.3 only (functionish RegExp)
+ return typeof obj === "object" || typeof obj === "function" ?
+ class2type[ toString.call( obj ) ] || "object" :
+ typeof obj;
+}
+/* global Symbol */
+// Defining this global in .eslintrc.json would create a danger of using the global
+// unguarded in another place, it seems safer to define global only for this module
+
+
+
+var
+ version = "3.5.1",
+
+ // Define a local copy of jQuery
+ jQuery = function( selector, context ) {
+
+ // The jQuery object is actually just the init constructor 'enhanced'
+ // Need init if jQuery is called (just allow error to be thrown if not included)
+ return new jQuery.fn.init( selector, context );
+ };
+
+jQuery.fn = jQuery.prototype = {
+
+ // The current version of jQuery being used
+ jquery: version,
+
+ constructor: jQuery,
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ toArray: function() {
+ return slice.call( this );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+
+ // Return all the elements in a clean array
+ if ( num == null ) {
+ return slice.call( this );
+ }
+
+ // Return just the one element from the set
+ return num < 0 ? this[ num + this.length ] : this[ num ];
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems ) {
+
+ // Build a new jQuery matched element set
+ var ret = jQuery.merge( this.constructor(), elems );
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ each: function( callback ) {
+ return jQuery.each( this, callback );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map( this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ } ) );
+ },
+
+ slice: function() {
+ return this.pushStack( slice.apply( this, arguments ) );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ even: function() {
+ return this.pushStack( jQuery.grep( this, function( _elem, i ) {
+ return ( i + 1 ) % 2;
+ } ) );
+ },
+
+ odd: function() {
+ return this.pushStack( jQuery.grep( this, function( _elem, i ) {
+ return i % 2;
+ } ) );
+ },
+
+ eq: function( i ) {
+ var len = this.length,
+ j = +i + ( i < 0 ? len : 0 );
+ return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor();
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: push,
+ sort: arr.sort,
+ splice: arr.splice
+};
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var options, name, src, copy, copyIsArray, clone,
+ target = arguments[ 0 ] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+
+ // Skip the boolean and the target
+ target = arguments[ i ] || {};
+ i++;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !isFunction( target ) ) {
+ target = {};
+ }
+
+ // Extend jQuery itself if only one argument is passed
+ if ( i === length ) {
+ target = this;
+ i--;
+ }
+
+ for ( ; i < length; i++ ) {
+
+ // Only deal with non-null/undefined values
+ if ( ( options = arguments[ i ] ) != null ) {
+
+ // Extend the base object
+ for ( name in options ) {
+ copy = options[ name ];
+
+ // Prevent Object.prototype pollution
+ // Prevent never-ending loop
+ if ( name === "__proto__" || target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
+ ( copyIsArray = Array.isArray( copy ) ) ) ) {
+ src = target[ name ];
+
+ // Ensure proper type for the source value
+ if ( copyIsArray && !Array.isArray( src ) ) {
+ clone = [];
+ } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {
+ clone = {};
+ } else {
+ clone = src;
+ }
+ copyIsArray = false;
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend( {
+
+ // Unique for each copy of jQuery on the page
+ expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
+
+ // Assume jQuery is ready without the ready module
+ isReady: true,
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ noop: function() {},
+
+ isPlainObject: function( obj ) {
+ var proto, Ctor;
+
+ // Detect obvious negatives
+ // Use toString instead of jQuery.type to catch host objects
+ if ( !obj || toString.call( obj ) !== "[object Object]" ) {
+ return false;
+ }
+
+ proto = getProto( obj );
+
+ // Objects with no prototype (e.g., `Object.create( null )`) are plain
+ if ( !proto ) {
+ return true;
+ }
+
+ // Objects with prototype are plain iff they were constructed by a global Object function
+ Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
+ return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
+ },
+
+ isEmptyObject: function( obj ) {
+ var name;
+
+ for ( name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ // Evaluates a script in a provided context; falls back to the global one
+ // if not specified.
+ globalEval: function( code, options, doc ) {
+ DOMEval( code, { nonce: options && options.nonce }, doc );
+ },
+
+ each: function( obj, callback ) {
+ var length, i = 0;
+
+ if ( isArrayLike( obj ) ) {
+ length = obj.length;
+ for ( ; i < length; i++ ) {
+ if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( i in obj ) {
+ if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
+ break;
+ }
+ }
+ }
+
+ return obj;
+ },
+
+ // results is for internal usage only
+ makeArray: function( arr, results ) {
+ var ret = results || [];
+
+ if ( arr != null ) {
+ if ( isArrayLike( Object( arr ) ) ) {
+ jQuery.merge( ret,
+ typeof arr === "string" ?
+ [ arr ] : arr
+ );
+ } else {
+ push.call( ret, arr );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, arr, i ) {
+ return arr == null ? -1 : indexOf.call( arr, elem, i );
+ },
+
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // push.apply(_, arraylike) throws on ancient WebKit
+ merge: function( first, second ) {
+ var len = +second.length,
+ j = 0,
+ i = first.length;
+
+ for ( ; j < len; j++ ) {
+ first[ i++ ] = second[ j ];
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, invert ) {
+ var callbackInverse,
+ matches = [],
+ i = 0,
+ length = elems.length,
+ callbackExpect = !invert;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( ; i < length; i++ ) {
+ callbackInverse = !callback( elems[ i ], i );
+ if ( callbackInverse !== callbackExpect ) {
+ matches.push( elems[ i ] );
+ }
+ }
+
+ return matches;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var length, value,
+ i = 0,
+ ret = [];
+
+ // Go through the array, translating each of the items to their new values
+ if ( isArrayLike( elems ) ) {
+ length = elems.length;
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( i in elems ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret.push( value );
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return flat( ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // jQuery.support is not used in Core but other projects attach their
+ // properties to it so it needs to exist.
+ support: support
+} );
+
+if ( typeof Symbol === "function" ) {
+ jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
+}
+
+// Populate the class2type map
+jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
+function( _i, name ) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+} );
+
+function isArrayLike( obj ) {
+
+ // Support: real iOS 8.2 only (not reproducible in simulator)
+ // `in` check used to prevent JIT error (gh-2145)
+ // hasOwn isn't used here due to false negatives
+ // regarding Nodelist length in IE
+ var length = !!obj && "length" in obj && obj.length,
+ type = toType( obj );
+
+ if ( isFunction( obj ) || isWindow( obj ) ) {
+ return false;
+ }
+
+ return type === "array" || length === 0 ||
+ typeof length === "number" && length > 0 && ( length - 1 ) in obj;
+}
+var Sizzle =
+/*!
+ * Sizzle CSS Selector Engine v2.3.5
+ * https://sizzlejs.com/
+ *
+ * Copyright JS Foundation and other contributors
+ * Released under the MIT license
+ * https://js.foundation/
+ *
+ * Date: 2020-03-14
+ */
+( function( window ) {
+var i,
+ support,
+ Expr,
+ getText,
+ isXML,
+ tokenize,
+ compile,
+ select,
+ outermostContext,
+ sortInput,
+ hasDuplicate,
+
+ // Local document vars
+ setDocument,
+ document,
+ docElem,
+ documentIsHTML,
+ rbuggyQSA,
+ rbuggyMatches,
+ matches,
+ contains,
+
+ // Instance-specific data
+ expando = "sizzle" + 1 * new Date(),
+ preferredDoc = window.document,
+ dirruns = 0,
+ done = 0,
+ classCache = createCache(),
+ tokenCache = createCache(),
+ compilerCache = createCache(),
+ nonnativeSelectorCache = createCache(),
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ }
+ return 0;
+ },
+
+ // Instance methods
+ hasOwn = ( {} ).hasOwnProperty,
+ arr = [],
+ pop = arr.pop,
+ pushNative = arr.push,
+ push = arr.push,
+ slice = arr.slice,
+
+ // Use a stripped-down indexOf as it's faster than native
+ // https://jsperf.com/thor-indexof-vs-for/5
+ indexOf = function( list, elem ) {
+ var i = 0,
+ len = list.length;
+ for ( ; i < len; i++ ) {
+ if ( list[ i ] === elem ) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" +
+ "ismap|loop|multiple|open|readonly|required|scoped",
+
+ // Regular expressions
+
+ // http://www.w3.org/TR/css3-selectors/#whitespace
+ whitespace = "[\\x20\\t\\r\\n\\f]",
+
+ // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram
+ identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace +
+ "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",
+
+ // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
+ attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
+
+ // Operator (capture 2)
+ "*([*^$|!~]?=)" + whitespace +
+
+ // "Attribute values must be CSS identifiers [capture 5]
+ // or strings [capture 3 or capture 4]"
+ "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" +
+ whitespace + "*\\]",
+
+ pseudos = ":(" + identifier + ")(?:\\((" +
+
+ // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
+ // 1. quoted (capture 3; capture 4 or capture 5)
+ "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
+
+ // 2. simple (capture 6)
+ "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
+
+ // 3. anything else (capture 2)
+ ".*" +
+ ")\\)|)",
+
+ // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
+ rwhitespace = new RegExp( whitespace + "+", "g" ),
+ rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" +
+ whitespace + "+$", "g" ),
+
+ rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
+ rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace +
+ "*" ),
+ rdescend = new RegExp( whitespace + "|>" ),
+
+ rpseudo = new RegExp( pseudos ),
+ ridentifier = new RegExp( "^" + identifier + "$" ),
+
+ matchExpr = {
+ "ID": new RegExp( "^#(" + identifier + ")" ),
+ "CLASS": new RegExp( "^\\.(" + identifier + ")" ),
+ "TAG": new RegExp( "^(" + identifier + "|[*])" ),
+ "ATTR": new RegExp( "^" + attributes ),
+ "PSEUDO": new RegExp( "^" + pseudos ),
+ "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" +
+ whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" +
+ whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
+ "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
+
+ // For use in libraries implementing .is()
+ // We use this for POS matching in `select`
+ "needsContext": new RegExp( "^" + whitespace +
+ "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace +
+ "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
+ },
+
+ rhtml = /HTML$/i,
+ rinputs = /^(?:input|select|textarea|button)$/i,
+ rheader = /^h\d$/i,
+
+ rnative = /^[^{]+\{\s*\[native \w/,
+
+ // Easily-parseable/retrievable ID or TAG or CLASS selectors
+ rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
+
+ rsibling = /[+~]/,
+
+ // CSS escapes
+ // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
+ runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ),
+ funescape = function( escape, nonHex ) {
+ var high = "0x" + escape.slice( 1 ) - 0x10000;
+
+ return nonHex ?
+
+ // Strip the backslash prefix from a non-hex escape sequence
+ nonHex :
+
+ // Replace a hexadecimal escape sequence with the encoded Unicode code point
+ // Support: IE <=11+
+ // For values outside the Basic Multilingual Plane (BMP), manually construct a
+ // surrogate pair
+ high < 0 ?
+ String.fromCharCode( high + 0x10000 ) :
+ String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
+ },
+
+ // CSS string/identifier serialization
+ // https://drafts.csswg.org/cssom/#common-serializing-idioms
+ rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,
+ fcssescape = function( ch, asCodePoint ) {
+ if ( asCodePoint ) {
+
+ // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
+ if ( ch === "\0" ) {
+ return "\uFFFD";
+ }
+
+ // Control characters and (dependent upon position) numbers get escaped as code points
+ return ch.slice( 0, -1 ) + "\\" +
+ ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
+ }
+
+ // Other potentially-special ASCII characters get backslash-escaped
+ return "\\" + ch;
+ },
+
+ // Used for iframes
+ // See setDocument()
+ // Removing the function wrapper causes a "Permission Denied"
+ // error in IE
+ unloadHandler = function() {
+ setDocument();
+ },
+
+ inDisabledFieldset = addCombinator(
+ function( elem ) {
+ return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset";
+ },
+ { dir: "parentNode", next: "legend" }
+ );
+
+// Optimize for push.apply( _, NodeList )
+try {
+ push.apply(
+ ( arr = slice.call( preferredDoc.childNodes ) ),
+ preferredDoc.childNodes
+ );
+
+ // Support: Android<4.0
+ // Detect silently failing push.apply
+ // eslint-disable-next-line no-unused-expressions
+ arr[ preferredDoc.childNodes.length ].nodeType;
+} catch ( e ) {
+ push = { apply: arr.length ?
+
+ // Leverage slice if possible
+ function( target, els ) {
+ pushNative.apply( target, slice.call( els ) );
+ } :
+
+ // Support: IE<9
+ // Otherwise append directly
+ function( target, els ) {
+ var j = target.length,
+ i = 0;
+
+ // Can't trust NodeList.length
+ while ( ( target[ j++ ] = els[ i++ ] ) ) {}
+ target.length = j - 1;
+ }
+ };
+}
+
+function Sizzle( selector, context, results, seed ) {
+ var m, i, elem, nid, match, groups, newSelector,
+ newContext = context && context.ownerDocument,
+
+ // nodeType defaults to 9, since context defaults to document
+ nodeType = context ? context.nodeType : 9;
+
+ results = results || [];
+
+ // Return early from calls with invalid selector or context
+ if ( typeof selector !== "string" || !selector ||
+ nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
+
+ return results;
+ }
+
+ // Try to shortcut find operations (as opposed to filters) in HTML documents
+ if ( !seed ) {
+ setDocument( context );
+ context = context || document;
+
+ if ( documentIsHTML ) {
+
+ // If the selector is sufficiently simple, try using a "get*By*" DOM method
+ // (excepting DocumentFragment context, where the methods don't exist)
+ if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) {
+
+ // ID selector
+ if ( ( m = match[ 1 ] ) ) {
+
+ // Document context
+ if ( nodeType === 9 ) {
+ if ( ( elem = context.getElementById( m ) ) ) {
+
+ // Support: IE, Opera, Webkit
+ // TODO: identify versions
+ // getElementById can match elements by name instead of ID
+ if ( elem.id === m ) {
+ results.push( elem );
+ return results;
+ }
+ } else {
+ return results;
+ }
+
+ // Element context
+ } else {
+
+ // Support: IE, Opera, Webkit
+ // TODO: identify versions
+ // getElementById can match elements by name instead of ID
+ if ( newContext && ( elem = newContext.getElementById( m ) ) &&
+ contains( context, elem ) &&
+ elem.id === m ) {
+
+ results.push( elem );
+ return results;
+ }
+ }
+
+ // Type selector
+ } else if ( match[ 2 ] ) {
+ push.apply( results, context.getElementsByTagName( selector ) );
+ return results;
+
+ // Class selector
+ } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName &&
+ context.getElementsByClassName ) {
+
+ push.apply( results, context.getElementsByClassName( m ) );
+ return results;
+ }
+ }
+
+ // Take advantage of querySelectorAll
+ if ( support.qsa &&
+ !nonnativeSelectorCache[ selector + " " ] &&
+ ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) &&
+
+ // Support: IE 8 only
+ // Exclude object elements
+ ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) {
+
+ newSelector = selector;
+ newContext = context;
+
+ // qSA considers elements outside a scoping root when evaluating child or
+ // descendant combinators, which is not what we want.
+ // In such cases, we work around the behavior by prefixing every selector in the
+ // list with an ID selector referencing the scope context.
+ // The technique has to be used as well when a leading combinator is used
+ // as such selectors are not recognized by querySelectorAll.
+ // Thanks to Andrew Dupont for this technique.
+ if ( nodeType === 1 &&
+ ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) {
+
+ // Expand context for sibling selectors
+ newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
+ context;
+
+ // We can use :scope instead of the ID hack if the browser
+ // supports it & if we're not changing the context.
+ if ( newContext !== context || !support.scope ) {
+
+ // Capture the context ID, setting it first if necessary
+ if ( ( nid = context.getAttribute( "id" ) ) ) {
+ nid = nid.replace( rcssescape, fcssescape );
+ } else {
+ context.setAttribute( "id", ( nid = expando ) );
+ }
+ }
+
+ // Prefix every selector in the list
+ groups = tokenize( selector );
+ i = groups.length;
+ while ( i-- ) {
+ groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " +
+ toSelector( groups[ i ] );
+ }
+ newSelector = groups.join( "," );
+ }
+
+ try {
+ push.apply( results,
+ newContext.querySelectorAll( newSelector )
+ );
+ return results;
+ } catch ( qsaError ) {
+ nonnativeSelectorCache( selector, true );
+ } finally {
+ if ( nid === expando ) {
+ context.removeAttribute( "id" );
+ }
+ }
+ }
+ }
+ }
+
+ // All others
+ return select( selector.replace( rtrim, "$1" ), context, results, seed );
+}
+
+/**
+ * Create key-value caches of limited size
+ * @returns {function(string, object)} Returns the Object data after storing it on itself with
+ * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
+ * deleting the oldest entry
+ */
+function createCache() {
+ var keys = [];
+
+ function cache( key, value ) {
+
+ // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
+ if ( keys.push( key + " " ) > Expr.cacheLength ) {
+
+ // Only keep the most recent entries
+ delete cache[ keys.shift() ];
+ }
+ return ( cache[ key + " " ] = value );
+ }
+ return cache;
+}
+
+/**
+ * Mark a function for special use by Sizzle
+ * @param {Function} fn The function to mark
+ */
+function markFunction( fn ) {
+ fn[ expando ] = true;
+ return fn;
+}
+
+/**
+ * Support testing using an element
+ * @param {Function} fn Passed the created element and returns a boolean result
+ */
+function assert( fn ) {
+ var el = document.createElement( "fieldset" );
+
+ try {
+ return !!fn( el );
+ } catch ( e ) {
+ return false;
+ } finally {
+
+ // Remove from its parent by default
+ if ( el.parentNode ) {
+ el.parentNode.removeChild( el );
+ }
+
+ // release memory in IE
+ el = null;
+ }
+}
+
+/**
+ * Adds the same handler for all of the specified attrs
+ * @param {String} attrs Pipe-separated list of attributes
+ * @param {Function} handler The method that will be applied
+ */
+function addHandle( attrs, handler ) {
+ var arr = attrs.split( "|" ),
+ i = arr.length;
+
+ while ( i-- ) {
+ Expr.attrHandle[ arr[ i ] ] = handler;
+ }
+}
+
+/**
+ * Checks document order of two siblings
+ * @param {Element} a
+ * @param {Element} b
+ * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
+ */
+function siblingCheck( a, b ) {
+ var cur = b && a,
+ diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
+ a.sourceIndex - b.sourceIndex;
+
+ // Use IE sourceIndex if available on both nodes
+ if ( diff ) {
+ return diff;
+ }
+
+ // Check if b follows a
+ if ( cur ) {
+ while ( ( cur = cur.nextSibling ) ) {
+ if ( cur === b ) {
+ return -1;
+ }
+ }
+ }
+
+ return a ? 1 : -1;
+}
+
+/**
+ * Returns a function to use in pseudos for input types
+ * @param {String} type
+ */
+function createInputPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for buttons
+ * @param {String} type
+ */
+function createButtonPseudo( type ) {
+ return function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return ( name === "input" || name === "button" ) && elem.type === type;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for :enabled/:disabled
+ * @param {Boolean} disabled true for :disabled; false for :enabled
+ */
+function createDisabledPseudo( disabled ) {
+
+ // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
+ return function( elem ) {
+
+ // Only certain elements can match :enabled or :disabled
+ // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
+ // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
+ if ( "form" in elem ) {
+
+ // Check for inherited disabledness on relevant non-disabled elements:
+ // * listed form-associated elements in a disabled fieldset
+ // https://html.spec.whatwg.org/multipage/forms.html#category-listed
+ // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
+ // * option elements in a disabled optgroup
+ // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
+ // All such elements have a "form" property.
+ if ( elem.parentNode && elem.disabled === false ) {
+
+ // Option elements defer to a parent optgroup if present
+ if ( "label" in elem ) {
+ if ( "label" in elem.parentNode ) {
+ return elem.parentNode.disabled === disabled;
+ } else {
+ return elem.disabled === disabled;
+ }
+ }
+
+ // Support: IE 6 - 11
+ // Use the isDisabled shortcut property to check for disabled fieldset ancestors
+ return elem.isDisabled === disabled ||
+
+ // Where there is no isDisabled, check manually
+ /* jshint -W018 */
+ elem.isDisabled !== !disabled &&
+ inDisabledFieldset( elem ) === disabled;
+ }
+
+ return elem.disabled === disabled;
+
+ // Try to winnow out elements that can't be disabled before trusting the disabled property.
+ // Some victims get caught in our net (label, legend, menu, track), but it shouldn't
+ // even exist on them, let alone have a boolean value.
+ } else if ( "label" in elem ) {
+ return elem.disabled === disabled;
+ }
+
+ // Remaining elements are neither :enabled nor :disabled
+ return false;
+ };
+}
+
+/**
+ * Returns a function to use in pseudos for positionals
+ * @param {Function} fn
+ */
+function createPositionalPseudo( fn ) {
+ return markFunction( function( argument ) {
+ argument = +argument;
+ return markFunction( function( seed, matches ) {
+ var j,
+ matchIndexes = fn( [], seed.length, argument ),
+ i = matchIndexes.length;
+
+ // Match elements found at the specified indexes
+ while ( i-- ) {
+ if ( seed[ ( j = matchIndexes[ i ] ) ] ) {
+ seed[ j ] = !( matches[ j ] = seed[ j ] );
+ }
+ }
+ } );
+ } );
+}
+
+/**
+ * Checks a node for validity as a Sizzle context
+ * @param {Element|Object=} context
+ * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
+ */
+function testContext( context ) {
+ return context && typeof context.getElementsByTagName !== "undefined" && context;
+}
+
+// Expose support vars for convenience
+support = Sizzle.support = {};
+
+/**
+ * Detects XML nodes
+ * @param {Element|Object} elem An element or a document
+ * @returns {Boolean} True iff elem is a non-HTML XML node
+ */
+isXML = Sizzle.isXML = function( elem ) {
+ var namespace = elem.namespaceURI,
+ docElem = ( elem.ownerDocument || elem ).documentElement;
+
+ // Support: IE <=8
+ // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes
+ // https://bugs.jquery.com/ticket/4833
+ return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" );
+};
+
+/**
+ * Sets document-related variables once based on the current document
+ * @param {Element|Object} [doc] An element or document object to use to set the document
+ * @returns {Object} Returns the current document
+ */
+setDocument = Sizzle.setDocument = function( node ) {
+ var hasCompare, subWindow,
+ doc = node ? node.ownerDocument || node : preferredDoc;
+
+ // Return early if doc is invalid or already selected
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) {
+ return document;
+ }
+
+ // Update global variables
+ document = doc;
+ docElem = document.documentElement;
+ documentIsHTML = !isXML( document );
+
+ // Support: IE 9 - 11+, Edge 12 - 18+
+ // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( preferredDoc != document &&
+ ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) {
+
+ // Support: IE 11, Edge
+ if ( subWindow.addEventListener ) {
+ subWindow.addEventListener( "unload", unloadHandler, false );
+
+ // Support: IE 9 - 10 only
+ } else if ( subWindow.attachEvent ) {
+ subWindow.attachEvent( "onunload", unloadHandler );
+ }
+ }
+
+ // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only,
+ // Safari 4 - 5 only, Opera <=11.6 - 12.x only
+ // IE/Edge & older browsers don't support the :scope pseudo-class.
+ // Support: Safari 6.0 only
+ // Safari 6.0 supports :scope but it's an alias of :root there.
+ support.scope = assert( function( el ) {
+ docElem.appendChild( el ).appendChild( document.createElement( "div" ) );
+ return typeof el.querySelectorAll !== "undefined" &&
+ !el.querySelectorAll( ":scope fieldset div" ).length;
+ } );
+
+ /* Attributes
+ ---------------------------------------------------------------------- */
+
+ // Support: IE<8
+ // Verify that getAttribute really returns attributes and not properties
+ // (excepting IE8 booleans)
+ support.attributes = assert( function( el ) {
+ el.className = "i";
+ return !el.getAttribute( "className" );
+ } );
+
+ /* getElement(s)By*
+ ---------------------------------------------------------------------- */
+
+ // Check if getElementsByTagName("*") returns only elements
+ support.getElementsByTagName = assert( function( el ) {
+ el.appendChild( document.createComment( "" ) );
+ return !el.getElementsByTagName( "*" ).length;
+ } );
+
+ // Support: IE<9
+ support.getElementsByClassName = rnative.test( document.getElementsByClassName );
+
+ // Support: IE<10
+ // Check if getElementById returns elements by name
+ // The broken getElementById methods don't pick up programmatically-set names,
+ // so use a roundabout getElementsByName test
+ support.getById = assert( function( el ) {
+ docElem.appendChild( el ).id = expando;
+ return !document.getElementsByName || !document.getElementsByName( expando ).length;
+ } );
+
+ // ID filter and find
+ if ( support.getById ) {
+ Expr.filter[ "ID" ] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ return elem.getAttribute( "id" ) === attrId;
+ };
+ };
+ Expr.find[ "ID" ] = function( id, context ) {
+ if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
+ var elem = context.getElementById( id );
+ return elem ? [ elem ] : [];
+ }
+ };
+ } else {
+ Expr.filter[ "ID" ] = function( id ) {
+ var attrId = id.replace( runescape, funescape );
+ return function( elem ) {
+ var node = typeof elem.getAttributeNode !== "undefined" &&
+ elem.getAttributeNode( "id" );
+ return node && node.value === attrId;
+ };
+ };
+
+ // Support: IE 6 - 7 only
+ // getElementById is not reliable as a find shortcut
+ Expr.find[ "ID" ] = function( id, context ) {
+ if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
+ var node, i, elems,
+ elem = context.getElementById( id );
+
+ if ( elem ) {
+
+ // Verify the id attribute
+ node = elem.getAttributeNode( "id" );
+ if ( node && node.value === id ) {
+ return [ elem ];
+ }
+
+ // Fall back on getElementsByName
+ elems = context.getElementsByName( id );
+ i = 0;
+ while ( ( elem = elems[ i++ ] ) ) {
+ node = elem.getAttributeNode( "id" );
+ if ( node && node.value === id ) {
+ return [ elem ];
+ }
+ }
+ }
+
+ return [];
+ }
+ };
+ }
+
+ // Tag
+ Expr.find[ "TAG" ] = support.getElementsByTagName ?
+ function( tag, context ) {
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
+ return context.getElementsByTagName( tag );
+
+ // DocumentFragment nodes don't have gEBTN
+ } else if ( support.qsa ) {
+ return context.querySelectorAll( tag );
+ }
+ } :
+
+ function( tag, context ) {
+ var elem,
+ tmp = [],
+ i = 0,
+
+ // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
+ results = context.getElementsByTagName( tag );
+
+ // Filter out possible comments
+ if ( tag === "*" ) {
+ while ( ( elem = results[ i++ ] ) ) {
+ if ( elem.nodeType === 1 ) {
+ tmp.push( elem );
+ }
+ }
+
+ return tmp;
+ }
+ return results;
+ };
+
+ // Class
+ Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) {
+ if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
+ return context.getElementsByClassName( className );
+ }
+ };
+
+ /* QSA/matchesSelector
+ ---------------------------------------------------------------------- */
+
+ // QSA and matchesSelector support
+
+ // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
+ rbuggyMatches = [];
+
+ // qSa(:focus) reports false when true (Chrome 21)
+ // We allow this because of a bug in IE8/9 that throws an error
+ // whenever `document.activeElement` is accessed on an iframe
+ // So, we allow :focus to pass through QSA all the time to avoid the IE error
+ // See https://bugs.jquery.com/ticket/13378
+ rbuggyQSA = [];
+
+ if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) {
+
+ // Build QSA regex
+ // Regex strategy adopted from Diego Perini
+ assert( function( el ) {
+
+ var input;
+
+ // Select is set to empty string on purpose
+ // This is to test IE's treatment of not explicitly
+ // setting a boolean content attribute,
+ // since its presence should be enough
+ // https://bugs.jquery.com/ticket/12359
+ docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" +
+ "<select id='" + expando + "-\r\\' msallowcapture=''>" +
+ "<option selected=''></option></select>";
+
+ // Support: IE8, Opera 11-12.16
+ // Nothing should be selected when empty strings follow ^= or $= or *=
+ // The test attribute must be unknown in Opera but "safe" for WinRT
+ // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
+ if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) {
+ rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
+ }
+
+ // Support: IE8
+ // Boolean attributes and "value" are not treated correctly
+ if ( !el.querySelectorAll( "[selected]" ).length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
+ }
+
+ // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
+ if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
+ rbuggyQSA.push( "~=" );
+ }
+
+ // Support: IE 11+, Edge 15 - 18+
+ // IE 11/Edge don't find elements on a `[name='']` query in some cases.
+ // Adding a temporary attribute to the document before the selection works
+ // around the issue.
+ // Interestingly, IE 10 & older don't seem to have the issue.
+ input = document.createElement( "input" );
+ input.setAttribute( "name", "" );
+ el.appendChild( input );
+ if ( !el.querySelectorAll( "[name='']" ).length ) {
+ rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" +
+ whitespace + "*(?:''|\"\")" );
+ }
+
+ // Webkit/Opera - :checked should return selected option elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ // IE8 throws error here and will not see later tests
+ if ( !el.querySelectorAll( ":checked" ).length ) {
+ rbuggyQSA.push( ":checked" );
+ }
+
+ // Support: Safari 8+, iOS 8+
+ // https://bugs.webkit.org/show_bug.cgi?id=136851
+ // In-page `selector#id sibling-combinator selector` fails
+ if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
+ rbuggyQSA.push( ".#.+[+~]" );
+ }
+
+ // Support: Firefox <=3.6 - 5 only
+ // Old Firefox doesn't throw on a badly-escaped identifier.
+ el.querySelectorAll( "\\\f" );
+ rbuggyQSA.push( "[\\r\\n\\f]" );
+ } );
+
+ assert( function( el ) {
+ el.innerHTML = "<a href='' disabled='disabled'></a>" +
+ "<select disabled='disabled'><option/></select>";
+
+ // Support: Windows 8 Native Apps
+ // The type and name attributes are restricted during .innerHTML assignment
+ var input = document.createElement( "input" );
+ input.setAttribute( "type", "hidden" );
+ el.appendChild( input ).setAttribute( "name", "D" );
+
+ // Support: IE8
+ // Enforce case-sensitivity of name attribute
+ if ( el.querySelectorAll( "[name=d]" ).length ) {
+ rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
+ }
+
+ // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
+ // IE8 throws error here and will not see later tests
+ if ( el.querySelectorAll( ":enabled" ).length !== 2 ) {
+ rbuggyQSA.push( ":enabled", ":disabled" );
+ }
+
+ // Support: IE9-11+
+ // IE's :disabled selector does not pick up the children of disabled fieldsets
+ docElem.appendChild( el ).disabled = true;
+ if ( el.querySelectorAll( ":disabled" ).length !== 2 ) {
+ rbuggyQSA.push( ":enabled", ":disabled" );
+ }
+
+ // Support: Opera 10 - 11 only
+ // Opera 10-11 does not throw on post-comma invalid pseudos
+ el.querySelectorAll( "*,:x" );
+ rbuggyQSA.push( ",.*:" );
+ } );
+ }
+
+ if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches ||
+ docElem.webkitMatchesSelector ||
+ docElem.mozMatchesSelector ||
+ docElem.oMatchesSelector ||
+ docElem.msMatchesSelector ) ) ) ) {
+
+ assert( function( el ) {
+
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9)
+ support.disconnectedMatch = matches.call( el, "*" );
+
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( el, "[s!='']:x" );
+ rbuggyMatches.push( "!=", pseudos );
+ } );
+ }
+
+ rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) );
+ rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) );
+
+ /* Contains
+ ---------------------------------------------------------------------- */
+ hasCompare = rnative.test( docElem.compareDocumentPosition );
+
+ // Element contains another
+ // Purposefully self-exclusive
+ // As in, an element does not contain itself
+ contains = hasCompare || rnative.test( docElem.contains ) ?
+ function( a, b ) {
+ var adown = a.nodeType === 9 ? a.documentElement : a,
+ bup = b && b.parentNode;
+ return a === bup || !!( bup && bup.nodeType === 1 && (
+ adown.contains ?
+ adown.contains( bup ) :
+ a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
+ ) );
+ } :
+ function( a, b ) {
+ if ( b ) {
+ while ( ( b = b.parentNode ) ) {
+ if ( b === a ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ };
+
+ /* Sorting
+ ---------------------------------------------------------------------- */
+
+ // Document order sorting
+ sortOrder = hasCompare ?
+ function( a, b ) {
+
+ // Flag for duplicate removal
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ // Sort on method existence if only one input has compareDocumentPosition
+ var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
+ if ( compare ) {
+ return compare;
+ }
+
+ // Calculate position if both inputs belong to the same document
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ?
+ a.compareDocumentPosition( b ) :
+
+ // Otherwise we know they are disconnected
+ 1;
+
+ // Disconnected nodes
+ if ( compare & 1 ||
+ ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) {
+
+ // Choose the first element that is related to our preferred document
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( a == document || a.ownerDocument == preferredDoc &&
+ contains( preferredDoc, a ) ) {
+ return -1;
+ }
+
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( b == document || b.ownerDocument == preferredDoc &&
+ contains( preferredDoc, b ) ) {
+ return 1;
+ }
+
+ // Maintain original order
+ return sortInput ?
+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+ 0;
+ }
+
+ return compare & 4 ? -1 : 1;
+ } :
+ function( a, b ) {
+
+ // Exit early if the nodes are identical
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ var cur,
+ i = 0,
+ aup = a.parentNode,
+ bup = b.parentNode,
+ ap = [ a ],
+ bp = [ b ];
+
+ // Parentless nodes are either documents or disconnected
+ if ( !aup || !bup ) {
+
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ /* eslint-disable eqeqeq */
+ return a == document ? -1 :
+ b == document ? 1 :
+ /* eslint-enable eqeqeq */
+ aup ? -1 :
+ bup ? 1 :
+ sortInput ?
+ ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
+ 0;
+
+ // If the nodes are siblings, we can do a quick check
+ } else if ( aup === bup ) {
+ return siblingCheck( a, b );
+ }
+
+ // Otherwise we need full lists of their ancestors for comparison
+ cur = a;
+ while ( ( cur = cur.parentNode ) ) {
+ ap.unshift( cur );
+ }
+ cur = b;
+ while ( ( cur = cur.parentNode ) ) {
+ bp.unshift( cur );
+ }
+
+ // Walk down the tree looking for a discrepancy
+ while ( ap[ i ] === bp[ i ] ) {
+ i++;
+ }
+
+ return i ?
+
+ // Do a sibling check if the nodes have a common ancestor
+ siblingCheck( ap[ i ], bp[ i ] ) :
+
+ // Otherwise nodes in our document sort first
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ /* eslint-disable eqeqeq */
+ ap[ i ] == preferredDoc ? -1 :
+ bp[ i ] == preferredDoc ? 1 :
+ /* eslint-enable eqeqeq */
+ 0;
+ };
+
+ return document;
+};
+
+Sizzle.matches = function( expr, elements ) {
+ return Sizzle( expr, null, null, elements );
+};
+
+Sizzle.matchesSelector = function( elem, expr ) {
+ setDocument( elem );
+
+ if ( support.matchesSelector && documentIsHTML &&
+ !nonnativeSelectorCache[ expr + " " ] &&
+ ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
+ ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
+
+ try {
+ var ret = matches.call( elem, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || support.disconnectedMatch ||
+
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9
+ elem.document && elem.document.nodeType !== 11 ) {
+ return ret;
+ }
+ } catch ( e ) {
+ nonnativeSelectorCache( expr, true );
+ }
+ }
+
+ return Sizzle( expr, document, null, [ elem ] ).length > 0;
+};
+
+Sizzle.contains = function( context, elem ) {
+
+ // Set document vars if needed
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( ( context.ownerDocument || context ) != document ) {
+ setDocument( context );
+ }
+ return contains( context, elem );
+};
+
+Sizzle.attr = function( elem, name ) {
+
+ // Set document vars if needed
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( ( elem.ownerDocument || elem ) != document ) {
+ setDocument( elem );
+ }
+
+ var fn = Expr.attrHandle[ name.toLowerCase() ],
+
+ // Don't get fooled by Object.prototype properties (jQuery #13807)
+ val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
+ fn( elem, name, !documentIsHTML ) :
+ undefined;
+
+ return val !== undefined ?
+ val :
+ support.attributes || !documentIsHTML ?
+ elem.getAttribute( name ) :
+ ( val = elem.getAttributeNode( name ) ) && val.specified ?
+ val.value :
+ null;
+};
+
+Sizzle.escape = function( sel ) {
+ return ( sel + "" ).replace( rcssescape, fcssescape );
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Document sorting and removing duplicates
+ * @param {ArrayLike} results
+ */
+Sizzle.uniqueSort = function( results ) {
+ var elem,
+ duplicates = [],
+ j = 0,
+ i = 0;
+
+ // Unless we *know* we can detect duplicates, assume their presence
+ hasDuplicate = !support.detectDuplicates;
+ sortInput = !support.sortStable && results.slice( 0 );
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ while ( ( elem = results[ i++ ] ) ) {
+ if ( elem === results[ i ] ) {
+ j = duplicates.push( i );
+ }
+ }
+ while ( j-- ) {
+ results.splice( duplicates[ j ], 1 );
+ }
+ }
+
+ // Clear input after sorting to release objects
+ // See https://github.com/jquery/sizzle/pull/225
+ sortInput = null;
+
+ return results;
+};
+
+/**
+ * Utility function for retrieving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+getText = Sizzle.getText = function( elem ) {
+ var node,
+ ret = "",
+ i = 0,
+ nodeType = elem.nodeType;
+
+ if ( !nodeType ) {
+
+ // If no nodeType, this is expected to be an array
+ while ( ( node = elem[ i++ ] ) ) {
+
+ // Do not traverse comment nodes
+ ret += getText( node );
+ }
+ } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+
+ // Use textContent for elements
+ // innerText usage removed for consistency of new lines (jQuery #11153)
+ if ( typeof elem.textContent === "string" ) {
+ return elem.textContent;
+ } else {
+
+ // Traverse its children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+
+ // Do not include comment or processing instruction nodes
+
+ return ret;
+};
+
+Expr = Sizzle.selectors = {
+
+ // Can be adjusted by the user
+ cacheLength: 50,
+
+ createPseudo: markFunction,
+
+ match: matchExpr,
+
+ attrHandle: {},
+
+ find: {},
+
+ relative: {
+ ">": { dir: "parentNode", first: true },
+ " ": { dir: "parentNode" },
+ "+": { dir: "previousSibling", first: true },
+ "~": { dir: "previousSibling" }
+ },
+
+ preFilter: {
+ "ATTR": function( match ) {
+ match[ 1 ] = match[ 1 ].replace( runescape, funescape );
+
+ // Move the given value to match[3] whether quoted or unquoted
+ match[ 3 ] = ( match[ 3 ] || match[ 4 ] ||
+ match[ 5 ] || "" ).replace( runescape, funescape );
+
+ if ( match[ 2 ] === "~=" ) {
+ match[ 3 ] = " " + match[ 3 ] + " ";
+ }
+
+ return match.slice( 0, 4 );
+ },
+
+ "CHILD": function( match ) {
+
+ /* matches from matchExpr["CHILD"]
+ 1 type (only|nth|...)
+ 2 what (child|of-type)
+ 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
+ 4 xn-component of xn+y argument ([+-]?\d*n|)
+ 5 sign of xn-component
+ 6 x of xn-component
+ 7 sign of y-component
+ 8 y of y-component
+ */
+ match[ 1 ] = match[ 1 ].toLowerCase();
+
+ if ( match[ 1 ].slice( 0, 3 ) === "nth" ) {
+
+ // nth-* requires argument
+ if ( !match[ 3 ] ) {
+ Sizzle.error( match[ 0 ] );
+ }
+
+ // numeric x and y parameters for Expr.filter.CHILD
+ // remember that false/true cast respectively to 0/1
+ match[ 4 ] = +( match[ 4 ] ?
+ match[ 5 ] + ( match[ 6 ] || 1 ) :
+ 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) );
+ match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" );
+
+ // other types prohibit arguments
+ } else if ( match[ 3 ] ) {
+ Sizzle.error( match[ 0 ] );
+ }
+
+ return match;
+ },
+
+ "PSEUDO": function( match ) {
+ var excess,
+ unquoted = !match[ 6 ] && match[ 2 ];
+
+ if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) {
+ return null;
+ }
+
+ // Accept quoted arguments as-is
+ if ( match[ 3 ] ) {
+ match[ 2 ] = match[ 4 ] || match[ 5 ] || "";
+
+ // Strip excess characters from unquoted arguments
+ } else if ( unquoted && rpseudo.test( unquoted ) &&
+
+ // Get excess from tokenize (recursively)
+ ( excess = tokenize( unquoted, true ) ) &&
+
+ // advance to the next closing parenthesis
+ ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) {
+
+ // excess is a negative index
+ match[ 0 ] = match[ 0 ].slice( 0, excess );
+ match[ 2 ] = unquoted.slice( 0, excess );
+ }
+
+ // Return only captures needed by the pseudo filter method (type and argument)
+ return match.slice( 0, 3 );
+ }
+ },
+
+ filter: {
+
+ "TAG": function( nodeNameSelector ) {
+ var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
+ return nodeNameSelector === "*" ?
+ function() {
+ return true;
+ } :
+ function( elem ) {
+ return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
+ };
+ },
+
+ "CLASS": function( className ) {
+ var pattern = classCache[ className + " " ];
+
+ return pattern ||
+ ( pattern = new RegExp( "(^|" + whitespace +
+ ")" + className + "(" + whitespace + "|$)" ) ) && classCache(
+ className, function( elem ) {
+ return pattern.test(
+ typeof elem.className === "string" && elem.className ||
+ typeof elem.getAttribute !== "undefined" &&
+ elem.getAttribute( "class" ) ||
+ ""
+ );
+ } );
+ },
+
+ "ATTR": function( name, operator, check ) {
+ return function( elem ) {
+ var result = Sizzle.attr( elem, name );
+
+ if ( result == null ) {
+ return operator === "!=";
+ }
+ if ( !operator ) {
+ return true;
+ }
+
+ result += "";
+
+ /* eslint-disable max-len */
+
+ return operator === "=" ? result === check :
+ operator === "!=" ? result !== check :
+ operator === "^=" ? check && result.indexOf( check ) === 0 :
+ operator === "*=" ? check && result.indexOf( check ) > -1 :
+ operator === "$=" ? check && result.slice( -check.length ) === check :
+ operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
+ operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
+ false;
+ /* eslint-enable max-len */
+
+ };
+ },
+
+ "CHILD": function( type, what, _argument, first, last ) {
+ var simple = type.slice( 0, 3 ) !== "nth",
+ forward = type.slice( -4 ) !== "last",
+ ofType = what === "of-type";
+
+ return first === 1 && last === 0 ?
+
+ // Shortcut for :nth-*(n)
+ function( elem ) {
+ return !!elem.parentNode;
+ } :
+
+ function( elem, _context, xml ) {
+ var cache, uniqueCache, outerCache, node, nodeIndex, start,
+ dir = simple !== forward ? "nextSibling" : "previousSibling",
+ parent = elem.parentNode,
+ name = ofType && elem.nodeName.toLowerCase(),
+ useCache = !xml && !ofType,
+ diff = false;
+
+ if ( parent ) {
+
+ // :(first|last|only)-(child|of-type)
+ if ( simple ) {
+ while ( dir ) {
+ node = elem;
+ while ( ( node = node[ dir ] ) ) {
+ if ( ofType ?
+ node.nodeName.toLowerCase() === name :
+ node.nodeType === 1 ) {
+
+ return false;
+ }
+ }
+
+ // Reverse direction for :only-* (if we haven't yet done so)
+ start = dir = type === "only" && !start && "nextSibling";
+ }
+ return true;
+ }
+
+ start = [ forward ? parent.firstChild : parent.lastChild ];
+
+ // non-xml :nth-child(...) stores cache data on `parent`
+ if ( forward && useCache ) {
+
+ // Seek `elem` from a previously-cached index
+
+ // ...in a gzip-friendly way
+ node = parent;
+ outerCache = node[ expando ] || ( node[ expando ] = {} );
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ node.uniqueID ] ||
+ ( outerCache[ node.uniqueID ] = {} );
+
+ cache = uniqueCache[ type ] || [];
+ nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
+ diff = nodeIndex && cache[ 2 ];
+ node = nodeIndex && parent.childNodes[ nodeIndex ];
+
+ while ( ( node = ++nodeIndex && node && node[ dir ] ||
+
+ // Fallback to seeking `elem` from the start
+ ( diff = nodeIndex = 0 ) || start.pop() ) ) {
+
+ // When found, cache indexes on `parent` and break
+ if ( node.nodeType === 1 && ++diff && node === elem ) {
+ uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
+ break;
+ }
+ }
+
+ } else {
+
+ // Use previously-cached element index if available
+ if ( useCache ) {
+
+ // ...in a gzip-friendly way
+ node = elem;
+ outerCache = node[ expando ] || ( node[ expando ] = {} );
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ node.uniqueID ] ||
+ ( outerCache[ node.uniqueID ] = {} );
+
+ cache = uniqueCache[ type ] || [];
+ nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
+ diff = nodeIndex;
+ }
+
+ // xml :nth-child(...)
+ // or :nth-last-child(...) or :nth(-last)?-of-type(...)
+ if ( diff === false ) {
+
+ // Use the same loop as above to seek `elem` from the start
+ while ( ( node = ++nodeIndex && node && node[ dir ] ||
+ ( diff = nodeIndex = 0 ) || start.pop() ) ) {
+
+ if ( ( ofType ?
+ node.nodeName.toLowerCase() === name :
+ node.nodeType === 1 ) &&
+ ++diff ) {
+
+ // Cache the index of each encountered element
+ if ( useCache ) {
+ outerCache = node[ expando ] ||
+ ( node[ expando ] = {} );
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ node.uniqueID ] ||
+ ( outerCache[ node.uniqueID ] = {} );
+
+ uniqueCache[ type ] = [ dirruns, diff ];
+ }
+
+ if ( node === elem ) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Incorporate the offset, then check against cycle size
+ diff -= last;
+ return diff === first || ( diff % first === 0 && diff / first >= 0 );
+ }
+ };
+ },
+
+ "PSEUDO": function( pseudo, argument ) {
+
+ // pseudo-class names are case-insensitive
+ // http://www.w3.org/TR/selectors/#pseudo-classes
+ // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
+ // Remember that setFilters inherits from pseudos
+ var args,
+ fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
+ Sizzle.error( "unsupported pseudo: " + pseudo );
+
+ // The user may use createPseudo to indicate that
+ // arguments are needed to create the filter function
+ // just as Sizzle does
+ if ( fn[ expando ] ) {
+ return fn( argument );
+ }
+
+ // But maintain support for old signatures
+ if ( fn.length > 1 ) {
+ args = [ pseudo, pseudo, "", argument ];
+ return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
+ markFunction( function( seed, matches ) {
+ var idx,
+ matched = fn( seed, argument ),
+ i = matched.length;
+ while ( i-- ) {
+ idx = indexOf( seed, matched[ i ] );
+ seed[ idx ] = !( matches[ idx ] = matched[ i ] );
+ }
+ } ) :
+ function( elem ) {
+ return fn( elem, 0, args );
+ };
+ }
+
+ return fn;
+ }
+ },
+
+ pseudos: {
+
+ // Potentially complex pseudos
+ "not": markFunction( function( selector ) {
+
+ // Trim the selector passed to compile
+ // to avoid treating leading and trailing
+ // spaces as combinators
+ var input = [],
+ results = [],
+ matcher = compile( selector.replace( rtrim, "$1" ) );
+
+ return matcher[ expando ] ?
+ markFunction( function( seed, matches, _context, xml ) {
+ var elem,
+ unmatched = matcher( seed, null, xml, [] ),
+ i = seed.length;
+
+ // Match elements unmatched by `matcher`
+ while ( i-- ) {
+ if ( ( elem = unmatched[ i ] ) ) {
+ seed[ i ] = !( matches[ i ] = elem );
+ }
+ }
+ } ) :
+ function( elem, _context, xml ) {
+ input[ 0 ] = elem;
+ matcher( input, null, xml, results );
+
+ // Don't keep the element (issue #299)
+ input[ 0 ] = null;
+ return !results.pop();
+ };
+ } ),
+
+ "has": markFunction( function( selector ) {
+ return function( elem ) {
+ return Sizzle( selector, elem ).length > 0;
+ };
+ } ),
+
+ "contains": markFunction( function( text ) {
+ text = text.replace( runescape, funescape );
+ return function( elem ) {
+ return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1;
+ };
+ } ),
+
+ // "Whether an element is represented by a :lang() selector
+ // is based solely on the element's language value
+ // being equal to the identifier C,
+ // or beginning with the identifier C immediately followed by "-".
+ // The matching of C against the element's language value is performed case-insensitively.
+ // The identifier C does not have to be a valid language name."
+ // http://www.w3.org/TR/selectors/#lang-pseudo
+ "lang": markFunction( function( lang ) {
+
+ // lang value must be a valid identifier
+ if ( !ridentifier.test( lang || "" ) ) {
+ Sizzle.error( "unsupported lang: " + lang );
+ }
+ lang = lang.replace( runescape, funescape ).toLowerCase();
+ return function( elem ) {
+ var elemLang;
+ do {
+ if ( ( elemLang = documentIsHTML ?
+ elem.lang :
+ elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) {
+
+ elemLang = elemLang.toLowerCase();
+ return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
+ }
+ } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 );
+ return false;
+ };
+ } ),
+
+ // Miscellaneous
+ "target": function( elem ) {
+ var hash = window.location && window.location.hash;
+ return hash && hash.slice( 1 ) === elem.id;
+ },
+
+ "root": function( elem ) {
+ return elem === docElem;
+ },
+
+ "focus": function( elem ) {
+ return elem === document.activeElement &&
+ ( !document.hasFocus || document.hasFocus() ) &&
+ !!( elem.type || elem.href || ~elem.tabIndex );
+ },
+
+ // Boolean properties
+ "enabled": createDisabledPseudo( false ),
+ "disabled": createDisabledPseudo( true ),
+
+ "checked": function( elem ) {
+
+ // In CSS3, :checked should return both checked and selected elements
+ // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
+ var nodeName = elem.nodeName.toLowerCase();
+ return ( nodeName === "input" && !!elem.checked ) ||
+ ( nodeName === "option" && !!elem.selected );
+ },
+
+ "selected": function( elem ) {
+
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ // eslint-disable-next-line no-unused-expressions
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ // Contents
+ "empty": function( elem ) {
+
+ // http://www.w3.org/TR/selectors/#empty-pseudo
+ // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
+ // but not by others (comment: 8; processing instruction: 7; etc.)
+ // nodeType < 6 works because attributes (2) do not appear as children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
+ if ( elem.nodeType < 6 ) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ "parent": function( elem ) {
+ return !Expr.pseudos[ "empty" ]( elem );
+ },
+
+ // Element/input types
+ "header": function( elem ) {
+ return rheader.test( elem.nodeName );
+ },
+
+ "input": function( elem ) {
+ return rinputs.test( elem.nodeName );
+ },
+
+ "button": function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && elem.type === "button" || name === "button";
+ },
+
+ "text": function( elem ) {
+ var attr;
+ return elem.nodeName.toLowerCase() === "input" &&
+ elem.type === "text" &&
+
+ // Support: IE<8
+ // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
+ ( ( attr = elem.getAttribute( "type" ) ) == null ||
+ attr.toLowerCase() === "text" );
+ },
+
+ // Position-in-collection
+ "first": createPositionalPseudo( function() {
+ return [ 0 ];
+ } ),
+
+ "last": createPositionalPseudo( function( _matchIndexes, length ) {
+ return [ length - 1 ];
+ } ),
+
+ "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) {
+ return [ argument < 0 ? argument + length : argument ];
+ } ),
+
+ "even": createPositionalPseudo( function( matchIndexes, length ) {
+ var i = 0;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ } ),
+
+ "odd": createPositionalPseudo( function( matchIndexes, length ) {
+ var i = 1;
+ for ( ; i < length; i += 2 ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ } ),
+
+ "lt": createPositionalPseudo( function( matchIndexes, length, argument ) {
+ var i = argument < 0 ?
+ argument + length :
+ argument > length ?
+ length :
+ argument;
+ for ( ; --i >= 0; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ } ),
+
+ "gt": createPositionalPseudo( function( matchIndexes, length, argument ) {
+ var i = argument < 0 ? argument + length : argument;
+ for ( ; ++i < length; ) {
+ matchIndexes.push( i );
+ }
+ return matchIndexes;
+ } )
+ }
+};
+
+Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ];
+
+// Add button/input type pseudos
+for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
+ Expr.pseudos[ i ] = createInputPseudo( i );
+}
+for ( i in { submit: true, reset: true } ) {
+ Expr.pseudos[ i ] = createButtonPseudo( i );
+}
+
+// Easy API for creating new setFilters
+function setFilters() {}
+setFilters.prototype = Expr.filters = Expr.pseudos;
+Expr.setFilters = new setFilters();
+
+tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
+ var matched, match, tokens, type,
+ soFar, groups, preFilters,
+ cached = tokenCache[ selector + " " ];
+
+ if ( cached ) {
+ return parseOnly ? 0 : cached.slice( 0 );
+ }
+
+ soFar = selector;
+ groups = [];
+ preFilters = Expr.preFilter;
+
+ while ( soFar ) {
+
+ // Comma and first run
+ if ( !matched || ( match = rcomma.exec( soFar ) ) ) {
+ if ( match ) {
+
+ // Don't consume trailing commas as valid
+ soFar = soFar.slice( match[ 0 ].length ) || soFar;
+ }
+ groups.push( ( tokens = [] ) );
+ }
+
+ matched = false;
+
+ // Combinators
+ if ( ( match = rcombinators.exec( soFar ) ) ) {
+ matched = match.shift();
+ tokens.push( {
+ value: matched,
+
+ // Cast descendant combinators to space
+ type: match[ 0 ].replace( rtrim, " " )
+ } );
+ soFar = soFar.slice( matched.length );
+ }
+
+ // Filters
+ for ( type in Expr.filter ) {
+ if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] ||
+ ( match = preFilters[ type ]( match ) ) ) ) {
+ matched = match.shift();
+ tokens.push( {
+ value: matched,
+ type: type,
+ matches: match
+ } );
+ soFar = soFar.slice( matched.length );
+ }
+ }
+
+ if ( !matched ) {
+ break;
+ }
+ }
+
+ // Return the length of the invalid excess
+ // if we're just parsing
+ // Otherwise, throw an error or return tokens
+ return parseOnly ?
+ soFar.length :
+ soFar ?
+ Sizzle.error( selector ) :
+
+ // Cache the tokens
+ tokenCache( selector, groups ).slice( 0 );
+};
+
+function toSelector( tokens ) {
+ var i = 0,
+ len = tokens.length,
+ selector = "";
+ for ( ; i < len; i++ ) {
+ selector += tokens[ i ].value;
+ }
+ return selector;
+}
+
+function addCombinator( matcher, combinator, base ) {
+ var dir = combinator.dir,
+ skip = combinator.next,
+ key = skip || dir,
+ checkNonElements = base && key === "parentNode",
+ doneName = done++;
+
+ return combinator.first ?
+
+ // Check against closest ancestor/preceding element
+ function( elem, context, xml ) {
+ while ( ( elem = elem[ dir ] ) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ return matcher( elem, context, xml );
+ }
+ }
+ return false;
+ } :
+
+ // Check against all ancestor/preceding elements
+ function( elem, context, xml ) {
+ var oldCache, uniqueCache, outerCache,
+ newCache = [ dirruns, doneName ];
+
+ // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
+ if ( xml ) {
+ while ( ( elem = elem[ dir ] ) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ if ( matcher( elem, context, xml ) ) {
+ return true;
+ }
+ }
+ }
+ } else {
+ while ( ( elem = elem[ dir ] ) ) {
+ if ( elem.nodeType === 1 || checkNonElements ) {
+ outerCache = elem[ expando ] || ( elem[ expando ] = {} );
+
+ // Support: IE <9 only
+ // Defend against cloned attroperties (jQuery gh-1709)
+ uniqueCache = outerCache[ elem.uniqueID ] ||
+ ( outerCache[ elem.uniqueID ] = {} );
+
+ if ( skip && skip === elem.nodeName.toLowerCase() ) {
+ elem = elem[ dir ] || elem;
+ } else if ( ( oldCache = uniqueCache[ key ] ) &&
+ oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
+
+ // Assign to newCache so results back-propagate to previous elements
+ return ( newCache[ 2 ] = oldCache[ 2 ] );
+ } else {
+
+ // Reuse newcache so results back-propagate to previous elements
+ uniqueCache[ key ] = newCache;
+
+ // A match means we're done; a fail means we have to keep checking
+ if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ };
+}
+
+function elementMatcher( matchers ) {
+ return matchers.length > 1 ?
+ function( elem, context, xml ) {
+ var i = matchers.length;
+ while ( i-- ) {
+ if ( !matchers[ i ]( elem, context, xml ) ) {
+ return false;
+ }
+ }
+ return true;
+ } :
+ matchers[ 0 ];
+}
+
+function multipleContexts( selector, contexts, results ) {
+ var i = 0,
+ len = contexts.length;
+ for ( ; i < len; i++ ) {
+ Sizzle( selector, contexts[ i ], results );
+ }
+ return results;
+}
+
+function condense( unmatched, map, filter, context, xml ) {
+ var elem,
+ newUnmatched = [],
+ i = 0,
+ len = unmatched.length,
+ mapped = map != null;
+
+ for ( ; i < len; i++ ) {
+ if ( ( elem = unmatched[ i ] ) ) {
+ if ( !filter || filter( elem, context, xml ) ) {
+ newUnmatched.push( elem );
+ if ( mapped ) {
+ map.push( i );
+ }
+ }
+ }
+ }
+
+ return newUnmatched;
+}
+
+function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
+ if ( postFilter && !postFilter[ expando ] ) {
+ postFilter = setMatcher( postFilter );
+ }
+ if ( postFinder && !postFinder[ expando ] ) {
+ postFinder = setMatcher( postFinder, postSelector );
+ }
+ return markFunction( function( seed, results, context, xml ) {
+ var temp, i, elem,
+ preMap = [],
+ postMap = [],
+ preexisting = results.length,
+
+ // Get initial elements from seed or context
+ elems = seed || multipleContexts(
+ selector || "*",
+ context.nodeType ? [ context ] : context,
+ []
+ ),
+
+ // Prefilter to get matcher input, preserving a map for seed-results synchronization
+ matcherIn = preFilter && ( seed || !selector ) ?
+ condense( elems, preMap, preFilter, context, xml ) :
+ elems,
+
+ matcherOut = matcher ?
+
+ // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
+ postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
+
+ // ...intermediate processing is necessary
+ [] :
+
+ // ...otherwise use results directly
+ results :
+ matcherIn;
+
+ // Find primary matches
+ if ( matcher ) {
+ matcher( matcherIn, matcherOut, context, xml );
+ }
+
+ // Apply postFilter
+ if ( postFilter ) {
+ temp = condense( matcherOut, postMap );
+ postFilter( temp, [], context, xml );
+
+ // Un-match failing elements by moving them back to matcherIn
+ i = temp.length;
+ while ( i-- ) {
+ if ( ( elem = temp[ i ] ) ) {
+ matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem );
+ }
+ }
+ }
+
+ if ( seed ) {
+ if ( postFinder || preFilter ) {
+ if ( postFinder ) {
+
+ // Get the final matcherOut by condensing this intermediate into postFinder contexts
+ temp = [];
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( ( elem = matcherOut[ i ] ) ) {
+
+ // Restore matcherIn since elem is not yet a final match
+ temp.push( ( matcherIn[ i ] = elem ) );
+ }
+ }
+ postFinder( null, ( matcherOut = [] ), temp, xml );
+ }
+
+ // Move matched elements from seed to results to keep them synchronized
+ i = matcherOut.length;
+ while ( i-- ) {
+ if ( ( elem = matcherOut[ i ] ) &&
+ ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) {
+
+ seed[ temp ] = !( results[ temp ] = elem );
+ }
+ }
+ }
+
+ // Add elements to results, through postFinder if defined
+ } else {
+ matcherOut = condense(
+ matcherOut === results ?
+ matcherOut.splice( preexisting, matcherOut.length ) :
+ matcherOut
+ );
+ if ( postFinder ) {
+ postFinder( null, results, matcherOut, xml );
+ } else {
+ push.apply( results, matcherOut );
+ }
+ }
+ } );
+}
+
+function matcherFromTokens( tokens ) {
+ var checkContext, matcher, j,
+ len = tokens.length,
+ leadingRelative = Expr.relative[ tokens[ 0 ].type ],
+ implicitRelative = leadingRelative || Expr.relative[ " " ],
+ i = leadingRelative ? 1 : 0,
+
+ // The foundational matcher ensures that elements are reachable from top-level context(s)
+ matchContext = addCombinator( function( elem ) {
+ return elem === checkContext;
+ }, implicitRelative, true ),
+ matchAnyContext = addCombinator( function( elem ) {
+ return indexOf( checkContext, elem ) > -1;
+ }, implicitRelative, true ),
+ matchers = [ function( elem, context, xml ) {
+ var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
+ ( checkContext = context ).nodeType ?
+ matchContext( elem, context, xml ) :
+ matchAnyContext( elem, context, xml ) );
+
+ // Avoid hanging onto element (issue #299)
+ checkContext = null;
+ return ret;
+ } ];
+
+ for ( ; i < len; i++ ) {
+ if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) {
+ matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ];
+ } else {
+ matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches );
+
+ // Return special upon seeing a positional matcher
+ if ( matcher[ expando ] ) {
+
+ // Find the next relative operator (if any) for proper handling
+ j = ++i;
+ for ( ; j < len; j++ ) {
+ if ( Expr.relative[ tokens[ j ].type ] ) {
+ break;
+ }
+ }
+ return setMatcher(
+ i > 1 && elementMatcher( matchers ),
+ i > 1 && toSelector(
+
+ // If the preceding token was a descendant combinator, insert an implicit any-element `*`
+ tokens
+ .slice( 0, i - 1 )
+ .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } )
+ ).replace( rtrim, "$1" ),
+ matcher,
+ i < j && matcherFromTokens( tokens.slice( i, j ) ),
+ j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ),
+ j < len && toSelector( tokens )
+ );
+ }
+ matchers.push( matcher );
+ }
+ }
+
+ return elementMatcher( matchers );
+}
+
+function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
+ var bySet = setMatchers.length > 0,
+ byElement = elementMatchers.length > 0,
+ superMatcher = function( seed, context, xml, results, outermost ) {
+ var elem, j, matcher,
+ matchedCount = 0,
+ i = "0",
+ unmatched = seed && [],
+ setMatched = [],
+ contextBackup = outermostContext,
+
+ // We must always have either seed elements or outermost context
+ elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ),
+
+ // Use integer dirruns iff this is the outermost matcher
+ dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ),
+ len = elems.length;
+
+ if ( outermost ) {
+
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ outermostContext = context == document || context || outermost;
+ }
+
+ // Add elements passing elementMatchers directly to results
+ // Support: IE<9, Safari
+ // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
+ for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) {
+ if ( byElement && elem ) {
+ j = 0;
+
+ // Support: IE 11+, Edge 17 - 18+
+ // IE/Edge sometimes throw a "Permission denied" error when strict-comparing
+ // two documents; shallow comparisons work.
+ // eslint-disable-next-line eqeqeq
+ if ( !context && elem.ownerDocument != document ) {
+ setDocument( elem );
+ xml = !documentIsHTML;
+ }
+ while ( ( matcher = elementMatchers[ j++ ] ) ) {
+ if ( matcher( elem, context || document, xml ) ) {
+ results.push( elem );
+ break;
+ }
+ }
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ }
+ }
+
+ // Track unmatched elements for set filters
+ if ( bySet ) {
+
+ // They will have gone through all possible matchers
+ if ( ( elem = !matcher && elem ) ) {
+ matchedCount--;
+ }
+
+ // Lengthen the array for every element, matched or not
+ if ( seed ) {
+ unmatched.push( elem );
+ }
+ }
+ }
+
+ // `i` is now the count of elements visited above, and adding it to `matchedCount`
+ // makes the latter nonnegative.
+ matchedCount += i;
+
+ // Apply set filters to unmatched elements
+ // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
+ // equals `i`), unless we didn't visit _any_ elements in the above loop because we have
+ // no element matchers and no seed.
+ // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
+ // case, which will result in a "00" `matchedCount` that differs from `i` but is also
+ // numerically zero.
+ if ( bySet && i !== matchedCount ) {
+ j = 0;
+ while ( ( matcher = setMatchers[ j++ ] ) ) {
+ matcher( unmatched, setMatched, context, xml );
+ }
+
+ if ( seed ) {
+
+ // Reintegrate element matches to eliminate the need for sorting
+ if ( matchedCount > 0 ) {
+ while ( i-- ) {
+ if ( !( unmatched[ i ] || setMatched[ i ] ) ) {
+ setMatched[ i ] = pop.call( results );
+ }
+ }
+ }
+
+ // Discard index placeholder values to get only actual matches
+ setMatched = condense( setMatched );
+ }
+
+ // Add matches to results
+ push.apply( results, setMatched );
+
+ // Seedless set matches succeeding multiple successful matchers stipulate sorting
+ if ( outermost && !seed && setMatched.length > 0 &&
+ ( matchedCount + setMatchers.length ) > 1 ) {
+
+ Sizzle.uniqueSort( results );
+ }
+ }
+
+ // Override manipulation of globals by nested matchers
+ if ( outermost ) {
+ dirruns = dirrunsUnique;
+ outermostContext = contextBackup;
+ }
+
+ return unmatched;
+ };
+
+ return bySet ?
+ markFunction( superMatcher ) :
+ superMatcher;
+}
+
+compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
+ var i,
+ setMatchers = [],
+ elementMatchers = [],
+ cached = compilerCache[ selector + " " ];
+
+ if ( !cached ) {
+
+ // Generate a function of recursive functions that can be used to check each element
+ if ( !match ) {
+ match = tokenize( selector );
+ }
+ i = match.length;
+ while ( i-- ) {
+ cached = matcherFromTokens( match[ i ] );
+ if ( cached[ expando ] ) {
+ setMatchers.push( cached );
+ } else {
+ elementMatchers.push( cached );
+ }
+ }
+
+ // Cache the compiled function
+ cached = compilerCache(
+ selector,
+ matcherFromGroupMatchers( elementMatchers, setMatchers )
+ );
+
+ // Save selector and tokenization
+ cached.selector = selector;
+ }
+ return cached;
+};
+
+/**
+ * A low-level selection function that works with Sizzle's compiled
+ * selector functions
+ * @param {String|Function} selector A selector or a pre-compiled
+ * selector function built with Sizzle.compile
+ * @param {Element} context
+ * @param {Array} [results]
+ * @param {Array} [seed] A set of elements to match against
+ */
+select = Sizzle.select = function( selector, context, results, seed ) {
+ var i, tokens, token, type, find,
+ compiled = typeof selector === "function" && selector,
+ match = !seed && tokenize( ( selector = compiled.selector || selector ) );
+
+ results = results || [];
+
+ // Try to minimize operations if there is only one selector in the list and no seed
+ // (the latter of which guarantees us context)
+ if ( match.length === 1 ) {
+
+ // Reduce context if the leading compound selector is an ID
+ tokens = match[ 0 ] = match[ 0 ].slice( 0 );
+ if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" &&
+ context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) {
+
+ context = ( Expr.find[ "ID" ]( token.matches[ 0 ]
+ .replace( runescape, funescape ), context ) || [] )[ 0 ];
+ if ( !context ) {
+ return results;
+
+ // Precompiled matchers will still verify ancestry, so step up a level
+ } else if ( compiled ) {
+ context = context.parentNode;
+ }
+
+ selector = selector.slice( tokens.shift().value.length );
+ }
+
+ // Fetch a seed set for right-to-left matching
+ i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length;
+ while ( i-- ) {
+ token = tokens[ i ];
+
+ // Abort if we hit a combinator
+ if ( Expr.relative[ ( type = token.type ) ] ) {
+ break;
+ }
+ if ( ( find = Expr.find[ type ] ) ) {
+
+ // Search, expanding context for leading sibling combinators
+ if ( ( seed = find(
+ token.matches[ 0 ].replace( runescape, funescape ),
+ rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) ||
+ context
+ ) ) ) {
+
+ // If seed is empty or no tokens remain, we can return early
+ tokens.splice( i, 1 );
+ selector = seed.length && toSelector( tokens );
+ if ( !selector ) {
+ push.apply( results, seed );
+ return results;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ // Compile and execute a filtering function if one is not provided
+ // Provide `match` to avoid retokenization if we modified the selector above
+ ( compiled || compile( selector, match ) )(
+ seed,
+ context,
+ !documentIsHTML,
+ results,
+ !context || rsibling.test( selector ) && testContext( context.parentNode ) || context
+ );
+ return results;
+};
+
+// One-time assignments
+
+// Sort stability
+support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando;
+
+// Support: Chrome 14-35+
+// Always assume duplicates if they aren't passed to the comparison function
+support.detectDuplicates = !!hasDuplicate;
+
+// Initialize against the default document
+setDocument();
+
+// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
+// Detached nodes confoundingly follow *each other*
+support.sortDetached = assert( function( el ) {
+
+ // Should return 1, but returns 4 (following)
+ return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1;
+} );
+
+// Support: IE<8
+// Prevent attribute/property "interpolation"
+// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
+if ( !assert( function( el ) {
+ el.innerHTML = "<a href='#'></a>";
+ return el.firstChild.getAttribute( "href" ) === "#";
+} ) ) {
+ addHandle( "type|href|height|width", function( elem, name, isXML ) {
+ if ( !isXML ) {
+ return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
+ }
+ } );
+}
+
+// Support: IE<9
+// Use defaultValue in place of getAttribute("value")
+if ( !support.attributes || !assert( function( el ) {
+ el.innerHTML = "<input/>";
+ el.firstChild.setAttribute( "value", "" );
+ return el.firstChild.getAttribute( "value" ) === "";
+} ) ) {
+ addHandle( "value", function( elem, _name, isXML ) {
+ if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
+ return elem.defaultValue;
+ }
+ } );
+}
+
+// Support: IE<9
+// Use getAttributeNode to fetch booleans when getAttribute lies
+if ( !assert( function( el ) {
+ return el.getAttribute( "disabled" ) == null;
+} ) ) {
+ addHandle( booleans, function( elem, name, isXML ) {
+ var val;
+ if ( !isXML ) {
+ return elem[ name ] === true ? name.toLowerCase() :
+ ( val = elem.getAttributeNode( name ) ) && val.specified ?
+ val.value :
+ null;
+ }
+ } );
+}
+
+return Sizzle;
+
+} )( window );
+
+
+
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+
+// Deprecated
+jQuery.expr[ ":" ] = jQuery.expr.pseudos;
+jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+jQuery.escapeSelector = Sizzle.escape;
+
+
+
+
+var dir = function( elem, dir, until ) {
+ var matched = [],
+ truncate = until !== undefined;
+
+ while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
+ if ( elem.nodeType === 1 ) {
+ if ( truncate && jQuery( elem ).is( until ) ) {
+ break;
+ }
+ matched.push( elem );
+ }
+ }
+ return matched;
+};
+
+
+var siblings = function( n, elem ) {
+ var matched = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ matched.push( n );
+ }
+ }
+
+ return matched;
+};
+
+
+var rneedsContext = jQuery.expr.match.needsContext;
+
+
+
+function nodeName( elem, name ) {
+
+ return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
+
+};
+var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i );
+
+
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, not ) {
+ if ( isFunction( qualifier ) ) {
+ return jQuery.grep( elements, function( elem, i ) {
+ return !!qualifier.call( elem, i, elem ) !== not;
+ } );
+ }
+
+ // Single element
+ if ( qualifier.nodeType ) {
+ return jQuery.grep( elements, function( elem ) {
+ return ( elem === qualifier ) !== not;
+ } );
+ }
+
+ // Arraylike of elements (jQuery, arguments, Array)
+ if ( typeof qualifier !== "string" ) {
+ return jQuery.grep( elements, function( elem ) {
+ return ( indexOf.call( qualifier, elem ) > -1 ) !== not;
+ } );
+ }
+
+ // Filtered directly for both simple and complex selectors
+ return jQuery.filter( qualifier, elements, not );
+}
+
+jQuery.filter = function( expr, elems, not ) {
+ var elem = elems[ 0 ];
+
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ if ( elems.length === 1 && elem.nodeType === 1 ) {
+ return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];
+ }
+
+ return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
+ return elem.nodeType === 1;
+ } ) );
+};
+
+jQuery.fn.extend( {
+ find: function( selector ) {
+ var i, ret,
+ len = this.length,
+ self = this;
+
+ if ( typeof selector !== "string" ) {
+ return this.pushStack( jQuery( selector ).filter( function() {
+ for ( i = 0; i < len; i++ ) {
+ if ( jQuery.contains( self[ i ], this ) ) {
+ return true;
+ }
+ }
+ } ) );
+ }
+
+ ret = this.pushStack( [] );
+
+ for ( i = 0; i < len; i++ ) {
+ jQuery.find( selector, self[ i ], ret );
+ }
+
+ return len > 1 ? jQuery.uniqueSort( ret ) : ret;
+ },
+ filter: function( selector ) {
+ return this.pushStack( winnow( this, selector || [], false ) );
+ },
+ not: function( selector ) {
+ return this.pushStack( winnow( this, selector || [], true ) );
+ },
+ is: function( selector ) {
+ return !!winnow(
+ this,
+
+ // If this is a positional/relative selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ typeof selector === "string" && rneedsContext.test( selector ) ?
+ jQuery( selector ) :
+ selector || [],
+ false
+ ).length;
+ }
+} );
+
+
+// Initialize a jQuery object
+
+
+// A central reference to the root jQuery(document)
+var rootjQuery,
+
+ // A simple way to check for HTML strings
+ // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+ // Strict HTML recognition (#11290: must start with <)
+ // Shortcut simple #id case for speed
+ rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,
+
+ init = jQuery.fn.init = function( selector, context, root ) {
+ var match, elem;
+
+ // HANDLE: $(""), $(null), $(undefined), $(false)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Method init() accepts an alternate rootjQuery
+ // so migrate can support jQuery.sub (gh-2101)
+ root = root || rootjQuery;
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ if ( selector[ 0 ] === "<" &&
+ selector[ selector.length - 1 ] === ">" &&
+ selector.length >= 3 ) {
+
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = rquickExpr.exec( selector );
+ }
+
+ // Match html or make sure no context is specified for #id
+ if ( match && ( match[ 1 ] || !context ) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[ 1 ] ) {
+ context = context instanceof jQuery ? context[ 0 ] : context;
+
+ // Option to run scripts is true for back-compat
+ // Intentionally let the error be thrown if parseHTML is not present
+ jQuery.merge( this, jQuery.parseHTML(
+ match[ 1 ],
+ context && context.nodeType ? context.ownerDocument || context : document,
+ true
+ ) );
+
+ // HANDLE: $(html, props)
+ if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
+ for ( match in context ) {
+
+ // Properties of context are called as methods if possible
+ if ( isFunction( this[ match ] ) ) {
+ this[ match ]( context[ match ] );
+
+ // ...and otherwise set as attributes
+ } else {
+ this.attr( match, context[ match ] );
+ }
+ }
+ }
+
+ return this;
+
+ // HANDLE: $(#id)
+ } else {
+ elem = document.getElementById( match[ 2 ] );
+
+ if ( elem ) {
+
+ // Inject the element directly into the jQuery object
+ this[ 0 ] = elem;
+ this.length = 1;
+ }
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return ( context || root ).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(DOMElement)
+ } else if ( selector.nodeType ) {
+ this[ 0 ] = selector;
+ this.length = 1;
+ return this;
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( isFunction( selector ) ) {
+ return root.ready !== undefined ?
+ root.ready( selector ) :
+
+ // Execute immediately if ready is not present
+ selector( jQuery );
+ }
+
+ return jQuery.makeArray( selector, this );
+ };
+
+// Give the init function the jQuery prototype for later instantiation
+init.prototype = jQuery.fn;
+
+// Initialize central reference
+rootjQuery = jQuery( document );
+
+
+var rparentsprev = /^(?:parents|prev(?:Until|All))/,
+
+ // Methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
+
+jQuery.fn.extend( {
+ has: function( target ) {
+ var targets = jQuery( target, this ),
+ l = targets.length;
+
+ return this.filter( function() {
+ var i = 0;
+ for ( ; i < l; i++ ) {
+ if ( jQuery.contains( this, targets[ i ] ) ) {
+ return true;
+ }
+ }
+ } );
+ },
+
+ closest: function( selectors, context ) {
+ var cur,
+ i = 0,
+ l = this.length,
+ matched = [],
+ targets = typeof selectors !== "string" && jQuery( selectors );
+
+ // Positional selectors never match, since there's no _selection_ context
+ if ( !rneedsContext.test( selectors ) ) {
+ for ( ; i < l; i++ ) {
+ for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {
+
+ // Always skip document fragments
+ if ( cur.nodeType < 11 && ( targets ?
+ targets.index( cur ) > -1 :
+
+ // Don't pass non-elements to Sizzle
+ cur.nodeType === 1 &&
+ jQuery.find.matchesSelector( cur, selectors ) ) ) {
+
+ matched.push( cur );
+ break;
+ }
+ }
+ }
+ }
+
+ return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
+ },
+
+ // Determine the position of an element within the set
+ index: function( elem ) {
+
+ // No argument, return index in parent
+ if ( !elem ) {
+ return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
+ }
+
+ // Index in selector
+ if ( typeof elem === "string" ) {
+ return indexOf.call( jQuery( elem ), this[ 0 ] );
+ }
+
+ // Locate the position of the desired element
+ return indexOf.call( this,
+
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[ 0 ] : elem
+ );
+ },
+
+ add: function( selector, context ) {
+ return this.pushStack(
+ jQuery.uniqueSort(
+ jQuery.merge( this.get(), jQuery( selector, context ) )
+ )
+ );
+ },
+
+ addBack: function( selector ) {
+ return this.add( selector == null ?
+ this.prevObject : this.prevObject.filter( selector )
+ );
+ }
+} );
+
+function sibling( cur, dir ) {
+ while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}
+ return cur;
+}
+
+jQuery.each( {
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, _i, until ) {
+ return dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return sibling( elem, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return sibling( elem, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, _i, until ) {
+ return dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, _i, until ) {
+ return dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return siblings( ( elem.parentNode || {} ).firstChild, elem );
+ },
+ children: function( elem ) {
+ return siblings( elem.firstChild );
+ },
+ contents: function( elem ) {
+ if ( elem.contentDocument != null &&
+
+ // Support: IE 11+
+ // <object> elements with no `data` attribute has an object
+ // `contentDocument` with a `null` prototype.
+ getProto( elem.contentDocument ) ) {
+
+ return elem.contentDocument;
+ }
+
+ // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only
+ // Treat the template element as a regular one in browsers that
+ // don't support it.
+ if ( nodeName( elem, "template" ) ) {
+ elem = elem.content || elem;
+ }
+
+ return jQuery.merge( [], elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var matched = jQuery.map( this, fn, until );
+
+ if ( name.slice( -5 ) !== "Until" ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ matched = jQuery.filter( selector, matched );
+ }
+
+ if ( this.length > 1 ) {
+
+ // Remove duplicates
+ if ( !guaranteedUnique[ name ] ) {
+ jQuery.uniqueSort( matched );
+ }
+
+ // Reverse order for parents* and prev-derivatives
+ if ( rparentsprev.test( name ) ) {
+ matched.reverse();
+ }
+ }
+
+ return this.pushStack( matched );
+ };
+} );
+var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g );
+
+
+
+// Convert String-formatted options into Object-formatted ones
+function createOptions( options ) {
+ var object = {};
+ jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {
+ object[ flag ] = true;
+ } );
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * options: an optional list of space-separated options that will change how
+ * the callback list behaves or a more traditional option object
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible options:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( options ) {
+
+ // Convert options from String-formatted to Object-formatted if needed
+ // (we check in cache first)
+ options = typeof options === "string" ?
+ createOptions( options ) :
+ jQuery.extend( {}, options );
+
+ var // Flag to know if list is currently firing
+ firing,
+
+ // Last fire value for non-forgettable lists
+ memory,
+
+ // Flag to know if list was already fired
+ fired,
+
+ // Flag to prevent firing
+ locked,
+
+ // Actual callback list
+ list = [],
+
+ // Queue of execution data for repeatable lists
+ queue = [],
+
+ // Index of currently firing callback (modified by add/remove as needed)
+ firingIndex = -1,
+
+ // Fire callbacks
+ fire = function() {
+
+ // Enforce single-firing
+ locked = locked || options.once;
+
+ // Execute callbacks for all pending executions,
+ // respecting firingIndex overrides and runtime changes
+ fired = firing = true;
+ for ( ; queue.length; firingIndex = -1 ) {
+ memory = queue.shift();
+ while ( ++firingIndex < list.length ) {
+
+ // Run callback and check for early termination
+ if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
+ options.stopOnFalse ) {
+
+ // Jump to end and forget the data so .add doesn't re-fire
+ firingIndex = list.length;
+ memory = false;
+ }
+ }
+ }
+
+ // Forget the data if we're done with it
+ if ( !options.memory ) {
+ memory = false;
+ }
+
+ firing = false;
+
+ // Clean up if we're done firing for good
+ if ( locked ) {
+
+ // Keep an empty list if we have data for future add calls
+ if ( memory ) {
+ list = [];
+
+ // Otherwise, this object is spent
+ } else {
+ list = "";
+ }
+ }
+ },
+
+ // Actual Callbacks object
+ self = {
+
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+
+ // If we have memory from a past run, we should fire after adding
+ if ( memory && !firing ) {
+ firingIndex = list.length - 1;
+ queue.push( memory );
+ }
+
+ ( function add( args ) {
+ jQuery.each( args, function( _, arg ) {
+ if ( isFunction( arg ) ) {
+ if ( !options.unique || !self.has( arg ) ) {
+ list.push( arg );
+ }
+ } else if ( arg && arg.length && toType( arg ) !== "string" ) {
+
+ // Inspect recursively
+ add( arg );
+ }
+ } );
+ } )( arguments );
+
+ if ( memory && !firing ) {
+ fire();
+ }
+ }
+ return this;
+ },
+
+ // Remove a callback from the list
+ remove: function() {
+ jQuery.each( arguments, function( _, arg ) {
+ var index;
+ while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
+ list.splice( index, 1 );
+
+ // Handle firing indexes
+ if ( index <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ } );
+ return this;
+ },
+
+ // Check if a given callback is in the list.
+ // If no argument is given, return whether or not list has callbacks attached.
+ has: function( fn ) {
+ return fn ?
+ jQuery.inArray( fn, list ) > -1 :
+ list.length > 0;
+ },
+
+ // Remove all callbacks from the list
+ empty: function() {
+ if ( list ) {
+ list = [];
+ }
+ return this;
+ },
+
+ // Disable .fire and .add
+ // Abort any current/pending executions
+ // Clear all callbacks and values
+ disable: function() {
+ locked = queue = [];
+ list = memory = "";
+ return this;
+ },
+ disabled: function() {
+ return !list;
+ },
+
+ // Disable .fire
+ // Also disable .add unless we have memory (since it would have no effect)
+ // Abort any pending executions
+ lock: function() {
+ locked = queue = [];
+ if ( !memory && !firing ) {
+ list = memory = "";
+ }
+ return this;
+ },
+ locked: function() {
+ return !!locked;
+ },
+
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ if ( !locked ) {
+ args = args || [];
+ args = [ context, args.slice ? args.slice() : args ];
+ queue.push( args );
+ if ( !firing ) {
+ fire();
+ }
+ }
+ return this;
+ },
+
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+
+
+function Identity( v ) {
+ return v;
+}
+function Thrower( ex ) {
+ throw ex;
+}
+
+function adoptValue( value, resolve, reject, noValue ) {
+ var method;
+
+ try {
+
+ // Check for promise aspect first to privilege synchronous behavior
+ if ( value && isFunction( ( method = value.promise ) ) ) {
+ method.call( value ).done( resolve ).fail( reject );
+
+ // Other thenables
+ } else if ( value && isFunction( ( method = value.then ) ) ) {
+ method.call( value, resolve, reject );
+
+ // Other non-thenables
+ } else {
+
+ // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:
+ // * false: [ value ].slice( 0 ) => resolve( value )
+ // * true: [ value ].slice( 1 ) => resolve()
+ resolve.apply( undefined, [ value ].slice( noValue ) );
+ }
+
+ // For Promises/A+, convert exceptions into rejections
+ // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in
+ // Deferred#then to conditionally suppress rejection.
+ } catch ( value ) {
+
+ // Support: Android 4.0 only
+ // Strict mode functions invoked without .call/.apply get global-object context
+ reject.apply( undefined, [ value ] );
+ }
+}
+
+jQuery.extend( {
+
+ Deferred: function( func ) {
+ var tuples = [
+
+ // action, add listener, callbacks,
+ // ... .then handlers, argument index, [final state]
+ [ "notify", "progress", jQuery.Callbacks( "memory" ),
+ jQuery.Callbacks( "memory" ), 2 ],
+ [ "resolve", "done", jQuery.Callbacks( "once memory" ),
+ jQuery.Callbacks( "once memory" ), 0, "resolved" ],
+ [ "reject", "fail", jQuery.Callbacks( "once memory" ),
+ jQuery.Callbacks( "once memory" ), 1, "rejected" ]
+ ],
+ state = "pending",
+ promise = {
+ state: function() {
+ return state;
+ },
+ always: function() {
+ deferred.done( arguments ).fail( arguments );
+ return this;
+ },
+ "catch": function( fn ) {
+ return promise.then( null, fn );
+ },
+
+ // Keep pipe for back-compat
+ pipe: function( /* fnDone, fnFail, fnProgress */ ) {
+ var fns = arguments;
+
+ return jQuery.Deferred( function( newDefer ) {
+ jQuery.each( tuples, function( _i, tuple ) {
+
+ // Map tuples (progress, done, fail) to arguments (done, fail, progress)
+ var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];
+
+ // deferred.progress(function() { bind to newDefer or newDefer.notify })
+ // deferred.done(function() { bind to newDefer or newDefer.resolve })
+ // deferred.fail(function() { bind to newDefer or newDefer.reject })
+ deferred[ tuple[ 1 ] ]( function() {
+ var returned = fn && fn.apply( this, arguments );
+ if ( returned && isFunction( returned.promise ) ) {
+ returned.promise()
+ .progress( newDefer.notify )
+ .done( newDefer.resolve )
+ .fail( newDefer.reject );
+ } else {
+ newDefer[ tuple[ 0 ] + "With" ](
+ this,
+ fn ? [ returned ] : arguments
+ );
+ }
+ } );
+ } );
+ fns = null;
+ } ).promise();
+ },
+ then: function( onFulfilled, onRejected, onProgress ) {
+ var maxDepth = 0;
+ function resolve( depth, deferred, handler, special ) {
+ return function() {
+ var that = this,
+ args = arguments,
+ mightThrow = function() {
+ var returned, then;
+
+ // Support: Promises/A+ section 2.3.3.3.3
+ // https://promisesaplus.com/#point-59
+ // Ignore double-resolution attempts
+ if ( depth < maxDepth ) {
+ return;
+ }
+
+ returned = handler.apply( that, args );
+
+ // Support: Promises/A+ section 2.3.1
+ // https://promisesaplus.com/#point-48
+ if ( returned === deferred.promise() ) {
+ throw new TypeError( "Thenable self-resolution" );
+ }
+
+ // Support: Promises/A+ sections 2.3.3.1, 3.5
+ // https://promisesaplus.com/#point-54
+ // https://promisesaplus.com/#point-75
+ // Retrieve `then` only once
+ then = returned &&
+
+ // Support: Promises/A+ section 2.3.4
+ // https://promisesaplus.com/#point-64
+ // Only check objects and functions for thenability
+ ( typeof returned === "object" ||
+ typeof returned === "function" ) &&
+ returned.then;
+
+ // Handle a returned thenable
+ if ( isFunction( then ) ) {
+
+ // Special processors (notify) just wait for resolution
+ if ( special ) {
+ then.call(
+ returned,
+ resolve( maxDepth, deferred, Identity, special ),
+ resolve( maxDepth, deferred, Thrower, special )
+ );
+
+ // Normal processors (resolve) also hook into progress
+ } else {
+
+ // ...and disregard older resolution values
+ maxDepth++;
+
+ then.call(
+ returned,
+ resolve( maxDepth, deferred, Identity, special ),
+ resolve( maxDepth, deferred, Thrower, special ),
+ resolve( maxDepth, deferred, Identity,
+ deferred.notifyWith )
+ );
+ }
+
+ // Handle all other returned values
+ } else {
+
+ // Only substitute handlers pass on context
+ // and multiple values (non-spec behavior)
+ if ( handler !== Identity ) {
+ that = undefined;
+ args = [ returned ];
+ }
+
+ // Process the value(s)
+ // Default process is resolve
+ ( special || deferred.resolveWith )( that, args );
+ }
+ },
+
+ // Only normal processors (resolve) catch and reject exceptions
+ process = special ?
+ mightThrow :
+ function() {
+ try {
+ mightThrow();
+ } catch ( e ) {
+
+ if ( jQuery.Deferred.exceptionHook ) {
+ jQuery.Deferred.exceptionHook( e,
+ process.stackTrace );
+ }
+
+ // Support: Promises/A+ section 2.3.3.3.4.1
+ // https://promisesaplus.com/#point-61
+ // Ignore post-resolution exceptions
+ if ( depth + 1 >= maxDepth ) {
+
+ // Only substitute handlers pass on context
+ // and multiple values (non-spec behavior)
+ if ( handler !== Thrower ) {
+ that = undefined;
+ args = [ e ];
+ }
+
+ deferred.rejectWith( that, args );
+ }
+ }
+ };
+
+ // Support: Promises/A+ section 2.3.3.3.1
+ // https://promisesaplus.com/#point-57
+ // Re-resolve promises immediately to dodge false rejection from
+ // subsequent errors
+ if ( depth ) {
+ process();
+ } else {
+
+ // Call an optional hook to record the stack, in case of exception
+ // since it's otherwise lost when execution goes async
+ if ( jQuery.Deferred.getStackHook ) {
+ process.stackTrace = jQuery.Deferred.getStackHook();
+ }
+ window.setTimeout( process );
+ }
+ };
+ }
+
+ return jQuery.Deferred( function( newDefer ) {
+
+ // progress_handlers.add( ... )
+ tuples[ 0 ][ 3 ].add(
+ resolve(
+ 0,
+ newDefer,
+ isFunction( onProgress ) ?
+ onProgress :
+ Identity,
+ newDefer.notifyWith
+ )
+ );
+
+ // fulfilled_handlers.add( ... )
+ tuples[ 1 ][ 3 ].add(
+ resolve(
+ 0,
+ newDefer,
+ isFunction( onFulfilled ) ?
+ onFulfilled :
+ Identity
+ )
+ );
+
+ // rejected_handlers.add( ... )
+ tuples[ 2 ][ 3 ].add(
+ resolve(
+ 0,
+ newDefer,
+ isFunction( onRejected ) ?
+ onRejected :
+ Thrower
+ )
+ );
+ } ).promise();
+ },
+
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ return obj != null ? jQuery.extend( obj, promise ) : promise;
+ }
+ },
+ deferred = {};
+
+ // Add list-specific methods
+ jQuery.each( tuples, function( i, tuple ) {
+ var list = tuple[ 2 ],
+ stateString = tuple[ 5 ];
+
+ // promise.progress = list.add
+ // promise.done = list.add
+ // promise.fail = list.add
+ promise[ tuple[ 1 ] ] = list.add;
+
+ // Handle state
+ if ( stateString ) {
+ list.add(
+ function() {
+
+ // state = "resolved" (i.e., fulfilled)
+ // state = "rejected"
+ state = stateString;
+ },
+
+ // rejected_callbacks.disable
+ // fulfilled_callbacks.disable
+ tuples[ 3 - i ][ 2 ].disable,
+
+ // rejected_handlers.disable
+ // fulfilled_handlers.disable
+ tuples[ 3 - i ][ 3 ].disable,
+
+ // progress_callbacks.lock
+ tuples[ 0 ][ 2 ].lock,
+
+ // progress_handlers.lock
+ tuples[ 0 ][ 3 ].lock
+ );
+ }
+
+ // progress_handlers.fire
+ // fulfilled_handlers.fire
+ // rejected_handlers.fire
+ list.add( tuple[ 3 ].fire );
+
+ // deferred.notify = function() { deferred.notifyWith(...) }
+ // deferred.resolve = function() { deferred.resolveWith(...) }
+ // deferred.reject = function() { deferred.rejectWith(...) }
+ deferred[ tuple[ 0 ] ] = function() {
+ deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments );
+ return this;
+ };
+
+ // deferred.notifyWith = list.fireWith
+ // deferred.resolveWith = list.fireWith
+ // deferred.rejectWith = list.fireWith
+ deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
+ } );
+
+ // Make the deferred a promise
+ promise.promise( deferred );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( singleValue ) {
+ var
+
+ // count of uncompleted subordinates
+ remaining = arguments.length,
+
+ // count of unprocessed arguments
+ i = remaining,
+
+ // subordinate fulfillment data
+ resolveContexts = Array( i ),
+ resolveValues = slice.call( arguments ),
+
+ // the master Deferred
+ master = jQuery.Deferred(),
+
+ // subordinate callback factory
+ updateFunc = function( i ) {
+ return function( value ) {
+ resolveContexts[ i ] = this;
+ resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
+ if ( !( --remaining ) ) {
+ master.resolveWith( resolveContexts, resolveValues );
+ }
+ };
+ };
+
+ // Single- and empty arguments are adopted like Promise.resolve
+ if ( remaining <= 1 ) {
+ adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject,
+ !remaining );
+
+ // Use .then() to unwrap secondary thenables (cf. gh-3000)
+ if ( master.state() === "pending" ||
+ isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {
+
+ return master.then();
+ }
+ }
+
+ // Multiple arguments are aggregated like Promise.all array elements
+ while ( i-- ) {
+ adoptValue( resolveValues[ i ], updateFunc( i ), master.reject );
+ }
+
+ return master.promise();
+ }
+} );
+
+
+// These usually indicate a programmer mistake during development,
+// warn about them ASAP rather than swallowing them by default.
+var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
+
+jQuery.Deferred.exceptionHook = function( error, stack ) {
+
+ // Support: IE 8 - 9 only
+ // Console exists when dev tools are open, which can happen at any time
+ if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {
+ window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack );
+ }
+};
+
+
+
+
+jQuery.readyException = function( error ) {
+ window.setTimeout( function() {
+ throw error;
+ } );
+};
+
+
+
+
+// The deferred used on DOM ready
+var readyList = jQuery.Deferred();
+
+jQuery.fn.ready = function( fn ) {
+
+ readyList
+ .then( fn )
+
+ // Wrap jQuery.readyException in a function so that the lookup
+ // happens at the time of error handling instead of callback
+ // registration.
+ .catch( function( error ) {
+ jQuery.readyException( error );
+ } );
+
+ return this;
+};
+
+jQuery.extend( {
+
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+
+ // Abort if there are pending holds or we're already ready
+ if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
+ return;
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.resolveWith( document, [ jQuery ] );
+ }
+} );
+
+jQuery.ready.then = readyList.then;
+
+// The ready event handler and self cleanup method
+function completed() {
+ document.removeEventListener( "DOMContentLoaded", completed );
+ window.removeEventListener( "load", completed );
+ jQuery.ready();
+}
+
+// Catch cases where $(document).ready() is called
+// after the browser event has already occurred.
+// Support: IE <=9 - 10 only
+// Older IE sometimes signals "interactive" too soon
+if ( document.readyState === "complete" ||
+ ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {
+
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ window.setTimeout( jQuery.ready );
+
+} else {
+
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", completed );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", completed );
+}
+
+
+
+
+// Multifunctional method to get and set values of a collection
+// The value/s can optionally be executed if it's a function
+var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
+ var i = 0,
+ len = elems.length,
+ bulk = key == null;
+
+ // Sets many values
+ if ( toType( key ) === "object" ) {
+ chainable = true;
+ for ( i in key ) {
+ access( elems, fn, i, key[ i ], true, emptyGet, raw );
+ }
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ chainable = true;
+
+ if ( !isFunction( value ) ) {
+ raw = true;
+ }
+
+ if ( bulk ) {
+
+ // Bulk operations run against the entire set
+ if ( raw ) {
+ fn.call( elems, value );
+ fn = null;
+
+ // ...except when executing function values
+ } else {
+ bulk = fn;
+ fn = function( elem, _key, value ) {
+ return bulk.call( jQuery( elem ), value );
+ };
+ }
+ }
+
+ if ( fn ) {
+ for ( ; i < len; i++ ) {
+ fn(
+ elems[ i ], key, raw ?
+ value :
+ value.call( elems[ i ], i, fn( elems[ i ], key ) )
+ );
+ }
+ }
+ }
+
+ if ( chainable ) {
+ return elems;
+ }
+
+ // Gets
+ if ( bulk ) {
+ return fn.call( elems );
+ }
+
+ return len ? fn( elems[ 0 ], key ) : emptyGet;
+};
+
+
+// Matches dashed string for camelizing
+var rmsPrefix = /^-ms-/,
+ rdashAlpha = /-([a-z])/g;
+
+// Used by camelCase as callback to replace()
+function fcamelCase( _all, letter ) {
+ return letter.toUpperCase();
+}
+
+// Convert dashed to camelCase; used by the css and data modules
+// Support: IE <=9 - 11, Edge 12 - 15
+// Microsoft forgot to hump their vendor prefix (#9572)
+function camelCase( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+}
+var acceptData = function( owner ) {
+
+ // Accepts only:
+ // - Node
+ // - Node.ELEMENT_NODE
+ // - Node.DOCUMENT_NODE
+ // - Object
+ // - Any
+ return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
+};
+
+
+
+
+function Data() {
+ this.expando = jQuery.expando + Data.uid++;
+}
+
+Data.uid = 1;
+
+Data.prototype = {
+
+ cache: function( owner ) {
+
+ // Check if the owner object already has a cache
+ var value = owner[ this.expando ];
+
+ // If not, create one
+ if ( !value ) {
+ value = {};
+
+ // We can accept data for non-element nodes in modern browsers,
+ // but we should not, see #8335.
+ // Always return an empty object.
+ if ( acceptData( owner ) ) {
+
+ // If it is a node unlikely to be stringify-ed or looped over
+ // use plain assignment
+ if ( owner.nodeType ) {
+ owner[ this.expando ] = value;
+
+ // Otherwise secure it in a non-enumerable property
+ // configurable must be true to allow the property to be
+ // deleted when data is removed
+ } else {
+ Object.defineProperty( owner, this.expando, {
+ value: value,
+ configurable: true
+ } );
+ }
+ }
+ }
+
+ return value;
+ },
+ set: function( owner, data, value ) {
+ var prop,
+ cache = this.cache( owner );
+
+ // Handle: [ owner, key, value ] args
+ // Always use camelCase key (gh-2257)
+ if ( typeof data === "string" ) {
+ cache[ camelCase( data ) ] = value;
+
+ // Handle: [ owner, { properties } ] args
+ } else {
+
+ // Copy the properties one-by-one to the cache object
+ for ( prop in data ) {
+ cache[ camelCase( prop ) ] = data[ prop ];
+ }
+ }
+ return cache;
+ },
+ get: function( owner, key ) {
+ return key === undefined ?
+ this.cache( owner ) :
+
+ // Always use camelCase key (gh-2257)
+ owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];
+ },
+ access: function( owner, key, value ) {
+
+ // In cases where either:
+ //
+ // 1. No key was specified
+ // 2. A string key was specified, but no value provided
+ //
+ // Take the "read" path and allow the get method to determine
+ // which value to return, respectively either:
+ //
+ // 1. The entire cache object
+ // 2. The data stored at the key
+ //
+ if ( key === undefined ||
+ ( ( key && typeof key === "string" ) && value === undefined ) ) {
+
+ return this.get( owner, key );
+ }
+
+ // When the key is not a string, or both a key and value
+ // are specified, set or extend (existing objects) with either:
+ //
+ // 1. An object of properties
+ // 2. A key and value
+ //
+ this.set( owner, key, value );
+
+ // Since the "set" path can have two possible entry points
+ // return the expected data based on which path was taken[*]
+ return value !== undefined ? value : key;
+ },
+ remove: function( owner, key ) {
+ var i,
+ cache = owner[ this.expando ];
+
+ if ( cache === undefined ) {
+ return;
+ }
+
+ if ( key !== undefined ) {
+
+ // Support array or space separated string of keys
+ if ( Array.isArray( key ) ) {
+
+ // If key is an array of keys...
+ // We always set camelCase keys, so remove that.
+ key = key.map( camelCase );
+ } else {
+ key = camelCase( key );
+
+ // If a key with the spaces exists, use it.
+ // Otherwise, create an array by matching non-whitespace
+ key = key in cache ?
+ [ key ] :
+ ( key.match( rnothtmlwhite ) || [] );
+ }
+
+ i = key.length;
+
+ while ( i-- ) {
+ delete cache[ key[ i ] ];
+ }
+ }
+
+ // Remove the expando if there's no more data
+ if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
+
+ // Support: Chrome <=35 - 45
+ // Webkit & Blink performance suffers when deleting properties
+ // from DOM nodes, so set to undefined instead
+ // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
+ if ( owner.nodeType ) {
+ owner[ this.expando ] = undefined;
+ } else {
+ delete owner[ this.expando ];
+ }
+ }
+ },
+ hasData: function( owner ) {
+ var cache = owner[ this.expando ];
+ return cache !== undefined && !jQuery.isEmptyObject( cache );
+ }
+};
+var dataPriv = new Data();
+
+var dataUser = new Data();
+
+
+
+// Implementation Summary
+//
+// 1. Enforce API surface and semantic compatibility with 1.9.x branch
+// 2. Improve the module's maintainability by reducing the storage
+// paths to a single mechanism.
+// 3. Use the same single mechanism to support "private" and "user" data.
+// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
+// 5. Avoid exposing implementation details on user objects (eg. expando properties)
+// 6. Provide a clear path for implementation upgrade to WeakMap in 2014
+
+var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
+ rmultiDash = /[A-Z]/g;
+
+function getData( data ) {
+ if ( data === "true" ) {
+ return true;
+ }
+
+ if ( data === "false" ) {
+ return false;
+ }
+
+ if ( data === "null" ) {
+ return null;
+ }
+
+ // Only convert to a number if it doesn't change the string
+ if ( data === +data + "" ) {
+ return +data;
+ }
+
+ if ( rbrace.test( data ) ) {
+ return JSON.parse( data );
+ }
+
+ return data;
+}
+
+function dataAttr( elem, key, data ) {
+ var name;
+
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+ name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase();
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = getData( data );
+ } catch ( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ dataUser.set( elem, key, data );
+ } else {
+ data = undefined;
+ }
+ }
+ return data;
+}
+
+jQuery.extend( {
+ hasData: function( elem ) {
+ return dataUser.hasData( elem ) || dataPriv.hasData( elem );
+ },
+
+ data: function( elem, name, data ) {
+ return dataUser.access( elem, name, data );
+ },
+
+ removeData: function( elem, name ) {
+ dataUser.remove( elem, name );
+ },
+
+ // TODO: Now that all calls to _data and _removeData have been replaced
+ // with direct calls to dataPriv methods, these can be deprecated.
+ _data: function( elem, name, data ) {
+ return dataPriv.access( elem, name, data );
+ },
+
+ _removeData: function( elem, name ) {
+ dataPriv.remove( elem, name );
+ }
+} );
+
+jQuery.fn.extend( {
+ data: function( key, value ) {
+ var i, name, data,
+ elem = this[ 0 ],
+ attrs = elem && elem.attributes;
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = dataUser.get( elem );
+
+ if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) {
+ i = attrs.length;
+ while ( i-- ) {
+
+ // Support: IE 11 only
+ // The attrs elements can be null (#14894)
+ if ( attrs[ i ] ) {
+ name = attrs[ i ].name;
+ if ( name.indexOf( "data-" ) === 0 ) {
+ name = camelCase( name.slice( 5 ) );
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ }
+ dataPriv.set( elem, "hasDataAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each( function() {
+ dataUser.set( this, key );
+ } );
+ }
+
+ return access( this, function( value ) {
+ var data;
+
+ // The calling jQuery object (element matches) is not empty
+ // (and therefore has an element appears at this[ 0 ]) and the
+ // `value` parameter was not undefined. An empty jQuery object
+ // will result in `undefined` for elem = this[ 0 ] which will
+ // throw an exception if an attempt to read a data cache is made.
+ if ( elem && value === undefined ) {
+
+ // Attempt to get data from the cache
+ // The key will always be camelCased in Data
+ data = dataUser.get( elem, key );
+ if ( data !== undefined ) {
+ return data;
+ }
+
+ // Attempt to "discover" the data in
+ // HTML5 custom data-* attrs
+ data = dataAttr( elem, key );
+ if ( data !== undefined ) {
+ return data;
+ }
+
+ // We tried really hard, but the data doesn't exist.
+ return;
+ }
+
+ // Set the data...
+ this.each( function() {
+
+ // We always store the camelCased key
+ dataUser.set( this, key, value );
+ } );
+ }, null, value, arguments.length > 1, null, true );
+ },
+
+ removeData: function( key ) {
+ return this.each( function() {
+ dataUser.remove( this, key );
+ } );
+ }
+} );
+
+
+jQuery.extend( {
+ queue: function( elem, type, data ) {
+ var queue;
+
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ queue = dataPriv.get( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !queue || Array.isArray( data ) ) {
+ queue = dataPriv.access( elem, type, jQuery.makeArray( data ) );
+ } else {
+ queue.push( data );
+ }
+ }
+ return queue || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ startLength = queue.length,
+ fn = queue.shift(),
+ hooks = jQuery._queueHooks( elem, type ),
+ next = function() {
+ jQuery.dequeue( elem, type );
+ };
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ startLength--;
+ }
+
+ if ( fn ) {
+
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift( "inprogress" );
+ }
+
+ // Clear up the last queue stop function
+ delete hooks.stop;
+ fn.call( elem, next, hooks );
+ }
+
+ if ( !startLength && hooks ) {
+ hooks.empty.fire();
+ }
+ },
+
+ // Not public - generate a queueHooks object, or return the current one
+ _queueHooks: function( elem, type ) {
+ var key = type + "queueHooks";
+ return dataPriv.get( elem, key ) || dataPriv.access( elem, key, {
+ empty: jQuery.Callbacks( "once memory" ).add( function() {
+ dataPriv.remove( elem, [ type + "queue", key ] );
+ } )
+ } );
+ }
+} );
+
+jQuery.fn.extend( {
+ queue: function( type, data ) {
+ var setter = 2;
+
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
+ return jQuery.queue( this[ 0 ], type );
+ }
+
+ return data === undefined ?
+ this :
+ this.each( function() {
+ var queue = jQuery.queue( this, type, data );
+
+ // Ensure a hooks for this queue
+ jQuery._queueHooks( this, type );
+
+ if ( type === "fx" && queue[ 0 ] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ } );
+ },
+ dequeue: function( type ) {
+ return this.each( function() {
+ jQuery.dequeue( this, type );
+ } );
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, obj ) {
+ var tmp,
+ count = 1,
+ defer = jQuery.Deferred(),
+ elements = this,
+ i = this.length,
+ resolve = function() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ };
+
+ if ( typeof type !== "string" ) {
+ obj = type;
+ type = undefined;
+ }
+ type = type || "fx";
+
+ while ( i-- ) {
+ tmp = dataPriv.get( elements[ i ], type + "queueHooks" );
+ if ( tmp && tmp.empty ) {
+ count++;
+ tmp.empty.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( obj );
+ }
+} );
+var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;
+
+var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
+
+
+var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
+
+var documentElement = document.documentElement;
+
+
+
+ var isAttached = function( elem ) {
+ return jQuery.contains( elem.ownerDocument, elem );
+ },
+ composed = { composed: true };
+
+ // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only
+ // Check attachment across shadow DOM boundaries when possible (gh-3504)
+ // Support: iOS 10.0-10.2 only
+ // Early iOS 10 versions support `attachShadow` but not `getRootNode`,
+ // leading to errors. We need to check for `getRootNode`.
+ if ( documentElement.getRootNode ) {
+ isAttached = function( elem ) {
+ return jQuery.contains( elem.ownerDocument, elem ) ||
+ elem.getRootNode( composed ) === elem.ownerDocument;
+ };
+ }
+var isHiddenWithinTree = function( elem, el ) {
+
+ // isHiddenWithinTree might be called from jQuery#filter function;
+ // in that case, element will be second argument
+ elem = el || elem;
+
+ // Inline style trumps all
+ return elem.style.display === "none" ||
+ elem.style.display === "" &&
+
+ // Otherwise, check computed style
+ // Support: Firefox <=43 - 45
+ // Disconnected elements can have computed display: none, so first confirm that elem is
+ // in the document.
+ isAttached( elem ) &&
+
+ jQuery.css( elem, "display" ) === "none";
+ };
+
+
+
+function adjustCSS( elem, prop, valueParts, tween ) {
+ var adjusted, scale,
+ maxIterations = 20,
+ currentValue = tween ?
+ function() {
+ return tween.cur();
+ } :
+ function() {
+ return jQuery.css( elem, prop, "" );
+ },
+ initial = currentValue(),
+ unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
+
+ // Starting value computation is required for potential unit mismatches
+ initialInUnit = elem.nodeType &&
+ ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
+ rcssNum.exec( jQuery.css( elem, prop ) );
+
+ if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
+
+ // Support: Firefox <=54
+ // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)
+ initial = initial / 2;
+
+ // Trust units reported by jQuery.css
+ unit = unit || initialInUnit[ 3 ];
+
+ // Iteratively approximate from a nonzero starting point
+ initialInUnit = +initial || 1;
+
+ while ( maxIterations-- ) {
+
+ // Evaluate and update our best guess (doubling guesses that zero out).
+ // Finish if the scale equals or crosses 1 (making the old*new product non-positive).
+ jQuery.style( elem, prop, initialInUnit + unit );
+ if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {
+ maxIterations = 0;
+ }
+ initialInUnit = initialInUnit / scale;
+
+ }
+
+ initialInUnit = initialInUnit * 2;
+ jQuery.style( elem, prop, initialInUnit + unit );
+
+ // Make sure we update the tween properties later on
+ valueParts = valueParts || [];
+ }
+
+ if ( valueParts ) {
+ initialInUnit = +initialInUnit || +initial || 0;
+
+ // Apply relative offset (+=/-=) if specified
+ adjusted = valueParts[ 1 ] ?
+ initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
+ +valueParts[ 2 ];
+ if ( tween ) {
+ tween.unit = unit;
+ tween.start = initialInUnit;
+ tween.end = adjusted;
+ }
+ }
+ return adjusted;
+}
+
+
+var defaultDisplayMap = {};
+
+function getDefaultDisplay( elem ) {
+ var temp,
+ doc = elem.ownerDocument,
+ nodeName = elem.nodeName,
+ display = defaultDisplayMap[ nodeName ];
+
+ if ( display ) {
+ return display;
+ }
+
+ temp = doc.body.appendChild( doc.createElement( nodeName ) );
+ display = jQuery.css( temp, "display" );
+
+ temp.parentNode.removeChild( temp );
+
+ if ( display === "none" ) {
+ display = "block";
+ }
+ defaultDisplayMap[ nodeName ] = display;
+
+ return display;
+}
+
+function showHide( elements, show ) {
+ var display, elem,
+ values = [],
+ index = 0,
+ length = elements.length;
+
+ // Determine new display value for elements that need to change
+ for ( ; index < length; index++ ) {
+ elem = elements[ index ];
+ if ( !elem.style ) {
+ continue;
+ }
+
+ display = elem.style.display;
+ if ( show ) {
+
+ // Since we force visibility upon cascade-hidden elements, an immediate (and slow)
+ // check is required in this first loop unless we have a nonempty display value (either
+ // inline or about-to-be-restored)
+ if ( display === "none" ) {
+ values[ index ] = dataPriv.get( elem, "display" ) || null;
+ if ( !values[ index ] ) {
+ elem.style.display = "";
+ }
+ }
+ if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) {
+ values[ index ] = getDefaultDisplay( elem );
+ }
+ } else {
+ if ( display !== "none" ) {
+ values[ index ] = "none";
+
+ // Remember what we're overwriting
+ dataPriv.set( elem, "display", display );
+ }
+ }
+ }
+
+ // Set the display of the elements in a second loop to avoid constant reflow
+ for ( index = 0; index < length; index++ ) {
+ if ( values[ index ] != null ) {
+ elements[ index ].style.display = values[ index ];
+ }
+ }
+
+ return elements;
+}
+
+jQuery.fn.extend( {
+ show: function() {
+ return showHide( this, true );
+ },
+ hide: function() {
+ return showHide( this );
+ },
+ toggle: function( state ) {
+ if ( typeof state === "boolean" ) {
+ return state ? this.show() : this.hide();
+ }
+
+ return this.each( function() {
+ if ( isHiddenWithinTree( this ) ) {
+ jQuery( this ).show();
+ } else {
+ jQuery( this ).hide();
+ }
+ } );
+ }
+} );
+var rcheckableType = ( /^(?:checkbox|radio)$/i );
+
+var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i );
+
+var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i );
+
+
+
+( function() {
+ var fragment = document.createDocumentFragment(),
+ div = fragment.appendChild( document.createElement( "div" ) ),
+ input = document.createElement( "input" );
+
+ // Support: Android 4.0 - 4.3 only
+ // Check state lost if the name is set (#11217)
+ // Support: Windows Web Apps (WWA)
+ // `name` and `type` must use .setAttribute for WWA (#14901)
+ input.setAttribute( "type", "radio" );
+ input.setAttribute( "checked", "checked" );
+ input.setAttribute( "name", "t" );
+
+ div.appendChild( input );
+
+ // Support: Android <=4.1 only
+ // Older WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Support: IE <=11 only
+ // Make sure textarea (and checkbox) defaultValue is properly cloned
+ div.innerHTML = "<textarea>x</textarea>";
+ support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
+
+ // Support: IE <=9 only
+ // IE <=9 replaces <option> tags with their contents when inserted outside of
+ // the select element.
+ div.innerHTML = "<option></option>";
+ support.option = !!div.lastChild;
+} )();
+
+
+// We have to close these tags to support XHTML (#13200)
+var wrapMap = {
+
+ // XHTML parsers do not magically insert elements in the
+ // same way that tag soup parsers do. So we cannot shorten
+ // this by omitting <tbody> or other required elements.
+ thead: [ 1, "<table>", "</table>" ],
+ col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
+ tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+ td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+
+ _default: [ 0, "", "" ]
+};
+
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// Support: IE <=9 only
+if ( !support.option ) {
+ wrapMap.optgroup = wrapMap.option = [ 1, "<select multiple='multiple'>", "</select>" ];
+}
+
+
+function getAll( context, tag ) {
+
+ // Support: IE <=9 - 11 only
+ // Use typeof to avoid zero-argument method invocation on host objects (#15151)
+ var ret;
+
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
+ ret = context.getElementsByTagName( tag || "*" );
+
+ } else if ( typeof context.querySelectorAll !== "undefined" ) {
+ ret = context.querySelectorAll( tag || "*" );
+
+ } else {
+ ret = [];
+ }
+
+ if ( tag === undefined || tag && nodeName( context, tag ) ) {
+ return jQuery.merge( [ context ], ret );
+ }
+
+ return ret;
+}
+
+
+// Mark scripts as having already been evaluated
+function setGlobalEval( elems, refElements ) {
+ var i = 0,
+ l = elems.length;
+
+ for ( ; i < l; i++ ) {
+ dataPriv.set(
+ elems[ i ],
+ "globalEval",
+ !refElements || dataPriv.get( refElements[ i ], "globalEval" )
+ );
+ }
+}
+
+
+var rhtml = /<|&#?\w+;/;
+
+function buildFragment( elems, context, scripts, selection, ignored ) {
+ var elem, tmp, tag, wrap, attached, j,
+ fragment = context.createDocumentFragment(),
+ nodes = [],
+ i = 0,
+ l = elems.length;
+
+ for ( ; i < l; i++ ) {
+ elem = elems[ i ];
+
+ if ( elem || elem === 0 ) {
+
+ // Add nodes directly
+ if ( toType( elem ) === "object" ) {
+
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // push.apply(_, arraylike) throws on ancient WebKit
+ jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
+
+ // Convert non-html into a text node
+ } else if ( !rhtml.test( elem ) ) {
+ nodes.push( context.createTextNode( elem ) );
+
+ // Convert html into DOM nodes
+ } else {
+ tmp = tmp || fragment.appendChild( context.createElement( "div" ) );
+
+ // Deserialize a standard representation
+ tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
+ wrap = wrapMap[ tag ] || wrapMap._default;
+ tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];
+
+ // Descend through wrappers to the right content
+ j = wrap[ 0 ];
+ while ( j-- ) {
+ tmp = tmp.lastChild;
+ }
+
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // push.apply(_, arraylike) throws on ancient WebKit
+ jQuery.merge( nodes, tmp.childNodes );
+
+ // Remember the top-level container
+ tmp = fragment.firstChild;
+
+ // Ensure the created nodes are orphaned (#12392)
+ tmp.textContent = "";
+ }
+ }
+ }
+
+ // Remove wrapper from fragment
+ fragment.textContent = "";
+
+ i = 0;
+ while ( ( elem = nodes[ i++ ] ) ) {
+
+ // Skip elements already in the context collection (trac-4087)
+ if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
+ if ( ignored ) {
+ ignored.push( elem );
+ }
+ continue;
+ }
+
+ attached = isAttached( elem );
+
+ // Append to fragment
+ tmp = getAll( fragment.appendChild( elem ), "script" );
+
+ // Preserve script evaluation history
+ if ( attached ) {
+ setGlobalEval( tmp );
+ }
+
+ // Capture executables
+ if ( scripts ) {
+ j = 0;
+ while ( ( elem = tmp[ j++ ] ) ) {
+ if ( rscriptType.test( elem.type || "" ) ) {
+ scripts.push( elem );
+ }
+ }
+ }
+ }
+
+ return fragment;
+}
+
+
+var
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
+ rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
+
+function returnTrue() {
+ return true;
+}
+
+function returnFalse() {
+ return false;
+}
+
+// Support: IE <=9 - 11+
+// focus() and blur() are asynchronous, except when they are no-op.
+// So expect focus to be synchronous when the element is already active,
+// and blur to be synchronous when the element is not already active.
+// (focus and blur are always synchronous in other supported browsers,
+// this just defines when we can count on it).
+function expectSync( elem, type ) {
+ return ( elem === safeActiveElement() ) === ( type === "focus" );
+}
+
+// Support: IE <=9 only
+// Accessing document.activeElement can throw unexpectedly
+// https://bugs.jquery.com/ticket/13393
+function safeActiveElement() {
+ try {
+ return document.activeElement;
+ } catch ( err ) { }
+}
+
+function on( elem, types, selector, data, fn, one ) {
+ var origFn, type;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) {
+
+ // ( types-Object, data )
+ data = data || selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ on( elem, type, selector, data, types[ type ], one );
+ }
+ return elem;
+ }
+
+ if ( data == null && fn == null ) {
+
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return elem;
+ }
+
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
+ };
+
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+ }
+ return elem.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ } );
+}
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ global: {},
+
+ add: function( elem, types, handler, data, selector ) {
+
+ var handleObjIn, eventHandle, tmp,
+ events, t, handleObj,
+ special, handlers, type, namespaces, origType,
+ elemData = dataPriv.get( elem );
+
+ // Only attach events to objects that accept data
+ if ( !acceptData( elem ) ) {
+ return;
+ }
+
+ // Caller can pass in an object of custom data in lieu of the handler
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
+ }
+
+ // Ensure that invalid selectors throw exceptions at attach time
+ // Evaluate against documentElement in case elem is a non-element node (e.g., document)
+ if ( selector ) {
+ jQuery.find.matchesSelector( documentElement, selector );
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure and main handler, if this is the first
+ if ( !( events = elemData.events ) ) {
+ events = elemData.events = Object.create( null );
+ }
+ if ( !( eventHandle = elemData.handle ) ) {
+ eventHandle = elemData.handle = function( e ) {
+
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
+ jQuery.event.dispatch.apply( elem, arguments ) : undefined;
+ };
+ }
+
+ // Handle multiple events separated by a space
+ types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[ t ] ) || [];
+ type = origType = tmp[ 1 ];
+ namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
+
+ // There *must* be a type, no attaching namespace-only handlers
+ if ( !type ) {
+ continue;
+ }
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend( {
+ type: type,
+ origType: origType,
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
+ namespace: namespaces.join( "." )
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ if ( !( handlers = events[ type ] ) ) {
+ handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener if the special events handler returns false
+ if ( !special.setup ||
+ special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ },
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+
+ var j, origCount, tmp,
+ events, t, handleObj,
+ special, handlers, type, namespaces, origType,
+ elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );
+
+ if ( !elemData || !( events = elemData.events ) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
+ t = types.length;
+ while ( t-- ) {
+ tmp = rtypenamespace.exec( types[ t ] ) || [];
+ type = origType = tmp[ 1 ];
+ namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+ handlers = events[ type ] || [];
+ tmp = tmp[ 2 ] &&
+ new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );
+
+ // Remove matching events
+ origCount = j = handlers.length;
+ while ( j-- ) {
+ handleObj = handlers[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !tmp || tmp.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector ||
+ selector === "**" && handleObj.selector ) ) {
+ handlers.splice( j, 1 );
+
+ if ( handleObj.selector ) {
+ handlers.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+ }
+
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( origCount && !handlers.length ) {
+ if ( !special.teardown ||
+ special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
+
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove data and the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ dataPriv.remove( elem, "handle events" );
+ }
+ },
+
+ dispatch: function( nativeEvent ) {
+
+ var i, j, ret, matched, handleObj, handlerQueue,
+ args = new Array( arguments.length ),
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( nativeEvent ),
+
+ handlers = (
+ dataPriv.get( this, "events" ) || Object.create( null )
+ )[ event.type ] || [],
+ special = jQuery.event.special[ event.type ] || {};
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
+ args[ 0 ] = event;
+
+ for ( i = 1; i < arguments.length; i++ ) {
+ args[ i ] = arguments[ i ];
+ }
+
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers
+ handlerQueue = jQuery.event.handlers.call( this, event, handlers );
+
+ // Run delegates first; they may want to stop propagation beneath us
+ i = 0;
+ while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
+ event.currentTarget = matched.elem;
+
+ j = 0;
+ while ( ( handleObj = matched.handlers[ j++ ] ) &&
+ !event.isImmediatePropagationStopped() ) {
+
+ // If the event is namespaced, then each handler is only invoked if it is
+ // specially universal or its namespaces are a superset of the event's.
+ if ( !event.rnamespace || handleObj.namespace === false ||
+ event.rnamespace.test( handleObj.namespace ) ) {
+
+ event.handleObj = handleObj;
+ event.data = handleObj.data;
+
+ ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
+ handleObj.handler ).apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ if ( ( event.result = ret ) === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
+ return event.result;
+ },
+
+ handlers: function( event, handlers ) {
+ var i, handleObj, sel, matchedHandlers, matchedSelectors,
+ handlerQueue = [],
+ delegateCount = handlers.delegateCount,
+ cur = event.target;
+
+ // Find delegate handlers
+ if ( delegateCount &&
+
+ // Support: IE <=9
+ // Black-hole SVG <use> instance trees (trac-13180)
+ cur.nodeType &&
+
+ // Support: Firefox <=42
+ // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
+ // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
+ // Support: IE 11 only
+ // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
+ !( event.type === "click" && event.button >= 1 ) ) {
+
+ for ( ; cur !== this; cur = cur.parentNode || this ) {
+
+ // Don't check non-elements (#13208)
+ // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
+ if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {
+ matchedHandlers = [];
+ matchedSelectors = {};
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+
+ // Don't conflict with Object.prototype properties (#13203)
+ sel = handleObj.selector + " ";
+
+ if ( matchedSelectors[ sel ] === undefined ) {
+ matchedSelectors[ sel ] = handleObj.needsContext ?
+ jQuery( sel, this ).index( cur ) > -1 :
+ jQuery.find( sel, this, null, [ cur ] ).length;
+ }
+ if ( matchedSelectors[ sel ] ) {
+ matchedHandlers.push( handleObj );
+ }
+ }
+ if ( matchedHandlers.length ) {
+ handlerQueue.push( { elem: cur, handlers: matchedHandlers } );
+ }
+ }
+ }
+ }
+
+ // Add the remaining (directly-bound) handlers
+ cur = this;
+ if ( delegateCount < handlers.length ) {
+ handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );
+ }
+
+ return handlerQueue;
+ },
+
+ addProp: function( name, hook ) {
+ Object.defineProperty( jQuery.Event.prototype, name, {
+ enumerable: true,
+ configurable: true,
+
+ get: isFunction( hook ) ?
+ function() {
+ if ( this.originalEvent ) {
+ return hook( this.originalEvent );
+ }
+ } :
+ function() {
+ if ( this.originalEvent ) {
+ return this.originalEvent[ name ];
+ }
+ },
+
+ set: function( value ) {
+ Object.defineProperty( this, name, {
+ enumerable: true,
+ configurable: true,
+ writable: true,
+ value: value
+ } );
+ }
+ } );
+ },
+
+ fix: function( originalEvent ) {
+ return originalEvent[ jQuery.expando ] ?
+ originalEvent :
+ new jQuery.Event( originalEvent );
+ },
+
+ special: {
+ load: {
+
+ // Prevent triggered image.load events from bubbling to window.load
+ noBubble: true
+ },
+ click: {
+
+ // Utilize native event to ensure correct state for checkable inputs
+ setup: function( data ) {
+
+ // For mutual compressibility with _default, replace `this` access with a local var.
+ // `|| data` is dead code meant only to preserve the variable through minification.
+ var el = this || data;
+
+ // Claim the first handler
+ if ( rcheckableType.test( el.type ) &&
+ el.click && nodeName( el, "input" ) ) {
+
+ // dataPriv.set( el, "click", ... )
+ leverageNative( el, "click", returnTrue );
+ }
+
+ // Return false to allow normal processing in the caller
+ return false;
+ },
+ trigger: function( data ) {
+
+ // For mutual compressibility with _default, replace `this` access with a local var.
+ // `|| data` is dead code meant only to preserve the variable through minification.
+ var el = this || data;
+
+ // Force setup before triggering a click
+ if ( rcheckableType.test( el.type ) &&
+ el.click && nodeName( el, "input" ) ) {
+
+ leverageNative( el, "click" );
+ }
+
+ // Return non-false to allow normal event-path propagation
+ return true;
+ },
+
+ // For cross-browser consistency, suppress native .click() on links
+ // Also prevent it if we're currently inside a leveraged native-event stack
+ _default: function( event ) {
+ var target = event.target;
+ return rcheckableType.test( target.type ) &&
+ target.click && nodeName( target, "input" ) &&
+ dataPriv.get( target, "click" ) ||
+ nodeName( target, "a" );
+ }
+ },
+
+ beforeunload: {
+ postDispatch: function( event ) {
+
+ // Support: Firefox 20+
+ // Firefox doesn't alert if the returnValue field is not set.
+ if ( event.result !== undefined && event.originalEvent ) {
+ event.originalEvent.returnValue = event.result;
+ }
+ }
+ }
+ }
+};
+
+// Ensure the presence of an event listener that handles manually-triggered
+// synthetic events by interrupting progress until reinvoked in response to
+// *native* events that it fires directly, ensuring that state changes have
+// already occurred before other listeners are invoked.
+function leverageNative( el, type, expectSync ) {
+
+ // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add
+ if ( !expectSync ) {
+ if ( dataPriv.get( el, type ) === undefined ) {
+ jQuery.event.add( el, type, returnTrue );
+ }
+ return;
+ }
+
+ // Register the controller as a special universal handler for all event namespaces
+ dataPriv.set( el, type, false );
+ jQuery.event.add( el, type, {
+ namespace: false,
+ handler: function( event ) {
+ var notAsync, result,
+ saved = dataPriv.get( this, type );
+
+ if ( ( event.isTrigger & 1 ) && this[ type ] ) {
+
+ // Interrupt processing of the outer synthetic .trigger()ed event
+ // Saved data should be false in such cases, but might be a leftover capture object
+ // from an async native handler (gh-4350)
+ if ( !saved.length ) {
+
+ // Store arguments for use when handling the inner native event
+ // There will always be at least one argument (an event object), so this array
+ // will not be confused with a leftover capture object.
+ saved = slice.call( arguments );
+ dataPriv.set( this, type, saved );
+
+ // Trigger the native event and capture its result
+ // Support: IE <=9 - 11+
+ // focus() and blur() are asynchronous
+ notAsync = expectSync( this, type );
+ this[ type ]();
+ result = dataPriv.get( this, type );
+ if ( saved !== result || notAsync ) {
+ dataPriv.set( this, type, false );
+ } else {
+ result = {};
+ }
+ if ( saved !== result ) {
+
+ // Cancel the outer synthetic event
+ event.stopImmediatePropagation();
+ event.preventDefault();
+ return result.value;
+ }
+
+ // If this is an inner synthetic event for an event with a bubbling surrogate
+ // (focus or blur), assume that the surrogate already propagated from triggering the
+ // native event and prevent that from happening again here.
+ // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the
+ // bubbling surrogate propagates *after* the non-bubbling base), but that seems
+ // less bad than duplication.
+ } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {
+ event.stopPropagation();
+ }
+
+ // If this is a native event triggered above, everything is now in order
+ // Fire an inner synthetic event with the original arguments
+ } else if ( saved.length ) {
+
+ // ...and capture the result
+ dataPriv.set( this, type, {
+ value: jQuery.event.trigger(
+
+ // Support: IE <=9 - 11+
+ // Extend with the prototype to reset the above stopImmediatePropagation()
+ jQuery.extend( saved[ 0 ], jQuery.Event.prototype ),
+ saved.slice( 1 ),
+ this
+ )
+ } );
+
+ // Abort handling of the native event
+ event.stopImmediatePropagation();
+ }
+ }
+ } );
+}
+
+jQuery.removeEvent = function( elem, type, handle ) {
+
+ // This "if" is needed for plain objects
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle );
+ }
+};
+
+jQuery.Event = function( src, props ) {
+
+ // Allow instantiation without the 'new' keyword
+ if ( !( this instanceof jQuery.Event ) ) {
+ return new jQuery.Event( src, props );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = src.defaultPrevented ||
+ src.defaultPrevented === undefined &&
+
+ // Support: Android <=2.3 only
+ src.returnValue === false ?
+ returnTrue :
+ returnFalse;
+
+ // Create target properties
+ // Support: Safari <=6 - 7 only
+ // Target should not be a text node (#504, #13143)
+ this.target = ( src.target && src.target.nodeType === 3 ) ?
+ src.target.parentNode :
+ src.target;
+
+ this.currentTarget = src.currentTarget;
+ this.relatedTarget = src.relatedTarget;
+
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // Put explicitly provided properties onto the event object
+ if ( props ) {
+ jQuery.extend( this, props );
+ }
+
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || Date.now();
+
+ // Mark it as fixed
+ this[ jQuery.expando ] = true;
+};
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+ constructor: jQuery.Event,
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse,
+ isSimulated: false,
+
+ preventDefault: function() {
+ var e = this.originalEvent;
+
+ this.isDefaultPrevented = returnTrue;
+
+ if ( e && !this.isSimulated ) {
+ e.preventDefault();
+ }
+ },
+ stopPropagation: function() {
+ var e = this.originalEvent;
+
+ this.isPropagationStopped = returnTrue;
+
+ if ( e && !this.isSimulated ) {
+ e.stopPropagation();
+ }
+ },
+ stopImmediatePropagation: function() {
+ var e = this.originalEvent;
+
+ this.isImmediatePropagationStopped = returnTrue;
+
+ if ( e && !this.isSimulated ) {
+ e.stopImmediatePropagation();
+ }
+
+ this.stopPropagation();
+ }
+};
+
+// Includes all common event props including KeyEvent and MouseEvent specific props
+jQuery.each( {
+ altKey: true,
+ bubbles: true,
+ cancelable: true,
+ changedTouches: true,
+ ctrlKey: true,
+ detail: true,
+ eventPhase: true,
+ metaKey: true,
+ pageX: true,
+ pageY: true,
+ shiftKey: true,
+ view: true,
+ "char": true,
+ code: true,
+ charCode: true,
+ key: true,
+ keyCode: true,
+ button: true,
+ buttons: true,
+ clientX: true,
+ clientY: true,
+ offsetX: true,
+ offsetY: true,
+ pointerId: true,
+ pointerType: true,
+ screenX: true,
+ screenY: true,
+ targetTouches: true,
+ toElement: true,
+ touches: true,
+
+ which: function( event ) {
+ var button = event.button;
+
+ // Add which for key events
+ if ( event.which == null && rkeyEvent.test( event.type ) ) {
+ return event.charCode != null ? event.charCode : event.keyCode;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {
+ if ( button & 1 ) {
+ return 1;
+ }
+
+ if ( button & 2 ) {
+ return 3;
+ }
+
+ if ( button & 4 ) {
+ return 2;
+ }
+
+ return 0;
+ }
+
+ return event.which;
+ }
+}, jQuery.event.addProp );
+
+jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) {
+ jQuery.event.special[ type ] = {
+
+ // Utilize native event if possible so blur/focus sequence is correct
+ setup: function() {
+
+ // Claim the first handler
+ // dataPriv.set( this, "focus", ... )
+ // dataPriv.set( this, "blur", ... )
+ leverageNative( this, type, expectSync );
+
+ // Return false to allow normal processing in the caller
+ return false;
+ },
+ trigger: function() {
+
+ // Force setup before trigger
+ leverageNative( this, type );
+
+ // Return non-false to allow normal event-path propagation
+ return true;
+ },
+
+ delegateType: delegateType
+ };
+} );
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+// so that event delegation works in jQuery.
+// Do the same for pointerenter/pointerleave and pointerover/pointerout
+//
+// Support: Safari 7 only
+// Safari sends mouseenter too often; see:
+// https://bugs.chromium.org/p/chromium/issues/detail?id=470258
+// for the description of the bug (it existed in older Chrome versions as well).
+jQuery.each( {
+ mouseenter: "mouseover",
+ mouseleave: "mouseout",
+ pointerenter: "pointerover",
+ pointerleave: "pointerout"
+}, function( orig, fix ) {
+ jQuery.event.special[ orig ] = {
+ delegateType: fix,
+ bindType: fix,
+
+ handle: function( event ) {
+ var ret,
+ target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj;
+
+ // For mouseenter/leave call the handler if related is outside the target.
+ // NB: No relatedTarget if the mouse left/entered the browser window
+ if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
+ event.type = handleObj.origType;
+ ret = handleObj.handler.apply( this, arguments );
+ event.type = fix;
+ }
+ return ret;
+ }
+ };
+} );
+
+jQuery.fn.extend( {
+
+ on: function( types, selector, data, fn ) {
+ return on( this, types, selector, data, fn );
+ },
+ one: function( types, selector, data, fn ) {
+ return on( this, types, selector, data, fn, 1 );
+ },
+ off: function( types, selector, fn ) {
+ var handleObj, type;
+ if ( types && types.preventDefault && types.handleObj ) {
+
+ // ( event ) dispatched jQuery.Event
+ handleObj = types.handleObj;
+ jQuery( types.delegateTarget ).off(
+ handleObj.namespace ?
+ handleObj.origType + "." + handleObj.namespace :
+ handleObj.origType,
+ handleObj.selector,
+ handleObj.handler
+ );
+ return this;
+ }
+ if ( typeof types === "object" ) {
+
+ // ( types-object [, selector] )
+ for ( type in types ) {
+ this.off( type, selector, types[ type ] );
+ }
+ return this;
+ }
+ if ( selector === false || typeof selector === "function" ) {
+
+ // ( types [, fn] )
+ fn = selector;
+ selector = undefined;
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ }
+ return this.each( function() {
+ jQuery.event.remove( this, types, fn, selector );
+ } );
+ }
+} );
+
+
+var
+
+ // Support: IE <=10 - 11, Edge 12 - 13 only
+ // In IE/Edge using regex groups here causes severe slowdowns.
+ // See https://connect.microsoft.com/IE/feedback/details/1736512/
+ rnoInnerhtml = /<script|<style|<link/i,
+
+ // checked="checked" or checked
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+ rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;
+
+// Prefer a tbody over its parent table for containing new rows
+function manipulationTarget( elem, content ) {
+ if ( nodeName( elem, "table" ) &&
+ nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) {
+
+ return jQuery( elem ).children( "tbody" )[ 0 ] || elem;
+ }
+
+ return elem;
+}
+
+// Replace/restore the type attribute of script elements for safe DOM manipulation
+function disableScript( elem ) {
+ elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type;
+ return elem;
+}
+function restoreScript( elem ) {
+ if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) {
+ elem.type = elem.type.slice( 5 );
+ } else {
+ elem.removeAttribute( "type" );
+ }
+
+ return elem;
+}
+
+function cloneCopyEvent( src, dest ) {
+ var i, l, type, pdataOld, udataOld, udataCur, events;
+
+ if ( dest.nodeType !== 1 ) {
+ return;
+ }
+
+ // 1. Copy private data: events, handlers, etc.
+ if ( dataPriv.hasData( src ) ) {
+ pdataOld = dataPriv.get( src );
+ events = pdataOld.events;
+
+ if ( events ) {
+ dataPriv.remove( dest, "handle events" );
+
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type, events[ type ][ i ] );
+ }
+ }
+ }
+ }
+
+ // 2. Copy user data
+ if ( dataUser.hasData( src ) ) {
+ udataOld = dataUser.access( src );
+ udataCur = jQuery.extend( {}, udataOld );
+
+ dataUser.set( dest, udataCur );
+ }
+}
+
+// Fix IE bugs, see support tests
+function fixInput( src, dest ) {
+ var nodeName = dest.nodeName.toLowerCase();
+
+ // Fails to persist the checked state of a cloned checkbox or radio button.
+ if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
+ dest.checked = src.checked;
+
+ // Fails to return the selected option to the default selected state when cloning options
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
+ }
+}
+
+function domManip( collection, args, callback, ignored ) {
+
+ // Flatten any nested arrays
+ args = flat( args );
+
+ var fragment, first, scripts, hasScripts, node, doc,
+ i = 0,
+ l = collection.length,
+ iNoClone = l - 1,
+ value = args[ 0 ],
+ valueIsFunction = isFunction( value );
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( valueIsFunction ||
+ ( l > 1 && typeof value === "string" &&
+ !support.checkClone && rchecked.test( value ) ) ) {
+ return collection.each( function( index ) {
+ var self = collection.eq( index );
+ if ( valueIsFunction ) {
+ args[ 0 ] = value.call( this, index, self.html() );
+ }
+ domManip( self, args, callback, ignored );
+ } );
+ }
+
+ if ( l ) {
+ fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );
+ first = fragment.firstChild;
+
+ if ( fragment.childNodes.length === 1 ) {
+ fragment = first;
+ }
+
+ // Require either new content or an interest in ignored elements to invoke the callback
+ if ( first || ignored ) {
+ scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
+ hasScripts = scripts.length;
+
+ // Use the original fragment for the last item
+ // instead of the first because it can end up
+ // being emptied incorrectly in certain situations (#8070).
+ for ( ; i < l; i++ ) {
+ node = fragment;
+
+ if ( i !== iNoClone ) {
+ node = jQuery.clone( node, true, true );
+
+ // Keep references to cloned scripts for later restoration
+ if ( hasScripts ) {
+
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // push.apply(_, arraylike) throws on ancient WebKit
+ jQuery.merge( scripts, getAll( node, "script" ) );
+ }
+ }
+
+ callback.call( collection[ i ], node, i );
+ }
+
+ if ( hasScripts ) {
+ doc = scripts[ scripts.length - 1 ].ownerDocument;
+
+ // Reenable scripts
+ jQuery.map( scripts, restoreScript );
+
+ // Evaluate executable scripts on first document insertion
+ for ( i = 0; i < hasScripts; i++ ) {
+ node = scripts[ i ];
+ if ( rscriptType.test( node.type || "" ) &&
+ !dataPriv.access( node, "globalEval" ) &&
+ jQuery.contains( doc, node ) ) {
+
+ if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) {
+
+ // Optional AJAX dependency, but won't run scripts if not present
+ if ( jQuery._evalUrl && !node.noModule ) {
+ jQuery._evalUrl( node.src, {
+ nonce: node.nonce || node.getAttribute( "nonce" )
+ }, doc );
+ }
+ } else {
+ DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return collection;
+}
+
+function remove( elem, selector, keepData ) {
+ var node,
+ nodes = selector ? jQuery.filter( selector, elem ) : elem,
+ i = 0;
+
+ for ( ; ( node = nodes[ i ] ) != null; i++ ) {
+ if ( !keepData && node.nodeType === 1 ) {
+ jQuery.cleanData( getAll( node ) );
+ }
+
+ if ( node.parentNode ) {
+ if ( keepData && isAttached( node ) ) {
+ setGlobalEval( getAll( node, "script" ) );
+ }
+ node.parentNode.removeChild( node );
+ }
+ }
+
+ return elem;
+}
+
+jQuery.extend( {
+ htmlPrefilter: function( html ) {
+ return html;
+ },
+
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var i, l, srcElements, destElements,
+ clone = elem.cloneNode( true ),
+ inPage = isAttached( elem );
+
+ // Fix IE cloning issues
+ if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
+ !jQuery.isXMLDoc( elem ) ) {
+
+ // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2
+ destElements = getAll( clone );
+ srcElements = getAll( elem );
+
+ for ( i = 0, l = srcElements.length; i < l; i++ ) {
+ fixInput( srcElements[ i ], destElements[ i ] );
+ }
+ }
+
+ // Copy the events from the original to the clone
+ if ( dataAndEvents ) {
+ if ( deepDataAndEvents ) {
+ srcElements = srcElements || getAll( elem );
+ destElements = destElements || getAll( clone );
+
+ for ( i = 0, l = srcElements.length; i < l; i++ ) {
+ cloneCopyEvent( srcElements[ i ], destElements[ i ] );
+ }
+ } else {
+ cloneCopyEvent( elem, clone );
+ }
+ }
+
+ // Preserve script evaluation history
+ destElements = getAll( clone, "script" );
+ if ( destElements.length > 0 ) {
+ setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
+ }
+
+ // Return the cloned set
+ return clone;
+ },
+
+ cleanData: function( elems ) {
+ var data, elem, type,
+ special = jQuery.event.special,
+ i = 0;
+
+ for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {
+ if ( acceptData( elem ) ) {
+ if ( ( data = elem[ dataPriv.expando ] ) ) {
+ if ( data.events ) {
+ for ( type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+ }
+
+ // Support: Chrome <=35 - 45+
+ // Assign undefined instead of using delete, see Data#remove
+ elem[ dataPriv.expando ] = undefined;
+ }
+ if ( elem[ dataUser.expando ] ) {
+
+ // Support: Chrome <=35 - 45+
+ // Assign undefined instead of using delete, see Data#remove
+ elem[ dataUser.expando ] = undefined;
+ }
+ }
+ }
+ }
+} );
+
+jQuery.fn.extend( {
+ detach: function( selector ) {
+ return remove( this, selector, true );
+ },
+
+ remove: function( selector ) {
+ return remove( this, selector );
+ },
+
+ text: function( value ) {
+ return access( this, function( value ) {
+ return value === undefined ?
+ jQuery.text( this ) :
+ this.empty().each( function() {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ this.textContent = value;
+ }
+ } );
+ }, null, value, arguments.length );
+ },
+
+ append: function() {
+ return domManip( this, arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.appendChild( elem );
+ }
+ } );
+ },
+
+ prepend: function() {
+ return domManip( this, arguments, function( elem ) {
+ if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
+ var target = manipulationTarget( this, elem );
+ target.insertBefore( elem, target.firstChild );
+ }
+ } );
+ },
+
+ before: function() {
+ return domManip( this, arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this );
+ }
+ } );
+ },
+
+ after: function() {
+ return domManip( this, arguments, function( elem ) {
+ if ( this.parentNode ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ }
+ } );
+ },
+
+ empty: function() {
+ var elem,
+ i = 0;
+
+ for ( ; ( elem = this[ i ] ) != null; i++ ) {
+ if ( elem.nodeType === 1 ) {
+
+ // Prevent memory leaks
+ jQuery.cleanData( getAll( elem, false ) );
+
+ // Remove any remaining nodes
+ elem.textContent = "";
+ }
+ }
+
+ return this;
+ },
+
+ clone: function( dataAndEvents, deepDataAndEvents ) {
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+ return this.map( function() {
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+ } );
+ },
+
+ html: function( value ) {
+ return access( this, function( value ) {
+ var elem = this[ 0 ] || {},
+ i = 0,
+ l = this.length;
+
+ if ( value === undefined && elem.nodeType === 1 ) {
+ return elem.innerHTML;
+ }
+
+ // See if we can take a shortcut and just use innerHTML
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+ !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
+
+ value = jQuery.htmlPrefilter( value );
+
+ try {
+ for ( ; i < l; i++ ) {
+ elem = this[ i ] || {};
+
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( getAll( elem, false ) );
+ elem.innerHTML = value;
+ }
+ }
+
+ elem = 0;
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch ( e ) {}
+ }
+
+ if ( elem ) {
+ this.empty().append( value );
+ }
+ }, null, value, arguments.length );
+ },
+
+ replaceWith: function() {
+ var ignored = [];
+
+ // Make the changes, replacing each non-ignored context element with the new content
+ return domManip( this, arguments, function( elem ) {
+ var parent = this.parentNode;
+
+ if ( jQuery.inArray( this, ignored ) < 0 ) {
+ jQuery.cleanData( getAll( this ) );
+ if ( parent ) {
+ parent.replaceChild( elem, this );
+ }
+ }
+
+ // Force callback invocation
+ }, ignored );
+ }
+} );
+
+jQuery.each( {
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var elems,
+ ret = [],
+ insert = jQuery( selector ),
+ last = insert.length - 1,
+ i = 0;
+
+ for ( ; i <= last; i++ ) {
+ elems = i === last ? this : this.clone( true );
+ jQuery( insert[ i ] )[ original ]( elems );
+
+ // Support: Android <=4.0 only, PhantomJS 1 only
+ // .get() because push.apply(_, arraylike) throws on ancient WebKit
+ push.apply( ret, elems.get() );
+ }
+
+ return this.pushStack( ret );
+ };
+} );
+var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
+
+var getStyles = function( elem ) {
+
+ // Support: IE <=11 only, Firefox <=30 (#15098, #14150)
+ // IE throws on elements created in popups
+ // FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
+ var view = elem.ownerDocument.defaultView;
+
+ if ( !view || !view.opener ) {
+ view = window;
+ }
+
+ return view.getComputedStyle( elem );
+ };
+
+var swap = function( elem, options, callback ) {
+ var ret, name,
+ old = {};
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.call( elem );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+};
+
+
+var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
+
+
+
+( function() {
+
+ // Executing both pixelPosition & boxSizingReliable tests require only one layout
+ // so they're executed at the same time to save the second computation.
+ function computeStyleTests() {
+
+ // This is a singleton, we need to execute it only once
+ if ( !div ) {
+ return;
+ }
+
+ container.style.cssText = "position:absolute;left:-11111px;width:60px;" +
+ "margin-top:1px;padding:0;border:0";
+ div.style.cssText =
+ "position:relative;display:block;box-sizing:border-box;overflow:scroll;" +
+ "margin:auto;border:1px;padding:1px;" +
+ "width:60%;top:1%";
+ documentElement.appendChild( container ).appendChild( div );
+
+ var divStyle = window.getComputedStyle( div );
+ pixelPositionVal = divStyle.top !== "1%";
+
+ // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44
+ reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12;
+
+ // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3
+ // Some styles come back with percentage values, even though they shouldn't
+ div.style.right = "60%";
+ pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36;
+
+ // Support: IE 9 - 11 only
+ // Detect misreporting of content dimensions for box-sizing:border-box elements
+ boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36;
+
+ // Support: IE 9 only
+ // Detect overflow:scroll screwiness (gh-3699)
+ // Support: Chrome <=64
+ // Don't get tricked when zoom affects offsetWidth (gh-4029)
+ div.style.position = "absolute";
+ scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12;
+
+ documentElement.removeChild( container );
+
+ // Nullify the div so it wouldn't be stored in the memory and
+ // it will also be a sign that checks already performed
+ div = null;
+ }
+
+ function roundPixelMeasures( measure ) {
+ return Math.round( parseFloat( measure ) );
+ }
+
+ var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,
+ reliableTrDimensionsVal, reliableMarginLeftVal,
+ container = document.createElement( "div" ),
+ div = document.createElement( "div" );
+
+ // Finish early in limited (non-browser) environments
+ if ( !div.style ) {
+ return;
+ }
+
+ // Support: IE <=9 - 11 only
+ // Style of cloned element affects source element cloned (#8908)
+ div.style.backgroundClip = "content-box";
+ div.cloneNode( true ).style.backgroundClip = "";
+ support.clearCloneStyle = div.style.backgroundClip === "content-box";
+
+ jQuery.extend( support, {
+ boxSizingReliable: function() {
+ computeStyleTests();
+ return boxSizingReliableVal;
+ },
+ pixelBoxStyles: function() {
+ computeStyleTests();
+ return pixelBoxStylesVal;
+ },
+ pixelPosition: function() {
+ computeStyleTests();
+ return pixelPositionVal;
+ },
+ reliableMarginLeft: function() {
+ computeStyleTests();
+ return reliableMarginLeftVal;
+ },
+ scrollboxSize: function() {
+ computeStyleTests();
+ return scrollboxSizeVal;
+ },
+
+ // Support: IE 9 - 11+, Edge 15 - 18+
+ // IE/Edge misreport `getComputedStyle` of table rows with width/height
+ // set in CSS while `offset*` properties report correct values.
+ // Behavior in IE 9 is more subtle than in newer versions & it passes
+ // some versions of this test; make sure not to make it pass there!
+ reliableTrDimensions: function() {
+ var table, tr, trChild, trStyle;
+ if ( reliableTrDimensionsVal == null ) {
+ table = document.createElement( "table" );
+ tr = document.createElement( "tr" );
+ trChild = document.createElement( "div" );
+
+ table.style.cssText = "position:absolute;left:-11111px";
+ tr.style.height = "1px";
+ trChild.style.height = "9px";
+
+ documentElement
+ .appendChild( table )
+ .appendChild( tr )
+ .appendChild( trChild );
+
+ trStyle = window.getComputedStyle( tr );
+ reliableTrDimensionsVal = parseInt( trStyle.height ) > 3;
+
+ documentElement.removeChild( table );
+ }
+ return reliableTrDimensionsVal;
+ }
+ } );
+} )();
+
+
+function curCSS( elem, name, computed ) {
+ var width, minWidth, maxWidth, ret,
+
+ // Support: Firefox 51+
+ // Retrieving style before computed somehow
+ // fixes an issue with getting wrong values
+ // on detached elements
+ style = elem.style;
+
+ computed = computed || getStyles( elem );
+
+ // getPropertyValue is needed for:
+ // .css('filter') (IE 9 only, #12537)
+ // .css('--customProperty) (#3144)
+ if ( computed ) {
+ ret = computed.getPropertyValue( name ) || computed[ name ];
+
+ if ( ret === "" && !isAttached( elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+
+ // A tribute to the "awesome hack by Dean Edwards"
+ // Android Browser returns percentage for some values,
+ // but width seems to be reliably pixels.
+ // This is against the CSSOM draft spec:
+ // https://drafts.csswg.org/cssom/#resolved-values
+ if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) {
+
+ // Remember the original values
+ width = style.width;
+ minWidth = style.minWidth;
+ maxWidth = style.maxWidth;
+
+ // Put in the new values to get a computed value out
+ style.minWidth = style.maxWidth = style.width = ret;
+ ret = computed.width;
+
+ // Revert the changed values
+ style.width = width;
+ style.minWidth = minWidth;
+ style.maxWidth = maxWidth;
+ }
+ }
+
+ return ret !== undefined ?
+
+ // Support: IE <=9 - 11 only
+ // IE returns zIndex value as an integer.
+ ret + "" :
+ ret;
+}
+
+
+function addGetHookIf( conditionFn, hookFn ) {
+
+ // Define the hook, we'll check on the first run if it's really needed.
+ return {
+ get: function() {
+ if ( conditionFn() ) {
+
+ // Hook not needed (or it's not possible to use it due
+ // to missing dependency), remove it.
+ delete this.get;
+ return;
+ }
+
+ // Hook needed; redefine it so that the support test is not executed again.
+ return ( this.get = hookFn ).apply( this, arguments );
+ }
+ };
+}
+
+
+var cssPrefixes = [ "Webkit", "Moz", "ms" ],
+ emptyStyle = document.createElement( "div" ).style,
+ vendorProps = {};
+
+// Return a vendor-prefixed property or undefined
+function vendorPropName( name ) {
+
+ // Check for vendor prefixed names
+ var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),
+ i = cssPrefixes.length;
+
+ while ( i-- ) {
+ name = cssPrefixes[ i ] + capName;
+ if ( name in emptyStyle ) {
+ return name;
+ }
+ }
+}
+
+// Return a potentially-mapped jQuery.cssProps or vendor prefixed property
+function finalPropName( name ) {
+ var final = jQuery.cssProps[ name ] || vendorProps[ name ];
+
+ if ( final ) {
+ return final;
+ }
+ if ( name in emptyStyle ) {
+ return name;
+ }
+ return vendorProps[ name ] = vendorPropName( name ) || name;
+}
+
+
+var
+
+ // Swappable if display is none or starts with table
+ // except "table", "table-cell", or "table-caption"
+ // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
+ rdisplayswap = /^(none|table(?!-c[ea]).+)/,
+ rcustomProp = /^--/,
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+ cssNormalTransform = {
+ letterSpacing: "0",
+ fontWeight: "400"
+ };
+
+function setPositiveNumber( _elem, value, subtract ) {
+
+ // Any relative (+/-) values have already been
+ // normalized at this point
+ var matches = rcssNum.exec( value );
+ return matches ?
+
+ // Guard against undefined "subtract", e.g., when used as in cssHooks
+ Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) :
+ value;
+}
+
+function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {
+ var i = dimension === "width" ? 1 : 0,
+ extra = 0,
+ delta = 0;
+
+ // Adjustment may not be necessary
+ if ( box === ( isBorderBox ? "border" : "content" ) ) {
+ return 0;
+ }
+
+ for ( ; i < 4; i += 2 ) {
+
+ // Both box models exclude margin
+ if ( box === "margin" ) {
+ delta += jQuery.css( elem, box + cssExpand[ i ], true, styles );
+ }
+
+ // If we get here with a content-box, we're seeking "padding" or "border" or "margin"
+ if ( !isBorderBox ) {
+
+ // Add padding
+ delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+
+ // For "border" or "margin", add border
+ if ( box !== "padding" ) {
+ delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+
+ // But still keep track of it otherwise
+ } else {
+ extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+
+ // If we get here with a border-box (content + padding + border), we're seeking "content" or
+ // "padding" or "margin"
+ } else {
+
+ // For "content", subtract padding
+ if ( box === "content" ) {
+ delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
+ }
+
+ // For "content" or "padding", subtract border
+ if ( box !== "margin" ) {
+ delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
+ }
+ }
+ }
+
+ // Account for positive content-box scroll gutter when requested by providing computedVal
+ if ( !isBorderBox && computedVal >= 0 ) {
+
+ // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border
+ // Assuming integer scroll gutter, subtract the rest and round down
+ delta += Math.max( 0, Math.ceil(
+ elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
+ computedVal -
+ delta -
+ extra -
+ 0.5
+
+ // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter
+ // Use an explicit zero to avoid NaN (gh-3964)
+ ) ) || 0;
+ }
+
+ return delta;
+}
+
+function getWidthOrHeight( elem, dimension, extra ) {
+
+ // Start with computed style
+ var styles = getStyles( elem ),
+
+ // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322).
+ // Fake content-box until we know it's needed to know the true value.
+ boxSizingNeeded = !support.boxSizingReliable() || extra,
+ isBorderBox = boxSizingNeeded &&
+ jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ valueIsBorderBox = isBorderBox,
+
+ val = curCSS( elem, dimension, styles ),
+ offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 );
+
+ // Support: Firefox <=54
+ // Return a confounding non-pixel value or feign ignorance, as appropriate.
+ if ( rnumnonpx.test( val ) ) {
+ if ( !extra ) {
+ return val;
+ }
+ val = "auto";
+ }
+
+
+ // Support: IE 9 - 11 only
+ // Use offsetWidth/offsetHeight for when box sizing is unreliable.
+ // In those cases, the computed value can be trusted to be border-box.
+ if ( ( !support.boxSizingReliable() && isBorderBox ||
+
+ // Support: IE 10 - 11+, Edge 15 - 18+
+ // IE/Edge misreport `getComputedStyle` of table rows with width/height
+ // set in CSS while `offset*` properties report correct values.
+ // Interestingly, in some cases IE 9 doesn't suffer from this issue.
+ !support.reliableTrDimensions() && nodeName( elem, "tr" ) ||
+
+ // Fall back to offsetWidth/offsetHeight when value is "auto"
+ // This happens for inline elements with no explicit setting (gh-3571)
+ val === "auto" ||
+
+ // Support: Android <=4.1 - 4.3 only
+ // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)
+ !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) &&
+
+ // Make sure the element is visible & connected
+ elem.getClientRects().length ) {
+
+ isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
+
+ // Where available, offsetWidth/offsetHeight approximate border box dimensions.
+ // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the
+ // retrieved value as a content box dimension.
+ valueIsBorderBox = offsetProp in elem;
+ if ( valueIsBorderBox ) {
+ val = elem[ offsetProp ];
+ }
+ }
+
+ // Normalize "" and auto
+ val = parseFloat( val ) || 0;
+
+ // Adjust for the element's box model
+ return ( val +
+ boxModelAdjustment(
+ elem,
+ dimension,
+ extra || ( isBorderBox ? "border" : "content" ),
+ valueIsBorderBox,
+ styles,
+
+ // Provide the current computed size to request scroll gutter calculation (gh-3589)
+ val
+ )
+ ) + "px";
+}
+
+jQuery.extend( {
+
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity" );
+ return ret === "" ? "1" : ret;
+ }
+ }
+ }
+ },
+
+ // Don't automatically add "px" to these possibly-unitless properties
+ cssNumber: {
+ "animationIterationCount": true,
+ "columnCount": true,
+ "fillOpacity": true,
+ "flexGrow": true,
+ "flexShrink": true,
+ "fontWeight": true,
+ "gridArea": true,
+ "gridColumn": true,
+ "gridColumnEnd": true,
+ "gridColumnStart": true,
+ "gridRow": true,
+ "gridRowEnd": true,
+ "gridRowStart": true,
+ "lineHeight": true,
+ "opacity": true,
+ "order": true,
+ "orphans": true,
+ "widows": true,
+ "zIndex": true,
+ "zoom": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {},
+
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
+ }
+
+ // Make sure that we're working with the right name
+ var ret, type, hooks,
+ origName = camelCase( name ),
+ isCustomProp = rcustomProp.test( name ),
+ style = elem.style;
+
+ // Make sure that we're working with the right name. We don't
+ // want to query the value if it is a CSS custom property
+ // since they are user-defined.
+ if ( !isCustomProp ) {
+ name = finalPropName( origName );
+ }
+
+ // Gets hook for the prefixed version, then unprefixed version
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // Convert "+=" or "-=" to relative numbers (#7345)
+ if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
+ value = adjustCSS( elem, name, ret );
+
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // Make sure that null and NaN values aren't set (#7116)
+ if ( value == null || value !== value ) {
+ return;
+ }
+
+ // If a number was passed in, add the unit (except for certain CSS properties)
+ // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append
+ // "px" to a few hardcoded values.
+ if ( type === "number" && !isCustomProp ) {
+ value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
+ }
+
+ // background-* props affect original clone's values
+ if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
+ style[ name ] = "inherit";
+ }
+
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !( "set" in hooks ) ||
+ ( value = hooks.set( elem, value, extra ) ) !== undefined ) {
+
+ if ( isCustomProp ) {
+ style.setProperty( name, value );
+ } else {
+ style[ name ] = value;
+ }
+ }
+
+ } else {
+
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks &&
+ ( ret = hooks.get( elem, false, extra ) ) !== undefined ) {
+
+ return ret;
+ }
+
+ // Otherwise just get the value from the style object
+ return style[ name ];
+ }
+ },
+
+ css: function( elem, name, extra, styles ) {
+ var val, num, hooks,
+ origName = camelCase( name ),
+ isCustomProp = rcustomProp.test( name );
+
+ // Make sure that we're working with the right name. We don't
+ // want to modify the value if it is a CSS custom property
+ // since they are user-defined.
+ if ( !isCustomProp ) {
+ name = finalPropName( origName );
+ }
+
+ // Try prefixed name followed by the unprefixed name
+ hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
+
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks ) {
+ val = hooks.get( elem, true, extra );
+ }
+
+ // Otherwise, if a way to get the computed value exists, use that
+ if ( val === undefined ) {
+ val = curCSS( elem, name, styles );
+ }
+
+ // Convert "normal" to computed value
+ if ( val === "normal" && name in cssNormalTransform ) {
+ val = cssNormalTransform[ name ];
+ }
+
+ // Make numeric if forced or a qualifier was provided and val looks numeric
+ if ( extra === "" || extra ) {
+ num = parseFloat( val );
+ return extra === true || isFinite( num ) ? num || 0 : val;
+ }
+
+ return val;
+ }
+} );
+
+jQuery.each( [ "height", "width" ], function( _i, dimension ) {
+ jQuery.cssHooks[ dimension ] = {
+ get: function( elem, computed, extra ) {
+ if ( computed ) {
+
+ // Certain elements can have dimension info if we invisibly show them
+ // but it must have a current display style that would benefit
+ return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
+
+ // Support: Safari 8+
+ // Table columns in Safari have non-zero offsetWidth & zero
+ // getBoundingClientRect().width unless display is changed.
+ // Support: IE <=11 only
+ // Running getBoundingClientRect on a disconnected node
+ // in IE throws an error.
+ ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?
+ swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, dimension, extra );
+ } ) :
+ getWidthOrHeight( elem, dimension, extra );
+ }
+ },
+
+ set: function( elem, value, extra ) {
+ var matches,
+ styles = getStyles( elem ),
+
+ // Only read styles.position if the test has a chance to fail
+ // to avoid forcing a reflow.
+ scrollboxSizeBuggy = !support.scrollboxSize() &&
+ styles.position === "absolute",
+
+ // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991)
+ boxSizingNeeded = scrollboxSizeBuggy || extra,
+ isBorderBox = boxSizingNeeded &&
+ jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
+ subtract = extra ?
+ boxModelAdjustment(
+ elem,
+ dimension,
+ extra,
+ isBorderBox,
+ styles
+ ) :
+ 0;
+
+ // Account for unreliable border-box dimensions by comparing offset* to computed and
+ // faking a content-box to get border and padding (gh-3699)
+ if ( isBorderBox && scrollboxSizeBuggy ) {
+ subtract -= Math.ceil(
+ elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
+ parseFloat( styles[ dimension ] ) -
+ boxModelAdjustment( elem, dimension, "border", false, styles ) -
+ 0.5
+ );
+ }
+
+ // Convert to pixels if value adjustment is needed
+ if ( subtract && ( matches = rcssNum.exec( value ) ) &&
+ ( matches[ 3 ] || "px" ) !== "px" ) {
+
+ elem.style[ dimension ] = value;
+ value = jQuery.css( elem, dimension );
+ }
+
+ return setPositiveNumber( elem, value, subtract );
+ }
+ };
+} );
+
+jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
+ function( elem, computed ) {
+ if ( computed ) {
+ return ( parseFloat( curCSS( elem, "marginLeft" ) ) ||
+ elem.getBoundingClientRect().left -
+ swap( elem, { marginLeft: 0 }, function() {
+ return elem.getBoundingClientRect().left;
+ } )
+ ) + "px";
+ }
+ }
+);
+
+// These hooks are used by animate to expand properties
+jQuery.each( {
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i = 0,
+ expanded = {},
+
+ // Assumes a single number if not a string
+ parts = typeof value === "string" ? value.split( " " ) : [ value ];
+
+ for ( ; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+
+ if ( prefix !== "margin" ) {
+ jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
+ }
+} );
+
+jQuery.fn.extend( {
+ css: function( name, value ) {
+ return access( this, function( elem, name, value ) {
+ var styles, len,
+ map = {},
+ i = 0;
+
+ if ( Array.isArray( name ) ) {
+ styles = getStyles( elem );
+ len = name.length;
+
+ for ( ; i < len; i++ ) {
+ map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
+ }
+
+ return map;
+ }
+
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ }, name, value, arguments.length > 1 );
+ }
+} );
+
+
+function Tween( elem, options, prop, end, easing ) {
+ return new Tween.prototype.init( elem, options, prop, end, easing );
+}
+jQuery.Tween = Tween;
+
+Tween.prototype = {
+ constructor: Tween,
+ init: function( elem, options, prop, end, easing, unit ) {
+ this.elem = elem;
+ this.prop = prop;
+ this.easing = easing || jQuery.easing._default;
+ this.options = options;
+ this.start = this.now = this.cur();
+ this.end = end;
+ this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
+ },
+ cur: function() {
+ var hooks = Tween.propHooks[ this.prop ];
+
+ return hooks && hooks.get ?
+ hooks.get( this ) :
+ Tween.propHooks._default.get( this );
+ },
+ run: function( percent ) {
+ var eased,
+ hooks = Tween.propHooks[ this.prop ];
+
+ if ( this.options.duration ) {
+ this.pos = eased = jQuery.easing[ this.easing ](
+ percent, this.options.duration * percent, 0, 1, this.options.duration
+ );
+ } else {
+ this.pos = eased = percent;
+ }
+ this.now = ( this.end - this.start ) * eased + this.start;
+
+ if ( this.options.step ) {
+ this.options.step.call( this.elem, this.now, this );
+ }
+
+ if ( hooks && hooks.set ) {
+ hooks.set( this );
+ } else {
+ Tween.propHooks._default.set( this );
+ }
+ return this;
+ }
+};
+
+Tween.prototype.init.prototype = Tween.prototype;
+
+Tween.propHooks = {
+ _default: {
+ get: function( tween ) {
+ var result;
+
+ // Use a property on the element directly when it is not a DOM element,
+ // or when there is no matching style property that exists.
+ if ( tween.elem.nodeType !== 1 ||
+ tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {
+ return tween.elem[ tween.prop ];
+ }
+
+ // Passing an empty string as a 3rd parameter to .css will automatically
+ // attempt a parseFloat and fallback to a string if the parse fails.
+ // Simple values such as "10px" are parsed to Float;
+ // complex values such as "rotate(1rad)" are returned as-is.
+ result = jQuery.css( tween.elem, tween.prop, "" );
+
+ // Empty strings, null, undefined and "auto" are converted to 0.
+ return !result || result === "auto" ? 0 : result;
+ },
+ set: function( tween ) {
+
+ // Use step hook for back compat.
+ // Use cssHook if its there.
+ // Use .style if available and use plain properties where available.
+ if ( jQuery.fx.step[ tween.prop ] ) {
+ jQuery.fx.step[ tween.prop ]( tween );
+ } else if ( tween.elem.nodeType === 1 && (
+ jQuery.cssHooks[ tween.prop ] ||
+ tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) {
+ jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
+ } else {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+ }
+};
+
+// Support: IE <=9 only
+// Panic based approach to setting things on disconnected nodes
+Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
+ set: function( tween ) {
+ if ( tween.elem.nodeType && tween.elem.parentNode ) {
+ tween.elem[ tween.prop ] = tween.now;
+ }
+ }
+};
+
+jQuery.easing = {
+ linear: function( p ) {
+ return p;
+ },
+ swing: function( p ) {
+ return 0.5 - Math.cos( p * Math.PI ) / 2;
+ },
+ _default: "swing"
+};
+
+jQuery.fx = Tween.prototype.init;
+
+// Back compat <1.8 extension point
+jQuery.fx.step = {};
+
+
+
+
+var
+ fxNow, inProgress,
+ rfxtypes = /^(?:toggle|show|hide)$/,
+ rrun = /queueHooks$/;
+
+function schedule() {
+ if ( inProgress ) {
+ if ( document.hidden === false && window.requestAnimationFrame ) {
+ window.requestAnimationFrame( schedule );
+ } else {
+ window.setTimeout( schedule, jQuery.fx.interval );
+ }
+
+ jQuery.fx.tick();
+ }
+}
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+ window.setTimeout( function() {
+ fxNow = undefined;
+ } );
+ return ( fxNow = Date.now() );
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, includeWidth ) {
+ var which,
+ i = 0,
+ attrs = { height: type };
+
+ // If we include width, step value is 1 to do all cssExpand values,
+ // otherwise step value is 2 to skip over Left and Right
+ includeWidth = includeWidth ? 1 : 0;
+ for ( ; i < 4; i += 2 - includeWidth ) {
+ which = cssExpand[ i ];
+ attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
+ }
+
+ if ( includeWidth ) {
+ attrs.opacity = attrs.width = type;
+ }
+
+ return attrs;
+}
+
+function createTween( value, prop, animation ) {
+ var tween,
+ collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
+ index = 0,
+ length = collection.length;
+ for ( ; index < length; index++ ) {
+ if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {
+
+ // We're done with this property
+ return tween;
+ }
+ }
+}
+
+function defaultPrefilter( elem, props, opts ) {
+ var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,
+ isBox = "width" in props || "height" in props,
+ anim = this,
+ orig = {},
+ style = elem.style,
+ hidden = elem.nodeType && isHiddenWithinTree( elem ),
+ dataShow = dataPriv.get( elem, "fxshow" );
+
+ // Queue-skipping animations hijack the fx hooks
+ if ( !opts.queue ) {
+ hooks = jQuery._queueHooks( elem, "fx" );
+ if ( hooks.unqueued == null ) {
+ hooks.unqueued = 0;
+ oldfire = hooks.empty.fire;
+ hooks.empty.fire = function() {
+ if ( !hooks.unqueued ) {
+ oldfire();
+ }
+ };
+ }
+ hooks.unqueued++;
+
+ anim.always( function() {
+
+ // Ensure the complete handler is called before this completes
+ anim.always( function() {
+ hooks.unqueued--;
+ if ( !jQuery.queue( elem, "fx" ).length ) {
+ hooks.empty.fire();
+ }
+ } );
+ } );
+ }
+
+ // Detect show/hide animations
+ for ( prop in props ) {
+ value = props[ prop ];
+ if ( rfxtypes.test( value ) ) {
+ delete props[ prop ];
+ toggle = toggle || value === "toggle";
+ if ( value === ( hidden ? "hide" : "show" ) ) {
+
+ // Pretend to be hidden if this is a "show" and
+ // there is still data from a stopped show/hide
+ if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
+ hidden = true;
+
+ // Ignore all other no-op show/hide data
+ } else {
+ continue;
+ }
+ }
+ orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
+ }
+ }
+
+ // Bail out if this is a no-op like .hide().hide()
+ propTween = !jQuery.isEmptyObject( props );
+ if ( !propTween && jQuery.isEmptyObject( orig ) ) {
+ return;
+ }
+
+ // Restrict "overflow" and "display" styles during box animations
+ if ( isBox && elem.nodeType === 1 ) {
+
+ // Support: IE <=9 - 11, Edge 12 - 15
+ // Record all 3 overflow attributes because IE does not infer the shorthand
+ // from identically-valued overflowX and overflowY and Edge just mirrors
+ // the overflowX value there.
+ opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
+
+ // Identify a display type, preferring old show/hide data over the CSS cascade
+ restoreDisplay = dataShow && dataShow.display;
+ if ( restoreDisplay == null ) {
+ restoreDisplay = dataPriv.get( elem, "display" );
+ }
+ display = jQuery.css( elem, "display" );
+ if ( display === "none" ) {
+ if ( restoreDisplay ) {
+ display = restoreDisplay;
+ } else {
+
+ // Get nonempty value(s) by temporarily forcing visibility
+ showHide( [ elem ], true );
+ restoreDisplay = elem.style.display || restoreDisplay;
+ display = jQuery.css( elem, "display" );
+ showHide( [ elem ] );
+ }
+ }
+
+ // Animate inline elements as inline-block
+ if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) {
+ if ( jQuery.css( elem, "float" ) === "none" ) {
+
+ // Restore the original display value at the end of pure show/hide animations
+ if ( !propTween ) {
+ anim.done( function() {
+ style.display = restoreDisplay;
+ } );
+ if ( restoreDisplay == null ) {
+ display = style.display;
+ restoreDisplay = display === "none" ? "" : display;
+ }
+ }
+ style.display = "inline-block";
+ }
+ }
+ }
+
+ if ( opts.overflow ) {
+ style.overflow = "hidden";
+ anim.always( function() {
+ style.overflow = opts.overflow[ 0 ];
+ style.overflowX = opts.overflow[ 1 ];
+ style.overflowY = opts.overflow[ 2 ];
+ } );
+ }
+
+ // Implement show/hide animations
+ propTween = false;
+ for ( prop in orig ) {
+
+ // General show/hide setup for this element animation
+ if ( !propTween ) {
+ if ( dataShow ) {
+ if ( "hidden" in dataShow ) {
+ hidden = dataShow.hidden;
+ }
+ } else {
+ dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } );
+ }
+
+ // Store hidden/visible for toggle so `.stop().toggle()` "reverses"
+ if ( toggle ) {
+ dataShow.hidden = !hidden;
+ }
+
+ // Show elements before animating them
+ if ( hidden ) {
+ showHide( [ elem ], true );
+ }
+
+ /* eslint-disable no-loop-func */
+
+ anim.done( function() {
+
+ /* eslint-enable no-loop-func */
+
+ // The final step of a "hide" animation is actually hiding the element
+ if ( !hidden ) {
+ showHide( [ elem ] );
+ }
+ dataPriv.remove( elem, "fxshow" );
+ for ( prop in orig ) {
+ jQuery.style( elem, prop, orig[ prop ] );
+ }
+ } );
+ }
+
+ // Per-property setup
+ propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
+ if ( !( prop in dataShow ) ) {
+ dataShow[ prop ] = propTween.start;
+ if ( hidden ) {
+ propTween.end = propTween.start;
+ propTween.start = 0;
+ }
+ }
+ }
+}
+
+function propFilter( props, specialEasing ) {
+ var index, name, easing, value, hooks;
+
+ // camelCase, specialEasing and expand cssHook pass
+ for ( index in props ) {
+ name = camelCase( index );
+ easing = specialEasing[ name ];
+ value = props[ index ];
+ if ( Array.isArray( value ) ) {
+ easing = value[ 1 ];
+ value = props[ index ] = value[ 0 ];
+ }
+
+ if ( index !== name ) {
+ props[ name ] = value;
+ delete props[ index ];
+ }
+
+ hooks = jQuery.cssHooks[ name ];
+ if ( hooks && "expand" in hooks ) {
+ value = hooks.expand( value );
+ delete props[ name ];
+
+ // Not quite $.extend, this won't overwrite existing keys.
+ // Reusing 'index' because we have the correct "name"
+ for ( index in value ) {
+ if ( !( index in props ) ) {
+ props[ index ] = value[ index ];
+ specialEasing[ index ] = easing;
+ }
+ }
+ } else {
+ specialEasing[ name ] = easing;
+ }
+ }
+}
+
+function Animation( elem, properties, options ) {
+ var result,
+ stopped,
+ index = 0,
+ length = Animation.prefilters.length,
+ deferred = jQuery.Deferred().always( function() {
+
+ // Don't match elem in the :animated selector
+ delete tick.elem;
+ } ),
+ tick = function() {
+ if ( stopped ) {
+ return false;
+ }
+ var currentTime = fxNow || createFxNow(),
+ remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
+
+ // Support: Android 2.3 only
+ // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
+ temp = remaining / animation.duration || 0,
+ percent = 1 - temp,
+ index = 0,
+ length = animation.tweens.length;
+
+ for ( ; index < length; index++ ) {
+ animation.tweens[ index ].run( percent );
+ }
+
+ deferred.notifyWith( elem, [ animation, percent, remaining ] );
+
+ // If there's more to do, yield
+ if ( percent < 1 && length ) {
+ return remaining;
+ }
+
+ // If this was an empty animation, synthesize a final progress notification
+ if ( !length ) {
+ deferred.notifyWith( elem, [ animation, 1, 0 ] );
+ }
+
+ // Resolve the animation and report its conclusion
+ deferred.resolveWith( elem, [ animation ] );
+ return false;
+ },
+ animation = deferred.promise( {
+ elem: elem,
+ props: jQuery.extend( {}, properties ),
+ opts: jQuery.extend( true, {
+ specialEasing: {},
+ easing: jQuery.easing._default
+ }, options ),
+ originalProperties: properties,
+ originalOptions: options,
+ startTime: fxNow || createFxNow(),
+ duration: options.duration,
+ tweens: [],
+ createTween: function( prop, end ) {
+ var tween = jQuery.Tween( elem, animation.opts, prop, end,
+ animation.opts.specialEasing[ prop ] || animation.opts.easing );
+ animation.tweens.push( tween );
+ return tween;
+ },
+ stop: function( gotoEnd ) {
+ var index = 0,
+
+ // If we are going to the end, we want to run all the tweens
+ // otherwise we skip this part
+ length = gotoEnd ? animation.tweens.length : 0;
+ if ( stopped ) {
+ return this;
+ }
+ stopped = true;
+ for ( ; index < length; index++ ) {
+ animation.tweens[ index ].run( 1 );
+ }
+
+ // Resolve when we played the last frame; otherwise, reject
+ if ( gotoEnd ) {
+ deferred.notifyWith( elem, [ animation, 1, 0 ] );
+ deferred.resolveWith( elem, [ animation, gotoEnd ] );
+ } else {
+ deferred.rejectWith( elem, [ animation, gotoEnd ] );
+ }
+ return this;
+ }
+ } ),
+ props = animation.props;
+
+ propFilter( props, animation.opts.specialEasing );
+
+ for ( ; index < length; index++ ) {
+ result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
+ if ( result ) {
+ if ( isFunction( result.stop ) ) {
+ jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
+ result.stop.bind( result );
+ }
+ return result;
+ }
+ }
+
+ jQuery.map( props, createTween, animation );
+
+ if ( isFunction( animation.opts.start ) ) {
+ animation.opts.start.call( elem, animation );
+ }
+
+ // Attach callbacks from options
+ animation
+ .progress( animation.opts.progress )
+ .done( animation.opts.done, animation.opts.complete )
+ .fail( animation.opts.fail )
+ .always( animation.opts.always );
+
+ jQuery.fx.timer(
+ jQuery.extend( tick, {
+ elem: elem,
+ anim: animation,
+ queue: animation.opts.queue
+ } )
+ );
+
+ return animation;
+}
+
+jQuery.Animation = jQuery.extend( Animation, {
+
+ tweeners: {
+ "*": [ function( prop, value ) {
+ var tween = this.createTween( prop, value );
+ adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
+ return tween;
+ } ]
+ },
+
+ tweener: function( props, callback ) {
+ if ( isFunction( props ) ) {
+ callback = props;
+ props = [ "*" ];
+ } else {
+ props = props.match( rnothtmlwhite );
+ }
+
+ var prop,
+ index = 0,
+ length = props.length;
+
+ for ( ; index < length; index++ ) {
+ prop = props[ index ];
+ Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
+ Animation.tweeners[ prop ].unshift( callback );
+ }
+ },
+
+ prefilters: [ defaultPrefilter ],
+
+ prefilter: function( callback, prepend ) {
+ if ( prepend ) {
+ Animation.prefilters.unshift( callback );
+ } else {
+ Animation.prefilters.push( callback );
+ }
+ }
+} );
+
+jQuery.speed = function( speed, easing, fn ) {
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+ complete: fn || !fn && easing ||
+ isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && !isFunction( easing ) && easing
+ };
+
+ // Go to the end state if fx are off
+ if ( jQuery.fx.off ) {
+ opt.duration = 0;
+
+ } else {
+ if ( typeof opt.duration !== "number" ) {
+ if ( opt.duration in jQuery.fx.speeds ) {
+ opt.duration = jQuery.fx.speeds[ opt.duration ];
+
+ } else {
+ opt.duration = jQuery.fx.speeds._default;
+ }
+ }
+ }
+
+ // Normalize opt.queue - true/undefined/null -> "fx"
+ if ( opt.queue == null || opt.queue === true ) {
+ opt.queue = "fx";
+ }
+
+ // Queueing
+ opt.old = opt.complete;
+
+ opt.complete = function() {
+ if ( isFunction( opt.old ) ) {
+ opt.old.call( this );
+ }
+
+ if ( opt.queue ) {
+ jQuery.dequeue( this, opt.queue );
+ }
+ };
+
+ return opt;
+};
+
+jQuery.fn.extend( {
+ fadeTo: function( speed, to, easing, callback ) {
+
+ // Show any hidden elements after setting opacity to 0
+ return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show()
+
+ // Animate to the value specified
+ .end().animate( { opacity: to }, speed, easing, callback );
+ },
+ animate: function( prop, speed, easing, callback ) {
+ var empty = jQuery.isEmptyObject( prop ),
+ optall = jQuery.speed( speed, easing, callback ),
+ doAnimation = function() {
+
+ // Operate on a copy of prop so per-property easing won't be lost
+ var anim = Animation( this, jQuery.extend( {}, prop ), optall );
+
+ // Empty animations, or finishing resolves immediately
+ if ( empty || dataPriv.get( this, "finish" ) ) {
+ anim.stop( true );
+ }
+ };
+ doAnimation.finish = doAnimation;
+
+ return empty || optall.queue === false ?
+ this.each( doAnimation ) :
+ this.queue( optall.queue, doAnimation );
+ },
+ stop: function( type, clearQueue, gotoEnd ) {
+ var stopQueue = function( hooks ) {
+ var stop = hooks.stop;
+ delete hooks.stop;
+ stop( gotoEnd );
+ };
+
+ if ( typeof type !== "string" ) {
+ gotoEnd = clearQueue;
+ clearQueue = type;
+ type = undefined;
+ }
+ if ( clearQueue ) {
+ this.queue( type || "fx", [] );
+ }
+
+ return this.each( function() {
+ var dequeue = true,
+ index = type != null && type + "queueHooks",
+ timers = jQuery.timers,
+ data = dataPriv.get( this );
+
+ if ( index ) {
+ if ( data[ index ] && data[ index ].stop ) {
+ stopQueue( data[ index ] );
+ }
+ } else {
+ for ( index in data ) {
+ if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
+ stopQueue( data[ index ] );
+ }
+ }
+ }
+
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this &&
+ ( type == null || timers[ index ].queue === type ) ) {
+
+ timers[ index ].anim.stop( gotoEnd );
+ dequeue = false;
+ timers.splice( index, 1 );
+ }
+ }
+
+ // Start the next in the queue if the last step wasn't forced.
+ // Timers currently will call their complete callbacks, which
+ // will dequeue but only if they were gotoEnd.
+ if ( dequeue || !gotoEnd ) {
+ jQuery.dequeue( this, type );
+ }
+ } );
+ },
+ finish: function( type ) {
+ if ( type !== false ) {
+ type = type || "fx";
+ }
+ return this.each( function() {
+ var index,
+ data = dataPriv.get( this ),
+ queue = data[ type + "queue" ],
+ hooks = data[ type + "queueHooks" ],
+ timers = jQuery.timers,
+ length = queue ? queue.length : 0;
+
+ // Enable finishing flag on private data
+ data.finish = true;
+
+ // Empty the queue first
+ jQuery.queue( this, type, [] );
+
+ if ( hooks && hooks.stop ) {
+ hooks.stop.call( this, true );
+ }
+
+ // Look for any active animations, and finish them
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
+ timers[ index ].anim.stop( true );
+ timers.splice( index, 1 );
+ }
+ }
+
+ // Look for any animations in the old queue and finish them
+ for ( index = 0; index < length; index++ ) {
+ if ( queue[ index ] && queue[ index ].finish ) {
+ queue[ index ].finish.call( this );
+ }
+ }
+
+ // Turn off finishing flag
+ delete data.finish;
+ } );
+ }
+} );
+
+jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) {
+ var cssFn = jQuery.fn[ name ];
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return speed == null || typeof speed === "boolean" ?
+ cssFn.apply( this, arguments ) :
+ this.animate( genFx( name, true ), speed, easing, callback );
+ };
+} );
+
+// Generate shortcuts for custom animations
+jQuery.each( {
+ slideDown: genFx( "show" ),
+ slideUp: genFx( "hide" ),
+ slideToggle: genFx( "toggle" ),
+ fadeIn: { opacity: "show" },
+ fadeOut: { opacity: "hide" },
+ fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return this.animate( props, speed, easing, callback );
+ };
+} );
+
+jQuery.timers = [];
+jQuery.fx.tick = function() {
+ var timer,
+ i = 0,
+ timers = jQuery.timers;
+
+ fxNow = Date.now();
+
+ for ( ; i < timers.length; i++ ) {
+ timer = timers[ i ];
+
+ // Run the timer and safely remove it when done (allowing for external removal)
+ if ( !timer() && timers[ i ] === timer ) {
+ timers.splice( i--, 1 );
+ }
+ }
+
+ if ( !timers.length ) {
+ jQuery.fx.stop();
+ }
+ fxNow = undefined;
+};
+
+jQuery.fx.timer = function( timer ) {
+ jQuery.timers.push( timer );
+ jQuery.fx.start();
+};
+
+jQuery.fx.interval = 13;
+jQuery.fx.start = function() {
+ if ( inProgress ) {
+ return;
+ }
+
+ inProgress = true;
+ schedule();
+};
+
+jQuery.fx.stop = function() {
+ inProgress = null;
+};
+
+jQuery.fx.speeds = {
+ slow: 600,
+ fast: 200,
+
+ // Default speed
+ _default: 400
+};
+
+
+// Based off of the plugin by Clint Helfers, with permission.
+// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
+jQuery.fn.delay = function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function( next, hooks ) {
+ var timeout = window.setTimeout( next, time );
+ hooks.stop = function() {
+ window.clearTimeout( timeout );
+ };
+ } );
+};
+
+
+( function() {
+ var input = document.createElement( "input" ),
+ select = document.createElement( "select" ),
+ opt = select.appendChild( document.createElement( "option" ) );
+
+ input.type = "checkbox";
+
+ // Support: Android <=4.3 only
+ // Default value for a checkbox should be "on"
+ support.checkOn = input.value !== "";
+
+ // Support: IE <=11 only
+ // Must access selectedIndex to make default options select
+ support.optSelected = opt.selected;
+
+ // Support: IE <=11 only
+ // An input loses its value after becoming a radio
+ input = document.createElement( "input" );
+ input.value = "t";
+ input.type = "radio";
+ support.radioValue = input.value === "t";
+} )();
+
+
+var boolHook,
+ attrHandle = jQuery.expr.attrHandle;
+
+jQuery.fn.extend( {
+ attr: function( name, value ) {
+ return access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each( function() {
+ jQuery.removeAttr( this, name );
+ } );
+ }
+} );
+
+jQuery.extend( {
+ attr: function( elem, name, value ) {
+ var ret, hooks,
+ nType = elem.nodeType;
+
+ // Don't get/set attributes on text, comment and attribute nodes
+ if ( nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === "undefined" ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ // Attribute hooks are determined by the lowercase version
+ // Grab necessary hook if one is defined
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+ hooks = jQuery.attrHooks[ name.toLowerCase() ] ||
+ ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );
+ }
+
+ if ( value !== undefined ) {
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+ return;
+ }
+
+ if ( hooks && "set" in hooks &&
+ ( ret = hooks.set( elem, value, name ) ) !== undefined ) {
+ return ret;
+ }
+
+ elem.setAttribute( name, value + "" );
+ return value;
+ }
+
+ if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
+ return ret;
+ }
+
+ ret = jQuery.find.attr( elem, name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret == null ? undefined : ret;
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ if ( !support.radioValue && value === "radio" &&
+ nodeName( elem, "input" ) ) {
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ }
+ },
+
+ removeAttr: function( elem, value ) {
+ var name,
+ i = 0,
+
+ // Attribute names can contain non-HTML whitespace characters
+ // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
+ attrNames = value && value.match( rnothtmlwhite );
+
+ if ( attrNames && elem.nodeType === 1 ) {
+ while ( ( name = attrNames[ i++ ] ) ) {
+ elem.removeAttribute( name );
+ }
+ }
+ }
+} );
+
+// Hooks for boolean attributes
+boolHook = {
+ set: function( elem, value, name ) {
+ if ( value === false ) {
+
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else {
+ elem.setAttribute( name, name );
+ }
+ return name;
+ }
+};
+
+jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) {
+ var getter = attrHandle[ name ] || jQuery.find.attr;
+
+ attrHandle[ name ] = function( elem, name, isXML ) {
+ var ret, handle,
+ lowercaseName = name.toLowerCase();
+
+ if ( !isXML ) {
+
+ // Avoid an infinite loop by temporarily removing this function from the getter
+ handle = attrHandle[ lowercaseName ];
+ attrHandle[ lowercaseName ] = ret;
+ ret = getter( elem, name, isXML ) != null ?
+ lowercaseName :
+ null;
+ attrHandle[ lowercaseName ] = handle;
+ }
+ return ret;
+ };
+} );
+
+
+
+
+var rfocusable = /^(?:input|select|textarea|button)$/i,
+ rclickable = /^(?:a|area)$/i;
+
+jQuery.fn.extend( {
+ prop: function( name, value ) {
+ return access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ removeProp: function( name ) {
+ return this.each( function() {
+ delete this[ jQuery.propFix[ name ] || name ];
+ } );
+ }
+} );
+
+jQuery.extend( {
+ prop: function( elem, name, value ) {
+ var ret, hooks,
+ nType = elem.nodeType;
+
+ // Don't get/set properties on text, comment and attribute nodes
+ if ( nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
+
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ if ( hooks && "set" in hooks &&
+ ( ret = hooks.set( elem, value, name ) ) !== undefined ) {
+ return ret;
+ }
+
+ return ( elem[ name ] = value );
+ }
+
+ if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
+ return ret;
+ }
+
+ return elem[ name ];
+ },
+
+ propHooks: {
+ tabIndex: {
+ get: function( elem ) {
+
+ // Support: IE <=9 - 11 only
+ // elem.tabIndex doesn't always return the
+ // correct value when it hasn't been explicitly set
+ // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ // Use proper attribute retrieval(#12072)
+ var tabindex = jQuery.find.attr( elem, "tabindex" );
+
+ if ( tabindex ) {
+ return parseInt( tabindex, 10 );
+ }
+
+ if (
+ rfocusable.test( elem.nodeName ) ||
+ rclickable.test( elem.nodeName ) &&
+ elem.href
+ ) {
+ return 0;
+ }
+
+ return -1;
+ }
+ }
+ },
+
+ propFix: {
+ "for": "htmlFor",
+ "class": "className"
+ }
+} );
+
+// Support: IE <=11 only
+// Accessing the selectedIndex property
+// forces the browser to respect setting selected
+// on the option
+// The getter ensures a default option is selected
+// when in an optgroup
+// eslint rule "no-unused-expressions" is disabled for this code
+// since it considers such accessions noop
+if ( !support.optSelected ) {
+ jQuery.propHooks.selected = {
+ get: function( elem ) {
+
+ /* eslint no-unused-expressions: "off" */
+
+ var parent = elem.parentNode;
+ if ( parent && parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ return null;
+ },
+ set: function( elem ) {
+
+ /* eslint no-unused-expressions: "off" */
+
+ var parent = elem.parentNode;
+ if ( parent ) {
+ parent.selectedIndex;
+
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ }
+ };
+}
+
+jQuery.each( [
+ "tabIndex",
+ "readOnly",
+ "maxLength",
+ "cellSpacing",
+ "cellPadding",
+ "rowSpan",
+ "colSpan",
+ "useMap",
+ "frameBorder",
+ "contentEditable"
+], function() {
+ jQuery.propFix[ this.toLowerCase() ] = this;
+} );
+
+
+
+
+ // Strip and collapse whitespace according to HTML spec
+ // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace
+ function stripAndCollapse( value ) {
+ var tokens = value.match( rnothtmlwhite ) || [];
+ return tokens.join( " " );
+ }
+
+
+function getClass( elem ) {
+ return elem.getAttribute && elem.getAttribute( "class" ) || "";
+}
+
+function classesToArray( value ) {
+ if ( Array.isArray( value ) ) {
+ return value;
+ }
+ if ( typeof value === "string" ) {
+ return value.match( rnothtmlwhite ) || [];
+ }
+ return [];
+}
+
+jQuery.fn.extend( {
+ addClass: function( value ) {
+ var classes, elem, cur, curValue, clazz, j, finalValue,
+ i = 0;
+
+ if ( isFunction( value ) ) {
+ return this.each( function( j ) {
+ jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
+ } );
+ }
+
+ classes = classesToArray( value );
+
+ if ( classes.length ) {
+ while ( ( elem = this[ i++ ] ) ) {
+ curValue = getClass( elem );
+ cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
+
+ if ( cur ) {
+ j = 0;
+ while ( ( clazz = classes[ j++ ] ) ) {
+ if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
+ cur += clazz + " ";
+ }
+ }
+
+ // Only assign if different to avoid unneeded rendering.
+ finalValue = stripAndCollapse( cur );
+ if ( curValue !== finalValue ) {
+ elem.setAttribute( "class", finalValue );
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var classes, elem, cur, curValue, clazz, j, finalValue,
+ i = 0;
+
+ if ( isFunction( value ) ) {
+ return this.each( function( j ) {
+ jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
+ } );
+ }
+
+ if ( !arguments.length ) {
+ return this.attr( "class", "" );
+ }
+
+ classes = classesToArray( value );
+
+ if ( classes.length ) {
+ while ( ( elem = this[ i++ ] ) ) {
+ curValue = getClass( elem );
+
+ // This expression is here for better compressibility (see addClass)
+ cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
+
+ if ( cur ) {
+ j = 0;
+ while ( ( clazz = classes[ j++ ] ) ) {
+
+ // Remove *all* instances
+ while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
+ cur = cur.replace( " " + clazz + " ", " " );
+ }
+ }
+
+ // Only assign if different to avoid unneeded rendering.
+ finalValue = stripAndCollapse( cur );
+ if ( curValue !== finalValue ) {
+ elem.setAttribute( "class", finalValue );
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value,
+ isValidValue = type === "string" || Array.isArray( value );
+
+ if ( typeof stateVal === "boolean" && isValidValue ) {
+ return stateVal ? this.addClass( value ) : this.removeClass( value );
+ }
+
+ if ( isFunction( value ) ) {
+ return this.each( function( i ) {
+ jQuery( this ).toggleClass(
+ value.call( this, i, getClass( this ), stateVal ),
+ stateVal
+ );
+ } );
+ }
+
+ return this.each( function() {
+ var className, i, self, classNames;
+
+ if ( isValidValue ) {
+
+ // Toggle individual class names
+ i = 0;
+ self = jQuery( this );
+ classNames = classesToArray( value );
+
+ while ( ( className = classNames[ i++ ] ) ) {
+
+ // Check each className given, space separated list
+ if ( self.hasClass( className ) ) {
+ self.removeClass( className );
+ } else {
+ self.addClass( className );
+ }
+ }
+
+ // Toggle whole class name
+ } else if ( value === undefined || type === "boolean" ) {
+ className = getClass( this );
+ if ( className ) {
+
+ // Store className if set
+ dataPriv.set( this, "__className__", className );
+ }
+
+ // If the element has a class name or if we're passed `false`,
+ // then remove the whole classname (if there was one, the above saved it).
+ // Otherwise bring back whatever was previously saved (if anything),
+ // falling back to the empty string if nothing was stored.
+ if ( this.setAttribute ) {
+ this.setAttribute( "class",
+ className || value === false ?
+ "" :
+ dataPriv.get( this, "__className__" ) || ""
+ );
+ }
+ }
+ } );
+ },
+
+ hasClass: function( selector ) {
+ var className, elem,
+ i = 0;
+
+ className = " " + selector + " ";
+ while ( ( elem = this[ i++ ] ) ) {
+ if ( elem.nodeType === 1 &&
+ ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+} );
+
+
+
+
+var rreturn = /\r/g;
+
+jQuery.fn.extend( {
+ val: function( value ) {
+ var hooks, ret, valueIsFunction,
+ elem = this[ 0 ];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] ||
+ jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ if ( hooks &&
+ "get" in hooks &&
+ ( ret = hooks.get( elem, "value" ) ) !== undefined
+ ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ // Handle most common string cases
+ if ( typeof ret === "string" ) {
+ return ret.replace( rreturn, "" );
+ }
+
+ // Handle cases where value is null/undef or number
+ return ret == null ? "" : ret;
+ }
+
+ return;
+ }
+
+ valueIsFunction = isFunction( value );
+
+ return this.each( function( i ) {
+ var val;
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( valueIsFunction ) {
+ val = value.call( this, i, jQuery( this ).val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+
+ } else if ( typeof val === "number" ) {
+ val += "";
+
+ } else if ( Array.isArray( val ) ) {
+ val = jQuery.map( val, function( value ) {
+ return value == null ? "" : value + "";
+ } );
+ }
+
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ } );
+ }
+} );
+
+jQuery.extend( {
+ valHooks: {
+ option: {
+ get: function( elem ) {
+
+ var val = jQuery.find.attr( elem, "value" );
+ return val != null ?
+ val :
+
+ // Support: IE <=10 - 11 only
+ // option.text throws exceptions (#14686, #14858)
+ // Strip and collapse whitespace
+ // https://html.spec.whatwg.org/#strip-and-collapse-whitespace
+ stripAndCollapse( jQuery.text( elem ) );
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value, option, i,
+ options = elem.options,
+ index = elem.selectedIndex,
+ one = elem.type === "select-one",
+ values = one ? null : [],
+ max = one ? index + 1 : options.length;
+
+ if ( index < 0 ) {
+ i = max;
+
+ } else {
+ i = one ? index : 0;
+ }
+
+ // Loop through all the selected options
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // Support: IE <=9 only
+ // IE8-9 doesn't update selected after form reset (#2551)
+ if ( ( option.selected || i === index ) &&
+
+ // Don't return options that are disabled or in a disabled optgroup
+ !option.disabled &&
+ ( !option.parentNode.disabled ||
+ !nodeName( option.parentNode, "optgroup" ) ) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var optionSet, option,
+ options = elem.options,
+ values = jQuery.makeArray( value ),
+ i = options.length;
+
+ while ( i-- ) {
+ option = options[ i ];
+
+ /* eslint-disable no-cond-assign */
+
+ if ( option.selected =
+ jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1
+ ) {
+ optionSet = true;
+ }
+
+ /* eslint-enable no-cond-assign */
+ }
+
+ // Force browsers to behave consistently when non-matching value is set
+ if ( !optionSet ) {
+ elem.selectedIndex = -1;
+ }
+ return values;
+ }
+ }
+ }
+} );
+
+// Radios and checkboxes getter/setter
+jQuery.each( [ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ set: function( elem, value ) {
+ if ( Array.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );
+ }
+ }
+ };
+ if ( !support.checkOn ) {
+ jQuery.valHooks[ this ].get = function( elem ) {
+ return elem.getAttribute( "value" ) === null ? "on" : elem.value;
+ };
+ }
+} );
+
+
+
+
+// Return jQuery for attributes-only inclusion
+
+
+support.focusin = "onfocusin" in window;
+
+
+var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ stopPropagationCallback = function( e ) {
+ e.stopPropagation();
+ };
+
+jQuery.extend( jQuery.event, {
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+
+ var i, cur, tmp, bubbleType, ontype, handle, special, lastElement,
+ eventPath = [ elem || document ],
+ type = hasOwn.call( event, "type" ) ? event.type : event,
+ namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];
+
+ cur = lastElement = tmp = elem = elem || document;
+
+ // Don't do events on text and comment nodes
+ if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
+ return;
+ }
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf( "." ) > -1 ) {
+
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split( "." );
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+ ontype = type.indexOf( ":" ) < 0 && "on" + type;
+
+ // Caller can pass in a jQuery.Event object, Object, or just an event type string
+ event = event[ jQuery.expando ] ?
+ event :
+ new jQuery.Event( type, typeof event === "object" && event );
+
+ // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
+ event.isTrigger = onlyHandlers ? 2 : 3;
+ event.namespace = namespaces.join( "." );
+ event.rnamespace = event.namespace ?
+ new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
+ null;
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data == null ?
+ [ event ] :
+ jQuery.makeArray( data, [ event ] );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ if ( !rfocusMorph.test( bubbleType + type ) ) {
+ cur = cur.parentNode;
+ }
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push( cur );
+ tmp = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( tmp === ( elem.ownerDocument || document ) ) {
+ eventPath.push( tmp.defaultView || tmp.parentWindow || window );
+ }
+ }
+
+ // Fire handlers on the event path
+ i = 0;
+ while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
+ lastElement = cur;
+ event.type = i > 1 ?
+ bubbleType :
+ special.bindType || type;
+
+ // jQuery handler
+ handle = (
+ dataPriv.get( cur, "events" ) || Object.create( null )
+ )[ event.type ] &&
+ dataPriv.get( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+
+ // Native handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && handle.apply && acceptData( cur ) ) {
+ event.result = handle.apply( cur, data );
+ if ( event.result === false ) {
+ event.preventDefault();
+ }
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( ( !special._default ||
+ special._default.apply( eventPath.pop(), data ) === false ) &&
+ acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name as the event.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ tmp = elem[ ontype ];
+
+ if ( tmp ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+
+ if ( event.isPropagationStopped() ) {
+ lastElement.addEventListener( type, stopPropagationCallback );
+ }
+
+ elem[ type ]();
+
+ if ( event.isPropagationStopped() ) {
+ lastElement.removeEventListener( type, stopPropagationCallback );
+ }
+
+ jQuery.event.triggered = undefined;
+
+ if ( tmp ) {
+ elem[ ontype ] = tmp;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ // Piggyback on a donor event to simulate a different one
+ // Used only for `focus(in | out)` events
+ simulate: function( type, elem, event ) {
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ {
+ type: type,
+ isSimulated: true
+ }
+ );
+
+ jQuery.event.trigger( e, null, elem );
+ }
+
+} );
+
+jQuery.fn.extend( {
+
+ trigger: function( type, data ) {
+ return this.each( function() {
+ jQuery.event.trigger( type, data, this );
+ } );
+ },
+ triggerHandler: function( type, data ) {
+ var elem = this[ 0 ];
+ if ( elem ) {
+ return jQuery.event.trigger( type, data, elem, true );
+ }
+ }
+} );
+
+
+// Support: Firefox <=44
+// Firefox doesn't have focus(in | out) events
+// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
+//
+// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1
+// focus(in | out) events fire after focus & blur events,
+// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
+// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857
+if ( !support.focusin ) {
+ jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+ // Attach a single capturing handler on the document while someone wants focusin/focusout
+ var handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
+ };
+
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+
+ // Handle: regular nodes (via `this.ownerDocument`), window
+ // (via `this.document`) & document (via `this`).
+ var doc = this.ownerDocument || this.document || this,
+ attaches = dataPriv.access( doc, fix );
+
+ if ( !attaches ) {
+ doc.addEventListener( orig, handler, true );
+ }
+ dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
+ },
+ teardown: function() {
+ var doc = this.ownerDocument || this.document || this,
+ attaches = dataPriv.access( doc, fix ) - 1;
+
+ if ( !attaches ) {
+ doc.removeEventListener( orig, handler, true );
+ dataPriv.remove( doc, fix );
+
+ } else {
+ dataPriv.access( doc, fix, attaches );
+ }
+ }
+ };
+ } );
+}
+var location = window.location;
+
+var nonce = { guid: Date.now() };
+
+var rquery = ( /\?/ );
+
+
+
+// Cross-browser xml parsing
+jQuery.parseXML = function( data ) {
+ var xml;
+ if ( !data || typeof data !== "string" ) {
+ return null;
+ }
+
+ // Support: IE 9 - 11 only
+ // IE throws on parseFromString with invalid input.
+ try {
+ xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" );
+ } catch ( e ) {
+ xml = undefined;
+ }
+
+ if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+ return xml;
+};
+
+
+var
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
+ rsubmittable = /^(?:input|select|textarea|keygen)/i;
+
+function buildParams( prefix, obj, traditional, add ) {
+ var name;
+
+ if ( Array.isArray( obj ) ) {
+
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+
+ // Item is non-scalar (array or object), encode its numeric index.
+ buildParams(
+ prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]",
+ v,
+ traditional,
+ add
+ );
+ }
+ } );
+
+ } else if ( !traditional && toType( obj ) === "object" ) {
+
+ // Serialize object item.
+ for ( name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+
+// Serialize an array of form elements or a set of
+// key/values into a query string
+jQuery.param = function( a, traditional ) {
+ var prefix,
+ s = [],
+ add = function( key, valueOrFunction ) {
+
+ // If value is a function, invoke it and use its return value
+ var value = isFunction( valueOrFunction ) ?
+ valueOrFunction() :
+ valueOrFunction;
+
+ s[ s.length ] = encodeURIComponent( key ) + "=" +
+ encodeURIComponent( value == null ? "" : value );
+ };
+
+ if ( a == null ) {
+ return "";
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ } );
+
+ } else {
+
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" );
+};
+
+jQuery.fn.extend( {
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+ serializeArray: function() {
+ return this.map( function() {
+
+ // Can add propHook for "elements" to filter or add form elements
+ var elements = jQuery.prop( this, "elements" );
+ return elements ? jQuery.makeArray( elements ) : this;
+ } )
+ .filter( function() {
+ var type = this.type;
+
+ // Use .is( ":disabled" ) so that fieldset[disabled] works
+ return this.name && !jQuery( this ).is( ":disabled" ) &&
+ rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
+ ( this.checked || !rcheckableType.test( type ) );
+ } )
+ .map( function( _i, elem ) {
+ var val = jQuery( this ).val();
+
+ if ( val == null ) {
+ return null;
+ }
+
+ if ( Array.isArray( val ) ) {
+ return jQuery.map( val, function( val ) {
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ } );
+ }
+
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ } ).get();
+ }
+} );
+
+
+var
+ r20 = /%20/g,
+ rhash = /#.*$/,
+ rantiCache = /([?&])_=[^&]*/,
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
+
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
+ rnoContent = /^(?:GET|HEAD)$/,
+ rprotocol = /^\/\//,
+
+ /* Prefilters
+ * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+ * 2) These are called:
+ * - BEFORE asking for a transport
+ * - AFTER param serialization (s.data is a string if s.processData is true)
+ * 3) key is the dataType
+ * 4) the catchall symbol "*" can be used
+ * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+ */
+ prefilters = {},
+
+ /* Transports bindings
+ * 1) key is the dataType
+ * 2) the catchall symbol "*" can be used
+ * 3) selection will start with transport dataType and THEN go to "*" if needed
+ */
+ transports = {},
+
+ // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+ allTypes = "*/".concat( "*" ),
+
+ // Anchor tag for parsing the document origin
+ originAnchor = document.createElement( "a" );
+ originAnchor.href = location.href;
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+ // dataTypeExpression is optional and defaults to "*"
+ return function( dataTypeExpression, func ) {
+
+ if ( typeof dataTypeExpression !== "string" ) {
+ func = dataTypeExpression;
+ dataTypeExpression = "*";
+ }
+
+ var dataType,
+ i = 0,
+ dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];
+
+ if ( isFunction( func ) ) {
+
+ // For each dataType in the dataTypeExpression
+ while ( ( dataType = dataTypes[ i++ ] ) ) {
+
+ // Prepend if requested
+ if ( dataType[ 0 ] === "+" ) {
+ dataType = dataType.slice( 1 ) || "*";
+ ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );
+
+ // Otherwise append
+ } else {
+ ( structure[ dataType ] = structure[ dataType ] || [] ).push( func );
+ }
+ }
+ }
+ };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
+
+ var inspected = {},
+ seekingTransport = ( structure === transports );
+
+ function inspect( dataType ) {
+ var selected;
+ inspected[ dataType ] = true;
+ jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
+ var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
+ if ( typeof dataTypeOrTransport === "string" &&
+ !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
+
+ options.dataTypes.unshift( dataTypeOrTransport );
+ inspect( dataTypeOrTransport );
+ return false;
+ } else if ( seekingTransport ) {
+ return !( selected = dataTypeOrTransport );
+ }
+ } );
+ return selected;
+ }
+
+ return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+ var key, deep,
+ flatOptions = jQuery.ajaxSettings.flatOptions || {};
+
+ for ( key in src ) {
+ if ( src[ key ] !== undefined ) {
+ ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
+ }
+ }
+ if ( deep ) {
+ jQuery.extend( true, target, deep );
+ }
+
+ return target;
+}
+
+/* Handles responses to an ajax request:
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+ var ct, type, finalDataType, firstDataType,
+ contents = s.contents,
+ dataTypes = s.dataTypes;
+
+ // Remove auto dataType and get content-type in the process
+ while ( dataTypes[ 0 ] === "*" ) {
+ dataTypes.shift();
+ if ( ct === undefined ) {
+ ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" );
+ }
+ }
+
+ // Check if we're dealing with a known content-type
+ if ( ct ) {
+ for ( type in contents ) {
+ if ( contents[ type ] && contents[ type ].test( ct ) ) {
+ dataTypes.unshift( type );
+ break;
+ }
+ }
+ }
+
+ // Check to see if we have a response for the expected dataType
+ if ( dataTypes[ 0 ] in responses ) {
+ finalDataType = dataTypes[ 0 ];
+ } else {
+
+ // Try convertible dataTypes
+ for ( type in responses ) {
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) {
+ finalDataType = type;
+ break;
+ }
+ if ( !firstDataType ) {
+ firstDataType = type;
+ }
+ }
+
+ // Or just use first one
+ finalDataType = finalDataType || firstDataType;
+ }
+
+ // If we found a dataType
+ // We add the dataType to the list if needed
+ // and return the corresponding response
+ if ( finalDataType ) {
+ if ( finalDataType !== dataTypes[ 0 ] ) {
+ dataTypes.unshift( finalDataType );
+ }
+ return responses[ finalDataType ];
+ }
+}
+
+/* Chain conversions given the request and the original response
+ * Also sets the responseXXX fields on the jqXHR instance
+ */
+function ajaxConvert( s, response, jqXHR, isSuccess ) {
+ var conv2, current, conv, tmp, prev,
+ converters = {},
+
+ // Work with a copy of dataTypes in case we need to modify it for conversion
+ dataTypes = s.dataTypes.slice();
+
+ // Create converters map with lowercased keys
+ if ( dataTypes[ 1 ] ) {
+ for ( conv in s.converters ) {
+ converters[ conv.toLowerCase() ] = s.converters[ conv ];
+ }
+ }
+
+ current = dataTypes.shift();
+
+ // Convert to each sequential dataType
+ while ( current ) {
+
+ if ( s.responseFields[ current ] ) {
+ jqXHR[ s.responseFields[ current ] ] = response;
+ }
+
+ // Apply the dataFilter if provided
+ if ( !prev && isSuccess && s.dataFilter ) {
+ response = s.dataFilter( response, s.dataType );
+ }
+
+ prev = current;
+ current = dataTypes.shift();
+
+ if ( current ) {
+
+ // There's only work to do if current dataType is non-auto
+ if ( current === "*" ) {
+
+ current = prev;
+
+ // Convert response if prev dataType is non-auto and differs from current
+ } else if ( prev !== "*" && prev !== current ) {
+
+ // Seek a direct converter
+ conv = converters[ prev + " " + current ] || converters[ "* " + current ];
+
+ // If none found, seek a pair
+ if ( !conv ) {
+ for ( conv2 in converters ) {
+
+ // If conv2 outputs current
+ tmp = conv2.split( " " );
+ if ( tmp[ 1 ] === current ) {
+
+ // If prev can be converted to accepted input
+ conv = converters[ prev + " " + tmp[ 0 ] ] ||
+ converters[ "* " + tmp[ 0 ] ];
+ if ( conv ) {
+
+ // Condense equivalence converters
+ if ( conv === true ) {
+ conv = converters[ conv2 ];
+
+ // Otherwise, insert the intermediate dataType
+ } else if ( converters[ conv2 ] !== true ) {
+ current = tmp[ 0 ];
+ dataTypes.unshift( tmp[ 1 ] );
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ // Apply converter (if not an equivalence)
+ if ( conv !== true ) {
+
+ // Unless errors are allowed to bubble, catch and return them
+ if ( conv && s.throws ) {
+ response = conv( response );
+ } else {
+ try {
+ response = conv( response );
+ } catch ( e ) {
+ return {
+ state: "parsererror",
+ error: conv ? e : "No conversion from " + prev + " to " + current
+ };
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return { state: "success", data: response };
+}
+
+jQuery.extend( {
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {},
+
+ ajaxSettings: {
+ url: location.href,
+ type: "GET",
+ isLocal: rlocalProtocol.test( location.protocol ),
+ global: true,
+ processData: true,
+ async: true,
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+
+ /*
+ timeout: 0,
+ data: null,
+ dataType: null,
+ username: null,
+ password: null,
+ cache: null,
+ throws: false,
+ traditional: false,
+ headers: {},
+ */
+
+ accepts: {
+ "*": allTypes,
+ text: "text/plain",
+ html: "text/html",
+ xml: "application/xml, text/xml",
+ json: "application/json, text/javascript"
+ },
+
+ contents: {
+ xml: /\bxml\b/,
+ html: /\bhtml/,
+ json: /\bjson\b/
+ },
+
+ responseFields: {
+ xml: "responseXML",
+ text: "responseText",
+ json: "responseJSON"
+ },
+
+ // Data converters
+ // Keys separate source (or catchall "*") and destination types with a single space
+ converters: {
+
+ // Convert anything to text
+ "* text": String,
+
+ // Text to html (true = no transformation)
+ "text html": true,
+
+ // Evaluate text as a json expression
+ "text json": JSON.parse,
+
+ // Parse text as xml
+ "text xml": jQuery.parseXML
+ },
+
+ // For options that shouldn't be deep extended:
+ // you can add your own custom options here if
+ // and when you create one that shouldn't be
+ // deep extended (see ajaxExtend)
+ flatOptions: {
+ url: true,
+ context: true
+ }
+ },
+
+ // Creates a full fledged settings object into target
+ // with both ajaxSettings and settings fields.
+ // If target is omitted, writes into ajaxSettings.
+ ajaxSetup: function( target, settings ) {
+ return settings ?
+
+ // Building a settings object
+ ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
+
+ // Extending ajaxSettings
+ ajaxExtend( jQuery.ajaxSettings, target );
+ },
+
+ ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+ ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+ // Main method
+ ajax: function( url, options ) {
+
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
+ options = url;
+ url = undefined;
+ }
+
+ // Force options to be an object
+ options = options || {};
+
+ var transport,
+
+ // URL without anti-cache param
+ cacheURL,
+
+ // Response headers
+ responseHeadersString,
+ responseHeaders,
+
+ // timeout handle
+ timeoutTimer,
+
+ // Url cleanup var
+ urlAnchor,
+
+ // Request state (becomes false upon send and true upon completion)
+ completed,
+
+ // To know if global events are to be dispatched
+ fireGlobals,
+
+ // Loop variable
+ i,
+
+ // uncached part of the url
+ uncached,
+
+ // Create the final options object
+ s = jQuery.ajaxSetup( {}, options ),
+
+ // Callbacks context
+ callbackContext = s.context || s,
+
+ // Context for global events is callbackContext if it is a DOM node or jQuery collection
+ globalEventContext = s.context &&
+ ( callbackContext.nodeType || callbackContext.jquery ) ?
+ jQuery( callbackContext ) :
+ jQuery.event,
+
+ // Deferreds
+ deferred = jQuery.Deferred(),
+ completeDeferred = jQuery.Callbacks( "once memory" ),
+
+ // Status-dependent callbacks
+ statusCode = s.statusCode || {},
+
+ // Headers (they are sent all at once)
+ requestHeaders = {},
+ requestHeadersNames = {},
+
+ // Default abort message
+ strAbort = "canceled",
+
+ // Fake xhr
+ jqXHR = {
+ readyState: 0,
+
+ // Builds headers hashtable if needed
+ getResponseHeader: function( key ) {
+ var match;
+ if ( completed ) {
+ if ( !responseHeaders ) {
+ responseHeaders = {};
+ while ( ( match = rheaders.exec( responseHeadersString ) ) ) {
+ responseHeaders[ match[ 1 ].toLowerCase() + " " ] =
+ ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] )
+ .concat( match[ 2 ] );
+ }
+ }
+ match = responseHeaders[ key.toLowerCase() + " " ];
+ }
+ return match == null ? null : match.join( ", " );
+ },
+
+ // Raw string
+ getAllResponseHeaders: function() {
+ return completed ? responseHeadersString : null;
+ },
+
+ // Caches the header
+ setRequestHeader: function( name, value ) {
+ if ( completed == null ) {
+ name = requestHeadersNames[ name.toLowerCase() ] =
+ requestHeadersNames[ name.toLowerCase() ] || name;
+ requestHeaders[ name ] = value;
+ }
+ return this;
+ },
+
+ // Overrides response content-type header
+ overrideMimeType: function( type ) {
+ if ( completed == null ) {
+ s.mimeType = type;
+ }
+ return this;
+ },
+
+ // Status-dependent callbacks
+ statusCode: function( map ) {
+ var code;
+ if ( map ) {
+ if ( completed ) {
+
+ // Execute the appropriate callbacks
+ jqXHR.always( map[ jqXHR.status ] );
+ } else {
+
+ // Lazy-add the new callbacks in a way that preserves old ones
+ for ( code in map ) {
+ statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
+ }
+ }
+ }
+ return this;
+ },
+
+ // Cancel the request
+ abort: function( statusText ) {
+ var finalText = statusText || strAbort;
+ if ( transport ) {
+ transport.abort( finalText );
+ }
+ done( 0, finalText );
+ return this;
+ }
+ };
+
+ // Attach deferreds
+ deferred.promise( jqXHR );
+
+ // Add protocol if not provided (prefilters might expect it)
+ // Handle falsy url in the settings object (#10093: consistency with old signature)
+ // We also use the url parameter if available
+ s.url = ( ( url || s.url || location.href ) + "" )
+ .replace( rprotocol, location.protocol + "//" );
+
+ // Alias method option to type as per ticket #12004
+ s.type = options.method || options.type || s.method || s.type;
+
+ // Extract dataTypes list
+ s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ];
+
+ // A cross-domain request is in order when the origin doesn't match the current origin.
+ if ( s.crossDomain == null ) {
+ urlAnchor = document.createElement( "a" );
+
+ // Support: IE <=8 - 11, Edge 12 - 15
+ // IE throws exception on accessing the href property if url is malformed,
+ // e.g. http://example.com:80x/
+ try {
+ urlAnchor.href = s.url;
+
+ // Support: IE <=8 - 11 only
+ // Anchor's host property isn't correctly set when s.url is relative
+ urlAnchor.href = urlAnchor.href;
+ s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !==
+ urlAnchor.protocol + "//" + urlAnchor.host;
+ } catch ( e ) {
+
+ // If there is an error parsing the URL, assume it is crossDomain,
+ // it can be rejected by the transport if it is invalid
+ s.crossDomain = true;
+ }
+ }
+
+ // Convert data if not already a string
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
+ s.data = jQuery.param( s.data, s.traditional );
+ }
+
+ // Apply prefilters
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+ // If request was aborted inside a prefilter, stop there
+ if ( completed ) {
+ return jqXHR;
+ }
+
+ // We can fire global events as of now if asked to
+ // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
+ fireGlobals = jQuery.event && s.global;
+
+ // Watch for a new set of requests
+ if ( fireGlobals && jQuery.active++ === 0 ) {
+ jQuery.event.trigger( "ajaxStart" );
+ }
+
+ // Uppercase the type
+ s.type = s.type.toUpperCase();
+
+ // Determine if request has content
+ s.hasContent = !rnoContent.test( s.type );
+
+ // Save the URL in case we're toying with the If-Modified-Since
+ // and/or If-None-Match header later on
+ // Remove hash to simplify url manipulation
+ cacheURL = s.url.replace( rhash, "" );
+
+ // More options handling for requests with no content
+ if ( !s.hasContent ) {
+
+ // Remember the hash so we can put it back
+ uncached = s.url.slice( cacheURL.length );
+
+ // If data is available and should be processed, append data to url
+ if ( s.data && ( s.processData || typeof s.data === "string" ) ) {
+ cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data;
+
+ // #9682: remove data so that it's not used in an eventual retry
+ delete s.data;
+ }
+
+ // Add or update anti-cache param if needed
+ if ( s.cache === false ) {
+ cacheURL = cacheURL.replace( rantiCache, "$1" );
+ uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) +
+ uncached;
+ }
+
+ // Put hash and anti-cache on the URL that will be requested (gh-1732)
+ s.url = cacheURL + uncached;
+
+ // Change '%20' to '+' if this is encoded form body content (gh-2658)
+ } else if ( s.data && s.processData &&
+ ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) {
+ s.data = s.data.replace( r20, "+" );
+ }
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ if ( jQuery.lastModified[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
+ }
+ if ( jQuery.etag[ cacheURL ] ) {
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
+ }
+ }
+
+ // Set the correct header, if data is being sent
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
+ }
+
+ // Set the Accepts header for the server, depending on the dataType
+ jqXHR.setRequestHeader(
+ "Accept",
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
+ s.accepts[ s.dataTypes[ 0 ] ] +
+ ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+ s.accepts[ "*" ]
+ );
+
+ // Check for headers option
+ for ( i in s.headers ) {
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
+ }
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend &&
+ ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {
+
+ // Abort if not done already and return
+ return jqXHR.abort();
+ }
+
+ // Aborting is no longer a cancellation
+ strAbort = "abort";
+
+ // Install callbacks on deferreds
+ completeDeferred.add( s.complete );
+ jqXHR.done( s.success );
+ jqXHR.fail( s.error );
+
+ // Get transport
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+ // If no transport, we auto-abort
+ if ( !transport ) {
+ done( -1, "No Transport" );
+ } else {
+ jqXHR.readyState = 1;
+
+ // Send global event
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+ }
+
+ // If request was aborted inside ajaxSend, stop there
+ if ( completed ) {
+ return jqXHR;
+ }
+
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = window.setTimeout( function() {
+ jqXHR.abort( "timeout" );
+ }, s.timeout );
+ }
+
+ try {
+ completed = false;
+ transport.send( requestHeaders, done );
+ } catch ( e ) {
+
+ // Rethrow post-completion exceptions
+ if ( completed ) {
+ throw e;
+ }
+
+ // Propagate others as results
+ done( -1, e );
+ }
+ }
+
+ // Callback for when everything is done
+ function done( status, nativeStatusText, responses, headers ) {
+ var isSuccess, success, error, response, modified,
+ statusText = nativeStatusText;
+
+ // Ignore repeat invocations
+ if ( completed ) {
+ return;
+ }
+
+ completed = true;
+
+ // Clear timeout if it exists
+ if ( timeoutTimer ) {
+ window.clearTimeout( timeoutTimer );
+ }
+
+ // Dereference transport for early garbage collection
+ // (no matter how long the jqXHR object will be used)
+ transport = undefined;
+
+ // Cache response headers
+ responseHeadersString = headers || "";
+
+ // Set readyState
+ jqXHR.readyState = status > 0 ? 4 : 0;
+
+ // Determine if successful
+ isSuccess = status >= 200 && status < 300 || status === 304;
+
+ // Get response data
+ if ( responses ) {
+ response = ajaxHandleResponses( s, jqXHR, responses );
+ }
+
+ // Use a noop converter for missing script
+ if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) {
+ s.converters[ "text script" ] = function() {};
+ }
+
+ // Convert no matter what (that way responseXXX fields are always set)
+ response = ajaxConvert( s, response, jqXHR, isSuccess );
+
+ // If successful, handle type chaining
+ if ( isSuccess ) {
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ modified = jqXHR.getResponseHeader( "Last-Modified" );
+ if ( modified ) {
+ jQuery.lastModified[ cacheURL ] = modified;
+ }
+ modified = jqXHR.getResponseHeader( "etag" );
+ if ( modified ) {
+ jQuery.etag[ cacheURL ] = modified;
+ }
+ }
+
+ // if no content
+ if ( status === 204 || s.type === "HEAD" ) {
+ statusText = "nocontent";
+
+ // if not modified
+ } else if ( status === 304 ) {
+ statusText = "notmodified";
+
+ // If we have data, let's convert it
+ } else {
+ statusText = response.state;
+ success = response.data;
+ error = response.error;
+ isSuccess = !error;
+ }
+ } else {
+
+ // Extract error from statusText and normalize for non-aborts
+ error = statusText;
+ if ( status || !statusText ) {
+ statusText = "error";
+ if ( status < 0 ) {
+ status = 0;
+ }
+ }
+ }
+
+ // Set data for the fake xhr object
+ jqXHR.status = status;
+ jqXHR.statusText = ( nativeStatusText || statusText ) + "";
+
+ // Success/Error
+ if ( isSuccess ) {
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+ } else {
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+ }
+
+ // Status-dependent callbacks
+ jqXHR.statusCode( statusCode );
+ statusCode = undefined;
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
+ [ jqXHR, s, isSuccess ? success : error ] );
+ }
+
+ // Complete
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+
+ // Handle the global AJAX counter
+ if ( !( --jQuery.active ) ) {
+ jQuery.event.trigger( "ajaxStop" );
+ }
+ }
+ }
+
+ return jqXHR;
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get( url, data, callback, "json" );
+ },
+
+ getScript: function( url, callback ) {
+ return jQuery.get( url, undefined, callback, "script" );
+ }
+} );
+
+jQuery.each( [ "get", "post" ], function( _i, method ) {
+ jQuery[ method ] = function( url, data, callback, type ) {
+
+ // Shift arguments if data argument was omitted
+ if ( isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = undefined;
+ }
+
+ // The url can be an options object (which then must have .url)
+ return jQuery.ajax( jQuery.extend( {
+ url: url,
+ type: method,
+ dataType: type,
+ data: data,
+ success: callback
+ }, jQuery.isPlainObject( url ) && url ) );
+ };
+} );
+
+jQuery.ajaxPrefilter( function( s ) {
+ var i;
+ for ( i in s.headers ) {
+ if ( i.toLowerCase() === "content-type" ) {
+ s.contentType = s.headers[ i ] || "";
+ }
+ }
+} );
+
+
+jQuery._evalUrl = function( url, options, doc ) {
+ return jQuery.ajax( {
+ url: url,
+
+ // Make this explicit, since user can override this through ajaxSetup (#11264)
+ type: "GET",
+ dataType: "script",
+ cache: true,
+ async: false,
+ global: false,
+
+ // Only evaluate the response if it is successful (gh-4126)
+ // dataFilter is not invoked for failure responses, so using it instead
+ // of the default converter is kludgy but it works.
+ converters: {
+ "text script": function() {}
+ },
+ dataFilter: function( response ) {
+ jQuery.globalEval( response, options, doc );
+ }
+ } );
+};
+
+
+jQuery.fn.extend( {
+ wrapAll: function( html ) {
+ var wrap;
+
+ if ( this[ 0 ] ) {
+ if ( isFunction( html ) ) {
+ html = html.call( this[ 0 ] );
+ }
+
+ // The elements to wrap the target around
+ wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
+
+ if ( this[ 0 ].parentNode ) {
+ wrap.insertBefore( this[ 0 ] );
+ }
+
+ wrap.map( function() {
+ var elem = this;
+
+ while ( elem.firstElementChild ) {
+ elem = elem.firstElementChild;
+ }
+
+ return elem;
+ } ).append( this );
+ }
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ if ( isFunction( html ) ) {
+ return this.each( function( i ) {
+ jQuery( this ).wrapInner( html.call( this, i ) );
+ } );
+ }
+
+ return this.each( function() {
+ var self = jQuery( this ),
+ contents = self.contents();
+
+ if ( contents.length ) {
+ contents.wrapAll( html );
+
+ } else {
+ self.append( html );
+ }
+ } );
+ },
+
+ wrap: function( html ) {
+ var htmlIsFunction = isFunction( html );
+
+ return this.each( function( i ) {
+ jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );
+ } );
+ },
+
+ unwrap: function( selector ) {
+ this.parent( selector ).not( "body" ).each( function() {
+ jQuery( this ).replaceWith( this.childNodes );
+ } );
+ return this;
+ }
+} );
+
+
+jQuery.expr.pseudos.hidden = function( elem ) {
+ return !jQuery.expr.pseudos.visible( elem );
+};
+jQuery.expr.pseudos.visible = function( elem ) {
+ return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
+};
+
+
+
+
+jQuery.ajaxSettings.xhr = function() {
+ try {
+ return new window.XMLHttpRequest();
+ } catch ( e ) {}
+};
+
+var xhrSuccessStatus = {
+
+ // File protocol always yields status code 0, assume 200
+ 0: 200,
+
+ // Support: IE <=9 only
+ // #1450: sometimes IE returns 1223 when it should be 204
+ 1223: 204
+ },
+ xhrSupported = jQuery.ajaxSettings.xhr();
+
+support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
+support.ajax = xhrSupported = !!xhrSupported;
+
+jQuery.ajaxTransport( function( options ) {
+ var callback, errorCallback;
+
+ // Cross domain only allowed if supported through XMLHttpRequest
+ if ( support.cors || xhrSupported && !options.crossDomain ) {
+ return {
+ send: function( headers, complete ) {
+ var i,
+ xhr = options.xhr();
+
+ xhr.open(
+ options.type,
+ options.url,
+ options.async,
+ options.username,
+ options.password
+ );
+
+ // Apply custom fields if provided
+ if ( options.xhrFields ) {
+ for ( i in options.xhrFields ) {
+ xhr[ i ] = options.xhrFields[ i ];
+ }
+ }
+
+ // Override mime type if needed
+ if ( options.mimeType && xhr.overrideMimeType ) {
+ xhr.overrideMimeType( options.mimeType );
+ }
+
+ // X-Requested-With header
+ // For cross-domain requests, seeing as conditions for a preflight are
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
+ // (it can always be set on a per-request basis or even using ajaxSetup)
+ // For same-domain requests, won't change header if already provided.
+ if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) {
+ headers[ "X-Requested-With" ] = "XMLHttpRequest";
+ }
+
+ // Set headers
+ for ( i in headers ) {
+ xhr.setRequestHeader( i, headers[ i ] );
+ }
+
+ // Callback
+ callback = function( type ) {
+ return function() {
+ if ( callback ) {
+ callback = errorCallback = xhr.onload =
+ xhr.onerror = xhr.onabort = xhr.ontimeout =
+ xhr.onreadystatechange = null;
+
+ if ( type === "abort" ) {
+ xhr.abort();
+ } else if ( type === "error" ) {
+
+ // Support: IE <=9 only
+ // On a manual native abort, IE9 throws
+ // errors on any property access that is not readyState
+ if ( typeof xhr.status !== "number" ) {
+ complete( 0, "error" );
+ } else {
+ complete(
+
+ // File: protocol always yields status 0; see #8605, #14207
+ xhr.status,
+ xhr.statusText
+ );
+ }
+ } else {
+ complete(
+ xhrSuccessStatus[ xhr.status ] || xhr.status,
+ xhr.statusText,
+
+ // Support: IE <=9 only
+ // IE9 has no XHR2 but throws on binary (trac-11426)
+ // For XHR2 non-text, let the caller handle it (gh-2498)
+ ( xhr.responseType || "text" ) !== "text" ||
+ typeof xhr.responseText !== "string" ?
+ { binary: xhr.response } :
+ { text: xhr.responseText },
+ xhr.getAllResponseHeaders()
+ );
+ }
+ }
+ };
+ };
+
+ // Listen to events
+ xhr.onload = callback();
+ errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" );
+
+ // Support: IE 9 only
+ // Use onreadystatechange to replace onabort
+ // to handle uncaught aborts
+ if ( xhr.onabort !== undefined ) {
+ xhr.onabort = errorCallback;
+ } else {
+ xhr.onreadystatechange = function() {
+
+ // Check readyState before timeout as it changes
+ if ( xhr.readyState === 4 ) {
+
+ // Allow onerror to be called first,
+ // but that will not handle a native abort
+ // Also, save errorCallback to a variable
+ // as xhr.onerror cannot be accessed
+ window.setTimeout( function() {
+ if ( callback ) {
+ errorCallback();
+ }
+ } );
+ }
+ };
+ }
+
+ // Create the abort callback
+ callback = callback( "abort" );
+
+ try {
+
+ // Do send the request (this may raise an exception)
+ xhr.send( options.hasContent && options.data || null );
+ } catch ( e ) {
+
+ // #14683: Only rethrow if this hasn't been notified as an error yet
+ if ( callback ) {
+ throw e;
+ }
+ }
+ },
+
+ abort: function() {
+ if ( callback ) {
+ callback();
+ }
+ }
+ };
+ }
+} );
+
+
+
+
+// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)
+jQuery.ajaxPrefilter( function( s ) {
+ if ( s.crossDomain ) {
+ s.contents.script = false;
+ }
+} );
+
+// Install script dataType
+jQuery.ajaxSetup( {
+ accepts: {
+ script: "text/javascript, application/javascript, " +
+ "application/ecmascript, application/x-ecmascript"
+ },
+ contents: {
+ script: /\b(?:java|ecma)script\b/
+ },
+ converters: {
+ "text script": function( text ) {
+ jQuery.globalEval( text );
+ return text;
+ }
+ }
+} );
+
+// Handle cache's special case and crossDomain
+jQuery.ajaxPrefilter( "script", function( s ) {
+ if ( s.cache === undefined ) {
+ s.cache = false;
+ }
+ if ( s.crossDomain ) {
+ s.type = "GET";
+ }
+} );
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function( s ) {
+
+ // This transport only deals with cross domain or forced-by-attrs requests
+ if ( s.crossDomain || s.scriptAttrs ) {
+ var script, callback;
+ return {
+ send: function( _, complete ) {
+ script = jQuery( "<script>" )
+ .attr( s.scriptAttrs || {} )
+ .prop( { charset: s.scriptCharset, src: s.url } )
+ .on( "load error", callback = function( evt ) {
+ script.remove();
+ callback = null;
+ if ( evt ) {
+ complete( evt.type === "error" ? 404 : 200, evt.type );
+ }
+ } );
+
+ // Use native DOM manipulation to avoid our domManip AJAX trickery
+ document.head.appendChild( script[ 0 ] );
+ },
+ abort: function() {
+ if ( callback ) {
+ callback();
+ }
+ }
+ };
+ }
+} );
+
+
+
+
+var oldCallbacks = [],
+ rjsonp = /(=)\?(?=&|$)|\?\?/;
+
+// Default jsonp settings
+jQuery.ajaxSetup( {
+ jsonp: "callback",
+ jsonpCallback: function() {
+ var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce.guid++ ) );
+ this[ callback ] = true;
+ return callback;
+ }
+} );
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+ var callbackName, overwritten, responseContainer,
+ jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
+ "url" :
+ typeof s.data === "string" &&
+ ( s.contentType || "" )
+ .indexOf( "application/x-www-form-urlencoded" ) === 0 &&
+ rjsonp.test( s.data ) && "data"
+ );
+
+ // Handle iff the expected data type is "jsonp" or we have a parameter to set
+ if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
+
+ // Get callback name, remembering preexisting value associated with it
+ callbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ?
+ s.jsonpCallback() :
+ s.jsonpCallback;
+
+ // Insert callback into url or form data
+ if ( jsonProp ) {
+ s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
+ } else if ( s.jsonp !== false ) {
+ s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
+ }
+
+ // Use data converter to retrieve json after script execution
+ s.converters[ "script json" ] = function() {
+ if ( !responseContainer ) {
+ jQuery.error( callbackName + " was not called" );
+ }
+ return responseContainer[ 0 ];
+ };
+
+ // Force json dataType
+ s.dataTypes[ 0 ] = "json";
+
+ // Install callback
+ overwritten = window[ callbackName ];
+ window[ callbackName ] = function() {
+ responseContainer = arguments;
+ };
+
+ // Clean-up function (fires after converters)
+ jqXHR.always( function() {
+
+ // If previous value didn't exist - remove it
+ if ( overwritten === undefined ) {
+ jQuery( window ).removeProp( callbackName );
+
+ // Otherwise restore preexisting value
+ } else {
+ window[ callbackName ] = overwritten;
+ }
+
+ // Save back as free
+ if ( s[ callbackName ] ) {
+
+ // Make sure that re-using the options doesn't screw things around
+ s.jsonpCallback = originalSettings.jsonpCallback;
+
+ // Save the callback name for future use
+ oldCallbacks.push( callbackName );
+ }
+
+ // Call if it was a function and we have a response
+ if ( responseContainer && isFunction( overwritten ) ) {
+ overwritten( responseContainer[ 0 ] );
+ }
+
+ responseContainer = overwritten = undefined;
+ } );
+
+ // Delegate to script
+ return "script";
+ }
+} );
+
+
+
+
+// Support: Safari 8 only
+// In Safari 8 documents created via document.implementation.createHTMLDocument
+// collapse sibling forms: the second one becomes a child of the first one.
+// Because of that, this security measure has to be disabled in Safari 8.
+// https://bugs.webkit.org/show_bug.cgi?id=137337
+support.createHTMLDocument = ( function() {
+ var body = document.implementation.createHTMLDocument( "" ).body;
+ body.innerHTML = "<form></form><form></form>";
+ return body.childNodes.length === 2;
+} )();
+
+
+// Argument "data" should be string of html
+// context (optional): If specified, the fragment will be created in this context,
+// defaults to document
+// keepScripts (optional): If true, will include scripts passed in the html string
+jQuery.parseHTML = function( data, context, keepScripts ) {
+ if ( typeof data !== "string" ) {
+ return [];
+ }
+ if ( typeof context === "boolean" ) {
+ keepScripts = context;
+ context = false;
+ }
+
+ var base, parsed, scripts;
+
+ if ( !context ) {
+
+ // Stop scripts or inline event handlers from being executed immediately
+ // by using document.implementation
+ if ( support.createHTMLDocument ) {
+ context = document.implementation.createHTMLDocument( "" );
+
+ // Set the base href for the created document
+ // so any parsed elements with URLs
+ // are based on the document's URL (gh-2965)
+ base = context.createElement( "base" );
+ base.href = document.location.href;
+ context.head.appendChild( base );
+ } else {
+ context = document;
+ }
+ }
+
+ parsed = rsingleTag.exec( data );
+ scripts = !keepScripts && [];
+
+ // Single tag
+ if ( parsed ) {
+ return [ context.createElement( parsed[ 1 ] ) ];
+ }
+
+ parsed = buildFragment( [ data ], context, scripts );
+
+ if ( scripts && scripts.length ) {
+ jQuery( scripts ).remove();
+ }
+
+ return jQuery.merge( [], parsed.childNodes );
+};
+
+
+/**
+ * Load a url into a page
+ */
+jQuery.fn.load = function( url, params, callback ) {
+ var selector, type, response,
+ self = this,
+ off = url.indexOf( " " );
+
+ if ( off > -1 ) {
+ selector = stripAndCollapse( url.slice( off ) );
+ url = url.slice( 0, off );
+ }
+
+ // If it's a function
+ if ( isFunction( params ) ) {
+
+ // We assume that it's the callback
+ callback = params;
+ params = undefined;
+
+ // Otherwise, build a param string
+ } else if ( params && typeof params === "object" ) {
+ type = "POST";
+ }
+
+ // If we have elements to modify, make the request
+ if ( self.length > 0 ) {
+ jQuery.ajax( {
+ url: url,
+
+ // If "type" variable is undefined, then "GET" method will be used.
+ // Make value of this field explicit since
+ // user can override it through ajaxSetup method
+ type: type || "GET",
+ dataType: "html",
+ data: params
+ } ).done( function( responseText ) {
+
+ // Save response for use in complete callback
+ response = arguments;
+
+ self.html( selector ?
+
+ // If a selector was specified, locate the right elements in a dummy div
+ // Exclude scripts to avoid IE 'Permission Denied' errors
+ jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :
+
+ // Otherwise use the full result
+ responseText );
+
+ // If the request succeeds, this function gets "data", "status", "jqXHR"
+ // but they are ignored because response was set above.
+ // If it fails, this function gets "jqXHR", "status", "error"
+ } ).always( callback && function( jqXHR, status ) {
+ self.each( function() {
+ callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );
+ } );
+ } );
+ }
+
+ return this;
+};
+
+
+
+
+jQuery.expr.pseudos.animated = function( elem ) {
+ return jQuery.grep( jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ } ).length;
+};
+
+
+
+
+jQuery.offset = {
+ setOffset: function( elem, options, i ) {
+ var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
+ position = jQuery.css( elem, "position" ),
+ curElem = jQuery( elem ),
+ props = {};
+
+ // Set position first, in-case top/left are set even on static elem
+ if ( position === "static" ) {
+ elem.style.position = "relative";
+ }
+
+ curOffset = curElem.offset();
+ curCSSTop = jQuery.css( elem, "top" );
+ curCSSLeft = jQuery.css( elem, "left" );
+ calculatePosition = ( position === "absolute" || position === "fixed" ) &&
+ ( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1;
+
+ // Need to be able to calculate position if either
+ // top or left is auto and position is either absolute or fixed
+ if ( calculatePosition ) {
+ curPosition = curElem.position();
+ curTop = curPosition.top;
+ curLeft = curPosition.left;
+
+ } else {
+ curTop = parseFloat( curCSSTop ) || 0;
+ curLeft = parseFloat( curCSSLeft ) || 0;
+ }
+
+ if ( isFunction( options ) ) {
+
+ // Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
+ options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
+ }
+
+ if ( options.top != null ) {
+ props.top = ( options.top - curOffset.top ) + curTop;
+ }
+ if ( options.left != null ) {
+ props.left = ( options.left - curOffset.left ) + curLeft;
+ }
+
+ if ( "using" in options ) {
+ options.using.call( elem, props );
+
+ } else {
+ if ( typeof props.top === "number" ) {
+ props.top += "px";
+ }
+ if ( typeof props.left === "number" ) {
+ props.left += "px";
+ }
+ curElem.css( props );
+ }
+ }
+};
+
+jQuery.fn.extend( {
+
+ // offset() relates an element's border box to the document origin
+ offset: function( options ) {
+
+ // Preserve chaining for setter
+ if ( arguments.length ) {
+ return options === undefined ?
+ this :
+ this.each( function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ } );
+ }
+
+ var rect, win,
+ elem = this[ 0 ];
+
+ if ( !elem ) {
+ return;
+ }
+
+ // Return zeros for disconnected and hidden (display: none) elements (gh-2310)
+ // Support: IE <=11 only
+ // Running getBoundingClientRect on a
+ // disconnected node in IE throws an error
+ if ( !elem.getClientRects().length ) {
+ return { top: 0, left: 0 };
+ }
+
+ // Get document-relative position by adding viewport scroll to viewport-relative gBCR
+ rect = elem.getBoundingClientRect();
+ win = elem.ownerDocument.defaultView;
+ return {
+ top: rect.top + win.pageYOffset,
+ left: rect.left + win.pageXOffset
+ };
+ },
+
+ // position() relates an element's margin box to its offset parent's padding box
+ // This corresponds to the behavior of CSS absolute positioning
+ position: function() {
+ if ( !this[ 0 ] ) {
+ return;
+ }
+
+ var offsetParent, offset, doc,
+ elem = this[ 0 ],
+ parentOffset = { top: 0, left: 0 };
+
+ // position:fixed elements are offset from the viewport, which itself always has zero offset
+ if ( jQuery.css( elem, "position" ) === "fixed" ) {
+
+ // Assume position:fixed implies availability of getBoundingClientRect
+ offset = elem.getBoundingClientRect();
+
+ } else {
+ offset = this.offset();
+
+ // Account for the *real* offset parent, which can be the document or its root element
+ // when a statically positioned element is identified
+ doc = elem.ownerDocument;
+ offsetParent = elem.offsetParent || doc.documentElement;
+ while ( offsetParent &&
+ ( offsetParent === doc.body || offsetParent === doc.documentElement ) &&
+ jQuery.css( offsetParent, "position" ) === "static" ) {
+
+ offsetParent = offsetParent.parentNode;
+ }
+ if ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) {
+
+ // Incorporate borders into its offset, since they are outside its content origin
+ parentOffset = jQuery( offsetParent ).offset();
+ parentOffset.top += jQuery.css( offsetParent, "borderTopWidth", true );
+ parentOffset.left += jQuery.css( offsetParent, "borderLeftWidth", true );
+ }
+ }
+
+ // Subtract parent offsets and element margins
+ return {
+ top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
+ left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
+ };
+ },
+
+ // This method will return documentElement in the following cases:
+ // 1) For the element inside the iframe without offsetParent, this method will return
+ // documentElement of the parent window
+ // 2) For the hidden or detached element
+ // 3) For body or html element, i.e. in case of the html node - it will return itself
+ //
+ // but those exceptions were never presented as a real life use-cases
+ // and might be considered as more preferable results.
+ //
+ // This logic, however, is not guaranteed and can change at any point in the future
+ offsetParent: function() {
+ return this.map( function() {
+ var offsetParent = this.offsetParent;
+
+ while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+
+ return offsetParent || documentElement;
+ } );
+ }
+} );
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
+ var top = "pageYOffset" === prop;
+
+ jQuery.fn[ method ] = function( val ) {
+ return access( this, function( elem, method, val ) {
+
+ // Coalesce documents and windows
+ var win;
+ if ( isWindow( elem ) ) {
+ win = elem;
+ } else if ( elem.nodeType === 9 ) {
+ win = elem.defaultView;
+ }
+
+ if ( val === undefined ) {
+ return win ? win[ prop ] : elem[ method ];
+ }
+
+ if ( win ) {
+ win.scrollTo(
+ !top ? val : win.pageXOffset,
+ top ? val : win.pageYOffset
+ );
+
+ } else {
+ elem[ method ] = val;
+ }
+ }, method, val, arguments.length );
+ };
+} );
+
+// Support: Safari <=7 - 9.1, Chrome <=37 - 49
+// Add the top/left cssHooks using jQuery.fn.position
+// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
+// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347
+// getComputedStyle returns percent when specified for top/left/bottom/right;
+// rather than make the css module depend on the offset module, just check for it here
+jQuery.each( [ "top", "left" ], function( _i, prop ) {
+ jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
+ function( elem, computed ) {
+ if ( computed ) {
+ computed = curCSS( elem, prop );
+
+ // If curCSS returns percentage, fallback to offset
+ return rnumnonpx.test( computed ) ?
+ jQuery( elem ).position()[ prop ] + "px" :
+ computed;
+ }
+ }
+ );
+} );
+
+
+// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+ jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name },
+ function( defaultExtra, funcName ) {
+
+ // Margin is only for outerHeight, outerWidth
+ jQuery.fn[ funcName ] = function( margin, value ) {
+ var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
+ extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
+
+ return access( this, function( elem, type, value ) {
+ var doc;
+
+ if ( isWindow( elem ) ) {
+
+ // $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)
+ return funcName.indexOf( "outer" ) === 0 ?
+ elem[ "inner" + name ] :
+ elem.document.documentElement[ "client" + name ];
+ }
+
+ // Get document width or height
+ if ( elem.nodeType === 9 ) {
+ doc = elem.documentElement;
+
+ // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
+ // whichever is greatest
+ return Math.max(
+ elem.body[ "scroll" + name ], doc[ "scroll" + name ],
+ elem.body[ "offset" + name ], doc[ "offset" + name ],
+ doc[ "client" + name ]
+ );
+ }
+
+ return value === undefined ?
+
+ // Get width or height on the element, requesting but not forcing parseFloat
+ jQuery.css( elem, type, extra ) :
+
+ // Set width or height on the element
+ jQuery.style( elem, type, value, extra );
+ }, type, chainable ? margin : undefined, chainable );
+ };
+ } );
+} );
+
+
+jQuery.each( [
+ "ajaxStart",
+ "ajaxStop",
+ "ajaxComplete",
+ "ajaxError",
+ "ajaxSuccess",
+ "ajaxSend"
+], function( _i, type ) {
+ jQuery.fn[ type ] = function( fn ) {
+ return this.on( type, fn );
+ };
+} );
+
+
+
+
+jQuery.fn.extend( {
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.on( types, selector, data, fn );
+ },
+ undelegate: function( selector, types, fn ) {
+
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length === 1 ?
+ this.off( selector, "**" ) :
+ this.off( types, selector || "**", fn );
+ },
+
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ }
+} );
+
+jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup contextmenu" ).split( " " ),
+ function( _i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ return arguments.length > 0 ?
+ this.on( name, null, data, fn ) :
+ this.trigger( name );
+ };
+ } );
+
+
+
+
+// Support: Android <=4.0 only
+// Make sure we trim BOM and NBSP
+var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
+
+// Bind a function to a context, optionally partially applying any
+// arguments.
+// jQuery.proxy is deprecated to promote standards (specifically Function#bind)
+// However, it is not slated for removal any time soon
+jQuery.proxy = function( fn, context ) {
+ var tmp, args, proxy;
+
+ if ( typeof context === "string" ) {
+ tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ args = slice.call( arguments, 2 );
+ proxy = function() {
+ return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || jQuery.guid++;
+
+ return proxy;
+};
+
+jQuery.holdReady = function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+};
+jQuery.isArray = Array.isArray;
+jQuery.parseJSON = JSON.parse;
+jQuery.nodeName = nodeName;
+jQuery.isFunction = isFunction;
+jQuery.isWindow = isWindow;
+jQuery.camelCase = camelCase;
+jQuery.type = toType;
+
+jQuery.now = Date.now;
+
+jQuery.isNumeric = function( obj ) {
+
+ // As of jQuery 3.0, isNumeric is limited to
+ // strings and numbers (primitives or objects)
+ // that can be coerced to finite numbers (gh-2662)
+ var type = jQuery.type( obj );
+ return ( type === "number" || type === "string" ) &&
+
+ // parseFloat NaNs numeric-cast false positives ("")
+ // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
+ // subtraction forces infinities to NaN
+ !isNaN( obj - parseFloat( obj ) );
+};
+
+jQuery.trim = function( text ) {
+ return text == null ?
+ "" :
+ ( text + "" ).replace( rtrim, "" );
+};
+
+
+
+// Register as a named AMD module, since jQuery can be concatenated with other
+// files that may use define, but not via a proper concatenation script that
+// understands anonymous AMD modules. A named AMD is safest and most robust
+// way to register. Lowercase jquery is used because AMD module names are
+// derived from file names, and jQuery is normally delivered in a lowercase
+// file name. Do this after creating the global so that if an AMD module wants
+// to call noConflict to hide this version of jQuery, it will work.
+
+// Note that for maximum portability, libraries that are not jQuery should
+// declare themselves as anonymous modules, and avoid setting a global if an
+// AMD loader is present. jQuery is a special case. For more information, see
+// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
+
+if ( typeof define === "function" && define.amd ) {
+ define( "jquery", [], function() {
+ return jQuery;
+ } );
+}
+
+
+
+
+var
+
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$;
+
+jQuery.noConflict = function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+};
+
+// Expose jQuery and $ identifiers, even in AMD
+// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
+// and CommonJS for browser emulators (#13566)
+if ( typeof noGlobal === "undefined" ) {
+ window.jQuery = window.$ = jQuery;
+}
+
+
+
+
+return jQuery;
+} );
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_55_fbf9ee_1x400.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_55_fbf9ee_1x400.png
new file mode 100644
index 0000000..cd43001
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_55_fbf9ee_1x400.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_65_ffffff_1x400.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_65_ffffff_1x400.png
new file mode 100644
index 0000000..e376256
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_65_ffffff_1x400.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_dadada_1x400.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_dadada_1x400.png
new file mode 100644
index 0000000..4caff27
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_dadada_1x400.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_e6e6e6_1x400.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_e6e6e6_1x400.png
new file mode 100644
index 0000000..ade4aea
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_75_e6e6e6_1x400.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_95_fef1ec_1x400.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_95_fef1ec_1x400.png
new file mode 100644
index 0000000..7202e44
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_glass_95_fef1ec_1x400.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_highlight-soft_75_cccccc_1x100.png
new file mode 100644
index 0000000..e898778
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-bg_highlight-soft_75_cccccc_1x100.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_222222_256x240.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_222222_256x240.png
new file mode 100644
index 0000000..e723e17
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_222222_256x240.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_2e83ff_256x240.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_2e83ff_256x240.png
new file mode 100644
index 0000000..1f5f497
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_2e83ff_256x240.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_454545_256x240.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_454545_256x240.png
new file mode 100644
index 0000000..618f5b0
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_454545_256x240.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_888888_256x240.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_888888_256x240.png
new file mode 100644
index 0000000..ee5e33f
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_888888_256x240.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_cd0a0a_256x240.png b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_cd0a0a_256x240.png
new file mode 100644
index 0000000..7e8ebc1
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/images/ui-icons_cd0a0a_256x240.png
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.js b/src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.js
new file mode 100644
index 0000000..2a4e76d
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.js
@@ -0,0 +1,2815 @@
+/*! jQuery UI - v1.12.1 - 2020-06-16
+* http://jqueryui.com
+* Includes: widget.js, form-reset-mixin.js, keycode.js, labels.js, unique-id.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/tabs.js
+* Copyright jQuery Foundation and other contributors; Licensed MIT */
+
+(function( factory ) {
+ if ( typeof define === "function" && define.amd ) {
+
+ // AMD. Register as an anonymous module.
+ define([ "jquery" ], factory );
+ } else {
+
+ // Browser globals
+ factory( jQuery );
+ }
+}(function( $ ) {
+
+$.ui = $.ui || {};
+
+var version = $.ui.version = "1.12.1";
+
+
+/*!
+ * jQuery UI Widget 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: Widget
+//>>group: Core
+//>>description: Provides a factory for creating stateful widgets with a common API.
+//>>docs: http://api.jqueryui.com/jQuery.widget/
+//>>demos: http://jqueryui.com/widget/
+
+
+
+var widgetUuid = 0;
+var widgetSlice = Array.prototype.slice;
+
+$.cleanData = ( function( orig ) {
+ return function( elems ) {
+ var events, elem, i;
+ for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
+ try {
+
+ // Only trigger remove when necessary to save time
+ events = $._data( elem, "events" );
+ if ( events && events.remove ) {
+ $( elem ).triggerHandler( "remove" );
+ }
+
+ // Http://bugs.jquery.com/ticket/8235
+ } catch ( e ) {}
+ }
+ orig( elems );
+ };
+} )( $.cleanData );
+
+$.widget = function( name, base, prototype ) {
+ var existingConstructor, constructor, basePrototype;
+
+ // ProxiedPrototype allows the provided prototype to remain unmodified
+ // so that it can be used as a mixin for multiple widgets (#8876)
+ var proxiedPrototype = {};
+
+ var namespace = name.split( "." )[ 0 ];
+ name = name.split( "." )[ 1 ];
+ var fullName = namespace + "-" + name;
+
+ if ( !prototype ) {
+ prototype = base;
+ base = $.Widget;
+ }
+
+ if ( $.isArray( prototype ) ) {
+ prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
+ }
+
+ // Create selector for plugin
+ $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
+ return !!$.data( elem, fullName );
+ };
+
+ $[ namespace ] = $[ namespace ] || {};
+ existingConstructor = $[ namespace ][ name ];
+ constructor = $[ namespace ][ name ] = function( options, element ) {
+
+ // Allow instantiation without "new" keyword
+ if ( !this._createWidget ) {
+ return new constructor( options, element );
+ }
+
+ // Allow instantiation without initializing for simple inheritance
+ // must use "new" keyword (the code above always passes args)
+ if ( arguments.length ) {
+ this._createWidget( options, element );
+ }
+ };
+
+ // Extend with the existing constructor to carry over any static properties
+ $.extend( constructor, existingConstructor, {
+ version: prototype.version,
+
+ // Copy the object used to create the prototype in case we need to
+ // redefine the widget later
+ _proto: $.extend( {}, prototype ),
+
+ // Track widgets that inherit from this widget in case this widget is
+ // redefined after a widget inherits from it
+ _childConstructors: []
+ } );
+
+ basePrototype = new base();
+
+ // We need to make the options hash a property directly on the new instance
+ // otherwise we'll modify the options hash on the prototype that we're
+ // inheriting from
+ basePrototype.options = $.widget.extend( {}, basePrototype.options );
+ $.each( prototype, function( prop, value ) {
+ if ( !$.isFunction( value ) ) {
+ proxiedPrototype[ prop ] = value;
+ return;
+ }
+ proxiedPrototype[ prop ] = ( function() {
+ function _super() {
+ return base.prototype[ prop ].apply( this, arguments );
+ }
+
+ function _superApply( args ) {
+ return base.prototype[ prop ].apply( this, args );
+ }
+
+ return function() {
+ var __super = this._super;
+ var __superApply = this._superApply;
+ var returnValue;
+
+ this._super = _super;
+ this._superApply = _superApply;
+
+ returnValue = value.apply( this, arguments );
+
+ this._super = __super;
+ this._superApply = __superApply;
+
+ return returnValue;
+ };
+ } )();
+ } );
+ constructor.prototype = $.widget.extend( basePrototype, {
+
+ // TODO: remove support for widgetEventPrefix
+ // always use the name + a colon as the prefix, e.g., draggable:start
+ // don't prefix for widgets that aren't DOM-based
+ widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name
+ }, proxiedPrototype, {
+ constructor: constructor,
+ namespace: namespace,
+ widgetName: name,
+ widgetFullName: fullName
+ } );
+
+ // If this widget is being redefined then we need to find all widgets that
+ // are inheriting from it and redefine all of them so that they inherit from
+ // the new version of this widget. We're essentially trying to replace one
+ // level in the prototype chain.
+ if ( existingConstructor ) {
+ $.each( existingConstructor._childConstructors, function( i, child ) {
+ var childPrototype = child.prototype;
+
+ // Redefine the child widget using the same prototype that was
+ // originally used, but inherit from the new version of the base
+ $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor,
+ child._proto );
+ } );
+
+ // Remove the list of existing child constructors from the old constructor
+ // so the old child constructors can be garbage collected
+ delete existingConstructor._childConstructors;
+ } else {
+ base._childConstructors.push( constructor );
+ }
+
+ $.widget.bridge( name, constructor );
+
+ return constructor;
+};
+
+$.widget.extend = function( target ) {
+ var input = widgetSlice.call( arguments, 1 );
+ var inputIndex = 0;
+ var inputLength = input.length;
+ var key;
+ var value;
+
+ for ( ; inputIndex < inputLength; inputIndex++ ) {
+ for ( key in input[ inputIndex ] ) {
+ value = input[ inputIndex ][ key ];
+ if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
+
+ // Clone objects
+ if ( $.isPlainObject( value ) ) {
+ target[ key ] = $.isPlainObject( target[ key ] ) ?
+ $.widget.extend( {}, target[ key ], value ) :
+
+ // Don't extend strings, arrays, etc. with objects
+ $.widget.extend( {}, value );
+
+ // Copy everything else by reference
+ } else {
+ target[ key ] = value;
+ }
+ }
+ }
+ }
+ return target;
+};
+
+$.widget.bridge = function( name, object ) {
+ var fullName = object.prototype.widgetFullName || name;
+ $.fn[ name ] = function( options ) {
+ var isMethodCall = typeof options === "string";
+ var args = widgetSlice.call( arguments, 1 );
+ var returnValue = this;
+
+ if ( isMethodCall ) {
+
+ // If this is an empty collection, we need to have the instance method
+ // return undefined instead of the jQuery instance
+ if ( !this.length && options === "instance" ) {
+ returnValue = undefined;
+ } else {
+ this.each( function() {
+ var methodValue;
+ var instance = $.data( this, fullName );
+
+ if ( options === "instance" ) {
+ returnValue = instance;
+ return false;
+ }
+
+ if ( !instance ) {
+ return $.error( "cannot call methods on " + name +
+ " prior to initialization; " +
+ "attempted to call method '" + options + "'" );
+ }
+
+ if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) {
+ return $.error( "no such method '" + options + "' for " + name +
+ " widget instance" );
+ }
+
+ methodValue = instance[ options ].apply( instance, args );
+
+ if ( methodValue !== instance && methodValue !== undefined ) {
+ returnValue = methodValue && methodValue.jquery ?
+ returnValue.pushStack( methodValue.get() ) :
+ methodValue;
+ return false;
+ }
+ } );
+ }
+ } else {
+
+ // Allow multiple hashes to be passed on init
+ if ( args.length ) {
+ options = $.widget.extend.apply( null, [ options ].concat( args ) );
+ }
+
+ this.each( function() {
+ var instance = $.data( this, fullName );
+ if ( instance ) {
+ instance.option( options || {} );
+ if ( instance._init ) {
+ instance._init();
+ }
+ } else {
+ $.data( this, fullName, new object( options, this ) );
+ }
+ } );
+ }
+
+ return returnValue;
+ };
+};
+
+$.Widget = function( /* options, element */ ) {};
+$.Widget._childConstructors = [];
+
+$.Widget.prototype = {
+ widgetName: "widget",
+ widgetEventPrefix: "",
+ defaultElement: "<div>",
+
+ options: {
+ classes: {},
+ disabled: false,
+
+ // Callbacks
+ create: null
+ },
+
+ _createWidget: function( options, element ) {
+ element = $( element || this.defaultElement || this )[ 0 ];
+ this.element = $( element );
+ this.uuid = widgetUuid++;
+ this.eventNamespace = "." + this.widgetName + this.uuid;
+
+ this.bindings = $();
+ this.hoverable = $();
+ this.focusable = $();
+ this.classesElementLookup = {};
+
+ if ( element !== this ) {
+ $.data( element, this.widgetFullName, this );
+ this._on( true, this.element, {
+ remove: function( event ) {
+ if ( event.target === element ) {
+ this.destroy();
+ }
+ }
+ } );
+ this.document = $( element.style ?
+
+ // Element within the document
+ element.ownerDocument :
+
+ // Element is window or document
+ element.document || element );
+ this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );
+ }
+
+ this.options = $.widget.extend( {},
+ this.options,
+ this._getCreateOptions(),
+ options );
+
+ this._create();
+
+ if ( this.options.disabled ) {
+ this._setOptionDisabled( this.options.disabled );
+ }
+
+ this._trigger( "create", null, this._getCreateEventData() );
+ this._init();
+ },
+
+ _getCreateOptions: function() {
+ return {};
+ },
+
+ _getCreateEventData: $.noop,
+
+ _create: $.noop,
+
+ _init: $.noop,
+
+ destroy: function() {
+ var that = this;
+
+ this._destroy();
+ $.each( this.classesElementLookup, function( key, value ) {
+ that._removeClass( value, key );
+ } );
+
+ // We can probably remove the unbind calls in 2.0
+ // all event bindings should go through this._on()
+ this.element
+ .off( this.eventNamespace )
+ .removeData( this.widgetFullName );
+ this.widget()
+ .off( this.eventNamespace )
+ .removeAttr( "aria-disabled" );
+
+ // Clean up events and states
+ this.bindings.off( this.eventNamespace );
+ },
+
+ _destroy: $.noop,
+
+ widget: function() {
+ return this.element;
+ },
+
+ option: function( key, value ) {
+ var options = key;
+ var parts;
+ var curOption;
+ var i;
+
+ if ( arguments.length === 0 ) {
+
+ // Don't return a reference to the internal hash
+ return $.widget.extend( {}, this.options );
+ }
+
+ if ( typeof key === "string" ) {
+
+ // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
+ options = {};
+ parts = key.split( "." );
+ key = parts.shift();
+ if ( parts.length ) {
+ curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
+ for ( i = 0; i < parts.length - 1; i++ ) {
+ curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
+ curOption = curOption[ parts[ i ] ];
+ }
+ key = parts.pop();
+ if ( arguments.length === 1 ) {
+ return curOption[ key ] === undefined ? null : curOption[ key ];
+ }
+ curOption[ key ] = value;
+ } else {
+ if ( arguments.length === 1 ) {
+ return this.options[ key ] === undefined ? null : this.options[ key ];
+ }
+ options[ key ] = value;
+ }
+ }
+
+ this._setOptions( options );
+
+ return this;
+ },
+
+ _setOptions: function( options ) {
+ var key;
+
+ for ( key in options ) {
+ this._setOption( key, options[ key ] );
+ }
+
+ return this;
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "classes" ) {
+ this._setOptionClasses( value );
+ }
+
+ this.options[ key ] = value;
+
+ if ( key === "disabled" ) {
+ this._setOptionDisabled( value );
+ }
+
+ return this;
+ },
+
+ _setOptionClasses: function( value ) {
+ var classKey, elements, currentElements;
+
+ for ( classKey in value ) {
+ currentElements = this.classesElementLookup[ classKey ];
+ if ( value[ classKey ] === this.options.classes[ classKey ] ||
+ !currentElements ||
+ !currentElements.length ) {
+ continue;
+ }
+
+ // We are doing this to create a new jQuery object because the _removeClass() call
+ // on the next line is going to destroy the reference to the current elements being
+ // tracked. We need to save a copy of this collection so that we can add the new classes
+ // below.
+ elements = $( currentElements.get() );
+ this._removeClass( currentElements, classKey );
+
+ // We don't use _addClass() here, because that uses this.options.classes
+ // for generating the string of classes. We want to use the value passed in from
+ // _setOption(), this is the new value of the classes option which was passed to
+ // _setOption(). We pass this value directly to _classes().
+ elements.addClass( this._classes( {
+ element: elements,
+ keys: classKey,
+ classes: value,
+ add: true
+ } ) );
+ }
+ },
+
+ _setOptionDisabled: function( value ) {
+ this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value );
+
+ // If the widget is becoming disabled, then nothing is interactive
+ if ( value ) {
+ this._removeClass( this.hoverable, null, "ui-state-hover" );
+ this._removeClass( this.focusable, null, "ui-state-focus" );
+ }
+ },
+
+ enable: function() {
+ return this._setOptions( { disabled: false } );
+ },
+
+ disable: function() {
+ return this._setOptions( { disabled: true } );
+ },
+
+ _classes: function( options ) {
+ var full = [];
+ var that = this;
+
+ options = $.extend( {
+ element: this.element,
+ classes: this.options.classes || {}
+ }, options );
+
+ function processClassString( classes, checkOption ) {
+ var current, i;
+ for ( i = 0; i < classes.length; i++ ) {
+ current = that.classesElementLookup[ classes[ i ] ] || $();
+ if ( options.add ) {
+ current = $( $.unique( current.get().concat( options.element.get() ) ) );
+ } else {
+ current = $( current.not( options.element ).get() );
+ }
+ that.classesElementLookup[ classes[ i ] ] = current;
+ full.push( classes[ i ] );
+ if ( checkOption && options.classes[ classes[ i ] ] ) {
+ full.push( options.classes[ classes[ i ] ] );
+ }
+ }
+ }
+
+ this._on( options.element, {
+ "remove": "_untrackClassesElement"
+ } );
+
+ if ( options.keys ) {
+ processClassString( options.keys.match( /\S+/g ) || [], true );
+ }
+ if ( options.extra ) {
+ processClassString( options.extra.match( /\S+/g ) || [] );
+ }
+
+ return full.join( " " );
+ },
+
+ _untrackClassesElement: function( event ) {
+ var that = this;
+ $.each( that.classesElementLookup, function( key, value ) {
+ if ( $.inArray( event.target, value ) !== -1 ) {
+ that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
+ }
+ } );
+ },
+
+ _removeClass: function( element, keys, extra ) {
+ return this._toggleClass( element, keys, extra, false );
+ },
+
+ _addClass: function( element, keys, extra ) {
+ return this._toggleClass( element, keys, extra, true );
+ },
+
+ _toggleClass: function( element, keys, extra, add ) {
+ add = ( typeof add === "boolean" ) ? add : extra;
+ var shift = ( typeof element === "string" || element === null ),
+ options = {
+ extra: shift ? keys : extra,
+ keys: shift ? element : keys,
+ element: shift ? this.element : element,
+ add: add
+ };
+ options.element.toggleClass( this._classes( options ), add );
+ return this;
+ },
+
+ _on: function( suppressDisabledCheck, element, handlers ) {
+ var delegateElement;
+ var instance = this;
+
+ // No suppressDisabledCheck flag, shuffle arguments
+ if ( typeof suppressDisabledCheck !== "boolean" ) {
+ handlers = element;
+ element = suppressDisabledCheck;
+ suppressDisabledCheck = false;
+ }
+
+ // No element argument, shuffle and use this.element
+ if ( !handlers ) {
+ handlers = element;
+ element = this.element;
+ delegateElement = this.widget();
+ } else {
+ element = delegateElement = $( element );
+ this.bindings = this.bindings.add( element );
+ }
+
+ $.each( handlers, function( event, handler ) {
+ function handlerProxy() {
+
+ // Allow widgets to customize the disabled handling
+ // - disabled as an array instead of boolean
+ // - disabled class as method for disabling individual parts
+ if ( !suppressDisabledCheck &&
+ ( instance.options.disabled === true ||
+ $( this ).hasClass( "ui-state-disabled" ) ) ) {
+ return;
+ }
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+
+ // Copy the guid so direct unbinding works
+ if ( typeof handler !== "string" ) {
+ handlerProxy.guid = handler.guid =
+ handler.guid || handlerProxy.guid || $.guid++;
+ }
+
+ var match = event.match( /^([\w:-]*)\s*(.*)$/ );
+ var eventName = match[ 1 ] + instance.eventNamespace;
+ var selector = match[ 2 ];
+
+ if ( selector ) {
+ delegateElement.on( eventName, selector, handlerProxy );
+ } else {
+ element.on( eventName, handlerProxy );
+ }
+ } );
+ },
+
+ _off: function( element, eventName ) {
+ eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
+ this.eventNamespace;
+ element.off( eventName ).off( eventName );
+
+ // Clear the stack to avoid memory leaks (#10056)
+ this.bindings = $( this.bindings.not( element ).get() );
+ this.focusable = $( this.focusable.not( element ).get() );
+ this.hoverable = $( this.hoverable.not( element ).get() );
+ },
+
+ _delay: function( handler, delay ) {
+ function handlerProxy() {
+ return ( typeof handler === "string" ? instance[ handler ] : handler )
+ .apply( instance, arguments );
+ }
+ var instance = this;
+ return setTimeout( handlerProxy, delay || 0 );
+ },
+
+ _hoverable: function( element ) {
+ this.hoverable = this.hoverable.add( element );
+ this._on( element, {
+ mouseenter: function( event ) {
+ this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
+ },
+ mouseleave: function( event ) {
+ this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
+ }
+ } );
+ },
+
+ _focusable: function( element ) {
+ this.focusable = this.focusable.add( element );
+ this._on( element, {
+ focusin: function( event ) {
+ this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
+ },
+ focusout: function( event ) {
+ this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
+ }
+ } );
+ },
+
+ _trigger: function( type, event, data ) {
+ var prop, orig;
+ var callback = this.options[ type ];
+
+ data = data || {};
+ event = $.Event( event );
+ event.type = ( type === this.widgetEventPrefix ?
+ type :
+ this.widgetEventPrefix + type ).toLowerCase();
+
+ // The original event may come from any element
+ // so we need to reset the target on the new event
+ event.target = this.element[ 0 ];
+
+ // Copy original event properties over to the new event
+ orig = event.originalEvent;
+ if ( orig ) {
+ for ( prop in orig ) {
+ if ( !( prop in event ) ) {
+ event[ prop ] = orig[ prop ];
+ }
+ }
+ }
+
+ this.element.trigger( event, data );
+ return !( $.isFunction( callback ) &&
+ callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
+ event.isDefaultPrevented() );
+ }
+};
+
+$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
+ $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
+ if ( typeof options === "string" ) {
+ options = { effect: options };
+ }
+
+ var hasOptions;
+ var effectName = !options ?
+ method :
+ options === true || typeof options === "number" ?
+ defaultEffect :
+ options.effect || defaultEffect;
+
+ options = options || {};
+ if ( typeof options === "number" ) {
+ options = { duration: options };
+ }
+
+ hasOptions = !$.isEmptyObject( options );
+ options.complete = callback;
+
+ if ( options.delay ) {
+ element.delay( options.delay );
+ }
+
+ if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
+ element[ method ]( options );
+ } else if ( effectName !== method && element[ effectName ] ) {
+ element[ effectName ]( options.duration, options.easing, callback );
+ } else {
+ element.queue( function( next ) {
+ $( this )[ method ]();
+ if ( callback ) {
+ callback.call( element[ 0 ] );
+ }
+ next();
+ } );
+ }
+ };
+} );
+
+var widget = $.widget;
+
+
+
+
+// Support: IE8 Only
+// IE8 does not support the form attribute and when it is supplied. It overwrites the form prop
+// with a string, so we need to find the proper form.
+var form = $.fn.form = function() {
+ return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form );
+};
+
+
+/*!
+ * jQuery UI Form Reset Mixin 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: Form Reset Mixin
+//>>group: Core
+//>>description: Refresh input widgets when their form is reset
+//>>docs: http://api.jqueryui.com/form-reset-mixin/
+
+
+
+var formResetMixin = $.ui.formResetMixin = {
+ _formResetHandler: function() {
+ var form = $( this );
+
+ // Wait for the form reset to actually happen before refreshing
+ setTimeout( function() {
+ var instances = form.data( "ui-form-reset-instances" );
+ $.each( instances, function() {
+ this.refresh();
+ } );
+ } );
+ },
+
+ _bindFormResetHandler: function() {
+ this.form = this.element.form();
+ if ( !this.form.length ) {
+ return;
+ }
+
+ var instances = this.form.data( "ui-form-reset-instances" ) || [];
+ if ( !instances.length ) {
+
+ // We don't use _on() here because we use a single event handler per form
+ this.form.on( "reset.ui-form-reset", this._formResetHandler );
+ }
+ instances.push( this );
+ this.form.data( "ui-form-reset-instances", instances );
+ },
+
+ _unbindFormResetHandler: function() {
+ if ( !this.form.length ) {
+ return;
+ }
+
+ var instances = this.form.data( "ui-form-reset-instances" );
+ instances.splice( $.inArray( this, instances ), 1 );
+ if ( instances.length ) {
+ this.form.data( "ui-form-reset-instances", instances );
+ } else {
+ this.form
+ .removeData( "ui-form-reset-instances" )
+ .off( "reset.ui-form-reset" );
+ }
+ }
+};
+
+
+/*!
+ * jQuery UI Keycode 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: Keycode
+//>>group: Core
+//>>description: Provide keycodes as keynames
+//>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/
+
+
+var keycode = $.ui.keyCode = {
+ BACKSPACE: 8,
+ COMMA: 188,
+ DELETE: 46,
+ DOWN: 40,
+ END: 35,
+ ENTER: 13,
+ ESCAPE: 27,
+ HOME: 36,
+ LEFT: 37,
+ PAGE_DOWN: 34,
+ PAGE_UP: 33,
+ PERIOD: 190,
+ RIGHT: 39,
+ SPACE: 32,
+ TAB: 9,
+ UP: 38
+};
+
+
+
+
+// Internal use only
+var escapeSelector = $.ui.escapeSelector = ( function() {
+ var selectorEscape = /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;
+ return function( selector ) {
+ return selector.replace( selectorEscape, "\\$1" );
+ };
+} )();
+
+
+/*!
+ * jQuery UI Labels 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: labels
+//>>group: Core
+//>>description: Find all the labels associated with a given input
+//>>docs: http://api.jqueryui.com/labels/
+
+
+
+var labels = $.fn.labels = function() {
+ var ancestor, selector, id, labels, ancestors;
+
+ // Check control.labels first
+ if ( this[ 0 ].labels && this[ 0 ].labels.length ) {
+ return this.pushStack( this[ 0 ].labels );
+ }
+
+ // Support: IE <= 11, FF <= 37, Android <= 2.3 only
+ // Above browsers do not support control.labels. Everything below is to support them
+ // as well as document fragments. control.labels does not work on document fragments
+ labels = this.eq( 0 ).parents( "label" );
+
+ // Look for the label based on the id
+ id = this.attr( "id" );
+ if ( id ) {
+
+ // We don't search against the document in case the element
+ // is disconnected from the DOM
+ ancestor = this.eq( 0 ).parents().last();
+
+ // Get a full set of top level ancestors
+ ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() );
+
+ // Create a selector for the label based on the id
+ selector = "label[for='" + $.ui.escapeSelector( id ) + "']";
+
+ labels = labels.add( ancestors.find( selector ).addBack( selector ) );
+
+ }
+
+ // Return whatever we have found for labels
+ return this.pushStack( labels );
+};
+
+
+/*!
+ * jQuery UI Unique ID 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: uniqueId
+//>>group: Core
+//>>description: Functions to generate and remove uniqueId's
+//>>docs: http://api.jqueryui.com/uniqueId/
+
+
+
+var uniqueId = $.fn.extend( {
+ uniqueId: ( function() {
+ var uuid = 0;
+
+ return function() {
+ return this.each( function() {
+ if ( !this.id ) {
+ this.id = "ui-id-" + ( ++uuid );
+ }
+ } );
+ };
+ } )(),
+
+ removeUniqueId: function() {
+ return this.each( function() {
+ if ( /^ui-id-\d+$/.test( this.id ) ) {
+ $( this ).removeAttr( "id" );
+ }
+ } );
+ }
+} );
+
+
+/*!
+ * jQuery UI Controlgroup 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: Controlgroup
+//>>group: Widgets
+//>>description: Visually groups form control widgets
+//>>docs: http://api.jqueryui.com/controlgroup/
+//>>demos: http://jqueryui.com/controlgroup/
+//>>css.structure: ../../themes/base/core.css
+//>>css.structure: ../../themes/base/controlgroup.css
+//>>css.theme: ../../themes/base/theme.css
+
+
+var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g;
+
+var widgetsControlgroup = $.widget( "ui.controlgroup", {
+ version: "1.12.1",
+ defaultElement: "<div>",
+ options: {
+ direction: "horizontal",
+ disabled: null,
+ onlyVisible: true,
+ items: {
+ "button": "input[type=button], input[type=submit], input[type=reset], button, a",
+ "controlgroupLabel": ".ui-controlgroup-label",
+ "checkboxradio": "input[type='checkbox'], input[type='radio']",
+ "selectmenu": "select",
+ "spinner": ".ui-spinner-input"
+ }
+ },
+
+ _create: function() {
+ this._enhance();
+ },
+
+ // To support the enhanced option in jQuery Mobile, we isolate DOM manipulation
+ _enhance: function() {
+ this.element.attr( "role", "toolbar" );
+ this.refresh();
+ },
+
+ _destroy: function() {
+ this._callChildMethod( "destroy" );
+ this.childWidgets.removeData( "ui-controlgroup-data" );
+ this.element.removeAttr( "role" );
+ if ( this.options.items.controlgroupLabel ) {
+ this.element
+ .find( this.options.items.controlgroupLabel )
+ .find( ".ui-controlgroup-label-contents" )
+ .contents().unwrap();
+ }
+ },
+
+ _initWidgets: function() {
+ var that = this,
+ childWidgets = [];
+
+ // First we iterate over each of the items options
+ $.each( this.options.items, function( widget, selector ) {
+ var labels;
+ var options = {};
+
+ // Make sure the widget has a selector set
+ if ( !selector ) {
+ return;
+ }
+
+ if ( widget === "controlgroupLabel" ) {
+ labels = that.element.find( selector );
+ labels.each( function() {
+ var element = $( this );
+
+ if ( element.children( ".ui-controlgroup-label-contents" ).length ) {
+ return;
+ }
+ element.contents()
+ .wrapAll( "<span class='ui-controlgroup-label-contents'></span>" );
+ } );
+ that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" );
+ childWidgets = childWidgets.concat( labels.get() );
+ return;
+ }
+
+ // Make sure the widget actually exists
+ if ( !$.fn[ widget ] ) {
+ return;
+ }
+
+ // We assume everything is in the middle to start because we can't determine
+ // first / last elements until all enhancments are done.
+ if ( that[ "_" + widget + "Options" ] ) {
+ options = that[ "_" + widget + "Options" ]( "middle" );
+ } else {
+ options = { classes: {} };
+ }
+
+ // Find instances of this widget inside controlgroup and init them
+ that.element
+ .find( selector )
+ .each( function() {
+ var element = $( this );
+ var instance = element[ widget ]( "instance" );
+
+ // We need to clone the default options for this type of widget to avoid
+ // polluting the variable options which has a wider scope than a single widget.
+ var instanceOptions = $.widget.extend( {}, options );
+
+ // If the button is the child of a spinner ignore it
+ // TODO: Find a more generic solution
+ if ( widget === "button" && element.parent( ".ui-spinner" ).length ) {
+ return;
+ }
+
+ // Create the widget if it doesn't exist
+ if ( !instance ) {
+ instance = element[ widget ]()[ widget ]( "instance" );
+ }
+ if ( instance ) {
+ instanceOptions.classes =
+ that._resolveClassesValues( instanceOptions.classes, instance );
+ }
+ element[ widget ]( instanceOptions );
+
+ // Store an instance of the controlgroup to be able to reference
+ // from the outermost element for changing options and refresh
+ var widgetElement = element[ widget ]( "widget" );
+ $.data( widgetElement[ 0 ], "ui-controlgroup-data",
+ instance ? instance : element[ widget ]( "instance" ) );
+
+ childWidgets.push( widgetElement[ 0 ] );
+ } );
+ } );
+
+ this.childWidgets = $( $.unique( childWidgets ) );
+ this._addClass( this.childWidgets, "ui-controlgroup-item" );
+ },
+
+ _callChildMethod: function( method ) {
+ this.childWidgets.each( function() {
+ var element = $( this ),
+ data = element.data( "ui-controlgroup-data" );
+ if ( data && data[ method ] ) {
+ data[ method ]();
+ }
+ } );
+ },
+
+ _updateCornerClass: function( element, position ) {
+ var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all";
+ var add = this._buildSimpleOptions( position, "label" ).classes.label;
+
+ this._removeClass( element, null, remove );
+ this._addClass( element, null, add );
+ },
+
+ _buildSimpleOptions: function( position, key ) {
+ var direction = this.options.direction === "vertical";
+ var result = {
+ classes: {}
+ };
+ result.classes[ key ] = {
+ "middle": "",
+ "first": "ui-corner-" + ( direction ? "top" : "left" ),
+ "last": "ui-corner-" + ( direction ? "bottom" : "right" ),
+ "only": "ui-corner-all"
+ }[ position ];
+
+ return result;
+ },
+
+ _spinnerOptions: function( position ) {
+ var options = this._buildSimpleOptions( position, "ui-spinner" );
+
+ options.classes[ "ui-spinner-up" ] = "";
+ options.classes[ "ui-spinner-down" ] = "";
+
+ return options;
+ },
+
+ _buttonOptions: function( position ) {
+ return this._buildSimpleOptions( position, "ui-button" );
+ },
+
+ _checkboxradioOptions: function( position ) {
+ return this._buildSimpleOptions( position, "ui-checkboxradio-label" );
+ },
+
+ _selectmenuOptions: function( position ) {
+ var direction = this.options.direction === "vertical";
+ return {
+ width: direction ? "auto" : false,
+ classes: {
+ middle: {
+ "ui-selectmenu-button-open": "",
+ "ui-selectmenu-button-closed": ""
+ },
+ first: {
+ "ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ),
+ "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" )
+ },
+ last: {
+ "ui-selectmenu-button-open": direction ? "" : "ui-corner-tr",
+ "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" )
+ },
+ only: {
+ "ui-selectmenu-button-open": "ui-corner-top",
+ "ui-selectmenu-button-closed": "ui-corner-all"
+ }
+
+ }[ position ]
+ };
+ },
+
+ _resolveClassesValues: function( classes, instance ) {
+ var result = {};
+ $.each( classes, function( key ) {
+ var current = instance.options.classes[ key ] || "";
+ current = $.trim( current.replace( controlgroupCornerRegex, "" ) );
+ result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " );
+ } );
+ return result;
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "direction" ) {
+ this._removeClass( "ui-controlgroup-" + this.options.direction );
+ }
+
+ this._super( key, value );
+ if ( key === "disabled" ) {
+ this._callChildMethod( value ? "disable" : "enable" );
+ return;
+ }
+
+ this.refresh();
+ },
+
+ refresh: function() {
+ var children,
+ that = this;
+
+ this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction );
+
+ if ( this.options.direction === "horizontal" ) {
+ this._addClass( null, "ui-helper-clearfix" );
+ }
+ this._initWidgets();
+
+ children = this.childWidgets;
+
+ // We filter here because we need to track all childWidgets not just the visible ones
+ if ( this.options.onlyVisible ) {
+ children = children.filter( ":visible" );
+ }
+
+ if ( children.length ) {
+
+ // We do this last because we need to make sure all enhancment is done
+ // before determining first and last
+ $.each( [ "first", "last" ], function( index, value ) {
+ var instance = children[ value ]().data( "ui-controlgroup-data" );
+
+ if ( instance && that[ "_" + instance.widgetName + "Options" ] ) {
+ var options = that[ "_" + instance.widgetName + "Options" ](
+ children.length === 1 ? "only" : value
+ );
+ options.classes = that._resolveClassesValues( options.classes, instance );
+ instance.element[ instance.widgetName ]( options );
+ } else {
+ that._updateCornerClass( children[ value ](), value );
+ }
+ } );
+
+ // Finally call the refresh method on each of the child widgets.
+ this._callChildMethod( "refresh" );
+ }
+ }
+} );
+
+/*!
+ * jQuery UI Checkboxradio 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: Checkboxradio
+//>>group: Widgets
+//>>description: Enhances a form with multiple themeable checkboxes or radio buttons.
+//>>docs: http://api.jqueryui.com/checkboxradio/
+//>>demos: http://jqueryui.com/checkboxradio/
+//>>css.structure: ../../themes/base/core.css
+//>>css.structure: ../../themes/base/button.css
+//>>css.structure: ../../themes/base/checkboxradio.css
+//>>css.theme: ../../themes/base/theme.css
+
+
+
+$.widget( "ui.checkboxradio", [ $.ui.formResetMixin, {
+ version: "1.12.1",
+ options: {
+ disabled: null,
+ label: null,
+ icon: true,
+ classes: {
+ "ui-checkboxradio-label": "ui-corner-all",
+ "ui-checkboxradio-icon": "ui-corner-all"
+ }
+ },
+
+ _getCreateOptions: function() {
+ var disabled, labels;
+ var that = this;
+ var options = this._super() || {};
+
+ // We read the type here, because it makes more sense to throw a element type error first,
+ // rather then the error for lack of a label. Often if its the wrong type, it
+ // won't have a label (e.g. calling on a div, btn, etc)
+ this._readType();
+
+ labels = this.element.labels();
+
+ // If there are multiple labels, use the last one
+ this.label = $( labels[ labels.length - 1 ] );
+ if ( !this.label.length ) {
+ $.error( "No label found for checkboxradio widget" );
+ }
+
+ this.originalLabel = "";
+
+ // We need to get the label text but this may also need to make sure it does not contain the
+ // input itself.
+ this.label.contents().not( this.element[ 0 ] ).each( function() {
+
+ // The label contents could be text, html, or a mix. We concat each element to get a
+ // string representation of the label, without the input as part of it.
+ that.originalLabel += this.nodeType === 3 ? $( this ).text() : this.outerHTML;
+ } );
+
+ // Set the label option if we found label text
+ if ( this.originalLabel ) {
+ options.label = this.originalLabel;
+ }
+
+ disabled = this.element[ 0 ].disabled;
+ if ( disabled != null ) {
+ options.disabled = disabled;
+ }
+ return options;
+ },
+
+ _create: function() {
+ var checked = this.element[ 0 ].checked;
+
+ this._bindFormResetHandler();
+
+ if ( this.options.disabled == null ) {
+ this.options.disabled = this.element[ 0 ].disabled;
+ }
+
+ this._setOption( "disabled", this.options.disabled );
+ this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" );
+ this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" );
+
+ if ( this.type === "radio" ) {
+ this._addClass( this.label, "ui-checkboxradio-radio-label" );
+ }
+
+ if ( this.options.label && this.options.label !== this.originalLabel ) {
+ this._updateLabel();
+ } else if ( this.originalLabel ) {
+ this.options.label = this.originalLabel;
+ }
+
+ this._enhance();
+
+ if ( checked ) {
+ this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" );
+ if ( this.icon ) {
+ this._addClass( this.icon, null, "ui-state-hover" );
+ }
+ }
+
+ this._on( {
+ change: "_toggleClasses",
+ focus: function() {
+ this._addClass( this.label, null, "ui-state-focus ui-visual-focus" );
+ },
+ blur: function() {
+ this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" );
+ }
+ } );
+ },
+
+ _readType: function() {
+ var nodeName = this.element[ 0 ].nodeName.toLowerCase();
+ this.type = this.element[ 0 ].type;
+ if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) {
+ $.error( "Can't create checkboxradio on element.nodeName=" + nodeName +
+ " and element.type=" + this.type );
+ }
+ },
+
+ // Support jQuery Mobile enhanced option
+ _enhance: function() {
+ this._updateIcon( this.element[ 0 ].checked );
+ },
+
+ widget: function() {
+ return this.label;
+ },
+
+ _getRadioGroup: function() {
+ var group;
+ var name = this.element[ 0 ].name;
+ var nameSelector = "input[name='" + $.ui.escapeSelector( name ) + "']";
+
+ if ( !name ) {
+ return $( [] );
+ }
+
+ if ( this.form.length ) {
+ group = $( this.form[ 0 ].elements ).filter( nameSelector );
+ } else {
+
+ // Not inside a form, check all inputs that also are not inside a form
+ group = $( nameSelector ).filter( function() {
+ return $( this ).form().length === 0;
+ } );
+ }
+
+ return group.not( this.element );
+ },
+
+ _toggleClasses: function() {
+ var checked = this.element[ 0 ].checked;
+ this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
+
+ if ( this.options.icon && this.type === "checkbox" ) {
+ this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked )
+ ._toggleClass( this.icon, null, "ui-icon-blank", !checked );
+ }
+
+ if ( this.type === "radio" ) {
+ this._getRadioGroup()
+ .each( function() {
+ var instance = $( this ).checkboxradio( "instance" );
+
+ if ( instance ) {
+ instance._removeClass( instance.label,
+ "ui-checkboxradio-checked", "ui-state-active" );
+ }
+ } );
+ }
+ },
+
+ _destroy: function() {
+ this._unbindFormResetHandler();
+
+ if ( this.icon ) {
+ this.icon.remove();
+ this.iconSpace.remove();
+ }
+ },
+
+ _setOption: function( key, value ) {
+
+ // We don't allow the value to be set to nothing
+ if ( key === "label" && !value ) {
+ return;
+ }
+
+ this._super( key, value );
+
+ if ( key === "disabled" ) {
+ this._toggleClass( this.label, null, "ui-state-disabled", value );
+ this.element[ 0 ].disabled = value;
+
+ // Don't refresh when setting disabled
+ return;
+ }
+ this.refresh();
+ },
+
+ _updateIcon: function( checked ) {
+ var toAdd = "ui-icon ui-icon-background ";
+
+ if ( this.options.icon ) {
+ if ( !this.icon ) {
+ this.icon = $( "<span>" );
+ this.iconSpace = $( "<span> </span>" );
+ this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" );
+ }
+
+ if ( this.type === "checkbox" ) {
+ toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank";
+ this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" );
+ } else {
+ toAdd += "ui-icon-blank";
+ }
+ this._addClass( this.icon, "ui-checkboxradio-icon", toAdd );
+ if ( !checked ) {
+ this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" );
+ }
+ this.icon.prependTo( this.label ).after( this.iconSpace );
+ } else if ( this.icon !== undefined ) {
+ this.icon.remove();
+ this.iconSpace.remove();
+ delete this.icon;
+ }
+ },
+
+ _updateLabel: function() {
+
+ // Remove the contents of the label ( minus the icon, icon space, and input )
+ var contents = this.label.contents().not( this.element[ 0 ] );
+ if ( this.icon ) {
+ contents = contents.not( this.icon[ 0 ] );
+ }
+ if ( this.iconSpace ) {
+ contents = contents.not( this.iconSpace[ 0 ] );
+ }
+ contents.remove();
+
+ this.label.append( this.options.label );
+ },
+
+ refresh: function() {
+ var checked = this.element[ 0 ].checked,
+ isDisabled = this.element[ 0 ].disabled;
+
+ this._updateIcon( checked );
+ this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
+ if ( this.options.label !== null ) {
+ this._updateLabel();
+ }
+
+ if ( isDisabled !== this.options.disabled ) {
+ this._setOptions( { "disabled": isDisabled } );
+ }
+ }
+
+} ] );
+
+var widgetsCheckboxradio = $.ui.checkboxradio;
+
+
+/*!
+ * jQuery UI Button 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: Button
+//>>group: Widgets
+//>>description: Enhances a form with themeable buttons.
+//>>docs: http://api.jqueryui.com/button/
+//>>demos: http://jqueryui.com/button/
+//>>css.structure: ../../themes/base/core.css
+//>>css.structure: ../../themes/base/button.css
+//>>css.theme: ../../themes/base/theme.css
+
+
+
+$.widget( "ui.button", {
+ version: "1.12.1",
+ defaultElement: "<button>",
+ options: {
+ classes: {
+ "ui-button": "ui-corner-all"
+ },
+ disabled: null,
+ icon: null,
+ iconPosition: "beginning",
+ label: null,
+ showLabel: true
+ },
+
+ _getCreateOptions: function() {
+ var disabled,
+
+ // This is to support cases like in jQuery Mobile where the base widget does have
+ // an implementation of _getCreateOptions
+ options = this._super() || {};
+
+ this.isInput = this.element.is( "input" );
+
+ disabled = this.element[ 0 ].disabled;
+ if ( disabled != null ) {
+ options.disabled = disabled;
+ }
+
+ this.originalLabel = this.isInput ? this.element.val() : this.element.html();
+ if ( this.originalLabel ) {
+ options.label = this.originalLabel;
+ }
+
+ return options;
+ },
+
+ _create: function() {
+ if ( !this.option.showLabel & !this.options.icon ) {
+ this.options.showLabel = true;
+ }
+
+ // We have to check the option again here even though we did in _getCreateOptions,
+ // because null may have been passed on init which would override what was set in
+ // _getCreateOptions
+ if ( this.options.disabled == null ) {
+ this.options.disabled = this.element[ 0 ].disabled || false;
+ }
+
+ this.hasTitle = !!this.element.attr( "title" );
+
+ // Check to see if the label needs to be set or if its already correct
+ if ( this.options.label && this.options.label !== this.originalLabel ) {
+ if ( this.isInput ) {
+ this.element.val( this.options.label );
+ } else {
+ this.element.html( this.options.label );
+ }
+ }
+ this._addClass( "ui-button", "ui-widget" );
+ this._setOption( "disabled", this.options.disabled );
+ this._enhance();
+
+ if ( this.element.is( "a" ) ) {
+ this._on( {
+ "keyup": function( event ) {
+ if ( event.keyCode === $.ui.keyCode.SPACE ) {
+ event.preventDefault();
+
+ // Support: PhantomJS <= 1.9, IE 8 Only
+ // If a native click is available use it so we actually cause navigation
+ // otherwise just trigger a click event
+ if ( this.element[ 0 ].click ) {
+ this.element[ 0 ].click();
+ } else {
+ this.element.trigger( "click" );
+ }
+ }
+ }
+ } );
+ }
+ },
+
+ _enhance: function() {
+ if ( !this.element.is( "button" ) ) {
+ this.element.attr( "role", "button" );
+ }
+
+ if ( this.options.icon ) {
+ this._updateIcon( "icon", this.options.icon );
+ this._updateTooltip();
+ }
+ },
+
+ _updateTooltip: function() {
+ this.title = this.element.attr( "title" );
+
+ if ( !this.options.showLabel && !this.title ) {
+ this.element.attr( "title", this.options.label );
+ }
+ },
+
+ _updateIcon: function( option, value ) {
+ var icon = option !== "iconPosition",
+ position = icon ? this.options.iconPosition : value,
+ displayBlock = position === "top" || position === "bottom";
+
+ // Create icon
+ if ( !this.icon ) {
+ this.icon = $( "<span>" );
+
+ this._addClass( this.icon, "ui-button-icon", "ui-icon" );
+
+ if ( !this.options.showLabel ) {
+ this._addClass( "ui-button-icon-only" );
+ }
+ } else if ( icon ) {
+
+ // If we are updating the icon remove the old icon class
+ this._removeClass( this.icon, null, this.options.icon );
+ }
+
+ // If we are updating the icon add the new icon class
+ if ( icon ) {
+ this._addClass( this.icon, null, value );
+ }
+
+ this._attachIcon( position );
+
+ // If the icon is on top or bottom we need to add the ui-widget-icon-block class and remove
+ // the iconSpace if there is one.
+ if ( displayBlock ) {
+ this._addClass( this.icon, null, "ui-widget-icon-block" );
+ if ( this.iconSpace ) {
+ this.iconSpace.remove();
+ }
+ } else {
+
+ // Position is beginning or end so remove the ui-widget-icon-block class and add the
+ // space if it does not exist
+ if ( !this.iconSpace ) {
+ this.iconSpace = $( "<span> </span>" );
+ this._addClass( this.iconSpace, "ui-button-icon-space" );
+ }
+ this._removeClass( this.icon, null, "ui-wiget-icon-block" );
+ this._attachIconSpace( position );
+ }
+ },
+
+ _destroy: function() {
+ this.element.removeAttr( "role" );
+
+ if ( this.icon ) {
+ this.icon.remove();
+ }
+ if ( this.iconSpace ) {
+ this.iconSpace.remove();
+ }
+ if ( !this.hasTitle ) {
+ this.element.removeAttr( "title" );
+ }
+ },
+
+ _attachIconSpace: function( iconPosition ) {
+ this.icon[ /^(?:end|bottom)/.test( iconPosition ) ? "before" : "after" ]( this.iconSpace );
+ },
+
+ _attachIcon: function( iconPosition ) {
+ this.element[ /^(?:end|bottom)/.test( iconPosition ) ? "append" : "prepend" ]( this.icon );
+ },
+
+ _setOptions: function( options ) {
+ var newShowLabel = options.showLabel === undefined ?
+ this.options.showLabel :
+ options.showLabel,
+ newIcon = options.icon === undefined ? this.options.icon : options.icon;
+
+ if ( !newShowLabel && !newIcon ) {
+ options.showLabel = true;
+ }
+ this._super( options );
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "icon" ) {
+ if ( value ) {
+ this._updateIcon( key, value );
+ } else if ( this.icon ) {
+ this.icon.remove();
+ if ( this.iconSpace ) {
+ this.iconSpace.remove();
+ }
+ }
+ }
+
+ if ( key === "iconPosition" ) {
+ this._updateIcon( key, value );
+ }
+
+ // Make sure we can't end up with a button that has neither text nor icon
+ if ( key === "showLabel" ) {
+ this._toggleClass( "ui-button-icon-only", null, !value );
+ this._updateTooltip();
+ }
+
+ if ( key === "label" ) {
+ if ( this.isInput ) {
+ this.element.val( value );
+ } else {
+
+ // If there is an icon, append it, else nothing then append the value
+ // this avoids removal of the icon when setting label text
+ this.element.html( value );
+ if ( this.icon ) {
+ this._attachIcon( this.options.iconPosition );
+ this._attachIconSpace( this.options.iconPosition );
+ }
+ }
+ }
+
+ this._super( key, value );
+
+ if ( key === "disabled" ) {
+ this._toggleClass( null, "ui-state-disabled", value );
+ this.element[ 0 ].disabled = value;
+ if ( value ) {
+ this.element.blur();
+ }
+ }
+ },
+
+ refresh: function() {
+
+ // Make sure to only check disabled if its an element that supports this otherwise
+ // check for the disabled class to determine state
+ var isDisabled = this.element.is( "input, button" ) ?
+ this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" );
+
+ if ( isDisabled !== this.options.disabled ) {
+ this._setOptions( { disabled: isDisabled } );
+ }
+
+ this._updateTooltip();
+ }
+} );
+
+// DEPRECATED
+if ( $.uiBackCompat !== false ) {
+
+ // Text and Icons options
+ $.widget( "ui.button", $.ui.button, {
+ options: {
+ text: true,
+ icons: {
+ primary: null,
+ secondary: null
+ }
+ },
+
+ _create: function() {
+ if ( this.options.showLabel && !this.options.text ) {
+ this.options.showLabel = this.options.text;
+ }
+ if ( !this.options.showLabel && this.options.text ) {
+ this.options.text = this.options.showLabel;
+ }
+ if ( !this.options.icon && ( this.options.icons.primary ||
+ this.options.icons.secondary ) ) {
+ if ( this.options.icons.primary ) {
+ this.options.icon = this.options.icons.primary;
+ } else {
+ this.options.icon = this.options.icons.secondary;
+ this.options.iconPosition = "end";
+ }
+ } else if ( this.options.icon ) {
+ this.options.icons.primary = this.options.icon;
+ }
+ this._super();
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "text" ) {
+ this._super( "showLabel", value );
+ return;
+ }
+ if ( key === "showLabel" ) {
+ this.options.text = value;
+ }
+ if ( key === "icon" ) {
+ this.options.icons.primary = value;
+ }
+ if ( key === "icons" ) {
+ if ( value.primary ) {
+ this._super( "icon", value.primary );
+ this._super( "iconPosition", "beginning" );
+ } else if ( value.secondary ) {
+ this._super( "icon", value.secondary );
+ this._super( "iconPosition", "end" );
+ }
+ }
+ this._superApply( arguments );
+ }
+ } );
+
+ $.fn.button = ( function( orig ) {
+ return function() {
+ if ( !this.length || ( this.length && this[ 0 ].tagName !== "INPUT" ) ||
+ ( this.length && this[ 0 ].tagName === "INPUT" && (
+ this.attr( "type" ) !== "checkbox" && this.attr( "type" ) !== "radio"
+ ) ) ) {
+ return orig.apply( this, arguments );
+ }
+ if ( !$.ui.checkboxradio ) {
+ $.error( "Checkboxradio widget missing" );
+ }
+ if ( arguments.length === 0 ) {
+ return this.checkboxradio( {
+ "icon": false
+ } );
+ }
+ return this.checkboxradio.apply( this, arguments );
+ };
+ } )( $.fn.button );
+
+ $.fn.buttonset = function() {
+ if ( !$.ui.controlgroup ) {
+ $.error( "Controlgroup widget missing" );
+ }
+ if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) {
+ return this.controlgroup.apply( this,
+ [ arguments[ 0 ], "items.button", arguments[ 2 ] ] );
+ }
+ if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) {
+ return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] );
+ }
+ if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) {
+ arguments[ 0 ].items = {
+ button: arguments[ 0 ].items
+ };
+ }
+ return this.controlgroup.apply( this, arguments );
+ };
+}
+
+var widgetsButton = $.ui.button;
+
+
+
+var safeActiveElement = $.ui.safeActiveElement = function( document ) {
+ var activeElement;
+
+ // Support: IE 9 only
+ // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
+ try {
+ activeElement = document.activeElement;
+ } catch ( error ) {
+ activeElement = document.body;
+ }
+
+ // Support: IE 9 - 11 only
+ // IE may return null instead of an element
+ // Interestingly, this only seems to occur when NOT in an iframe
+ if ( !activeElement ) {
+ activeElement = document.body;
+ }
+
+ // Support: IE 11 only
+ // IE11 returns a seemingly empty object in some cases when accessing
+ // document.activeElement from an <iframe>
+ if ( !activeElement.nodeName ) {
+ activeElement = document.body;
+ }
+
+ return activeElement;
+};
+
+
+/*!
+ * jQuery UI Tabs 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ */
+
+//>>label: Tabs
+//>>group: Widgets
+//>>description: Transforms a set of container elements into a tab structure.
+//>>docs: http://api.jqueryui.com/tabs/
+//>>demos: http://jqueryui.com/tabs/
+//>>css.structure: ../../themes/base/core.css
+//>>css.structure: ../../themes/base/tabs.css
+//>>css.theme: ../../themes/base/theme.css
+
+
+
+$.widget( "ui.tabs", {
+ version: "1.12.1",
+ delay: 300,
+ options: {
+ active: null,
+ classes: {
+ "ui-tabs": "ui-corner-all",
+ "ui-tabs-nav": "ui-corner-all",
+ "ui-tabs-panel": "ui-corner-bottom",
+ "ui-tabs-tab": "ui-corner-top"
+ },
+ collapsible: false,
+ event: "click",
+ heightStyle: "content",
+ hide: null,
+ show: null,
+
+ // Callbacks
+ activate: null,
+ beforeActivate: null,
+ beforeLoad: null,
+ load: null
+ },
+
+ _isLocal: ( function() {
+ var rhash = /#.*$/;
+
+ return function( anchor ) {
+ var anchorUrl, locationUrl;
+
+ anchorUrl = anchor.href.replace( rhash, "" );
+ locationUrl = location.href.replace( rhash, "" );
+
+ // Decoding may throw an error if the URL isn't UTF-8 (#9518)
+ try {
+ anchorUrl = decodeURIComponent( anchorUrl );
+ } catch ( error ) {}
+ try {
+ locationUrl = decodeURIComponent( locationUrl );
+ } catch ( error ) {}
+
+ return anchor.hash.length > 1 && anchorUrl === locationUrl;
+ };
+ } )(),
+
+ _create: function() {
+ var that = this,
+ options = this.options;
+
+ this.running = false;
+
+ this._addClass( "ui-tabs", "ui-widget ui-widget-content" );
+ this._toggleClass( "ui-tabs-collapsible", null, options.collapsible );
+
+ this._processTabs();
+ options.active = this._initialActive();
+
+ // Take disabling tabs via class attribute from HTML
+ // into account and update option properly.
+ if ( $.isArray( options.disabled ) ) {
+ options.disabled = $.unique( options.disabled.concat(
+ $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
+ return that.tabs.index( li );
+ } )
+ ) ).sort();
+ }
+
+ // Check for length avoids error when initializing empty list
+ if ( this.options.active !== false && this.anchors.length ) {
+ this.active = this._findActive( options.active );
+ } else {
+ this.active = $();
+ }
+
+ this._refresh();
+
+ if ( this.active.length ) {
+ this.load( options.active );
+ }
+ },
+
+ _initialActive: function() {
+ var active = this.options.active,
+ collapsible = this.options.collapsible,
+ locationHash = location.hash.substring( 1 );
+
+ if ( active === null ) {
+
+ // check the fragment identifier in the URL
+ if ( locationHash ) {
+ this.tabs.each( function( i, tab ) {
+ if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
+ active = i;
+ return false;
+ }
+ } );
+ }
+
+ // Check for a tab marked active via a class
+ if ( active === null ) {
+ active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
+ }
+
+ // No active tab, set to false
+ if ( active === null || active === -1 ) {
+ active = this.tabs.length ? 0 : false;
+ }
+ }
+
+ // Handle numbers: negative, out of range
+ if ( active !== false ) {
+ active = this.tabs.index( this.tabs.eq( active ) );
+ if ( active === -1 ) {
+ active = collapsible ? false : 0;
+ }
+ }
+
+ // Don't allow collapsible: false and active: false
+ if ( !collapsible && active === false && this.anchors.length ) {
+ active = 0;
+ }
+
+ return active;
+ },
+
+ _getCreateEventData: function() {
+ return {
+ tab: this.active,
+ panel: !this.active.length ? $() : this._getPanelForTab( this.active )
+ };
+ },
+
+ _tabKeydown: function( event ) {
+ var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ),
+ selectedIndex = this.tabs.index( focusedTab ),
+ goingForward = true;
+
+ if ( this._handlePageNav( event ) ) {
+ return;
+ }
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.RIGHT:
+ case $.ui.keyCode.DOWN:
+ selectedIndex++;
+ break;
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.LEFT:
+ goingForward = false;
+ selectedIndex--;
+ break;
+ case $.ui.keyCode.END:
+ selectedIndex = this.anchors.length - 1;
+ break;
+ case $.ui.keyCode.HOME:
+ selectedIndex = 0;
+ break;
+ case $.ui.keyCode.SPACE:
+
+ // Activate only, no collapsing
+ event.preventDefault();
+ clearTimeout( this.activating );
+ this._activate( selectedIndex );
+ return;
+ case $.ui.keyCode.ENTER:
+
+ // Toggle (cancel delayed activation, allow collapsing)
+ event.preventDefault();
+ clearTimeout( this.activating );
+
+ // Determine if we should collapse or activate
+ this._activate( selectedIndex === this.options.active ? false : selectedIndex );
+ return;
+ default:
+ return;
+ }
+
+ // Focus the appropriate tab, based on which key was pressed
+ event.preventDefault();
+ clearTimeout( this.activating );
+ selectedIndex = this._focusNextTab( selectedIndex, goingForward );
+
+ // Navigating with control/command key will prevent automatic activation
+ if ( !event.ctrlKey && !event.metaKey ) {
+
+ // Update aria-selected immediately so that AT think the tab is already selected.
+ // Otherwise AT may confuse the user by stating that they need to activate the tab,
+ // but the tab will already be activated by the time the announcement finishes.
+ focusedTab.attr( "aria-selected", "false" );
+ this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
+
+ this.activating = this._delay( function() {
+ this.option( "active", selectedIndex );
+ }, this.delay );
+ }
+ },
+
+ _panelKeydown: function( event ) {
+ if ( this._handlePageNav( event ) ) {
+ return;
+ }
+
+ // Ctrl+up moves focus to the current tab
+ if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
+ event.preventDefault();
+ this.active.trigger( "focus" );
+ }
+ },
+
+ // Alt+page up/down moves focus to the previous/next tab (and activates)
+ _handlePageNav: function( event ) {
+ if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
+ this._activate( this._focusNextTab( this.options.active - 1, false ) );
+ return true;
+ }
+ if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
+ this._activate( this._focusNextTab( this.options.active + 1, true ) );
+ return true;
+ }
+ },
+
+ _findNextTab: function( index, goingForward ) {
+ var lastTabIndex = this.tabs.length - 1;
+
+ function constrain() {
+ if ( index > lastTabIndex ) {
+ index = 0;
+ }
+ if ( index < 0 ) {
+ index = lastTabIndex;
+ }
+ return index;
+ }
+
+ while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
+ index = goingForward ? index + 1 : index - 1;
+ }
+
+ return index;
+ },
+
+ _focusNextTab: function( index, goingForward ) {
+ index = this._findNextTab( index, goingForward );
+ this.tabs.eq( index ).trigger( "focus" );
+ return index;
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "active" ) {
+
+ // _activate() will handle invalid values and update this.options
+ this._activate( value );
+ return;
+ }
+
+ this._super( key, value );
+
+ if ( key === "collapsible" ) {
+ this._toggleClass( "ui-tabs-collapsible", null, value );
+
+ // Setting collapsible: false while collapsed; open first panel
+ if ( !value && this.options.active === false ) {
+ this._activate( 0 );
+ }
+ }
+
+ if ( key === "event" ) {
+ this._setupEvents( value );
+ }
+
+ if ( key === "heightStyle" ) {
+ this._setupHeightStyle( value );
+ }
+ },
+
+ _sanitizeSelector: function( hash ) {
+ return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
+ },
+
+ refresh: function() {
+ var options = this.options,
+ lis = this.tablist.children( ":has(a[href])" );
+
+ // Get disabled tabs from class attribute from HTML
+ // this will get converted to a boolean if needed in _refresh()
+ options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
+ return lis.index( tab );
+ } );
+
+ this._processTabs();
+
+ // Was collapsed or no tabs
+ if ( options.active === false || !this.anchors.length ) {
+ options.active = false;
+ this.active = $();
+
+ // was active, but active tab is gone
+ } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
+
+ // all remaining tabs are disabled
+ if ( this.tabs.length === options.disabled.length ) {
+ options.active = false;
+ this.active = $();
+
+ // activate previous tab
+ } else {
+ this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
+ }
+
+ // was active, active tab still exists
+ } else {
+
+ // make sure active index is correct
+ options.active = this.tabs.index( this.active );
+ }
+
+ this._refresh();
+ },
+
+ _refresh: function() {
+ this._setOptionDisabled( this.options.disabled );
+ this._setupEvents( this.options.event );
+ this._setupHeightStyle( this.options.heightStyle );
+
+ this.tabs.not( this.active ).attr( {
+ "aria-selected": "false",
+ "aria-expanded": "false",
+ tabIndex: -1
+ } );
+ this.panels.not( this._getPanelForTab( this.active ) )
+ .hide()
+ .attr( {
+ "aria-hidden": "true"
+ } );
+
+ // Make sure one tab is in the tab order
+ if ( !this.active.length ) {
+ this.tabs.eq( 0 ).attr( "tabIndex", 0 );
+ } else {
+ this.active
+ .attr( {
+ "aria-selected": "true",
+ "aria-expanded": "true",
+ tabIndex: 0
+ } );
+ this._addClass( this.active, "ui-tabs-active", "ui-state-active" );
+ this._getPanelForTab( this.active )
+ .show()
+ .attr( {
+ "aria-hidden": "false"
+ } );
+ }
+ },
+
+ _processTabs: function() {
+ var that = this,
+ prevTabs = this.tabs,
+ prevAnchors = this.anchors,
+ prevPanels = this.panels;
+
+ this.tablist = this._getList().attr( "role", "tablist" );
+ this._addClass( this.tablist, "ui-tabs-nav",
+ "ui-helper-reset ui-helper-clearfix ui-widget-header" );
+
+ // Prevent users from focusing disabled tabs via click
+ this.tablist
+ .on( "mousedown" + this.eventNamespace, "> li", function( event ) {
+ if ( $( this ).is( ".ui-state-disabled" ) ) {
+ event.preventDefault();
+ }
+ } )
+
+ // Support: IE <9
+ // Preventing the default action in mousedown doesn't prevent IE
+ // from focusing the element, so if the anchor gets focused, blur.
+ // We don't have to worry about focusing the previously focused
+ // element since clicking on a non-focusable element should focus
+ // the body anyway.
+ .on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() {
+ if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
+ this.blur();
+ }
+ } );
+
+ this.tabs = this.tablist.find( "> li:has(a[href])" )
+ .attr( {
+ role: "tab",
+ tabIndex: -1
+ } );
+ this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" );
+
+ this.anchors = this.tabs.map( function() {
+ return $( "a", this )[ 0 ];
+ } )
+ .attr( {
+ role: "presentation",
+ tabIndex: -1
+ } );
+ this._addClass( this.anchors, "ui-tabs-anchor" );
+
+ this.panels = $();
+
+ this.anchors.each( function( i, anchor ) {
+ var selector, panel, panelId,
+ anchorId = $( anchor ).uniqueId().attr( "id" ),
+ tab = $( anchor ).closest( "li" ),
+ originalAriaControls = tab.attr( "aria-controls" );
+
+ // Inline tab
+ if ( that._isLocal( anchor ) ) {
+ selector = anchor.hash;
+ panelId = selector.substring( 1 );
+ panel = that.element.find( that._sanitizeSelector( selector ) );
+
+ // remote tab
+ } else {
+
+ // If the tab doesn't already have aria-controls,
+ // generate an id by using a throw-away element
+ panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
+ selector = "#" + panelId;
+ panel = that.element.find( selector );
+ if ( !panel.length ) {
+ panel = that._createPanel( panelId );
+ panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
+ }
+ panel.attr( "aria-live", "polite" );
+ }
+
+ if ( panel.length ) {
+ that.panels = that.panels.add( panel );
+ }
+ if ( originalAriaControls ) {
+ tab.data( "ui-tabs-aria-controls", originalAriaControls );
+ }
+ tab.attr( {
+ "aria-controls": panelId,
+ "aria-labelledby": anchorId
+ } );
+ panel.attr( "aria-labelledby", anchorId );
+ } );
+
+ this.panels.attr( "role", "tabpanel" );
+ this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" );
+
+ // Avoid memory leaks (#10056)
+ if ( prevTabs ) {
+ this._off( prevTabs.not( this.tabs ) );
+ this._off( prevAnchors.not( this.anchors ) );
+ this._off( prevPanels.not( this.panels ) );
+ }
+ },
+
+ // Allow overriding how to find the list for rare usage scenarios (#7715)
+ _getList: function() {
+ return this.tablist || this.element.find( "ol, ul" ).eq( 0 );
+ },
+
+ _createPanel: function( id ) {
+ return $( "<div>" )
+ .attr( "id", id )
+ .data( "ui-tabs-destroy", true );
+ },
+
+ _setOptionDisabled: function( disabled ) {
+ var currentItem, li, i;
+
+ if ( $.isArray( disabled ) ) {
+ if ( !disabled.length ) {
+ disabled = false;
+ } else if ( disabled.length === this.anchors.length ) {
+ disabled = true;
+ }
+ }
+
+ // Disable tabs
+ for ( i = 0; ( li = this.tabs[ i ] ); i++ ) {
+ currentItem = $( li );
+ if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
+ currentItem.attr( "aria-disabled", "true" );
+ this._addClass( currentItem, null, "ui-state-disabled" );
+ } else {
+ currentItem.removeAttr( "aria-disabled" );
+ this._removeClass( currentItem, null, "ui-state-disabled" );
+ }
+ }
+
+ this.options.disabled = disabled;
+
+ this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null,
+ disabled === true );
+ },
+
+ _setupEvents: function( event ) {
+ var events = {};
+ if ( event ) {
+ $.each( event.split( " " ), function( index, eventName ) {
+ events[ eventName ] = "_eventHandler";
+ } );
+ }
+
+ this._off( this.anchors.add( this.tabs ).add( this.panels ) );
+
+ // Always prevent the default action, even when disabled
+ this._on( true, this.anchors, {
+ click: function( event ) {
+ event.preventDefault();
+ }
+ } );
+ this._on( this.anchors, events );
+ this._on( this.tabs, { keydown: "_tabKeydown" } );
+ this._on( this.panels, { keydown: "_panelKeydown" } );
+
+ this._focusable( this.tabs );
+ this._hoverable( this.tabs );
+ },
+
+ _setupHeightStyle: function( heightStyle ) {
+ var maxHeight,
+ parent = this.element.parent();
+
+ if ( heightStyle === "fill" ) {
+ maxHeight = parent.height();
+ maxHeight -= this.element.outerHeight() - this.element.height();
+
+ this.element.siblings( ":visible" ).each( function() {
+ var elem = $( this ),
+ position = elem.css( "position" );
+
+ if ( position === "absolute" || position === "fixed" ) {
+ return;
+ }
+ maxHeight -= elem.outerHeight( true );
+ } );
+
+ this.element.children().not( this.panels ).each( function() {
+ maxHeight -= $( this ).outerHeight( true );
+ } );
+
+ this.panels.each( function() {
+ $( this ).height( Math.max( 0, maxHeight -
+ $( this ).innerHeight() + $( this ).height() ) );
+ } )
+ .css( "overflow", "auto" );
+ } else if ( heightStyle === "auto" ) {
+ maxHeight = 0;
+ this.panels.each( function() {
+ maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
+ } ).height( maxHeight );
+ }
+ },
+
+ _eventHandler: function( event ) {
+ var options = this.options,
+ active = this.active,
+ anchor = $( event.currentTarget ),
+ tab = anchor.closest( "li" ),
+ clickedIsActive = tab[ 0 ] === active[ 0 ],
+ collapsing = clickedIsActive && options.collapsible,
+ toShow = collapsing ? $() : this._getPanelForTab( tab ),
+ toHide = !active.length ? $() : this._getPanelForTab( active ),
+ eventData = {
+ oldTab: active,
+ oldPanel: toHide,
+ newTab: collapsing ? $() : tab,
+ newPanel: toShow
+ };
+
+ event.preventDefault();
+
+ if ( tab.hasClass( "ui-state-disabled" ) ||
+
+ // tab is already loading
+ tab.hasClass( "ui-tabs-loading" ) ||
+
+ // can't switch durning an animation
+ this.running ||
+
+ // click on active header, but not collapsible
+ ( clickedIsActive && !options.collapsible ) ||
+
+ // allow canceling activation
+ ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
+ return;
+ }
+
+ options.active = collapsing ? false : this.tabs.index( tab );
+
+ this.active = clickedIsActive ? $() : tab;
+ if ( this.xhr ) {
+ this.xhr.abort();
+ }
+
+ if ( !toHide.length && !toShow.length ) {
+ $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
+ }
+
+ if ( toShow.length ) {
+ this.load( this.tabs.index( tab ), event );
+ }
+ this._toggle( event, eventData );
+ },
+
+ // Handles show/hide for selecting tabs
+ _toggle: function( event, eventData ) {
+ var that = this,
+ toShow = eventData.newPanel,
+ toHide = eventData.oldPanel;
+
+ this.running = true;
+
+ function complete() {
+ that.running = false;
+ that._trigger( "activate", event, eventData );
+ }
+
+ function show() {
+ that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" );
+
+ if ( toShow.length && that.options.show ) {
+ that._show( toShow, that.options.show, complete );
+ } else {
+ toShow.show();
+ complete();
+ }
+ }
+
+ // Start out by hiding, then showing, then completing
+ if ( toHide.length && this.options.hide ) {
+ this._hide( toHide, this.options.hide, function() {
+ that._removeClass( eventData.oldTab.closest( "li" ),
+ "ui-tabs-active", "ui-state-active" );
+ show();
+ } );
+ } else {
+ this._removeClass( eventData.oldTab.closest( "li" ),
+ "ui-tabs-active", "ui-state-active" );
+ toHide.hide();
+ show();
+ }
+
+ toHide.attr( "aria-hidden", "true" );
+ eventData.oldTab.attr( {
+ "aria-selected": "false",
+ "aria-expanded": "false"
+ } );
+
+ // If we're switching tabs, remove the old tab from the tab order.
+ // If we're opening from collapsed state, remove the previous tab from the tab order.
+ // If we're collapsing, then keep the collapsing tab in the tab order.
+ if ( toShow.length && toHide.length ) {
+ eventData.oldTab.attr( "tabIndex", -1 );
+ } else if ( toShow.length ) {
+ this.tabs.filter( function() {
+ return $( this ).attr( "tabIndex" ) === 0;
+ } )
+ .attr( "tabIndex", -1 );
+ }
+
+ toShow.attr( "aria-hidden", "false" );
+ eventData.newTab.attr( {
+ "aria-selected": "true",
+ "aria-expanded": "true",
+ tabIndex: 0
+ } );
+ },
+
+ _activate: function( index ) {
+ var anchor,
+ active = this._findActive( index );
+
+ // Trying to activate the already active panel
+ if ( active[ 0 ] === this.active[ 0 ] ) {
+ return;
+ }
+
+ // Trying to collapse, simulate a click on the current active header
+ if ( !active.length ) {
+ active = this.active;
+ }
+
+ anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
+ this._eventHandler( {
+ target: anchor,
+ currentTarget: anchor,
+ preventDefault: $.noop
+ } );
+ },
+
+ _findActive: function( index ) {
+ return index === false ? $() : this.tabs.eq( index );
+ },
+
+ _getIndex: function( index ) {
+
+ // meta-function to give users option to provide a href string instead of a numerical index.
+ if ( typeof index === "string" ) {
+ index = this.anchors.index( this.anchors.filter( "[href$='" +
+ $.ui.escapeSelector( index ) + "']" ) );
+ }
+
+ return index;
+ },
+
+ _destroy: function() {
+ if ( this.xhr ) {
+ this.xhr.abort();
+ }
+
+ this.tablist
+ .removeAttr( "role" )
+ .off( this.eventNamespace );
+
+ this.anchors
+ .removeAttr( "role tabIndex" )
+ .removeUniqueId();
+
+ this.tabs.add( this.panels ).each( function() {
+ if ( $.data( this, "ui-tabs-destroy" ) ) {
+ $( this ).remove();
+ } else {
+ $( this ).removeAttr( "role tabIndex " +
+ "aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" );
+ }
+ } );
+
+ this.tabs.each( function() {
+ var li = $( this ),
+ prev = li.data( "ui-tabs-aria-controls" );
+ if ( prev ) {
+ li
+ .attr( "aria-controls", prev )
+ .removeData( "ui-tabs-aria-controls" );
+ } else {
+ li.removeAttr( "aria-controls" );
+ }
+ } );
+
+ this.panels.show();
+
+ if ( this.options.heightStyle !== "content" ) {
+ this.panels.css( "height", "" );
+ }
+ },
+
+ enable: function( index ) {
+ var disabled = this.options.disabled;
+ if ( disabled === false ) {
+ return;
+ }
+
+ if ( index === undefined ) {
+ disabled = false;
+ } else {
+ index = this._getIndex( index );
+ if ( $.isArray( disabled ) ) {
+ disabled = $.map( disabled, function( num ) {
+ return num !== index ? num : null;
+ } );
+ } else {
+ disabled = $.map( this.tabs, function( li, num ) {
+ return num !== index ? num : null;
+ } );
+ }
+ }
+ this._setOptionDisabled( disabled );
+ },
+
+ disable: function( index ) {
+ var disabled = this.options.disabled;
+ if ( disabled === true ) {
+ return;
+ }
+
+ if ( index === undefined ) {
+ disabled = true;
+ } else {
+ index = this._getIndex( index );
+ if ( $.inArray( index, disabled ) !== -1 ) {
+ return;
+ }
+ if ( $.isArray( disabled ) ) {
+ disabled = $.merge( [ index ], disabled ).sort();
+ } else {
+ disabled = [ index ];
+ }
+ }
+ this._setOptionDisabled( disabled );
+ },
+
+ load: function( index, event ) {
+ index = this._getIndex( index );
+ var that = this,
+ tab = this.tabs.eq( index ),
+ anchor = tab.find( ".ui-tabs-anchor" ),
+ panel = this._getPanelForTab( tab ),
+ eventData = {
+ tab: tab,
+ panel: panel
+ },
+ complete = function( jqXHR, status ) {
+ if ( status === "abort" ) {
+ that.panels.stop( false, true );
+ }
+
+ that._removeClass( tab, "ui-tabs-loading" );
+ panel.removeAttr( "aria-busy" );
+
+ if ( jqXHR === that.xhr ) {
+ delete that.xhr;
+ }
+ };
+
+ // Not remote
+ if ( this._isLocal( anchor[ 0 ] ) ) {
+ return;
+ }
+
+ this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
+
+ // Support: jQuery <1.8
+ // jQuery <1.8 returns false if the request is canceled in beforeSend,
+ // but as of 1.8, $.ajax() always returns a jqXHR object.
+ if ( this.xhr && this.xhr.statusText !== "canceled" ) {
+ this._addClass( tab, "ui-tabs-loading" );
+ panel.attr( "aria-busy", "true" );
+
+ this.xhr
+ .done( function( response, status, jqXHR ) {
+
+ // support: jQuery <1.8
+ // http://bugs.jquery.com/ticket/11778
+ setTimeout( function() {
+ panel.html( response );
+ that._trigger( "load", event, eventData );
+
+ complete( jqXHR, status );
+ }, 1 );
+ } )
+ .fail( function( jqXHR, status ) {
+
+ // support: jQuery <1.8
+ // http://bugs.jquery.com/ticket/11778
+ setTimeout( function() {
+ complete( jqXHR, status );
+ }, 1 );
+ } );
+ }
+ },
+
+ _ajaxSettings: function( anchor, event, eventData ) {
+ var that = this;
+ return {
+
+ // Support: IE <11 only
+ // Strip any hash that exists to prevent errors with the Ajax request
+ url: anchor.attr( "href" ).replace( /#.*$/, "" ),
+ beforeSend: function( jqXHR, settings ) {
+ return that._trigger( "beforeLoad", event,
+ $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
+ }
+ };
+ },
+
+ _getPanelForTab: function( tab ) {
+ var id = $( tab ).attr( "aria-controls" );
+ return this.element.find( this._sanitizeSelector( "#" + id ) );
+ }
+} );
+
+// DEPRECATED
+// TODO: Switch return back to widget declaration at top of file when this is removed
+if ( $.uiBackCompat !== false ) {
+
+ // Backcompat for ui-tab class (now ui-tabs-tab)
+ $.widget( "ui.tabs", $.ui.tabs, {
+ _processTabs: function() {
+ this._superApply( arguments );
+ this._addClass( this.tabs, "ui-tab" );
+ }
+ } );
+}
+
+var widgetsTabs = $.ui.tabs;
+
+
+
+
+})); \ No newline at end of file
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.structure.css b/src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.structure.css
new file mode 100644
index 0000000..b4e4056
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.structure.css
@@ -0,0 +1,286 @@
+/*!
+ * jQuery UI CSS Framework 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/category/theming/
+ */
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden {
+ display: none;
+}
+.ui-helper-hidden-accessible {
+ border: 0;
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+.ui-helper-reset {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ line-height: 1.3;
+ text-decoration: none;
+ font-size: 100%;
+ list-style: none;
+}
+.ui-helper-clearfix:before,
+.ui-helper-clearfix:after {
+ content: "";
+ display: table;
+ border-collapse: collapse;
+}
+.ui-helper-clearfix:after {
+ clear: both;
+}
+.ui-helper-zfix {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ position: absolute;
+ opacity: 0;
+ filter:Alpha(Opacity=0); /* support: IE8 */
+}
+
+.ui-front {
+ z-index: 100;
+}
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled {
+ cursor: default !important;
+ pointer-events: none;
+}
+
+
+/* Icons
+----------------------------------*/
+.ui-icon {
+ display: inline-block;
+ vertical-align: middle;
+ margin-top: -.25em;
+ position: relative;
+ text-indent: -99999px;
+ overflow: hidden;
+ background-repeat: no-repeat;
+}
+
+.ui-widget-icon-block {
+ left: 50%;
+ margin-left: -8px;
+ display: block;
+}
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+.ui-button {
+ padding: .4em 1em;
+ display: inline-block;
+ position: relative;
+ line-height: normal;
+ margin-right: .1em;
+ cursor: pointer;
+ vertical-align: middle;
+ text-align: center;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+
+ /* Support: IE <= 11 */
+ overflow: visible;
+}
+
+.ui-button,
+.ui-button:link,
+.ui-button:visited,
+.ui-button:hover,
+.ui-button:active {
+ text-decoration: none;
+}
+
+/* to make room for the icon, a width needs to be set here */
+.ui-button-icon-only {
+ width: 2em;
+ box-sizing: border-box;
+ text-indent: -9999px;
+ white-space: nowrap;
+}
+
+/* no icon support for input elements */
+input.ui-button.ui-button-icon-only {
+ text-indent: 0;
+}
+
+/* button icon element(s) */
+.ui-button-icon-only .ui-icon {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ margin-top: -8px;
+ margin-left: -8px;
+}
+
+.ui-button.ui-icon-notext .ui-icon {
+ padding: 0;
+ width: 2.1em;
+ height: 2.1em;
+ text-indent: -9999px;
+ white-space: nowrap;
+
+}
+
+input.ui-button.ui-icon-notext .ui-icon {
+ width: auto;
+ height: auto;
+ text-indent: 0;
+ white-space: normal;
+ padding: .4em 1em;
+}
+
+/* workarounds */
+/* Support: Firefox 5 - 40 */
+input.ui-button::-moz-focus-inner,
+button.ui-button::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+.ui-controlgroup {
+ vertical-align: middle;
+ display: inline-block;
+}
+.ui-controlgroup > .ui-controlgroup-item {
+ float: left;
+ margin-left: 0;
+ margin-right: 0;
+}
+.ui-controlgroup > .ui-controlgroup-item:focus,
+.ui-controlgroup > .ui-controlgroup-item.ui-visual-focus {
+ z-index: 9999;
+}
+.ui-controlgroup-vertical > .ui-controlgroup-item {
+ display: block;
+ float: none;
+ width: 100%;
+ margin-top: 0;
+ margin-bottom: 0;
+ text-align: left;
+}
+.ui-controlgroup-vertical .ui-controlgroup-item {
+ box-sizing: border-box;
+}
+.ui-controlgroup .ui-controlgroup-label {
+ padding: .4em 1em;
+}
+.ui-controlgroup .ui-controlgroup-label span {
+ font-size: 80%;
+}
+.ui-controlgroup-horizontal .ui-controlgroup-label + .ui-controlgroup-item {
+ border-left: none;
+}
+.ui-controlgroup-vertical .ui-controlgroup-label + .ui-controlgroup-item {
+ border-top: none;
+}
+.ui-controlgroup-horizontal .ui-controlgroup-label.ui-widget-content {
+ border-right: none;
+}
+.ui-controlgroup-vertical .ui-controlgroup-label.ui-widget-content {
+ border-bottom: none;
+}
+
+/* Spinner specific style fixes */
+.ui-controlgroup-vertical .ui-spinner-input {
+
+ /* Support: IE8 only, Android < 4.4 only */
+ width: 75%;
+ width: calc( 100% - 2.4em );
+}
+.ui-controlgroup-vertical .ui-spinner .ui-spinner-up {
+ border-top-style: solid;
+}
+
+.ui-checkboxradio-label .ui-icon-background {
+ box-shadow: inset 1px 1px 1px #ccc;
+ border-radius: .12em;
+ border: none;
+}
+.ui-checkboxradio-radio-label .ui-icon-background {
+ width: 16px;
+ height: 16px;
+ border-radius: 1em;
+ overflow: visible;
+ border: none;
+}
+.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon,
+.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon {
+ background-image: none;
+ width: 8px;
+ height: 8px;
+ border-width: 4px;
+ border-style: solid;
+}
+.ui-checkboxradio-disabled {
+ pointer-events: none;
+}
+.ui-tabs {
+ position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
+ padding: .2em;
+}
+.ui-tabs .ui-tabs-nav {
+ margin: 0;
+ padding: .2em .2em 0;
+}
+.ui-tabs .ui-tabs-nav li {
+ list-style: none;
+ float: left;
+ position: relative;
+ top: 0;
+ margin: 1px .2em 0 0;
+ border-bottom-width: 0;
+ padding: 0;
+ white-space: nowrap;
+}
+.ui-tabs .ui-tabs-nav .ui-tabs-anchor {
+ float: left;
+ padding: .5em 1em;
+ text-decoration: none;
+}
+.ui-tabs .ui-tabs-nav li.ui-tabs-active {
+ margin-bottom: -1px;
+ padding-bottom: 1px;
+}
+.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,
+.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,
+.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor {
+ cursor: text;
+}
+.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor {
+ cursor: pointer;
+}
+.ui-tabs .ui-tabs-panel {
+ display: block;
+ border-width: 0;
+ padding: 1em 1.4em;
+ background: none;
+}
diff --git a/src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.theme.css b/src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.theme.css
new file mode 100644
index 0000000..3c5908b
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.theme.css
@@ -0,0 +1,443 @@
+/*!
+ * jQuery UI CSS Framework 1.12.1
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/category/theming/
+ *
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?scope=&folderName=smoothness&cornerRadiusShadow=8px&offsetLeftShadow=-8px&offsetTopShadow=-8px&thicknessShadow=8px&opacityShadow=30&bgImgOpacityShadow=0&bgTextureShadow=flat&bgColorShadow=aaaaaa&opacityOverlay=30&bgImgOpacityOverlay=0&bgTextureOverlay=flat&bgColorOverlay=aaaaaa&iconColorError=cd0a0a&fcError=cd0a0a&borderColorError=cd0a0a&bgImgOpacityError=95&bgTextureError=glass&bgColorError=fef1ec&iconColorHighlight=2e83ff&fcHighlight=363636&borderColorHighlight=fcefa1&bgImgOpacityHighlight=55&bgTextureHighlight=glass&bgColorHighlight=fbf9ee&iconColorActive=454545&fcActive=212121&borderColorActive=aaaaaa&bgImgOpacityActive=65&bgTextureActive=glass&bgColorActive=ffffff&iconColorHover=454545&fcHover=212121&borderColorHover=999999&bgImgOpacityHover=75&bgTextureHover=glass&bgColorHover=dadada&iconColorDefault=888888&fcDefault=555555&borderColorDefault=d3d3d3&bgImgOpacityDefault=75&bgTextureDefault=glass&bgColorDefault=e6e6e6&iconColorContent=222222&fcContent=222222&borderColorContent=aaaaaa&bgImgOpacityContent=75&bgTextureContent=flat&bgColorContent=ffffff&iconColorHeader=222222&fcHeader=222222&borderColorHeader=aaaaaa&bgImgOpacityHeader=75&bgTextureHeader=highlight_soft&bgColorHeader=cccccc&cornerRadius=4px&fsDefault=1.1em&fwDefault=normal&ffDefault=Verdana%2CArial%2Csans-serif
+ */
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget {
+ font-family: Verdana,Arial,sans-serif;
+ font-size: 1.1em;
+}
+.ui-widget .ui-widget {
+ font-size: 1em;
+}
+.ui-widget input,
+.ui-widget select,
+.ui-widget textarea,
+.ui-widget button {
+ font-family: Verdana,Arial,sans-serif;
+ font-size: 1em;
+}
+.ui-widget.ui-widget-content {
+ border: 1px solid #d3d3d3;
+}
+.ui-widget-content {
+ border: 1px solid #aaaaaa;
+ background: #ffffff;
+ color: #222222;
+}
+.ui-widget-content a {
+ color: #222222;
+}
+.ui-widget-header {
+ border: 1px solid #aaaaaa;
+ background: #cccccc url("images/ui-bg_highlight-soft_75_cccccc_1x100.png") 50% 50% repeat-x;
+ color: #222222;
+ font-weight: bold;
+}
+.ui-widget-header a {
+ color: #222222;
+}
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default,
+.ui-widget-content .ui-state-default,
+.ui-widget-header .ui-state-default,
+.ui-button,
+
+/* We use html here because we need a greater specificity to make sure disabled
+works properly when clicked or hovered */
+html .ui-button.ui-state-disabled:hover,
+html .ui-button.ui-state-disabled:active {
+ border: 1px solid #d3d3d3;
+ background: #e6e6e6 url("images/ui-bg_glass_75_e6e6e6_1x400.png") 50% 50% repeat-x;
+ font-weight: normal;
+ color: #555555;
+}
+.ui-state-default a,
+.ui-state-default a:link,
+.ui-state-default a:visited,
+a.ui-button,
+a:link.ui-button,
+a:visited.ui-button,
+.ui-button {
+ color: #555555;
+ text-decoration: none;
+}
+.ui-state-hover,
+.ui-widget-content .ui-state-hover,
+.ui-widget-header .ui-state-hover,
+.ui-state-focus,
+.ui-widget-content .ui-state-focus,
+.ui-widget-header .ui-state-focus,
+.ui-button:hover,
+.ui-button:focus {
+ border: 1px solid #999999;
+ background: #dadada url("images/ui-bg_glass_75_dadada_1x400.png") 50% 50% repeat-x;
+ font-weight: normal;
+ color: #212121;
+}
+.ui-state-hover a,
+.ui-state-hover a:hover,
+.ui-state-hover a:link,
+.ui-state-hover a:visited,
+.ui-state-focus a,
+.ui-state-focus a:hover,
+.ui-state-focus a:link,
+.ui-state-focus a:visited,
+a.ui-button:hover,
+a.ui-button:focus {
+ color: #212121;
+ text-decoration: none;
+}
+
+.ui-visual-focus {
+ box-shadow: 0 0 3px 1px rgb(94, 158, 214);
+}
+.ui-state-active,
+.ui-widget-content .ui-state-active,
+.ui-widget-header .ui-state-active,
+a.ui-button:active,
+.ui-button:active,
+.ui-button.ui-state-active:hover {
+ border: 1px solid #aaaaaa;
+ background: #ffffff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;
+ font-weight: normal;
+ color: #212121;
+}
+.ui-icon-background,
+.ui-state-active .ui-icon-background {
+ border: #aaaaaa;
+ background-color: #212121;
+}
+.ui-state-active a,
+.ui-state-active a:link,
+.ui-state-active a:visited {
+ color: #212121;
+ text-decoration: none;
+}
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight,
+.ui-widget-content .ui-state-highlight,
+.ui-widget-header .ui-state-highlight {
+ border: 1px solid #fcefa1;
+ background: #fbf9ee url("images/ui-bg_glass_55_fbf9ee_1x400.png") 50% 50% repeat-x;
+ color: #363636;
+}
+.ui-state-checked {
+ border: 1px solid #fcefa1;
+ background: #fbf9ee;
+}
+.ui-state-highlight a,
+.ui-widget-content .ui-state-highlight a,
+.ui-widget-header .ui-state-highlight a {
+ color: #363636;
+}
+.ui-state-error,
+.ui-widget-content .ui-state-error,
+.ui-widget-header .ui-state-error {
+ border: 1px solid #cd0a0a;
+ background: #fef1ec url("images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x;
+ color: #cd0a0a;
+}
+.ui-state-error a,
+.ui-widget-content .ui-state-error a,
+.ui-widget-header .ui-state-error a {
+ color: #cd0a0a;
+}
+.ui-state-error-text,
+.ui-widget-content .ui-state-error-text,
+.ui-widget-header .ui-state-error-text {
+ color: #cd0a0a;
+}
+.ui-priority-primary,
+.ui-widget-content .ui-priority-primary,
+.ui-widget-header .ui-priority-primary {
+ font-weight: bold;
+}
+.ui-priority-secondary,
+.ui-widget-content .ui-priority-secondary,
+.ui-widget-header .ui-priority-secondary {
+ opacity: .7;
+ filter:Alpha(Opacity=70); /* support: IE8 */
+ font-weight: normal;
+}
+.ui-state-disabled,
+.ui-widget-content .ui-state-disabled,
+.ui-widget-header .ui-state-disabled {
+ opacity: .35;
+ filter:Alpha(Opacity=35); /* support: IE8 */
+ background-image: none;
+}
+.ui-state-disabled .ui-icon {
+ filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */
+}
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon {
+ width: 16px;
+ height: 16px;
+}
+.ui-icon,
+.ui-widget-content .ui-icon {
+ background-image: url("images/ui-icons_222222_256x240.png");
+}
+.ui-widget-header .ui-icon {
+ background-image: url("images/ui-icons_222222_256x240.png");
+}
+.ui-state-hover .ui-icon,
+.ui-state-focus .ui-icon,
+.ui-button:hover .ui-icon,
+.ui-button:focus .ui-icon {
+ background-image: url("images/ui-icons_454545_256x240.png");
+}
+.ui-state-active .ui-icon,
+.ui-button:active .ui-icon {
+ background-image: url("images/ui-icons_454545_256x240.png");
+}
+.ui-state-highlight .ui-icon,
+.ui-button .ui-state-highlight.ui-icon {
+ background-image: url("images/ui-icons_2e83ff_256x240.png");
+}
+.ui-state-error .ui-icon,
+.ui-state-error-text .ui-icon {
+ background-image: url("images/ui-icons_cd0a0a_256x240.png");
+}
+.ui-button .ui-icon {
+ background-image: url("images/ui-icons_888888_256x240.png");
+}
+
+/* positioning */
+.ui-icon-blank { background-position: 16px 16px; }
+.ui-icon-caret-1-n { background-position: 0 0; }
+.ui-icon-caret-1-ne { background-position: -16px 0; }
+.ui-icon-caret-1-e { background-position: -32px 0; }
+.ui-icon-caret-1-se { background-position: -48px 0; }
+.ui-icon-caret-1-s { background-position: -65px 0; }
+.ui-icon-caret-1-sw { background-position: -80px 0; }
+.ui-icon-caret-1-w { background-position: -96px 0; }
+.ui-icon-caret-1-nw { background-position: -112px 0; }
+.ui-icon-caret-2-n-s { background-position: -128px 0; }
+.ui-icon-caret-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -65px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -65px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 1px -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-on { background-position: -96px -144px; }
+.ui-icon-radio-off { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-all,
+.ui-corner-top,
+.ui-corner-left,
+.ui-corner-tl {
+ border-top-left-radius: 4px;
+}
+.ui-corner-all,
+.ui-corner-top,
+.ui-corner-right,
+.ui-corner-tr {
+ border-top-right-radius: 4px;
+}
+.ui-corner-all,
+.ui-corner-bottom,
+.ui-corner-left,
+.ui-corner-bl {
+ border-bottom-left-radius: 4px;
+}
+.ui-corner-all,
+.ui-corner-bottom,
+.ui-corner-right,
+.ui-corner-br {
+ border-bottom-right-radius: 4px;
+}
+
+/* Overlays */
+.ui-widget-overlay {
+ background: #aaaaaa;
+ opacity: .3;
+ filter: Alpha(Opacity=30); /* support: IE8 */
+}
+.ui-widget-shadow {
+ -webkit-box-shadow: -8px -8px 8px #aaaaaa;
+ box-shadow: -8px -8px 8px #aaaaaa;
+}
diff --git a/src/lib/vendor/jquery-ui-iconfont-2.3.2/font/jquery-ui.woff2 b/src/lib/vendor/jquery-ui-iconfont-2.3.2/font/jquery-ui.woff2
new file mode 100644
index 0000000..f055e4a
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-iconfont-2.3.2/font/jquery-ui.woff2
Binary files differ
diff --git a/src/lib/vendor/jquery-ui-iconfont-2.3.2/jquery-ui-1.12.icon-font.css b/src/lib/vendor/jquery-ui-iconfont-2.3.2/jquery-ui-1.12.icon-font.css
new file mode 100644
index 0000000..63fb850
--- /dev/null
+++ b/src/lib/vendor/jquery-ui-iconfont-2.3.2/jquery-ui-1.12.icon-font.css
@@ -0,0 +1,839 @@
+/**
+ * ----------------------------------------------------------------------
+ * Icon Font for jQuery UI
+ * ----------------------------------------------------------------------
+ *
+ * ICON FONT Version: 2.1
+ * Glyphs: 332
+ * Copyright: (c) 2015-2017 Michael Keck.
+ * License: CC BY-SA 3.0
+ * https://creativecommons.org/licenses/by-sa/3.0/
+ * Generated: with IcoMoon-App (Chromium)
+ *
+ * STYLESHEET Version: 2.3.2
+ * Modified: 2017-03-04
+ * jQuery UI: 1.12 & 1.12.1
+ * jQMobile: 1.4.5
+ * Copyright: (c) 2015-2017 Michael Keck.
+ * License: GPL license
+ * http://www.gnu.org/licenses/gpl.html
+ */
+
+/* load icon font */
+@font-face {
+ font-family: 'jquery-ui';
+ src: url('font/jquery-ui.woff2?juif-bac778') format("woff2");
+ font-style: normal;
+ font-variant: normal;
+ font-weight: normal;
+}
+
+
+/* basic settings */
+html .ui-icon {
+ background-image: none !important;
+ display: inline-block;
+ font: normal normal normal 14px/16px sans-serif;
+ height: 1.2em;
+ line-height: 1.2em;
+ margin: 0;
+ overflow: hidden;
+ padding: 0;
+ position: relative;
+ text-indent: -99999em;
+ vertical-align: middle;
+ width: 1.2em;
+}
+
+/* UI-Icons */
+html .ui-icon:after {
+ display: block;
+ font-family: 'jquery-ui', sans-serif;
+ height: 1em;
+ left: 50%;
+ line-height: 1;
+ margin: -.5em;
+ position: absolute;
+ text-align: center;
+ text-indent: 0;
+ text-transform: none;
+ top: 50%;
+ vertical-align: middle;
+ width: 1em;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-transform: translate(0,0);
+ -moz-transform: translate(0,0);
+ transform: translate(0,0);
+}
+
+
+/**
+ * --------------------------------------------------------
+ * jQuery UI 1.12.x
+ * --------------------------------------------------------
+ */
+
+/* positioning on button element(s) */
+html .ui-button,
+html .ui-controlgroup .ui-controlgroup-label,
+html .ui-spinner .ui-spinner-input {
+ line-height: inherit;
+}
+html .ui-controlgroup .ui-controlgroup-label span {
+ line-height: 1;
+ margin: 0;
+ padding: 0;
+}
+html .ui-button .ui-icon {
+ margin: -.25em 0 -.15em 0;
+}
+html .ui-button-icon-only {
+ min-width: 2.5em;
+}
+html .ui-button-icon-only .ui-icon {
+ left: 50%;
+ margin: -0.6em 0 0 -.6em;
+ position: absolute;
+ top: 50%;
+}
+html .ui-selectmenu-button .ui-icon {
+ margin: -.6em 0 0 0;
+ position: absolute;
+ right: .5em;
+ top: 50%;
+}
+html .ui-selectmenu-text {
+ margin-right: 1em;
+}
+html .ui-spinner .ui-spinner-input {
+ margin: 0;
+ padding: .4em 2.5em .4em 1em;
+}
+html .ui-widget-icon-block {
+ display: block;
+ left: auto;
+ margin: 0;
+ width: 100%;
+ position: relative;
+}
+
+html .ui-datepicker .ui-datepicker-prev .ui-icon,
+html .ui-datepicker .ui-datepicker-next .ui-icon {
+ margin-left: -0.6em;
+ margin-top: -0.6em;
+}
+
+/* close button positioning on dialogs titlebar */
+html .ui-dialog .ui-dialog-titlebar-close {
+ height: 1.8em;
+ margin: -0.9em 0 0 0;
+ right: 0.3em;
+ width: 1.8em;
+}
+/* resizable on dialog */
+html .ui-dialog .ui-resizable-se {
+ bottom: 1px;
+ display: block;
+ height: 1em;
+ position: absolute;
+ right: 1px;
+ width: 1em;
+}
+.ui-dialog .ui-resizable-se:after {
+ left: 0;
+ margin: 0;
+ top: 0
+}
+/* positioning on accordion(s) */
+.ui-accordion .ui-accordion-header .ui-accordion-header-icon {
+ margin-left: -0.2em;
+ margin-right: 0.4em;
+}
+
+html .ui-icon-background,
+html .ui-state-active .ui-icon-background,
+html .ui-checkboxradio-label .ui-icon-background,
+html .ui-checkboxradio-radio-label .ui-icon-background,
+html .ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon,
+html .ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon {
+ background-color: rgba(0,0,0,.25);
+ border: 0 none;
+ color:inherit;
+ font: normal normal normal 14px/16px sans-serif;
+ height: 1.2em;
+ line-height: 1.2em;
+ width: 1.2em;
+ -webkit-box-shadow: inset 1px 1px 1px rgba(0,0,0,.25);
+ -moz-box-shadow: inset 1px 1px 1px rgba(0,0,0,.25);
+ box-shadow: inset 1px 1px 1px rgba(0,0,0,.25);
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+
+/* etxra */
+.has-left-icon li,
+li.has-left-icon {
+ list-style: none;
+}
+.has-left-icon[class^="ui-icon-"],
+.has-left-icon[class*=" ui-icon-"],
+.has-left-icon [class^="ui-icon-"],
+.has-left-icon [class*=" ui-icon-"] {
+ padding-left: 1.5em;
+ position: relative;
+}
+.has-left-icon[class^="ui-icon-"]:after,
+.has-left-icon[class*=" ui-icon-"]:after,
+.has-left-icon [class^="ui-icon-"]:after,
+.has-left-icon [class*=" ui-icon-"]:after {
+ left: 0;
+ margin: 0;
+ position: absolute;
+ top: 0;
+}
+.has-right-icon[class^="ui-icon-"],
+.has-right-icon[class*=" ui-icon-"],
+.has-right-icon [class^="ui-icon-"],
+.has-right-icon [class*=" ui-icon-"] {
+ padding-right: 1.5em;
+ position: relative;
+}
+.has-right-icon[class^="ui-icon-"]:after,
+.has-right-icon[class*=" ui-icon-"]:after,
+.has-right-icon [class^="ui-icon-"]:after,
+.has-right-icon [class*=" ui-icon-"]:after {
+ right: 0;
+ margin: 0;
+ position: absolute;
+ top: 0;
+}
+
+
+/**
+ * --------------------------------------------------------
+ * jQuery Mobile
+ * (testet with version 1.4.5)
+ * --------------------------------------------------------
+ */
+.ui-mobile .ui-input-search:after,
+.ui-mobile .ui-btn-icon-left:after,
+.ui-mobile .ui-btn-icon-right:after,
+.ui-mobile .ui-btn-icon-top:after,
+.ui-mobile .ui-btn-icon-bottom:after,
+.ui-mobile .ui-btn-icon-notext:after {
+ background-image: none !important;
+ color: #fff;
+ display: block;
+ height: 20px;
+ font: normal normal normal 14px 'jquery-ui', sans-serif;
+ left: 50%;
+ line-height: 14px;
+ margin-left: -10px;
+ margin-top: -10px;
+ padding: 3px;
+ position: absolute;
+ text-align: center;
+ text-indent: 0;
+ text-shadow: none;
+ text-transform: none;
+ top: 50%;
+ vertical-align: middle;
+ width: 20px;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ -webkit-transform: translate(0,0);
+ -moz-transform: translate(0,0);
+ transform: translate(0,0);
+}
+.ui-mobile .ui-input-search:after,
+.ui-mobile .ui-alt-icon.ui-btn-icon-left:after, .ui-mobile .ui-alt-icon .ui-btn-icon-left:after,
+.ui-mobile .ui-alt-icon.ui-btn-icon-right:after, .ui-mobile .ui-alt-icon .ui-btn-icon-right:after,
+.ui-mobile .ui-alt-icon.ui-btn-icon-top:after, .ui-mobile .ui-alt-icon .ui-btn-icon-top:after,
+.ui-mobile .ui-alt-icon.ui-btn-icon-bottom:after, .ui-mobile .ui-alt-icon .ui-btn-icon-bottom:after,
+.ui-mobile .ui-alt-icon.ui-btn-icon-notext:after, .ui-mobile .ui-alt-icon .ui-btn-icon-notext:after {
+ color: #000;
+}
+.ui-mobile .ui-input-search:after,
+.ui-mobile .ui-btn-icon-left:after {
+ left: .37em;
+ margin-left: 0;
+}
+.ui-mobile .ui-btn-icon-right:after {
+ left: auto;
+ margin-left: 0;
+ right: .37em;
+}
+.ui-mobile .ui-mini.ui-btn-icon-left:after,
+.ui-mobile .ui-mini .ui-btn-icon-left:after,
+.ui-mobile .ui-header .ui-btn-icon-left:after,
+.ui-mobile .ui-footer .ui-btn-icon-left:after {
+ left: .37em;
+}
+.ui-mobile .ui-mini.ui-btn-icon-right:after,
+.ui-mobile .ui-mini .ui-btn-icon-right:after,
+.ui-mobile .ui-header .ui-btn-icon-right:after,
+.ui-mobile .ui-footer .ui-btn-icon-right:after {
+ right: .37em;
+}
+.ui-mobile .ui-btn-icon-top:after {
+ margin-top: 0;
+ top: .5625em;
+}
+.ui-mobile .ui-btn-icon-bottom:after {
+ bottom: .5625em;
+ margin-top: 0;
+ top: auto;
+}
+
+.ui-btn.ui-checkbox-on.ui-checkbox-on:after {
+ color: #fff;
+}
+.ui-btn.ui-checkbox-off:after,
+.ui-btn.ui-checkbox-on:after,
+.ui-btn.ui-radio-off:after,
+.ui-btn.ui-radio-on:after {
+ display: block;
+ font-size: 14px;
+ height: 20px;
+ margin: -10px 2px 0 2px;
+ padding: 3px;
+ width: 20px;
+}
+.ui-mini .ui-btn.ui-checkbox-off:after,
+.ui-mini .ui-btn.ui-checkbox-on:after,
+.ui-mini .ui-btn.ui-radio-off:after,
+.ui-mini .ui-btn.ui-radio-on:after {
+ height: 18px;
+ margin: -9px 2px 0 2px;
+ padding: 2px;
+ width: 18px;
+}
+.ui-alt-icon.ui-btn.ui-checkbox-on:after,
+.ui-alt-icon .ui-btn.ui-checkbox-on:after {
+ color: #000;
+}
+.ui-radio .ui-btn.ui-radio-on:after {
+ background: #fff none 0 0 no-repeat;
+ border-style: solid;
+ border-width: 5px;
+ height: 20px;
+ padding: 0;
+ text-indent: -9999px;
+ width: 20px;
+}
+.ui-mini .ui-radio .ui-btn.ui-radio-on:after {
+ height: 18px;
+ border-width: 4px;
+ width: 18px;
+}
+.ui-alt-icon.ui-btn.ui-radio-on:after,
+.ui-alt-icon .ui-btn.ui-radio-on:after {
+ background-color: #000;
+}
+
+
+
+/* apply glyphs to icons */
+.ui-icon-blank:after { content: ' '; } /* <-- yeah, this really needed! */
+.ui-icon-addon:after,
+.ui-icon-puzzle:after { content: '\e6ca'; }
+.ui-icon-address:after { content: '\e702'; }
+.ui-icon-alert:after { content: '\e65f'; }
+.ui-icon-alert-b:after { content: '\e660'; }
+.ui-icon-anchor:after { content: '\e6ba'; }
+.ui-icon-archive:after { content: '\e70d'; }
+.ui-icon-arrow-1-e:after,
+.ui-icon-arrow-r:after { content: '\e603'; }
+.ui-icon-arrow-1-n:after,
+.ui-icon-arrow-u:after { content: '\e601'; }
+.ui-icon-arrow-1-ne:after,
+.ui-icon-arrow-u-r:after { content: '\e602'; }
+.ui-icon-arrow-1-nw:after,
+.ui-icon-arrow-u-l:after { content: '\e608'; }
+.ui-icon-arrow-1-s:after,
+.ui-icon-arrow-d:after { content: '\e605'; }
+.ui-icon-arrow-1-se:after,
+.ui-icon-arrow-d-r:after { content: '\e604'; }
+.ui-icon-arrow-1-sw:after,
+.ui-icon-arrow-d-l:after { content: '\e606'; }
+.ui-icon-arrow-1-w:after,
+.ui-icon-arrow-l:after { content: '\e607'; }
+.ui-icon-arrow-2-e-w:after,
+.ui-icon-move-h:after,
+.ui-icon-resize-h:after { content: '\e617'; }
+.ui-icon-arrow-2-n-s:after,
+.ui-icon-move-v:after,
+.ui-icon-resize-v:after { content: '\e615'; }
+.ui-icon-arrow-2-ne-sw:after { content: '\e616'; }
+.ui-icon-arrow-2-se-nw:after { content: '\e618'; }
+.ui-icon-arrow-4:after,
+.ui-icon-move:after { content: '\e619'; }
+.ui-icon-arrow-4-diag:after { content: '\e61a'; }
+.ui-icon-arrowrefresh-1-e:after { content: '\e612'; }
+.ui-icon-arrowrefresh-1-n:after { content: '\e611'; }
+.ui-icon-arrowrefresh-1-s:after { content: '\e613'; }
+.ui-icon-arrowrefresh-1-w:after { content: '\e614'; }
+.ui-icon-arrowreturn-1-e:after,
+.ui-icon-forward:after { content: '\e60e'; }
+.ui-icon-arrowreturn-1-n:after { content: '\e60d'; }
+.ui-icon-arrowreturn-1-s:after,
+.ui-icon-back:after { content: '\e60f'; }
+.ui-icon-arrowreturn-1-w:after { content: '\e610'; }
+.ui-icon-arrowreturnthick-1-e:after { content: '\e628'; }
+.ui-icon-arrowreturnthick-1-n:after { content: '\e627'; }
+.ui-icon-arrowreturnthick-1-s:after { content: '\e629'; }
+.ui-icon-arrowreturnthick-1-w:after { content: '\e62a'; }
+.ui-icon-arrowstop-1-e:after { content: '\e60a'; }
+.ui-icon-arrowstop-1-n:after { content: '\e609'; }
+.ui-icon-arrowstop-1-s:after { content: '\e60b'; }
+.ui-icon-arrowstop-1-w:after { content: '\e60c'; }
+.ui-icon-arrowthick-1-e:after { content: '\e61d'; }
+.ui-icon-arrowthick-1-n:after { content: '\e61b'; }
+.ui-icon-arrowthick-1-ne:after { content: '\e61c'; }
+.ui-icon-arrowthick-1-nw:after { content: '\e622'; }
+.ui-icon-arrowthick-1-s:after { content: '\e61f'; }
+.ui-icon-arrowthick-1-se:after { content: '\e61e'; }
+.ui-icon-arrowthick-1-sw:after { content: '\e620'; }
+.ui-icon-arrowthick-1-w:after { content: '\e621'; }
+.ui-icon-arrowthick-2-e-w:after { content: '\e62d'; }
+.ui-icon-arrowthick-2-n-s:after { content: '\e62b'; }
+.ui-icon-arrowthick-2-ne-sw:after { content: '\e62c'; }
+.ui-icon-arrowthick-2-se-nw:after { content: '\e62e'; }
+.ui-icon-arrowthickstop-1-e:after { content: '\e624'; }
+.ui-icon-arrowthickstop-1-n:after { content: '\e623'; }
+.ui-icon-arrowthickstop-1-s:after { content: '\e625'; }
+.ui-icon-arrowthickstop-1-w:after { content: '\e626'; }
+.ui-icon-battery-0:after { content: '\e721'; }
+.ui-icon-battery-1:after { content: '\e722'; }
+.ui-icon-battery-2:after { content: '\e723'; }
+.ui-icon-battery-3:after { content: '\e724'; }
+.ui-icon-book:after { content: '\e6fb'; }
+.ui-icon-book-b:after { content: '\e6fc'; }
+.ui-icon-bookmark:after { content: '\e6c5'; }
+.ui-icon-bookmark-b:after { content: '\e6c6'; }
+.ui-icon-box:after { content: '\e6eb'; }
+.ui-icon-bucket:after { content: '\e728'; }
+.ui-icon-bug:after { content: '\e72e'; }
+.ui-icon-bullet:after,
+html .ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon:after,
+html .ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon:after { content: '\e65d'; }
+.ui-icon-bullhorn:after { content: '\e731'; }
+.ui-icon-calculator:after { content: '\e6fd'; }
+.ui-icon-calculator-b:after { content: '\e6fe'; }
+.ui-icon-calendar:after { content: '\e6ff'; }
+.ui-icon-calendar-b:after { content: '\e700'; }
+.ui-icon-calendar-day:after { content: '\e701'; }
+.ui-icon-camera:after { content: '\e6e8'; }
+.ui-icon-cancel:after,
+.ui-icon-forbidden:after { content: '\e675'; }
+.ui-icon-caret-1-e:after,
+.ui-icon-caret-r:after,
+.ui-icon-carat-r:after { content: '\e639'; }
+.ui-icon-caret-1-n:after,
+.ui-icon-caret-u:after,
+.ui-icon-carat-u:after { content: '\e637'; }
+.ui-icon-caret-1-ne:after { content: '\e638'; }
+.ui-icon-caret-1-nw:after { content: '\e63e'; }
+.ui-icon-caret-1-s:after,
+.ui-icon-caret-d:after,
+.ui-icon-carat-d:after { content: '\e63b'; }
+.ui-icon-caret-1-se:after { content: '\e63a'; }
+.ui-icon-caret-1-sw:after { content: '\e63c'; }
+.ui-icon-caret-1-w:after,
+.ui-icon-caret-l:after,
+.ui-icon-carat-l:after { content: '\e63d'; }
+.ui-icon-caret-2-e:after { content: '\e640'; }
+.ui-icon-caret-2-e-w:after { content: '\e643'; }
+.ui-icon-caret-2-n:after { content: '\e63f'; }
+.ui-icon-caret-2-n-s:after { content: '\e644'; }
+.ui-icon-caret-2-s:after { content: '\e641'; }
+.ui-icon-caret-2-w:after { content: '\e642'; }
+.ui-icon-caretstop-1-e:after,
+.ui-icon-caratstop-1-e:after { content: '\e905'; }
+.ui-icon-caretstop-1-n:after,
+.ui-icon-caratstop-1-n:after { content: '\e901'; }
+.ui-icon-caretstop-1-s:after,
+.ui-icon-caratstop-1-s:after { content: '\e900'; }
+.ui-icon-caretstop-1-w:after,
+.ui-icon-caratstop-1-w:after { content: '\e904'; }
+.ui-icon-cart:after,
+.ui-icon-shop:after { content: '\e6d6'; }
+.ui-icon-cart-b:after,
+.ui-icon-shop-b:after { content: '\e6d7'; }
+.ui-icon-chart-bars:after { content: '\e734'; }
+.ui-icon-chart-line:after { content: '\e735'; }
+.ui-icon-chart-pie:after { content: '\e733'; }
+.ui-icon-check:after,
+html .ui-btn.ui-checkbox-on.ui-checkbox-on:after,
+html .ui-alt-icon.ui-btn.ui-checkbox-on:after,
+html .ui-alt-icon .ui-btn.ui-checkbox-on:after { content: '\e670'; }
+.ui-icon-check-off:after,
+.ui-icon-checkbox:after,
+.ui-icon-checkbox-off:after,
+.ui-icon-checkbox-unchecked:after { content: '\e673'; }
+.ui-icon-check-on:after,
+.ui-icon-checkbox-on:after,
+.ui-icon-checkbox-checked:after { content: '\e674'; }
+.ui-icon-circle:after,
+.ui-icon-radio-off:after,
+.ui-icon-radio-btn:after,
+.ui-icon-radio-btn-off:after,
+.ui-icon-radio-btn-unchecked:after { content: '\e65e'; }
+.ui-icon-circle-arrow-e:after { content: '\e630'; }
+.ui-icon-circle-arrow-n:after { content: '\e62f'; }
+.ui-icon-circle-arrow-s:after { content: '\e631'; }
+.ui-icon-circle-arrow-w:after { content: '\e632'; }
+.ui-icon-circle-b-arrow-e:after { content: '\e634'; }
+.ui-icon-circle-b-arrow-n:after { content: '\e633'; }
+.ui-icon-circle-b-arrow-s:after { content: '\e635'; }
+.ui-icon-circle-b-arrow-w:after { content: '\e636'; }
+.ui-icon-circle-b-check:after { content: '\e672'; }
+.ui-icon-circle-b-close:after { content: '\e678'; }
+.ui-icon-circle-b-help:after { content: '\e663'; }
+.ui-icon-circle-b-info:after { content: '\e666'; }
+.ui-icon-circle-b-minus:after { content: '\e67e'; }
+.ui-icon-circle-b-notice:after { content: '\e669'; }
+.ui-icon-circle-b-plus:after { content: '\e684'; }
+.ui-icon-circle-b-triangle-e:after { content: '\e65a'; }
+.ui-icon-circle-b-triangle-n:after { content: '\e659'; }
+.ui-icon-circle-b-triangle-s:after { content: '\e65b'; }
+.ui-icon-circle-b-triangle-w:after { content: '\e65c'; }
+.ui-icon-circle-check:after { content: '\e671'; }
+.ui-icon-circle-close:after { content: '\e677'; }
+.ui-icon-circle-help:after,
+.ui-icon-help:after { content: '\e662'; }
+.ui-icon-circle-info:after,
+.ui-icon-info:after { content: '\e665'; }
+.ui-icon-circle-minus:after { content: '\e67d'; }
+.ui-icon-circle-notice:after,
+.ui-icon-notice:after { content: '\e668'; }
+.ui-icon-circle-phone:after { content: '\e705'; }
+.ui-icon-circle-plus:after { content: '\e683'; }
+.ui-icon-circle-triangle-e:after { content: '\e656'; }
+.ui-icon-circle-triangle-n:after { content: '\e655'; }
+.ui-icon-circle-triangle-s:after { content: '\e657'; }
+.ui-icon-circle-triangle-w:after { content: '\e658'; }
+.ui-icon-circle-zoom:after { content: '\e712'; }
+.ui-icon-circle-zoomin:after { content: '\e714'; }
+.ui-icon-circle-zoomout:after { content: '\e716'; }
+.ui-icon-circlesmall-close:after { content: '\e67b'; }
+.ui-icon-circlesmall-minus:after { content: '\e681'; }
+.ui-icon-circlesmall-plus:after { content: '\e687'; }
+.ui-icon-client:after { content: '\e72f'; }
+.ui-icon-clipboard:after,
+.ui-icon-paste:after { content: '\e68b'; }
+.ui-icon-clock:after { content: '\e6d9'; }
+.ui-icon-clock-b:after { content: '\e6da'; }
+.ui-icon-close:after,
+.ui-icon-delete:after { content: '\e676'; }
+.ui-icon-closethick:after { content: '\e679'; }
+.ui-icon-cloud:after { content: '\e6dc'; }
+.ui-icon-cloud-b:after { content: '\e6dd'; }
+.ui-icon-cloud-download:after { content: '\e6de'; }
+.ui-icon-cloud-upload:after { content: '\e6df'; }
+.ui-icon-comment:after { content: '\e6e0'; }
+.ui-icon-comments:after { content: '\e6e1'; }
+.ui-icon-console:after { content: '\e6c0'; }
+.ui-icon-contact:after,
+.ui-icon-vcard:after { content: '\e703'; }
+.ui-icon-copy:after,
+.ui-icon-files:after { content: '\e689'; }
+.ui-icon-creditcard:after { content: '\e6d8'; }
+.ui-icon-database:after { content: '\e6f9'; }
+.ui-icon-databases:after { content: '\e6fa'; }
+.ui-icon-disk:after,
+.ui-icon-save:after { content: '\e68c'; }
+.ui-icon-document:after,
+.ui-icon-file:after { content: '\e69c'; }
+.ui-icon-document-b:after { content: '\e69d'; }
+.ui-icon-download:after { content: '\e6aa'; }
+.ui-icon-eject:after { content: '\e6b6'; }
+.ui-icon-erase:after { content: '\e72b'; }
+.ui-icon-extlink:after,
+.ui-icon-linkext:after,
+.ui-icon-action:after { content: '\e6b8'; }
+.ui-icon-eye:after { content: '\e6ea'; }
+.ui-icon-file-audio:after,
+.ui-icon-audio:after { content: '\e69e'; }
+.ui-icon-file-pdf:after { content: '\e6a3'; }
+.ui-icon-file-report:after { content: '\e6a6'; }
+.ui-icon-file-richtext:after { content: '\e6a4'; }
+.ui-icon-file-table:after { content: '\e6a5'; }
+.ui-icon-file-text:after { content: '\e6a7'; }
+.ui-icon-file-word:after { content: '\e6a8'; }
+.ui-icon-file-zip:after { content: '\e6a9'; }
+.ui-icon-flag:after { content: '\e6e9'; }
+.ui-icon-folder-collapsed:after,
+.ui-icon-folder:after,
+.ui-icon-folder-closed:after { content: '\e69a'; }
+.ui-icon-folder-open:after { content: '\e69b'; }
+.ui-icon-fullscreen:after,
+.ui-icon-fullscreen-on:after { content: '\e902'; }
+.ui-icon-fullscreen-off:after { content: '\e903'; }
+.ui-icon-gear:after { content: '\e6e6'; }
+.ui-icon-gears:after { content: '\e6e7'; }
+.ui-icon-globe:after { content: '\e6e2'; }
+.ui-icon-globe-b:after { content: '\e6e3'; }
+.ui-icon-grip-diagonal-se:after { content: '\e66a'; }
+.ui-icon-grip-dotted-horizontal:after { content: '\e66e'; }
+.ui-icon-grip-dotted-vertical:after { content: '\e66f'; }
+.ui-icon-grip-solid-horizontal:after { content: '\e66c'; }
+.ui-icon-grip-solid-vertical:after { content: '\e66d'; }
+.ui-icon-gripsmall-diagonal-se:after { content: '\e66b'; }
+.ui-icon-heart:after { content: '\e6d1'; }
+.ui-icon-heart-b:after { content: '\e6d2'; }
+.ui-icon-heart-beat:after { content: '\e6d3'; }
+.ui-icon-help-plain:after { content: '\e661'; }
+.ui-icon-history:after { content: '\e6db'; }
+.ui-icon-home:after { content: '\e6c4'; }
+.ui-icon-image:after,
+.ui-icon-file-image:after { content: '\e6a1'; }
+.ui-icon-info-plain:after { content: '\e664'; }
+.ui-icon-jquery:after { content: '\e746'; }
+.ui-icon-key:after { content: '\e6d4'; }
+.ui-icon-lightbulb:after { content: '\e6d5'; }
+.ui-icon-link:after { content: '\e6b7'; }
+.ui-icon-link-broken:after { content: '\e6b9'; }
+.ui-icon-loading-status-balls:after { content: '\e741'; }
+.ui-icon-loading-status-circle:after { content: '\e742'; }
+.ui-icon-loading-status-comet:after { content: '\e743'; }
+.ui-icon-loading-status-lines:after { content: '\e744'; }
+.ui-icon-loading-status-planet:after { content: '\e745'; }
+.ui-icon-location:after { content: '\e6e4'; }
+.ui-icon-locked:after,
+.ui-icon-lock:after { content: '\e6bb'; }
+.ui-icon-mail-attachment:after { content: '\e70b'; }
+.ui-icon-mail-closed:after,
+.ui-icon-mail:after,
+.ui-icon-email:after { content: '\e706'; }
+.ui-icon-mail-forward:after { content: '\e708'; }
+.ui-icon-mail-open:after,
+.ui-icon-mail-read:after { content: '\e707'; }
+.ui-icon-mail-reply:after { content: '\e709'; }
+.ui-icon-mail-replyall:after { content: '\e70a'; }
+.ui-icon-mail-send:after { content: '\e70c'; }
+.ui-icon-marker:after { content: '\e72c'; }
+.ui-icon-menu:after,
+.ui-icon-bars:after { content: '\e6c3'; }
+.ui-icon-microphone:after { content: '\e6b2'; }
+.ui-icon-microphone-off:after { content: '\e6b3'; }
+.ui-icon-minus:after { content: '\e67c'; }
+.ui-icon-minusthick:after { content: '\e67f'; }
+.ui-icon-movie:after,
+.ui-icon-file-movie:after { content: '\e69f'; }
+.ui-icon-navigation:after { content: '\e6e5'; }
+.ui-icon-newspaper:after,
+.ui-icon-newsletter:after,
+.ui-icon-news:after { content: '\e70e'; }
+.ui-icon-newwin:after,
+.ui-icon-popup:after,
+.ui-icon-windows:after { content: '\e6be'; }
+.ui-icon-note:after { content: '\e695'; }
+.ui-icon-notice-plain:after { content: '\e667'; }
+.ui-icon-package:after { content: '\e6cc'; }
+.ui-icon-palette:after { content: '\e729'; }
+.ui-icon-pause:after { content: '\e6ad'; }
+.ui-icon-pencil:after,
+.ui-icon-edit:after { content: '\e688'; }
+.ui-icon-person:after,
+.ui-icon-user:after { content: '\e6d0'; }
+.ui-icon-persons:after,
+.ui-icon-users:after,
+.ui-icon-group:after { content: '\e6cf'; }
+.ui-icon-phone:after { content: '\e704'; }
+.ui-icon-pilcrow:after { content: '\e727'; }
+.ui-icon-pin-s:after { content: '\e70f'; }
+.ui-icon-pin-w:after { content: '\e710'; }
+.ui-icon-play:after { content: '\e6ac'; }
+.ui-icon-plugin:after { content: '\e6cb'; }
+.ui-icon-plus:after { content: '\e682'; }
+.ui-icon-plusthick:after { content: '\e685'; }
+.ui-icon-power:after,
+.ui-icon-switch:after { content: '\e6cd'; }
+.ui-icon-print:after { content: '\e692'; }
+.ui-icon-print-b:after { content: '\e693'; }
+.ui-icon-print-layout:after { content: '\e694'; }
+.ui-icon-prush:after { content: '\e72a'; }
+.ui-icon-radio-on:after,
+.ui-icon-radio-btn-on:after,
+.ui-icon-radio-btn-checked:after { content: '\e6f5'; }
+.ui-icon-redo:after { content: '\e68e'; }
+.ui-icon-refresh:after,
+.ui-icon-reload:after { content: '\e6ce'; }
+.ui-icon-rename:after,
+.ui-icon-input:after { content: '\e68f'; }
+.ui-icon-retweet:after { content: '\e6b5'; }
+.ui-icon-scissors:after,
+.ui-icon-cut:after { content: '\e68a'; }
+.ui-icon-screen-desktop:after,
+.ui-icon-desktop:after { content: '\e718'; }
+.ui-icon-screen-laptop:after,
+.ui-icon-laptop:after { content: '\e719'; }
+.ui-icon-screen-mobile:after,
+.ui-icon-mobile:after { content: '\e71a'; }
+.ui-icon-script:after,
+.ui-icon-file-script:after { content: '\e6a2'; }
+.ui-icon-search:after,
+.ui-input-search:after { content: '\e6f2'; }
+.ui-icon-select:after { content: '\e72d'; }
+.ui-icon-selectbox:after { content: '\e6f6'; }
+.ui-icon-server:after { content: '\e730'; }
+.ui-icon-settings:after { content: '\e6f4'; }
+.ui-icon-shield:after { content: '\e732'; }
+.ui-icon-shuffle:after { content: '\e6b4'; }
+.ui-icon-shuttle:after { content: '\e73f'; }
+.ui-icon-sign-in:after,
+.ui-icon-login:after { content: '\e6ee'; }
+.ui-icon-sign-out:after,
+.ui-icon-logout:after,
+.ui-icon-logoff:after { content: '\e6ef'; }
+.ui-icon-signal:after { content: '\e725'; }
+.ui-icon-signal-diag:after,
+.ui-icon-rss:after,
+.ui-icon-feed:after { content: '\e726'; }
+.ui-icon-sitemap:after { content: '\e736'; }
+.ui-icon-sorting:after { content: '\e71e'; }
+.ui-icon-sorting-asc:after { content: '\e71f'; }
+.ui-icon-sorting-desc:after { content: '\e720'; }
+.ui-icon-squaresmall-close:after { content: '\e67a'; }
+.ui-icon-squaresmall-minus:after { content: '\e680'; }
+.ui-icon-squaresmall-plus:after { content: '\e686'; }
+.ui-icon-star:after { content: '\e6c7'; }
+.ui-icon-star-b:after { content: '\e6c9'; }
+.ui-icon-star-h:after { content: '\e6c8'; }
+.ui-icon-stop:after { content: '\e6ae'; }
+.ui-icon-structure:after { content: '\e737'; }
+.ui-icon-suitcase:after { content: '\e6f7'; }
+.ui-icon-table:after { content: '\e696'; }
+.ui-icon-tag:after { content: '\e697'; }
+.ui-icon-tags:after { content: '\e698'; }
+.ui-icon-template:after { content: '\e738'; }
+.ui-icon-ticket:after { content: '\e699'; }
+.ui-icon-toggle-off:after { content: '\e6f0'; }
+.ui-icon-toggle-on:after { content: '\e6f1'; }
+.ui-icon-transfer-e-w:after { content: '\e6ec'; }
+.ui-icon-transferthick-e-w:after { content: '\e6ed'; }
+.ui-icon-transform:after { content: '\e739'; }
+.ui-icon-translate:after { content: '\e740'; }
+.ui-icon-trash:after,
+.ui-icon-recycle:after { content: '\e690'; }
+.ui-icon-trash-b:after { content: '\e691'; }
+.ui-icon-triangle-1-e:after { content: '\e647'; }
+.ui-icon-triangle-1-e-stop:after,
+.ui-icon-seek-end:after { content: '\e64e'; }
+.ui-icon-triangle-1-n:after { content: '\e645'; }
+.ui-icon-triangle-1-n-stop:after { content: '\e64d'; }
+.ui-icon-triangle-1-ne:after { content: '\e646'; }
+.ui-icon-triangle-1-nw:after { content: '\e64c'; }
+.ui-icon-triangle-1-s:after { content: '\e64b'; }
+.ui-icon-triangle-1-s-stop:after { content: '\e64f'; }
+.ui-icon-triangle-1-se:after { content: '\e64a'; }
+.ui-icon-triangle-1-sw:after { content: '\e648'; }
+.ui-icon-triangle-1-w:after { content: '\e649'; }
+.ui-icon-triangle-1-w-stop:after,
+.ui-icon-seek-first:after { content: '\e650'; }
+.ui-icon-triangle-2-e:after,
+.ui-icon-seek-next:after { content: '\e651'; }
+.ui-icon-triangle-2-e-w:after { content: '\e654'; }
+.ui-icon-triangle-2-n-s:after { content: '\e653'; }
+.ui-icon-triangle-2-w:after,
+.ui-icon-seek-prev:after { content: '\e652'; }
+.ui-icon-truck:after { content: '\e6f8'; }
+.ui-icon-undo:after { content: '\e68d'; }
+.ui-icon-unlocked:after,
+.ui-icon-lock-open:after { content: '\e6bc'; }
+.ui-icon-upload:after { content: '\e6ab'; }
+.ui-icon-vcs-branch:after { content: '\e73d'; }
+.ui-icon-vcs-compare:after { content: '\e73b'; }
+.ui-icon-vcs-fork:after { content: '\e73a'; }
+.ui-icon-vcs-merge:after { content: '\e73e'; }
+.ui-icon-vcs-pull-request:after { content: '\e73c'; }
+.ui-icon-video:after,
+.ui-icon-file-video:after { content: '\e6a0'; }
+.ui-icon-view-icons:after,
+.ui-icon-grid-b:after { content: '\e71b'; }
+.ui-icon-view-icons-b:after,
+.ui-icon-grid:after { content: '\e71c'; }
+.ui-icon-view-list:after,
+.ui-icon-list:after,
+.ui-icon-bullets:after { content: '\e71d'; }
+.ui-icon-volume-off:after,
+.ui-icon-volume-mute:after { content: '\e6af'; }
+.ui-icon-volume-on:after,
+.ui-icon-volume-high:after { content: '\e6b0'; }
+.ui-icon-volume-on-b:after,
+.ui-icon-volume-low:after { content: '\e6b1'; }
+.ui-icon-window:after { content: '\e6bd'; }
+.ui-icon-window-close:after { content: '\e6c1'; }
+.ui-icon-window-minimize:after { content: '\e6c2'; }
+.ui-icon-window-sidebar:after { content: '\e6bf'; }
+.ui-icon-wrench:after { content: '\e6f3'; }
+.ui-icon-zoom:after { content: '\e711'; }
+.ui-icon-zoomequal:after { content: '\e717'; }
+.ui-icon-zoomin:after { content: '\e713'; }
+.ui-icon-zoomout:after { content: '\e715'; }
+
+.ui-icon-carat-1-e:after { content: '\e639'; } /* deprecated: use '.ui-icon-caret-1-e' instead */
+.ui-icon-carat-1-n:after { content: '\e637'; } /* deprecated: use '.ui-icon-caret-1-n' instead */
+.ui-icon-carat-1-s:after { content: '\e63b'; } /* deprecated: use '.ui-icon-caret-1-s' instead */
+.ui-icon-carat-1-w:after { content: '\e63d'; } /* deprecated: use '.ui-icon-caret-1-w' instead */
+.ui-icon-carat-2-e:after { content: '\e640'; } /* deprecated: use '.ui-icon-caret-2-e' instead */
+.ui-icon-carat-2-e-w:after { content: '\e643'; } /* deprecated: use '.ui-icon-caret-2-e-w' instead */
+.ui-icon-carat-2-n:after { content: '\e63f'; } /* deprecated: use '.ui-icon-caret-2-n' instead */
+.ui-icon-carat-2-n-s:after { content: '\e644'; } /* deprecated: use '.ui-icon-caret-2-n-s' instead */
+.ui-icon-carat-2-s:after { content: '\e641'; } /* deprecated: use '.ui-icon-caret-2-s' instead */
+.ui-icon-carat-2-w:after { content: '\e642'; } /* deprecated: use '.ui-icon-caret-2-w' instead */
+.ui-icon-caratstop-1-e:after { content: '\e905'; } /* deprecated: use '.ui-icon-caretstop-1-e' instead */
+.ui-icon-caratstop-1-n:after { content: '\e901'; } /* deprecated: use '.ui-icon-caretstop-1-n' instead */
+.ui-icon-caratstop-1-s:after { content: '\e900'; } /* deprecated: use '.ui-icon-caretstop-1-s' instead */
+.ui-icon-caratstop-1-w:after { content: '\e904'; } /* deprecated: use '.ui-icon-caretstop-1-w' instead */
+
+/* bounce animations */
+@keyframes bounce {
+ 0%, 100% { -webkit-transform: scale(0.2); -moz-transform: scale(0.2); -ms-transform: scale(0.2); transform: scale(0.2); }
+ 50% { -webkit-transform: scale(1.0); -moz-transform: scale(1.0); -ms-transform: scale(1.0); transform: scale(1.0); }
+}
+@-moz-keyframes bounce { 0%, 100% { -moz-transform: scale(0.2); transform: scale(0.2); } 50% { -moz-transform: scale(1.0); transform: scale(1.0); } }
+@-ms-keyframes bounce { 0%, 100% { -ms-transform: scale(0.2); transform: scale(0.2); } 50% { -ms-transform: scale(1.0); transform: scale(1.0); } }
+@-webkit-keyframes bounce { 0%, 100% { -webkit-transform: scale(0.2); transform: scale(0.2); } 50% { -webkit-transform: scale(1.0); transform: scale(1.0); } }
+
+[class^='ui-icon-'].bounce:after,
+[class*=' ui-icon-'].bounce:after {
+ animation: bounce 1s infinite ease-in-out;
+ -moz-animation: bounce 1s infinite ease-in-out;
+ -ms-animation: bounce 1s infinite ease-in-out;
+ -webkit-animation: bounce 1s infinite ease-in-out;
+}
+
+
+/* rotated animations */
+@keyframes rotate {
+ from { -webkit-transform: rotate(0deg); -moz-transform: rotate(0deg); -ms-transform: rotate(0deg); transform: rotate(0deg); }
+ to { -webkit-transform: rotate(359deg); -moz-transform: rotate(359deg); -ms-transform: rotate(359deg); transform: rotate(359deg); }
+}
+@-moz-keyframes rotate { from { -moz-transform: rotate(0deg); transform: rotate(0deg); } to { -moz-transform: rotate(359deg); transform: rotate(359deg); } }
+@-ms-keyframes rotate { from { -ms-transform: rotate(0deg); transform: rotate(0deg); } to { -ms-transform: rotate(359deg); transform: rotate(359deg); } }
+@-webkit-keyframes rotate { from { -webkit-transform: rotate(0deg); transform: rotate(0deg); } to { -webkit-transform: rotate(359deg); transform: rotate(359deg); } }
+
+[class^='ui-icon-'].rotate, /* clockwise */
+[class*=' ui-icon-'].rotate, /* clockwise */
+[class^='ui-icon-'].rotate-reverse, /* anti clockwise */
+[class*=' ui-icon-'].rotate-reverse /* anti clockwise */ {
+ animation: rotate 1s infinite linear;
+ -moz-animation: rotate 1s infinite linear;
+ -ms-animation: rotate 1s infinite linear;
+ -webkit-animation: rotate 1s infinite linear;
+}
+[class^='ui-icon-'].rotate-reverse, /* anti clockwise */
+[class*=' ui-icon-'].rotate-reverse /* anti clockwise */ {
+ animation-direction: reverse;
+ -moz-animation-direction: reverse;
+ -ms-animation-direction: reverse;
+ -webkit-animation-direction: reverse;
+}
diff --git a/src/lib/vendor/jquery.smooth-scroll.js b/src/lib/vendor/jquery.smooth-scroll.js
new file mode 100644
index 0000000..e2d4fd6
--- /dev/null
+++ b/src/lib/vendor/jquery.smooth-scroll.js
@@ -0,0 +1,357 @@
+/*!
+ * jQuery Smooth Scroll - v2.2.0 - 2017-05-05
+ * https://github.com/kswedberg/jquery-smooth-scroll
+ * Copyright (c) 2017 Karl Swedberg
+ * Licensed MIT
+ */
+
+(function(factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['jquery'], factory);
+ } else if (typeof module === 'object' && module.exports) {
+ // CommonJS
+ factory(require('jquery'));
+ } else {
+ // Browser globals
+ factory(jQuery);
+ }
+}(function($) {
+
+ var version = '2.2.0';
+ var optionOverrides = {};
+ var defaults = {
+ exclude: [],
+ excludeWithin: [],
+ offset: 0,
+
+ // one of 'top' or 'left'
+ direction: 'top',
+
+ // if set, bind click events through delegation
+ // supported since jQuery 1.4.2
+ delegateSelector: null,
+
+ // jQuery set of elements you wish to scroll (for $.smoothScroll).
+ // if null (default), $('html, body').firstScrollable() is used.
+ scrollElement: null,
+
+ // only use if you want to override default behavior
+ scrollTarget: null,
+
+ // automatically focus the target element after scrolling to it
+ autoFocus: false,
+
+ // fn(opts) function to be called before scrolling occurs.
+ // `this` is the element(s) being scrolled
+ beforeScroll: function() {},
+
+ // fn(opts) function to be called after scrolling occurs.
+ // `this` is the triggering element
+ afterScroll: function() {},
+
+ // easing name. jQuery comes with "swing" and "linear." For others, you'll need an easing plugin
+ // from jQuery UI or elsewhere
+ easing: 'swing',
+
+ // speed can be a number or 'auto'
+ // if 'auto', the speed will be calculated based on the formula:
+ // (current scroll position - target scroll position) / autoCoeffic
+ speed: 400,
+
+ // coefficient for "auto" speed
+ autoCoefficient: 2,
+
+ // $.fn.smoothScroll only: whether to prevent the default click action
+ preventDefault: true
+ };
+
+ var getScrollable = function(opts) {
+ var scrollable = [];
+ var scrolled = false;
+ var dir = opts.dir && opts.dir === 'left' ? 'scrollLeft' : 'scrollTop';
+
+ this.each(function() {
+ var el = $(this);
+
+ if (this === document || this === window) {
+ return;
+ }
+
+ if (document.scrollingElement && (this === document.documentElement || this === document.body)) {
+ scrollable.push(document.scrollingElement);
+
+ return false;
+ }
+
+ if (el[dir]() > 0) {
+ scrollable.push(this);
+ } else {
+ // if scroll(Top|Left) === 0, nudge the element 1px and see if it moves
+ el[dir](1);
+ scrolled = el[dir]() > 0;
+
+ if (scrolled) {
+ scrollable.push(this);
+ }
+ // then put it back, of course
+ el[dir](0);
+ }
+ });
+
+ if (!scrollable.length) {
+ this.each(function() {
+ // If no scrollable elements and <html> has scroll-behavior:smooth because
+ // "When this property is specified on the root element, it applies to the viewport instead."
+ // and "The scroll-behavior property of the … body element is *not* propagated to the viewport."
+ // → https://drafts.csswg.org/cssom-view/#propdef-scroll-behavior
+ if (this === document.documentElement && $(this).css('scrollBehavior') === 'smooth') {
+ scrollable = [this];
+ }
+
+ // If still no scrollable elements, fall back to <body>,
+ // if it's in the jQuery collection
+ // (doing this because Safari sets scrollTop async,
+ // so can't set it to 1 and immediately get the value.)
+ if (!scrollable.length && this.nodeName === 'BODY') {
+ scrollable = [this];
+ }
+ });
+ }
+
+ // Use the first scrollable element if we're calling firstScrollable()
+ if (opts.el === 'first' && scrollable.length > 1) {
+ scrollable = [scrollable[0]];
+ }
+
+ return scrollable;
+ };
+
+ var rRelative = /^([\-\+]=)(\d+)/;
+
+ $.fn.extend({
+ scrollable: function(dir) {
+ var scrl = getScrollable.call(this, {dir: dir});
+
+ return this.pushStack(scrl);
+ },
+ firstScrollable: function(dir) {
+ var scrl = getScrollable.call(this, {el: 'first', dir: dir});
+
+ return this.pushStack(scrl);
+ },
+
+ smoothScroll: function(options, extra) {
+ options = options || {};
+
+ if (options === 'options') {
+ if (!extra) {
+ return this.first().data('ssOpts');
+ }
+
+ return this.each(function() {
+ var $this = $(this);
+ var opts = $.extend($this.data('ssOpts') || {}, extra);
+
+ $(this).data('ssOpts', opts);
+ });
+ }
+
+ var opts = $.extend({}, $.fn.smoothScroll.defaults, options);
+
+ var clickHandler = function(event) {
+ var escapeSelector = function(str) {
+ return str.replace(/(:|\.|\/)/g, '\\$1');
+ };
+
+ var link = this;
+ var $link = $(this);
+ var thisOpts = $.extend({}, opts, $link.data('ssOpts') || {});
+ var exclude = opts.exclude;
+ var excludeWithin = thisOpts.excludeWithin;
+ var elCounter = 0;
+ var ewlCounter = 0;
+ var include = true;
+ var clickOpts = {};
+ var locationPath = $.smoothScroll.filterPath(location.pathname);
+ var linkPath = $.smoothScroll.filterPath(link.pathname);
+ var hostMatch = location.hostname === link.hostname || !link.hostname;
+ var pathMatch = thisOpts.scrollTarget || (linkPath === locationPath);
+ var thisHash = escapeSelector(link.hash);
+
+ if (thisHash && !$(thisHash).length) {
+ include = false;
+ }
+
+ if (!thisOpts.scrollTarget && (!hostMatch || !pathMatch || !thisHash)) {
+ include = false;
+ } else {
+ while (include && elCounter < exclude.length) {
+ if ($link.is(escapeSelector(exclude[elCounter++]))) {
+ include = false;
+ }
+ }
+
+ while (include && ewlCounter < excludeWithin.length) {
+ if ($link.closest(excludeWithin[ewlCounter++]).length) {
+ include = false;
+ }
+ }
+ }
+
+ if (include) {
+ if (thisOpts.preventDefault) {
+ event.preventDefault();
+ }
+
+ $.extend(clickOpts, thisOpts, {
+ scrollTarget: thisOpts.scrollTarget || thisHash,
+ link: link
+ });
+
+ $.smoothScroll(clickOpts);
+ }
+ };
+
+ if (options.delegateSelector !== null) {
+ this
+ .off('click.smoothscroll', options.delegateSelector)
+ .on('click.smoothscroll', options.delegateSelector, clickHandler);
+ } else {
+ this
+ .off('click.smoothscroll')
+ .on('click.smoothscroll', clickHandler);
+ }
+
+ return this;
+ }
+ });
+
+ var getExplicitOffset = function(val) {
+ var explicit = {relative: ''};
+ var parts = typeof val === 'string' && rRelative.exec(val);
+
+ if (typeof val === 'number') {
+ explicit.px = val;
+ } else if (parts) {
+ explicit.relative = parts[1];
+ explicit.px = parseFloat(parts[2]) || 0;
+ }
+
+ return explicit;
+ };
+
+ var onAfterScroll = function(opts) {
+ var $tgt = $(opts.scrollTarget);
+
+ if (opts.autoFocus && $tgt.length) {
+ $tgt[0].focus();
+
+ if (!$tgt.is(document.activeElement)) {
+ $tgt.prop({tabIndex: -1});
+ $tgt[0].focus();
+ }
+ }
+
+ opts.afterScroll.call(opts.link, opts);
+ };
+
+ $.smoothScroll = function(options, px) {
+ if (options === 'options' && typeof px === 'object') {
+ return $.extend(optionOverrides, px);
+ }
+ var opts, $scroller, speed, delta;
+ var explicitOffset = getExplicitOffset(options);
+ var scrollTargetOffset = {};
+ var scrollerOffset = 0;
+ var offPos = 'offset';
+ var scrollDir = 'scrollTop';
+ var aniProps = {};
+ var aniOpts = {};
+
+ if (explicitOffset.px) {
+ opts = $.extend({link: null}, $.fn.smoothScroll.defaults, optionOverrides);
+ } else {
+ opts = $.extend({link: null}, $.fn.smoothScroll.defaults, options || {}, optionOverrides);
+
+ if (opts.scrollElement) {
+ offPos = 'position';
+
+ if (opts.scrollElement.css('position') === 'static') {
+ opts.scrollElement.css('position', 'relative');
+ }
+ }
+
+ if (px) {
+ explicitOffset = getExplicitOffset(px);
+ }
+ }
+
+ scrollDir = opts.direction === 'left' ? 'scrollLeft' : scrollDir;
+
+ if (opts.scrollElement) {
+ $scroller = opts.scrollElement;
+
+ if (!explicitOffset.px && !(/^(?:HTML|BODY)$/).test($scroller[0].nodeName)) {
+ scrollerOffset = $scroller[scrollDir]();
+ }
+ } else {
+ $scroller = $('html, body').firstScrollable(opts.direction);
+ }
+
+ // beforeScroll callback function must fire before calculating offset
+ opts.beforeScroll.call($scroller, opts);
+
+ scrollTargetOffset = explicitOffset.px ? explicitOffset : {
+ relative: '',
+ px: ($(opts.scrollTarget)[offPos]() && $(opts.scrollTarget)[offPos]()[opts.direction]) || 0
+ };
+
+ aniProps[scrollDir] = scrollTargetOffset.relative + (scrollTargetOffset.px + scrollerOffset + opts.offset);
+
+ speed = opts.speed;
+
+ // automatically calculate the speed of the scroll based on distance / coefficient
+ if (speed === 'auto') {
+
+ // $scroller[scrollDir]() is position before scroll, aniProps[scrollDir] is position after
+ // When delta is greater, speed will be greater.
+ delta = Math.abs(aniProps[scrollDir] - $scroller[scrollDir]());
+
+ // Divide the delta by the coefficient
+ speed = delta / opts.autoCoefficient;
+ }
+
+ aniOpts = {
+ duration: speed,
+ easing: opts.easing,
+ complete: function() {
+ onAfterScroll(opts);
+ }
+ };
+
+ if (opts.step) {
+ aniOpts.step = opts.step;
+ }
+
+ if ($scroller.length) {
+ $scroller.stop().animate(aniProps, aniOpts);
+ } else {
+ onAfterScroll(opts);
+ }
+ };
+
+ $.smoothScroll.version = version;
+ $.smoothScroll.filterPath = function(string) {
+ string = string || '';
+
+ return string
+ .replace(/^\//, '')
+ .replace(/(?:index|default).[a-zA-Z]{3,4}$/, '')
+ .replace(/\/$/, '');
+ };
+
+ // default options
+ $.fn.smoothScroll.defaults = defaults;
+
+}));
diff --git a/src/lib/vendor/punycode-1.4.1.js b/src/lib/vendor/punycode-1.4.1.js
new file mode 100644
index 0000000..2c87f6c
--- /dev/null
+++ b/src/lib/vendor/punycode-1.4.1.js
@@ -0,0 +1,533 @@
+/*! https://mths.be/punycode v1.4.1 by @mathias */
+;(function(root) {
+
+ /** Detect free variables */
+ var freeExports = typeof exports == 'object' && exports &&
+ !exports.nodeType && exports;
+ var freeModule = typeof module == 'object' && module &&
+ !module.nodeType && module;
+ var freeGlobal = typeof global == 'object' && global;
+ if (
+ freeGlobal.global === freeGlobal ||
+ freeGlobal.window === freeGlobal ||
+ freeGlobal.self === freeGlobal
+ ) {
+ root = freeGlobal;
+ }
+
+ /**
+ * The `punycode` object.
+ * @name punycode
+ * @type Object
+ */
+ var punycode,
+
+ /** Highest positive signed 32-bit float value */
+ maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
+
+ /** Bootstring parameters */
+ base = 36,
+ tMin = 1,
+ tMax = 26,
+ skew = 38,
+ damp = 700,
+ initialBias = 72,
+ initialN = 128, // 0x80
+ delimiter = '-', // '\x2D'
+
+ /** Regular expressions */
+ regexPunycode = /^xn--/,
+ regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars
+ regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators
+
+ /** Error messages */
+ errors = {
+ 'overflow': 'Overflow: input needs wider integers to process',
+ 'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
+ 'invalid-input': 'Invalid input'
+ },
+
+ /** Convenience shortcuts */
+ baseMinusTMin = base - tMin,
+ floor = Math.floor,
+ stringFromCharCode = String.fromCharCode,
+
+ /** Temporary variable */
+ key;
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
+ * A generic error utility function.
+ * @private
+ * @param {String} type The error type.
+ * @returns {Error} Throws a `RangeError` with the applicable error message.
+ */
+ function error(type) {
+ throw new RangeError(errors[type]);
+ }
+
+ /**
+ * A generic `Array#map` utility function.
+ * @private
+ * @param {Array} array The array to iterate over.
+ * @param {Function} callback The function that gets called for every array
+ * item.
+ * @returns {Array} A new array of values returned by the callback function.
+ */
+ function map(array, fn) {
+ var length = array.length;
+ var result = [];
+ while (length--) {
+ result[length] = fn(array[length]);
+ }
+ return result;
+ }
+
+ /**
+ * A simple `Array#map`-like wrapper to work with domain name strings or email
+ * addresses.
+ * @private
+ * @param {String} domain The domain name or email address.
+ * @param {Function} callback The function that gets called for every
+ * character.
+ * @returns {Array} A new string of characters returned by the callback
+ * function.
+ */
+ function mapDomain(string, fn) {
+ var parts = string.split('@');
+ var result = '';
+ if (parts.length > 1) {
+ // In email addresses, only the domain name should be punycoded. Leave
+ // the local part (i.e. everything up to `@`) intact.
+ result = parts[0] + '@';
+ string = parts[1];
+ }
+ // Avoid `split(regex)` for IE8 compatibility. See #17.
+ string = string.replace(regexSeparators, '\x2E');
+ var labels = string.split('.');
+ var encoded = map(labels, fn).join('.');
+ return result + encoded;
+ }
+
+ /**
+ * Creates an array containing the numeric code points of each Unicode
+ * character in the string. While JavaScript uses UCS-2 internally,
+ * this function will convert a pair of surrogate halves (each of which
+ * UCS-2 exposes as separate characters) into a single code point,
+ * matching UTF-16.
+ * @see `punycode.ucs2.encode`
+ * @see <https://mathiasbynens.be/notes/javascript-encoding>
+ * @memberOf punycode.ucs2
+ * @name decode
+ * @param {String} string The Unicode input string (UCS-2).
+ * @returns {Array} The new array of code points.
+ */
+ function ucs2decode(string) {
+ var output = [],
+ counter = 0,
+ length = string.length,
+ value,
+ extra;
+ while (counter < length) {
+ value = string.charCodeAt(counter++);
+ if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
+ // high surrogate, and there is a next character
+ extra = string.charCodeAt(counter++);
+ if ((extra & 0xFC00) == 0xDC00) { // low surrogate
+ output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
+ } else {
+ // unmatched surrogate; only append this code unit, in case the next
+ // code unit is the high surrogate of a surrogate pair
+ output.push(value);
+ counter--;
+ }
+ } else {
+ output.push(value);
+ }
+ }
+ return output;
+ }
+
+ /**
+ * Creates a string based on an array of numeric code points.
+ * @see `punycode.ucs2.decode`
+ * @memberOf punycode.ucs2
+ * @name encode
+ * @param {Array} codePoints The array of numeric code points.
+ * @returns {String} The new Unicode string (UCS-2).
+ */
+ function ucs2encode(array) {
+ return map(array, function(value) {
+ var output = '';
+ if (value > 0xFFFF) {
+ value -= 0x10000;
+ output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
+ value = 0xDC00 | value & 0x3FF;
+ }
+ output += stringFromCharCode(value);
+ return output;
+ }).join('');
+ }
+
+ /**
+ * Converts a basic code point into a digit/integer.
+ * @see `digitToBasic()`
+ * @private
+ * @param {Number} codePoint The basic numeric code point value.
+ * @returns {Number} The numeric value of a basic code point (for use in
+ * representing integers) in the range `0` to `base - 1`, or `base` if
+ * the code point does not represent a value.
+ */
+ function basicToDigit(codePoint) {
+ if (codePoint - 48 < 10) {
+ return codePoint - 22;
+ }
+ if (codePoint - 65 < 26) {
+ return codePoint - 65;
+ }
+ if (codePoint - 97 < 26) {
+ return codePoint - 97;
+ }
+ return base;
+ }
+
+ /**
+ * Converts a digit/integer into a basic code point.
+ * @see `basicToDigit()`
+ * @private
+ * @param {Number} digit The numeric value of a basic code point.
+ * @returns {Number} The basic code point whose value (when used for
+ * representing integers) is `digit`, which needs to be in the range
+ * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
+ * used; else, the lowercase form is used. The behavior is undefined
+ * if `flag` is non-zero and `digit` has no uppercase form.
+ */
+ function digitToBasic(digit, flag) {
+ // 0..25 map to ASCII a..z or A..Z
+ // 26..35 map to ASCII 0..9
+ return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
+ }
+
+ /**
+ * Bias adaptation function as per section 3.4 of RFC 3492.
+ * https://tools.ietf.org/html/rfc3492#section-3.4
+ * @private
+ */
+ function adapt(delta, numPoints, firstTime) {
+ var k = 0;
+ delta = firstTime ? floor(delta / damp) : delta >> 1;
+ delta += floor(delta / numPoints);
+ for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
+ delta = floor(delta / baseMinusTMin);
+ }
+ return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
+ }
+
+ /**
+ * Converts a Punycode string of ASCII-only symbols to a string of Unicode
+ * symbols.
+ * @memberOf punycode
+ * @param {String} input The Punycode string of ASCII-only symbols.
+ * @returns {String} The resulting string of Unicode symbols.
+ */
+ function decode(input) {
+ // Don't use UCS-2
+ var output = [],
+ inputLength = input.length,
+ out,
+ i = 0,
+ n = initialN,
+ bias = initialBias,
+ basic,
+ j,
+ index,
+ oldi,
+ w,
+ k,
+ digit,
+ t,
+ /** Cached calculation results */
+ baseMinusT;
+
+ // Handle the basic code points: let `basic` be the number of input code
+ // points before the last delimiter, or `0` if there is none, then copy
+ // the first basic code points to the output.
+
+ basic = input.lastIndexOf(delimiter);
+ if (basic < 0) {
+ basic = 0;
+ }
+
+ for (j = 0; j < basic; ++j) {
+ // if it's not a basic code point
+ if (input.charCodeAt(j) >= 0x80) {
+ error('not-basic');
+ }
+ output.push(input.charCodeAt(j));
+ }
+
+ // Main decoding loop: start just after the last delimiter if any basic code
+ // points were copied; start at the beginning otherwise.
+
+ for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
+
+ // `index` is the index of the next character to be consumed.
+ // Decode a generalized variable-length integer into `delta`,
+ // which gets added to `i`. The overflow checking is easier
+ // if we increase `i` as we go, then subtract off its starting
+ // value at the end to obtain `delta`.
+ for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
+
+ if (index >= inputLength) {
+ error('invalid-input');
+ }
+
+ digit = basicToDigit(input.charCodeAt(index++));
+
+ if (digit >= base || digit > floor((maxInt - i) / w)) {
+ error('overflow');
+ }
+
+ i += digit * w;
+ t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+
+ if (digit < t) {
+ break;
+ }
+
+ baseMinusT = base - t;
+ if (w > floor(maxInt / baseMinusT)) {
+ error('overflow');
+ }
+
+ w *= baseMinusT;
+
+ }
+
+ out = output.length + 1;
+ bias = adapt(i - oldi, out, oldi == 0);
+
+ // `i` was supposed to wrap around from `out` to `0`,
+ // incrementing `n` each time, so we'll fix that now:
+ if (floor(i / out) > maxInt - n) {
+ error('overflow');
+ }
+
+ n += floor(i / out);
+ i %= out;
+
+ // Insert `n` at position `i` of the output
+ output.splice(i++, 0, n);
+
+ }
+
+ return ucs2encode(output);
+ }
+
+ /**
+ * Converts a string of Unicode symbols (e.g. a domain name label) to a
+ * Punycode string of ASCII-only symbols.
+ * @memberOf punycode
+ * @param {String} input The string of Unicode symbols.
+ * @returns {String} The resulting Punycode string of ASCII-only symbols.
+ */
+ function encode(input) {
+ var n,
+ delta,
+ handledCPCount,
+ basicLength,
+ bias,
+ j,
+ m,
+ q,
+ k,
+ t,
+ currentValue,
+ output = [],
+ /** `inputLength` will hold the number of code points in `input`. */
+ inputLength,
+ /** Cached calculation results */
+ handledCPCountPlusOne,
+ baseMinusT,
+ qMinusT;
+
+ // Convert the input in UCS-2 to Unicode
+ input = ucs2decode(input);
+
+ // Cache the length
+ inputLength = input.length;
+
+ // Initialize the state
+ n = initialN;
+ delta = 0;
+ bias = initialBias;
+
+ // Handle the basic code points
+ for (j = 0; j < inputLength; ++j) {
+ currentValue = input[j];
+ if (currentValue < 0x80) {
+ output.push(stringFromCharCode(currentValue));
+ }
+ }
+
+ handledCPCount = basicLength = output.length;
+
+ // `handledCPCount` is the number of code points that have been handled;
+ // `basicLength` is the number of basic code points.
+
+ // Finish the basic string - if it is not empty - with a delimiter
+ if (basicLength) {
+ output.push(delimiter);
+ }
+
+ // Main encoding loop:
+ while (handledCPCount < inputLength) {
+
+ // All non-basic code points < n have been handled already. Find the next
+ // larger one:
+ for (m = maxInt, j = 0; j < inputLength; ++j) {
+ currentValue = input[j];
+ if (currentValue >= n && currentValue < m) {
+ m = currentValue;
+ }
+ }
+
+ // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
+ // but guard against overflow
+ handledCPCountPlusOne = handledCPCount + 1;
+ if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
+ error('overflow');
+ }
+
+ delta += (m - n) * handledCPCountPlusOne;
+ n = m;
+
+ for (j = 0; j < inputLength; ++j) {
+ currentValue = input[j];
+
+ if (currentValue < n && ++delta > maxInt) {
+ error('overflow');
+ }
+
+ if (currentValue == n) {
+ // Represent delta as a generalized variable-length integer
+ for (q = delta, k = base; /* no condition */; k += base) {
+ t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+ if (q < t) {
+ break;
+ }
+ qMinusT = q - t;
+ baseMinusT = base - t;
+ output.push(
+ stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
+ );
+ q = floor(qMinusT / baseMinusT);
+ }
+
+ output.push(stringFromCharCode(digitToBasic(q, 0)));
+ bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
+ delta = 0;
+ ++handledCPCount;
+ }
+ }
+
+ ++delta;
+ ++n;
+
+ }
+ return output.join('');
+ }
+
+ /**
+ * Converts a Punycode string representing a domain name or an email address
+ * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
+ * it doesn't matter if you call it on a string that has already been
+ * converted to Unicode.
+ * @memberOf punycode
+ * @param {String} input The Punycoded domain name or email address to
+ * convert to Unicode.
+ * @returns {String} The Unicode representation of the given Punycode
+ * string.
+ */
+ function toUnicode(input) {
+ return mapDomain(input, function(string) {
+ return regexPunycode.test(string)
+ ? decode(string.slice(4).toLowerCase())
+ : string;
+ });
+ }
+
+ /**
+ * Converts a Unicode string representing a domain name or an email address to
+ * Punycode. Only the non-ASCII parts of the domain name will be converted,
+ * i.e. it doesn't matter if you call it with a domain that's already in
+ * ASCII.
+ * @memberOf punycode
+ * @param {String} input The domain name or email address to convert, as a
+ * Unicode string.
+ * @returns {String} The Punycode representation of the given domain name or
+ * email address.
+ */
+ function toASCII(input) {
+ return mapDomain(input, function(string) {
+ return regexNonASCII.test(string)
+ ? 'xn--' + encode(string)
+ : string;
+ });
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /** Define the public API */
+ punycode = {
+ /**
+ * A string representing the current Punycode.js version number.
+ * @memberOf punycode
+ * @type String
+ */
+ 'version': '1.4.1',
+ /**
+ * An object of methods to convert from JavaScript's internal character
+ * representation (UCS-2) to Unicode code points, and back.
+ * @see <https://mathiasbynens.be/notes/javascript-encoding>
+ * @memberOf punycode
+ * @type Object
+ */
+ 'ucs2': {
+ 'decode': ucs2decode,
+ 'encode': ucs2encode
+ },
+ 'decode': decode,
+ 'encode': encode,
+ 'toASCII': toASCII,
+ 'toUnicode': toUnicode
+ };
+
+ /** Expose `punycode` */
+ // Some AMD build optimizers, like r.js, check for specific condition patterns
+ // like the following:
+ if (
+ typeof define == 'function' &&
+ typeof define.amd == 'object' &&
+ define.amd
+ ) {
+ define('punycode', function() {
+ return punycode;
+ });
+ } else if (freeExports && freeModule) {
+ if (module.exports == freeExports) {
+ // in Node.js, io.js, or RingoJS v0.8.0+
+ freeModule.exports = punycode;
+ } else {
+ // in Narwhal or RingoJS v0.7.0-
+ for (key in punycode) {
+ punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
+ }
+ }
+ } else {
+ // in Rhino or a web browser
+ root.punycode = punycode;
+ }
+
+}(this));
diff --git a/src/lib/vendor/select2-4.0.11/select2-4.0.11.css b/src/lib/vendor/select2-4.0.11/select2-4.0.11.css
new file mode 100644
index 0000000..750b320
--- /dev/null
+++ b/src/lib/vendor/select2-4.0.11/select2-4.0.11.css
@@ -0,0 +1,481 @@
+.select2-container {
+ box-sizing: border-box;
+ display: inline-block;
+ margin: 0;
+ position: relative;
+ vertical-align: middle; }
+ .select2-container .select2-selection--single {
+ box-sizing: border-box;
+ cursor: pointer;
+ display: block;
+ height: 28px;
+ user-select: none;
+ -webkit-user-select: none; }
+ .select2-container .select2-selection--single .select2-selection__rendered {
+ display: block;
+ padding-left: 8px;
+ padding-right: 20px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap; }
+ .select2-container .select2-selection--single .select2-selection__clear {
+ position: relative; }
+ .select2-container[dir="rtl"] .select2-selection--single .select2-selection__rendered {
+ padding-right: 8px;
+ padding-left: 20px; }
+ .select2-container .select2-selection--multiple {
+ box-sizing: border-box;
+ cursor: pointer;
+ display: block;
+ min-height: 32px;
+ user-select: none;
+ -webkit-user-select: none; }
+ .select2-container .select2-selection--multiple .select2-selection__rendered {
+ display: inline-block;
+ overflow: hidden;
+ padding-left: 8px;
+ text-overflow: ellipsis;
+ white-space: nowrap; }
+ .select2-container .select2-search--inline {
+ float: left; }
+ .select2-container .select2-search--inline .select2-search__field {
+ box-sizing: border-box;
+ border: none;
+ font-size: 100%;
+ margin-top: 5px;
+ padding: 0; }
+ .select2-container .select2-search--inline .select2-search__field::-webkit-search-cancel-button {
+ -webkit-appearance: none; }
+
+.select2-dropdown {
+ background-color: white;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ box-sizing: border-box;
+ display: block;
+ position: absolute;
+ left: -100000px;
+ width: 100%;
+ z-index: 1051; }
+
+.select2-results {
+ display: block; }
+
+.select2-results__options {
+ list-style: none;
+ margin: 0;
+ padding: 0; }
+
+.select2-results__option {
+ padding: 6px;
+ user-select: none;
+ -webkit-user-select: none; }
+ .select2-results__option[aria-selected] {
+ cursor: pointer; }
+
+.select2-container--open .select2-dropdown {
+ left: 0; }
+
+.select2-container--open .select2-dropdown--above {
+ border-bottom: none;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0; }
+
+.select2-container--open .select2-dropdown--below {
+ border-top: none;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0; }
+
+.select2-search--dropdown {
+ display: block;
+ padding: 4px; }
+ .select2-search--dropdown .select2-search__field {
+ padding: 4px;
+ width: 100%;
+ box-sizing: border-box; }
+ .select2-search--dropdown .select2-search__field::-webkit-search-cancel-button {
+ -webkit-appearance: none; }
+ .select2-search--dropdown.select2-search--hide {
+ display: none; }
+
+.select2-close-mask {
+ border: 0;
+ margin: 0;
+ padding: 0;
+ display: block;
+ position: fixed;
+ left: 0;
+ top: 0;
+ min-height: 100%;
+ min-width: 100%;
+ height: auto;
+ width: auto;
+ opacity: 0;
+ z-index: 99;
+ background-color: #fff;
+ filter: alpha(opacity=0); }
+
+.select2-hidden-accessible {
+ border: 0 !important;
+ clip: rect(0 0 0 0) !important;
+ -webkit-clip-path: inset(50%) !important;
+ clip-path: inset(50%) !important;
+ height: 1px !important;
+ overflow: hidden !important;
+ padding: 0 !important;
+ position: absolute !important;
+ width: 1px !important;
+ white-space: nowrap !important; }
+
+.select2-container--default .select2-selection--single {
+ background-color: #fff;
+ border: 1px solid #aaa;
+ border-radius: 4px; }
+ .select2-container--default .select2-selection--single .select2-selection__rendered {
+ color: #444;
+ line-height: 28px; }
+ .select2-container--default .select2-selection--single .select2-selection__clear {
+ cursor: pointer;
+ float: right;
+ font-weight: bold; }
+ .select2-container--default .select2-selection--single .select2-selection__placeholder {
+ color: #999; }
+ .select2-container--default .select2-selection--single .select2-selection__arrow {
+ height: 26px;
+ position: absolute;
+ top: 1px;
+ right: 1px;
+ width: 20px; }
+ .select2-container--default .select2-selection--single .select2-selection__arrow b {
+ border-color: #888 transparent transparent transparent;
+ border-style: solid;
+ border-width: 5px 4px 0 4px;
+ height: 0;
+ left: 50%;
+ margin-left: -4px;
+ margin-top: -2px;
+ position: absolute;
+ top: 50%;
+ width: 0; }
+
+.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__clear {
+ float: left; }
+
+.select2-container--default[dir="rtl"] .select2-selection--single .select2-selection__arrow {
+ left: 1px;
+ right: auto; }
+
+.select2-container--default.select2-container--disabled .select2-selection--single {
+ background-color: #eee;
+ cursor: default; }
+ .select2-container--default.select2-container--disabled .select2-selection--single .select2-selection__clear {
+ display: none; }
+
+.select2-container--default.select2-container--open .select2-selection--single .select2-selection__arrow b {
+ border-color: transparent transparent #888 transparent;
+ border-width: 0 4px 5px 4px; }
+
+.select2-container--default .select2-selection--multiple {
+ background-color: white;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: text; }
+ .select2-container--default .select2-selection--multiple .select2-selection__rendered {
+ box-sizing: border-box;
+ list-style: none;
+ margin: 0;
+ padding: 0 5px;
+ width: 100%; }
+ .select2-container--default .select2-selection--multiple .select2-selection__rendered li {
+ list-style: none; }
+ .select2-container--default .select2-selection--multiple .select2-selection__clear {
+ cursor: pointer;
+ float: right;
+ font-weight: bold;
+ margin-top: 5px;
+ margin-right: 10px;
+ padding: 1px; }
+ .select2-container--default .select2-selection--multiple .select2-selection__choice {
+ background-color: #e4e4e4;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: default;
+ float: left;
+ margin-right: 5px;
+ margin-top: 5px;
+ padding: 0 5px; }
+ .select2-container--default .select2-selection--multiple .select2-selection__choice__remove {
+ color: #999;
+ cursor: pointer;
+ display: inline-block;
+ font-weight: bold;
+ margin-right: 2px; }
+ .select2-container--default .select2-selection--multiple .select2-selection__choice__remove:hover {
+ color: #333; }
+
+.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice, .select2-container--default[dir="rtl"] .select2-selection--multiple .select2-search--inline {
+ float: right; }
+
+.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
+ margin-left: 5px;
+ margin-right: auto; }
+
+.select2-container--default[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
+ margin-left: 2px;
+ margin-right: auto; }
+
+.select2-container--default.select2-container--focus .select2-selection--multiple {
+ border: solid black 1px;
+ outline: 0; }
+
+.select2-container--default.select2-container--disabled .select2-selection--multiple {
+ background-color: #eee;
+ cursor: default; }
+
+.select2-container--default.select2-container--disabled .select2-selection__choice__remove {
+ display: none; }
+
+.select2-container--default.select2-container--open.select2-container--above .select2-selection--single, .select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
+ border-top-left-radius: 0;
+ border-top-right-radius: 0; }
+
+.select2-container--default.select2-container--open.select2-container--below .select2-selection--single, .select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0; }
+
+.select2-container--default .select2-search--dropdown .select2-search__field {
+ border: 1px solid #aaa; }
+
+.select2-container--default .select2-search--inline .select2-search__field {
+ background: transparent;
+ border: none;
+ outline: 0;
+ box-shadow: none;
+ -webkit-appearance: textfield; }
+
+.select2-container--default .select2-results > .select2-results__options {
+ max-height: 200px;
+ overflow-y: auto; }
+
+.select2-container--default .select2-results__option[role=group] {
+ padding: 0; }
+
+.select2-container--default .select2-results__option[aria-disabled=true] {
+ color: #999; }
+
+.select2-container--default .select2-results__option[aria-selected=true] {
+ background-color: #ddd; }
+
+.select2-container--default .select2-results__option .select2-results__option {
+ padding-left: 1em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__group {
+ padding-left: 0; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -1em;
+ padding-left: 2em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -2em;
+ padding-left: 3em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -3em;
+ padding-left: 4em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -4em;
+ padding-left: 5em; }
+ .select2-container--default .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option .select2-results__option {
+ margin-left: -5em;
+ padding-left: 6em; }
+
+.select2-container--default .select2-results__option--highlighted[aria-selected] {
+ background-color: #5897fb;
+ color: white; }
+
+.select2-container--default .select2-results__group {
+ cursor: default;
+ display: block;
+ padding: 6px; }
+
+.select2-container--classic .select2-selection--single {
+ background-color: #f7f7f7;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ outline: 0;
+ background-image: -webkit-linear-gradient(top, white 50%, #eeeeee 100%);
+ background-image: -o-linear-gradient(top, white 50%, #eeeeee 100%);
+ background-image: linear-gradient(to bottom, white 50%, #eeeeee 100%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
+ .select2-container--classic .select2-selection--single:focus {
+ border: 1px solid #5897fb; }
+ .select2-container--classic .select2-selection--single .select2-selection__rendered {
+ color: #444;
+ line-height: 28px; }
+ .select2-container--classic .select2-selection--single .select2-selection__clear {
+ cursor: pointer;
+ float: right;
+ font-weight: bold;
+ margin-right: 10px; }
+ .select2-container--classic .select2-selection--single .select2-selection__placeholder {
+ color: #999; }
+ .select2-container--classic .select2-selection--single .select2-selection__arrow {
+ background-color: #ddd;
+ border: none;
+ border-left: 1px solid #aaa;
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ height: 26px;
+ position: absolute;
+ top: 1px;
+ right: 1px;
+ width: 20px;
+ background-image: -webkit-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
+ background-image: -o-linear-gradient(top, #eeeeee 50%, #cccccc 100%);
+ background-image: linear-gradient(to bottom, #eeeeee 50%, #cccccc 100%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFCCCCCC', GradientType=0); }
+ .select2-container--classic .select2-selection--single .select2-selection__arrow b {
+ border-color: #888 transparent transparent transparent;
+ border-style: solid;
+ border-width: 5px 4px 0 4px;
+ height: 0;
+ left: 50%;
+ margin-left: -4px;
+ margin-top: -2px;
+ position: absolute;
+ top: 50%;
+ width: 0; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__clear {
+ float: left; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--single .select2-selection__arrow {
+ border: none;
+ border-right: 1px solid #aaa;
+ border-radius: 0;
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+ left: 1px;
+ right: auto; }
+
+.select2-container--classic.select2-container--open .select2-selection--single {
+ border: 1px solid #5897fb; }
+ .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow {
+ background: transparent;
+ border: none; }
+ .select2-container--classic.select2-container--open .select2-selection--single .select2-selection__arrow b {
+ border-color: transparent transparent #888 transparent;
+ border-width: 0 4px 5px 4px; }
+
+.select2-container--classic.select2-container--open.select2-container--above .select2-selection--single {
+ border-top: none;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0;
+ background-image: -webkit-linear-gradient(top, white 0%, #eeeeee 50%);
+ background-image: -o-linear-gradient(top, white 0%, #eeeeee 50%);
+ background-image: linear-gradient(to bottom, white 0%, #eeeeee 50%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFFFF', endColorstr='#FFEEEEEE', GradientType=0); }
+
+.select2-container--classic.select2-container--open.select2-container--below .select2-selection--single {
+ border-bottom: none;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+ background-image: -webkit-linear-gradient(top, #eeeeee 50%, white 100%);
+ background-image: -o-linear-gradient(top, #eeeeee 50%, white 100%);
+ background-image: linear-gradient(to bottom, #eeeeee 50%, white 100%);
+ background-repeat: repeat-x;
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFEEEEEE', endColorstr='#FFFFFFFF', GradientType=0); }
+
+.select2-container--classic .select2-selection--multiple {
+ background-color: white;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: text;
+ outline: 0; }
+ .select2-container--classic .select2-selection--multiple:focus {
+ border: 1px solid #5897fb; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__rendered {
+ list-style: none;
+ margin: 0;
+ padding: 0 5px; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__clear {
+ display: none; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__choice {
+ background-color: #e4e4e4;
+ border: 1px solid #aaa;
+ border-radius: 4px;
+ cursor: default;
+ float: left;
+ margin-right: 5px;
+ margin-top: 5px;
+ padding: 0 5px; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove {
+ color: #888;
+ cursor: pointer;
+ display: inline-block;
+ font-weight: bold;
+ margin-right: 2px; }
+ .select2-container--classic .select2-selection--multiple .select2-selection__choice__remove:hover {
+ color: #555; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice {
+ float: right;
+ margin-left: 5px;
+ margin-right: auto; }
+
+.select2-container--classic[dir="rtl"] .select2-selection--multiple .select2-selection__choice__remove {
+ margin-left: 2px;
+ margin-right: auto; }
+
+.select2-container--classic.select2-container--open .select2-selection--multiple {
+ border: 1px solid #5897fb; }
+
+.select2-container--classic.select2-container--open.select2-container--above .select2-selection--multiple {
+ border-top: none;
+ border-top-left-radius: 0;
+ border-top-right-radius: 0; }
+
+.select2-container--classic.select2-container--open.select2-container--below .select2-selection--multiple {
+ border-bottom: none;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0; }
+
+.select2-container--classic .select2-search--dropdown .select2-search__field {
+ border: 1px solid #aaa;
+ outline: 0; }
+
+.select2-container--classic .select2-search--inline .select2-search__field {
+ outline: 0;
+ box-shadow: none; }
+
+.select2-container--classic .select2-dropdown {
+ background-color: white;
+ border: 1px solid transparent; }
+
+.select2-container--classic .select2-dropdown--above {
+ border-bottom: none; }
+
+.select2-container--classic .select2-dropdown--below {
+ border-top: none; }
+
+.select2-container--classic .select2-results > .select2-results__options {
+ max-height: 200px;
+ overflow-y: auto; }
+
+.select2-container--classic .select2-results__option[role=group] {
+ padding: 0; }
+
+.select2-container--classic .select2-results__option[aria-disabled=true] {
+ color: grey; }
+
+.select2-container--classic .select2-results__option--highlighted[aria-selected] {
+ background-color: #3875d7;
+ color: white; }
+
+.select2-container--classic .select2-results__group {
+ cursor: default;
+ display: block;
+ padding: 6px; }
+
+.select2-container--classic.select2-container--open .select2-dropdown {
+ border-color: #5897fb; }
diff --git a/src/lib/vendor/select2-4.0.11/select2-4.0.11.js b/src/lib/vendor/select2-4.0.11/select2-4.0.11.js
new file mode 100644
index 0000000..6da089a
--- /dev/null
+++ b/src/lib/vendor/select2-4.0.11/select2-4.0.11.js
@@ -0,0 +1,6044 @@
+/*!
+ * Select2 4.0.11
+ * https://select2.github.io
+ *
+ * Released under the MIT license
+ * https://github.com/select2/select2/blob/master/LICENSE.md
+ */
+;(function (factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module.
+ define(['jquery'], factory);
+ } else if (typeof module === 'object' && module.exports) {
+ // Node/CommonJS
+ module.exports = function (root, jQuery) {
+ if (jQuery === undefined) {
+ // require('jQuery') returns a factory that requires window to
+ // build a jQuery instance, we normalize how we use modules
+ // that require this pattern but the window provided is a noop
+ // if it's defined (how jquery works)
+ if (typeof window !== 'undefined') {
+ jQuery = require('jquery');
+ }
+ else {
+ jQuery = require('jquery')(root);
+ }
+ }
+ factory(jQuery);
+ return jQuery;
+ };
+ } else {
+ // Browser globals
+ factory(jQuery);
+ }
+} (function (jQuery) {
+ // This is needed so we can catch the AMD loader configuration and use it
+ // The inner file should be wrapped (by `banner.start.js`) in a function that
+ // returns the AMD loader references.
+ var S2 =(function () {
+ // Restore the Select2 AMD loader so it can be used
+ // Needed mostly in the language files, where the loader is not inserted
+ if (jQuery && jQuery.fn && jQuery.fn.select2 && jQuery.fn.select2.amd) {
+ var S2 = jQuery.fn.select2.amd;
+ }
+var S2;(function () { if (!S2 || !S2.requirejs) {
+if (!S2) { S2 = {}; } else { require = S2; }
+/**
+ * @license almond 0.3.3 Copyright jQuery Foundation and other contributors.
+ * Released under MIT license, http://github.com/requirejs/almond/LICENSE
+ */
+//Going sloppy to avoid 'use strict' string cost, but strict practices should
+//be followed.
+/*global setTimeout: false */
+
+var requirejs, require, define;
+(function (undef) {
+ var main, req, makeMap, handlers,
+ defined = {},
+ waiting = {},
+ config = {},
+ defining = {},
+ hasOwn = Object.prototype.hasOwnProperty,
+ aps = [].slice,
+ jsSuffixRegExp = /\.js$/;
+
+ function hasProp(obj, prop) {
+ return hasOwn.call(obj, prop);
+ }
+
+ /**
+ * Given a relative module name, like ./something, normalize it to
+ * a real name that can be mapped to a path.
+ * @param {String} name the relative name
+ * @param {String} baseName a real name that the name arg is relative
+ * to.
+ * @returns {String} normalized name
+ */
+ function normalize(name, baseName) {
+ var nameParts, nameSegment, mapValue, foundMap, lastIndex,
+ foundI, foundStarMap, starI, i, j, part, normalizedBaseParts,
+ baseParts = baseName && baseName.split("/"),
+ map = config.map,
+ starMap = (map && map['*']) || {};
+
+ //Adjust any relative paths.
+ if (name) {
+ name = name.split('/');
+ lastIndex = name.length - 1;
+
+ // If wanting node ID compatibility, strip .js from end
+ // of IDs. Have to do this here, and not in nameToUrl
+ // because node allows either .js or non .js to map
+ // to same file.
+ if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
+ name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
+ }
+
+ // Starts with a '.' so need the baseName
+ if (name[0].charAt(0) === '.' && baseParts) {
+ //Convert baseName to array, and lop off the last part,
+ //so that . matches that 'directory' and not name of the baseName's
+ //module. For instance, baseName of 'one/two/three', maps to
+ //'one/two/three.js', but we want the directory, 'one/two' for
+ //this normalization.
+ normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
+ name = normalizedBaseParts.concat(name);
+ }
+
+ //start trimDots
+ for (i = 0; i < name.length; i++) {
+ part = name[i];
+ if (part === '.') {
+ name.splice(i, 1);
+ i -= 1;
+ } else if (part === '..') {
+ // If at the start, or previous value is still ..,
+ // keep them so that when converted to a path it may
+ // still work when converted to a path, even though
+ // as an ID it is less than ideal. In larger point
+ // releases, may be better to just kick out an error.
+ if (i === 0 || (i === 1 && name[2] === '..') || name[i - 1] === '..') {
+ continue;
+ } else if (i > 0) {
+ name.splice(i - 1, 2);
+ i -= 2;
+ }
+ }
+ }
+ //end trimDots
+
+ name = name.join('/');
+ }
+
+ //Apply map config if available.
+ if ((baseParts || starMap) && map) {
+ nameParts = name.split('/');
+
+ for (i = nameParts.length; i > 0; i -= 1) {
+ nameSegment = nameParts.slice(0, i).join("/");
+
+ if (baseParts) {
+ //Find the longest baseName segment match in the config.
+ //So, do joins on the biggest to smallest lengths of baseParts.
+ for (j = baseParts.length; j > 0; j -= 1) {
+ mapValue = map[baseParts.slice(0, j).join('/')];
+
+ //baseName segment has config, find if it has one for
+ //this name.
+ if (mapValue) {
+ mapValue = mapValue[nameSegment];
+ if (mapValue) {
+ //Match, update name to the new value.
+ foundMap = mapValue;
+ foundI = i;
+ break;
+ }
+ }
+ }
+ }
+
+ if (foundMap) {
+ break;
+ }
+
+ //Check for a star map match, but just hold on to it,
+ //if there is a shorter segment match later in a matching
+ //config, then favor over this star map.
+ if (!foundStarMap && starMap && starMap[nameSegment]) {
+ foundStarMap = starMap[nameSegment];
+ starI = i;
+ }
+ }
+
+ if (!foundMap && foundStarMap) {
+ foundMap = foundStarMap;
+ foundI = starI;
+ }
+
+ if (foundMap) {
+ nameParts.splice(0, foundI, foundMap);
+ name = nameParts.join('/');
+ }
+ }
+
+ return name;
+ }
+
+ function makeRequire(relName, forceSync) {
+ return function () {
+ //A version of a require function that passes a moduleName
+ //value for items that may need to
+ //look up paths relative to the moduleName
+ var args = aps.call(arguments, 0);
+
+ //If first arg is not require('string'), and there is only
+ //one arg, it is the array form without a callback. Insert
+ //a null so that the following concat is correct.
+ if (typeof args[0] !== 'string' && args.length === 1) {
+ args.push(null);
+ }
+ return req.apply(undef, args.concat([relName, forceSync]));
+ };
+ }
+
+ function makeNormalize(relName) {
+ return function (name) {
+ return normalize(name, relName);
+ };
+ }
+
+ function makeLoad(depName) {
+ return function (value) {
+ defined[depName] = value;
+ };
+ }
+
+ function callDep(name) {
+ if (hasProp(waiting, name)) {
+ var args = waiting[name];
+ delete waiting[name];
+ defining[name] = true;
+ main.apply(undef, args);
+ }
+
+ if (!hasProp(defined, name) && !hasProp(defining, name)) {
+ throw new Error('No ' + name);
+ }
+ return defined[name];
+ }
+
+ //Turns a plugin!resource to [plugin, resource]
+ //with the plugin being undefined if the name
+ //did not have a plugin prefix.
+ function splitPrefix(name) {
+ var prefix,
+ index = name ? name.indexOf('!') : -1;
+ if (index > -1) {
+ prefix = name.substring(0, index);
+ name = name.substring(index + 1, name.length);
+ }
+ return [prefix, name];
+ }
+
+ //Creates a parts array for a relName where first part is plugin ID,
+ //second part is resource ID. Assumes relName has already been normalized.
+ function makeRelParts(relName) {
+ return relName ? splitPrefix(relName) : [];
+ }
+
+ /**
+ * Makes a name map, normalizing the name, and using a plugin
+ * for normalization if necessary. Grabs a ref to plugin
+ * too, as an optimization.
+ */
+ makeMap = function (name, relParts) {
+ var plugin,
+ parts = splitPrefix(name),
+ prefix = parts[0],
+ relResourceName = relParts[1];
+
+ name = parts[1];
+
+ if (prefix) {
+ prefix = normalize(prefix, relResourceName);
+ plugin = callDep(prefix);
+ }
+
+ //Normalize according
+ if (prefix) {
+ if (plugin && plugin.normalize) {
+ name = plugin.normalize(name, makeNormalize(relResourceName));
+ } else {
+ name = normalize(name, relResourceName);
+ }
+ } else {
+ name = normalize(name, relResourceName);
+ parts = splitPrefix(name);
+ prefix = parts[0];
+ name = parts[1];
+ if (prefix) {
+ plugin = callDep(prefix);
+ }
+ }
+
+ //Using ridiculous property names for space reasons
+ return {
+ f: prefix ? prefix + '!' + name : name, //fullName
+ n: name,
+ pr: prefix,
+ p: plugin
+ };
+ };
+
+ function makeConfig(name) {
+ return function () {
+ return (config && config.config && config.config[name]) || {};
+ };
+ }
+
+ handlers = {
+ require: function (name) {
+ return makeRequire(name);
+ },
+ exports: function (name) {
+ var e = defined[name];
+ if (typeof e !== 'undefined') {
+ return e;
+ } else {
+ return (defined[name] = {});
+ }
+ },
+ module: function (name) {
+ return {
+ id: name,
+ uri: '',
+ exports: defined[name],
+ config: makeConfig(name)
+ };
+ }
+ };
+
+ main = function (name, deps, callback, relName) {
+ var cjsModule, depName, ret, map, i, relParts,
+ args = [],
+ callbackType = typeof callback,
+ usingExports;
+
+ //Use name if no relName
+ relName = relName || name;
+ relParts = makeRelParts(relName);
+
+ //Call the callback to define the module, if necessary.
+ if (callbackType === 'undefined' || callbackType === 'function') {
+ //Pull out the defined dependencies and pass the ordered
+ //values to the callback.
+ //Default to [require, exports, module] if no deps
+ deps = !deps.length && callback.length ? ['require', 'exports', 'module'] : deps;
+ for (i = 0; i < deps.length; i += 1) {
+ map = makeMap(deps[i], relParts);
+ depName = map.f;
+
+ //Fast path CommonJS standard dependencies.
+ if (depName === "require") {
+ args[i] = handlers.require(name);
+ } else if (depName === "exports") {
+ //CommonJS module spec 1.1
+ args[i] = handlers.exports(name);
+ usingExports = true;
+ } else if (depName === "module") {
+ //CommonJS module spec 1.1
+ cjsModule = args[i] = handlers.module(name);
+ } else if (hasProp(defined, depName) ||
+ hasProp(waiting, depName) ||
+ hasProp(defining, depName)) {
+ args[i] = callDep(depName);
+ } else if (map.p) {
+ map.p.load(map.n, makeRequire(relName, true), makeLoad(depName), {});
+ args[i] = defined[depName];
+ } else {
+ throw new Error(name + ' missing ' + depName);
+ }
+ }
+
+ ret = callback ? callback.apply(defined[name], args) : undefined;
+
+ if (name) {
+ //If setting exports via "module" is in play,
+ //favor that over return value and exports. After that,
+ //favor a non-undefined return value over exports use.
+ if (cjsModule && cjsModule.exports !== undef &&
+ cjsModule.exports !== defined[name]) {
+ defined[name] = cjsModule.exports;
+ } else if (ret !== undef || !usingExports) {
+ //Use the return value from the function.
+ defined[name] = ret;
+ }
+ }
+ } else if (name) {
+ //May just be an object definition for the module. Only
+ //worry about defining if have a module name.
+ defined[name] = callback;
+ }
+ };
+
+ requirejs = require = req = function (deps, callback, relName, forceSync, alt) {
+ if (typeof deps === "string") {
+ if (handlers[deps]) {
+ //callback in this case is really relName
+ return handlers[deps](callback);
+ }
+ //Just return the module wanted. In this scenario, the
+ //deps arg is the module name, and second arg (if passed)
+ //is just the relName.
+ //Normalize module name, if it contains . or ..
+ return callDep(makeMap(deps, makeRelParts(callback)).f);
+ } else if (!deps.splice) {
+ //deps is a config object, not an array.
+ config = deps;
+ if (config.deps) {
+ req(config.deps, config.callback);
+ }
+ if (!callback) {
+ return;
+ }
+
+ if (callback.splice) {
+ //callback is an array, which means it is a dependency list.
+ //Adjust args if there are dependencies
+ deps = callback;
+ callback = relName;
+ relName = null;
+ } else {
+ deps = undef;
+ }
+ }
+
+ //Support require(['a'])
+ callback = callback || function () {};
+
+ //If relName is a function, it is an errback handler,
+ //so remove it.
+ if (typeof relName === 'function') {
+ relName = forceSync;
+ forceSync = alt;
+ }
+
+ //Simulate async callback;
+ if (forceSync) {
+ main(undef, deps, callback, relName);
+ } else {
+ //Using a non-zero value because of concern for what old browsers
+ //do, and latest browsers "upgrade" to 4 if lower value is used:
+ //http://www.whatwg.org/specs/web-apps/current-work/multipage/timers.html#dom-windowtimers-settimeout:
+ //If want a value immediately, use require('id') instead -- something
+ //that works in almond on the global level, but not guaranteed and
+ //unlikely to work in other AMD implementations.
+ setTimeout(function () {
+ main(undef, deps, callback, relName);
+ }, 4);
+ }
+
+ return req;
+ };
+
+ /**
+ * Just drops the config on the floor, but returns req in case
+ * the config return value is used.
+ */
+ req.config = function (cfg) {
+ return req(cfg);
+ };
+
+ /**
+ * Expose module registry for debugging and tooling
+ */
+ requirejs._defined = defined;
+
+ define = function (name, deps, callback) {
+ if (typeof name !== 'string') {
+ throw new Error('See almond README: incorrect module build, no module name');
+ }
+
+ //This module may not have dependencies
+ if (!deps.splice) {
+ //deps is not an array, so probably means
+ //an object literal or factory function for
+ //the value. Adjust args.
+ callback = deps;
+ deps = [];
+ }
+
+ if (!hasProp(defined, name) && !hasProp(waiting, name)) {
+ waiting[name] = [name, deps, callback];
+ }
+ };
+
+ define.amd = {
+ jQuery: true
+ };
+}());
+
+S2.requirejs = requirejs;S2.require = require;S2.define = define;
+}
+}());
+S2.define("almond", function(){});
+
+/* global jQuery:false, $:false */
+S2.define('jquery',[],function () {
+ var _$ = jQuery || $;
+
+ if (_$ == null && console && console.error) {
+ console.error(
+ 'Select2: An instance of jQuery or a jQuery-compatible library was not ' +
+ 'found. Make sure that you are including jQuery before Select2 on your ' +
+ 'web page.'
+ );
+ }
+
+ return _$;
+});
+
+S2.define('select2/utils',[
+ 'jquery'
+], function ($) {
+ var Utils = {};
+
+ Utils.Extend = function (ChildClass, SuperClass) {
+ var __hasProp = {}.hasOwnProperty;
+
+ function BaseConstructor () {
+ this.constructor = ChildClass;
+ }
+
+ for (var key in SuperClass) {
+ if (__hasProp.call(SuperClass, key)) {
+ ChildClass[key] = SuperClass[key];
+ }
+ }
+
+ BaseConstructor.prototype = SuperClass.prototype;
+ ChildClass.prototype = new BaseConstructor();
+ ChildClass.__super__ = SuperClass.prototype;
+
+ return ChildClass;
+ };
+
+ function getMethods (theClass) {
+ var proto = theClass.prototype;
+
+ var methods = [];
+
+ for (var methodName in proto) {
+ var m = proto[methodName];
+
+ if (typeof m !== 'function') {
+ continue;
+ }
+
+ if (methodName === 'constructor') {
+ continue;
+ }
+
+ methods.push(methodName);
+ }
+
+ return methods;
+ }
+
+ Utils.Decorate = function (SuperClass, DecoratorClass) {
+ var decoratedMethods = getMethods(DecoratorClass);
+ var superMethods = getMethods(SuperClass);
+
+ function DecoratedClass () {
+ var unshift = Array.prototype.unshift;
+
+ var argCount = DecoratorClass.prototype.constructor.length;
+
+ var calledConstructor = SuperClass.prototype.constructor;
+
+ if (argCount > 0) {
+ unshift.call(arguments, SuperClass.prototype.constructor);
+
+ calledConstructor = DecoratorClass.prototype.constructor;
+ }
+
+ calledConstructor.apply(this, arguments);
+ }
+
+ DecoratorClass.displayName = SuperClass.displayName;
+
+ function ctr () {
+ this.constructor = DecoratedClass;
+ }
+
+ DecoratedClass.prototype = new ctr();
+
+ for (var m = 0; m < superMethods.length; m++) {
+ var superMethod = superMethods[m];
+
+ DecoratedClass.prototype[superMethod] =
+ SuperClass.prototype[superMethod];
+ }
+
+ var calledMethod = function (methodName) {
+ // Stub out the original method if it's not decorating an actual method
+ var originalMethod = function () {};
+
+ if (methodName in DecoratedClass.prototype) {
+ originalMethod = DecoratedClass.prototype[methodName];
+ }
+
+ var decoratedMethod = DecoratorClass.prototype[methodName];
+
+ return function () {
+ var unshift = Array.prototype.unshift;
+
+ unshift.call(arguments, originalMethod);
+
+ return decoratedMethod.apply(this, arguments);
+ };
+ };
+
+ for (var d = 0; d < decoratedMethods.length; d++) {
+ var decoratedMethod = decoratedMethods[d];
+
+ DecoratedClass.prototype[decoratedMethod] = calledMethod(decoratedMethod);
+ }
+
+ return DecoratedClass;
+ };
+
+ var Observable = function () {
+ this.listeners = {};
+ };
+
+ Observable.prototype.on = function (event, callback) {
+ this.listeners = this.listeners || {};
+
+ if (event in this.listeners) {
+ this.listeners[event].push(callback);
+ } else {
+ this.listeners[event] = [callback];
+ }
+ };
+
+ Observable.prototype.trigger = function (event) {
+ var slice = Array.prototype.slice;
+ var params = slice.call(arguments, 1);
+
+ this.listeners = this.listeners || {};
+
+ // Params should always come in as an array
+ if (params == null) {
+ params = [];
+ }
+
+ // If there are no arguments to the event, use a temporary object
+ if (params.length === 0) {
+ params.push({});
+ }
+
+ // Set the `_type` of the first object to the event
+ params[0]._type = event;
+
+ if (event in this.listeners) {
+ this.invoke(this.listeners[event], slice.call(arguments, 1));
+ }
+
+ if ('*' in this.listeners) {
+ this.invoke(this.listeners['*'], arguments);
+ }
+ };
+
+ Observable.prototype.invoke = function (listeners, params) {
+ for (var i = 0, len = listeners.length; i < len; i++) {
+ listeners[i].apply(this, params);
+ }
+ };
+
+ Utils.Observable = Observable;
+
+ Utils.generateChars = function (length) {
+ var chars = '';
+
+ for (var i = 0; i < length; i++) {
+ var randomChar = Math.floor(Math.random() * 36);
+ chars += randomChar.toString(36);
+ }
+
+ return chars;
+ };
+
+ Utils.bind = function (func, context) {
+ return function () {
+ func.apply(context, arguments);
+ };
+ };
+
+ Utils._convertData = function (data) {
+ for (var originalKey in data) {
+ var keys = originalKey.split('-');
+
+ var dataLevel = data;
+
+ if (keys.length === 1) {
+ continue;
+ }
+
+ for (var k = 0; k < keys.length; k++) {
+ var key = keys[k];
+
+ // Lowercase the first letter
+ // By default, dash-separated becomes camelCase
+ key = key.substring(0, 1).toLowerCase() + key.substring(1);
+
+ if (!(key in dataLevel)) {
+ dataLevel[key] = {};
+ }
+
+ if (k == keys.length - 1) {
+ dataLevel[key] = data[originalKey];
+ }
+
+ dataLevel = dataLevel[key];
+ }
+
+ delete data[originalKey];
+ }
+
+ return data;
+ };
+
+ Utils.hasScroll = function (index, el) {
+ // Adapted from the function created by @ShadowScripter
+ // and adapted by @BillBarry on the Stack Exchange Code Review website.
+ // The original code can be found at
+ // http://codereview.stackexchange.com/q/13338
+ // and was designed to be used with the Sizzle selector engine.
+
+ var $el = $(el);
+ var overflowX = el.style.overflowX;
+ var overflowY = el.style.overflowY;
+
+ //Check both x and y declarations
+ if (overflowX === overflowY &&
+ (overflowY === 'hidden' || overflowY === 'visible')) {
+ return false;
+ }
+
+ if (overflowX === 'scroll' || overflowY === 'scroll') {
+ return true;
+ }
+
+ return ($el.innerHeight() < el.scrollHeight ||
+ $el.innerWidth() < el.scrollWidth);
+ };
+
+ Utils.escapeMarkup = function (markup) {
+ var replaceMap = {
+ '\\': '&#92;',
+ '&': '&amp;',
+ '<': '&lt;',
+ '>': '&gt;',
+ '"': '&quot;',
+ '\'': '&#39;',
+ '/': '&#47;'
+ };
+
+ // Do not try to escape the markup if it's not a string
+ if (typeof markup !== 'string') {
+ return markup;
+ }
+
+ return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
+ return replaceMap[match];
+ });
+ };
+
+ // Append an array of jQuery nodes to a given element.
+ Utils.appendMany = function ($element, $nodes) {
+ // jQuery 1.7.x does not support $.fn.append() with an array
+ // Fall back to a jQuery object collection using $.fn.add()
+ if ($.fn.jquery.substr(0, 3) === '1.7') {
+ var $jqNodes = $();
+
+ $.map($nodes, function (node) {
+ $jqNodes = $jqNodes.add(node);
+ });
+
+ $nodes = $jqNodes;
+ }
+
+ $element.append($nodes);
+ };
+
+ // Cache objects in Utils.__cache instead of $.data (see #4346)
+ Utils.__cache = {};
+
+ var id = 0;
+ Utils.GetUniqueElementId = function (element) {
+ // Get a unique element Id. If element has no id,
+ // creates a new unique number, stores it in the id
+ // attribute and returns the new id.
+ // If an id already exists, it simply returns it.
+
+ var select2Id = element.getAttribute('data-select2-id');
+ if (select2Id == null) {
+ // If element has id, use it.
+ if (element.id) {
+ select2Id = element.id;
+ element.setAttribute('data-select2-id', select2Id);
+ } else {
+ element.setAttribute('data-select2-id', ++id);
+ select2Id = id.toString();
+ }
+ }
+ return select2Id;
+ };
+
+ Utils.StoreData = function (element, name, value) {
+ // Stores an item in the cache for a specified element.
+ // name is the cache key.
+ var id = Utils.GetUniqueElementId(element);
+ if (!Utils.__cache[id]) {
+ Utils.__cache[id] = {};
+ }
+
+ Utils.__cache[id][name] = value;
+ };
+
+ Utils.GetData = function (element, name) {
+ // Retrieves a value from the cache by its key (name)
+ // name is optional. If no name specified, return
+ // all cache items for the specified element.
+ // and for a specified element.
+ var id = Utils.GetUniqueElementId(element);
+ if (name) {
+ if (Utils.__cache[id]) {
+ if (Utils.__cache[id][name] != null) {
+ return Utils.__cache[id][name];
+ }
+ return $(element).data(name); // Fallback to HTML5 data attribs.
+ }
+ return $(element).data(name); // Fallback to HTML5 data attribs.
+ } else {
+ return Utils.__cache[id];
+ }
+ };
+
+ Utils.RemoveData = function (element) {
+ // Removes all cached items for a specified element.
+ var id = Utils.GetUniqueElementId(element);
+ if (Utils.__cache[id] != null) {
+ delete Utils.__cache[id];
+ }
+
+ element.removeAttribute('data-select2-id');
+ };
+
+ return Utils;
+});
+
+S2.define('select2/results',[
+ 'jquery',
+ './utils'
+], function ($, Utils) {
+ function Results ($element, options, dataAdapter) {
+ this.$element = $element;
+ this.data = dataAdapter;
+ this.options = options;
+
+ Results.__super__.constructor.call(this);
+ }
+
+ Utils.Extend(Results, Utils.Observable);
+
+ Results.prototype.render = function () {
+ var $results = $(
+ '<ul class="select2-results__options" role="listbox"></ul>'
+ );
+
+ if (this.options.get('multiple')) {
+ $results.attr('aria-multiselectable', 'true');
+ }
+
+ this.$results = $results;
+
+ return $results;
+ };
+
+ Results.prototype.clear = function () {
+ this.$results.empty();
+ };
+
+ Results.prototype.displayMessage = function (params) {
+ var escapeMarkup = this.options.get('escapeMarkup');
+
+ this.clear();
+ this.hideLoading();
+
+ var $message = $(
+ '<li role="alert" aria-live="assertive"' +
+ ' class="select2-results__option"></li>'
+ );
+
+ var message = this.options.get('translations').get(params.message);
+
+ $message.append(
+ escapeMarkup(
+ message(params.args)
+ )
+ );
+
+ $message[0].className += ' select2-results__message';
+
+ this.$results.append($message);
+ };
+
+ Results.prototype.hideMessages = function () {
+ this.$results.find('.select2-results__message').remove();
+ };
+
+ Results.prototype.append = function (data) {
+ this.hideLoading();
+
+ var $options = [];
+
+ if (data.results == null || data.results.length === 0) {
+ if (this.$results.children().length === 0) {
+ this.trigger('results:message', {
+ message: 'noResults'
+ });
+ }
+
+ return;
+ }
+
+ data.results = this.sort(data.results);
+
+ for (var d = 0; d < data.results.length; d++) {
+ var item = data.results[d];
+
+ var $option = this.option(item);
+
+ $options.push($option);
+ }
+
+ this.$results.append($options);
+ };
+
+ Results.prototype.position = function ($results, $dropdown) {
+ var $resultsContainer = $dropdown.find('.select2-results');
+ $resultsContainer.append($results);
+ };
+
+ Results.prototype.sort = function (data) {
+ var sorter = this.options.get('sorter');
+
+ return sorter(data);
+ };
+
+ Results.prototype.highlightFirstItem = function () {
+ var $options = this.$results
+ .find('.select2-results__option[aria-selected]');
+
+ var $selected = $options.filter('[aria-selected=true]');
+
+ // Check if there are any selected options
+ if ($selected.length > 0) {
+ // If there are selected options, highlight the first
+ $selected.first().trigger('mouseenter');
+ } else {
+ // If there are no selected options, highlight the first option
+ // in the dropdown
+ $options.first().trigger('mouseenter');
+ }
+
+ this.ensureHighlightVisible();
+ };
+
+ Results.prototype.setClasses = function () {
+ var self = this;
+
+ this.data.current(function (selected) {
+ var selectedIds = $.map(selected, function (s) {
+ return s.id.toString();
+ });
+
+ var $options = self.$results
+ .find('.select2-results__option[aria-selected]');
+
+ $options.each(function () {
+ var $option = $(this);
+
+ var item = Utils.GetData(this, 'data');
+
+ // id needs to be converted to a string when comparing
+ var id = '' + item.id;
+
+ if ((item.element != null && item.element.selected) ||
+ (item.element == null && $.inArray(id, selectedIds) > -1)) {
+ $option.attr('aria-selected', 'true');
+ } else {
+ $option.attr('aria-selected', 'false');
+ }
+ });
+
+ });
+ };
+
+ Results.prototype.showLoading = function (params) {
+ this.hideLoading();
+
+ var loadingMore = this.options.get('translations').get('searching');
+
+ var loading = {
+ disabled: true,
+ loading: true,
+ text: loadingMore(params)
+ };
+ var $loading = this.option(loading);
+ $loading.className += ' loading-results';
+
+ this.$results.prepend($loading);
+ };
+
+ Results.prototype.hideLoading = function () {
+ this.$results.find('.loading-results').remove();
+ };
+
+ Results.prototype.option = function (data) {
+ var option = document.createElement('li');
+ option.className = 'select2-results__option';
+
+ var attrs = {
+ 'role': 'option',
+ 'aria-selected': 'false'
+ };
+
+ var matches = window.Element.prototype.matches ||
+ window.Element.prototype.msMatchesSelector ||
+ window.Element.prototype.webkitMatchesSelector;
+
+ if ((data.element != null && matches.call(data.element, ':disabled')) ||
+ (data.element == null && data.disabled)) {
+ delete attrs['aria-selected'];
+ attrs['aria-disabled'] = 'true';
+ }
+
+ if (data.id == null) {
+ delete attrs['aria-selected'];
+ }
+
+ if (data._resultId != null) {
+ option.id = data._resultId;
+ }
+
+ if (data.title) {
+ option.title = data.title;
+ }
+
+ if (data.children) {
+ attrs.role = 'group';
+ attrs['aria-label'] = data.text;
+ delete attrs['aria-selected'];
+ }
+
+ for (var attr in attrs) {
+ var val = attrs[attr];
+
+ option.setAttribute(attr, val);
+ }
+
+ if (data.children) {
+ var $option = $(option);
+
+ var label = document.createElement('strong');
+ label.className = 'select2-results__group';
+
+ var $label = $(label);
+ this.template(data, label);
+
+ var $children = [];
+
+ for (var c = 0; c < data.children.length; c++) {
+ var child = data.children[c];
+
+ var $child = this.option(child);
+
+ $children.push($child);
+ }
+
+ var $childrenContainer = $('<ul></ul>', {
+ 'class': 'select2-results__options select2-results__options--nested'
+ });
+
+ $childrenContainer.append($children);
+
+ $option.append(label);
+ $option.append($childrenContainer);
+ } else {
+ this.template(data, option);
+ }
+
+ Utils.StoreData(option, 'data', data);
+
+ return option;
+ };
+
+ Results.prototype.bind = function (container, $container) {
+ var self = this;
+
+ var id = container.id + '-results';
+
+ this.$results.attr('id', id);
+
+ container.on('results:all', function (params) {
+ self.clear();
+ self.append(params.data);
+
+ if (container.isOpen()) {
+ self.setClasses();
+ self.highlightFirstItem();
+ }
+ });
+
+ container.on('results:append', function (params) {
+ self.append(params.data);
+
+ if (container.isOpen()) {
+ self.setClasses();
+ }
+ });
+
+ container.on('query', function (params) {
+ self.hideMessages();
+ self.showLoading(params);
+ });
+
+ container.on('select', function () {
+ if (!container.isOpen()) {
+ return;
+ }
+
+ self.setClasses();
+
+ if (self.options.get('scrollAfterSelect')) {
+ self.highlightFirstItem();
+ }
+ });
+
+ container.on('unselect', function () {
+ if (!container.isOpen()) {
+ return;
+ }
+
+ self.setClasses();
+
+ if (self.options.get('scrollAfterSelect')) {
+ self.highlightFirstItem();
+ }
+ });
+
+ container.on('open', function () {
+ // When the dropdown is open, aria-expended="true"
+ self.$results.attr('aria-expanded', 'true');
+ self.$results.attr('aria-hidden', 'false');
+
+ self.setClasses();
+ self.ensureHighlightVisible();
+ });
+
+ container.on('close', function () {
+ // When the dropdown is closed, aria-expended="false"
+ self.$results.attr('aria-expanded', 'false');
+ self.$results.attr('aria-hidden', 'true');
+ self.$results.removeAttr('aria-activedescendant');
+ });
+
+ container.on('results:toggle', function () {
+ var $highlighted = self.getHighlightedResults();
+
+ if ($highlighted.length === 0) {
+ return;
+ }
+
+ $highlighted.trigger('mouseup');
+ });
+
+ container.on('results:select', function () {
+ var $highlighted = self.getHighlightedResults();
+
+ if ($highlighted.length === 0) {
+ return;
+ }
+
+ var data = Utils.GetData($highlighted[0], 'data');
+
+ if ($highlighted.attr('aria-selected') == 'true') {
+ self.trigger('close', {});
+ } else {
+ self.trigger('select', {
+ data: data
+ });
+ }
+ });
+
+ container.on('results:previous', function () {
+ var $highlighted = self.getHighlightedResults();
+
+ var $options = self.$results.find('[aria-selected]');
+
+ var currentIndex = $options.index($highlighted);
+
+ // If we are already at the top, don't move further
+ // If no options, currentIndex will be -1
+ if (currentIndex <= 0) {
+ return;
+ }
+
+ var nextIndex = currentIndex - 1;
+
+ // If none are highlighted, highlight the first
+ if ($highlighted.length === 0) {
+ nextIndex = 0;
+ }
+
+ var $next = $options.eq(nextIndex);
+
+ $next.trigger('mouseenter');
+
+ var currentOffset = self.$results.offset().top;
+ var nextTop = $next.offset().top;
+ var nextOffset = self.$results.scrollTop() + (nextTop - currentOffset);
+
+ if (nextIndex === 0) {
+ self.$results.scrollTop(0);
+ } else if (nextTop - currentOffset < 0) {
+ self.$results.scrollTop(nextOffset);
+ }
+ });
+
+ container.on('results:next', function () {
+ var $highlighted = self.getHighlightedResults();
+
+ var $options = self.$results.find('[aria-selected]');
+
+ var currentIndex = $options.index($highlighted);
+
+ var nextIndex = currentIndex + 1;
+
+ // If we are at the last option, stay there
+ if (nextIndex >= $options.length) {
+ return;
+ }
+
+ var $next = $options.eq(nextIndex);
+
+ $next.trigger('mouseenter');
+
+ var currentOffset = self.$results.offset().top +
+ self.$results.outerHeight(false);
+ var nextBottom = $next.offset().top + $next.outerHeight(false);
+ var nextOffset = self.$results.scrollTop() + nextBottom - currentOffset;
+
+ if (nextIndex === 0) {
+ self.$results.scrollTop(0);
+ } else if (nextBottom > currentOffset) {
+ self.$results.scrollTop(nextOffset);
+ }
+ });
+
+ container.on('results:focus', function (params) {
+ params.element.addClass('select2-results__option--highlighted');
+ });
+
+ container.on('results:message', function (params) {
+ self.displayMessage(params);
+ });
+
+ if ($.fn.mousewheel) {
+ this.$results.on('mousewheel', function (e) {
+ var top = self.$results.scrollTop();
+
+ var bottom = self.$results.get(0).scrollHeight - top + e.deltaY;
+
+ var isAtTop = e.deltaY > 0 && top - e.deltaY <= 0;
+ var isAtBottom = e.deltaY < 0 && bottom <= self.$results.height();
+
+ if (isAtTop) {
+ self.$results.scrollTop(0);
+
+ e.preventDefault();
+ e.stopPropagation();
+ } else if (isAtBottom) {
+ self.$results.scrollTop(
+ self.$results.get(0).scrollHeight - self.$results.height()
+ );
+
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ });
+ }
+
+ this.$results.on('mouseup', '.select2-results__option[aria-selected]',
+ function (evt) {
+ var $this = $(this);
+
+ var data = Utils.GetData(this, 'data');
+
+ if ($this.attr('aria-selected') === 'true') {
+ if (self.options.get('multiple')) {
+ self.trigger('unselect', {
+ originalEvent: evt,
+ data: data
+ });
+ } else {
+ self.trigger('close', {});
+ }
+
+ return;
+ }
+
+ self.trigger('select', {
+ originalEvent: evt,
+ data: data
+ });
+ });
+
+ this.$results.on('mouseenter', '.select2-results__option[aria-selected]',
+ function (evt) {
+ var data = Utils.GetData(this, 'data');
+
+ self.getHighlightedResults()
+ .removeClass('select2-results__option--highlighted');
+
+ self.trigger('results:focus', {
+ data: data,
+ element: $(this)
+ });
+ });
+ };
+
+ Results.prototype.getHighlightedResults = function () {
+ var $highlighted = this.$results
+ .find('.select2-results__option--highlighted');
+
+ return $highlighted;
+ };
+
+ Results.prototype.destroy = function () {
+ this.$results.remove();
+ };
+
+ Results.prototype.ensureHighlightVisible = function () {
+ var $highlighted = this.getHighlightedResults();
+
+ if ($highlighted.length === 0) {
+ return;
+ }
+
+ var $options = this.$results.find('[aria-selected]');
+
+ var currentIndex = $options.index($highlighted);
+
+ var currentOffset = this.$results.offset().top;
+ var nextTop = $highlighted.offset().top;
+ var nextOffset = this.$results.scrollTop() + (nextTop - currentOffset);
+
+ var offsetDelta = nextTop - currentOffset;
+ nextOffset -= $highlighted.outerHeight(false) * 2;
+
+ if (currentIndex <= 2) {
+ this.$results.scrollTop(0);
+ } else if (offsetDelta > this.$results.outerHeight() || offsetDelta < 0) {
+ this.$results.scrollTop(nextOffset);
+ }
+ };
+
+ Results.prototype.template = function (result, container) {
+ var template = this.options.get('templateResult');
+ var escapeMarkup = this.options.get('escapeMarkup');
+
+ var content = template(result, container);
+
+ if (content == null) {
+ container.style.display = 'none';
+ } else if (typeof content === 'string') {
+ container.innerHTML = escapeMarkup(content);
+ } else {
+ $(container).append(content);
+ }
+ };
+
+ return Results;
+});
+
+S2.define('select2/keys',[
+
+], function () {
+ var KEYS = {
+ BACKSPACE: 8,
+ TAB: 9,
+ ENTER: 13,
+ SHIFT: 16,
+ CTRL: 17,
+ ALT: 18,
+ ESC: 27,
+ SPACE: 32,
+ PAGE_UP: 33,
+ PAGE_DOWN: 34,
+ END: 35,
+ HOME: 36,
+ LEFT: 37,
+ UP: 38,
+ RIGHT: 39,
+ DOWN: 40,
+ DELETE: 46
+ };
+
+ return KEYS;
+});
+
+S2.define('select2/selection/base',[
+ 'jquery',
+ '../utils',
+ '../keys'
+], function ($, Utils, KEYS) {
+ function BaseSelection ($element, options) {
+ this.$element = $element;
+ this.options = options;
+
+ BaseSelection.__super__.constructor.call(this);
+ }
+
+ Utils.Extend(BaseSelection, Utils.Observable);
+
+ BaseSelection.prototype.render = function () {
+ var $selection = $(
+ '<span class="select2-selection" role="combobox" ' +
+ ' aria-haspopup="true" aria-expanded="false">' +
+ '</span>'
+ );
+
+ this._tabindex = 0;
+
+ if (Utils.GetData(this.$element[0], 'old-tabindex') != null) {
+ this._tabindex = Utils.GetData(this.$element[0], 'old-tabindex');
+ } else if (this.$element.attr('tabindex') != null) {
+ this._tabindex = this.$element.attr('tabindex');
+ }
+
+ $selection.attr('title', this.$element.attr('title'));
+ $selection.attr('tabindex', this._tabindex);
+ $selection.attr('aria-disabled', 'false');
+
+ this.$selection = $selection;
+
+ return $selection;
+ };
+
+ BaseSelection.prototype.bind = function (container, $container) {
+ var self = this;
+
+ var resultsId = container.id + '-results';
+
+ this.container = container;
+
+ this.$selection.on('focus', function (evt) {
+ self.trigger('focus', evt);
+ });
+
+ this.$selection.on('blur', function (evt) {
+ self._handleBlur(evt);
+ });
+
+ this.$selection.on('keydown', function (evt) {
+ self.trigger('keypress', evt);
+
+ if (evt.which === KEYS.SPACE) {
+ evt.preventDefault();
+ }
+ });
+
+ container.on('results:focus', function (params) {
+ self.$selection.attr('aria-activedescendant', params.data._resultId);
+ });
+
+ container.on('selection:update', function (params) {
+ self.update(params.data);
+ });
+
+ container.on('open', function () {
+ // When the dropdown is open, aria-expanded="true"
+ self.$selection.attr('aria-expanded', 'true');
+ self.$selection.attr('aria-owns', resultsId);
+
+ self._attachCloseHandler(container);
+ });
+
+ container.on('close', function () {
+ // When the dropdown is closed, aria-expanded="false"
+ self.$selection.attr('aria-expanded', 'false');
+ self.$selection.removeAttr('aria-activedescendant');
+ self.$selection.removeAttr('aria-owns');
+
+ self.$selection.trigger('focus');
+
+ self._detachCloseHandler(container);
+ });
+
+ container.on('enable', function () {
+ self.$selection.attr('tabindex', self._tabindex);
+ self.$selection.attr('aria-disabled', 'false');
+ });
+
+ container.on('disable', function () {
+ self.$selection.attr('tabindex', '-1');
+ self.$selection.attr('aria-disabled', 'true');
+ });
+ };
+
+ BaseSelection.prototype._handleBlur = function (evt) {
+ var self = this;
+
+ // This needs to be delayed as the active element is the body when the tab
+ // key is pressed, possibly along with others.
+ window.setTimeout(function () {
+ // Don't trigger `blur` if the focus is still in the selection
+ if (
+ (document.activeElement == self.$selection[0]) ||
+ ($.contains(self.$selection[0], document.activeElement))
+ ) {
+ return;
+ }
+
+ self.trigger('blur', evt);
+ }, 1);
+ };
+
+ BaseSelection.prototype._attachCloseHandler = function (container) {
+
+ $(document.body).on('mousedown.select2.' + container.id, function (e) {
+ var $target = $(e.target);
+
+ var $select = $target.closest('.select2');
+
+ var $all = $('.select2.select2-container--open');
+
+ $all.each(function () {
+ if (this == $select[0]) {
+ return;
+ }
+
+ var $element = Utils.GetData(this, 'element');
+
+ $element.select2('close');
+ });
+ });
+ };
+
+ BaseSelection.prototype._detachCloseHandler = function (container) {
+ $(document.body).off('mousedown.select2.' + container.id);
+ };
+
+ BaseSelection.prototype.position = function ($selection, $container) {
+ var $selectionContainer = $container.find('.selection');
+ $selectionContainer.append($selection);
+ };
+
+ BaseSelection.prototype.destroy = function () {
+ this._detachCloseHandler(this.container);
+ };
+
+ BaseSelection.prototype.update = function (data) {
+ throw new Error('The `update` method must be defined in child classes.');
+ };
+
+ return BaseSelection;
+});
+
+S2.define('select2/selection/single',[
+ 'jquery',
+ './base',
+ '../utils',
+ '../keys'
+], function ($, BaseSelection, Utils, KEYS) {
+ function SingleSelection () {
+ SingleSelection.__super__.constructor.apply(this, arguments);
+ }
+
+ Utils.Extend(SingleSelection, BaseSelection);
+
+ SingleSelection.prototype.render = function () {
+ var $selection = SingleSelection.__super__.render.call(this);
+
+ $selection.addClass('select2-selection--single');
+
+ $selection.html(
+ '<span class="select2-selection__rendered"></span>' +
+ '<span class="select2-selection__arrow" role="presentation">' +
+ '<b role="presentation"></b>' +
+ '</span>'
+ );
+
+ return $selection;
+ };
+
+ SingleSelection.prototype.bind = function (container, $container) {
+ var self = this;
+
+ SingleSelection.__super__.bind.apply(this, arguments);
+
+ var id = container.id + '-container';
+
+ this.$selection.find('.select2-selection__rendered')
+ .attr('id', id)
+ .attr('role', 'textbox')
+ .attr('aria-readonly', 'true');
+ this.$selection.attr('aria-labelledby', id);
+
+ this.$selection.on('mousedown', function (evt) {
+ // Only respond to left clicks
+ if (evt.which !== 1) {
+ return;
+ }
+
+ self.trigger('toggle', {
+ originalEvent: evt
+ });
+ });
+
+ this.$selection.on('focus', function (evt) {
+ // User focuses on the container
+ });
+
+ this.$selection.on('blur', function (evt) {
+ // User exits the container
+ });
+
+ container.on('focus', function (evt) {
+ if (!container.isOpen()) {
+ self.$selection.trigger('focus');
+ }
+ });
+ };
+
+ SingleSelection.prototype.clear = function () {
+ var $rendered = this.$selection.find('.select2-selection__rendered');
+ $rendered.empty();
+ $rendered.removeAttr('title'); // clear tooltip on empty
+ };
+
+ SingleSelection.prototype.display = function (data, container) {
+ var template = this.options.get('templateSelection');
+ var escapeMarkup = this.options.get('escapeMarkup');
+
+ return escapeMarkup(template(data, container));
+ };
+
+ SingleSelection.prototype.selectionContainer = function () {
+ return $('<span></span>');
+ };
+
+ SingleSelection.prototype.update = function (data) {
+ if (data.length === 0) {
+ this.clear();
+ return;
+ }
+
+ var selection = data[0];
+
+ var $rendered = this.$selection.find('.select2-selection__rendered');
+ var formatted = this.display(selection, $rendered);
+
+ $rendered.empty().append(formatted);
+
+ var title = selection.title || selection.text;
+
+ if (title) {
+ $rendered.attr('title', title);
+ } else {
+ $rendered.removeAttr('title');
+ }
+ };
+
+ return SingleSelection;
+});
+
+S2.define('select2/selection/multiple',[
+ 'jquery',
+ './base',
+ '../utils'
+], function ($, BaseSelection, Utils) {
+ function MultipleSelection ($element, options) {
+ MultipleSelection.__super__.constructor.apply(this, arguments);
+ }
+
+ Utils.Extend(MultipleSelection, BaseSelection);
+
+ MultipleSelection.prototype.render = function () {
+ var $selection = MultipleSelection.__super__.render.call(this);
+
+ $selection.addClass('select2-selection--multiple');
+
+ $selection.html(
+ '<ul class="select2-selection__rendered"></ul>'
+ );
+
+ return $selection;
+ };
+
+ MultipleSelection.prototype.bind = function (container, $container) {
+ var self = this;
+
+ MultipleSelection.__super__.bind.apply(this, arguments);
+
+ this.$selection.on('click', function (evt) {
+ self.trigger('toggle', {
+ originalEvent: evt
+ });
+ });
+
+ this.$selection.on(
+ 'click',
+ '.select2-selection__choice__remove',
+ function (evt) {
+ // Ignore the event if it is disabled
+ if (self.options.get('disabled')) {
+ return;
+ }
+
+ var $remove = $(this);
+ var $selection = $remove.parent();
+
+ var data = Utils.GetData($selection[0], 'data');
+
+ self.trigger('unselect', {
+ originalEvent: evt,
+ data: data
+ });
+ }
+ );
+ };
+
+ MultipleSelection.prototype.clear = function () {
+ var $rendered = this.$selection.find('.select2-selection__rendered');
+ $rendered.empty();
+ $rendered.removeAttr('title');
+ };
+
+ MultipleSelection.prototype.display = function (data, container) {
+ var template = this.options.get('templateSelection');
+ var escapeMarkup = this.options.get('escapeMarkup');
+
+ return escapeMarkup(template(data, container));
+ };
+
+ MultipleSelection.prototype.selectionContainer = function () {
+ var $container = $(
+ '<li class="select2-selection__choice">' +
+ '<span class="select2-selection__choice__remove" role="presentation">' +
+ '&times;' +
+ '</span>' +
+ '</li>'
+ );
+
+ return $container;
+ };
+
+ MultipleSelection.prototype.update = function (data) {
+ this.clear();
+
+ if (data.length === 0) {
+ return;
+ }
+
+ var $selections = [];
+
+ for (var d = 0; d < data.length; d++) {
+ var selection = data[d];
+
+ var $selection = this.selectionContainer();
+ var formatted = this.display(selection, $selection);
+
+ $selection.append(formatted);
+
+ var title = selection.title || selection.text;
+
+ if (title) {
+ $selection.attr('title', title);
+ }
+
+ Utils.StoreData($selection[0], 'data', selection);
+
+ $selections.push($selection);
+ }
+
+ var $rendered = this.$selection.find('.select2-selection__rendered');
+
+ Utils.appendMany($rendered, $selections);
+ };
+
+ return MultipleSelection;
+});
+
+S2.define('select2/selection/placeholder',[
+ '../utils'
+], function (Utils) {
+ function Placeholder (decorated, $element, options) {
+ this.placeholder = this.normalizePlaceholder(options.get('placeholder'));
+
+ decorated.call(this, $element, options);
+ }
+
+ Placeholder.prototype.normalizePlaceholder = function (_, placeholder) {
+ if (typeof placeholder === 'string') {
+ placeholder = {
+ id: '',
+ text: placeholder
+ };
+ }
+
+ return placeholder;
+ };
+
+ Placeholder.prototype.createPlaceholder = function (decorated, placeholder) {
+ var $placeholder = this.selectionContainer();
+
+ $placeholder.html(this.display(placeholder));
+ $placeholder.addClass('select2-selection__placeholder')
+ .removeClass('select2-selection__choice');
+
+ return $placeholder;
+ };
+
+ Placeholder.prototype.update = function (decorated, data) {
+ var singlePlaceholder = (
+ data.length == 1 && data[0].id != this.placeholder.id
+ );
+ var multipleSelections = data.length > 1;
+
+ if (multipleSelections || singlePlaceholder) {
+ return decorated.call(this, data);
+ }
+
+ this.clear();
+
+ var $placeholder = this.createPlaceholder(this.placeholder);
+
+ this.$selection.find('.select2-selection__rendered').append($placeholder);
+ };
+
+ return Placeholder;
+});
+
+S2.define('select2/selection/allowClear',[
+ 'jquery',
+ '../keys',
+ '../utils'
+], function ($, KEYS, Utils) {
+ function AllowClear () { }
+
+ AllowClear.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ decorated.call(this, container, $container);
+
+ if (this.placeholder == null) {
+ if (this.options.get('debug') && window.console && console.error) {
+ console.error(
+ 'Select2: The `allowClear` option should be used in combination ' +
+ 'with the `placeholder` option.'
+ );
+ }
+ }
+
+ this.$selection.on('mousedown', '.select2-selection__clear',
+ function (evt) {
+ self._handleClear(evt);
+ });
+
+ container.on('keypress', function (evt) {
+ self._handleKeyboardClear(evt, container);
+ });
+ };
+
+ AllowClear.prototype._handleClear = function (_, evt) {
+ // Ignore the event if it is disabled
+ if (this.options.get('disabled')) {
+ return;
+ }
+
+ var $clear = this.$selection.find('.select2-selection__clear');
+
+ // Ignore the event if nothing has been selected
+ if ($clear.length === 0) {
+ return;
+ }
+
+ evt.stopPropagation();
+
+ var data = Utils.GetData($clear[0], 'data');
+
+ var previousVal = this.$element.val();
+ this.$element.val(this.placeholder.id);
+
+ var unselectData = {
+ data: data
+ };
+ this.trigger('clear', unselectData);
+ if (unselectData.prevented) {
+ this.$element.val(previousVal);
+ return;
+ }
+
+ for (var d = 0; d < data.length; d++) {
+ unselectData = {
+ data: data[d]
+ };
+
+ // Trigger the `unselect` event, so people can prevent it from being
+ // cleared.
+ this.trigger('unselect', unselectData);
+
+ // If the event was prevented, don't clear it out.
+ if (unselectData.prevented) {
+ this.$element.val(previousVal);
+ return;
+ }
+ }
+
+ this.$element.trigger('change');
+
+ this.trigger('toggle', {});
+ };
+
+ AllowClear.prototype._handleKeyboardClear = function (_, evt, container) {
+ if (container.isOpen()) {
+ return;
+ }
+
+ if (evt.which == KEYS.DELETE || evt.which == KEYS.BACKSPACE) {
+ this._handleClear(evt);
+ }
+ };
+
+ AllowClear.prototype.update = function (decorated, data) {
+ decorated.call(this, data);
+
+ if (this.$selection.find('.select2-selection__placeholder').length > 0 ||
+ data.length === 0) {
+ return;
+ }
+
+ var removeAll = this.options.get('translations').get('removeAllItems');
+
+ var $remove = $(
+ '<span class="select2-selection__clear" title="' + removeAll() +'">' +
+ '&times;' +
+ '</span>'
+ );
+ Utils.StoreData($remove[0], 'data', data);
+
+ this.$selection.find('.select2-selection__rendered').prepend($remove);
+ };
+
+ return AllowClear;
+});
+
+S2.define('select2/selection/search',[
+ 'jquery',
+ '../utils',
+ '../keys'
+], function ($, Utils, KEYS) {
+ function Search (decorated, $element, options) {
+ decorated.call(this, $element, options);
+ }
+
+ Search.prototype.render = function (decorated) {
+ var $search = $(
+ '<li class="select2-search select2-search--inline">' +
+ '<input class="select2-search__field" type="search" tabindex="-1"' +
+ ' autocomplete="off" autocorrect="off" autocapitalize="none"' +
+ ' spellcheck="false" role="searchbox" aria-autocomplete="list" />' +
+ '</li>'
+ );
+
+ this.$searchContainer = $search;
+ this.$search = $search.find('input');
+
+ var $rendered = decorated.call(this);
+
+ this._transferTabIndex();
+
+ return $rendered;
+ };
+
+ Search.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ var resultsId = container.id + '-results';
+
+ decorated.call(this, container, $container);
+
+ container.on('open', function () {
+ self.$search.attr('aria-controls', resultsId);
+ self.$search.trigger('focus');
+ });
+
+ container.on('close', function () {
+ self.$search.val('');
+ self.$search.removeAttr('aria-controls');
+ self.$search.removeAttr('aria-activedescendant');
+ self.$search.trigger('focus');
+ });
+
+ container.on('enable', function () {
+ self.$search.prop('disabled', false);
+
+ self._transferTabIndex();
+ });
+
+ container.on('disable', function () {
+ self.$search.prop('disabled', true);
+ });
+
+ container.on('focus', function (evt) {
+ self.$search.trigger('focus');
+ });
+
+ container.on('results:focus', function (params) {
+ if (params.data._resultId) {
+ self.$search.attr('aria-activedescendant', params.data._resultId);
+ } else {
+ self.$search.removeAttr('aria-activedescendant');
+ }
+ });
+
+ this.$selection.on('focusin', '.select2-search--inline', function (evt) {
+ self.trigger('focus', evt);
+ });
+
+ this.$selection.on('focusout', '.select2-search--inline', function (evt) {
+ self._handleBlur(evt);
+ });
+
+ this.$selection.on('keydown', '.select2-search--inline', function (evt) {
+ evt.stopPropagation();
+
+ self.trigger('keypress', evt);
+
+ self._keyUpPrevented = evt.isDefaultPrevented();
+
+ var key = evt.which;
+
+ if (key === KEYS.BACKSPACE && self.$search.val() === '') {
+ var $previousChoice = self.$searchContainer
+ .prev('.select2-selection__choice');
+
+ if ($previousChoice.length > 0) {
+ var item = Utils.GetData($previousChoice[0], 'data');
+
+ self.searchRemoveChoice(item);
+
+ evt.preventDefault();
+ }
+ }
+ });
+
+ this.$selection.on('click', '.select2-search--inline', function (evt) {
+ if (self.$search.val()) {
+ evt.stopPropagation();
+ }
+ });
+
+ // Try to detect the IE version should the `documentMode` property that
+ // is stored on the document. This is only implemented in IE and is
+ // slightly cleaner than doing a user agent check.
+ // This property is not available in Edge, but Edge also doesn't have
+ // this bug.
+ var msie = document.documentMode;
+ var disableInputEvents = msie && msie <= 11;
+
+ // Workaround for browsers which do not support the `input` event
+ // This will prevent double-triggering of events for browsers which support
+ // both the `keyup` and `input` events.
+ this.$selection.on(
+ 'input.searchcheck',
+ '.select2-search--inline',
+ function (evt) {
+ // IE will trigger the `input` event when a placeholder is used on a
+ // search box. To get around this issue, we are forced to ignore all
+ // `input` events in IE and keep using `keyup`.
+ if (disableInputEvents) {
+ self.$selection.off('input.search input.searchcheck');
+ return;
+ }
+
+ // Unbind the duplicated `keyup` event
+ self.$selection.off('keyup.search');
+ }
+ );
+
+ this.$selection.on(
+ 'keyup.search input.search',
+ '.select2-search--inline',
+ function (evt) {
+ // IE will trigger the `input` event when a placeholder is used on a
+ // search box. To get around this issue, we are forced to ignore all
+ // `input` events in IE and keep using `keyup`.
+ if (disableInputEvents && evt.type === 'input') {
+ self.$selection.off('input.search input.searchcheck');
+ return;
+ }
+
+ var key = evt.which;
+
+ // We can freely ignore events from modifier keys
+ if (key == KEYS.SHIFT || key == KEYS.CTRL || key == KEYS.ALT) {
+ return;
+ }
+
+ // Tabbing will be handled during the `keydown` phase
+ if (key == KEYS.TAB) {
+ return;
+ }
+
+ self.handleSearch(evt);
+ }
+ );
+ };
+
+ /**
+ * This method will transfer the tabindex attribute from the rendered
+ * selection to the search box. This allows for the search box to be used as
+ * the primary focus instead of the selection container.
+ *
+ * @private
+ */
+ Search.prototype._transferTabIndex = function (decorated) {
+ this.$search.attr('tabindex', this.$selection.attr('tabindex'));
+ this.$selection.attr('tabindex', '-1');
+ };
+
+ Search.prototype.createPlaceholder = function (decorated, placeholder) {
+ this.$search.attr('placeholder', placeholder.text);
+ };
+
+ Search.prototype.update = function (decorated, data) {
+ var searchHadFocus = this.$search[0] == document.activeElement;
+
+ this.$search.attr('placeholder', '');
+
+ decorated.call(this, data);
+
+ this.$selection.find('.select2-selection__rendered')
+ .append(this.$searchContainer);
+
+ this.resizeSearch();
+ if (searchHadFocus) {
+ this.$search.trigger('focus');
+ }
+ };
+
+ Search.prototype.handleSearch = function () {
+ this.resizeSearch();
+
+ if (!this._keyUpPrevented) {
+ var input = this.$search.val();
+
+ this.trigger('query', {
+ term: input
+ });
+ }
+
+ this._keyUpPrevented = false;
+ };
+
+ Search.prototype.searchRemoveChoice = function (decorated, item) {
+ this.trigger('unselect', {
+ data: item
+ });
+
+ this.$search.val(item.text);
+ this.handleSearch();
+ };
+
+ Search.prototype.resizeSearch = function () {
+ this.$search.css('width', '25px');
+
+ var width = '';
+
+ if (this.$search.attr('placeholder') !== '') {
+ width = this.$selection.find('.select2-selection__rendered').width();
+ } else {
+ var minimumWidth = this.$search.val().length + 1;
+
+ width = (minimumWidth * 0.75) + 'em';
+ }
+
+ this.$search.css('width', width);
+ };
+
+ return Search;
+});
+
+S2.define('select2/selection/eventRelay',[
+ 'jquery'
+], function ($) {
+ function EventRelay () { }
+
+ EventRelay.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+ var relayEvents = [
+ 'open', 'opening',
+ 'close', 'closing',
+ 'select', 'selecting',
+ 'unselect', 'unselecting',
+ 'clear', 'clearing'
+ ];
+
+ var preventableEvents = [
+ 'opening', 'closing', 'selecting', 'unselecting', 'clearing'
+ ];
+
+ decorated.call(this, container, $container);
+
+ container.on('*', function (name, params) {
+ // Ignore events that should not be relayed
+ if ($.inArray(name, relayEvents) === -1) {
+ return;
+ }
+
+ // The parameters should always be an object
+ params = params || {};
+
+ // Generate the jQuery event for the Select2 event
+ var evt = $.Event('select2:' + name, {
+ params: params
+ });
+
+ self.$element.trigger(evt);
+
+ // Only handle preventable events if it was one
+ if ($.inArray(name, preventableEvents) === -1) {
+ return;
+ }
+
+ params.prevented = evt.isDefaultPrevented();
+ });
+ };
+
+ return EventRelay;
+});
+
+S2.define('select2/translation',[
+ 'jquery',
+ 'require'
+], function ($, require) {
+ function Translation (dict) {
+ this.dict = dict || {};
+ }
+
+ Translation.prototype.all = function () {
+ return this.dict;
+ };
+
+ Translation.prototype.get = function (key) {
+ return this.dict[key];
+ };
+
+ Translation.prototype.extend = function (translation) {
+ this.dict = $.extend({}, translation.all(), this.dict);
+ };
+
+ // Static functions
+
+ Translation._cache = {};
+
+ Translation.loadPath = function (path) {
+ if (!(path in Translation._cache)) {
+ var translations = require(path);
+
+ Translation._cache[path] = translations;
+ }
+
+ return new Translation(Translation._cache[path]);
+ };
+
+ return Translation;
+});
+
+S2.define('select2/diacritics',[
+
+], function () {
+ var diacritics = {
+ '\u24B6': 'A',
+ '\uFF21': 'A',
+ '\u00C0': 'A',
+ '\u00C1': 'A',
+ '\u00C2': 'A',
+ '\u1EA6': 'A',
+ '\u1EA4': 'A',
+ '\u1EAA': 'A',
+ '\u1EA8': 'A',
+ '\u00C3': 'A',
+ '\u0100': 'A',
+ '\u0102': 'A',
+ '\u1EB0': 'A',
+ '\u1EAE': 'A',
+ '\u1EB4': 'A',
+ '\u1EB2': 'A',
+ '\u0226': 'A',
+ '\u01E0': 'A',
+ '\u00C4': 'A',
+ '\u01DE': 'A',
+ '\u1EA2': 'A',
+ '\u00C5': 'A',
+ '\u01FA': 'A',
+ '\u01CD': 'A',
+ '\u0200': 'A',
+ '\u0202': 'A',
+ '\u1EA0': 'A',
+ '\u1EAC': 'A',
+ '\u1EB6': 'A',
+ '\u1E00': 'A',
+ '\u0104': 'A',
+ '\u023A': 'A',
+ '\u2C6F': 'A',
+ '\uA732': 'AA',
+ '\u00C6': 'AE',
+ '\u01FC': 'AE',
+ '\u01E2': 'AE',
+ '\uA734': 'AO',
+ '\uA736': 'AU',
+ '\uA738': 'AV',
+ '\uA73A': 'AV',
+ '\uA73C': 'AY',
+ '\u24B7': 'B',
+ '\uFF22': 'B',
+ '\u1E02': 'B',
+ '\u1E04': 'B',
+ '\u1E06': 'B',
+ '\u0243': 'B',
+ '\u0182': 'B',
+ '\u0181': 'B',
+ '\u24B8': 'C',
+ '\uFF23': 'C',
+ '\u0106': 'C',
+ '\u0108': 'C',
+ '\u010A': 'C',
+ '\u010C': 'C',
+ '\u00C7': 'C',
+ '\u1E08': 'C',
+ '\u0187': 'C',
+ '\u023B': 'C',
+ '\uA73E': 'C',
+ '\u24B9': 'D',
+ '\uFF24': 'D',
+ '\u1E0A': 'D',
+ '\u010E': 'D',
+ '\u1E0C': 'D',
+ '\u1E10': 'D',
+ '\u1E12': 'D',
+ '\u1E0E': 'D',
+ '\u0110': 'D',
+ '\u018B': 'D',
+ '\u018A': 'D',
+ '\u0189': 'D',
+ '\uA779': 'D',
+ '\u01F1': 'DZ',
+ '\u01C4': 'DZ',
+ '\u01F2': 'Dz',
+ '\u01C5': 'Dz',
+ '\u24BA': 'E',
+ '\uFF25': 'E',
+ '\u00C8': 'E',
+ '\u00C9': 'E',
+ '\u00CA': 'E',
+ '\u1EC0': 'E',
+ '\u1EBE': 'E',
+ '\u1EC4': 'E',
+ '\u1EC2': 'E',
+ '\u1EBC': 'E',
+ '\u0112': 'E',
+ '\u1E14': 'E',
+ '\u1E16': 'E',
+ '\u0114': 'E',
+ '\u0116': 'E',
+ '\u00CB': 'E',
+ '\u1EBA': 'E',
+ '\u011A': 'E',
+ '\u0204': 'E',
+ '\u0206': 'E',
+ '\u1EB8': 'E',
+ '\u1EC6': 'E',
+ '\u0228': 'E',
+ '\u1E1C': 'E',
+ '\u0118': 'E',
+ '\u1E18': 'E',
+ '\u1E1A': 'E',
+ '\u0190': 'E',
+ '\u018E': 'E',
+ '\u24BB': 'F',
+ '\uFF26': 'F',
+ '\u1E1E': 'F',
+ '\u0191': 'F',
+ '\uA77B': 'F',
+ '\u24BC': 'G',
+ '\uFF27': 'G',
+ '\u01F4': 'G',
+ '\u011C': 'G',
+ '\u1E20': 'G',
+ '\u011E': 'G',
+ '\u0120': 'G',
+ '\u01E6': 'G',
+ '\u0122': 'G',
+ '\u01E4': 'G',
+ '\u0193': 'G',
+ '\uA7A0': 'G',
+ '\uA77D': 'G',
+ '\uA77E': 'G',
+ '\u24BD': 'H',
+ '\uFF28': 'H',
+ '\u0124': 'H',
+ '\u1E22': 'H',
+ '\u1E26': 'H',
+ '\u021E': 'H',
+ '\u1E24': 'H',
+ '\u1E28': 'H',
+ '\u1E2A': 'H',
+ '\u0126': 'H',
+ '\u2C67': 'H',
+ '\u2C75': 'H',
+ '\uA78D': 'H',
+ '\u24BE': 'I',
+ '\uFF29': 'I',
+ '\u00CC': 'I',
+ '\u00CD': 'I',
+ '\u00CE': 'I',
+ '\u0128': 'I',
+ '\u012A': 'I',
+ '\u012C': 'I',
+ '\u0130': 'I',
+ '\u00CF': 'I',
+ '\u1E2E': 'I',
+ '\u1EC8': 'I',
+ '\u01CF': 'I',
+ '\u0208': 'I',
+ '\u020A': 'I',
+ '\u1ECA': 'I',
+ '\u012E': 'I',
+ '\u1E2C': 'I',
+ '\u0197': 'I',
+ '\u24BF': 'J',
+ '\uFF2A': 'J',
+ '\u0134': 'J',
+ '\u0248': 'J',
+ '\u24C0': 'K',
+ '\uFF2B': 'K',
+ '\u1E30': 'K',
+ '\u01E8': 'K',
+ '\u1E32': 'K',
+ '\u0136': 'K',
+ '\u1E34': 'K',
+ '\u0198': 'K',
+ '\u2C69': 'K',
+ '\uA740': 'K',
+ '\uA742': 'K',
+ '\uA744': 'K',
+ '\uA7A2': 'K',
+ '\u24C1': 'L',
+ '\uFF2C': 'L',
+ '\u013F': 'L',
+ '\u0139': 'L',
+ '\u013D': 'L',
+ '\u1E36': 'L',
+ '\u1E38': 'L',
+ '\u013B': 'L',
+ '\u1E3C': 'L',
+ '\u1E3A': 'L',
+ '\u0141': 'L',
+ '\u023D': 'L',
+ '\u2C62': 'L',
+ '\u2C60': 'L',
+ '\uA748': 'L',
+ '\uA746': 'L',
+ '\uA780': 'L',
+ '\u01C7': 'LJ',
+ '\u01C8': 'Lj',
+ '\u24C2': 'M',
+ '\uFF2D': 'M',
+ '\u1E3E': 'M',
+ '\u1E40': 'M',
+ '\u1E42': 'M',
+ '\u2C6E': 'M',
+ '\u019C': 'M',
+ '\u24C3': 'N',
+ '\uFF2E': 'N',
+ '\u01F8': 'N',
+ '\u0143': 'N',
+ '\u00D1': 'N',
+ '\u1E44': 'N',
+ '\u0147': 'N',
+ '\u1E46': 'N',
+ '\u0145': 'N',
+ '\u1E4A': 'N',
+ '\u1E48': 'N',
+ '\u0220': 'N',
+ '\u019D': 'N',
+ '\uA790': 'N',
+ '\uA7A4': 'N',
+ '\u01CA': 'NJ',
+ '\u01CB': 'Nj',
+ '\u24C4': 'O',
+ '\uFF2F': 'O',
+ '\u00D2': 'O',
+ '\u00D3': 'O',
+ '\u00D4': 'O',
+ '\u1ED2': 'O',
+ '\u1ED0': 'O',
+ '\u1ED6': 'O',
+ '\u1ED4': 'O',
+ '\u00D5': 'O',
+ '\u1E4C': 'O',
+ '\u022C': 'O',
+ '\u1E4E': 'O',
+ '\u014C': 'O',
+ '\u1E50': 'O',
+ '\u1E52': 'O',
+ '\u014E': 'O',
+ '\u022E': 'O',
+ '\u0230': 'O',
+ '\u00D6': 'O',
+ '\u022A': 'O',
+ '\u1ECE': 'O',
+ '\u0150': 'O',
+ '\u01D1': 'O',
+ '\u020C': 'O',
+ '\u020E': 'O',
+ '\u01A0': 'O',
+ '\u1EDC': 'O',
+ '\u1EDA': 'O',
+ '\u1EE0': 'O',
+ '\u1EDE': 'O',
+ '\u1EE2': 'O',
+ '\u1ECC': 'O',
+ '\u1ED8': 'O',
+ '\u01EA': 'O',
+ '\u01EC': 'O',
+ '\u00D8': 'O',
+ '\u01FE': 'O',
+ '\u0186': 'O',
+ '\u019F': 'O',
+ '\uA74A': 'O',
+ '\uA74C': 'O',
+ '\u0152': 'OE',
+ '\u01A2': 'OI',
+ '\uA74E': 'OO',
+ '\u0222': 'OU',
+ '\u24C5': 'P',
+ '\uFF30': 'P',
+ '\u1E54': 'P',
+ '\u1E56': 'P',
+ '\u01A4': 'P',
+ '\u2C63': 'P',
+ '\uA750': 'P',
+ '\uA752': 'P',
+ '\uA754': 'P',
+ '\u24C6': 'Q',
+ '\uFF31': 'Q',
+ '\uA756': 'Q',
+ '\uA758': 'Q',
+ '\u024A': 'Q',
+ '\u24C7': 'R',
+ '\uFF32': 'R',
+ '\u0154': 'R',
+ '\u1E58': 'R',
+ '\u0158': 'R',
+ '\u0210': 'R',
+ '\u0212': 'R',
+ '\u1E5A': 'R',
+ '\u1E5C': 'R',
+ '\u0156': 'R',
+ '\u1E5E': 'R',
+ '\u024C': 'R',
+ '\u2C64': 'R',
+ '\uA75A': 'R',
+ '\uA7A6': 'R',
+ '\uA782': 'R',
+ '\u24C8': 'S',
+ '\uFF33': 'S',
+ '\u1E9E': 'S',
+ '\u015A': 'S',
+ '\u1E64': 'S',
+ '\u015C': 'S',
+ '\u1E60': 'S',
+ '\u0160': 'S',
+ '\u1E66': 'S',
+ '\u1E62': 'S',
+ '\u1E68': 'S',
+ '\u0218': 'S',
+ '\u015E': 'S',
+ '\u2C7E': 'S',
+ '\uA7A8': 'S',
+ '\uA784': 'S',
+ '\u24C9': 'T',
+ '\uFF34': 'T',
+ '\u1E6A': 'T',
+ '\u0164': 'T',
+ '\u1E6C': 'T',
+ '\u021A': 'T',
+ '\u0162': 'T',
+ '\u1E70': 'T',
+ '\u1E6E': 'T',
+ '\u0166': 'T',
+ '\u01AC': 'T',
+ '\u01AE': 'T',
+ '\u023E': 'T',
+ '\uA786': 'T',
+ '\uA728': 'TZ',
+ '\u24CA': 'U',
+ '\uFF35': 'U',
+ '\u00D9': 'U',
+ '\u00DA': 'U',
+ '\u00DB': 'U',
+ '\u0168': 'U',
+ '\u1E78': 'U',
+ '\u016A': 'U',
+ '\u1E7A': 'U',
+ '\u016C': 'U',
+ '\u00DC': 'U',
+ '\u01DB': 'U',
+ '\u01D7': 'U',
+ '\u01D5': 'U',
+ '\u01D9': 'U',
+ '\u1EE6': 'U',
+ '\u016E': 'U',
+ '\u0170': 'U',
+ '\u01D3': 'U',
+ '\u0214': 'U',
+ '\u0216': 'U',
+ '\u01AF': 'U',
+ '\u1EEA': 'U',
+ '\u1EE8': 'U',
+ '\u1EEE': 'U',
+ '\u1EEC': 'U',
+ '\u1EF0': 'U',
+ '\u1EE4': 'U',
+ '\u1E72': 'U',
+ '\u0172': 'U',
+ '\u1E76': 'U',
+ '\u1E74': 'U',
+ '\u0244': 'U',
+ '\u24CB': 'V',
+ '\uFF36': 'V',
+ '\u1E7C': 'V',
+ '\u1E7E': 'V',
+ '\u01B2': 'V',
+ '\uA75E': 'V',
+ '\u0245': 'V',
+ '\uA760': 'VY',
+ '\u24CC': 'W',
+ '\uFF37': 'W',
+ '\u1E80': 'W',
+ '\u1E82': 'W',
+ '\u0174': 'W',
+ '\u1E86': 'W',
+ '\u1E84': 'W',
+ '\u1E88': 'W',
+ '\u2C72': 'W',
+ '\u24CD': 'X',
+ '\uFF38': 'X',
+ '\u1E8A': 'X',
+ '\u1E8C': 'X',
+ '\u24CE': 'Y',
+ '\uFF39': 'Y',
+ '\u1EF2': 'Y',
+ '\u00DD': 'Y',
+ '\u0176': 'Y',
+ '\u1EF8': 'Y',
+ '\u0232': 'Y',
+ '\u1E8E': 'Y',
+ '\u0178': 'Y',
+ '\u1EF6': 'Y',
+ '\u1EF4': 'Y',
+ '\u01B3': 'Y',
+ '\u024E': 'Y',
+ '\u1EFE': 'Y',
+ '\u24CF': 'Z',
+ '\uFF3A': 'Z',
+ '\u0179': 'Z',
+ '\u1E90': 'Z',
+ '\u017B': 'Z',
+ '\u017D': 'Z',
+ '\u1E92': 'Z',
+ '\u1E94': 'Z',
+ '\u01B5': 'Z',
+ '\u0224': 'Z',
+ '\u2C7F': 'Z',
+ '\u2C6B': 'Z',
+ '\uA762': 'Z',
+ '\u24D0': 'a',
+ '\uFF41': 'a',
+ '\u1E9A': 'a',
+ '\u00E0': 'a',
+ '\u00E1': 'a',
+ '\u00E2': 'a',
+ '\u1EA7': 'a',
+ '\u1EA5': 'a',
+ '\u1EAB': 'a',
+ '\u1EA9': 'a',
+ '\u00E3': 'a',
+ '\u0101': 'a',
+ '\u0103': 'a',
+ '\u1EB1': 'a',
+ '\u1EAF': 'a',
+ '\u1EB5': 'a',
+ '\u1EB3': 'a',
+ '\u0227': 'a',
+ '\u01E1': 'a',
+ '\u00E4': 'a',
+ '\u01DF': 'a',
+ '\u1EA3': 'a',
+ '\u00E5': 'a',
+ '\u01FB': 'a',
+ '\u01CE': 'a',
+ '\u0201': 'a',
+ '\u0203': 'a',
+ '\u1EA1': 'a',
+ '\u1EAD': 'a',
+ '\u1EB7': 'a',
+ '\u1E01': 'a',
+ '\u0105': 'a',
+ '\u2C65': 'a',
+ '\u0250': 'a',
+ '\uA733': 'aa',
+ '\u00E6': 'ae',
+ '\u01FD': 'ae',
+ '\u01E3': 'ae',
+ '\uA735': 'ao',
+ '\uA737': 'au',
+ '\uA739': 'av',
+ '\uA73B': 'av',
+ '\uA73D': 'ay',
+ '\u24D1': 'b',
+ '\uFF42': 'b',
+ '\u1E03': 'b',
+ '\u1E05': 'b',
+ '\u1E07': 'b',
+ '\u0180': 'b',
+ '\u0183': 'b',
+ '\u0253': 'b',
+ '\u24D2': 'c',
+ '\uFF43': 'c',
+ '\u0107': 'c',
+ '\u0109': 'c',
+ '\u010B': 'c',
+ '\u010D': 'c',
+ '\u00E7': 'c',
+ '\u1E09': 'c',
+ '\u0188': 'c',
+ '\u023C': 'c',
+ '\uA73F': 'c',
+ '\u2184': 'c',
+ '\u24D3': 'd',
+ '\uFF44': 'd',
+ '\u1E0B': 'd',
+ '\u010F': 'd',
+ '\u1E0D': 'd',
+ '\u1E11': 'd',
+ '\u1E13': 'd',
+ '\u1E0F': 'd',
+ '\u0111': 'd',
+ '\u018C': 'd',
+ '\u0256': 'd',
+ '\u0257': 'd',
+ '\uA77A': 'd',
+ '\u01F3': 'dz',
+ '\u01C6': 'dz',
+ '\u24D4': 'e',
+ '\uFF45': 'e',
+ '\u00E8': 'e',
+ '\u00E9': 'e',
+ '\u00EA': 'e',
+ '\u1EC1': 'e',
+ '\u1EBF': 'e',
+ '\u1EC5': 'e',
+ '\u1EC3': 'e',
+ '\u1EBD': 'e',
+ '\u0113': 'e',
+ '\u1E15': 'e',
+ '\u1E17': 'e',
+ '\u0115': 'e',
+ '\u0117': 'e',
+ '\u00EB': 'e',
+ '\u1EBB': 'e',
+ '\u011B': 'e',
+ '\u0205': 'e',
+ '\u0207': 'e',
+ '\u1EB9': 'e',
+ '\u1EC7': 'e',
+ '\u0229': 'e',
+ '\u1E1D': 'e',
+ '\u0119': 'e',
+ '\u1E19': 'e',
+ '\u1E1B': 'e',
+ '\u0247': 'e',
+ '\u025B': 'e',
+ '\u01DD': 'e',
+ '\u24D5': 'f',
+ '\uFF46': 'f',
+ '\u1E1F': 'f',
+ '\u0192': 'f',
+ '\uA77C': 'f',
+ '\u24D6': 'g',
+ '\uFF47': 'g',
+ '\u01F5': 'g',
+ '\u011D': 'g',
+ '\u1E21': 'g',
+ '\u011F': 'g',
+ '\u0121': 'g',
+ '\u01E7': 'g',
+ '\u0123': 'g',
+ '\u01E5': 'g',
+ '\u0260': 'g',
+ '\uA7A1': 'g',
+ '\u1D79': 'g',
+ '\uA77F': 'g',
+ '\u24D7': 'h',
+ '\uFF48': 'h',
+ '\u0125': 'h',
+ '\u1E23': 'h',
+ '\u1E27': 'h',
+ '\u021F': 'h',
+ '\u1E25': 'h',
+ '\u1E29': 'h',
+ '\u1E2B': 'h',
+ '\u1E96': 'h',
+ '\u0127': 'h',
+ '\u2C68': 'h',
+ '\u2C76': 'h',
+ '\u0265': 'h',
+ '\u0195': 'hv',
+ '\u24D8': 'i',
+ '\uFF49': 'i',
+ '\u00EC': 'i',
+ '\u00ED': 'i',
+ '\u00EE': 'i',
+ '\u0129': 'i',
+ '\u012B': 'i',
+ '\u012D': 'i',
+ '\u00EF': 'i',
+ '\u1E2F': 'i',
+ '\u1EC9': 'i',
+ '\u01D0': 'i',
+ '\u0209': 'i',
+ '\u020B': 'i',
+ '\u1ECB': 'i',
+ '\u012F': 'i',
+ '\u1E2D': 'i',
+ '\u0268': 'i',
+ '\u0131': 'i',
+ '\u24D9': 'j',
+ '\uFF4A': 'j',
+ '\u0135': 'j',
+ '\u01F0': 'j',
+ '\u0249': 'j',
+ '\u24DA': 'k',
+ '\uFF4B': 'k',
+ '\u1E31': 'k',
+ '\u01E9': 'k',
+ '\u1E33': 'k',
+ '\u0137': 'k',
+ '\u1E35': 'k',
+ '\u0199': 'k',
+ '\u2C6A': 'k',
+ '\uA741': 'k',
+ '\uA743': 'k',
+ '\uA745': 'k',
+ '\uA7A3': 'k',
+ '\u24DB': 'l',
+ '\uFF4C': 'l',
+ '\u0140': 'l',
+ '\u013A': 'l',
+ '\u013E': 'l',
+ '\u1E37': 'l',
+ '\u1E39': 'l',
+ '\u013C': 'l',
+ '\u1E3D': 'l',
+ '\u1E3B': 'l',
+ '\u017F': 'l',
+ '\u0142': 'l',
+ '\u019A': 'l',
+ '\u026B': 'l',
+ '\u2C61': 'l',
+ '\uA749': 'l',
+ '\uA781': 'l',
+ '\uA747': 'l',
+ '\u01C9': 'lj',
+ '\u24DC': 'm',
+ '\uFF4D': 'm',
+ '\u1E3F': 'm',
+ '\u1E41': 'm',
+ '\u1E43': 'm',
+ '\u0271': 'm',
+ '\u026F': 'm',
+ '\u24DD': 'n',
+ '\uFF4E': 'n',
+ '\u01F9': 'n',
+ '\u0144': 'n',
+ '\u00F1': 'n',
+ '\u1E45': 'n',
+ '\u0148': 'n',
+ '\u1E47': 'n',
+ '\u0146': 'n',
+ '\u1E4B': 'n',
+ '\u1E49': 'n',
+ '\u019E': 'n',
+ '\u0272': 'n',
+ '\u0149': 'n',
+ '\uA791': 'n',
+ '\uA7A5': 'n',
+ '\u01CC': 'nj',
+ '\u24DE': 'o',
+ '\uFF4F': 'o',
+ '\u00F2': 'o',
+ '\u00F3': 'o',
+ '\u00F4': 'o',
+ '\u1ED3': 'o',
+ '\u1ED1': 'o',
+ '\u1ED7': 'o',
+ '\u1ED5': 'o',
+ '\u00F5': 'o',
+ '\u1E4D': 'o',
+ '\u022D': 'o',
+ '\u1E4F': 'o',
+ '\u014D': 'o',
+ '\u1E51': 'o',
+ '\u1E53': 'o',
+ '\u014F': 'o',
+ '\u022F': 'o',
+ '\u0231': 'o',
+ '\u00F6': 'o',
+ '\u022B': 'o',
+ '\u1ECF': 'o',
+ '\u0151': 'o',
+ '\u01D2': 'o',
+ '\u020D': 'o',
+ '\u020F': 'o',
+ '\u01A1': 'o',
+ '\u1EDD': 'o',
+ '\u1EDB': 'o',
+ '\u1EE1': 'o',
+ '\u1EDF': 'o',
+ '\u1EE3': 'o',
+ '\u1ECD': 'o',
+ '\u1ED9': 'o',
+ '\u01EB': 'o',
+ '\u01ED': 'o',
+ '\u00F8': 'o',
+ '\u01FF': 'o',
+ '\u0254': 'o',
+ '\uA74B': 'o',
+ '\uA74D': 'o',
+ '\u0275': 'o',
+ '\u0153': 'oe',
+ '\u01A3': 'oi',
+ '\u0223': 'ou',
+ '\uA74F': 'oo',
+ '\u24DF': 'p',
+ '\uFF50': 'p',
+ '\u1E55': 'p',
+ '\u1E57': 'p',
+ '\u01A5': 'p',
+ '\u1D7D': 'p',
+ '\uA751': 'p',
+ '\uA753': 'p',
+ '\uA755': 'p',
+ '\u24E0': 'q',
+ '\uFF51': 'q',
+ '\u024B': 'q',
+ '\uA757': 'q',
+ '\uA759': 'q',
+ '\u24E1': 'r',
+ '\uFF52': 'r',
+ '\u0155': 'r',
+ '\u1E59': 'r',
+ '\u0159': 'r',
+ '\u0211': 'r',
+ '\u0213': 'r',
+ '\u1E5B': 'r',
+ '\u1E5D': 'r',
+ '\u0157': 'r',
+ '\u1E5F': 'r',
+ '\u024D': 'r',
+ '\u027D': 'r',
+ '\uA75B': 'r',
+ '\uA7A7': 'r',
+ '\uA783': 'r',
+ '\u24E2': 's',
+ '\uFF53': 's',
+ '\u00DF': 's',
+ '\u015B': 's',
+ '\u1E65': 's',
+ '\u015D': 's',
+ '\u1E61': 's',
+ '\u0161': 's',
+ '\u1E67': 's',
+ '\u1E63': 's',
+ '\u1E69': 's',
+ '\u0219': 's',
+ '\u015F': 's',
+ '\u023F': 's',
+ '\uA7A9': 's',
+ '\uA785': 's',
+ '\u1E9B': 's',
+ '\u24E3': 't',
+ '\uFF54': 't',
+ '\u1E6B': 't',
+ '\u1E97': 't',
+ '\u0165': 't',
+ '\u1E6D': 't',
+ '\u021B': 't',
+ '\u0163': 't',
+ '\u1E71': 't',
+ '\u1E6F': 't',
+ '\u0167': 't',
+ '\u01AD': 't',
+ '\u0288': 't',
+ '\u2C66': 't',
+ '\uA787': 't',
+ '\uA729': 'tz',
+ '\u24E4': 'u',
+ '\uFF55': 'u',
+ '\u00F9': 'u',
+ '\u00FA': 'u',
+ '\u00FB': 'u',
+ '\u0169': 'u',
+ '\u1E79': 'u',
+ '\u016B': 'u',
+ '\u1E7B': 'u',
+ '\u016D': 'u',
+ '\u00FC': 'u',
+ '\u01DC': 'u',
+ '\u01D8': 'u',
+ '\u01D6': 'u',
+ '\u01DA': 'u',
+ '\u1EE7': 'u',
+ '\u016F': 'u',
+ '\u0171': 'u',
+ '\u01D4': 'u',
+ '\u0215': 'u',
+ '\u0217': 'u',
+ '\u01B0': 'u',
+ '\u1EEB': 'u',
+ '\u1EE9': 'u',
+ '\u1EEF': 'u',
+ '\u1EED': 'u',
+ '\u1EF1': 'u',
+ '\u1EE5': 'u',
+ '\u1E73': 'u',
+ '\u0173': 'u',
+ '\u1E77': 'u',
+ '\u1E75': 'u',
+ '\u0289': 'u',
+ '\u24E5': 'v',
+ '\uFF56': 'v',
+ '\u1E7D': 'v',
+ '\u1E7F': 'v',
+ '\u028B': 'v',
+ '\uA75F': 'v',
+ '\u028C': 'v',
+ '\uA761': 'vy',
+ '\u24E6': 'w',
+ '\uFF57': 'w',
+ '\u1E81': 'w',
+ '\u1E83': 'w',
+ '\u0175': 'w',
+ '\u1E87': 'w',
+ '\u1E85': 'w',
+ '\u1E98': 'w',
+ '\u1E89': 'w',
+ '\u2C73': 'w',
+ '\u24E7': 'x',
+ '\uFF58': 'x',
+ '\u1E8B': 'x',
+ '\u1E8D': 'x',
+ '\u24E8': 'y',
+ '\uFF59': 'y',
+ '\u1EF3': 'y',
+ '\u00FD': 'y',
+ '\u0177': 'y',
+ '\u1EF9': 'y',
+ '\u0233': 'y',
+ '\u1E8F': 'y',
+ '\u00FF': 'y',
+ '\u1EF7': 'y',
+ '\u1E99': 'y',
+ '\u1EF5': 'y',
+ '\u01B4': 'y',
+ '\u024F': 'y',
+ '\u1EFF': 'y',
+ '\u24E9': 'z',
+ '\uFF5A': 'z',
+ '\u017A': 'z',
+ '\u1E91': 'z',
+ '\u017C': 'z',
+ '\u017E': 'z',
+ '\u1E93': 'z',
+ '\u1E95': 'z',
+ '\u01B6': 'z',
+ '\u0225': 'z',
+ '\u0240': 'z',
+ '\u2C6C': 'z',
+ '\uA763': 'z',
+ '\u0386': '\u0391',
+ '\u0388': '\u0395',
+ '\u0389': '\u0397',
+ '\u038A': '\u0399',
+ '\u03AA': '\u0399',
+ '\u038C': '\u039F',
+ '\u038E': '\u03A5',
+ '\u03AB': '\u03A5',
+ '\u038F': '\u03A9',
+ '\u03AC': '\u03B1',
+ '\u03AD': '\u03B5',
+ '\u03AE': '\u03B7',
+ '\u03AF': '\u03B9',
+ '\u03CA': '\u03B9',
+ '\u0390': '\u03B9',
+ '\u03CC': '\u03BF',
+ '\u03CD': '\u03C5',
+ '\u03CB': '\u03C5',
+ '\u03B0': '\u03C5',
+ '\u03CE': '\u03C9',
+ '\u03C2': '\u03C3',
+ '\u2019': '\''
+ };
+
+ return diacritics;
+});
+
+S2.define('select2/data/base',[
+ '../utils'
+], function (Utils) {
+ function BaseAdapter ($element, options) {
+ BaseAdapter.__super__.constructor.call(this);
+ }
+
+ Utils.Extend(BaseAdapter, Utils.Observable);
+
+ BaseAdapter.prototype.current = function (callback) {
+ throw new Error('The `current` method must be defined in child classes.');
+ };
+
+ BaseAdapter.prototype.query = function (params, callback) {
+ throw new Error('The `query` method must be defined in child classes.');
+ };
+
+ BaseAdapter.prototype.bind = function (container, $container) {
+ // Can be implemented in subclasses
+ };
+
+ BaseAdapter.prototype.destroy = function () {
+ // Can be implemented in subclasses
+ };
+
+ BaseAdapter.prototype.generateResultId = function (container, data) {
+ var id = container.id + '-result-';
+
+ id += Utils.generateChars(4);
+
+ if (data.id != null) {
+ id += '-' + data.id.toString();
+ } else {
+ id += '-' + Utils.generateChars(4);
+ }
+ return id;
+ };
+
+ return BaseAdapter;
+});
+
+S2.define('select2/data/select',[
+ './base',
+ '../utils',
+ 'jquery'
+], function (BaseAdapter, Utils, $) {
+ function SelectAdapter ($element, options) {
+ this.$element = $element;
+ this.options = options;
+
+ SelectAdapter.__super__.constructor.call(this);
+ }
+
+ Utils.Extend(SelectAdapter, BaseAdapter);
+
+ SelectAdapter.prototype.current = function (callback) {
+ var data = [];
+ var self = this;
+
+ this.$element.find(':selected').each(function () {
+ var $option = $(this);
+
+ var option = self.item($option);
+
+ data.push(option);
+ });
+
+ callback(data);
+ };
+
+ SelectAdapter.prototype.select = function (data) {
+ var self = this;
+
+ data.selected = true;
+
+ // If data.element is a DOM node, use it instead
+ if ($(data.element).is('option')) {
+ data.element.selected = true;
+
+ this.$element.trigger('change');
+
+ return;
+ }
+
+ if (this.$element.prop('multiple')) {
+ this.current(function (currentData) {
+ var val = [];
+
+ data = [data];
+ data.push.apply(data, currentData);
+
+ for (var d = 0; d < data.length; d++) {
+ var id = data[d].id;
+
+ if ($.inArray(id, val) === -1) {
+ val.push(id);
+ }
+ }
+
+ self.$element.val(val);
+ self.$element.trigger('change');
+ });
+ } else {
+ var val = data.id;
+
+ this.$element.val(val);
+ this.$element.trigger('change');
+ }
+ };
+
+ SelectAdapter.prototype.unselect = function (data) {
+ var self = this;
+
+ if (!this.$element.prop('multiple')) {
+ return;
+ }
+
+ data.selected = false;
+
+ if ($(data.element).is('option')) {
+ data.element.selected = false;
+
+ this.$element.trigger('change');
+
+ return;
+ }
+
+ this.current(function (currentData) {
+ var val = [];
+
+ for (var d = 0; d < currentData.length; d++) {
+ var id = currentData[d].id;
+
+ if (id !== data.id && $.inArray(id, val) === -1) {
+ val.push(id);
+ }
+ }
+
+ self.$element.val(val);
+
+ self.$element.trigger('change');
+ });
+ };
+
+ SelectAdapter.prototype.bind = function (container, $container) {
+ var self = this;
+
+ this.container = container;
+
+ container.on('select', function (params) {
+ self.select(params.data);
+ });
+
+ container.on('unselect', function (params) {
+ self.unselect(params.data);
+ });
+ };
+
+ SelectAdapter.prototype.destroy = function () {
+ // Remove anything added to child elements
+ this.$element.find('*').each(function () {
+ // Remove any custom data set by Select2
+ Utils.RemoveData(this);
+ });
+ };
+
+ SelectAdapter.prototype.query = function (params, callback) {
+ var data = [];
+ var self = this;
+
+ var $options = this.$element.children();
+
+ $options.each(function () {
+ var $option = $(this);
+
+ if (!$option.is('option') && !$option.is('optgroup')) {
+ return;
+ }
+
+ var option = self.item($option);
+
+ var matches = self.matches(params, option);
+
+ if (matches !== null) {
+ data.push(matches);
+ }
+ });
+
+ callback({
+ results: data
+ });
+ };
+
+ SelectAdapter.prototype.addOptions = function ($options) {
+ Utils.appendMany(this.$element, $options);
+ };
+
+ SelectAdapter.prototype.option = function (data) {
+ var option;
+
+ if (data.children) {
+ option = document.createElement('optgroup');
+ option.label = data.text;
+ } else {
+ option = document.createElement('option');
+
+ if (option.textContent !== undefined) {
+ option.textContent = data.text;
+ } else {
+ option.innerText = data.text;
+ }
+ }
+
+ if (data.id !== undefined) {
+ option.value = data.id;
+ }
+
+ if (data.disabled) {
+ option.disabled = true;
+ }
+
+ if (data.selected) {
+ option.selected = true;
+ }
+
+ if (data.title) {
+ option.title = data.title;
+ }
+
+ var $option = $(option);
+
+ var normalizedData = this._normalizeItem(data);
+ normalizedData.element = option;
+
+ // Override the option's data with the combined data
+ Utils.StoreData(option, 'data', normalizedData);
+
+ return $option;
+ };
+
+ SelectAdapter.prototype.item = function ($option) {
+ var data = {};
+
+ data = Utils.GetData($option[0], 'data');
+
+ if (data != null) {
+ return data;
+ }
+
+ if ($option.is('option')) {
+ data = {
+ id: $option.val(),
+ text: $option.text(),
+ disabled: $option.prop('disabled'),
+ selected: $option.prop('selected'),
+ title: $option.prop('title')
+ };
+ } else if ($option.is('optgroup')) {
+ data = {
+ text: $option.prop('label'),
+ children: [],
+ title: $option.prop('title')
+ };
+
+ var $children = $option.children('option');
+ var children = [];
+
+ for (var c = 0; c < $children.length; c++) {
+ var $child = $($children[c]);
+
+ var child = this.item($child);
+
+ children.push(child);
+ }
+
+ data.children = children;
+ }
+
+ data = this._normalizeItem(data);
+ data.element = $option[0];
+
+ Utils.StoreData($option[0], 'data', data);
+
+ return data;
+ };
+
+ SelectAdapter.prototype._normalizeItem = function (item) {
+ if (item !== Object(item)) {
+ item = {
+ id: item,
+ text: item
+ };
+ }
+
+ item = $.extend({}, {
+ text: ''
+ }, item);
+
+ var defaults = {
+ selected: false,
+ disabled: false
+ };
+
+ if (item.id != null) {
+ item.id = item.id.toString();
+ }
+
+ if (item.text != null) {
+ item.text = item.text.toString();
+ }
+
+ if (item._resultId == null && item.id && this.container != null) {
+ item._resultId = this.generateResultId(this.container, item);
+ }
+
+ return $.extend({}, defaults, item);
+ };
+
+ SelectAdapter.prototype.matches = function (params, data) {
+ var matcher = this.options.get('matcher');
+
+ return matcher(params, data);
+ };
+
+ return SelectAdapter;
+});
+
+S2.define('select2/data/array',[
+ './select',
+ '../utils',
+ 'jquery'
+], function (SelectAdapter, Utils, $) {
+ function ArrayAdapter ($element, options) {
+ this._dataToConvert = options.get('data') || [];
+
+ ArrayAdapter.__super__.constructor.call(this, $element, options);
+ }
+
+ Utils.Extend(ArrayAdapter, SelectAdapter);
+
+ ArrayAdapter.prototype.bind = function (container, $container) {
+ ArrayAdapter.__super__.bind.call(this, container, $container);
+
+ this.addOptions(this.convertToOptions(this._dataToConvert));
+ };
+
+ ArrayAdapter.prototype.select = function (data) {
+ var $option = this.$element.find('option').filter(function (i, elm) {
+ return elm.value == data.id.toString();
+ });
+
+ if ($option.length === 0) {
+ $option = this.option(data);
+
+ this.addOptions($option);
+ }
+
+ ArrayAdapter.__super__.select.call(this, data);
+ };
+
+ ArrayAdapter.prototype.convertToOptions = function (data) {
+ var self = this;
+
+ var $existing = this.$element.find('option');
+ var existingIds = $existing.map(function () {
+ return self.item($(this)).id;
+ }).get();
+
+ var $options = [];
+
+ // Filter out all items except for the one passed in the argument
+ function onlyItem (item) {
+ return function () {
+ return $(this).val() == item.id;
+ };
+ }
+
+ for (var d = 0; d < data.length; d++) {
+ var item = this._normalizeItem(data[d]);
+
+ // Skip items which were pre-loaded, only merge the data
+ if ($.inArray(item.id, existingIds) >= 0) {
+ var $existingOption = $existing.filter(onlyItem(item));
+
+ var existingData = this.item($existingOption);
+ var newData = $.extend(true, {}, item, existingData);
+
+ var $newOption = this.option(newData);
+
+ $existingOption.replaceWith($newOption);
+
+ continue;
+ }
+
+ var $option = this.option(item);
+
+ if (item.children) {
+ var $children = this.convertToOptions(item.children);
+
+ Utils.appendMany($option, $children);
+ }
+
+ $options.push($option);
+ }
+
+ return $options;
+ };
+
+ return ArrayAdapter;
+});
+
+S2.define('select2/data/ajax',[
+ './array',
+ '../utils',
+ 'jquery'
+], function (ArrayAdapter, Utils, $) {
+ function AjaxAdapter ($element, options) {
+ this.ajaxOptions = this._applyDefaults(options.get('ajax'));
+
+ if (this.ajaxOptions.processResults != null) {
+ this.processResults = this.ajaxOptions.processResults;
+ }
+
+ AjaxAdapter.__super__.constructor.call(this, $element, options);
+ }
+
+ Utils.Extend(AjaxAdapter, ArrayAdapter);
+
+ AjaxAdapter.prototype._applyDefaults = function (options) {
+ var defaults = {
+ data: function (params) {
+ return $.extend({}, params, {
+ q: params.term
+ });
+ },
+ transport: function (params, success, failure) {
+ var $request = $.ajax(params);
+
+ $request.then(success);
+ $request.fail(failure);
+
+ return $request;
+ }
+ };
+
+ return $.extend({}, defaults, options, true);
+ };
+
+ AjaxAdapter.prototype.processResults = function (results) {
+ return results;
+ };
+
+ AjaxAdapter.prototype.query = function (params, callback) {
+ var matches = [];
+ var self = this;
+
+ if (this._request != null) {
+ // JSONP requests cannot always be aborted
+ if ($.isFunction(this._request.abort)) {
+ this._request.abort();
+ }
+
+ this._request = null;
+ }
+
+ var options = $.extend({
+ type: 'GET'
+ }, this.ajaxOptions);
+
+ if (typeof options.url === 'function') {
+ options.url = options.url.call(this.$element, params);
+ }
+
+ if (typeof options.data === 'function') {
+ options.data = options.data.call(this.$element, params);
+ }
+
+ function request () {
+ var $request = options.transport(options, function (data) {
+ var results = self.processResults(data, params);
+
+ if (self.options.get('debug') && window.console && console.error) {
+ // Check to make sure that the response included a `results` key.
+ if (!results || !results.results || !$.isArray(results.results)) {
+ console.error(
+ 'Select2: The AJAX results did not return an array in the ' +
+ '`results` key of the response.'
+ );
+ }
+ }
+
+ callback(results);
+ }, function () {
+ // Attempt to detect if a request was aborted
+ // Only works if the transport exposes a status property
+ if ('status' in $request &&
+ ($request.status === 0 || $request.status === '0')) {
+ return;
+ }
+
+ self.trigger('results:message', {
+ message: 'errorLoading'
+ });
+ });
+
+ self._request = $request;
+ }
+
+ if (this.ajaxOptions.delay && params.term != null) {
+ if (this._queryTimeout) {
+ window.clearTimeout(this._queryTimeout);
+ }
+
+ this._queryTimeout = window.setTimeout(request, this.ajaxOptions.delay);
+ } else {
+ request();
+ }
+ };
+
+ return AjaxAdapter;
+});
+
+S2.define('select2/data/tags',[
+ 'jquery'
+], function ($) {
+ function Tags (decorated, $element, options) {
+ var tags = options.get('tags');
+
+ var createTag = options.get('createTag');
+
+ if (createTag !== undefined) {
+ this.createTag = createTag;
+ }
+
+ var insertTag = options.get('insertTag');
+
+ if (insertTag !== undefined) {
+ this.insertTag = insertTag;
+ }
+
+ decorated.call(this, $element, options);
+
+ if ($.isArray(tags)) {
+ for (var t = 0; t < tags.length; t++) {
+ var tag = tags[t];
+ var item = this._normalizeItem(tag);
+
+ var $option = this.option(item);
+
+ this.$element.append($option);
+ }
+ }
+ }
+
+ Tags.prototype.query = function (decorated, params, callback) {
+ var self = this;
+
+ this._removeOldTags();
+
+ if (params.term == null || params.page != null) {
+ decorated.call(this, params, callback);
+ return;
+ }
+
+ function wrapper (obj, child) {
+ var data = obj.results;
+
+ for (var i = 0; i < data.length; i++) {
+ var option = data[i];
+
+ var checkChildren = (
+ option.children != null &&
+ !wrapper({
+ results: option.children
+ }, true)
+ );
+
+ var optionText = (option.text || '').toUpperCase();
+ var paramsTerm = (params.term || '').toUpperCase();
+
+ var checkText = optionText === paramsTerm;
+
+ if (checkText || checkChildren) {
+ if (child) {
+ return false;
+ }
+
+ obj.data = data;
+ callback(obj);
+
+ return;
+ }
+ }
+
+ if (child) {
+ return true;
+ }
+
+ var tag = self.createTag(params);
+
+ if (tag != null) {
+ var $option = self.option(tag);
+ $option.attr('data-select2-tag', true);
+
+ self.addOptions([$option]);
+
+ self.insertTag(data, tag);
+ }
+
+ obj.results = data;
+
+ callback(obj);
+ }
+
+ decorated.call(this, params, wrapper);
+ };
+
+ Tags.prototype.createTag = function (decorated, params) {
+ var term = $.trim(params.term);
+
+ if (term === '') {
+ return null;
+ }
+
+ return {
+ id: term,
+ text: term
+ };
+ };
+
+ Tags.prototype.insertTag = function (_, data, tag) {
+ data.unshift(tag);
+ };
+
+ Tags.prototype._removeOldTags = function (_) {
+ var $options = this.$element.find('option[data-select2-tag]');
+
+ $options.each(function () {
+ if (this.selected) {
+ return;
+ }
+
+ $(this).remove();
+ });
+ };
+
+ return Tags;
+});
+
+S2.define('select2/data/tokenizer',[
+ 'jquery'
+], function ($) {
+ function Tokenizer (decorated, $element, options) {
+ var tokenizer = options.get('tokenizer');
+
+ if (tokenizer !== undefined) {
+ this.tokenizer = tokenizer;
+ }
+
+ decorated.call(this, $element, options);
+ }
+
+ Tokenizer.prototype.bind = function (decorated, container, $container) {
+ decorated.call(this, container, $container);
+
+ this.$search = container.dropdown.$search || container.selection.$search ||
+ $container.find('.select2-search__field');
+ };
+
+ Tokenizer.prototype.query = function (decorated, params, callback) {
+ var self = this;
+
+ function createAndSelect (data) {
+ // Normalize the data object so we can use it for checks
+ var item = self._normalizeItem(data);
+
+ // Check if the data object already exists as a tag
+ // Select it if it doesn't
+ var $existingOptions = self.$element.find('option').filter(function () {
+ return $(this).val() === item.id;
+ });
+
+ // If an existing option wasn't found for it, create the option
+ if (!$existingOptions.length) {
+ var $option = self.option(item);
+ $option.attr('data-select2-tag', true);
+
+ self._removeOldTags();
+ self.addOptions([$option]);
+ }
+
+ // Select the item, now that we know there is an option for it
+ select(item);
+ }
+
+ function select (data) {
+ self.trigger('select', {
+ data: data
+ });
+ }
+
+ params.term = params.term || '';
+
+ var tokenData = this.tokenizer(params, this.options, createAndSelect);
+
+ if (tokenData.term !== params.term) {
+ // Replace the search term if we have the search box
+ if (this.$search.length) {
+ this.$search.val(tokenData.term);
+ this.$search.trigger('focus');
+ }
+
+ params.term = tokenData.term;
+ }
+
+ decorated.call(this, params, callback);
+ };
+
+ Tokenizer.prototype.tokenizer = function (_, params, options, callback) {
+ var separators = options.get('tokenSeparators') || [];
+ var term = params.term;
+ var i = 0;
+
+ var createTag = this.createTag || function (params) {
+ return {
+ id: params.term,
+ text: params.term
+ };
+ };
+
+ while (i < term.length) {
+ var termChar = term[i];
+
+ if ($.inArray(termChar, separators) === -1) {
+ i++;
+
+ continue;
+ }
+
+ var part = term.substr(0, i);
+ var partParams = $.extend({}, params, {
+ term: part
+ });
+
+ var data = createTag(partParams);
+
+ if (data == null) {
+ i++;
+ continue;
+ }
+
+ callback(data);
+
+ // Reset the term to not include the tokenized portion
+ term = term.substr(i + 1) || '';
+ i = 0;
+ }
+
+ return {
+ term: term
+ };
+ };
+
+ return Tokenizer;
+});
+
+S2.define('select2/data/minimumInputLength',[
+
+], function () {
+ function MinimumInputLength (decorated, $e, options) {
+ this.minimumInputLength = options.get('minimumInputLength');
+
+ decorated.call(this, $e, options);
+ }
+
+ MinimumInputLength.prototype.query = function (decorated, params, callback) {
+ params.term = params.term || '';
+
+ if (params.term.length < this.minimumInputLength) {
+ this.trigger('results:message', {
+ message: 'inputTooShort',
+ args: {
+ minimum: this.minimumInputLength,
+ input: params.term,
+ params: params
+ }
+ });
+
+ return;
+ }
+
+ decorated.call(this, params, callback);
+ };
+
+ return MinimumInputLength;
+});
+
+S2.define('select2/data/maximumInputLength',[
+
+], function () {
+ function MaximumInputLength (decorated, $e, options) {
+ this.maximumInputLength = options.get('maximumInputLength');
+
+ decorated.call(this, $e, options);
+ }
+
+ MaximumInputLength.prototype.query = function (decorated, params, callback) {
+ params.term = params.term || '';
+
+ if (this.maximumInputLength > 0 &&
+ params.term.length > this.maximumInputLength) {
+ this.trigger('results:message', {
+ message: 'inputTooLong',
+ args: {
+ maximum: this.maximumInputLength,
+ input: params.term,
+ params: params
+ }
+ });
+
+ return;
+ }
+
+ decorated.call(this, params, callback);
+ };
+
+ return MaximumInputLength;
+});
+
+S2.define('select2/data/maximumSelectionLength',[
+
+], function (){
+ function MaximumSelectionLength (decorated, $e, options) {
+ this.maximumSelectionLength = options.get('maximumSelectionLength');
+
+ decorated.call(this, $e, options);
+ }
+
+ MaximumSelectionLength.prototype.bind =
+ function (decorated, container, $container) {
+ var self = this;
+
+ decorated.call(this, container, $container);
+
+ container.on('select', function () {
+ self._checkIfMaximumSelected();
+ });
+ };
+
+ MaximumSelectionLength.prototype.query =
+ function (decorated, params, callback) {
+ var self = this;
+
+ this._checkIfMaximumSelected(function () {
+ decorated.call(self, params, callback);
+ });
+ };
+
+ MaximumSelectionLength.prototype._checkIfMaximumSelected =
+ function (_, successCallback) {
+ var self = this;
+
+ this.current(function (currentData) {
+ var count = currentData != null ? currentData.length : 0;
+ if (self.maximumSelectionLength > 0 &&
+ count >= self.maximumSelectionLength) {
+ self.trigger('results:message', {
+ message: 'maximumSelected',
+ args: {
+ maximum: self.maximumSelectionLength
+ }
+ });
+ return;
+ }
+
+ if (successCallback) {
+ successCallback();
+ }
+ });
+ };
+
+ return MaximumSelectionLength;
+});
+
+S2.define('select2/dropdown',[
+ 'jquery',
+ './utils'
+], function ($, Utils) {
+ function Dropdown ($element, options) {
+ this.$element = $element;
+ this.options = options;
+
+ Dropdown.__super__.constructor.call(this);
+ }
+
+ Utils.Extend(Dropdown, Utils.Observable);
+
+ Dropdown.prototype.render = function () {
+ var $dropdown = $(
+ '<span class="select2-dropdown">' +
+ '<span class="select2-results"></span>' +
+ '</span>'
+ );
+
+ $dropdown.attr('dir', this.options.get('dir'));
+
+ this.$dropdown = $dropdown;
+
+ return $dropdown;
+ };
+
+ Dropdown.prototype.bind = function () {
+ // Should be implemented in subclasses
+ };
+
+ Dropdown.prototype.position = function ($dropdown, $container) {
+ // Should be implemented in subclasses
+ };
+
+ Dropdown.prototype.destroy = function () {
+ // Remove the dropdown from the DOM
+ this.$dropdown.remove();
+ };
+
+ return Dropdown;
+});
+
+S2.define('select2/dropdown/search',[
+ 'jquery',
+ '../utils'
+], function ($, Utils) {
+ function Search () { }
+
+ Search.prototype.render = function (decorated) {
+ var $rendered = decorated.call(this);
+
+ var $search = $(
+ '<span class="select2-search select2-search--dropdown">' +
+ '<input class="select2-search__field" type="search" tabindex="-1"' +
+ ' autocomplete="off" autocorrect="off" autocapitalize="none"' +
+ ' spellcheck="false" role="searchbox" aria-autocomplete="list" />' +
+ '</span>'
+ );
+
+ this.$searchContainer = $search;
+ this.$search = $search.find('input');
+
+ $rendered.prepend($search);
+
+ return $rendered;
+ };
+
+ Search.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ var resultsId = container.id + '-results';
+
+ decorated.call(this, container, $container);
+
+ this.$search.on('keydown', function (evt) {
+ self.trigger('keypress', evt);
+
+ self._keyUpPrevented = evt.isDefaultPrevented();
+ });
+
+ // Workaround for browsers which do not support the `input` event
+ // This will prevent double-triggering of events for browsers which support
+ // both the `keyup` and `input` events.
+ this.$search.on('input', function (evt) {
+ // Unbind the duplicated `keyup` event
+ $(this).off('keyup');
+ });
+
+ this.$search.on('keyup input', function (evt) {
+ self.handleSearch(evt);
+ });
+
+ container.on('open', function () {
+ self.$search.attr('tabindex', 0);
+ self.$search.attr('aria-controls', resultsId);
+
+ self.$search.trigger('focus');
+
+ window.setTimeout(function () {
+ self.$search.trigger('focus');
+ }, 0);
+ });
+
+ container.on('close', function () {
+ self.$search.attr('tabindex', -1);
+ self.$search.removeAttr('aria-controls');
+ self.$search.removeAttr('aria-activedescendant');
+
+ self.$search.val('');
+ self.$search.trigger('blur');
+ });
+
+ container.on('focus', function () {
+ if (!container.isOpen()) {
+ self.$search.trigger('focus');
+ }
+ });
+
+ container.on('results:all', function (params) {
+ if (params.query.term == null || params.query.term === '') {
+ var showSearch = self.showSearch(params);
+
+ if (showSearch) {
+ self.$searchContainer.removeClass('select2-search--hide');
+ } else {
+ self.$searchContainer.addClass('select2-search--hide');
+ }
+ }
+ });
+
+ container.on('results:focus', function (params) {
+ if (params.data._resultId) {
+ self.$search.attr('aria-activedescendant', params.data._resultId);
+ } else {
+ self.$search.removeAttr('aria-activedescendant');
+ }
+ });
+ };
+
+ Search.prototype.handleSearch = function (evt) {
+ if (!this._keyUpPrevented) {
+ var input = this.$search.val();
+
+ this.trigger('query', {
+ term: input
+ });
+ }
+
+ this._keyUpPrevented = false;
+ };
+
+ Search.prototype.showSearch = function (_, params) {
+ return true;
+ };
+
+ return Search;
+});
+
+S2.define('select2/dropdown/hidePlaceholder',[
+
+], function () {
+ function HidePlaceholder (decorated, $element, options, dataAdapter) {
+ this.placeholder = this.normalizePlaceholder(options.get('placeholder'));
+
+ decorated.call(this, $element, options, dataAdapter);
+ }
+
+ HidePlaceholder.prototype.append = function (decorated, data) {
+ data.results = this.removePlaceholder(data.results);
+
+ decorated.call(this, data);
+ };
+
+ HidePlaceholder.prototype.normalizePlaceholder = function (_, placeholder) {
+ if (typeof placeholder === 'string') {
+ placeholder = {
+ id: '',
+ text: placeholder
+ };
+ }
+
+ return placeholder;
+ };
+
+ HidePlaceholder.prototype.removePlaceholder = function (_, data) {
+ var modifiedData = data.slice(0);
+
+ for (var d = data.length - 1; d >= 0; d--) {
+ var item = data[d];
+
+ if (this.placeholder.id === item.id) {
+ modifiedData.splice(d, 1);
+ }
+ }
+
+ return modifiedData;
+ };
+
+ return HidePlaceholder;
+});
+
+S2.define('select2/dropdown/infiniteScroll',[
+ 'jquery'
+], function ($) {
+ function InfiniteScroll (decorated, $element, options, dataAdapter) {
+ this.lastParams = {};
+
+ decorated.call(this, $element, options, dataAdapter);
+
+ this.$loadingMore = this.createLoadingMore();
+ this.loading = false;
+ }
+
+ InfiniteScroll.prototype.append = function (decorated, data) {
+ this.$loadingMore.remove();
+ this.loading = false;
+
+ decorated.call(this, data);
+
+ if (this.showLoadingMore(data)) {
+ this.$results.append(this.$loadingMore);
+ this.loadMoreIfNeeded();
+ }
+ };
+
+ InfiniteScroll.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ decorated.call(this, container, $container);
+
+ container.on('query', function (params) {
+ self.lastParams = params;
+ self.loading = true;
+ });
+
+ container.on('query:append', function (params) {
+ self.lastParams = params;
+ self.loading = true;
+ });
+
+ this.$results.on('scroll', this.loadMoreIfNeeded.bind(this));
+ };
+
+ InfiniteScroll.prototype.loadMoreIfNeeded = function () {
+ var isLoadMoreVisible = $.contains(
+ document.documentElement,
+ this.$loadingMore[0]
+ );
+
+ if (this.loading || !isLoadMoreVisible) {
+ return;
+ }
+
+ var currentOffset = this.$results.offset().top +
+ this.$results.outerHeight(false);
+ var loadingMoreOffset = this.$loadingMore.offset().top +
+ this.$loadingMore.outerHeight(false);
+
+ if (currentOffset + 50 >= loadingMoreOffset) {
+ this.loadMore();
+ }
+ };
+
+ InfiniteScroll.prototype.loadMore = function () {
+ this.loading = true;
+
+ var params = $.extend({}, {page: 1}, this.lastParams);
+
+ params.page++;
+
+ this.trigger('query:append', params);
+ };
+
+ InfiniteScroll.prototype.showLoadingMore = function (_, data) {
+ return data.pagination && data.pagination.more;
+ };
+
+ InfiniteScroll.prototype.createLoadingMore = function () {
+ var $option = $(
+ '<li ' +
+ 'class="select2-results__option select2-results__option--load-more"' +
+ 'role="option" aria-disabled="true"></li>'
+ );
+
+ var message = this.options.get('translations').get('loadingMore');
+
+ $option.html(message(this.lastParams));
+
+ return $option;
+ };
+
+ return InfiniteScroll;
+});
+
+S2.define('select2/dropdown/attachBody',[
+ 'jquery',
+ '../utils'
+], function ($, Utils) {
+ function AttachBody (decorated, $element, options) {
+ this.$dropdownParent = $(options.get('dropdownParent') || document.body);
+
+ decorated.call(this, $element, options);
+ }
+
+ AttachBody.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ decorated.call(this, container, $container);
+
+ container.on('open', function () {
+ self._showDropdown();
+ self._attachPositioningHandler(container);
+
+ // Must bind after the results handlers to ensure correct sizing
+ self._bindContainerResultHandlers(container);
+ });
+
+ container.on('close', function () {
+ self._hideDropdown();
+ self._detachPositioningHandler(container);
+ });
+
+ this.$dropdownContainer.on('mousedown', function (evt) {
+ evt.stopPropagation();
+ });
+ };
+
+ AttachBody.prototype.destroy = function (decorated) {
+ decorated.call(this);
+
+ this.$dropdownContainer.remove();
+ };
+
+ AttachBody.prototype.position = function (decorated, $dropdown, $container) {
+ // Clone all of the container classes
+ $dropdown.attr('class', $container.attr('class'));
+
+ $dropdown.removeClass('select2');
+ $dropdown.addClass('select2-container--open');
+
+ $dropdown.css({
+ position: 'absolute',
+ top: -999999
+ });
+
+ this.$container = $container;
+ };
+
+ AttachBody.prototype.render = function (decorated) {
+ var $container = $('<span></span>');
+
+ var $dropdown = decorated.call(this);
+ $container.append($dropdown);
+
+ this.$dropdownContainer = $container;
+
+ return $container;
+ };
+
+ AttachBody.prototype._hideDropdown = function (decorated) {
+ this.$dropdownContainer.detach();
+ };
+
+ AttachBody.prototype._bindContainerResultHandlers =
+ function (decorated, container) {
+
+ // These should only be bound once
+ if (this._containerResultsHandlersBound) {
+ return;
+ }
+
+ var self = this;
+
+ container.on('results:all', function () {
+ self._positionDropdown();
+ self._resizeDropdown();
+ });
+
+ container.on('results:append', function () {
+ self._positionDropdown();
+ self._resizeDropdown();
+ });
+
+ container.on('results:message', function () {
+ self._positionDropdown();
+ self._resizeDropdown();
+ });
+
+ container.on('select', function () {
+ self._positionDropdown();
+ self._resizeDropdown();
+ });
+
+ container.on('unselect', function () {
+ self._positionDropdown();
+ self._resizeDropdown();
+ });
+
+ this._containerResultsHandlersBound = true;
+ };
+
+ AttachBody.prototype._attachPositioningHandler =
+ function (decorated, container) {
+ var self = this;
+
+ var scrollEvent = 'scroll.select2.' + container.id;
+ var resizeEvent = 'resize.select2.' + container.id;
+ var orientationEvent = 'orientationchange.select2.' + container.id;
+
+ var $watchers = this.$container.parents().filter(Utils.hasScroll);
+ $watchers.each(function () {
+ Utils.StoreData(this, 'select2-scroll-position', {
+ x: $(this).scrollLeft(),
+ y: $(this).scrollTop()
+ });
+ });
+
+ $watchers.on(scrollEvent, function (ev) {
+ var position = Utils.GetData(this, 'select2-scroll-position');
+ $(this).scrollTop(position.y);
+ });
+
+ $(window).on(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent,
+ function (e) {
+ self._positionDropdown();
+ self._resizeDropdown();
+ });
+ };
+
+ AttachBody.prototype._detachPositioningHandler =
+ function (decorated, container) {
+ var scrollEvent = 'scroll.select2.' + container.id;
+ var resizeEvent = 'resize.select2.' + container.id;
+ var orientationEvent = 'orientationchange.select2.' + container.id;
+
+ var $watchers = this.$container.parents().filter(Utils.hasScroll);
+ $watchers.off(scrollEvent);
+
+ $(window).off(scrollEvent + ' ' + resizeEvent + ' ' + orientationEvent);
+ };
+
+ AttachBody.prototype._positionDropdown = function () {
+ var $window = $(window);
+
+ var isCurrentlyAbove = this.$dropdown.hasClass('select2-dropdown--above');
+ var isCurrentlyBelow = this.$dropdown.hasClass('select2-dropdown--below');
+
+ var newDirection = null;
+
+ var offset = this.$container.offset();
+
+ offset.bottom = offset.top + this.$container.outerHeight(false);
+
+ var container = {
+ height: this.$container.outerHeight(false)
+ };
+
+ container.top = offset.top;
+ container.bottom = offset.top + container.height;
+
+ var dropdown = {
+ height: this.$dropdown.outerHeight(false)
+ };
+
+ var viewport = {
+ top: $window.scrollTop(),
+ bottom: $window.scrollTop() + $window.height()
+ };
+
+ var enoughRoomAbove = viewport.top < (offset.top - dropdown.height);
+ var enoughRoomBelow = viewport.bottom > (offset.bottom + dropdown.height);
+
+ var css = {
+ left: offset.left,
+ top: container.bottom
+ };
+
+ // Determine what the parent element is to use for calculating the offset
+ var $offsetParent = this.$dropdownParent;
+
+ // For statically positioned elements, we need to get the element
+ // that is determining the offset
+ if ($offsetParent.css('position') === 'static') {
+ $offsetParent = $offsetParent.offsetParent();
+ }
+
+ var parentOffset = {
+ top: 0,
+ left: 0
+ };
+
+ if ($.contains(document.body, $offsetParent[0])) {
+ parentOffset = $offsetParent.offset();
+ }
+
+ css.top -= parentOffset.top;
+ css.left -= parentOffset.left;
+
+ if (!isCurrentlyAbove && !isCurrentlyBelow) {
+ newDirection = 'below';
+ }
+
+ if (!enoughRoomBelow && enoughRoomAbove && !isCurrentlyAbove) {
+ newDirection = 'above';
+ } else if (!enoughRoomAbove && enoughRoomBelow && isCurrentlyAbove) {
+ newDirection = 'below';
+ }
+
+ if (newDirection == 'above' ||
+ (isCurrentlyAbove && newDirection !== 'below')) {
+ css.top = container.top - parentOffset.top - dropdown.height;
+ }
+
+ if (newDirection != null) {
+ this.$dropdown
+ .removeClass('select2-dropdown--below select2-dropdown--above')
+ .addClass('select2-dropdown--' + newDirection);
+ this.$container
+ .removeClass('select2-container--below select2-container--above')
+ .addClass('select2-container--' + newDirection);
+ }
+
+ this.$dropdownContainer.css(css);
+ };
+
+ AttachBody.prototype._resizeDropdown = function () {
+ var css = {
+ width: this.$container.outerWidth(false) + 'px'
+ };
+
+ if (this.options.get('dropdownAutoWidth')) {
+ css.minWidth = css.width;
+ css.position = 'relative';
+ css.width = 'auto';
+ }
+
+ this.$dropdown.css(css);
+ };
+
+ AttachBody.prototype._showDropdown = function (decorated) {
+ this.$dropdownContainer.appendTo(this.$dropdownParent);
+
+ this._positionDropdown();
+ this._resizeDropdown();
+ };
+
+ return AttachBody;
+});
+
+S2.define('select2/dropdown/minimumResultsForSearch',[
+
+], function () {
+ function countResults (data) {
+ var count = 0;
+
+ for (var d = 0; d < data.length; d++) {
+ var item = data[d];
+
+ if (item.children) {
+ count += countResults(item.children);
+ } else {
+ count++;
+ }
+ }
+
+ return count;
+ }
+
+ function MinimumResultsForSearch (decorated, $element, options, dataAdapter) {
+ this.minimumResultsForSearch = options.get('minimumResultsForSearch');
+
+ if (this.minimumResultsForSearch < 0) {
+ this.minimumResultsForSearch = Infinity;
+ }
+
+ decorated.call(this, $element, options, dataAdapter);
+ }
+
+ MinimumResultsForSearch.prototype.showSearch = function (decorated, params) {
+ if (countResults(params.data.results) < this.minimumResultsForSearch) {
+ return false;
+ }
+
+ return decorated.call(this, params);
+ };
+
+ return MinimumResultsForSearch;
+});
+
+S2.define('select2/dropdown/selectOnClose',[
+ '../utils'
+], function (Utils) {
+ function SelectOnClose () { }
+
+ SelectOnClose.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ decorated.call(this, container, $container);
+
+ container.on('close', function (params) {
+ self._handleSelectOnClose(params);
+ });
+ };
+
+ SelectOnClose.prototype._handleSelectOnClose = function (_, params) {
+ if (params && params.originalSelect2Event != null) {
+ var event = params.originalSelect2Event;
+
+ // Don't select an item if the close event was triggered from a select or
+ // unselect event
+ if (event._type === 'select' || event._type === 'unselect') {
+ return;
+ }
+ }
+
+ var $highlightedResults = this.getHighlightedResults();
+
+ // Only select highlighted results
+ if ($highlightedResults.length < 1) {
+ return;
+ }
+
+ var data = Utils.GetData($highlightedResults[0], 'data');
+
+ // Don't re-select already selected resulte
+ if (
+ (data.element != null && data.element.selected) ||
+ (data.element == null && data.selected)
+ ) {
+ return;
+ }
+
+ this.trigger('select', {
+ data: data
+ });
+ };
+
+ return SelectOnClose;
+});
+
+S2.define('select2/dropdown/closeOnSelect',[
+
+], function () {
+ function CloseOnSelect () { }
+
+ CloseOnSelect.prototype.bind = function (decorated, container, $container) {
+ var self = this;
+
+ decorated.call(this, container, $container);
+
+ container.on('select', function (evt) {
+ self._selectTriggered(evt);
+ });
+
+ container.on('unselect', function (evt) {
+ self._selectTriggered(evt);
+ });
+ };
+
+ CloseOnSelect.prototype._selectTriggered = function (_, evt) {
+ var originalEvent = evt.originalEvent;
+
+ // Don't close if the control key is being held
+ if (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey)) {
+ return;
+ }
+
+ this.trigger('close', {
+ originalEvent: originalEvent,
+ originalSelect2Event: evt
+ });
+ };
+
+ return CloseOnSelect;
+});
+
+S2.define('select2/i18n/en',[],function () {
+ // English
+ return {
+ errorLoading: function () {
+ return 'The results could not be loaded.';
+ },
+ inputTooLong: function (args) {
+ var overChars = args.input.length - args.maximum;
+
+ var message = 'Please delete ' + overChars + ' character';
+
+ if (overChars != 1) {
+ message += 's';
+ }
+
+ return message;
+ },
+ inputTooShort: function (args) {
+ var remainingChars = args.minimum - args.input.length;
+
+ var message = 'Please enter ' + remainingChars + ' or more characters';
+
+ return message;
+ },
+ loadingMore: function () {
+ return 'Loading more results…';
+ },
+ maximumSelected: function (args) {
+ var message = 'You can only select ' + args.maximum + ' item';
+
+ if (args.maximum != 1) {
+ message += 's';
+ }
+
+ return message;
+ },
+ noResults: function () {
+ return 'No results found';
+ },
+ searching: function () {
+ return 'Searching…';
+ },
+ removeAllItems: function () {
+ return 'Remove all items';
+ }
+ };
+});
+
+S2.define('select2/defaults',[
+ 'jquery',
+ 'require',
+
+ './results',
+
+ './selection/single',
+ './selection/multiple',
+ './selection/placeholder',
+ './selection/allowClear',
+ './selection/search',
+ './selection/eventRelay',
+
+ './utils',
+ './translation',
+ './diacritics',
+
+ './data/select',
+ './data/array',
+ './data/ajax',
+ './data/tags',
+ './data/tokenizer',
+ './data/minimumInputLength',
+ './data/maximumInputLength',
+ './data/maximumSelectionLength',
+
+ './dropdown',
+ './dropdown/search',
+ './dropdown/hidePlaceholder',
+ './dropdown/infiniteScroll',
+ './dropdown/attachBody',
+ './dropdown/minimumResultsForSearch',
+ './dropdown/selectOnClose',
+ './dropdown/closeOnSelect',
+
+ './i18n/en'
+], function ($, require,
+
+ ResultsList,
+
+ SingleSelection, MultipleSelection, Placeholder, AllowClear,
+ SelectionSearch, EventRelay,
+
+ Utils, Translation, DIACRITICS,
+
+ SelectData, ArrayData, AjaxData, Tags, Tokenizer,
+ MinimumInputLength, MaximumInputLength, MaximumSelectionLength,
+
+ Dropdown, DropdownSearch, HidePlaceholder, InfiniteScroll,
+ AttachBody, MinimumResultsForSearch, SelectOnClose, CloseOnSelect,
+
+ EnglishTranslation) {
+ function Defaults () {
+ this.reset();
+ }
+
+ Defaults.prototype.apply = function (options) {
+ options = $.extend(true, {}, this.defaults, options);
+
+ if (options.dataAdapter == null) {
+ if (options.ajax != null) {
+ options.dataAdapter = AjaxData;
+ } else if (options.data != null) {
+ options.dataAdapter = ArrayData;
+ } else {
+ options.dataAdapter = SelectData;
+ }
+
+ if (options.minimumInputLength > 0) {
+ options.dataAdapter = Utils.Decorate(
+ options.dataAdapter,
+ MinimumInputLength
+ );
+ }
+
+ if (options.maximumInputLength > 0) {
+ options.dataAdapter = Utils.Decorate(
+ options.dataAdapter,
+ MaximumInputLength
+ );
+ }
+
+ if (options.maximumSelectionLength > 0) {
+ options.dataAdapter = Utils.Decorate(
+ options.dataAdapter,
+ MaximumSelectionLength
+ );
+ }
+
+ if (options.tags) {
+ options.dataAdapter = Utils.Decorate(options.dataAdapter, Tags);
+ }
+
+ if (options.tokenSeparators != null || options.tokenizer != null) {
+ options.dataAdapter = Utils.Decorate(
+ options.dataAdapter,
+ Tokenizer
+ );
+ }
+
+ if (options.query != null) {
+ var Query = require(options.amdBase + 'compat/query');
+
+ options.dataAdapter = Utils.Decorate(
+ options.dataAdapter,
+ Query
+ );
+ }
+
+ if (options.initSelection != null) {
+ var InitSelection = require(options.amdBase + 'compat/initSelection');
+
+ options.dataAdapter = Utils.Decorate(
+ options.dataAdapter,
+ InitSelection
+ );
+ }
+ }
+
+ if (options.resultsAdapter == null) {
+ options.resultsAdapter = ResultsList;
+
+ if (options.ajax != null) {
+ options.resultsAdapter = Utils.Decorate(
+ options.resultsAdapter,
+ InfiniteScroll
+ );
+ }
+
+ if (options.placeholder != null) {
+ options.resultsAdapter = Utils.Decorate(
+ options.resultsAdapter,
+ HidePlaceholder
+ );
+ }
+
+ if (options.selectOnClose) {
+ options.resultsAdapter = Utils.Decorate(
+ options.resultsAdapter,
+ SelectOnClose
+ );
+ }
+ }
+
+ if (options.dropdownAdapter == null) {
+ if (options.multiple) {
+ options.dropdownAdapter = Dropdown;
+ } else {
+ var SearchableDropdown = Utils.Decorate(Dropdown, DropdownSearch);
+
+ options.dropdownAdapter = SearchableDropdown;
+ }
+
+ if (options.minimumResultsForSearch !== 0) {
+ options.dropdownAdapter = Utils.Decorate(
+ options.dropdownAdapter,
+ MinimumResultsForSearch
+ );
+ }
+
+ if (options.closeOnSelect) {
+ options.dropdownAdapter = Utils.Decorate(
+ options.dropdownAdapter,
+ CloseOnSelect
+ );
+ }
+
+ if (
+ options.dropdownCssClass != null ||
+ options.dropdownCss != null ||
+ options.adaptDropdownCssClass != null
+ ) {
+ var DropdownCSS = require(options.amdBase + 'compat/dropdownCss');
+
+ options.dropdownAdapter = Utils.Decorate(
+ options.dropdownAdapter,
+ DropdownCSS
+ );
+ }
+
+ options.dropdownAdapter = Utils.Decorate(
+ options.dropdownAdapter,
+ AttachBody
+ );
+ }
+
+ if (options.selectionAdapter == null) {
+ if (options.multiple) {
+ options.selectionAdapter = MultipleSelection;
+ } else {
+ options.selectionAdapter = SingleSelection;
+ }
+
+ // Add the placeholder mixin if a placeholder was specified
+ if (options.placeholder != null) {
+ options.selectionAdapter = Utils.Decorate(
+ options.selectionAdapter,
+ Placeholder
+ );
+ }
+
+ if (options.allowClear) {
+ options.selectionAdapter = Utils.Decorate(
+ options.selectionAdapter,
+ AllowClear
+ );
+ }
+
+ if (options.multiple) {
+ options.selectionAdapter = Utils.Decorate(
+ options.selectionAdapter,
+ SelectionSearch
+ );
+ }
+
+ if (
+ options.containerCssClass != null ||
+ options.containerCss != null ||
+ options.adaptContainerCssClass != null
+ ) {
+ var ContainerCSS = require(options.amdBase + 'compat/containerCss');
+
+ options.selectionAdapter = Utils.Decorate(
+ options.selectionAdapter,
+ ContainerCSS
+ );
+ }
+
+ options.selectionAdapter = Utils.Decorate(
+ options.selectionAdapter,
+ EventRelay
+ );
+ }
+
+ // If the defaults were not previously applied from an element, it is
+ // possible for the language option to have not been resolved
+ options.language = this._resolveLanguage(options.language);
+
+ // Always fall back to English since it will always be complete
+ options.language.push('en');
+
+ var uniqueLanguages = [];
+
+ for (var l = 0; l < options.language.length; l++) {
+ var language = options.language[l];
+
+ if (uniqueLanguages.indexOf(language) === -1) {
+ uniqueLanguages.push(language);
+ }
+ }
+
+ options.language = uniqueLanguages;
+
+ options.translations = this._processTranslations(
+ options.language,
+ options.debug
+ );
+
+ return options;
+ };
+
+ Defaults.prototype.reset = function () {
+ function stripDiacritics (text) {
+ // Used 'uni range + named function' from http://jsperf.com/diacritics/18
+ function match(a) {
+ return DIACRITICS[a] || a;
+ }
+
+ return text.replace(/[^\u0000-\u007E]/g, match);
+ }
+
+ function matcher (params, data) {
+ // Always return the object if there is nothing to compare
+ if ($.trim(params.term) === '') {
+ return data;
+ }
+
+ // Do a recursive check for options with children
+ if (data.children && data.children.length > 0) {
+ // Clone the data object if there are children
+ // This is required as we modify the object to remove any non-matches
+ var match = $.extend(true, {}, data);
+
+ // Check each child of the option
+ for (var c = data.children.length - 1; c >= 0; c--) {
+ var child = data.children[c];
+
+ var matches = matcher(params, child);
+
+ // If there wasn't a match, remove the object in the array
+ if (matches == null) {
+ match.children.splice(c, 1);
+ }
+ }
+
+ // If any children matched, return the new object
+ if (match.children.length > 0) {
+ return match;
+ }
+
+ // If there were no matching children, check just the plain object
+ return matcher(params, match);
+ }
+
+ var original = stripDiacritics(data.text).toUpperCase();
+ var term = stripDiacritics(params.term).toUpperCase();
+
+ // Check if the text contains the term
+ if (original.indexOf(term) > -1) {
+ return data;
+ }
+
+ // If it doesn't contain the term, don't return anything
+ return null;
+ }
+
+ this.defaults = {
+ amdBase: './',
+ amdLanguageBase: './i18n/',
+ closeOnSelect: true,
+ debug: false,
+ dropdownAutoWidth: false,
+ escapeMarkup: Utils.escapeMarkup,
+ language: {},
+ matcher: matcher,
+ minimumInputLength: 0,
+ maximumInputLength: 0,
+ maximumSelectionLength: 0,
+ minimumResultsForSearch: 0,
+ selectOnClose: false,
+ scrollAfterSelect: false,
+ sorter: function (data) {
+ return data;
+ },
+ templateResult: function (result) {
+ return result.text;
+ },
+ templateSelection: function (selection) {
+ return selection.text;
+ },
+ theme: 'default',
+ width: 'resolve'
+ };
+ };
+
+ Defaults.prototype.applyFromElement = function (options, $element) {
+ var optionLanguage = options.language;
+ var defaultLanguage = this.defaults.language;
+ var elementLanguage = $element.prop('lang');
+ var parentLanguage = $element.closest('[lang]').prop('lang');
+
+ var languages = Array.prototype.concat.call(
+ this._resolveLanguage(elementLanguage),
+ this._resolveLanguage(optionLanguage),
+ this._resolveLanguage(defaultLanguage),
+ this._resolveLanguage(parentLanguage)
+ );
+
+ options.language = languages;
+
+ return options;
+ };
+
+ Defaults.prototype._resolveLanguage = function (language) {
+ if (!language) {
+ return [];
+ }
+
+ if ($.isEmptyObject(language)) {
+ return [];
+ }
+
+ if ($.isPlainObject(language)) {
+ return [language];
+ }
+
+ var languages;
+
+ if (!$.isArray(language)) {
+ languages = [language];
+ } else {
+ languages = language;
+ }
+
+ var resolvedLanguages = [];
+
+ for (var l = 0; l < languages.length; l++) {
+ resolvedLanguages.push(languages[l]);
+
+ if (typeof languages[l] === 'string' && languages[l].indexOf('-') > 0) {
+ // Extract the region information if it is included
+ var languageParts = languages[l].split('-');
+ var baseLanguage = languageParts[0];
+
+ resolvedLanguages.push(baseLanguage);
+ }
+ }
+
+ return resolvedLanguages;
+ };
+
+ Defaults.prototype._processTranslations = function (languages, debug) {
+ var translations = new Translation();
+
+ for (var l = 0; l < languages.length; l++) {
+ var languageData = new Translation();
+
+ var language = languages[l];
+
+ if (typeof language === 'string') {
+ try {
+ // Try to load it with the original name
+ languageData = Translation.loadPath(language);
+ } catch (e) {
+ try {
+ // If we couldn't load it, check if it wasn't the full path
+ language = this.defaults.amdLanguageBase + language;
+ languageData = Translation.loadPath(language);
+ } catch (ex) {
+ // The translation could not be loaded at all. Sometimes this is
+ // because of a configuration problem, other times this can be
+ // because of how Select2 helps load all possible translation files
+ if (debug && window.console && console.warn) {
+ console.warn(
+ 'Select2: The language file for "' + language + '" could ' +
+ 'not be automatically loaded. A fallback will be used instead.'
+ );
+ }
+ }
+ }
+ } else if ($.isPlainObject(language)) {
+ languageData = new Translation(language);
+ } else {
+ languageData = language;
+ }
+
+ translations.extend(languageData);
+ }
+
+ return translations;
+ };
+
+ Defaults.prototype.set = function (key, value) {
+ var camelKey = $.camelCase(key);
+
+ var data = {};
+ data[camelKey] = value;
+
+ var convertedData = Utils._convertData(data);
+
+ $.extend(true, this.defaults, convertedData);
+ };
+
+ var defaults = new Defaults();
+
+ return defaults;
+});
+
+S2.define('select2/options',[
+ 'require',
+ 'jquery',
+ './defaults',
+ './utils'
+], function (require, $, Defaults, Utils) {
+ function Options (options, $element) {
+ this.options = options;
+
+ if ($element != null) {
+ this.fromElement($element);
+ }
+
+ if ($element != null) {
+ this.options = Defaults.applyFromElement(this.options, $element);
+ }
+
+ this.options = Defaults.apply(this.options);
+
+ if ($element && $element.is('input')) {
+ var InputCompat = require(this.get('amdBase') + 'compat/inputData');
+
+ this.options.dataAdapter = Utils.Decorate(
+ this.options.dataAdapter,
+ InputCompat
+ );
+ }
+ }
+
+ Options.prototype.fromElement = function ($e) {
+ var excludedData = ['select2'];
+
+ if (this.options.multiple == null) {
+ this.options.multiple = $e.prop('multiple');
+ }
+
+ if (this.options.disabled == null) {
+ this.options.disabled = $e.prop('disabled');
+ }
+
+ if (this.options.dir == null) {
+ if ($e.prop('dir')) {
+ this.options.dir = $e.prop('dir');
+ } else if ($e.closest('[dir]').prop('dir')) {
+ this.options.dir = $e.closest('[dir]').prop('dir');
+ } else {
+ this.options.dir = 'ltr';
+ }
+ }
+
+ $e.prop('disabled', this.options.disabled);
+ $e.prop('multiple', this.options.multiple);
+
+ if (Utils.GetData($e[0], 'select2Tags')) {
+ if (this.options.debug && window.console && console.warn) {
+ console.warn(
+ 'Select2: The `data-select2-tags` attribute has been changed to ' +
+ 'use the `data-data` and `data-tags="true"` attributes and will be ' +
+ 'removed in future versions of Select2.'
+ );
+ }
+
+ Utils.StoreData($e[0], 'data', Utils.GetData($e[0], 'select2Tags'));
+ Utils.StoreData($e[0], 'tags', true);
+ }
+
+ if (Utils.GetData($e[0], 'ajaxUrl')) {
+ if (this.options.debug && window.console && console.warn) {
+ console.warn(
+ 'Select2: The `data-ajax-url` attribute has been changed to ' +
+ '`data-ajax--url` and support for the old attribute will be removed' +
+ ' in future versions of Select2.'
+ );
+ }
+
+ $e.attr('ajax--url', Utils.GetData($e[0], 'ajaxUrl'));
+ Utils.StoreData($e[0], 'ajax-Url', Utils.GetData($e[0], 'ajaxUrl'));
+ }
+
+ var dataset = {};
+
+ function upperCaseLetter(_, letter) {
+ return letter.toUpperCase();
+ }
+
+ // Pre-load all of the attributes which are prefixed with `data-`
+ for (var attr = 0; attr < $e[0].attributes.length; attr++) {
+ var attributeName = $e[0].attributes[attr].name;
+ var prefix = 'data-';
+
+ if (attributeName.substr(0, prefix.length) == prefix) {
+ // Get the contents of the attribute after `data-`
+ var dataName = attributeName.substring(prefix.length);
+
+ // Get the data contents from the consistent source
+ // This is more than likely the jQuery data helper
+ var dataValue = Utils.GetData($e[0], dataName);
+
+ // camelCase the attribute name to match the spec
+ var camelDataName = dataName.replace(/-([a-z])/g, upperCaseLetter);
+
+ // Store the data attribute contents into the dataset since
+ dataset[camelDataName] = dataValue;
+ }
+ }
+
+ // Prefer the element's `dataset` attribute if it exists
+ // jQuery 1.x does not correctly handle data attributes with multiple dashes
+ if ($.fn.jquery && $.fn.jquery.substr(0, 2) == '1.' && $e[0].dataset) {
+ dataset = $.extend(true, {}, $e[0].dataset, dataset);
+ }
+
+ // Prefer our internal data cache if it exists
+ var data = $.extend(true, {}, Utils.GetData($e[0]), dataset);
+
+ data = Utils._convertData(data);
+
+ for (var key in data) {
+ if ($.inArray(key, excludedData) > -1) {
+ continue;
+ }
+
+ if ($.isPlainObject(this.options[key])) {
+ $.extend(this.options[key], data[key]);
+ } else {
+ this.options[key] = data[key];
+ }
+ }
+
+ return this;
+ };
+
+ Options.prototype.get = function (key) {
+ return this.options[key];
+ };
+
+ Options.prototype.set = function (key, val) {
+ this.options[key] = val;
+ };
+
+ return Options;
+});
+
+S2.define('select2/core',[
+ 'jquery',
+ './options',
+ './utils',
+ './keys'
+], function ($, Options, Utils, KEYS) {
+ var Select2 = function ($element, options) {
+ if (Utils.GetData($element[0], 'select2') != null) {
+ Utils.GetData($element[0], 'select2').destroy();
+ }
+
+ this.$element = $element;
+
+ this.id = this._generateId($element);
+
+ options = options || {};
+
+ this.options = new Options(options, $element);
+
+ Select2.__super__.constructor.call(this);
+
+ // Set up the tabindex
+
+ var tabindex = $element.attr('tabindex') || 0;
+ Utils.StoreData($element[0], 'old-tabindex', tabindex);
+ $element.attr('tabindex', '-1');
+
+ // Set up containers and adapters
+
+ var DataAdapter = this.options.get('dataAdapter');
+ this.dataAdapter = new DataAdapter($element, this.options);
+
+ var $container = this.render();
+
+ this._placeContainer($container);
+
+ var SelectionAdapter = this.options.get('selectionAdapter');
+ this.selection = new SelectionAdapter($element, this.options);
+ this.$selection = this.selection.render();
+
+ this.selection.position(this.$selection, $container);
+
+ var DropdownAdapter = this.options.get('dropdownAdapter');
+ this.dropdown = new DropdownAdapter($element, this.options);
+ this.$dropdown = this.dropdown.render();
+
+ this.dropdown.position(this.$dropdown, $container);
+
+ var ResultsAdapter = this.options.get('resultsAdapter');
+ this.results = new ResultsAdapter($element, this.options, this.dataAdapter);
+ this.$results = this.results.render();
+
+ this.results.position(this.$results, this.$dropdown);
+
+ // Bind events
+
+ var self = this;
+
+ // Bind the container to all of the adapters
+ this._bindAdapters();
+
+ // Register any DOM event handlers
+ this._registerDomEvents();
+
+ // Register any internal event handlers
+ this._registerDataEvents();
+ this._registerSelectionEvents();
+ this._registerDropdownEvents();
+ this._registerResultsEvents();
+ this._registerEvents();
+
+ // Set the initial state
+ this.dataAdapter.current(function (initialData) {
+ self.trigger('selection:update', {
+ data: initialData
+ });
+ });
+
+ // Hide the original select
+ $element.addClass('select2-hidden-accessible');
+ $element.attr('aria-hidden', 'true');
+
+ // Synchronize any monitored attributes
+ this._syncAttributes();
+
+ Utils.StoreData($element[0], 'select2', this);
+
+ // Ensure backwards compatibility with $element.data('select2').
+ $element.data('select2', this);
+ };
+
+ Utils.Extend(Select2, Utils.Observable);
+
+ Select2.prototype._generateId = function ($element) {
+ var id = '';
+
+ if ($element.attr('id') != null) {
+ id = $element.attr('id');
+ } else if ($element.attr('name') != null) {
+ id = $element.attr('name') + '-' + Utils.generateChars(2);
+ } else {
+ id = Utils.generateChars(4);
+ }
+
+ id = id.replace(/(:|\.|\[|\]|,)/g, '');
+ id = 'select2-' + id;
+
+ return id;
+ };
+
+ Select2.prototype._placeContainer = function ($container) {
+ $container.insertAfter(this.$element);
+
+ var width = this._resolveWidth(this.$element, this.options.get('width'));
+
+ if (width != null) {
+ $container.css('width', width);
+ }
+ };
+
+ Select2.prototype._resolveWidth = function ($element, method) {
+ var WIDTH = /^width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i;
+
+ if (method == 'resolve') {
+ var styleWidth = this._resolveWidth($element, 'style');
+
+ if (styleWidth != null) {
+ return styleWidth;
+ }
+
+ return this._resolveWidth($element, 'element');
+ }
+
+ if (method == 'element') {
+ var elementWidth = $element.outerWidth(false);
+
+ if (elementWidth <= 0) {
+ return 'auto';
+ }
+
+ return elementWidth + 'px';
+ }
+
+ if (method == 'style') {
+ var style = $element.attr('style');
+
+ if (typeof(style) !== 'string') {
+ return null;
+ }
+
+ var attrs = style.split(';');
+
+ for (var i = 0, l = attrs.length; i < l; i = i + 1) {
+ var attr = attrs[i].replace(/\s/g, '');
+ var matches = attr.match(WIDTH);
+
+ if (matches !== null && matches.length >= 1) {
+ return matches[1];
+ }
+ }
+
+ return null;
+ }
+
+ if (method == 'computedstyle') {
+ var computedStyle = window.getComputedStyle($element[0]);
+
+ return computedStyle.width;
+ }
+
+ return method;
+ };
+
+ Select2.prototype._bindAdapters = function () {
+ this.dataAdapter.bind(this, this.$container);
+ this.selection.bind(this, this.$container);
+
+ this.dropdown.bind(this, this.$container);
+ this.results.bind(this, this.$container);
+ };
+
+ Select2.prototype._registerDomEvents = function () {
+ var self = this;
+
+ this.$element.on('change.select2', function () {
+ self.dataAdapter.current(function (data) {
+ self.trigger('selection:update', {
+ data: data
+ });
+ });
+ });
+
+ this.$element.on('focus.select2', function (evt) {
+ self.trigger('focus', evt);
+ });
+
+ this._syncA = Utils.bind(this._syncAttributes, this);
+ this._syncS = Utils.bind(this._syncSubtree, this);
+
+ if (this.$element[0].attachEvent) {
+ this.$element[0].attachEvent('onpropertychange', this._syncA);
+ }
+
+ var observer = window.MutationObserver ||
+ window.WebKitMutationObserver ||
+ window.MozMutationObserver
+ ;
+
+ if (observer != null) {
+ this._observer = new observer(function (mutations) {
+ $.each(mutations, self._syncA);
+ $.each(mutations, self._syncS);
+ });
+ this._observer.observe(this.$element[0], {
+ attributes: true,
+ childList: true,
+ subtree: false
+ });
+ } else if (this.$element[0].addEventListener) {
+ this.$element[0].addEventListener(
+ 'DOMAttrModified',
+ self._syncA,
+ false
+ );
+ this.$element[0].addEventListener(
+ 'DOMNodeInserted',
+ self._syncS,
+ false
+ );
+ this.$element[0].addEventListener(
+ 'DOMNodeRemoved',
+ self._syncS,
+ false
+ );
+ }
+ };
+
+ Select2.prototype._registerDataEvents = function () {
+ var self = this;
+
+ this.dataAdapter.on('*', function (name, params) {
+ self.trigger(name, params);
+ });
+ };
+
+ Select2.prototype._registerSelectionEvents = function () {
+ var self = this;
+ var nonRelayEvents = ['toggle', 'focus'];
+
+ this.selection.on('toggle', function () {
+ self.toggleDropdown();
+ });
+
+ this.selection.on('focus', function (params) {
+ self.focus(params);
+ });
+
+ this.selection.on('*', function (name, params) {
+ if ($.inArray(name, nonRelayEvents) !== -1) {
+ return;
+ }
+
+ self.trigger(name, params);
+ });
+ };
+
+ Select2.prototype._registerDropdownEvents = function () {
+ var self = this;
+
+ this.dropdown.on('*', function (name, params) {
+ self.trigger(name, params);
+ });
+ };
+
+ Select2.prototype._registerResultsEvents = function () {
+ var self = this;
+
+ this.results.on('*', function (name, params) {
+ self.trigger(name, params);
+ });
+ };
+
+ Select2.prototype._registerEvents = function () {
+ var self = this;
+
+ this.on('open', function () {
+ self.$container.addClass('select2-container--open');
+ });
+
+ this.on('close', function () {
+ self.$container.removeClass('select2-container--open');
+ });
+
+ this.on('enable', function () {
+ self.$container.removeClass('select2-container--disabled');
+ });
+
+ this.on('disable', function () {
+ self.$container.addClass('select2-container--disabled');
+ });
+
+ this.on('blur', function () {
+ self.$container.removeClass('select2-container--focus');
+ });
+
+ this.on('query', function (params) {
+ if (!self.isOpen()) {
+ self.trigger('open', {});
+ }
+
+ this.dataAdapter.query(params, function (data) {
+ self.trigger('results:all', {
+ data: data,
+ query: params
+ });
+ });
+ });
+
+ this.on('query:append', function (params) {
+ this.dataAdapter.query(params, function (data) {
+ self.trigger('results:append', {
+ data: data,
+ query: params
+ });
+ });
+ });
+
+ this.on('keypress', function (evt) {
+ var key = evt.which;
+
+ if (self.isOpen()) {
+ if (key === KEYS.ESC || key === KEYS.TAB ||
+ (key === KEYS.UP && evt.altKey)) {
+ self.close();
+
+ evt.preventDefault();
+ } else if (key === KEYS.ENTER) {
+ self.trigger('results:select', {});
+
+ evt.preventDefault();
+ } else if ((key === KEYS.SPACE && evt.ctrlKey)) {
+ self.trigger('results:toggle', {});
+
+ evt.preventDefault();
+ } else if (key === KEYS.UP) {
+ self.trigger('results:previous', {});
+
+ evt.preventDefault();
+ } else if (key === KEYS.DOWN) {
+ self.trigger('results:next', {});
+
+ evt.preventDefault();
+ }
+ } else {
+ if (key === KEYS.ENTER || key === KEYS.SPACE ||
+ (key === KEYS.DOWN && evt.altKey)) {
+ self.open();
+
+ evt.preventDefault();
+ }
+ }
+ });
+ };
+
+ Select2.prototype._syncAttributes = function () {
+ this.options.set('disabled', this.$element.prop('disabled'));
+
+ if (this.options.get('disabled')) {
+ if (this.isOpen()) {
+ this.close();
+ }
+
+ this.trigger('disable', {});
+ } else {
+ this.trigger('enable', {});
+ }
+ };
+
+ Select2.prototype._syncSubtree = function (evt, mutations) {
+ var changed = false;
+ var self = this;
+
+ // Ignore any mutation events raised for elements that aren't options or
+ // optgroups. This handles the case when the select element is destroyed
+ if (
+ evt && evt.target && (
+ evt.target.nodeName !== 'OPTION' && evt.target.nodeName !== 'OPTGROUP'
+ )
+ ) {
+ return;
+ }
+
+ if (!mutations) {
+ // If mutation events aren't supported, then we can only assume that the
+ // change affected the selections
+ changed = true;
+ } else if (mutations.addedNodes && mutations.addedNodes.length > 0) {
+ for (var n = 0; n < mutations.addedNodes.length; n++) {
+ var node = mutations.addedNodes[n];
+
+ if (node.selected) {
+ changed = true;
+ }
+ }
+ } else if (mutations.removedNodes && mutations.removedNodes.length > 0) {
+ changed = true;
+ }
+
+ // Only re-pull the data if we think there is a change
+ if (changed) {
+ this.dataAdapter.current(function (currentData) {
+ self.trigger('selection:update', {
+ data: currentData
+ });
+ });
+ }
+ };
+
+ /**
+ * Override the trigger method to automatically trigger pre-events when
+ * there are events that can be prevented.
+ */
+ Select2.prototype.trigger = function (name, args) {
+ var actualTrigger = Select2.__super__.trigger;
+ var preTriggerMap = {
+ 'open': 'opening',
+ 'close': 'closing',
+ 'select': 'selecting',
+ 'unselect': 'unselecting',
+ 'clear': 'clearing'
+ };
+
+ if (args === undefined) {
+ args = {};
+ }
+
+ if (name in preTriggerMap) {
+ var preTriggerName = preTriggerMap[name];
+ var preTriggerArgs = {
+ prevented: false,
+ name: name,
+ args: args
+ };
+
+ actualTrigger.call(this, preTriggerName, preTriggerArgs);
+
+ if (preTriggerArgs.prevented) {
+ args.prevented = true;
+
+ return;
+ }
+ }
+
+ actualTrigger.call(this, name, args);
+ };
+
+ Select2.prototype.toggleDropdown = function () {
+ if (this.options.get('disabled')) {
+ return;
+ }
+
+ if (this.isOpen()) {
+ this.close();
+ } else {
+ this.open();
+ }
+ };
+
+ Select2.prototype.open = function () {
+ if (this.isOpen()) {
+ return;
+ }
+
+ this.trigger('query', {});
+ };
+
+ Select2.prototype.close = function () {
+ if (!this.isOpen()) {
+ return;
+ }
+
+ this.trigger('close', {});
+ };
+
+ Select2.prototype.isOpen = function () {
+ return this.$container.hasClass('select2-container--open');
+ };
+
+ Select2.prototype.hasFocus = function () {
+ return this.$container.hasClass('select2-container--focus');
+ };
+
+ Select2.prototype.focus = function (data) {
+ // No need to re-trigger focus events if we are already focused
+ if (this.hasFocus()) {
+ return;
+ }
+
+ this.$container.addClass('select2-container--focus');
+ this.trigger('focus', {});
+ };
+
+ Select2.prototype.enable = function (args) {
+ if (this.options.get('debug') && window.console && console.warn) {
+ console.warn(
+ 'Select2: The `select2("enable")` method has been deprecated and will' +
+ ' be removed in later Select2 versions. Use $element.prop("disabled")' +
+ ' instead.'
+ );
+ }
+
+ if (args == null || args.length === 0) {
+ args = [true];
+ }
+
+ var disabled = !args[0];
+
+ this.$element.prop('disabled', disabled);
+ };
+
+ Select2.prototype.data = function () {
+ if (this.options.get('debug') &&
+ arguments.length > 0 && window.console && console.warn) {
+ console.warn(
+ 'Select2: Data can no longer be set using `select2("data")`. You ' +
+ 'should consider setting the value instead using `$element.val()`.'
+ );
+ }
+
+ var data = [];
+
+ this.dataAdapter.current(function (currentData) {
+ data = currentData;
+ });
+
+ return data;
+ };
+
+ Select2.prototype.val = function (args) {
+ if (this.options.get('debug') && window.console && console.warn) {
+ console.warn(
+ 'Select2: The `select2("val")` method has been deprecated and will be' +
+ ' removed in later Select2 versions. Use $element.val() instead.'
+ );
+ }
+
+ if (args == null || args.length === 0) {
+ return this.$element.val();
+ }
+
+ var newVal = args[0];
+
+ if ($.isArray(newVal)) {
+ newVal = $.map(newVal, function (obj) {
+ return obj.toString();
+ });
+ }
+
+ this.$element.val(newVal).trigger('change');
+ };
+
+ Select2.prototype.destroy = function () {
+ this.$container.remove();
+
+ if (this.$element[0].detachEvent) {
+ this.$element[0].detachEvent('onpropertychange', this._syncA);
+ }
+
+ if (this._observer != null) {
+ this._observer.disconnect();
+ this._observer = null;
+ } else if (this.$element[0].removeEventListener) {
+ this.$element[0]
+ .removeEventListener('DOMAttrModified', this._syncA, false);
+ this.$element[0]
+ .removeEventListener('DOMNodeInserted', this._syncS, false);
+ this.$element[0]
+ .removeEventListener('DOMNodeRemoved', this._syncS, false);
+ }
+
+ this._syncA = null;
+ this._syncS = null;
+
+ this.$element.off('.select2');
+ this.$element.attr('tabindex',
+ Utils.GetData(this.$element[0], 'old-tabindex'));
+
+ this.$element.removeClass('select2-hidden-accessible');
+ this.$element.attr('aria-hidden', 'false');
+ Utils.RemoveData(this.$element[0]);
+ this.$element.removeData('select2');
+
+ this.dataAdapter.destroy();
+ this.selection.destroy();
+ this.dropdown.destroy();
+ this.results.destroy();
+
+ this.dataAdapter = null;
+ this.selection = null;
+ this.dropdown = null;
+ this.results = null;
+ };
+
+ Select2.prototype.render = function () {
+ var $container = $(
+ '<span class="select2 select2-container">' +
+ '<span class="selection"></span>' +
+ '<span class="dropdown-wrapper" aria-hidden="true"></span>' +
+ '</span>'
+ );
+
+ $container.attr('dir', this.options.get('dir'));
+
+ this.$container = $container;
+
+ this.$container.addClass('select2-container--' + this.options.get('theme'));
+
+ Utils.StoreData($container[0], 'element', this.$element);
+
+ return $container;
+ };
+
+ return Select2;
+});
+
+S2.define('jquery-mousewheel',[
+ 'jquery'
+], function ($) {
+ // Used to shim jQuery.mousewheel for non-full builds.
+ return $;
+});
+
+S2.define('jquery.select2',[
+ 'jquery',
+ 'jquery-mousewheel',
+
+ './select2/core',
+ './select2/defaults',
+ './select2/utils'
+], function ($, _, Select2, Defaults, Utils) {
+ if ($.fn.select2 == null) {
+ // All methods that should return the element
+ var thisMethods = ['open', 'close', 'destroy'];
+
+ $.fn.select2 = function (options) {
+ options = options || {};
+
+ if (typeof options === 'object') {
+ this.each(function () {
+ var instanceOptions = $.extend(true, {}, options);
+
+ var instance = new Select2($(this), instanceOptions);
+ });
+
+ return this;
+ } else if (typeof options === 'string') {
+ var ret;
+ var args = Array.prototype.slice.call(arguments, 1);
+
+ this.each(function () {
+ var instance = Utils.GetData(this, 'select2');
+
+ if (instance == null && window.console && console.error) {
+ console.error(
+ 'The select2(\'' + options + '\') method was called on an ' +
+ 'element that is not using Select2.'
+ );
+ }
+
+ ret = instance[options].apply(instance, args);
+ });
+
+ // Check if we should be returning `this`
+ if ($.inArray(options, thisMethods) > -1) {
+ return this;
+ }
+
+ return ret;
+ } else {
+ throw new Error('Invalid arguments for Select2: ' + options);
+ }
+ };
+ }
+
+ if ($.fn.select2.defaults == null) {
+ $.fn.select2.defaults = Defaults;
+ }
+
+ return Select2;
+});
+
+ // Return the AMD loader configuration so it can be used outside of this file
+ return {
+ define: S2.define,
+ require: S2.require
+ };
+}());
+
+ // Autoload the jQuery bindings
+ // We know that all of the modules exist above this, so we're safe
+ var select2 = S2.require('jquery.select2');
+
+ // Hold the AMD module references on the jQuery function that was just loaded
+ // This allows Select2 to use the internal loader outside of this file, such
+ // as in the language files.
+ jQuery.fn.select2.amd = S2;
+
+ // Return the Select2 instance for anyone who is importing it.
+ return select2;
+}));
diff --git a/src/lib/vendor/toggle-switch.css b/src/lib/vendor/toggle-switch.css
new file mode 100644
index 0000000..1b0386e
--- /dev/null
+++ b/src/lib/vendor/toggle-switch.css
@@ -0,0 +1,310 @@
+/*
+ * CSS TOGGLE SWITCHES
+ * Unlicense
+ *
+ * Ionuț Colceriu - ghinda.net
+ * https://github.com/ghinda/css-toggle-switch
+ *
+ */
+/* Toggle Switches
+ */
+/* Shared
+ */
+/* Checkbox
+ */
+/* Radio Switch
+ */
+/* Hide by default
+ */
+.switch-toggle a, .switch-light span span {
+ display: none; }
+
+/* We can't test for a specific feature,
+ * so we only target browsers with support for media queries.
+ */
+@media only screen {
+ /* Checkbox switch
+ */
+ /* Radio switch
+ */
+ /* Standalone Themes */
+ /* Candy Theme
+ * Based on the "Sort Switches / Toggles (PSD)" by Ormal Clarck
+ * http://www.premiumpixels.com/freebies/sort-switches-toggles-psd/
+ */
+ /* Android Theme
+ */
+ /* iOS Theme
+ */
+ .switch-light {
+ display: block;
+ height: 30px;
+ /* Outline the toggles when the inputs are focused
+ */
+ position: relative;
+ overflow: visible;
+ padding: 0;
+ margin-left: 100px;
+ /* Position the label over all the elements, except the slide-button (<a>)
+ * Clicking anywhere on the label will change the switch-state
+ */
+ /* Don't hide the input from screen-readers and keyboard access
+ */ }
+ .switch-light * {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box; }
+ .switch-light a {
+ display: block;
+ -webkit-transition: all 0.3s ease-out;
+ -moz-transition: all 0.3s ease-out;
+ transition: all 0.3s ease-out; }
+ .switch-light label, .switch-light > span {
+ line-height: 30px;
+ vertical-align: middle; }
+ .switch-light input:focus ~ a, .switch-light input:focus + label {
+ outline: 1px dotted #888; }
+ .switch-light label {
+ position: relative;
+ z-index: 3;
+ display: block;
+ width: 100%; }
+ .switch-light input {
+ position: absolute;
+ opacity: 0;
+ z-index: 5; }
+ .switch-light input:checked ~ a {
+ right: 0%; }
+ .switch-light > span {
+ position: absolute;
+ left: -100px;
+ width: 100%;
+ margin: 0;
+ padding-right: 100px;
+ text-align: left; }
+ .switch-light > span span {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 5;
+ display: block;
+ width: 50%;
+ margin-left: 100px;
+ text-align: center; }
+ .switch-light > span span:last-child {
+ left: 50%; }
+ .switch-light a {
+ position: absolute;
+ right: 50%;
+ top: 0;
+ z-index: 4;
+ display: block;
+ width: 50%;
+ height: 100%;
+ padding: 0; }
+ .switch-toggle {
+ display: block;
+ height: 30px;
+ /* Outline the toggles when the inputs are focused
+ */
+ position: relative;
+ /* For callout panels in foundation
+ */
+ padding: 0 !important;
+ /* Generate styles for the multiple states */ }
+ .switch-toggle * {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box; }
+ .switch-toggle a {
+ display: block;
+ -webkit-transition: all 0.3s ease-out;
+ -moz-transition: all 0.3s ease-out;
+ transition: all 0.3s ease-out; }
+ .switch-toggle label, .switch-toggle > span {
+ line-height: 30px;
+ vertical-align: middle; }
+ .switch-toggle input:focus ~ a, .switch-toggle input:focus + label {
+ outline: 1px dotted #888; }
+ .switch-toggle input {
+ position: absolute;
+ opacity: 0; }
+ .switch-toggle input + label {
+ position: relative;
+ z-index: 2;
+ float: left;
+ width: 50%;
+ height: 100%;
+ margin: 0;
+ text-align: center; }
+ .switch-toggle a {
+ position: absolute;
+ top: 0;
+ left: 0;
+ padding: 0;
+ z-index: 1;
+ width: 50%;
+ height: 100%; }
+ .switch-toggle input:last-of-type:checked ~ a {
+ left: 50%; }
+ .switch-toggle.switch-3 label, .switch-toggle.switch-3 a {
+ width: 33.33333%; }
+ .switch-toggle.switch-3 input:checked:nth-of-type(2) ~ a {
+ left: 33.33333%; }
+ .switch-toggle.switch-3 input:checked:last-of-type ~ a {
+ left: 66.66667%; }
+ .switch-toggle.switch-4 label, .switch-toggle.switch-4 a {
+ width: 25%; }
+ .switch-toggle.switch-4 input:checked:nth-of-type(2) ~ a {
+ left: 25%; }
+ .switch-toggle.switch-4 input:checked:nth-of-type(3) ~ a {
+ left: 50%; }
+ .switch-toggle.switch-4 input:checked:last-of-type ~ a {
+ left: 75%; }
+ .switch-toggle.switch-5 label, .switch-toggle.switch-5 a {
+ width: 20%; }
+ .switch-toggle.switch-5 input:checked:nth-of-type(2) ~ a {
+ left: 20%; }
+ .switch-toggle.switch-5 input:checked:nth-of-type(3) ~ a {
+ left: 40%; }
+ .switch-toggle.switch-5 input:checked:nth-of-type(4) ~ a {
+ left: 60%; }
+ .switch-toggle.switch-5 input:checked:last-of-type ~ a {
+ left: 80%; }
+ .switch-candy {
+ background-color: #2d3035;
+ border-radius: 3px;
+ color: #fff;
+ font-weight: bold;
+ text-align: center;
+ text-shadow: 1px 1px 1px #191b1e;
+ box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.3), 0 1px 0px rgba(255, 255, 255, 0.2); }
+ .switch-candy label {
+ color: #fff;
+ -webkit-transition: color 0.2s ease-out;
+ -moz-transition: color 0.2s ease-out;
+ transition: color 0.2s ease-out; }
+ .switch-candy input:checked + label {
+ color: #333;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); }
+ .switch-candy a {
+ border: 1px solid #333;
+ background-color: #70c66b;
+ border-radius: 3px;
+ background-image: -webkit-linear-gradient(top, rgba(255, 255, 255, 0.2), rgba(0, 0, 0, 0));
+ background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0.2), rgba(0, 0, 0, 0));
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), inset 0 1px 1px rgba(255, 255, 255, 0.45); }
+ .switch-candy > span {
+ color: #333;
+ text-shadow: none; }
+ .switch-candy span {
+ color: #fff; }
+ .switch-candy.switch-candy-blue a {
+ background-color: #38a3d4; }
+ .switch-candy.switch-candy-yellow a {
+ background-color: #f5e560; }
+ .switch-android {
+ background-color: #464747;
+ border-radius: 1px;
+ color: #fff;
+ box-shadow: inset rgba(0, 0, 0, 0.1) 0 1px 0;
+ /* Selected ON switch-light
+ */ }
+ .switch-android label {
+ color: #fff; }
+ .switch-android > span span {
+ opacity: 0;
+ -webkit-transition: all 0.1s;
+ -moz-transition: all 0.1s;
+ transition: all 0.1s; }
+ .switch-android > span span:first-of-type {
+ opacity: 1; }
+ .switch-android a {
+ background-color: #666;
+ border-radius: 1px;
+ box-shadow: inset rgba(255, 255, 255, 0.2) 0 1px 0, inset rgba(0, 0, 0, 0.3) 0 -1px 0; }
+ .switch-android.switch-light input:checked ~ a {
+ background-color: #0E88B1; }
+ .switch-android.switch-light input:checked ~ span span:first-of-type {
+ opacity: 0; }
+ .switch-android.switch-light input:checked ~ span span:last-of-type {
+ opacity: 1; }
+ .switch-android.switch-toggle, .switch-android > span span {
+ font-size: 85%;
+ text-transform: uppercase; }
+ .switch-ios.switch-light {
+ color: #868686; }
+ .switch-ios.switch-light a {
+ left: 0;
+ width: 30px;
+ background-color: #fff;
+ border: 1px solid #d3d3d3;
+ border-radius: 100%;
+ -webkit-transition: all 0.3s ease-out;
+ -moz-transition: all 0.3s ease-out;
+ transition: all 0.3s ease-out;
+ box-shadow: inset 0 -3px 3px rgba(0, 0, 0, 0.025), 0 1px 4px rgba(0, 0, 0, 0.15), 0 4px 4px rgba(0, 0, 0, 0.1); }
+ .switch-ios.switch-light > span span {
+ width: 100%;
+ left: 0;
+ opacity: 0; }
+ .switch-ios.switch-light > span span:first-of-type {
+ opacity: 1;
+ padding-left: 30px; }
+ .switch-ios.switch-light > span span:last-of-type {
+ padding-right: 30px; }
+ .switch-ios.switch-light > span:before {
+ content: '';
+ display: block;
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ left: 100px;
+ top: 0;
+ background-color: #fafafa;
+ border: 1px solid #d3d3d3;
+ border-radius: 30px;
+ -webkit-transition: all 0.5s ease-out;
+ -moz-transition: all 0.5s ease-out;
+ transition: all 0.5s ease-out;
+ box-shadow: inset rgba(0, 0, 0, 0.1) 0 1px 0; }
+ .switch-ios.switch-light input:checked ~ a {
+ left: 100%;
+ margin-left: -30px; }
+ .switch-ios.switch-light input:checked ~ span:before {
+ border-color: #53d76a;
+ box-shadow: inset 0 0 0 30px #53d76a; }
+ .switch-ios.switch-light input:checked ~ span span:first-of-type {
+ opacity: 0; }
+ .switch-ios.switch-light input:checked ~ span span:last-of-type {
+ opacity: 1;
+ color: #fff; }
+ .switch-ios.switch-toggle {
+ background-color: #fafafa;
+ border: 1px solid #d3d3d3;
+ border-radius: 30px;
+ box-shadow: inset rgba(0, 0, 0, 0.1) 0 1px 0; }
+ .switch-ios.switch-toggle a {
+ background-color: #53d76a;
+ border-radius: 25px;
+ -webkit-transition: all 0.3s ease-out;
+ -moz-transition: all 0.3s ease-out;
+ transition: all 0.3s ease-out; }
+ .switch-ios.switch-toggle label {
+ color: #868686; }
+ .switch-ios input:checked + label {
+ color: #3a3a3a; } }
+
+/* Bugfix for older Webkit, including mobile Webkit. Adapted from
+ * http://css-tricks.com/webkit-sibling-bug/
+ */
+@media only screen and (-webkit-max-device-pixel-ratio: 2) and (max-device-width: 1280px) {
+ .switch-light, .switch-toggle {
+ -webkit-animation: webkitSiblingBugfix infinite 1s; } }
+
+@-webkit-keyframes webkitSiblingBugfix {
+ from {
+ -webkit-transform: translate3d(0, 0, 0); }
+
+ to {
+ -webkit-transform: translate3d(0, 0, 0); } }
diff --git a/src/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.css b/src/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.css
new file mode 100644
index 0000000..b35a240
--- /dev/null
+++ b/src/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.css
@@ -0,0 +1,388 @@
+/* This is the core CSS of Tooltipster */
+
+/* GENERAL STRUCTURE RULES (do not edit this section) */
+
+.tooltipster-base {
+ /* this ensures that a constrained height set by functionPosition,
+ if greater that the natural height of the tooltip, will be enforced
+ in browsers that support display:flex */
+ display: flex;
+ pointer-events: none;
+ /* this may be overriden in JS for fixed position origins */
+ position: absolute;
+}
+
+.tooltipster-box {
+ /* see .tooltipster-base. flex-shrink 1 is only necessary for IE10-
+ and flex-basis auto for IE11- (at least) */
+ flex: 1 1 auto;
+}
+
+.tooltipster-content {
+ /* prevents an overflow if the user adds padding to the div */
+ box-sizing: border-box;
+ /* these make sure we'll be able to detect any overflow */
+ max-height: 100%;
+ max-width: 100%;
+ overflow: auto;
+}
+
+.tooltipster-ruler {
+ /* these let us test the size of the tooltip without overflowing the window */
+ bottom: 0;
+ left: 0;
+ overflow: hidden;
+ position: fixed;
+ right: 0;
+ top: 0;
+ visibility: hidden;
+}
+
+/* ANIMATIONS */
+
+/* Open/close animations */
+
+/* fade */
+
+.tooltipster-fade {
+ opacity: 0;
+ -webkit-transition-property: opacity;
+ -moz-transition-property: opacity;
+ -o-transition-property: opacity;
+ -ms-transition-property: opacity;
+ transition-property: opacity;
+}
+.tooltipster-fade.tooltipster-show {
+ opacity: 1;
+}
+
+/* grow */
+
+.tooltipster-grow {
+ -webkit-transform: scale(0,0);
+ -moz-transform: scale(0,0);
+ -o-transform: scale(0,0);
+ -ms-transform: scale(0,0);
+ transform: scale(0,0);
+ -webkit-transition-property: -webkit-transform;
+ -moz-transition-property: -moz-transform;
+ -o-transition-property: -o-transform;
+ -ms-transition-property: -ms-transform;
+ transition-property: transform;
+ -webkit-backface-visibility: hidden;
+}
+.tooltipster-grow.tooltipster-show {
+ -webkit-transform: scale(1,1);
+ -moz-transform: scale(1,1);
+ -o-transform: scale(1,1);
+ -ms-transform: scale(1,1);
+ transform: scale(1,1);
+ -webkit-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ -webkit-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ -moz-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ -ms-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ -o-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+}
+
+/* swing */
+
+.tooltipster-swing {
+ opacity: 0;
+ -webkit-transform: rotateZ(4deg);
+ -moz-transform: rotateZ(4deg);
+ -o-transform: rotateZ(4deg);
+ -ms-transform: rotateZ(4deg);
+ transform: rotateZ(4deg);
+ -webkit-transition-property: -webkit-transform, opacity;
+ -moz-transition-property: -moz-transform;
+ -o-transition-property: -o-transform;
+ -ms-transition-property: -ms-transform;
+ transition-property: transform;
+}
+.tooltipster-swing.tooltipster-show {
+ opacity: 1;
+ -webkit-transform: rotateZ(0deg);
+ -moz-transform: rotateZ(0deg);
+ -o-transform: rotateZ(0deg);
+ -ms-transform: rotateZ(0deg);
+ transform: rotateZ(0deg);
+ -webkit-transition-timing-function: cubic-bezier(0.230, 0.635, 0.495, 1);
+ -webkit-transition-timing-function: cubic-bezier(0.230, 0.635, 0.495, 2.4);
+ -moz-transition-timing-function: cubic-bezier(0.230, 0.635, 0.495, 2.4);
+ -ms-transition-timing-function: cubic-bezier(0.230, 0.635, 0.495, 2.4);
+ -o-transition-timing-function: cubic-bezier(0.230, 0.635, 0.495, 2.4);
+ transition-timing-function: cubic-bezier(0.230, 0.635, 0.495, 2.4);
+}
+
+/* fall */
+
+.tooltipster-fall {
+ -webkit-transition-property: top;
+ -moz-transition-property: top;
+ -o-transition-property: top;
+ -ms-transition-property: top;
+ transition-property: top;
+ -webkit-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ -webkit-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ -moz-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ -ms-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ -o-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+}
+.tooltipster-fall.tooltipster-initial {
+ top: 0 !important;
+}
+.tooltipster-fall.tooltipster-show {
+}
+.tooltipster-fall.tooltipster-dying {
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -o-transition-property: all;
+ -ms-transition-property: all;
+ transition-property: all;
+ top: 0 !important;
+ opacity: 0;
+}
+
+/* slide */
+
+.tooltipster-slide {
+ -webkit-transition-property: left;
+ -moz-transition-property: left;
+ -o-transition-property: left;
+ -ms-transition-property: left;
+ transition-property: left;
+ -webkit-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ -webkit-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ -moz-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ -ms-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ -o-transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+ transition-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1.15);
+}
+.tooltipster-slide.tooltipster-initial {
+ left: -40px !important;
+}
+.tooltipster-slide.tooltipster-show {
+}
+.tooltipster-slide.tooltipster-dying {
+ -webkit-transition-property: all;
+ -moz-transition-property: all;
+ -o-transition-property: all;
+ -ms-transition-property: all;
+ transition-property: all;
+ left: 0 !important;
+ opacity: 0;
+}
+
+/* Update animations */
+
+/* We use animations rather than transitions here because
+ transition durations may be specified in the style tag due to
+ animationDuration, and we try to avoid collisions and the use
+ of !important */
+
+/* fade */
+
+@keyframes tooltipster-fading {
+ 0% {
+ opacity: 0;
+ }
+ 100% {
+ opacity: 1;
+ }
+}
+
+.tooltipster-update-fade {
+ animation: tooltipster-fading 400ms;
+}
+
+/* rotate */
+
+@keyframes tooltipster-rotating {
+ 25% {
+ transform: rotate(-2deg);
+ }
+ 75% {
+ transform: rotate(2deg);
+ }
+ 100% {
+ transform: rotate(0);
+ }
+}
+
+.tooltipster-update-rotate {
+ animation: tooltipster-rotating 600ms;
+}
+
+/* scale */
+
+@keyframes tooltipster-scaling {
+ 50% {
+ transform: scale(1.1);
+ }
+ 100% {
+ transform: scale(1);
+ }
+}
+
+.tooltipster-update-scale {
+ animation: tooltipster-scaling 600ms;
+}
+
+/**
+ * DEFAULT STYLE OF THE SIDETIP PLUGIN
+ *
+ * All styles are "namespaced" with .tooltipster-sidetip to prevent
+ * conflicts between plugins.
+ */
+
+/* .tooltipster-box */
+
+.tooltipster-sidetip .tooltipster-box {
+ background: #565656;
+ border: 2px solid black;
+ border-radius: 4px;
+}
+
+.tooltipster-sidetip.tooltipster-bottom .tooltipster-box {
+ margin-top: 8px;
+}
+
+.tooltipster-sidetip.tooltipster-left .tooltipster-box {
+ margin-right: 8px;
+}
+
+.tooltipster-sidetip.tooltipster-right .tooltipster-box {
+ margin-left: 8px;
+}
+
+.tooltipster-sidetip.tooltipster-top .tooltipster-box {
+ margin-bottom: 8px;
+}
+
+/* .tooltipster-content */
+
+.tooltipster-sidetip .tooltipster-content {
+ color: white;
+ line-height: 18px;
+ padding: 6px 14px;
+}
+
+/* .tooltipster-arrow : will keep only the zone of .tooltipster-arrow-uncropped that
+corresponds to the arrow we want to display */
+
+.tooltipster-sidetip .tooltipster-arrow {
+ overflow: hidden;
+ position: absolute;
+}
+
+.tooltipster-sidetip.tooltipster-bottom .tooltipster-arrow {
+ height: 10px;
+ /* half the width, for centering */
+ margin-left: -10px;
+ top: 0;
+ width: 20px;
+}
+
+.tooltipster-sidetip.tooltipster-left .tooltipster-arrow {
+ height: 20px;
+ margin-top: -10px;
+ right: 0;
+ /* top 0 to keep the arrow from overflowing .tooltipster-base when it has not
+ been positioned yet */
+ top: 0;
+ width: 10px;
+}
+
+.tooltipster-sidetip.tooltipster-right .tooltipster-arrow {
+ height: 20px;
+ margin-top: -10px;
+ left: 0;
+ /* same as .tooltipster-left .tooltipster-arrow */
+ top: 0;
+ width: 10px;
+}
+
+.tooltipster-sidetip.tooltipster-top .tooltipster-arrow {
+ bottom: 0;
+ height: 10px;
+ margin-left: -10px;
+ width: 20px;
+}
+
+/* common rules between .tooltipster-arrow-background and .tooltipster-arrow-border */
+
+.tooltipster-sidetip .tooltipster-arrow-background, .tooltipster-sidetip .tooltipster-arrow-border {
+ height: 0;
+ position: absolute;
+ width: 0;
+}
+
+/* .tooltipster-arrow-background */
+
+.tooltipster-sidetip .tooltipster-arrow-background {
+ border: 10px solid transparent;
+}
+
+.tooltipster-sidetip.tooltipster-bottom .tooltipster-arrow-background {
+ border-bottom-color: #565656;
+ left: 0;
+ top: 3px;
+}
+
+.tooltipster-sidetip.tooltipster-left .tooltipster-arrow-background {
+ border-left-color: #565656;
+ left: -3px;
+ top: 0;
+}
+
+.tooltipster-sidetip.tooltipster-right .tooltipster-arrow-background {
+ border-right-color: #565656;
+ left: 3px;
+ top: 0;
+}
+
+.tooltipster-sidetip.tooltipster-top .tooltipster-arrow-background {
+ border-top-color: #565656;
+ left: 0;
+ top: -3px;
+}
+
+/* .tooltipster-arrow-border */
+
+.tooltipster-sidetip .tooltipster-arrow-border {
+ border: 10px solid transparent;
+ left: 0;
+ top: 0;
+}
+
+.tooltipster-sidetip.tooltipster-bottom .tooltipster-arrow-border {
+ border-bottom-color: black;
+}
+
+.tooltipster-sidetip.tooltipster-left .tooltipster-arrow-border {
+ border-left-color: black;
+}
+
+.tooltipster-sidetip.tooltipster-right .tooltipster-arrow-border {
+ border-right-color: black;
+}
+
+.tooltipster-sidetip.tooltipster-top .tooltipster-arrow-border {
+ border-top-color: black;
+}
+
+/* tooltipster-arrow-uncropped */
+
+.tooltipster-sidetip .tooltipster-arrow-uncropped {
+ position: relative;
+}
+
+.tooltipster-sidetip.tooltipster-bottom .tooltipster-arrow-uncropped {
+ top: -10px;
+}
+
+.tooltipster-sidetip.tooltipster-right .tooltipster-arrow-uncropped {
+ left: -10px;
+}
diff --git a/src/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.js b/src/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.js
new file mode 100644
index 0000000..e2250a6
--- /dev/null
+++ b/src/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.js
@@ -0,0 +1,4273 @@
+/**
+ * tooltipster http://iamceege.github.io/tooltipster/
+ * A rockin' custom tooltip jQuery plugin
+ * Developed by Caleb Jacob and Louis Ameline
+ * MIT license
+ */
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ // AMD. Register as an anonymous module unless amdModuleId is set
+ define(["jquery"], function (a0) {
+ return (factory(a0));
+ });
+ } else if (typeof exports === 'object') {
+ // Node. Does not work with strict CommonJS, but
+ // only CommonJS-like environments that support module.exports,
+ // like Node.
+ module.exports = factory(require("jquery"));
+ } else {
+ factory(jQuery);
+ }
+}(this, function ($) {
+
+// This file will be UMDified by a build task.
+
+var defaults = {
+ animation: 'fade',
+ animationDuration: 350,
+ content: null,
+ contentAsHTML: false,
+ contentCloning: false,
+ debug: true,
+ delay: 300,
+ delayTouch: [300, 500],
+ functionInit: null,
+ functionBefore: null,
+ functionReady: null,
+ functionAfter: null,
+ functionFormat: null,
+ IEmin: 6,
+ interactive: false,
+ multiple: false,
+ // will default to document.body, or must be an element positioned at (0, 0)
+ // in the document, typically like the very top views of an app.
+ parent: null,
+ plugins: ['sideTip'],
+ repositionOnScroll: false,
+ restoration: 'none',
+ selfDestruction: true,
+ theme: [],
+ timer: 0,
+ trackerInterval: 500,
+ trackOrigin: false,
+ trackTooltip: false,
+ trigger: 'hover',
+ triggerClose: {
+ click: false,
+ mouseleave: false,
+ originClick: false,
+ scroll: false,
+ tap: false,
+ touchleave: false
+ },
+ triggerOpen: {
+ click: false,
+ mouseenter: false,
+ tap: false,
+ touchstart: false
+ },
+ updateAnimation: 'rotate',
+ zIndex: 9999999
+ },
+ // we'll avoid using the 'window' global as a good practice but npm's
+ // jquery@<2.1.0 package actually requires a 'window' global, so not sure
+ // it's useful at all
+ win = (typeof window != 'undefined') ? window : null,
+ // env will be proxied by the core for plugins to have access its properties
+ env = {
+ // detect if this device can trigger touch events. Better have a false
+ // positive (unused listeners, that's ok) than a false negative.
+ // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.js
+ // http://stackoverflow.com/questions/4817029/whats-the-best-way-to-detect-a-touch-screen-device-using-javascript
+ hasTouchCapability: !!(
+ win
+ && ( 'ontouchstart' in win
+ || (win.DocumentTouch && win.document instanceof win.DocumentTouch)
+ || win.navigator.maxTouchPoints
+ )
+ ),
+ hasTransitions: transitionSupport(),
+ IE: false,
+ // don't set manually, it will be updated by a build task after the manifest
+ semVer: '4.2.6',
+ window: win
+ },
+ core = function() {
+
+ // core variables
+
+ // the core emitters
+ this.__$emitterPrivate = $({});
+ this.__$emitterPublic = $({});
+ this.__instancesLatestArr = [];
+ // collects plugin constructors
+ this.__plugins = {};
+ // proxy env variables for plugins who might use them
+ this._env = env;
+ };
+
+// core methods
+core.prototype = {
+
+ /**
+ * A function to proxy the public methods of an object onto another
+ *
+ * @param {object} constructor The constructor to bridge
+ * @param {object} obj The object that will get new methods (an instance or the core)
+ * @param {string} pluginName A plugin name for the console log message
+ * @return {core}
+ * @private
+ */
+ __bridge: function(constructor, obj, pluginName) {
+
+ // if it's not already bridged
+ if (!obj[pluginName]) {
+
+ var fn = function() {};
+ fn.prototype = constructor;
+
+ var pluginInstance = new fn();
+
+ // the _init method has to exist in instance constructors but might be missing
+ // in core constructors
+ if (pluginInstance.__init) {
+ pluginInstance.__init(obj);
+ }
+
+ $.each(constructor, function(methodName, fn) {
+
+ // don't proxy "private" methods, only "protected" and public ones
+ if (methodName.indexOf('__') != 0) {
+
+ // if the method does not exist yet
+ if (!obj[methodName]) {
+
+ obj[methodName] = function() {
+ return pluginInstance[methodName].apply(pluginInstance, Array.prototype.slice.apply(arguments));
+ };
+
+ // remember to which plugin this method corresponds (several plugins may
+ // have methods of the same name, we need to be sure)
+ obj[methodName].bridged = pluginInstance;
+ }
+ else if (defaults.debug) {
+
+ console.log('The '+ methodName +' method of the '+ pluginName
+ +' plugin conflicts with another plugin or native methods');
+ }
+ }
+ });
+
+ obj[pluginName] = pluginInstance;
+ }
+
+ return this;
+ },
+
+ /**
+ * For mockup in Node env if need be, for testing purposes
+ *
+ * @return {core}
+ * @private
+ */
+ __setWindow: function(window) {
+ env.window = window;
+ return this;
+ },
+
+ /**
+ * Returns a ruler, a tool to help measure the size of a tooltip under
+ * various settings. Meant for plugins
+ *
+ * @see Ruler
+ * @return {object} A Ruler instance
+ * @protected
+ */
+ _getRuler: function($tooltip) {
+ return new Ruler($tooltip);
+ },
+
+ /**
+ * For internal use by plugins, if needed
+ *
+ * @return {core}
+ * @protected
+ */
+ _off: function() {
+ this.__$emitterPrivate.off.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));
+ return this;
+ },
+
+ /**
+ * For internal use by plugins, if needed
+ *
+ * @return {core}
+ * @protected
+ */
+ _on: function() {
+ this.__$emitterPrivate.on.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));
+ return this;
+ },
+
+ /**
+ * For internal use by plugins, if needed
+ *
+ * @return {core}
+ * @protected
+ */
+ _one: function() {
+ this.__$emitterPrivate.one.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));
+ return this;
+ },
+
+ /**
+ * Returns (getter) or adds (setter) a plugin
+ *
+ * @param {string|object} plugin Provide a string (in the full form
+ * "namespace.name") to use as as getter, an object to use as a setter
+ * @return {object|core}
+ * @protected
+ */
+ _plugin: function(plugin) {
+
+ var self = this;
+
+ // getter
+ if (typeof plugin == 'string') {
+
+ var pluginName = plugin,
+ p = null;
+
+ // if the namespace is provided, it's easy to search
+ if (pluginName.indexOf('.') > 0) {
+ p = self.__plugins[pluginName];
+ }
+ // otherwise, return the first name that matches
+ else {
+ $.each(self.__plugins, function(i, plugin) {
+
+ if (plugin.name.substring(plugin.name.length - pluginName.length - 1) == '.'+ pluginName) {
+ p = plugin;
+ return false;
+ }
+ });
+ }
+
+ return p;
+ }
+ // setter
+ else {
+
+ // force namespaces
+ if (plugin.name.indexOf('.') < 0) {
+ throw new Error('Plugins must be namespaced');
+ }
+
+ self.__plugins[plugin.name] = plugin;
+
+ // if the plugin has core features
+ if (plugin.core) {
+
+ // bridge non-private methods onto the core to allow new core methods
+ self.__bridge(plugin.core, self, plugin.name);
+ }
+
+ return this;
+ }
+ },
+
+ /**
+ * Trigger events on the core emitters
+ *
+ * @returns {core}
+ * @protected
+ */
+ _trigger: function() {
+
+ var args = Array.prototype.slice.apply(arguments);
+
+ if (typeof args[0] == 'string') {
+ args[0] = { type: args[0] };
+ }
+
+ // note: the order of emitters matters
+ this.__$emitterPrivate.trigger.apply(this.__$emitterPrivate, args);
+ this.__$emitterPublic.trigger.apply(this.__$emitterPublic, args);
+
+ return this;
+ },
+
+ /**
+ * Returns instances of all tooltips in the page or an a given element
+ *
+ * @param {string|HTML object collection} selector optional Use this
+ * parameter to restrict the set of objects that will be inspected
+ * for the retrieval of instances. By default, all instances in the
+ * page are returned.
+ * @return {array} An array of instance objects
+ * @public
+ */
+ instances: function(selector) {
+
+ var instances = [],
+ sel = selector || '.tooltipstered';
+
+ $(sel).each(function() {
+
+ var $this = $(this),
+ ns = $this.data('tooltipster-ns');
+
+ if (ns) {
+
+ $.each(ns, function(i, namespace) {
+ instances.push($this.data(namespace));
+ });
+ }
+ });
+
+ return instances;
+ },
+
+ /**
+ * Returns the Tooltipster objects generated by the last initializing call
+ *
+ * @return {array} An array of instance objects
+ * @public
+ */
+ instancesLatest: function() {
+ return this.__instancesLatestArr;
+ },
+
+ /**
+ * For public use only, not to be used by plugins (use ::_off() instead)
+ *
+ * @return {core}
+ * @public
+ */
+ off: function() {
+ this.__$emitterPublic.off.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));
+ return this;
+ },
+
+ /**
+ * For public use only, not to be used by plugins (use ::_on() instead)
+ *
+ * @return {core}
+ * @public
+ */
+ on: function() {
+ this.__$emitterPublic.on.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));
+ return this;
+ },
+
+ /**
+ * For public use only, not to be used by plugins (use ::_one() instead)
+ *
+ * @return {core}
+ * @public
+ */
+ one: function() {
+ this.__$emitterPublic.one.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));
+ return this;
+ },
+
+ /**
+ * Returns all HTML elements which have one or more tooltips
+ *
+ * @param {string} selector optional Use this to restrict the results
+ * to the descendants of an element
+ * @return {array} An array of HTML elements
+ * @public
+ */
+ origins: function(selector) {
+
+ var sel = selector ?
+ selector +' ' :
+ '';
+
+ return $(sel +'.tooltipstered').toArray();
+ },
+
+ /**
+ * Change default options for all future instances
+ *
+ * @param {object} d The options that should be made defaults
+ * @return {core}
+ * @public
+ */
+ setDefaults: function(d) {
+ $.extend(defaults, d);
+ return this;
+ },
+
+ /**
+ * For users to trigger their handlers on the public emitter
+ *
+ * @returns {core}
+ * @public
+ */
+ triggerHandler: function() {
+ this.__$emitterPublic.triggerHandler.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));
+ return this;
+ }
+};
+
+// $.tooltipster will be used to call core methods
+$.tooltipster = new core();
+
+// the Tooltipster instance class (mind the capital T)
+$.Tooltipster = function(element, options) {
+
+ // list of instance variables
+
+ // stack of custom callbacks provided as parameters to API methods
+ this.__callbacks = {
+ close: [],
+ open: []
+ };
+ // the schedule time of DOM removal
+ this.__closingTime;
+ // this will be the user content shown in the tooltip. A capital "C" is used
+ // because there is also a method called content()
+ this.__Content;
+ // for the size tracker
+ this.__contentBcr;
+ // to disable the tooltip after destruction
+ this.__destroyed = false;
+ // we can't emit directly on the instance because if a method with the same
+ // name as the event exists, it will be called by jQuery. Se we use a plain
+ // object as emitter. This emitter is for internal use by plugins,
+ // if needed.
+ this.__$emitterPrivate = $({});
+ // this emitter is for the user to listen to events without risking to mess
+ // with our internal listeners
+ this.__$emitterPublic = $({});
+ this.__enabled = true;
+ // the reference to the gc interval
+ this.__garbageCollector;
+ // various position and size data recomputed before each repositioning
+ this.__Geometry;
+ // the tooltip position, saved after each repositioning by a plugin
+ this.__lastPosition;
+ // a unique namespace per instance
+ this.__namespace = 'tooltipster-'+ Math.round(Math.random()*1000000);
+ this.__options;
+ // will be used to support origins in scrollable areas
+ this.__$originParents;
+ this.__pointerIsOverOrigin = false;
+ // to remove themes if needed
+ this.__previousThemes = [];
+ // the state can be either: appearing, stable, disappearing, closed
+ this.__state = 'closed';
+ // timeout references
+ this.__timeouts = {
+ close: [],
+ open: null
+ };
+ // store touch events to be able to detect emulated mouse events
+ this.__touchEvents = [];
+ // the reference to the tracker interval
+ this.__tracker = null;
+ // the element to which this tooltip is associated
+ this._$origin;
+ // this will be the tooltip element (jQuery wrapped HTML element).
+ // It's the job of a plugin to create it and append it to the DOM
+ this._$tooltip;
+
+ // launch
+ this.__init(element, options);
+};
+
+$.Tooltipster.prototype = {
+
+ /**
+ * @param origin
+ * @param options
+ * @private
+ */
+ __init: function(origin, options) {
+
+ var self = this;
+
+ self._$origin = $(origin);
+ self.__options = $.extend(true, {}, defaults, options);
+
+ // some options may need to be reformatted
+ self.__optionsFormat();
+
+ // don't run on old IE if asked no to
+ if ( !env.IE
+ || env.IE >= self.__options.IEmin
+ ) {
+
+ // note: the content is null (empty) by default and can stay that
+ // way if the plugin remains initialized but not fed any content. The
+ // tooltip will just not appear.
+
+ // let's save the initial value of the title attribute for later
+ // restoration if need be.
+ var initialTitle = null;
+
+ // it will already have been saved in case of multiple tooltips
+ if (self._$origin.data('tooltipster-initialTitle') === undefined) {
+
+ initialTitle = self._$origin.attr('title');
+
+ // we do not want initialTitle to be "undefined" because
+ // of how jQuery's .data() method works
+ if (initialTitle === undefined) initialTitle = null;
+
+ self._$origin.data('tooltipster-initialTitle', initialTitle);
+ }
+
+ // If content is provided in the options, it has precedence over the
+ // title attribute.
+ // Note: an empty string is considered content, only 'null' represents
+ // the absence of content.
+ // Also, an existing title="" attribute will result in an empty string
+ // content
+ if (self.__options.content !== null) {
+ self.__contentSet(self.__options.content);
+ }
+ else {
+
+ var selector = self._$origin.attr('data-tooltip-content'),
+ $el;
+
+ if (selector){
+ $el = $(selector);
+ }
+
+ if ($el && $el[0]) {
+ self.__contentSet($el.first());
+ }
+ else {
+ self.__contentSet(initialTitle);
+ }
+ }
+
+ self._$origin
+ // strip the title off of the element to prevent the default tooltips
+ // from popping up
+ .removeAttr('title')
+ // to be able to find all instances on the page later (upon window
+ // events in particular)
+ .addClass('tooltipstered');
+
+ // set listeners on the origin
+ self.__prepareOrigin();
+
+ // set the garbage collector
+ self.__prepareGC();
+
+ // init plugins
+ $.each(self.__options.plugins, function(i, pluginName) {
+ self._plug(pluginName);
+ });
+
+ // to detect swiping
+ if (env.hasTouchCapability) {
+ $(env.window.document.body).on('touchmove.'+ self.__namespace +'-triggerOpen', function(event) {
+ self._touchRecordEvent(event);
+ });
+ }
+
+ self
+ // prepare the tooltip when it gets created. This event must
+ // be fired by a plugin
+ ._on('created', function() {
+ self.__prepareTooltip();
+ })
+ // save position information when it's sent by a plugin
+ ._on('repositioned', function(e) {
+ self.__lastPosition = e.position;
+ });
+ }
+ else {
+ self.__options.disabled = true;
+ }
+ },
+
+ /**
+ * Insert the content into the appropriate HTML element of the tooltip
+ *
+ * @returns {self}
+ * @private
+ */
+ __contentInsert: function() {
+
+ var self = this,
+ $el = self._$tooltip.find('.tooltipster-content'),
+ formattedContent = self.__Content,
+ format = function(content) {
+ formattedContent = content;
+ };
+
+ self._trigger({
+ type: 'format',
+ content: self.__Content,
+ format: format
+ });
+
+ if (self.__options.functionFormat) {
+
+ formattedContent = self.__options.functionFormat.call(
+ self,
+ self,
+ { origin: self._$origin[0] },
+ self.__Content
+ );
+ }
+
+ if (typeof formattedContent === 'string' && !self.__options.contentAsHTML) {
+ $el.text(formattedContent);
+ }
+ else {
+ $el
+ .empty()
+ .append(formattedContent);
+ }
+
+ return self;
+ },
+
+ /**
+ * Save the content, cloning it beforehand if need be
+ *
+ * @param content
+ * @returns {self}
+ * @private
+ */
+ __contentSet: function(content) {
+
+ // clone if asked. Cloning the object makes sure that each instance has its
+ // own version of the content (in case a same object were provided for several
+ // instances)
+ // reminder: typeof null === object
+ if (content instanceof $ && this.__options.contentCloning) {
+ content = content.clone(true);
+ }
+
+ this.__Content = content;
+
+ this._trigger({
+ type: 'updated',
+ content: content
+ });
+
+ return this;
+ },
+
+ /**
+ * Error message about a method call made after destruction
+ *
+ * @private
+ */
+ __destroyError: function() {
+ throw new Error('This tooltip has been destroyed and cannot execute your method call.');
+ },
+
+ /**
+ * Gather all information about dimensions and available space,
+ * called before every repositioning
+ *
+ * @private
+ * @returns {object}
+ */
+ __geometry: function() {
+
+ var self = this,
+ $target = self._$origin,
+ originIsArea = self._$origin.is('area');
+
+ // if this._$origin is a map area, the target we'll need
+ // the dimensions of is actually the image using the map,
+ // not the area itself
+ if (originIsArea) {
+
+ var mapName = self._$origin.parent().attr('name');
+
+ $target = $('img[usemap="#'+ mapName +'"]');
+ }
+
+ var bcr = $target[0].getBoundingClientRect(),
+ $document = $(env.window.document),
+ $window = $(env.window),
+ $parent = $target,
+ // some useful properties of important elements
+ geo = {
+ // available space for the tooltip, see down below
+ available: {
+ document: null,
+ window: null
+ },
+ document: {
+ size: {
+ height: $document.height(),
+ width: $document.width()
+ }
+ },
+ window: {
+ scroll: {
+ // the second ones are for IE compatibility
+ left: env.window.scrollX || env.window.document.documentElement.scrollLeft,
+ top: env.window.scrollY || env.window.document.documentElement.scrollTop
+ },
+ size: {
+ height: $window.height(),
+ width: $window.width()
+ }
+ },
+ origin: {
+ // the origin has a fixed lineage if itself or one of its
+ // ancestors has a fixed position
+ fixedLineage: false,
+ // relative to the document
+ offset: {},
+ size: {
+ height: bcr.bottom - bcr.top,
+ width: bcr.right - bcr.left
+ },
+ usemapImage: originIsArea ? $target[0] : null,
+ // relative to the window
+ windowOffset: {
+ bottom: bcr.bottom,
+ left: bcr.left,
+ right: bcr.right,
+ top: bcr.top
+ }
+ }
+ },
+ geoFixed = false;
+
+ // if the element is a map area, some properties may need
+ // to be recalculated
+ if (originIsArea) {
+
+ var shape = self._$origin.attr('shape'),
+ coords = self._$origin.attr('coords');
+
+ if (coords) {
+
+ coords = coords.split(',');
+
+ $.map(coords, function(val, i) {
+ coords[i] = parseInt(val);
+ });
+ }
+
+ // if the image itself is the area, nothing more to do
+ if (shape != 'default') {
+
+ switch(shape) {
+
+ case 'circle':
+
+ var circleCenterLeft = coords[0],
+ circleCenterTop = coords[1],
+ circleRadius = coords[2],
+ areaTopOffset = circleCenterTop - circleRadius,
+ areaLeftOffset = circleCenterLeft - circleRadius;
+
+ geo.origin.size.height = circleRadius * 2;
+ geo.origin.size.width = geo.origin.size.height;
+
+ geo.origin.windowOffset.left += areaLeftOffset;
+ geo.origin.windowOffset.top += areaTopOffset;
+
+ break;
+
+ case 'rect':
+
+ var areaLeft = coords[0],
+ areaTop = coords[1],
+ areaRight = coords[2],
+ areaBottom = coords[3];
+
+ geo.origin.size.height = areaBottom - areaTop;
+ geo.origin.size.width = areaRight - areaLeft;
+
+ geo.origin.windowOffset.left += areaLeft;
+ geo.origin.windowOffset.top += areaTop;
+
+ break;
+
+ case 'poly':
+
+ var areaSmallestX = 0,
+ areaSmallestY = 0,
+ areaGreatestX = 0,
+ areaGreatestY = 0,
+ arrayAlternate = 'even';
+
+ for (var i = 0; i < coords.length; i++) {
+
+ var areaNumber = coords[i];
+
+ if (arrayAlternate == 'even') {
+
+ if (areaNumber > areaGreatestX) {
+
+ areaGreatestX = areaNumber;
+
+ if (i === 0) {
+ areaSmallestX = areaGreatestX;
+ }
+ }
+
+ if (areaNumber < areaSmallestX) {
+ areaSmallestX = areaNumber;
+ }
+
+ arrayAlternate = 'odd';
+ }
+ else {
+ if (areaNumber > areaGreatestY) {
+
+ areaGreatestY = areaNumber;
+
+ if (i == 1) {
+ areaSmallestY = areaGreatestY;
+ }
+ }
+
+ if (areaNumber < areaSmallestY) {
+ areaSmallestY = areaNumber;
+ }
+
+ arrayAlternate = 'even';
+ }
+ }
+
+ geo.origin.size.height = areaGreatestY - areaSmallestY;
+ geo.origin.size.width = areaGreatestX - areaSmallestX;
+
+ geo.origin.windowOffset.left += areaSmallestX;
+ geo.origin.windowOffset.top += areaSmallestY;
+
+ break;
+ }
+ }
+ }
+
+ // user callback through an event
+ var edit = function(r) {
+ geo.origin.size.height = r.height,
+ geo.origin.windowOffset.left = r.left,
+ geo.origin.windowOffset.top = r.top,
+ geo.origin.size.width = r.width
+ };
+
+ self._trigger({
+ type: 'geometry',
+ edit: edit,
+ geometry: {
+ height: geo.origin.size.height,
+ left: geo.origin.windowOffset.left,
+ top: geo.origin.windowOffset.top,
+ width: geo.origin.size.width
+ }
+ });
+
+ // calculate the remaining properties with what we got
+
+ geo.origin.windowOffset.right = geo.origin.windowOffset.left + geo.origin.size.width;
+ geo.origin.windowOffset.bottom = geo.origin.windowOffset.top + geo.origin.size.height;
+
+ geo.origin.offset.left = geo.origin.windowOffset.left + geo.window.scroll.left;
+ geo.origin.offset.top = geo.origin.windowOffset.top + geo.window.scroll.top;
+ geo.origin.offset.bottom = geo.origin.offset.top + geo.origin.size.height;
+ geo.origin.offset.right = geo.origin.offset.left + geo.origin.size.width;
+
+ // the space that is available to display the tooltip relatively to the document
+ geo.available.document = {
+ bottom: {
+ height: geo.document.size.height - geo.origin.offset.bottom,
+ width: geo.document.size.width
+ },
+ left: {
+ height: geo.document.size.height,
+ width: geo.origin.offset.left
+ },
+ right: {
+ height: geo.document.size.height,
+ width: geo.document.size.width - geo.origin.offset.right
+ },
+ top: {
+ height: geo.origin.offset.top,
+ width: geo.document.size.width
+ }
+ };
+
+ // the space that is available to display the tooltip relatively to the viewport
+ // (the resulting values may be negative if the origin overflows the viewport)
+ geo.available.window = {
+ bottom: {
+ // the inner max is here to make sure the available height is no bigger
+ // than the viewport height (when the origin is off screen at the top).
+ // The outer max just makes sure that the height is not negative (when
+ // the origin overflows at the bottom).
+ height: Math.max(geo.window.size.height - Math.max(geo.origin.windowOffset.bottom, 0), 0),
+ width: geo.window.size.width
+ },
+ left: {
+ height: geo.window.size.height,
+ width: Math.max(geo.origin.windowOffset.left, 0)
+ },
+ right: {
+ height: geo.window.size.height,
+ width: Math.max(geo.window.size.width - Math.max(geo.origin.windowOffset.right, 0), 0)
+ },
+ top: {
+ height: Math.max(geo.origin.windowOffset.top, 0),
+ width: geo.window.size.width
+ }
+ };
+
+ while ($parent[0].tagName.toLowerCase() != 'html') {
+
+ if ($parent.css('position') == 'fixed') {
+ geo.origin.fixedLineage = true;
+ break;
+ }
+
+ $parent = $parent.parent();
+ }
+
+ return geo;
+ },
+
+ /**
+ * Some options may need to be formated before being used
+ *
+ * @returns {self}
+ * @private
+ */
+ __optionsFormat: function() {
+
+ if (typeof this.__options.animationDuration == 'number') {
+ this.__options.animationDuration = [this.__options.animationDuration, this.__options.animationDuration];
+ }
+
+ if (typeof this.__options.delay == 'number') {
+ this.__options.delay = [this.__options.delay, this.__options.delay];
+ }
+
+ if (typeof this.__options.delayTouch == 'number') {
+ this.__options.delayTouch = [this.__options.delayTouch, this.__options.delayTouch];
+ }
+
+ if (typeof this.__options.theme == 'string') {
+ this.__options.theme = [this.__options.theme];
+ }
+
+ // determine the future parent
+ if (this.__options.parent === null) {
+ this.__options.parent = $(env.window.document.body);
+ }
+ else if (typeof this.__options.parent == 'string') {
+ this.__options.parent = $(this.__options.parent);
+ }
+
+ if (this.__options.trigger == 'hover') {
+
+ this.__options.triggerOpen = {
+ mouseenter: true,
+ touchstart: true
+ };
+
+ this.__options.triggerClose = {
+ mouseleave: true,
+ originClick: true,
+ touchleave: true
+ };
+ }
+ else if (this.__options.trigger == 'click') {
+
+ this.__options.triggerOpen = {
+ click: true,
+ tap: true
+ };
+
+ this.__options.triggerClose = {
+ click: true,
+ tap: true
+ };
+ }
+
+ // for the plugins
+ this._trigger('options');
+
+ return this;
+ },
+
+ /**
+ * Schedules or cancels the garbage collector task
+ *
+ * @returns {self}
+ * @private
+ */
+ __prepareGC: function() {
+
+ var self = this;
+
+ // in case the selfDestruction option has been changed by a method call
+ if (self.__options.selfDestruction) {
+
+ // the GC task
+ self.__garbageCollector = setInterval(function() {
+
+ var now = new Date().getTime();
+
+ // forget the old events
+ self.__touchEvents = $.grep(self.__touchEvents, function(event, i) {
+ // 1 minute
+ return now - event.time > 60000;
+ });
+
+ // auto-destruct if the origin is gone
+ if (!bodyContains(self._$origin)) {
+
+ self.close(function(){
+ self.destroy();
+ });
+ }
+ }, 20000);
+ }
+ else {
+ clearInterval(self.__garbageCollector);
+ }
+
+ return self;
+ },
+
+ /**
+ * Sets listeners on the origin if the open triggers require them.
+ * Unlike the listeners set at opening time, these ones
+ * remain even when the tooltip is closed. It has been made a
+ * separate method so it can be called when the triggers are
+ * changed in the options. Closing is handled in _open()
+ * because of the bindings that may be needed on the tooltip
+ * itself
+ *
+ * @returns {self}
+ * @private
+ */
+ __prepareOrigin: function() {
+
+ var self = this;
+
+ // in case we're resetting the triggers
+ self._$origin.off('.'+ self.__namespace +'-triggerOpen');
+
+ // if the device is touch capable, even if only mouse triggers
+ // are asked, we need to listen to touch events to know if the mouse
+ // events are actually emulated (so we can ignore them)
+ if (env.hasTouchCapability) {
+
+ self._$origin.on(
+ 'touchstart.'+ self.__namespace +'-triggerOpen ' +
+ 'touchend.'+ self.__namespace +'-triggerOpen ' +
+ 'touchcancel.'+ self.__namespace +'-triggerOpen',
+ function(event){
+ self._touchRecordEvent(event);
+ }
+ );
+ }
+
+ // mouse click and touch tap work the same way
+ if ( self.__options.triggerOpen.click
+ || (self.__options.triggerOpen.tap && env.hasTouchCapability)
+ ) {
+
+ var eventNames = '';
+ if (self.__options.triggerOpen.click) {
+ eventNames += 'click.'+ self.__namespace +'-triggerOpen ';
+ }
+ if (self.__options.triggerOpen.tap && env.hasTouchCapability) {
+ eventNames += 'touchend.'+ self.__namespace +'-triggerOpen';
+ }
+
+ self._$origin.on(eventNames, function(event) {
+ if (self._touchIsMeaningfulEvent(event)) {
+ self._open(event);
+ }
+ });
+ }
+
+ // mouseenter and touch start work the same way
+ if ( self.__options.triggerOpen.mouseenter
+ || (self.__options.triggerOpen.touchstart && env.hasTouchCapability)
+ ) {
+
+ var eventNames = '';
+ if (self.__options.triggerOpen.mouseenter) {
+ eventNames += 'mouseenter.'+ self.__namespace +'-triggerOpen ';
+ }
+ if (self.__options.triggerOpen.touchstart && env.hasTouchCapability) {
+ eventNames += 'touchstart.'+ self.__namespace +'-triggerOpen';
+ }
+
+ self._$origin.on(eventNames, function(event) {
+ if ( self._touchIsTouchEvent(event)
+ || !self._touchIsEmulatedEvent(event)
+ ) {
+ self.__pointerIsOverOrigin = true;
+ self._openShortly(event);
+ }
+ });
+ }
+
+ // info for the mouseleave/touchleave close triggers when they use a delay
+ if ( self.__options.triggerClose.mouseleave
+ || (self.__options.triggerClose.touchleave && env.hasTouchCapability)
+ ) {
+
+ var eventNames = '';
+ if (self.__options.triggerClose.mouseleave) {
+ eventNames += 'mouseleave.'+ self.__namespace +'-triggerOpen ';
+ }
+ if (self.__options.triggerClose.touchleave && env.hasTouchCapability) {
+ eventNames += 'touchend.'+ self.__namespace +'-triggerOpen touchcancel.'+ self.__namespace +'-triggerOpen';
+ }
+
+ self._$origin.on(eventNames, function(event) {
+
+ if (self._touchIsMeaningfulEvent(event)) {
+ self.__pointerIsOverOrigin = false;
+ }
+ });
+ }
+
+ return self;
+ },
+
+ /**
+ * Do the things that need to be done only once after the tooltip
+ * HTML element it has been created. It has been made a separate
+ * method so it can be called when options are changed. Remember
+ * that the tooltip may actually exist in the DOM before it is
+ * opened, and present after it has been closed: it's the display
+ * plugin that takes care of handling it.
+ *
+ * @returns {self}
+ * @private
+ */
+ __prepareTooltip: function() {
+
+ var self = this,
+ p = self.__options.interactive ? 'auto' : '';
+
+ // this will be useful to know quickly if the tooltip is in
+ // the DOM or not
+ self._$tooltip
+ .attr('id', self.__namespace)
+ .css({
+ // pointer events
+ 'pointer-events': p,
+ zIndex: self.__options.zIndex
+ });
+
+ // themes
+ // remove the old ones and add the new ones
+ $.each(self.__previousThemes, function(i, theme) {
+ self._$tooltip.removeClass(theme);
+ });
+ $.each(self.__options.theme, function(i, theme) {
+ self._$tooltip.addClass(theme);
+ });
+
+ self.__previousThemes = $.merge([], self.__options.theme);
+
+ return self;
+ },
+
+ /**
+ * Handles the scroll on any of the parents of the origin (when the
+ * tooltip is open)
+ *
+ * @param {object} event
+ * @returns {self}
+ * @private
+ */
+ __scrollHandler: function(event) {
+
+ var self = this;
+
+ if (self.__options.triggerClose.scroll) {
+ self._close(event);
+ }
+ else {
+
+ // if the origin or tooltip have been removed: do nothing, the tracker will
+ // take care of it later
+ if (bodyContains(self._$origin) && bodyContains(self._$tooltip)) {
+
+ var geo = null;
+
+ // if the scroll happened on the window
+ if (event.target === env.window.document) {
+
+ // if the origin has a fixed lineage, window scroll will have no
+ // effect on its position nor on the position of the tooltip
+ if (!self.__Geometry.origin.fixedLineage) {
+
+ // we don't need to do anything unless repositionOnScroll is true
+ // because the tooltip will already have moved with the window
+ // (and of course with the origin)
+ if (self.__options.repositionOnScroll) {
+ self.reposition(event);
+ }
+ }
+ }
+ // if the scroll happened on another parent of the tooltip, it means
+ // that it's in a scrollable area and now needs to have its position
+ // adjusted or recomputed, depending ont the repositionOnScroll
+ // option. Also, if the origin is partly hidden due to a parent that
+ // hides its overflow, we'll just hide (not close) the tooltip.
+ else {
+
+ geo = self.__geometry();
+
+ var overflows = false;
+
+ // a fixed position origin is not affected by the overflow hiding
+ // of a parent
+ if (self._$origin.css('position') != 'fixed') {
+
+ self.__$originParents.each(function(i, el) {
+
+ var $el = $(el),
+ overflowX = $el.css('overflow-x'),
+ overflowY = $el.css('overflow-y');
+
+ if (overflowX != 'visible' || overflowY != 'visible') {
+
+ var bcr = el.getBoundingClientRect();
+
+ if (overflowX != 'visible') {
+
+ if ( geo.origin.windowOffset.left < bcr.left
+ || geo.origin.windowOffset.right > bcr.right
+ ) {
+ overflows = true;
+ return false;
+ }
+ }
+
+ if (overflowY != 'visible') {
+
+ if ( geo.origin.windowOffset.top < bcr.top
+ || geo.origin.windowOffset.bottom > bcr.bottom
+ ) {
+ overflows = true;
+ return false;
+ }
+ }
+ }
+
+ // no need to go further if fixed, for the same reason as above
+ if ($el.css('position') == 'fixed') {
+ return false;
+ }
+ });
+ }
+
+ if (overflows) {
+ self._$tooltip.css('visibility', 'hidden');
+ }
+ else {
+
+ self._$tooltip.css('visibility', 'visible');
+
+ // reposition
+ if (self.__options.repositionOnScroll) {
+ self.reposition(event);
+ }
+ // or just adjust offset
+ else {
+
+ // we have to use offset and not windowOffset because this way,
+ // only the scroll distance of the scrollable areas are taken into
+ // account (the scrolltop value of the main window must be
+ // ignored since the tooltip already moves with it)
+ var offsetLeft = geo.origin.offset.left - self.__Geometry.origin.offset.left,
+ offsetTop = geo.origin.offset.top - self.__Geometry.origin.offset.top;
+
+ // add the offset to the position initially computed by the display plugin
+ self._$tooltip.css({
+ left: self.__lastPosition.coord.left + offsetLeft,
+ top: self.__lastPosition.coord.top + offsetTop
+ });
+ }
+ }
+ }
+
+ self._trigger({
+ type: 'scroll',
+ event: event,
+ geo: geo
+ });
+ }
+ }
+
+ return self;
+ },
+
+ /**
+ * Changes the state of the tooltip
+ *
+ * @param {string} state
+ * @returns {self}
+ * @private
+ */
+ __stateSet: function(state) {
+
+ this.__state = state;
+
+ this._trigger({
+ type: 'state',
+ state: state
+ });
+
+ return this;
+ },
+
+ /**
+ * Clear appearance timeouts
+ *
+ * @returns {self}
+ * @private
+ */
+ __timeoutsClear: function() {
+
+ // there is only one possible open timeout: the delayed opening
+ // when the mouseenter/touchstart open triggers are used
+ clearTimeout(this.__timeouts.open);
+ this.__timeouts.open = null;
+
+ // ... but several close timeouts: the delayed closing when the
+ // mouseleave close trigger is used and the timer option
+ $.each(this.__timeouts.close, function(i, timeout) {
+ clearTimeout(timeout);
+ });
+ this.__timeouts.close = [];
+
+ return this;
+ },
+
+ /**
+ * Start the tracker that will make checks at regular intervals
+ *
+ * @returns {self}
+ * @private
+ */
+ __trackerStart: function() {
+
+ var self = this,
+ $content = self._$tooltip.find('.tooltipster-content');
+
+ // get the initial content size
+ if (self.__options.trackTooltip) {
+ self.__contentBcr = $content[0].getBoundingClientRect();
+ }
+
+ self.__tracker = setInterval(function() {
+
+ // if the origin or tooltip elements have been removed.
+ // Note: we could destroy the instance now if the origin has
+ // been removed but we'll leave that task to our garbage collector
+ if (!bodyContains(self._$origin) || !bodyContains(self._$tooltip)) {
+ self._close();
+ }
+ // if everything is alright
+ else {
+
+ // compare the former and current positions of the origin to reposition
+ // the tooltip if need be
+ if (self.__options.trackOrigin) {
+
+ var g = self.__geometry(),
+ identical = false;
+
+ // compare size first (a change requires repositioning too)
+ if (areEqual(g.origin.size, self.__Geometry.origin.size)) {
+
+ // for elements that have a fixed lineage (see __geometry()), we track the
+ // top and left properties (relative to window)
+ if (self.__Geometry.origin.fixedLineage) {
+ if (areEqual(g.origin.windowOffset, self.__Geometry.origin.windowOffset)) {
+ identical = true;
+ }
+ }
+ // otherwise, track total offset (relative to document)
+ else {
+ if (areEqual(g.origin.offset, self.__Geometry.origin.offset)) {
+ identical = true;
+ }
+ }
+ }
+
+ if (!identical) {
+
+ // close the tooltip when using the mouseleave close trigger
+ // (see https://github.com/iamceege/tooltipster/pull/253)
+ if (self.__options.triggerClose.mouseleave) {
+ self._close();
+ }
+ else {
+ self.reposition();
+ }
+ }
+ }
+
+ if (self.__options.trackTooltip) {
+
+ var currentBcr = $content[0].getBoundingClientRect();
+
+ if ( currentBcr.height !== self.__contentBcr.height
+ || currentBcr.width !== self.__contentBcr.width
+ ) {
+ self.reposition();
+ self.__contentBcr = currentBcr;
+ }
+ }
+ }
+ }, self.__options.trackerInterval);
+
+ return self;
+ },
+
+ /**
+ * Closes the tooltip (after the closing delay)
+ *
+ * @param event
+ * @param callback
+ * @param force Set to true to override a potential refusal of the user's function
+ * @returns {self}
+ * @protected
+ */
+ _close: function(event, callback, force) {
+
+ var self = this,
+ ok = true;
+
+ self._trigger({
+ type: 'close',
+ event: event,
+ stop: function() {
+ ok = false;
+ }
+ });
+
+ // a destroying tooltip (force == true) may not refuse to close
+ if (ok || force) {
+
+ // save the method custom callback and cancel any open method custom callbacks
+ if (callback) self.__callbacks.close.push(callback);
+ self.__callbacks.open = [];
+
+ // clear open/close timeouts
+ self.__timeoutsClear();
+
+ var finishCallbacks = function() {
+
+ // trigger any close method custom callbacks and reset them
+ $.each(self.__callbacks.close, function(i,c) {
+ c.call(self, self, {
+ event: event,
+ origin: self._$origin[0]
+ });
+ });
+
+ self.__callbacks.close = [];
+ };
+
+ if (self.__state != 'closed') {
+
+ var necessary = true,
+ d = new Date(),
+ now = d.getTime(),
+ newClosingTime = now + self.__options.animationDuration[1];
+
+ // the tooltip may already already be disappearing, but if a new
+ // call to close() is made after the animationDuration was changed
+ // to 0 (for example), we ought to actually close it sooner than
+ // previously scheduled. In that case it should be noted that the
+ // browser will not adapt the animation duration to the new
+ // animationDuration that was set after the start of the closing
+ // animation.
+ // Note: the same thing could be considered at opening, but is not
+ // really useful since the tooltip is actually opened immediately
+ // upon a call to _open(). Since it would not make the opening
+ // animation finish sooner, its sole impact would be to trigger the
+ // state event and the open callbacks sooner than the actual end of
+ // the opening animation, which is not great.
+ if (self.__state == 'disappearing') {
+
+ if ( newClosingTime > self.__closingTime
+ // in case closing is actually overdue because the script
+ // execution was suspended. See #679
+ && self.__options.animationDuration[1] > 0
+ ) {
+ necessary = false;
+ }
+ }
+
+ if (necessary) {
+
+ self.__closingTime = newClosingTime;
+
+ if (self.__state != 'disappearing') {
+ self.__stateSet('disappearing');
+ }
+
+ var finish = function() {
+
+ // stop the tracker
+ clearInterval(self.__tracker);
+
+ // a "beforeClose" option has been asked several times but would
+ // probably useless since the content element is still accessible
+ // via ::content(), and because people can always use listeners
+ // inside their content to track what's going on. For the sake of
+ // simplicity, this has been denied. Bur for the rare people who
+ // really need the option (for old browsers or for the case where
+ // detaching the content is actually destructive, for file or
+ // password inputs for example), this event will do the work.
+ self._trigger({
+ type: 'closing',
+ event: event
+ });
+
+ // unbind listeners which are no longer needed
+
+ self._$tooltip
+ .off('.'+ self.__namespace +'-triggerClose')
+ .removeClass('tooltipster-dying');
+
+ // orientationchange, scroll and resize listeners
+ $(env.window).off('.'+ self.__namespace +'-triggerClose');
+
+ // scroll listeners
+ self.__$originParents.each(function(i, el) {
+ $(el).off('scroll.'+ self.__namespace +'-triggerClose');
+ });
+ // clear the array to prevent memory leaks
+ self.__$originParents = null;
+
+ $(env.window.document.body).off('.'+ self.__namespace +'-triggerClose');
+
+ self._$origin.off('.'+ self.__namespace +'-triggerClose');
+
+ self._off('dismissable');
+
+ // a plugin that would like to remove the tooltip from the
+ // DOM when closed should bind on this
+ self.__stateSet('closed');
+
+ // trigger event
+ self._trigger({
+ type: 'after',
+ event: event
+ });
+
+ // call our constructor custom callback function
+ if (self.__options.functionAfter) {
+ self.__options.functionAfter.call(self, self, {
+ event: event,
+ origin: self._$origin[0]
+ });
+ }
+
+ // call our method custom callbacks functions
+ finishCallbacks();
+ };
+
+ if (env.hasTransitions) {
+
+ self._$tooltip.css({
+ '-moz-animation-duration': self.__options.animationDuration[1] + 'ms',
+ '-ms-animation-duration': self.__options.animationDuration[1] + 'ms',
+ '-o-animation-duration': self.__options.animationDuration[1] + 'ms',
+ '-webkit-animation-duration': self.__options.animationDuration[1] + 'ms',
+ 'animation-duration': self.__options.animationDuration[1] + 'ms',
+ 'transition-duration': self.__options.animationDuration[1] + 'ms'
+ });
+
+ self._$tooltip
+ // clear both potential open and close tasks
+ .clearQueue()
+ .removeClass('tooltipster-show')
+ // for transitions only
+ .addClass('tooltipster-dying');
+
+ if (self.__options.animationDuration[1] > 0) {
+ self._$tooltip.delay(self.__options.animationDuration[1]);
+ }
+
+ self._$tooltip.queue(finish);
+ }
+ else {
+
+ self._$tooltip
+ .stop()
+ .fadeOut(self.__options.animationDuration[1], finish);
+ }
+ }
+ }
+ // if the tooltip is already closed, we still need to trigger
+ // the method custom callbacks
+ else {
+ finishCallbacks();
+ }
+ }
+
+ return self;
+ },
+
+ /**
+ * For internal use by plugins, if needed
+ *
+ * @returns {self}
+ * @protected
+ */
+ _off: function() {
+ this.__$emitterPrivate.off.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));
+ return this;
+ },
+
+ /**
+ * For internal use by plugins, if needed
+ *
+ * @returns {self}
+ * @protected
+ */
+ _on: function() {
+ this.__$emitterPrivate.on.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));
+ return this;
+ },
+
+ /**
+ * For internal use by plugins, if needed
+ *
+ * @returns {self}
+ * @protected
+ */
+ _one: function() {
+ this.__$emitterPrivate.one.apply(this.__$emitterPrivate, Array.prototype.slice.apply(arguments));
+ return this;
+ },
+
+ /**
+ * Opens the tooltip right away.
+ *
+ * @param event
+ * @param callback Will be called when the opening animation is over
+ * @returns {self}
+ * @protected
+ */
+ _open: function(event, callback) {
+
+ var self = this;
+
+ // if the destruction process has not begun and if this was not
+ // triggered by an unwanted emulated click event
+ if (!self.__destroying) {
+
+ // check that the origin is still in the DOM
+ if ( bodyContains(self._$origin)
+ // if the tooltip is enabled
+ && self.__enabled
+ ) {
+
+ var ok = true;
+
+ // if the tooltip is not open yet, we need to call functionBefore.
+ // otherwise we can jst go on
+ if (self.__state == 'closed') {
+
+ // trigger an event. The event.stop function allows the callback
+ // to prevent the opening of the tooltip
+ self._trigger({
+ type: 'before',
+ event: event,
+ stop: function() {
+ ok = false;
+ }
+ });
+
+ if (ok && self.__options.functionBefore) {
+
+ // call our custom function before continuing
+ ok = self.__options.functionBefore.call(self, self, {
+ event: event,
+ origin: self._$origin[0]
+ });
+ }
+ }
+
+ if (ok !== false) {
+
+ // if there is some content
+ if (self.__Content !== null) {
+
+ // save the method callback and cancel close method callbacks
+ if (callback) {
+ self.__callbacks.open.push(callback);
+ }
+ self.__callbacks.close = [];
+
+ // get rid of any appearance timeouts
+ self.__timeoutsClear();
+
+ var extraTime,
+ finish = function() {
+
+ if (self.__state != 'stable') {
+ self.__stateSet('stable');
+ }
+
+ // trigger any open method custom callbacks and reset them
+ $.each(self.__callbacks.open, function(i,c) {
+ c.call(self, self, {
+ origin: self._$origin[0],
+ tooltip: self._$tooltip[0]
+ });
+ });
+
+ self.__callbacks.open = [];
+ };
+
+ // if the tooltip is already open
+ if (self.__state !== 'closed') {
+
+ // the timer (if any) will start (or restart) right now
+ extraTime = 0;
+
+ // if it was disappearing, cancel that
+ if (self.__state === 'disappearing') {
+
+ self.__stateSet('appearing');
+
+ if (env.hasTransitions) {
+
+ self._$tooltip
+ .clearQueue()
+ .removeClass('tooltipster-dying')
+ .addClass('tooltipster-show');
+
+ if (self.__options.animationDuration[0] > 0) {
+ self._$tooltip.delay(self.__options.animationDuration[0]);
+ }
+
+ self._$tooltip.queue(finish);
+ }
+ else {
+ // in case the tooltip was currently fading out, bring it back
+ // to life
+ self._$tooltip
+ .stop()
+ .fadeIn(finish);
+ }
+ }
+ // if the tooltip is already open, we still need to trigger the method
+ // custom callback
+ else if (self.__state == 'stable') {
+ finish();
+ }
+ }
+ // if the tooltip isn't already open, open it
+ else {
+
+ // a plugin must bind on this and store the tooltip in this._$tooltip
+ self.__stateSet('appearing');
+
+ // the timer (if any) will start when the tooltip has fully appeared
+ // after its transition
+ extraTime = self.__options.animationDuration[0];
+
+ // insert the content inside the tooltip
+ self.__contentInsert();
+
+ // reposition the tooltip and attach to the DOM
+ self.reposition(event, true);
+
+ // animate in the tooltip. If the display plugin wants no css
+ // animations, it may override the animation option with a
+ // dummy value that will produce no effect
+ if (env.hasTransitions) {
+
+ // note: there seems to be an issue with start animations which
+ // are randomly not played on fast devices in both Chrome and FF,
+ // couldn't find a way to solve it yet. It seems that applying
+ // the classes before appending to the DOM helps a little, but
+ // it messes up some CSS transitions. The issue almost never
+ // happens when delay[0]==0 though
+ self._$tooltip
+ .addClass('tooltipster-'+ self.__options.animation)
+ .addClass('tooltipster-initial')
+ .css({
+ '-moz-animation-duration': self.__options.animationDuration[0] + 'ms',
+ '-ms-animation-duration': self.__options.animationDuration[0] + 'ms',
+ '-o-animation-duration': self.__options.animationDuration[0] + 'ms',
+ '-webkit-animation-duration': self.__options.animationDuration[0] + 'ms',
+ 'animation-duration': self.__options.animationDuration[0] + 'ms',
+ 'transition-duration': self.__options.animationDuration[0] + 'ms'
+ });
+
+ setTimeout(
+ function() {
+
+ // a quick hover may have already triggered a mouseleave
+ if (self.__state != 'closed') {
+
+ self._$tooltip
+ .addClass('tooltipster-show')
+ .removeClass('tooltipster-initial');
+
+ if (self.__options.animationDuration[0] > 0) {
+ self._$tooltip.delay(self.__options.animationDuration[0]);
+ }
+
+ self._$tooltip.queue(finish);
+ }
+ },
+ 0
+ );
+ }
+ else {
+
+ // old browsers will have to live with this
+ self._$tooltip
+ .css('display', 'none')
+ .fadeIn(self.__options.animationDuration[0], finish);
+ }
+
+ // checks if the origin is removed while the tooltip is open
+ self.__trackerStart();
+
+ // NOTE: the listeners below have a '-triggerClose' namespace
+ // because we'll remove them when the tooltip closes (unlike
+ // the '-triggerOpen' listeners). So some of them are actually
+ // not about close triggers, rather about positioning.
+
+ $(env.window)
+ // reposition on resize
+ .on('resize.'+ self.__namespace +'-triggerClose', function(e) {
+
+ var $ae = $(document.activeElement);
+
+ // reposition only if the resize event was not triggered upon the opening
+ // of a virtual keyboard due to an input field being focused within the tooltip
+ // (otherwise the repositioning would lose the focus)
+ if ( (!$ae.is('input') && !$ae.is('textarea'))
+ || !$.contains(self._$tooltip[0], $ae[0])
+ ) {
+ self.reposition(e);
+ }
+ })
+ // same as below for parents
+ .on('scroll.'+ self.__namespace +'-triggerClose', function(e) {
+ self.__scrollHandler(e);
+ });
+
+ self.__$originParents = self._$origin.parents();
+
+ // scrolling may require the tooltip to be moved or even
+ // repositioned in some cases
+ self.__$originParents.each(function(i, parent) {
+
+ $(parent).on('scroll.'+ self.__namespace +'-triggerClose', function(e) {
+ self.__scrollHandler(e);
+ });
+ });
+
+ if ( self.__options.triggerClose.mouseleave
+ || (self.__options.triggerClose.touchleave && env.hasTouchCapability)
+ ) {
+
+ // we use an event to allow users/plugins to control when the mouseleave/touchleave
+ // close triggers will come to action. It allows to have more triggering elements
+ // than just the origin and the tooltip for example, or to cancel/delay the closing,
+ // or to make the tooltip interactive even if it wasn't when it was open, etc.
+ self._on('dismissable', function(event) {
+
+ if (event.dismissable) {
+
+ if (event.delay) {
+
+ timeout = setTimeout(function() {
+ // event.event may be undefined
+ self._close(event.event);
+ }, event.delay);
+
+ self.__timeouts.close.push(timeout);
+ }
+ else {
+ self._close(event);
+ }
+ }
+ else {
+ clearTimeout(timeout);
+ }
+ });
+
+ // now set the listeners that will trigger 'dismissable' events
+ var $elements = self._$origin,
+ eventNamesIn = '',
+ eventNamesOut = '',
+ timeout = null;
+
+ // if we have to allow interaction, bind on the tooltip too
+ if (self.__options.interactive) {
+ $elements = $elements.add(self._$tooltip);
+ }
+
+ if (self.__options.triggerClose.mouseleave) {
+ eventNamesIn += 'mouseenter.'+ self.__namespace +'-triggerClose ';
+ eventNamesOut += 'mouseleave.'+ self.__namespace +'-triggerClose ';
+ }
+ if (self.__options.triggerClose.touchleave && env.hasTouchCapability) {
+ eventNamesIn += 'touchstart.'+ self.__namespace +'-triggerClose';
+ eventNamesOut += 'touchend.'+ self.__namespace +'-triggerClose touchcancel.'+ self.__namespace +'-triggerClose';
+ }
+
+ $elements
+ // close after some time spent outside of the elements
+ .on(eventNamesOut, function(event) {
+
+ // it's ok if the touch gesture ended up to be a swipe,
+ // it's still a "touch leave" situation
+ if ( self._touchIsTouchEvent(event)
+ || !self._touchIsEmulatedEvent(event)
+ ) {
+
+ var delay = (event.type == 'mouseleave') ?
+ self.__options.delay :
+ self.__options.delayTouch;
+
+ self._trigger({
+ delay: delay[1],
+ dismissable: true,
+ event: event,
+ type: 'dismissable'
+ });
+ }
+ })
+ // suspend the mouseleave timeout when the pointer comes back
+ // over the elements
+ .on(eventNamesIn, function(event) {
+
+ // it's also ok if the touch event is a swipe gesture
+ if ( self._touchIsTouchEvent(event)
+ || !self._touchIsEmulatedEvent(event)
+ ) {
+ self._trigger({
+ dismissable: false,
+ event: event,
+ type: 'dismissable'
+ });
+ }
+ });
+ }
+
+ // close the tooltip when the origin gets a mouse click (common behavior of
+ // native tooltips)
+ if (self.__options.triggerClose.originClick) {
+
+ self._$origin.on('click.'+ self.__namespace + '-triggerClose', function(event) {
+
+ // we could actually let a tap trigger this but this feature just
+ // does not make sense on touch devices
+ if ( !self._touchIsTouchEvent(event)
+ && !self._touchIsEmulatedEvent(event)
+ ) {
+ self._close(event);
+ }
+ });
+ }
+
+ // set the same bindings for click and touch on the body to close the tooltip
+ if ( self.__options.triggerClose.click
+ || (self.__options.triggerClose.tap && env.hasTouchCapability)
+ ) {
+
+ // don't set right away since the click/tap event which triggered this method
+ // (if it was a click/tap) is going to bubble up to the body, we don't want it
+ // to close the tooltip immediately after it opened
+ setTimeout(function() {
+
+ if (self.__state != 'closed') {
+
+ var eventNames = '',
+ $body = $(env.window.document.body);
+
+ if (self.__options.triggerClose.click) {
+ eventNames += 'click.'+ self.__namespace +'-triggerClose ';
+ }
+ if (self.__options.triggerClose.tap && env.hasTouchCapability) {
+ eventNames += 'touchend.'+ self.__namespace +'-triggerClose';
+ }
+
+ $body.on(eventNames, function(event) {
+
+ if (self._touchIsMeaningfulEvent(event)) {
+
+ self._touchRecordEvent(event);
+
+ if (!self.__options.interactive || !$.contains(self._$tooltip[0], event.target)) {
+ self._close(event);
+ }
+ }
+ });
+
+ // needed to detect and ignore swiping
+ if (self.__options.triggerClose.tap && env.hasTouchCapability) {
+
+ $body.on('touchstart.'+ self.__namespace +'-triggerClose', function(event) {
+ self._touchRecordEvent(event);
+ });
+ }
+ }
+ }, 0);
+ }
+
+ self._trigger('ready');
+
+ // call our custom callback
+ if (self.__options.functionReady) {
+ self.__options.functionReady.call(self, self, {
+ origin: self._$origin[0],
+ tooltip: self._$tooltip[0]
+ });
+ }
+ }
+
+ // if we have a timer set, let the countdown begin
+ if (self.__options.timer > 0) {
+
+ var timeout = setTimeout(function() {
+ self._close();
+ }, self.__options.timer + extraTime);
+
+ self.__timeouts.close.push(timeout);
+ }
+ }
+ }
+ }
+ }
+
+ return self;
+ },
+
+ /**
+ * When using the mouseenter/touchstart open triggers, this function will
+ * schedule the opening of the tooltip after the delay, if there is one
+ *
+ * @param event
+ * @returns {self}
+ * @protected
+ */
+ _openShortly: function(event) {
+
+ var self = this,
+ ok = true;
+
+ if (self.__state != 'stable' && self.__state != 'appearing') {
+
+ // if a timeout is not already running
+ if (!self.__timeouts.open) {
+
+ self._trigger({
+ type: 'start',
+ event: event,
+ stop: function() {
+ ok = false;
+ }
+ });
+
+ if (ok) {
+
+ var delay = (event.type.indexOf('touch') == 0) ?
+ self.__options.delayTouch :
+ self.__options.delay;
+
+ if (delay[0]) {
+
+ self.__timeouts.open = setTimeout(function() {
+
+ self.__timeouts.open = null;
+
+ // open only if the pointer (mouse or touch) is still over the origin.
+ // The check on the "meaningful event" can only be made here, after some
+ // time has passed (to know if the touch was a swipe or not)
+ if (self.__pointerIsOverOrigin && self._touchIsMeaningfulEvent(event)) {
+
+ // signal that we go on
+ self._trigger('startend');
+
+ self._open(event);
+ }
+ else {
+ // signal that we cancel
+ self._trigger('startcancel');
+ }
+ }, delay[0]);
+ }
+ else {
+ // signal that we go on
+ self._trigger('startend');
+
+ self._open(event);
+ }
+ }
+ }
+ }
+
+ return self;
+ },
+
+ /**
+ * Meant for plugins to get their options
+ *
+ * @param {string} pluginName The name of the plugin that asks for its options
+ * @param {object} defaultOptions The default options of the plugin
+ * @returns {object} The options
+ * @protected
+ */
+ _optionsExtract: function(pluginName, defaultOptions) {
+
+ var self = this,
+ options = $.extend(true, {}, defaultOptions);
+
+ // if the plugin options were isolated in a property named after the
+ // plugin, use them (prevents conflicts with other plugins)
+ var pluginOptions = self.__options[pluginName];
+
+ // if not, try to get them as regular options
+ if (!pluginOptions){
+
+ pluginOptions = {};
+
+ $.each(defaultOptions, function(optionName, value) {
+
+ var o = self.__options[optionName];
+
+ if (o !== undefined) {
+ pluginOptions[optionName] = o;
+ }
+ });
+ }
+
+ // let's merge the default options and the ones that were provided. We'd want
+ // to do a deep copy but not let jQuery merge arrays, so we'll do a shallow
+ // extend on two levels, that will be enough if options are not more than 1
+ // level deep
+ $.each(options, function(optionName, value) {
+
+ if (pluginOptions[optionName] !== undefined) {
+
+ if (( typeof value == 'object'
+ && !(value instanceof Array)
+ && value != null
+ )
+ &&
+ ( typeof pluginOptions[optionName] == 'object'
+ && !(pluginOptions[optionName] instanceof Array)
+ && pluginOptions[optionName] != null
+ )
+ ) {
+ $.extend(options[optionName], pluginOptions[optionName]);
+ }
+ else {
+ options[optionName] = pluginOptions[optionName];
+ }
+ }
+ });
+
+ return options;
+ },
+
+ /**
+ * Used at instantiation of the plugin, or afterwards by plugins that activate themselves
+ * on existing instances
+ *
+ * @param {object} pluginName
+ * @returns {self}
+ * @protected
+ */
+ _plug: function(pluginName) {
+
+ var plugin = $.tooltipster._plugin(pluginName);
+
+ if (plugin) {
+
+ // if there is a constructor for instances
+ if (plugin.instance) {
+
+ // proxy non-private methods on the instance to allow new instance methods
+ $.tooltipster.__bridge(plugin.instance, this, plugin.name);
+ }
+ }
+ else {
+ throw new Error('The "'+ pluginName +'" plugin is not defined');
+ }
+
+ return this;
+ },
+
+ /**
+ * This will return true if the event is a mouse event which was
+ * emulated by the browser after a touch event. This allows us to
+ * really dissociate mouse and touch triggers.
+ *
+ * There is a margin of error if a real mouse event is fired right
+ * after (within the delay shown below) a touch event on the same
+ * element, but hopefully it should not happen often.
+ *
+ * @returns {boolean}
+ * @protected
+ */
+ _touchIsEmulatedEvent: function(event) {
+
+ var isEmulated = false,
+ now = new Date().getTime();
+
+ for (var i = this.__touchEvents.length - 1; i >= 0; i--) {
+
+ var e = this.__touchEvents[i];
+
+ // delay, in milliseconds. It's supposed to be 300ms in
+ // most browsers (350ms on iOS) to allow a double tap but
+ // can be less (check out FastClick for more info)
+ if (now - e.time < 500) {
+
+ if (e.target === event.target) {
+ isEmulated = true;
+ }
+ }
+ else {
+ break;
+ }
+ }
+
+ return isEmulated;
+ },
+
+ /**
+ * Returns false if the event was an emulated mouse event or
+ * a touch event involved in a swipe gesture.
+ *
+ * @param {object} event
+ * @returns {boolean}
+ * @protected
+ */
+ _touchIsMeaningfulEvent: function(event) {
+ return (
+ (this._touchIsTouchEvent(event) && !this._touchSwiped(event.target))
+ || (!this._touchIsTouchEvent(event) && !this._touchIsEmulatedEvent(event))
+ );
+ },
+
+ /**
+ * Checks if an event is a touch event
+ *
+ * @param {object} event
+ * @returns {boolean}
+ * @protected
+ */
+ _touchIsTouchEvent: function(event){
+ return event.type.indexOf('touch') == 0;
+ },
+
+ /**
+ * Store touch events for a while to detect swiping and emulated mouse events
+ *
+ * @param {object} event
+ * @returns {self}
+ * @protected
+ */
+ _touchRecordEvent: function(event) {
+
+ if (this._touchIsTouchEvent(event)) {
+ event.time = new Date().getTime();
+ this.__touchEvents.push(event);
+ }
+
+ return this;
+ },
+
+ /**
+ * Returns true if a swipe happened after the last touchstart event fired on
+ * event.target.
+ *
+ * We need to differentiate a swipe from a tap before we let the event open
+ * or close the tooltip. A swipe is when a touchmove (scroll) event happens
+ * on the body between the touchstart and the touchend events of an element.
+ *
+ * @param {object} target The HTML element that may have triggered the swipe
+ * @returns {boolean}
+ * @protected
+ */
+ _touchSwiped: function(target) {
+
+ var swiped = false;
+
+ for (var i = this.__touchEvents.length - 1; i >= 0; i--) {
+
+ var e = this.__touchEvents[i];
+
+ if (e.type == 'touchmove') {
+ swiped = true;
+ break;
+ }
+ else if (
+ e.type == 'touchstart'
+ && target === e.target
+ ) {
+ break;
+ }
+ }
+
+ return swiped;
+ },
+
+ /**
+ * Triggers an event on the instance emitters
+ *
+ * @returns {self}
+ * @protected
+ */
+ _trigger: function() {
+
+ var args = Array.prototype.slice.apply(arguments);
+
+ if (typeof args[0] == 'string') {
+ args[0] = { type: args[0] };
+ }
+
+ // add properties to the event
+ args[0].instance = this;
+ args[0].origin = this._$origin ? this._$origin[0] : null;
+ args[0].tooltip = this._$tooltip ? this._$tooltip[0] : null;
+
+ // note: the order of emitters matters
+ this.__$emitterPrivate.trigger.apply(this.__$emitterPrivate, args);
+ $.tooltipster._trigger.apply($.tooltipster, args);
+ this.__$emitterPublic.trigger.apply(this.__$emitterPublic, args);
+
+ return this;
+ },
+
+ /**
+ * Deactivate a plugin on this instance
+ *
+ * @returns {self}
+ * @protected
+ */
+ _unplug: function(pluginName) {
+
+ var self = this;
+
+ // if the plugin has been activated on this instance
+ if (self[pluginName]) {
+
+ var plugin = $.tooltipster._plugin(pluginName);
+
+ // if there is a constructor for instances
+ if (plugin.instance) {
+
+ // unbridge
+ $.each(plugin.instance, function(methodName, fn) {
+
+ // if the method exists (privates methods do not) and comes indeed from
+ // this plugin (may be missing or come from a conflicting plugin).
+ if ( self[methodName]
+ && self[methodName].bridged === self[pluginName]
+ ) {
+ delete self[methodName];
+ }
+ });
+ }
+
+ // destroy the plugin
+ if (self[pluginName].__destroy) {
+ self[pluginName].__destroy();
+ }
+
+ // remove the reference to the plugin instance
+ delete self[pluginName];
+ }
+
+ return self;
+ },
+
+ /**
+ * @see self::_close
+ * @returns {self}
+ * @public
+ */
+ close: function(callback) {
+
+ if (!this.__destroyed) {
+ this._close(null, callback);
+ }
+ else {
+ this.__destroyError();
+ }
+
+ return this;
+ },
+
+ /**
+ * Sets or gets the content of the tooltip
+ *
+ * @returns {mixed|self}
+ * @public
+ */
+ content: function(content) {
+
+ var self = this;
+
+ // getter method
+ if (content === undefined) {
+ return self.__Content;
+ }
+ // setter method
+ else {
+
+ if (!self.__destroyed) {
+
+ // change the content
+ self.__contentSet(content);
+
+ if (self.__Content !== null) {
+
+ // update the tooltip if it is open
+ if (self.__state !== 'closed') {
+
+ // reset the content in the tooltip
+ self.__contentInsert();
+
+ // reposition and resize the tooltip
+ self.reposition();
+
+ // if we want to play a little animation showing the content changed
+ if (self.__options.updateAnimation) {
+
+ if (env.hasTransitions) {
+
+ // keep the reference in the local scope
+ var animation = self.__options.updateAnimation;
+
+ self._$tooltip.addClass('tooltipster-update-'+ animation);
+
+ // remove the class after a while. The actual duration of the
+ // update animation may be shorter, it's set in the CSS rules
+ setTimeout(function() {
+
+ if (self.__state != 'closed') {
+
+ self._$tooltip.removeClass('tooltipster-update-'+ animation);
+ }
+ }, 1000);
+ }
+ else {
+ self._$tooltip.fadeTo(200, 0.5, function() {
+ if (self.__state != 'closed') {
+ self._$tooltip.fadeTo(200, 1);
+ }
+ });
+ }
+ }
+ }
+ }
+ else {
+ self._close();
+ }
+ }
+ else {
+ self.__destroyError();
+ }
+
+ return self;
+ }
+ },
+
+ /**
+ * Destroys the tooltip
+ *
+ * @returns {self}
+ * @public
+ */
+ destroy: function() {
+
+ var self = this;
+
+ if (!self.__destroyed) {
+
+ if(self.__state != 'closed'){
+
+ // no closing delay
+ self.option('animationDuration', 0)
+ // force closing
+ ._close(null, null, true);
+ }
+ else {
+ // there might be an open timeout still running
+ self.__timeoutsClear();
+ }
+
+ // send event
+ self._trigger('destroy');
+
+ self.__destroyed = true;
+
+ self._$origin
+ .removeData(self.__namespace)
+ // remove the open trigger listeners
+ .off('.'+ self.__namespace +'-triggerOpen');
+
+ // remove the touch listener
+ $(env.window.document.body).off('.' + self.__namespace +'-triggerOpen');
+
+ var ns = self._$origin.data('tooltipster-ns');
+
+ // if the origin has been removed from DOM, its data may
+ // well have been destroyed in the process and there would
+ // be nothing to clean up or restore
+ if (ns) {
+
+ // if there are no more tooltips on this element
+ if (ns.length === 1) {
+
+ // optional restoration of a title attribute
+ var title = null;
+ if (self.__options.restoration == 'previous') {
+ title = self._$origin.data('tooltipster-initialTitle');
+ }
+ else if (self.__options.restoration == 'current') {
+
+ // old school technique to stringify when outerHTML is not supported
+ title = (typeof self.__Content == 'string') ?
+ self.__Content :
+ $('<div></div>').append(self.__Content).html();
+ }
+
+ if (title) {
+ self._$origin.attr('title', title);
+ }
+
+ // final cleaning
+
+ self._$origin.removeClass('tooltipstered');
+
+ self._$origin
+ .removeData('tooltipster-ns')
+ .removeData('tooltipster-initialTitle');
+ }
+ else {
+ // remove the instance namespace from the list of namespaces of
+ // tooltips present on the element
+ ns = $.grep(ns, function(el, i) {
+ return el !== self.__namespace;
+ });
+ self._$origin.data('tooltipster-ns', ns);
+ }
+ }
+
+ // last event
+ self._trigger('destroyed');
+
+ // unbind private and public event listeners
+ self._off();
+ self.off();
+
+ // remove external references, just in case
+ self.__Content = null;
+ self.__$emitterPrivate = null;
+ self.__$emitterPublic = null;
+ self.__options.parent = null;
+ self._$origin = null;
+ self._$tooltip = null;
+
+ // make sure the object is no longer referenced in there to prevent
+ // memory leaks
+ $.tooltipster.__instancesLatestArr = $.grep($.tooltipster.__instancesLatestArr, function(el, i) {
+ return self !== el;
+ });
+
+ clearInterval(self.__garbageCollector);
+ }
+ else {
+ self.__destroyError();
+ }
+
+ // we return the scope rather than true so that the call to
+ // .tooltipster('destroy') actually returns the matched elements
+ // and applies to all of them
+ return self;
+ },
+
+ /**
+ * Disables the tooltip
+ *
+ * @returns {self}
+ * @public
+ */
+ disable: function() {
+
+ if (!this.__destroyed) {
+
+ // close first, in case the tooltip would not disappear on
+ // its own (no close trigger)
+ this._close();
+ this.__enabled = false;
+
+ return this;
+ }
+ else {
+ this.__destroyError();
+ }
+
+ return this;
+ },
+
+ /**
+ * Returns the HTML element of the origin
+ *
+ * @returns {self}
+ * @public
+ */
+ elementOrigin: function() {
+
+ if (!this.__destroyed) {
+ return this._$origin[0];
+ }
+ else {
+ this.__destroyError();
+ }
+ },
+
+ /**
+ * Returns the HTML element of the tooltip
+ *
+ * @returns {self}
+ * @public
+ */
+ elementTooltip: function() {
+ return this._$tooltip ? this._$tooltip[0] : null;
+ },
+
+ /**
+ * Enables the tooltip
+ *
+ * @returns {self}
+ * @public
+ */
+ enable: function() {
+ this.__enabled = true;
+ return this;
+ },
+
+ /**
+ * Alias, deprecated in 4.0.0
+ *
+ * @param {function} callback
+ * @returns {self}
+ * @public
+ */
+ hide: function(callback) {
+ return this.close(callback);
+ },
+
+ /**
+ * Returns the instance
+ *
+ * @returns {self}
+ * @public
+ */
+ instance: function() {
+ return this;
+ },
+
+ /**
+ * For public use only, not to be used by plugins (use ::_off() instead)
+ *
+ * @returns {self}
+ * @public
+ */
+ off: function() {
+
+ if (!this.__destroyed) {
+ this.__$emitterPublic.off.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));
+ }
+
+ return this;
+ },
+
+ /**
+ * For public use only, not to be used by plugins (use ::_on() instead)
+ *
+ * @returns {self}
+ * @public
+ */
+ on: function() {
+
+ if (!this.__destroyed) {
+ this.__$emitterPublic.on.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));
+ }
+ else {
+ this.__destroyError();
+ }
+
+ return this;
+ },
+
+ /**
+ * For public use only, not to be used by plugins
+ *
+ * @returns {self}
+ * @public
+ */
+ one: function() {
+
+ if (!this.__destroyed) {
+ this.__$emitterPublic.one.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));
+ }
+ else {
+ this.__destroyError();
+ }
+
+ return this;
+ },
+
+ /**
+ * @see self::_open
+ * @returns {self}
+ * @public
+ */
+ open: function(callback) {
+
+ if (!this.__destroyed) {
+ this._open(null, callback);
+ }
+ else {
+ this.__destroyError();
+ }
+
+ return this;
+ },
+
+ /**
+ * Get or set options. For internal use and advanced users only.
+ *
+ * @param {string} o Option name
+ * @param {mixed} val optional A new value for the option
+ * @return {mixed|self} If val is omitted, the value of the option
+ * is returned, otherwise the instance itself is returned
+ * @public
+ */
+ option: function(o, val) {
+
+ // getter
+ if (val === undefined) {
+ return this.__options[o];
+ }
+ // setter
+ else {
+
+ if (!this.__destroyed) {
+
+ // change value
+ this.__options[o] = val;
+
+ // format
+ this.__optionsFormat();
+
+ // re-prepare the triggers if needed
+ if ($.inArray(o, ['trigger', 'triggerClose', 'triggerOpen']) >= 0) {
+ this.__prepareOrigin();
+ }
+
+ if (o === 'selfDestruction') {
+ this.__prepareGC();
+ }
+ }
+ else {
+ this.__destroyError();
+ }
+
+ return this;
+ }
+ },
+
+ /**
+ * This method is in charge of setting the position and size properties of the tooltip.
+ * All the hard work is delegated to the display plugin.
+ * Note: The tooltip may be detached from the DOM at the moment the method is called
+ * but must be attached by the end of the method call.
+ *
+ * @param {object} event For internal use only. Defined if an event such as
+ * window resizing triggered the repositioning
+ * @param {boolean} tooltipIsDetached For internal use only. Set this to true if you
+ * know that the tooltip not being in the DOM is not an issue (typically when the
+ * tooltip element has just been created but has not been added to the DOM yet).
+ * @returns {self}
+ * @public
+ */
+ reposition: function(event, tooltipIsDetached) {
+
+ var self = this;
+
+ if (!self.__destroyed) {
+
+ // if the tooltip is still open and the origin is still in the DOM
+ if (self.__state != 'closed' && bodyContains(self._$origin)) {
+
+ // if the tooltip has not been removed from DOM manually (or if it
+ // has been detached on purpose)
+ if (tooltipIsDetached || bodyContains(self._$tooltip)) {
+
+ if (!tooltipIsDetached) {
+ // detach in case the tooltip overflows the window and adds
+ // scrollbars to it, so __geometry can be accurate
+ self._$tooltip.detach();
+ }
+
+ // refresh the geometry object before passing it as a helper
+ self.__Geometry = self.__geometry();
+
+ // let a plugin fo the rest
+ self._trigger({
+ type: 'reposition',
+ event: event,
+ helper: {
+ geo: self.__Geometry
+ }
+ });
+ }
+ }
+ }
+ else {
+ self.__destroyError();
+ }
+
+ return self;
+ },
+
+ /**
+ * Alias, deprecated in 4.0.0
+ *
+ * @param callback
+ * @returns {self}
+ * @public
+ */
+ show: function(callback) {
+ return this.open(callback);
+ },
+
+ /**
+ * Returns some properties about the instance
+ *
+ * @returns {object}
+ * @public
+ */
+ status: function() {
+
+ return {
+ destroyed: this.__destroyed,
+ enabled: this.__enabled,
+ open: this.__state !== 'closed',
+ state: this.__state
+ };
+ },
+
+ /**
+ * For public use only, not to be used by plugins
+ *
+ * @returns {self}
+ * @public
+ */
+ triggerHandler: function() {
+
+ if (!this.__destroyed) {
+ this.__$emitterPublic.triggerHandler.apply(this.__$emitterPublic, Array.prototype.slice.apply(arguments));
+ }
+ else {
+ this.__destroyError();
+ }
+
+ return this;
+ }
+};
+
+$.fn.tooltipster = function() {
+
+ // for using in closures
+ var args = Array.prototype.slice.apply(arguments),
+ // common mistake: an HTML element can't be in several tooltips at the same time
+ contentCloningWarning = 'You are using a single HTML element as content for several tooltips. You probably want to set the contentCloning option to TRUE.';
+
+ // this happens with $(sel).tooltipster(...) when $(sel) does not match anything
+ if (this.length === 0) {
+
+ // still chainable
+ return this;
+ }
+ // this happens when calling $(sel).tooltipster('methodName or options')
+ // where $(sel) matches one or more elements
+ else {
+
+ // method calls
+ if (typeof args[0] === 'string') {
+
+ var v = '#*$~&';
+
+ this.each(function() {
+
+ // retrieve the namepaces of the tooltip(s) that exist on that element.
+ // We will interact with the first tooltip only.
+ var ns = $(this).data('tooltipster-ns'),
+ // self represents the instance of the first tooltipster plugin
+ // associated to the current HTML object of the loop
+ self = ns ? $(this).data(ns[0]) : null;
+
+ // if the current element holds a tooltipster instance
+ if (self) {
+
+ if (typeof self[args[0]] === 'function') {
+
+ if ( this.length > 1
+ && args[0] == 'content'
+ && ( args[1] instanceof $
+ || (typeof args[1] == 'object' && args[1] != null && args[1].tagName)
+ )
+ && !self.__options.contentCloning
+ && self.__options.debug
+ ) {
+ console.log(contentCloningWarning);
+ }
+
+ // note : args[1] and args[2] may not be defined
+ var resp = self[args[0]](args[1], args[2]);
+ }
+ else {
+ throw new Error('Unknown method "'+ args[0] +'"');
+ }
+
+ // if the function returned anything other than the instance
+ // itself (which implies chaining, except for the `instance` method)
+ if (resp !== self || args[0] === 'instance') {
+
+ v = resp;
+
+ // return false to stop .each iteration on the first element
+ // matched by the selector
+ return false;
+ }
+ }
+ else {
+ throw new Error('You called Tooltipster\'s "'+ args[0] +'" method on an uninitialized element');
+ }
+ });
+
+ return (v !== '#*$~&') ? v : this;
+ }
+ // first argument is undefined or an object: the tooltip is initializing
+ else {
+
+ // reset the array of last initialized objects
+ $.tooltipster.__instancesLatestArr = [];
+
+ // is there a defined value for the multiple option in the options object ?
+ var multipleIsSet = args[0] && args[0].multiple !== undefined,
+ // if the multiple option is set to true, or if it's not defined but
+ // set to true in the defaults
+ multiple = (multipleIsSet && args[0].multiple) || (!multipleIsSet && defaults.multiple),
+ // same for content
+ contentIsSet = args[0] && args[0].content !== undefined,
+ content = (contentIsSet && args[0].content) || (!contentIsSet && defaults.content),
+ // same for contentCloning
+ contentCloningIsSet = args[0] && args[0].contentCloning !== undefined,
+ contentCloning =
+ (contentCloningIsSet && args[0].contentCloning)
+ || (!contentCloningIsSet && defaults.contentCloning),
+ // same for debug
+ debugIsSet = args[0] && args[0].debug !== undefined,
+ debug = (debugIsSet && args[0].debug) || (!debugIsSet && defaults.debug);
+
+ if ( this.length > 1
+ && ( content instanceof $
+ || (typeof content == 'object' && content != null && content.tagName)
+ )
+ && !contentCloning
+ && debug
+ ) {
+ console.log(contentCloningWarning);
+ }
+
+ // create a tooltipster instance for each element if it doesn't
+ // already have one or if the multiple option is set, and attach the
+ // object to it
+ this.each(function() {
+
+ var go = false,
+ $this = $(this),
+ ns = $this.data('tooltipster-ns'),
+ obj = null;
+
+ if (!ns) {
+ go = true;
+ }
+ else if (multiple) {
+ go = true;
+ }
+ else if (debug) {
+ console.log('Tooltipster: one or more tooltips are already attached to the element below. Ignoring.');
+ console.log(this);
+ }
+
+ if (go) {
+ obj = new $.Tooltipster(this, args[0]);
+
+ // save the reference of the new instance
+ if (!ns) ns = [];
+ ns.push(obj.__namespace);
+ $this.data('tooltipster-ns', ns);
+
+ // save the instance itself
+ $this.data(obj.__namespace, obj);
+
+ // call our constructor custom function.
+ // we do this here and not in ::init() because we wanted
+ // the object to be saved in $this.data before triggering
+ // it
+ if (obj.__options.functionInit) {
+ obj.__options.functionInit.call(obj, obj, {
+ origin: this
+ });
+ }
+
+ // and now the event, for the plugins and core emitter
+ obj._trigger('init');
+ }
+
+ $.tooltipster.__instancesLatestArr.push(obj);
+ });
+
+ return this;
+ }
+ }
+};
+
+// Utilities
+
+/**
+ * A class to check if a tooltip can fit in given dimensions
+ *
+ * @param {object} $tooltip The jQuery wrapped tooltip element, or a clone of it
+ */
+function Ruler($tooltip) {
+
+ // list of instance variables
+
+ this.$container;
+ this.constraints = null;
+ this.__$tooltip;
+
+ this.__init($tooltip);
+}
+
+Ruler.prototype = {
+
+ /**
+ * Move the tooltip into an invisible div that does not allow overflow to make
+ * size tests. Note: the tooltip may or may not be attached to the DOM at the
+ * moment this method is called, it does not matter.
+ *
+ * @param {object} $tooltip The object to test. May be just a clone of the
+ * actual tooltip.
+ * @private
+ */
+ __init: function($tooltip) {
+
+ this.__$tooltip = $tooltip;
+
+ this.__$tooltip
+ .css({
+ // for some reason we have to specify top and left 0
+ left: 0,
+ // any overflow will be ignored while measuring
+ overflow: 'hidden',
+ // positions at (0,0) without the div using 100% of the available width
+ position: 'absolute',
+ top: 0
+ })
+ // overflow must be auto during the test. We re-set this in case
+ // it were modified by the user
+ .find('.tooltipster-content')
+ .css('overflow', 'auto');
+
+ this.$container = $('<div class="tooltipster-ruler"></div>')
+ .append(this.__$tooltip)
+ .appendTo(env.window.document.body);
+ },
+
+ /**
+ * Force the browser to redraw (re-render) the tooltip immediately. This is required
+ * when you changed some CSS properties and need to make something with it
+ * immediately, without waiting for the browser to redraw at the end of instructions.
+ *
+ * @see http://stackoverflow.com/questions/3485365/how-can-i-force-webkit-to-redraw-repaint-to-propagate-style-changes
+ * @private
+ */
+ __forceRedraw: function() {
+
+ // note: this would work but for Webkit only
+ //this.__$tooltip.close();
+ //this.__$tooltip[0].offsetHeight;
+ //this.__$tooltip.open();
+
+ // works in FF too
+ var $p = this.__$tooltip.parent();
+ this.__$tooltip.detach();
+ this.__$tooltip.appendTo($p);
+ },
+
+ /**
+ * Set maximum dimensions for the tooltip. A call to ::measure afterwards
+ * will tell us if the content overflows or if it's ok
+ *
+ * @param {int} width
+ * @param {int} height
+ * @return {Ruler}
+ * @public
+ */
+ constrain: function(width, height) {
+
+ this.constraints = {
+ width: width,
+ height: height
+ };
+
+ this.__$tooltip.css({
+ // we disable display:flex, otherwise the content would overflow without
+ // creating horizontal scrolling (which we need to detect).
+ display: 'block',
+ // reset any previous height
+ height: '',
+ // we'll check if horizontal scrolling occurs
+ overflow: 'auto',
+ // we'll set the width and see what height is generated and if there
+ // is horizontal overflow
+ width: width
+ });
+
+ return this;
+ },
+
+ /**
+ * Reset the tooltip content overflow and remove the test container
+ *
+ * @returns {Ruler}
+ * @public
+ */
+ destroy: function() {
+
+ // in case the element was not a clone
+ this.__$tooltip
+ .detach()
+ .find('.tooltipster-content')
+ .css({
+ // reset to CSS value
+ display: '',
+ overflow: ''
+ });
+
+ this.$container.remove();
+ },
+
+ /**
+ * Removes any constraints
+ *
+ * @returns {Ruler}
+ * @public
+ */
+ free: function() {
+
+ this.constraints = null;
+
+ // reset to natural size
+ this.__$tooltip.css({
+ display: '',
+ height: '',
+ overflow: 'visible',
+ width: ''
+ });
+
+ return this;
+ },
+
+ /**
+ * Returns the size of the tooltip. When constraints are applied, also returns
+ * whether the tooltip fits in the provided dimensions.
+ * The idea is to see if the new height is small enough and if the content does
+ * not overflow horizontally.
+ *
+ * @param {int} width
+ * @param {int} height
+ * @returns {object} An object with a bool `fits` property and a `size` property
+ * @public
+ */
+ measure: function() {
+
+ this.__forceRedraw();
+
+ var tooltipBcr = this.__$tooltip[0].getBoundingClientRect(),
+ result = { size: {
+ // bcr.width/height are not defined in IE8- but in this
+ // case, bcr.right/bottom will have the same value
+ // except in iOS 8+ where tooltipBcr.bottom/right are wrong
+ // after scrolling for reasons yet to be determined.
+ // tooltipBcr.top/left might not be 0, see issue #514
+ height: tooltipBcr.height || (tooltipBcr.bottom - tooltipBcr.top),
+ width: tooltipBcr.width || (tooltipBcr.right - tooltipBcr.left)
+ }};
+
+ if (this.constraints) {
+
+ // note: we used to use offsetWidth instead of boundingRectClient but
+ // it returned rounded values, causing issues with sub-pixel layouts.
+
+ // note2: noticed that the bcrWidth of text content of a div was once
+ // greater than the bcrWidth of its container by 1px, causing the final
+ // tooltip box to be too small for its content. However, evaluating
+ // their widths one against the other (below) surprisingly returned
+ // equality. Happened only once in Chrome 48, was not able to reproduce
+ // => just having fun with float position values...
+
+ var $content = this.__$tooltip.find('.tooltipster-content'),
+ height = this.__$tooltip.outerHeight(),
+ contentBcr = $content[0].getBoundingClientRect(),
+ fits = {
+ height: height <= this.constraints.height,
+ width: (
+ // this condition accounts for min-width property that
+ // may apply
+ tooltipBcr.width <= this.constraints.width
+ // the -1 is here because scrollWidth actually returns
+ // a rounded value, and may be greater than bcr.width if
+ // it was rounded up. This may cause an issue for contents
+ // which actually really overflow by 1px or so, but that
+ // should be rare. Not sure how to solve this efficiently.
+ // See http://blogs.msdn.com/b/ie/archive/2012/02/17/sub-pixel-rendering-and-the-css-object-model.aspx
+ && contentBcr.width >= $content[0].scrollWidth - 1
+ )
+ };
+
+ result.fits = fits.height && fits.width;
+ }
+
+ // old versions of IE get the width wrong for some reason and it causes
+ // the text to be broken to a new line, so we round it up. If the width
+ // is the width of the screen though, we can assume it is accurate.
+ if ( env.IE
+ && env.IE <= 11
+ && result.size.width !== env.window.document.documentElement.clientWidth
+ ) {
+ result.size.width = Math.ceil(result.size.width) + 1;
+ }
+
+ return result;
+ }
+};
+
+// quick & dirty compare function, not bijective nor multidimensional
+function areEqual(a,b) {
+ var same = true;
+ $.each(a, function(i, _) {
+ if (b[i] === undefined || a[i] !== b[i]) {
+ same = false;
+ return false;
+ }
+ });
+ return same;
+}
+
+/**
+ * A fast function to check if an element is still in the DOM. It
+ * tries to use an id as ids are indexed by the browser, or falls
+ * back to jQuery's `contains` method. May fail if two elements
+ * have the same id, but so be it
+ *
+ * @param {object} $obj A jQuery-wrapped HTML element
+ * @return {boolean}
+ */
+function bodyContains($obj) {
+ var id = $obj.attr('id'),
+ el = id ? env.window.document.getElementById(id) : null;
+ // must also check that the element with the id is the one we want
+ return el ? el === $obj[0] : $.contains(env.window.document.body, $obj[0]);
+}
+
+// detect IE versions for dirty fixes
+var uA = navigator.userAgent.toLowerCase();
+if (uA.indexOf('msie') != -1) env.IE = parseInt(uA.split('msie')[1]);
+else if (uA.toLowerCase().indexOf('trident') !== -1 && uA.indexOf(' rv:11') !== -1) env.IE = 11;
+else if (uA.toLowerCase().indexOf('edge/') != -1) env.IE = parseInt(uA.toLowerCase().split('edge/')[1]);
+
+// detecting support for CSS transitions
+function transitionSupport() {
+
+ // env.window is not defined yet when this is called
+ if (!win) return false;
+
+ var b = win.document.body || win.document.documentElement,
+ s = b.style,
+ p = 'transition',
+ v = ['Moz', 'Webkit', 'Khtml', 'O', 'ms'];
+
+ if (typeof s[p] == 'string') { return true; }
+
+ p = p.charAt(0).toUpperCase() + p.substr(1);
+ for (var i=0; i<v.length; i++) {
+ if (typeof s[v[i] + p] == 'string') { return true; }
+ }
+ return false;
+}
+
+// we'll return jQuery for plugins not to have to declare it as a dependency,
+// but it's done by a build task since it should be included only once at the
+// end when we concatenate the main file with a plugin
+// sideTip is Tooltipster's default plugin.
+// This file will be UMDified by a build task.
+
+var pluginName = 'tooltipster.sideTip';
+
+$.tooltipster._plugin({
+ name: pluginName,
+ instance: {
+ /**
+ * Defaults are provided as a function for an easy override by inheritance
+ *
+ * @return {object} An object with the defaults options
+ * @private
+ */
+ __defaults: function() {
+
+ return {
+ // if the tooltip should display an arrow that points to the origin
+ arrow: true,
+ // the distance in pixels between the tooltip and the origin
+ distance: 6,
+ // allows to easily change the position of the tooltip
+ functionPosition: null,
+ maxWidth: null,
+ // used to accomodate the arrow of tooltip if there is one.
+ // First to make sure that the arrow target is not too close
+ // to the edge of the tooltip, so the arrow does not overflow
+ // the tooltip. Secondly when we reposition the tooltip to
+ // make sure that it's positioned in such a way that the arrow is
+ // still pointing at the target (and not a few pixels beyond it).
+ // It should be equal to or greater than half the width of
+ // the arrow (by width we mean the size of the side which touches
+ // the side of the tooltip).
+ minIntersection: 16,
+ minWidth: 0,
+ // deprecated in 4.0.0. Listed for _optionsExtract to pick it up
+ position: null,
+ side: 'top',
+ // set to false to position the tooltip relatively to the document rather
+ // than the window when we open it
+ viewportAware: true
+ };
+ },
+
+ /**
+ * Run once: at instantiation of the plugin
+ *
+ * @param {object} instance The tooltipster object that instantiated this plugin
+ * @private
+ */
+ __init: function(instance) {
+
+ var self = this;
+
+ // list of instance variables
+
+ self.__instance = instance;
+ self.__namespace = 'tooltipster-sideTip-'+ Math.round(Math.random()*1000000);
+ self.__previousState = 'closed';
+ self.__options;
+
+ // initial formatting
+ self.__optionsFormat();
+
+ self.__instance._on('state.'+ self.__namespace, function(event) {
+
+ if (event.state == 'closed') {
+ self.__close();
+ }
+ else if (event.state == 'appearing' && self.__previousState == 'closed') {
+ self.__create();
+ }
+
+ self.__previousState = event.state;
+ });
+
+ // reformat every time the options are changed
+ self.__instance._on('options.'+ self.__namespace, function() {
+ self.__optionsFormat();
+ });
+
+ self.__instance._on('reposition.'+ self.__namespace, function(e) {
+ self.__reposition(e.event, e.helper);
+ });
+ },
+
+ /**
+ * Called when the tooltip has closed
+ *
+ * @private
+ */
+ __close: function() {
+
+ // detach our content object first, so the next jQuery's remove()
+ // call does not unbind its event handlers
+ if (this.__instance.content() instanceof $) {
+ this.__instance.content().detach();
+ }
+
+ // remove the tooltip from the DOM
+ this.__instance._$tooltip.remove();
+ this.__instance._$tooltip = null;
+ },
+
+ /**
+ * Creates the HTML element of the tooltip.
+ *
+ * @private
+ */
+ __create: function() {
+
+ // note: we wrap with a .tooltipster-box div to be able to set a margin on it
+ // (.tooltipster-base must not have one)
+ var $html = $(
+ '<div class="tooltipster-base tooltipster-sidetip">' +
+ '<div class="tooltipster-box">' +
+ '<div class="tooltipster-content"></div>' +
+ '</div>' +
+ '<div class="tooltipster-arrow">' +
+ '<div class="tooltipster-arrow-uncropped">' +
+ '<div class="tooltipster-arrow-border"></div>' +
+ '<div class="tooltipster-arrow-background"></div>' +
+ '</div>' +
+ '</div>' +
+ '</div>'
+ );
+
+ // hide arrow if asked
+ if (!this.__options.arrow) {
+ $html
+ .find('.tooltipster-box')
+ .css('margin', 0)
+ .end()
+ .find('.tooltipster-arrow')
+ .hide();
+ }
+
+ // apply min/max width if asked
+ if (this.__options.minWidth) {
+ $html.css('min-width', this.__options.minWidth + 'px');
+ }
+ if (this.__options.maxWidth) {
+ $html.css('max-width', this.__options.maxWidth + 'px');
+ }
+
+ this.__instance._$tooltip = $html;
+
+ // tell the instance that the tooltip element has been created
+ this.__instance._trigger('created');
+ },
+
+ /**
+ * Used when the plugin is to be unplugged
+ *
+ * @private
+ */
+ __destroy: function() {
+ this.__instance._off('.'+ self.__namespace);
+ },
+
+ /**
+ * (Re)compute this.__options from the options declared to the instance
+ *
+ * @private
+ */
+ __optionsFormat: function() {
+
+ var self = this;
+
+ // get the options
+ self.__options = self.__instance._optionsExtract(pluginName, self.__defaults());
+
+ // for backward compatibility, deprecated in v4.0.0
+ if (self.__options.position) {
+ self.__options.side = self.__options.position;
+ }
+
+ // options formatting
+
+ // format distance as a four-cell array if it ain't one yet and then make
+ // it an object with top/bottom/left/right properties
+ if (typeof self.__options.distance != 'object') {
+ self.__options.distance = [self.__options.distance];
+ }
+ if (self.__options.distance.length < 4) {
+
+ if (self.__options.distance[1] === undefined) self.__options.distance[1] = self.__options.distance[0];
+ if (self.__options.distance[2] === undefined) self.__options.distance[2] = self.__options.distance[0];
+ if (self.__options.distance[3] === undefined) self.__options.distance[3] = self.__options.distance[1];
+
+ self.__options.distance = {
+ top: self.__options.distance[0],
+ right: self.__options.distance[1],
+ bottom: self.__options.distance[2],
+ left: self.__options.distance[3]
+ };
+ }
+
+ // let's transform:
+ // 'top' into ['top', 'bottom', 'right', 'left']
+ // 'right' into ['right', 'left', 'top', 'bottom']
+ // 'bottom' into ['bottom', 'top', 'right', 'left']
+ // 'left' into ['left', 'right', 'top', 'bottom']
+ if (typeof self.__options.side == 'string') {
+
+ var opposites = {
+ 'top': 'bottom',
+ 'right': 'left',
+ 'bottom': 'top',
+ 'left': 'right'
+ };
+
+ self.__options.side = [self.__options.side, opposites[self.__options.side]];
+
+ if (self.__options.side[0] == 'left' || self.__options.side[0] == 'right') {
+ self.__options.side.push('top', 'bottom');
+ }
+ else {
+ self.__options.side.push('right', 'left');
+ }
+ }
+
+ // misc
+ // disable the arrow in IE6 unless the arrow option was explicitly set to true
+ if ( $.tooltipster._env.IE === 6
+ && self.__options.arrow !== true
+ ) {
+ self.__options.arrow = false;
+ }
+ },
+
+ /**
+ * This method must compute and set the positioning properties of the
+ * tooltip (left, top, width, height, etc.). It must also make sure the
+ * tooltip is eventually appended to its parent (since the element may be
+ * detached from the DOM at the moment the method is called).
+ *
+ * We'll evaluate positioning scenarios to find which side can contain the
+ * tooltip in the best way. We'll consider things relatively to the window
+ * (unless the user asks not to), then to the document (if need be, or if the
+ * user explicitly requires the tests to run on the document). For each
+ * scenario, measures are taken, allowing us to know how well the tooltip
+ * is going to fit. After that, a sorting function will let us know what
+ * the best scenario is (we also allow the user to choose his favorite
+ * scenario by using an event).
+ *
+ * @param {object} helper An object that contains variables that plugin
+ * creators may find useful (see below)
+ * @param {object} helper.geo An object with many layout properties
+ * about objects of interest (window, document, origin). This should help
+ * plugin users compute the optimal position of the tooltip
+ * @private
+ */
+ __reposition: function(event, helper) {
+
+ var self = this,
+ finalResult,
+ // to know where to put the tooltip, we need to know on which point
+ // of the x or y axis we should center it. That coordinate is the target
+ targets = self.__targetFind(helper),
+ testResults = [];
+
+ // make sure the tooltip is detached while we make tests on a clone
+ self.__instance._$tooltip.detach();
+
+ // we could actually provide the original element to the Ruler and
+ // not a clone, but it just feels right to keep it out of the
+ // machinery.
+ var $clone = self.__instance._$tooltip.clone(),
+ // start position tests session
+ ruler = $.tooltipster._getRuler($clone),
+ satisfied = false,
+ animation = self.__instance.option('animation');
+
+ // an animation class could contain properties that distort the size
+ if (animation) {
+ $clone.removeClass('tooltipster-'+ animation);
+ }
+
+ // start evaluating scenarios
+ $.each(['window', 'document'], function(i, container) {
+
+ var takeTest = null;
+
+ // let the user decide to keep on testing or not
+ self.__instance._trigger({
+ container: container,
+ helper: helper,
+ satisfied: satisfied,
+ takeTest: function(bool) {
+ takeTest = bool;
+ },
+ results: testResults,
+ type: 'positionTest'
+ });
+
+ if ( takeTest == true
+ || ( takeTest != false
+ && satisfied == false
+ // skip the window scenarios if asked. If they are reintegrated by
+ // the callback of the positionTest event, they will have to be
+ // excluded using the callback of positionTested
+ && (container != 'window' || self.__options.viewportAware)
+ )
+ ) {
+
+ // for each allowed side
+ for (var i=0; i < self.__options.side.length; i++) {
+
+ var distance = {
+ horizontal: 0,
+ vertical: 0
+ },
+ side = self.__options.side[i];
+
+ if (side == 'top' || side == 'bottom') {
+ distance.vertical = self.__options.distance[side];
+ }
+ else {
+ distance.horizontal = self.__options.distance[side];
+ }
+
+ // this may have an effect on the size of the tooltip if there are css
+ // rules for the arrow or something else
+ self.__sideChange($clone, side);
+
+ $.each(['natural', 'constrained'], function(i, mode) {
+
+ takeTest = null;
+
+ // emit an event on the instance
+ self.__instance._trigger({
+ container: container,
+ event: event,
+ helper: helper,
+ mode: mode,
+ results: testResults,
+ satisfied: satisfied,
+ side: side,
+ takeTest: function(bool) {
+ takeTest = bool;
+ },
+ type: 'positionTest'
+ });
+
+ if ( takeTest == true
+ || ( takeTest != false
+ && satisfied == false
+ )
+ ) {
+
+ var testResult = {
+ container: container,
+ // we let the distance as an object here, it can make things a little easier
+ // during the user's calculations at positionTest/positionTested
+ distance: distance,
+ // whether the tooltip can fit in the size of the viewport (does not mean
+ // that we'll be able to make it initially entirely visible, see 'whole')
+ fits: null,
+ mode: mode,
+ outerSize: null,
+ side: side,
+ size: null,
+ target: targets[side],
+ // check if the origin has enough surface on screen for the tooltip to
+ // aim at it without overflowing the viewport (this is due to the thickness
+ // of the arrow represented by the minIntersection length).
+ // If not, the tooltip will have to be partly or entirely off screen in
+ // order to stay docked to the origin. This value will stay null when the
+ // container is the document, as it is not relevant
+ whole: null
+ };
+
+ // get the size of the tooltip with or without size constraints
+ var rulerConfigured = (mode == 'natural') ?
+ ruler.free() :
+ ruler.constrain(
+ helper.geo.available[container][side].width - distance.horizontal,
+ helper.geo.available[container][side].height - distance.vertical
+ ),
+ rulerResults = rulerConfigured.measure();
+
+ testResult.size = rulerResults.size;
+ testResult.outerSize = {
+ height: rulerResults.size.height + distance.vertical,
+ width: rulerResults.size.width + distance.horizontal
+ };
+
+ if (mode == 'natural') {
+
+ if( helper.geo.available[container][side].width >= testResult.outerSize.width
+ && helper.geo.available[container][side].height >= testResult.outerSize.height
+ ) {
+ testResult.fits = true;
+ }
+ else {
+ testResult.fits = false;
+ }
+ }
+ else {
+ testResult.fits = rulerResults.fits;
+ }
+
+ if (container == 'window') {
+
+ if (!testResult.fits) {
+ testResult.whole = false;
+ }
+ else {
+ if (side == 'top' || side == 'bottom') {
+
+ testResult.whole = (
+ helper.geo.origin.windowOffset.right >= self.__options.minIntersection
+ && helper.geo.window.size.width - helper.geo.origin.windowOffset.left >= self.__options.minIntersection
+ );
+ }
+ else {
+ testResult.whole = (
+ helper.geo.origin.windowOffset.bottom >= self.__options.minIntersection
+ && helper.geo.window.size.height - helper.geo.origin.windowOffset.top >= self.__options.minIntersection
+ );
+ }
+ }
+ }
+
+ testResults.push(testResult);
+
+ // we don't need to compute more positions if we have one fully on screen
+ if (testResult.whole) {
+ satisfied = true;
+ }
+ else {
+ // don't run the constrained test unless the natural width was greater
+ // than the available width, otherwise it's pointless as we know it
+ // wouldn't fit either
+ if ( testResult.mode == 'natural'
+ && ( testResult.fits
+ || testResult.size.width <= helper.geo.available[container][side].width
+ )
+ ) {
+ return false;
+ }
+ }
+ }
+ });
+ }
+ }
+ });
+
+ // the user may eliminate the unwanted scenarios from testResults, but he's
+ // not supposed to alter them at this point. functionPosition and the
+ // position event serve that purpose.
+ self.__instance._trigger({
+ edit: function(r) {
+ testResults = r;
+ },
+ event: event,
+ helper: helper,
+ results: testResults,
+ type: 'positionTested'
+ });
+
+ /**
+ * Sort the scenarios to find the favorite one.
+ *
+ * The favorite scenario is when we can fully display the tooltip on screen,
+ * even if it means that the middle of the tooltip is no longer centered on
+ * the middle of the origin (when the origin is near the edge of the screen
+ * or even partly off screen). We want the tooltip on the preferred side,
+ * even if it means that we have to use a constrained size rather than a
+ * natural one (as long as it fits). When the origin is off screen at the top
+ * the tooltip will be positioned at the bottom (if allowed), if the origin
+ * is off screen on the right, it will be positioned on the left, etc.
+ * If there are no scenarios where the tooltip can fit on screen, or if the
+ * user does not want the tooltip to fit on screen (viewportAware == false),
+ * we fall back to the scenarios relative to the document.
+ *
+ * When the tooltip is bigger than the viewport in either dimension, we stop
+ * looking at the window scenarios and consider the document scenarios only,
+ * with the same logic to find on which side it would fit best.
+ *
+ * If the tooltip cannot fit the document on any side, we force it at the
+ * bottom, so at least the user can scroll to see it.
+ */
+ testResults.sort(function(a, b) {
+
+ // best if it's whole (the tooltip fits and adapts to the viewport)
+ if (a.whole && !b.whole) {
+ return -1;
+ }
+ else if (!a.whole && b.whole) {
+ return 1;
+ }
+ else if (a.whole && b.whole) {
+
+ var ai = self.__options.side.indexOf(a.side),
+ bi = self.__options.side.indexOf(b.side);
+
+ // use the user's sides fallback array
+ if (ai < bi) {
+ return -1;
+ }
+ else if (ai > bi) {
+ return 1;
+ }
+ else {
+ // will be used if the user forced the tests to continue
+ return a.mode == 'natural' ? -1 : 1;
+ }
+ }
+ else {
+
+ // better if it fits
+ if (a.fits && !b.fits) {
+ return -1;
+ }
+ else if (!a.fits && b.fits) {
+ return 1;
+ }
+ else if (a.fits && b.fits) {
+
+ var ai = self.__options.side.indexOf(a.side),
+ bi = self.__options.side.indexOf(b.side);
+
+ // use the user's sides fallback array
+ if (ai < bi) {
+ return -1;
+ }
+ else if (ai > bi) {
+ return 1;
+ }
+ else {
+ // will be used if the user forced the tests to continue
+ return a.mode == 'natural' ? -1 : 1;
+ }
+ }
+ else {
+
+ // if everything failed, this will give a preference to the case where
+ // the tooltip overflows the document at the bottom
+ if ( a.container == 'document'
+ && a.side == 'bottom'
+ && a.mode == 'natural'
+ ) {
+ return -1;
+ }
+ else {
+ return 1;
+ }
+ }
+ }
+ });
+
+ finalResult = testResults[0];
+
+
+ // now let's find the coordinates of the tooltip relatively to the window
+ finalResult.coord = {};
+
+ switch (finalResult.side) {
+
+ case 'left':
+ case 'right':
+ finalResult.coord.top = Math.floor(finalResult.target - finalResult.size.height / 2);
+ break;
+
+ case 'bottom':
+ case 'top':
+ finalResult.coord.left = Math.floor(finalResult.target - finalResult.size.width / 2);
+ break;
+ }
+
+ switch (finalResult.side) {
+
+ case 'left':
+ finalResult.coord.left = helper.geo.origin.windowOffset.left - finalResult.outerSize.width;
+ break;
+
+ case 'right':
+ finalResult.coord.left = helper.geo.origin.windowOffset.right + finalResult.distance.horizontal;
+ break;
+
+ case 'top':
+ finalResult.coord.top = helper.geo.origin.windowOffset.top - finalResult.outerSize.height;
+ break;
+
+ case 'bottom':
+ finalResult.coord.top = helper.geo.origin.windowOffset.bottom + finalResult.distance.vertical;
+ break;
+ }
+
+ // if the tooltip can potentially be contained within the viewport dimensions
+ // and that we are asked to make it fit on screen
+ if (finalResult.container == 'window') {
+
+ // if the tooltip overflows the viewport, we'll move it accordingly (then it will
+ // not be centered on the middle of the origin anymore). We only move horizontally
+ // for top and bottom tooltips and vice versa.
+ if (finalResult.side == 'top' || finalResult.side == 'bottom') {
+
+ // if there is an overflow on the left
+ if (finalResult.coord.left < 0) {
+
+ // prevent the overflow unless the origin itself gets off screen (minus the
+ // margin needed to keep the arrow pointing at the target)
+ if (helper.geo.origin.windowOffset.right - this.__options.minIntersection >= 0) {
+ finalResult.coord.left = 0;
+ }
+ else {
+ finalResult.coord.left = helper.geo.origin.windowOffset.right - this.__options.minIntersection - 1;
+ }
+ }
+ // or an overflow on the right
+ else if (finalResult.coord.left > helper.geo.window.size.width - finalResult.size.width) {
+
+ if (helper.geo.origin.windowOffset.left + this.__options.minIntersection <= helper.geo.window.size.width) {
+ finalResult.coord.left = helper.geo.window.size.width - finalResult.size.width;
+ }
+ else {
+ finalResult.coord.left = helper.geo.origin.windowOffset.left + this.__options.minIntersection + 1 - finalResult.size.width;
+ }
+ }
+ }
+ else {
+
+ // overflow at the top
+ if (finalResult.coord.top < 0) {
+
+ if (helper.geo.origin.windowOffset.bottom - this.__options.minIntersection >= 0) {
+ finalResult.coord.top = 0;
+ }
+ else {
+ finalResult.coord.top = helper.geo.origin.windowOffset.bottom - this.__options.minIntersection - 1;
+ }
+ }
+ // or at the bottom
+ else if (finalResult.coord.top > helper.geo.window.size.height - finalResult.size.height) {
+
+ if (helper.geo.origin.windowOffset.top + this.__options.minIntersection <= helper.geo.window.size.height) {
+ finalResult.coord.top = helper.geo.window.size.height - finalResult.size.height;
+ }
+ else {
+ finalResult.coord.top = helper.geo.origin.windowOffset.top + this.__options.minIntersection + 1 - finalResult.size.height;
+ }
+ }
+ }
+ }
+ else {
+
+ // there might be overflow here too but it's easier to handle. If there has
+ // to be an overflow, we'll make sure it's on the right side of the screen
+ // (because the browser will extend the document size if there is an overflow
+ // on the right, but not on the left). The sort function above has already
+ // made sure that a bottom document overflow is preferred to a top overflow,
+ // so we don't have to care about it.
+
+ // if there is an overflow on the right
+ if (finalResult.coord.left > helper.geo.window.size.width - finalResult.size.width) {
+
+ // this may actually create on overflow on the left but we'll fix it in a sec
+ finalResult.coord.left = helper.geo.window.size.width - finalResult.size.width;
+ }
+
+ // if there is an overflow on the left
+ if (finalResult.coord.left < 0) {
+
+ // don't care if it overflows the right after that, we made our best
+ finalResult.coord.left = 0;
+ }
+ }
+
+
+ // submit the positioning proposal to the user function which may choose to change
+ // the side, size and/or the coordinates
+
+ // first, set the rules that corresponds to the proposed side: it may change
+ // the size of the tooltip, and the custom functionPosition may want to detect the
+ // size of something before making a decision. So let's make things easier for the
+ // implementor
+ self.__sideChange($clone, finalResult.side);
+
+ // add some variables to the helper
+ helper.tooltipClone = $clone[0];
+ helper.tooltipParent = self.__instance.option('parent').parent[0];
+ // move informative values to the helper
+ helper.mode = finalResult.mode;
+ helper.whole = finalResult.whole;
+ // add some variables to the helper for the functionPosition callback (these
+ // will also be added to the event fired by self.__instance._trigger but that's
+ // ok, we're just being consistent)
+ helper.origin = self.__instance._$origin[0];
+ helper.tooltip = self.__instance._$tooltip[0];
+
+ // leave only the actionable values in there for functionPosition
+ delete finalResult.container;
+ delete finalResult.fits;
+ delete finalResult.mode;
+ delete finalResult.outerSize;
+ delete finalResult.whole;
+
+ // keep only the distance on the relevant side, for clarity
+ finalResult.distance = finalResult.distance.horizontal || finalResult.distance.vertical;
+
+ // beginners may not be comfortable with the concept of editing the object
+ // passed by reference, so we provide an edit function and pass a clone
+ var finalResultClone = $.extend(true, {}, finalResult);
+
+ // emit an event on the instance
+ self.__instance._trigger({
+ edit: function(result) {
+ finalResult = result;
+ },
+ event: event,
+ helper: helper,
+ position: finalResultClone,
+ type: 'position'
+ });
+
+ if (self.__options.functionPosition) {
+
+ var result = self.__options.functionPosition.call(self, self.__instance, helper, finalResultClone);
+
+ if (result) finalResult = result;
+ }
+
+ // end the positioning tests session (the user might have had a
+ // use for it during the position event, now it's over)
+ ruler.destroy();
+
+ // compute the position of the target relatively to the tooltip root
+ // element so we can place the arrow and make the needed adjustments
+ var arrowCoord,
+ maxVal;
+
+ if (finalResult.side == 'top' || finalResult.side == 'bottom') {
+
+ arrowCoord = {
+ prop: 'left',
+ val: finalResult.target - finalResult.coord.left
+ };
+ maxVal = finalResult.size.width - this.__options.minIntersection;
+ }
+ else {
+
+ arrowCoord = {
+ prop: 'top',
+ val: finalResult.target - finalResult.coord.top
+ };
+ maxVal = finalResult.size.height - this.__options.minIntersection;
+ }
+
+ // cannot lie beyond the boundaries of the tooltip, minus the
+ // arrow margin
+ if (arrowCoord.val < this.__options.minIntersection) {
+ arrowCoord.val = this.__options.minIntersection;
+ }
+ else if (arrowCoord.val > maxVal) {
+ arrowCoord.val = maxVal;
+ }
+
+ var originParentOffset;
+
+ // let's convert the window-relative coordinates into coordinates relative to the
+ // future positioned parent that the tooltip will be appended to
+ if (helper.geo.origin.fixedLineage) {
+
+ // same as windowOffset when the position is fixed
+ originParentOffset = helper.geo.origin.windowOffset;
+ }
+ else {
+
+ // this assumes that the parent of the tooltip is located at
+ // (0, 0) in the document, typically like when the parent is
+ // <body>.
+ // If we ever allow other types of parent, .tooltipster-ruler
+ // will have to be appended to the parent to inherit css style
+ // values that affect the display of the text and such.
+ originParentOffset = {
+ left: helper.geo.origin.windowOffset.left + helper.geo.window.scroll.left,
+ top: helper.geo.origin.windowOffset.top + helper.geo.window.scroll.top
+ };
+ }
+
+ finalResult.coord = {
+ left: originParentOffset.left + (finalResult.coord.left - helper.geo.origin.windowOffset.left),
+ top: originParentOffset.top + (finalResult.coord.top - helper.geo.origin.windowOffset.top)
+ };
+
+ // set position values on the original tooltip element
+
+ self.__sideChange(self.__instance._$tooltip, finalResult.side);
+
+ if (helper.geo.origin.fixedLineage) {
+ self.__instance._$tooltip
+ .css('position', 'fixed');
+ }
+ else {
+ // CSS default
+ self.__instance._$tooltip
+ .css('position', '');
+ }
+
+ self.__instance._$tooltip
+ .css({
+ left: finalResult.coord.left,
+ top: finalResult.coord.top,
+ // we need to set a size even if the tooltip is in its natural size
+ // because when the tooltip is positioned beyond the width of the body
+ // (which is by default the width of the window; it will happen when
+ // you scroll the window horizontally to get to the origin), its text
+ // content will otherwise break lines at each word to keep up with the
+ // body overflow strategy.
+ height: finalResult.size.height,
+ width: finalResult.size.width
+ })
+ .find('.tooltipster-arrow')
+ .css({
+ 'left': '',
+ 'top': ''
+ })
+ .css(arrowCoord.prop, arrowCoord.val);
+
+ // append the tooltip HTML element to its parent
+ self.__instance._$tooltip.appendTo(self.__instance.option('parent'));
+
+ self.__instance._trigger({
+ type: 'repositioned',
+ event: event,
+ position: finalResult
+ });
+ },
+
+ /**
+ * Make whatever modifications are needed when the side is changed. This has
+ * been made an independant method for easy inheritance in custom plugins based
+ * on this default plugin.
+ *
+ * @param {object} $obj
+ * @param {string} side
+ * @private
+ */
+ __sideChange: function($obj, side) {
+
+ $obj
+ .removeClass('tooltipster-bottom')
+ .removeClass('tooltipster-left')
+ .removeClass('tooltipster-right')
+ .removeClass('tooltipster-top')
+ .addClass('tooltipster-'+ side);
+ },
+
+ /**
+ * Returns the target that the tooltip should aim at for a given side.
+ * The calculated value is a distance from the edge of the window
+ * (left edge for top/bottom sides, top edge for left/right side). The
+ * tooltip will be centered on that position and the arrow will be
+ * positioned there (as much as possible).
+ *
+ * @param {object} helper
+ * @return {integer}
+ * @private
+ */
+ __targetFind: function(helper) {
+
+ var target = {},
+ rects = this.__instance._$origin[0].getClientRects();
+
+ // these lines fix a Chrome bug (issue #491)
+ if (rects.length > 1) {
+ var opacity = this.__instance._$origin.css('opacity');
+ if(opacity == 1) {
+ this.__instance._$origin.css('opacity', 0.99);
+ rects = this.__instance._$origin[0].getClientRects();
+ this.__instance._$origin.css('opacity', 1);
+ }
+ }
+
+ // by default, the target will be the middle of the origin
+ if (rects.length < 2) {
+
+ target.top = Math.floor(helper.geo.origin.windowOffset.left + (helper.geo.origin.size.width / 2));
+ target.bottom = target.top;
+
+ target.left = Math.floor(helper.geo.origin.windowOffset.top + (helper.geo.origin.size.height / 2));
+ target.right = target.left;
+ }
+ // if multiple client rects exist, the element may be text split
+ // up into multiple lines and the middle of the origin may not be
+ // best option anymore. We need to choose the best target client rect
+ else {
+
+ // top: the first
+ var targetRect = rects[0];
+ target.top = Math.floor(targetRect.left + (targetRect.right - targetRect.left) / 2);
+
+ // right: the middle line, rounded down in case there is an even
+ // number of lines (looks more centered => check out the
+ // demo with 4 split lines)
+ if (rects.length > 2) {
+ targetRect = rects[Math.ceil(rects.length / 2) - 1];
+ }
+ else {
+ targetRect = rects[0];
+ }
+ target.right = Math.floor(targetRect.top + (targetRect.bottom - targetRect.top) / 2);
+
+ // bottom: the last
+ targetRect = rects[rects.length - 1];
+ target.bottom = Math.floor(targetRect.left + (targetRect.right - targetRect.left) / 2);
+
+ // left: the middle line, rounded up
+ if (rects.length > 2) {
+ targetRect = rects[Math.ceil((rects.length + 1) / 2) - 1];
+ }
+ else {
+ targetRect = rects[rects.length - 1];
+ }
+
+ target.left = Math.floor(targetRect.top + (targetRect.bottom - targetRect.top) / 2);
+ }
+
+ return target;
+ }
+ }
+});
+
+/* a build task will add "return $;" here */
+return $;
+
+}));
diff --git a/src/lib/vendor/underscore-1.9.1.js b/src/lib/vendor/underscore-1.9.1.js
new file mode 100644
index 0000000..8219dc5
--- /dev/null
+++ b/src/lib/vendor/underscore-1.9.1.js
@@ -0,0 +1,1692 @@
+// Underscore.js 1.9.1
+// http://underscorejs.org
+// (c) 2009-2018 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
+// Underscore may be freely distributed under the MIT license.
+
+(function() {
+
+ // Baseline setup
+ // --------------
+
+ // Establish the root object, `window` (`self`) in the browser, `global`
+ // on the server, or `this` in some virtual machines. We use `self`
+ // instead of `window` for `WebWorker` support.
+ var root = typeof self == 'object' && self.self === self && self ||
+ typeof global == 'object' && global.global === global && global ||
+ this ||
+ {};
+
+ // Save the previous value of the `_` variable.
+ var previousUnderscore = root._;
+
+ // Save bytes in the minified (but not gzipped) version:
+ var ArrayProto = Array.prototype, ObjProto = Object.prototype;
+ var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null;
+
+ // Create quick reference variables for speed access to core prototypes.
+ var push = ArrayProto.push,
+ slice = ArrayProto.slice,
+ toString = ObjProto.toString,
+ hasOwnProperty = ObjProto.hasOwnProperty;
+
+ // All **ECMAScript 5** native function implementations that we hope to use
+ // are declared here.
+ var nativeIsArray = Array.isArray,
+ nativeKeys = Object.keys,
+ nativeCreate = Object.create;
+
+ // Naked function reference for surrogate-prototype-swapping.
+ var Ctor = function(){};
+
+ // Create a safe reference to the Underscore object for use below.
+ var _ = function(obj) {
+ if (obj instanceof _) return obj;
+ if (!(this instanceof _)) return new _(obj);
+ this._wrapped = obj;
+ };
+
+ // Export the Underscore object for **Node.js**, with
+ // backwards-compatibility for their old module API. If we're in
+ // the browser, add `_` as a global object.
+ // (`nodeType` is checked to ensure that `module`
+ // and `exports` are not HTML elements.)
+ if (typeof exports != 'undefined' && !exports.nodeType) {
+ if (typeof module != 'undefined' && !module.nodeType && module.exports) {
+ exports = module.exports = _;
+ }
+ exports._ = _;
+ } else {
+ root._ = _;
+ }
+
+ // Current version.
+ _.VERSION = '1.9.1';
+
+ // Internal function that returns an efficient (for current engines) version
+ // of the passed-in callback, to be repeatedly applied in other Underscore
+ // functions.
+ var optimizeCb = function(func, context, argCount) {
+ if (context === void 0) return func;
+ switch (argCount == null ? 3 : argCount) {
+ case 1: return function(value) {
+ return func.call(context, value);
+ };
+ // The 2-argument case is omitted because we’re not using it.
+ case 3: return function(value, index, collection) {
+ return func.call(context, value, index, collection);
+ };
+ case 4: return function(accumulator, value, index, collection) {
+ return func.call(context, accumulator, value, index, collection);
+ };
+ }
+ return function() {
+ return func.apply(context, arguments);
+ };
+ };
+
+ var builtinIteratee;
+
+ // An internal function to generate callbacks that can be applied to each
+ // element in a collection, returning the desired result — either `identity`,
+ // an arbitrary callback, a property matcher, or a property accessor.
+ var cb = function(value, context, argCount) {
+ if (_.iteratee !== builtinIteratee) return _.iteratee(value, context);
+ if (value == null) return _.identity;
+ if (_.isFunction(value)) return optimizeCb(value, context, argCount);
+ if (_.isObject(value) && !_.isArray(value)) return _.matcher(value);
+ return _.property(value);
+ };
+
+ // External wrapper for our callback generator. Users may customize
+ // `_.iteratee` if they want additional predicate/iteratee shorthand styles.
+ // This abstraction hides the internal-only argCount argument.
+ _.iteratee = builtinIteratee = function(value, context) {
+ return cb(value, context, Infinity);
+ };
+
+ // Some functions take a variable number of arguments, or a few expected
+ // arguments at the beginning and then a variable number of values to operate
+ // on. This helper accumulates all remaining arguments past the function’s
+ // argument length (or an explicit `startIndex`), into an array that becomes
+ // the last argument. Similar to ES6’s "rest parameter".
+ var restArguments = function(func, startIndex) {
+ startIndex = startIndex == null ? func.length - 1 : +startIndex;
+ return function() {
+ var length = Math.max(arguments.length - startIndex, 0),
+ rest = Array(length),
+ index = 0;
+ for (; index < length; index++) {
+ rest[index] = arguments[index + startIndex];
+ }
+ switch (startIndex) {
+ case 0: return func.call(this, rest);
+ case 1: return func.call(this, arguments[0], rest);
+ case 2: return func.call(this, arguments[0], arguments[1], rest);
+ }
+ var args = Array(startIndex + 1);
+ for (index = 0; index < startIndex; index++) {
+ args[index] = arguments[index];
+ }
+ args[startIndex] = rest;
+ return func.apply(this, args);
+ };
+ };
+
+ // An internal function for creating a new object that inherits from another.
+ var baseCreate = function(prototype) {
+ if (!_.isObject(prototype)) return {};
+ if (nativeCreate) return nativeCreate(prototype);
+ Ctor.prototype = prototype;
+ var result = new Ctor;
+ Ctor.prototype = null;
+ return result;
+ };
+
+ var shallowProperty = function(key) {
+ return function(obj) {
+ return obj == null ? void 0 : obj[key];
+ };
+ };
+
+ var has = function(obj, path) {
+ return obj != null && hasOwnProperty.call(obj, path);
+ }
+
+ var deepGet = function(obj, path) {
+ var length = path.length;
+ for (var i = 0; i < length; i++) {
+ if (obj == null) return void 0;
+ obj = obj[path[i]];
+ }
+ return length ? obj : void 0;
+ };
+
+ // Helper for collection methods to determine whether a collection
+ // should be iterated as an array or as an object.
+ // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
+ // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
+ var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
+ var getLength = shallowProperty('length');
+ var isArrayLike = function(collection) {
+ var length = getLength(collection);
+ return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
+ };
+
+ // Collection Functions
+ // --------------------
+
+ // The cornerstone, an `each` implementation, aka `forEach`.
+ // Handles raw objects in addition to array-likes. Treats all
+ // sparse array-likes as if they were dense.
+ _.each = _.forEach = function(obj, iteratee, context) {
+ iteratee = optimizeCb(iteratee, context);
+ var i, length;
+ if (isArrayLike(obj)) {
+ for (i = 0, length = obj.length; i < length; i++) {
+ iteratee(obj[i], i, obj);
+ }
+ } else {
+ var keys = _.keys(obj);
+ for (i = 0, length = keys.length; i < length; i++) {
+ iteratee(obj[keys[i]], keys[i], obj);
+ }
+ }
+ return obj;
+ };
+
+ // Return the results of applying the iteratee to each element.
+ _.map = _.collect = function(obj, iteratee, context) {
+ iteratee = cb(iteratee, context);
+ var keys = !isArrayLike(obj) && _.keys(obj),
+ length = (keys || obj).length,
+ results = Array(length);
+ for (var index = 0; index < length; index++) {
+ var currentKey = keys ? keys[index] : index;
+ results[index] = iteratee(obj[currentKey], currentKey, obj);
+ }
+ return results;
+ };
+
+ // Create a reducing function iterating left or right.
+ var createReduce = function(dir) {
+ // Wrap code that reassigns argument variables in a separate function than
+ // the one that accesses `arguments.length` to avoid a perf hit. (#1991)
+ var reducer = function(obj, iteratee, memo, initial) {
+ var keys = !isArrayLike(obj) && _.keys(obj),
+ length = (keys || obj).length,
+ index = dir > 0 ? 0 : length - 1;
+ if (!initial) {
+ memo = obj[keys ? keys[index] : index];
+ index += dir;
+ }
+ for (; index >= 0 && index < length; index += dir) {
+ var currentKey = keys ? keys[index] : index;
+ memo = iteratee(memo, obj[currentKey], currentKey, obj);
+ }
+ return memo;
+ };
+
+ return function(obj, iteratee, memo, context) {
+ var initial = arguments.length >= 3;
+ return reducer(obj, optimizeCb(iteratee, context, 4), memo, initial);
+ };
+ };
+
+ // **Reduce** builds up a single result from a list of values, aka `inject`,
+ // or `foldl`.
+ _.reduce = _.foldl = _.inject = createReduce(1);
+
+ // The right-associative version of reduce, also known as `foldr`.
+ _.reduceRight = _.foldr = createReduce(-1);
+
+ // Return the first value which passes a truth test. Aliased as `detect`.
+ _.find = _.detect = function(obj, predicate, context) {
+ var keyFinder = isArrayLike(obj) ? _.findIndex : _.findKey;
+ var key = keyFinder(obj, predicate, context);
+ if (key !== void 0 && key !== -1) return obj[key];
+ };
+
+ // Return all the elements that pass a truth test.
+ // Aliased as `select`.
+ _.filter = _.select = function(obj, predicate, context) {
+ var results = [];
+ predicate = cb(predicate, context);
+ _.each(obj, function(value, index, list) {
+ if (predicate(value, index, list)) results.push(value);
+ });
+ return results;
+ };
+
+ // Return all the elements for which a truth test fails.
+ _.reject = function(obj, predicate, context) {
+ return _.filter(obj, _.negate(cb(predicate)), context);
+ };
+
+ // Determine whether all of the elements match a truth test.
+ // Aliased as `all`.
+ _.every = _.all = function(obj, predicate, context) {
+ predicate = cb(predicate, context);
+ var keys = !isArrayLike(obj) && _.keys(obj),
+ length = (keys || obj).length;
+ for (var index = 0; index < length; index++) {
+ var currentKey = keys ? keys[index] : index;
+ if (!predicate(obj[currentKey], currentKey, obj)) return false;
+ }
+ return true;
+ };
+
+ // Determine if at least one element in the object matches a truth test.
+ // Aliased as `any`.
+ _.some = _.any = function(obj, predicate, context) {
+ predicate = cb(predicate, context);
+ var keys = !isArrayLike(obj) && _.keys(obj),
+ length = (keys || obj).length;
+ for (var index = 0; index < length; index++) {
+ var currentKey = keys ? keys[index] : index;
+ if (predicate(obj[currentKey], currentKey, obj)) return true;
+ }
+ return false;
+ };
+
+ // Determine if the array or object contains a given item (using `===`).
+ // Aliased as `includes` and `include`.
+ _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {
+ if (!isArrayLike(obj)) obj = _.values(obj);
+ if (typeof fromIndex != 'number' || guard) fromIndex = 0;
+ return _.indexOf(obj, item, fromIndex) >= 0;
+ };
+
+ // Invoke a method (with arguments) on every item in a collection.
+ _.invoke = restArguments(function(obj, path, args) {
+ var contextPath, func;
+ if (_.isFunction(path)) {
+ func = path;
+ } else if (_.isArray(path)) {
+ contextPath = path.slice(0, -1);
+ path = path[path.length - 1];
+ }
+ return _.map(obj, function(context) {
+ var method = func;
+ if (!method) {
+ if (contextPath && contextPath.length) {
+ context = deepGet(context, contextPath);
+ }
+ if (context == null) return void 0;
+ method = context[path];
+ }
+ return method == null ? method : method.apply(context, args);
+ });
+ });
+
+ // Convenience version of a common use case of `map`: fetching a property.
+ _.pluck = function(obj, key) {
+ return _.map(obj, _.property(key));
+ };
+
+ // Convenience version of a common use case of `filter`: selecting only objects
+ // containing specific `key:value` pairs.
+ _.where = function(obj, attrs) {
+ return _.filter(obj, _.matcher(attrs));
+ };
+
+ // Convenience version of a common use case of `find`: getting the first object
+ // containing specific `key:value` pairs.
+ _.findWhere = function(obj, attrs) {
+ return _.find(obj, _.matcher(attrs));
+ };
+
+ // Return the maximum element (or element-based computation).
+ _.max = function(obj, iteratee, context) {
+ var result = -Infinity, lastComputed = -Infinity,
+ value, computed;
+ if (iteratee == null || typeof iteratee == 'number' && typeof obj[0] != 'object' && obj != null) {
+ obj = isArrayLike(obj) ? obj : _.values(obj);
+ for (var i = 0, length = obj.length; i < length; i++) {
+ value = obj[i];
+ if (value != null && value > result) {
+ result = value;
+ }
+ }
+ } else {
+ iteratee = cb(iteratee, context);
+ _.each(obj, function(v, index, list) {
+ computed = iteratee(v, index, list);
+ if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
+ result = v;
+ lastComputed = computed;
+ }
+ });
+ }
+ return result;
+ };
+
+ // Return the minimum element (or element-based computation).
+ _.min = function(obj, iteratee, context) {
+ var result = Infinity, lastComputed = Infinity,
+ value, computed;
+ if (iteratee == null || typeof iteratee == 'number' && typeof obj[0] != 'object' && obj != null) {
+ obj = isArrayLike(obj) ? obj : _.values(obj);
+ for (var i = 0, length = obj.length; i < length; i++) {
+ value = obj[i];
+ if (value != null && value < result) {
+ result = value;
+ }
+ }
+ } else {
+ iteratee = cb(iteratee, context);
+ _.each(obj, function(v, index, list) {
+ computed = iteratee(v, index, list);
+ if (computed < lastComputed || computed === Infinity && result === Infinity) {
+ result = v;
+ lastComputed = computed;
+ }
+ });
+ }
+ return result;
+ };
+
+ // Shuffle a collection.
+ _.shuffle = function(obj) {
+ return _.sample(obj, Infinity);
+ };
+
+ // Sample **n** random values from a collection using the modern version of the
+ // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
+ // If **n** is not specified, returns a single random element.
+ // The internal `guard` argument allows it to work with `map`.
+ _.sample = function(obj, n, guard) {
+ if (n == null || guard) {
+ if (!isArrayLike(obj)) obj = _.values(obj);
+ return obj[_.random(obj.length - 1)];
+ }
+ var sample = isArrayLike(obj) ? _.clone(obj) : _.values(obj);
+ var length = getLength(sample);
+ n = Math.max(Math.min(n, length), 0);
+ var last = length - 1;
+ for (var index = 0; index < n; index++) {
+ var rand = _.random(index, last);
+ var temp = sample[index];
+ sample[index] = sample[rand];
+ sample[rand] = temp;
+ }
+ return sample.slice(0, n);
+ };
+
+ // Sort the object's values by a criterion produced by an iteratee.
+ _.sortBy = function(obj, iteratee, context) {
+ var index = 0;
+ iteratee = cb(iteratee, context);
+ return _.pluck(_.map(obj, function(value, key, list) {
+ return {
+ value: value,
+ index: index++,
+ criteria: iteratee(value, key, list)
+ };
+ }).sort(function(left, right) {
+ var a = left.criteria;
+ var b = right.criteria;
+ if (a !== b) {
+ if (a > b || a === void 0) return 1;
+ if (a < b || b === void 0) return -1;
+ }
+ return left.index - right.index;
+ }), 'value');
+ };
+
+ // An internal function used for aggregate "group by" operations.
+ var group = function(behavior, partition) {
+ return function(obj, iteratee, context) {
+ var result = partition ? [[], []] : {};
+ iteratee = cb(iteratee, context);
+ _.each(obj, function(value, index) {
+ var key = iteratee(value, index, obj);
+ behavior(result, value, key);
+ });
+ return result;
+ };
+ };
+
+ // Groups the object's values by a criterion. Pass either a string attribute
+ // to group by, or a function that returns the criterion.
+ _.groupBy = group(function(result, value, key) {
+ if (has(result, key)) result[key].push(value); else result[key] = [value];
+ });
+
+ // Indexes the object's values by a criterion, similar to `groupBy`, but for
+ // when you know that your index values will be unique.
+ _.indexBy = group(function(result, value, key) {
+ result[key] = value;
+ });
+
+ // Counts instances of an object that group by a certain criterion. Pass
+ // either a string attribute to count by, or a function that returns the
+ // criterion.
+ _.countBy = group(function(result, value, key) {
+ if (has(result, key)) result[key]++; else result[key] = 1;
+ });
+
+ var reStrSymbol = /[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/g;
+ // Safely create a real, live array from anything iterable.
+ _.toArray = function(obj) {
+ if (!obj) return [];
+ if (_.isArray(obj)) return slice.call(obj);
+ if (_.isString(obj)) {
+ // Keep surrogate pair characters together
+ return obj.match(reStrSymbol);
+ }
+ if (isArrayLike(obj)) return _.map(obj, _.identity);
+ return _.values(obj);
+ };
+
+ // Return the number of elements in an object.
+ _.size = function(obj) {
+ if (obj == null) return 0;
+ return isArrayLike(obj) ? obj.length : _.keys(obj).length;
+ };
+
+ // Split a collection into two arrays: one whose elements all satisfy the given
+ // predicate, and one whose elements all do not satisfy the predicate.
+ _.partition = group(function(result, value, pass) {
+ result[pass ? 0 : 1].push(value);
+ }, true);
+
+ // Array Functions
+ // ---------------
+
+ // Get the first element of an array. Passing **n** will return the first N
+ // values in the array. Aliased as `head` and `take`. The **guard** check
+ // allows it to work with `_.map`.
+ _.first = _.head = _.take = function(array, n, guard) {
+ if (array == null || array.length < 1) return n == null ? void 0 : [];
+ if (n == null || guard) return array[0];
+ return _.initial(array, array.length - n);
+ };
+
+ // Returns everything but the last entry of the array. Especially useful on
+ // the arguments object. Passing **n** will return all the values in
+ // the array, excluding the last N.
+ _.initial = function(array, n, guard) {
+ return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
+ };
+
+ // Get the last element of an array. Passing **n** will return the last N
+ // values in the array.
+ _.last = function(array, n, guard) {
+ if (array == null || array.length < 1) return n == null ? void 0 : [];
+ if (n == null || guard) return array[array.length - 1];
+ return _.rest(array, Math.max(0, array.length - n));
+ };
+
+ // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
+ // Especially useful on the arguments object. Passing an **n** will return
+ // the rest N values in the array.
+ _.rest = _.tail = _.drop = function(array, n, guard) {
+ return slice.call(array, n == null || guard ? 1 : n);
+ };
+
+ // Trim out all falsy values from an array.
+ _.compact = function(array) {
+ return _.filter(array, Boolean);
+ };
+
+ // Internal implementation of a recursive `flatten` function.
+ var flatten = function(input, shallow, strict, output) {
+ output = output || [];
+ var idx = output.length;
+ for (var i = 0, length = getLength(input); i < length; i++) {
+ var value = input[i];
+ if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
+ // Flatten current level of array or arguments object.
+ if (shallow) {
+ var j = 0, len = value.length;
+ while (j < len) output[idx++] = value[j++];
+ } else {
+ flatten(value, shallow, strict, output);
+ idx = output.length;
+ }
+ } else if (!strict) {
+ output[idx++] = value;
+ }
+ }
+ return output;
+ };
+
+ // Flatten out an array, either recursively (by default), or just one level.
+ _.flatten = function(array, shallow) {
+ return flatten(array, shallow, false);
+ };
+
+ // Return a version of the array that does not contain the specified value(s).
+ _.without = restArguments(function(array, otherArrays) {
+ return _.difference(array, otherArrays);
+ });
+
+ // Produce a duplicate-free version of the array. If the array has already
+ // been sorted, you have the option of using a faster algorithm.
+ // The faster algorithm will not work with an iteratee if the iteratee
+ // is not a one-to-one function, so providing an iteratee will disable
+ // the faster algorithm.
+ // Aliased as `unique`.
+ _.uniq = _.unique = function(array, isSorted, iteratee, context) {
+ if (!_.isBoolean(isSorted)) {
+ context = iteratee;
+ iteratee = isSorted;
+ isSorted = false;
+ }
+ if (iteratee != null) iteratee = cb(iteratee, context);
+ var result = [];
+ var seen = [];
+ for (var i = 0, length = getLength(array); i < length; i++) {
+ var value = array[i],
+ computed = iteratee ? iteratee(value, i, array) : value;
+ if (isSorted && !iteratee) {
+ if (!i || seen !== computed) result.push(value);
+ seen = computed;
+ } else if (iteratee) {
+ if (!_.contains(seen, computed)) {
+ seen.push(computed);
+ result.push(value);
+ }
+ } else if (!_.contains(result, value)) {
+ result.push(value);
+ }
+ }
+ return result;
+ };
+
+ // Produce an array that contains the union: each distinct element from all of
+ // the passed-in arrays.
+ _.union = restArguments(function(arrays) {
+ return _.uniq(flatten(arrays, true, true));
+ });
+
+ // Produce an array that contains every item shared between all the
+ // passed-in arrays.
+ _.intersection = function(array) {
+ var result = [];
+ var argsLength = arguments.length;
+ for (var i = 0, length = getLength(array); i < length; i++) {
+ var item = array[i];
+ if (_.contains(result, item)) continue;
+ var j;
+ for (j = 1; j < argsLength; j++) {
+ if (!_.contains(arguments[j], item)) break;
+ }
+ if (j === argsLength) result.push(item);
+ }
+ return result;
+ };
+
+ // Take the difference between one array and a number of other arrays.
+ // Only the elements present in just the first array will remain.
+ _.difference = restArguments(function(array, rest) {
+ rest = flatten(rest, true, true);
+ return _.filter(array, function(value){
+ return !_.contains(rest, value);
+ });
+ });
+
+ // Complement of _.zip. Unzip accepts an array of arrays and groups
+ // each array's elements on shared indices.
+ _.unzip = function(array) {
+ var length = array && _.max(array, getLength).length || 0;
+ var result = Array(length);
+
+ for (var index = 0; index < length; index++) {
+ result[index] = _.pluck(array, index);
+ }
+ return result;
+ };
+
+ // Zip together multiple lists into a single array -- elements that share
+ // an index go together.
+ _.zip = restArguments(_.unzip);
+
+ // Converts lists into objects. Pass either a single array of `[key, value]`
+ // pairs, or two parallel arrays of the same length -- one of keys, and one of
+ // the corresponding values. Passing by pairs is the reverse of _.pairs.
+ _.object = function(list, values) {
+ var result = {};
+ for (var i = 0, length = getLength(list); i < length; i++) {
+ if (values) {
+ result[list[i]] = values[i];
+ } else {
+ result[list[i][0]] = list[i][1];
+ }
+ }
+ return result;
+ };
+
+ // Generator function to create the findIndex and findLastIndex functions.
+ var createPredicateIndexFinder = function(dir) {
+ return function(array, predicate, context) {
+ predicate = cb(predicate, context);
+ var length = getLength(array);
+ var index = dir > 0 ? 0 : length - 1;
+ for (; index >= 0 && index < length; index += dir) {
+ if (predicate(array[index], index, array)) return index;
+ }
+ return -1;
+ };
+ };
+
+ // Returns the first index on an array-like that passes a predicate test.
+ _.findIndex = createPredicateIndexFinder(1);
+ _.findLastIndex = createPredicateIndexFinder(-1);
+
+ // Use a comparator function to figure out the smallest index at which
+ // an object should be inserted so as to maintain order. Uses binary search.
+ _.sortedIndex = function(array, obj, iteratee, context) {
+ iteratee = cb(iteratee, context, 1);
+ var value = iteratee(obj);
+ var low = 0, high = getLength(array);
+ while (low < high) {
+ var mid = Math.floor((low + high) / 2);
+ if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
+ }
+ return low;
+ };
+
+ // Generator function to create the indexOf and lastIndexOf functions.
+ var createIndexFinder = function(dir, predicateFind, sortedIndex) {
+ return function(array, item, idx) {
+ var i = 0, length = getLength(array);
+ if (typeof idx == 'number') {
+ if (dir > 0) {
+ i = idx >= 0 ? idx : Math.max(idx + length, i);
+ } else {
+ length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
+ }
+ } else if (sortedIndex && idx && length) {
+ idx = sortedIndex(array, item);
+ return array[idx] === item ? idx : -1;
+ }
+ if (item !== item) {
+ idx = predicateFind(slice.call(array, i, length), _.isNaN);
+ return idx >= 0 ? idx + i : -1;
+ }
+ for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
+ if (array[idx] === item) return idx;
+ }
+ return -1;
+ };
+ };
+
+ // Return the position of the first occurrence of an item in an array,
+ // or -1 if the item is not included in the array.
+ // If the array is large and already in sort order, pass `true`
+ // for **isSorted** to use binary search.
+ _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
+ _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
+
+ // Generate an integer Array containing an arithmetic progression. A port of
+ // the native Python `range()` function. See
+ // [the Python documentation](http://docs.python.org/library/functions.html#range).
+ _.range = function(start, stop, step) {
+ if (stop == null) {
+ stop = start || 0;
+ start = 0;
+ }
+ if (!step) {
+ step = stop < start ? -1 : 1;
+ }
+
+ var length = Math.max(Math.ceil((stop - start) / step), 0);
+ var range = Array(length);
+
+ for (var idx = 0; idx < length; idx++, start += step) {
+ range[idx] = start;
+ }
+
+ return range;
+ };
+
+ // Chunk a single array into multiple arrays, each containing `count` or fewer
+ // items.
+ _.chunk = function(array, count) {
+ if (count == null || count < 1) return [];
+ var result = [];
+ var i = 0, length = array.length;
+ while (i < length) {
+ result.push(slice.call(array, i, i += count));
+ }
+ return result;
+ };
+
+ // Function (ahem) Functions
+ // ------------------
+
+ // Determines whether to execute a function as a constructor
+ // or a normal function with the provided arguments.
+ var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
+ if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
+ var self = baseCreate(sourceFunc.prototype);
+ var result = sourceFunc.apply(self, args);
+ if (_.isObject(result)) return result;
+ return self;
+ };
+
+ // Create a function bound to a given object (assigning `this`, and arguments,
+ // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
+ // available.
+ _.bind = restArguments(function(func, context, args) {
+ if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
+ var bound = restArguments(function(callArgs) {
+ return executeBound(func, bound, context, this, args.concat(callArgs));
+ });
+ return bound;
+ });
+
+ // Partially apply a function by creating a version that has had some of its
+ // arguments pre-filled, without changing its dynamic `this` context. _ acts
+ // as a placeholder by default, allowing any combination of arguments to be
+ // pre-filled. Set `_.partial.placeholder` for a custom placeholder argument.
+ _.partial = restArguments(function(func, boundArgs) {
+ var placeholder = _.partial.placeholder;
+ var bound = function() {
+ var position = 0, length = boundArgs.length;
+ var args = Array(length);
+ for (var i = 0; i < length; i++) {
+ args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundArgs[i];
+ }
+ while (position < arguments.length) args.push(arguments[position++]);
+ return executeBound(func, bound, this, this, args);
+ };
+ return bound;
+ });
+
+ _.partial.placeholder = _;
+
+ // Bind a number of an object's methods to that object. Remaining arguments
+ // are the method names to be bound. Useful for ensuring that all callbacks
+ // defined on an object belong to it.
+ _.bindAll = restArguments(function(obj, keys) {
+ keys = flatten(keys, false, false);
+ var index = keys.length;
+ if (index < 1) throw new Error('bindAll must be passed function names');
+ while (index--) {
+ var key = keys[index];
+ obj[key] = _.bind(obj[key], obj);
+ }
+ });
+
+ // Memoize an expensive function by storing its results.
+ _.memoize = function(func, hasher) {
+ var memoize = function(key) {
+ var cache = memoize.cache;
+ var address = '' + (hasher ? hasher.apply(this, arguments) : key);
+ if (!has(cache, address)) cache[address] = func.apply(this, arguments);
+ return cache[address];
+ };
+ memoize.cache = {};
+ return memoize;
+ };
+
+ // Delays a function for the given number of milliseconds, and then calls
+ // it with the arguments supplied.
+ _.delay = restArguments(function(func, wait, args) {
+ return setTimeout(function() {
+ return func.apply(null, args);
+ }, wait);
+ });
+
+ // Defers a function, scheduling it to run after the current call stack has
+ // cleared.
+ _.defer = _.partial(_.delay, _, 1);
+
+ // Returns a function, that, when invoked, will only be triggered at most once
+ // during a given window of time. Normally, the throttled function will run
+ // as much as it can, without ever going more than once per `wait` duration;
+ // but if you'd like to disable the execution on the leading edge, pass
+ // `{leading: false}`. To disable execution on the trailing edge, ditto.
+ _.throttle = function(func, wait, options) {
+ var timeout, context, args, result;
+ var previous = 0;
+ if (!options) options = {};
+
+ var later = function() {
+ previous = options.leading === false ? 0 : _.now();
+ timeout = null;
+ result = func.apply(context, args);
+ if (!timeout) context = args = null;
+ };
+
+ var throttled = function() {
+ var now = _.now();
+ if (!previous && options.leading === false) previous = now;
+ var remaining = wait - (now - previous);
+ context = this;
+ args = arguments;
+ if (remaining <= 0 || remaining > wait) {
+ if (timeout) {
+ clearTimeout(timeout);
+ timeout = null;
+ }
+ previous = now;
+ result = func.apply(context, args);
+ if (!timeout) context = args = null;
+ } else if (!timeout && options.trailing !== false) {
+ timeout = setTimeout(later, remaining);
+ }
+ return result;
+ };
+
+ throttled.cancel = function() {
+ clearTimeout(timeout);
+ previous = 0;
+ timeout = context = args = null;
+ };
+
+ return throttled;
+ };
+
+ // Returns a function, that, as long as it continues to be invoked, will not
+ // be triggered. The function will be called after it stops being called for
+ // N milliseconds. If `immediate` is passed, trigger the function on the
+ // leading edge, instead of the trailing.
+ _.debounce = function(func, wait, immediate) {
+ var timeout, result;
+
+ var later = function(context, args) {
+ timeout = null;
+ if (args) result = func.apply(context, args);
+ };
+
+ var debounced = restArguments(function(args) {
+ if (timeout) clearTimeout(timeout);
+ if (immediate) {
+ var callNow = !timeout;
+ timeout = setTimeout(later, wait);
+ if (callNow) result = func.apply(this, args);
+ } else {
+ timeout = _.delay(later, wait, this, args);
+ }
+
+ return result;
+ });
+
+ debounced.cancel = function() {
+ clearTimeout(timeout);
+ timeout = null;
+ };
+
+ return debounced;
+ };
+
+ // Returns the first function passed as an argument to the second,
+ // allowing you to adjust arguments, run code before and after, and
+ // conditionally execute the original function.
+ _.wrap = function(func, wrapper) {
+ return _.partial(wrapper, func);
+ };
+
+ // Returns a negated version of the passed-in predicate.
+ _.negate = function(predicate) {
+ return function() {
+ return !predicate.apply(this, arguments);
+ };
+ };
+
+ // Returns a function that is the composition of a list of functions, each
+ // consuming the return value of the function that follows.
+ _.compose = function() {
+ var args = arguments;
+ var start = args.length - 1;
+ return function() {
+ var i = start;
+ var result = args[start].apply(this, arguments);
+ while (i--) result = args[i].call(this, result);
+ return result;
+ };
+ };
+
+ // Returns a function that will only be executed on and after the Nth call.
+ _.after = function(times, func) {
+ return function() {
+ if (--times < 1) {
+ return func.apply(this, arguments);
+ }
+ };
+ };
+
+ // Returns a function that will only be executed up to (but not including) the Nth call.
+ _.before = function(times, func) {
+ var memo;
+ return function() {
+ if (--times > 0) {
+ memo = func.apply(this, arguments);
+ }
+ if (times <= 1) func = null;
+ return memo;
+ };
+ };
+
+ // Returns a function that will be executed at most one time, no matter how
+ // often you call it. Useful for lazy initialization.
+ _.once = _.partial(_.before, 2);
+
+ _.restArguments = restArguments;
+
+ // Object Functions
+ // ----------------
+
+ // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
+ var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
+ var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
+ 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
+
+ var collectNonEnumProps = function(obj, keys) {
+ var nonEnumIdx = nonEnumerableProps.length;
+ var constructor = obj.constructor;
+ var proto = _.isFunction(constructor) && constructor.prototype || ObjProto;
+
+ // Constructor is a special case.
+ var prop = 'constructor';
+ if (has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);
+
+ while (nonEnumIdx--) {
+ prop = nonEnumerableProps[nonEnumIdx];
+ if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
+ keys.push(prop);
+ }
+ }
+ };
+
+ // Retrieve the names of an object's own properties.
+ // Delegates to **ECMAScript 5**'s native `Object.keys`.
+ _.keys = function(obj) {
+ if (!_.isObject(obj)) return [];
+ if (nativeKeys) return nativeKeys(obj);
+ var keys = [];
+ for (var key in obj) if (has(obj, key)) keys.push(key);
+ // Ahem, IE < 9.
+ if (hasEnumBug) collectNonEnumProps(obj, keys);
+ return keys;
+ };
+
+ // Retrieve all the property names of an object.
+ _.allKeys = function(obj) {
+ if (!_.isObject(obj)) return [];
+ var keys = [];
+ for (var key in obj) keys.push(key);
+ // Ahem, IE < 9.
+ if (hasEnumBug) collectNonEnumProps(obj, keys);
+ return keys;
+ };
+
+ // Retrieve the values of an object's properties.
+ _.values = function(obj) {
+ var keys = _.keys(obj);
+ var length = keys.length;
+ var values = Array(length);
+ for (var i = 0; i < length; i++) {
+ values[i] = obj[keys[i]];
+ }
+ return values;
+ };
+
+ // Returns the results of applying the iteratee to each element of the object.
+ // In contrast to _.map it returns an object.
+ _.mapObject = function(obj, iteratee, context) {
+ iteratee = cb(iteratee, context);
+ var keys = _.keys(obj),
+ length = keys.length,
+ results = {};
+ for (var index = 0; index < length; index++) {
+ var currentKey = keys[index];
+ results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
+ }
+ return results;
+ };
+
+ // Convert an object into a list of `[key, value]` pairs.
+ // The opposite of _.object.
+ _.pairs = function(obj) {
+ var keys = _.keys(obj);
+ var length = keys.length;
+ var pairs = Array(length);
+ for (var i = 0; i < length; i++) {
+ pairs[i] = [keys[i], obj[keys[i]]];
+ }
+ return pairs;
+ };
+
+ // Invert the keys and values of an object. The values must be serializable.
+ _.invert = function(obj) {
+ var result = {};
+ var keys = _.keys(obj);
+ for (var i = 0, length = keys.length; i < length; i++) {
+ result[obj[keys[i]]] = keys[i];
+ }
+ return result;
+ };
+
+ // Return a sorted list of the function names available on the object.
+ // Aliased as `methods`.
+ _.functions = _.methods = function(obj) {
+ var names = [];
+ for (var key in obj) {
+ if (_.isFunction(obj[key])) names.push(key);
+ }
+ return names.sort();
+ };
+
+ // An internal function for creating assigner functions.
+ var createAssigner = function(keysFunc, defaults) {
+ return function(obj) {
+ var length = arguments.length;
+ if (defaults) obj = Object(obj);
+ if (length < 2 || obj == null) return obj;
+ for (var index = 1; index < length; index++) {
+ var source = arguments[index],
+ keys = keysFunc(source),
+ l = keys.length;
+ for (var i = 0; i < l; i++) {
+ var key = keys[i];
+ if (!defaults || obj[key] === void 0) obj[key] = source[key];
+ }
+ }
+ return obj;
+ };
+ };
+
+ // Extend a given object with all the properties in passed-in object(s).
+ _.extend = createAssigner(_.allKeys);
+
+ // Assigns a given object with all the own properties in the passed-in object(s).
+ // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
+ _.extendOwn = _.assign = createAssigner(_.keys);
+
+ // Returns the first key on an object that passes a predicate test.
+ _.findKey = function(obj, predicate, context) {
+ predicate = cb(predicate, context);
+ var keys = _.keys(obj), key;
+ for (var i = 0, length = keys.length; i < length; i++) {
+ key = keys[i];
+ if (predicate(obj[key], key, obj)) return key;
+ }
+ };
+
+ // Internal pick helper function to determine if `obj` has key `key`.
+ var keyInObj = function(value, key, obj) {
+ return key in obj;
+ };
+
+ // Return a copy of the object only containing the whitelisted properties.
+ _.pick = restArguments(function(obj, keys) {
+ var result = {}, iteratee = keys[0];
+ if (obj == null) return result;
+ if (_.isFunction(iteratee)) {
+ if (keys.length > 1) iteratee = optimizeCb(iteratee, keys[1]);
+ keys = _.allKeys(obj);
+ } else {
+ iteratee = keyInObj;
+ keys = flatten(keys, false, false);
+ obj = Object(obj);
+ }
+ for (var i = 0, length = keys.length; i < length; i++) {
+ var key = keys[i];
+ var value = obj[key];
+ if (iteratee(value, key, obj)) result[key] = value;
+ }
+ return result;
+ });
+
+ // Return a copy of the object without the blacklisted properties.
+ _.omit = restArguments(function(obj, keys) {
+ var iteratee = keys[0], context;
+ if (_.isFunction(iteratee)) {
+ iteratee = _.negate(iteratee);
+ if (keys.length > 1) context = keys[1];
+ } else {
+ keys = _.map(flatten(keys, false, false), String);
+ iteratee = function(value, key) {
+ return !_.contains(keys, key);
+ };
+ }
+ return _.pick(obj, iteratee, context);
+ });
+
+ // Fill in a given object with default properties.
+ _.defaults = createAssigner(_.allKeys, true);
+
+ // Creates an object that inherits from the given prototype object.
+ // If additional properties are provided then they will be added to the
+ // created object.
+ _.create = function(prototype, props) {
+ var result = baseCreate(prototype);
+ if (props) _.extendOwn(result, props);
+ return result;
+ };
+
+ // Create a (shallow-cloned) duplicate of an object.
+ _.clone = function(obj) {
+ if (!_.isObject(obj)) return obj;
+ return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
+ };
+
+ // Invokes interceptor with the obj, and then returns obj.
+ // The primary purpose of this method is to "tap into" a method chain, in
+ // order to perform operations on intermediate results within the chain.
+ _.tap = function(obj, interceptor) {
+ interceptor(obj);
+ return obj;
+ };
+
+ // Returns whether an object has a given set of `key:value` pairs.
+ _.isMatch = function(object, attrs) {
+ var keys = _.keys(attrs), length = keys.length;
+ if (object == null) return !length;
+ var obj = Object(object);
+ for (var i = 0; i < length; i++) {
+ var key = keys[i];
+ if (attrs[key] !== obj[key] || !(key in obj)) return false;
+ }
+ return true;
+ };
+
+
+ // Internal recursive comparison function for `isEqual`.
+ var eq, deepEq;
+ eq = function(a, b, aStack, bStack) {
+ // Identical objects are equal. `0 === -0`, but they aren't identical.
+ // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
+ if (a === b) return a !== 0 || 1 / a === 1 / b;
+ // `null` or `undefined` only equal to itself (strict comparison).
+ if (a == null || b == null) return false;
+ // `NaN`s are equivalent, but non-reflexive.
+ if (a !== a) return b !== b;
+ // Exhaust primitive checks
+ var type = typeof a;
+ if (type !== 'function' && type !== 'object' && typeof b != 'object') return false;
+ return deepEq(a, b, aStack, bStack);
+ };
+
+ // Internal recursive comparison function for `isEqual`.
+ deepEq = function(a, b, aStack, bStack) {
+ // Unwrap any wrapped objects.
+ if (a instanceof _) a = a._wrapped;
+ if (b instanceof _) b = b._wrapped;
+ // Compare `[[Class]]` names.
+ var className = toString.call(a);
+ if (className !== toString.call(b)) return false;
+ switch (className) {
+ // Strings, numbers, regular expressions, dates, and booleans are compared by value.
+ case '[object RegExp]':
+ // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
+ case '[object String]':
+ // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
+ // equivalent to `new String("5")`.
+ return '' + a === '' + b;
+ case '[object Number]':
+ // `NaN`s are equivalent, but non-reflexive.
+ // Object(NaN) is equivalent to NaN.
+ if (+a !== +a) return +b !== +b;
+ // An `egal` comparison is performed for other numeric values.
+ return +a === 0 ? 1 / +a === 1 / b : +a === +b;
+ case '[object Date]':
+ case '[object Boolean]':
+ // Coerce dates and booleans to numeric primitive values. Dates are compared by their
+ // millisecond representations. Note that invalid dates with millisecond representations
+ // of `NaN` are not equivalent.
+ return +a === +b;
+ case '[object Symbol]':
+ return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b);
+ }
+
+ var areArrays = className === '[object Array]';
+ if (!areArrays) {
+ if (typeof a != 'object' || typeof b != 'object') return false;
+
+ // Objects with different constructors are not equivalent, but `Object`s or `Array`s
+ // from different frames are.
+ var aCtor = a.constructor, bCtor = b.constructor;
+ if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
+ _.isFunction(bCtor) && bCtor instanceof bCtor)
+ && ('constructor' in a && 'constructor' in b)) {
+ return false;
+ }
+ }
+ // Assume equality for cyclic structures. The algorithm for detecting cyclic
+ // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
+
+ // Initializing stack of traversed objects.
+ // It's done here since we only need them for objects and arrays comparison.
+ aStack = aStack || [];
+ bStack = bStack || [];
+ var length = aStack.length;
+ while (length--) {
+ // Linear search. Performance is inversely proportional to the number of
+ // unique nested structures.
+ if (aStack[length] === a) return bStack[length] === b;
+ }
+
+ // Add the first object to the stack of traversed objects.
+ aStack.push(a);
+ bStack.push(b);
+
+ // Recursively compare objects and arrays.
+ if (areArrays) {
+ // Compare array lengths to determine if a deep comparison is necessary.
+ length = a.length;
+ if (length !== b.length) return false;
+ // Deep compare the contents, ignoring non-numeric properties.
+ while (length--) {
+ if (!eq(a[length], b[length], aStack, bStack)) return false;
+ }
+ } else {
+ // Deep compare objects.
+ var keys = _.keys(a), key;
+ length = keys.length;
+ // Ensure that both objects contain the same number of properties before comparing deep equality.
+ if (_.keys(b).length !== length) return false;
+ while (length--) {
+ // Deep compare each member
+ key = keys[length];
+ if (!(has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
+ }
+ }
+ // Remove the first object from the stack of traversed objects.
+ aStack.pop();
+ bStack.pop();
+ return true;
+ };
+
+ // Perform a deep comparison to check if two objects are equal.
+ _.isEqual = function(a, b) {
+ return eq(a, b);
+ };
+
+ // Is a given array, string, or object empty?
+ // An "empty" object has no enumerable own-properties.
+ _.isEmpty = function(obj) {
+ if (obj == null) return true;
+ if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
+ return _.keys(obj).length === 0;
+ };
+
+ // Is a given value a DOM element?
+ _.isElement = function(obj) {
+ return !!(obj && obj.nodeType === 1);
+ };
+
+ // Is a given value an array?
+ // Delegates to ECMA5's native Array.isArray
+ _.isArray = nativeIsArray || function(obj) {
+ return toString.call(obj) === '[object Array]';
+ };
+
+ // Is a given variable an object?
+ _.isObject = function(obj) {
+ var type = typeof obj;
+ return type === 'function' || type === 'object' && !!obj;
+ };
+
+ // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError, isMap, isWeakMap, isSet, isWeakSet.
+ _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error', 'Symbol', 'Map', 'WeakMap', 'Set', 'WeakSet'], function(name) {
+ _['is' + name] = function(obj) {
+ return toString.call(obj) === '[object ' + name + ']';
+ };
+ });
+
+ // Define a fallback version of the method in browsers (ahem, IE < 9), where
+ // there isn't any inspectable "Arguments" type.
+ if (!_.isArguments(arguments)) {
+ _.isArguments = function(obj) {
+ return has(obj, 'callee');
+ };
+ }
+
+ // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
+ // IE 11 (#1621), Safari 8 (#1929), and PhantomJS (#2236).
+ var nodelist = root.document && root.document.childNodes;
+ if (typeof /./ != 'function' && typeof Int8Array != 'object' && typeof nodelist != 'function') {
+ _.isFunction = function(obj) {
+ return typeof obj == 'function' || false;
+ };
+ }
+
+ // Is a given object a finite number?
+ _.isFinite = function(obj) {
+ return !_.isSymbol(obj) && isFinite(obj) && !isNaN(parseFloat(obj));
+ };
+
+ // Is the given value `NaN`?
+ _.isNaN = function(obj) {
+ return _.isNumber(obj) && isNaN(obj);
+ };
+
+ // Is a given value a boolean?
+ _.isBoolean = function(obj) {
+ return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
+ };
+
+ // Is a given value equal to null?
+ _.isNull = function(obj) {
+ return obj === null;
+ };
+
+ // Is a given variable undefined?
+ _.isUndefined = function(obj) {
+ return obj === void 0;
+ };
+
+ // Shortcut function for checking if an object has a given property directly
+ // on itself (in other words, not on a prototype).
+ _.has = function(obj, path) {
+ if (!_.isArray(path)) {
+ return has(obj, path);
+ }
+ var length = path.length;
+ for (var i = 0; i < length; i++) {
+ var key = path[i];
+ if (obj == null || !hasOwnProperty.call(obj, key)) {
+ return false;
+ }
+ obj = obj[key];
+ }
+ return !!length;
+ };
+
+ // Utility Functions
+ // -----------------
+
+ // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
+ // previous owner. Returns a reference to the Underscore object.
+ _.noConflict = function() {
+ root._ = previousUnderscore;
+ return this;
+ };
+
+ // Keep the identity function around for default iteratees.
+ _.identity = function(value) {
+ return value;
+ };
+
+ // Predicate-generating functions. Often useful outside of Underscore.
+ _.constant = function(value) {
+ return function() {
+ return value;
+ };
+ };
+
+ _.noop = function(){};
+
+ // Creates a function that, when passed an object, will traverse that object’s
+ // properties down the given `path`, specified as an array of keys or indexes.
+ _.property = function(path) {
+ if (!_.isArray(path)) {
+ return shallowProperty(path);
+ }
+ return function(obj) {
+ return deepGet(obj, path);
+ };
+ };
+
+ // Generates a function for a given object that returns a given property.
+ _.propertyOf = function(obj) {
+ if (obj == null) {
+ return function(){};
+ }
+ return function(path) {
+ return !_.isArray(path) ? obj[path] : deepGet(obj, path);
+ };
+ };
+
+ // Returns a predicate for checking whether an object has a given set of
+ // `key:value` pairs.
+ _.matcher = _.matches = function(attrs) {
+ attrs = _.extendOwn({}, attrs);
+ return function(obj) {
+ return _.isMatch(obj, attrs);
+ };
+ };
+
+ // Run a function **n** times.
+ _.times = function(n, iteratee, context) {
+ var accum = Array(Math.max(0, n));
+ iteratee = optimizeCb(iteratee, context, 1);
+ for (var i = 0; i < n; i++) accum[i] = iteratee(i);
+ return accum;
+ };
+
+ // Return a random integer between min and max (inclusive).
+ _.random = function(min, max) {
+ if (max == null) {
+ max = min;
+ min = 0;
+ }
+ return min + Math.floor(Math.random() * (max - min + 1));
+ };
+
+ // A (possibly faster) way to get the current timestamp as an integer.
+ _.now = Date.now || function() {
+ return new Date().getTime();
+ };
+
+ // List of HTML entities for escaping.
+ var escapeMap = {
+ '&': '&amp;',
+ '<': '&lt;',
+ '>': '&gt;',
+ '"': '&quot;',
+ "'": '&#x27;',
+ '`': '&#x60;'
+ };
+ var unescapeMap = _.invert(escapeMap);
+
+ // Functions for escaping and unescaping strings to/from HTML interpolation.
+ var createEscaper = function(map) {
+ var escaper = function(match) {
+ return map[match];
+ };
+ // Regexes for identifying a key that needs to be escaped.
+ var source = '(?:' + _.keys(map).join('|') + ')';
+ var testRegexp = RegExp(source);
+ var replaceRegexp = RegExp(source, 'g');
+ return function(string) {
+ string = string == null ? '' : '' + string;
+ return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
+ };
+ };
+ _.escape = createEscaper(escapeMap);
+ _.unescape = createEscaper(unescapeMap);
+
+ // Traverses the children of `obj` along `path`. If a child is a function, it
+ // is invoked with its parent as context. Returns the value of the final
+ // child, or `fallback` if any child is undefined.
+ _.result = function(obj, path, fallback) {
+ if (!_.isArray(path)) path = [path];
+ var length = path.length;
+ if (!length) {
+ return _.isFunction(fallback) ? fallback.call(obj) : fallback;
+ }
+ for (var i = 0; i < length; i++) {
+ var prop = obj == null ? void 0 : obj[path[i]];
+ if (prop === void 0) {
+ prop = fallback;
+ i = length; // Ensure we don't continue iterating.
+ }
+ obj = _.isFunction(prop) ? prop.call(obj) : prop;
+ }
+ return obj;
+ };
+
+ // Generate a unique integer id (unique within the entire client session).
+ // Useful for temporary DOM ids.
+ var idCounter = 0;
+ _.uniqueId = function(prefix) {
+ var id = ++idCounter + '';
+ return prefix ? prefix + id : id;
+ };
+
+ // By default, Underscore uses ERB-style template delimiters, change the
+ // following template settings to use alternative delimiters.
+ _.templateSettings = {
+ evaluate: /<%([\s\S]+?)%>/g,
+ interpolate: /<%=([\s\S]+?)%>/g,
+ escape: /<%-([\s\S]+?)%>/g
+ };
+
+ // When customizing `templateSettings`, if you don't want to define an
+ // interpolation, evaluation or escaping regex, we need one that is
+ // guaranteed not to match.
+ var noMatch = /(.)^/;
+
+ // Certain characters need to be escaped so that they can be put into a
+ // string literal.
+ var escapes = {
+ "'": "'",
+ '\\': '\\',
+ '\r': 'r',
+ '\n': 'n',
+ '\u2028': 'u2028',
+ '\u2029': 'u2029'
+ };
+
+ var escapeRegExp = /\\|'|\r|\n|\u2028|\u2029/g;
+
+ var escapeChar = function(match) {
+ return '\\' + escapes[match];
+ };
+
+ // JavaScript micro-templating, similar to John Resig's implementation.
+ // Underscore templating handles arbitrary delimiters, preserves whitespace,
+ // and correctly escapes quotes within interpolated code.
+ // NB: `oldSettings` only exists for backwards compatibility.
+ _.template = function(text, settings, oldSettings) {
+ if (!settings && oldSettings) settings = oldSettings;
+ settings = _.defaults({}, settings, _.templateSettings);
+
+ // Combine delimiters into one regular expression via alternation.
+ var matcher = RegExp([
+ (settings.escape || noMatch).source,
+ (settings.interpolate || noMatch).source,
+ (settings.evaluate || noMatch).source
+ ].join('|') + '|$', 'g');
+
+ // Compile the template source, escaping string literals appropriately.
+ var index = 0;
+ var source = "__p+='";
+ text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
+ source += text.slice(index, offset).replace(escapeRegExp, escapeChar);
+ index = offset + match.length;
+
+ if (escape) {
+ source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
+ } else if (interpolate) {
+ source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
+ } else if (evaluate) {
+ source += "';\n" + evaluate + "\n__p+='";
+ }
+
+ // Adobe VMs need the match returned to produce the correct offset.
+ return match;
+ });
+ source += "';\n";
+
+ // If a variable is not specified, place data values in local scope.
+ if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
+
+ source = "var __t,__p='',__j=Array.prototype.join," +
+ "print=function(){__p+=__j.call(arguments,'');};\n" +
+ source + 'return __p;\n';
+
+ var render;
+ try {
+ render = new Function(settings.variable || 'obj', '_', source);
+ } catch (e) {
+ e.source = source;
+ throw e;
+ }
+
+ var template = function(data) {
+ return render.call(this, data, _);
+ };
+
+ // Provide the compiled source as a convenience for precompilation.
+ var argument = settings.variable || 'obj';
+ template.source = 'function(' + argument + '){\n' + source + '}';
+
+ return template;
+ };
+
+ // Add a "chain" function. Start chaining a wrapped Underscore object.
+ _.chain = function(obj) {
+ var instance = _(obj);
+ instance._chain = true;
+ return instance;
+ };
+
+ // OOP
+ // ---------------
+ // If Underscore is called as a function, it returns a wrapped object that
+ // can be used OO-style. This wrapper holds altered versions of all the
+ // underscore functions. Wrapped objects may be chained.
+
+ // Helper function to continue chaining intermediate results.
+ var chainResult = function(instance, obj) {
+ return instance._chain ? _(obj).chain() : obj;
+ };
+
+ // Add your own custom functions to the Underscore object.
+ _.mixin = function(obj) {
+ _.each(_.functions(obj), function(name) {
+ var func = _[name] = obj[name];
+ _.prototype[name] = function() {
+ var args = [this._wrapped];
+ push.apply(args, arguments);
+ return chainResult(this, func.apply(_, args));
+ };
+ });
+ return _;
+ };
+
+ // Add all of the Underscore functions to the wrapper object.
+ _.mixin(_);
+
+ // Add all mutator Array functions to the wrapper.
+ _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
+ var method = ArrayProto[name];
+ _.prototype[name] = function() {
+ var obj = this._wrapped;
+ method.apply(obj, arguments);
+ if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
+ return chainResult(this, obj);
+ };
+ });
+
+ // Add all accessor Array functions to the wrapper.
+ _.each(['concat', 'join', 'slice'], function(name) {
+ var method = ArrayProto[name];
+ _.prototype[name] = function() {
+ return chainResult(this, method.apply(this._wrapped, arguments));
+ };
+ });
+
+ // Extracts the result from a wrapped and chained object.
+ _.prototype.value = function() {
+ return this._wrapped;
+ };
+
+ // Provide unwrapping proxy for some methods used in engine operations
+ // such as arithmetic and JSON stringification.
+ _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
+
+ _.prototype.toString = function() {
+ return String(this._wrapped);
+ };
+
+ // AMD registration happens at the end for compatibility with AMD loaders
+ // that may not enforce next-turn semantics on modules. Even though general
+ // practice for AMD registration is to be anonymous, underscore registers
+ // as a named module because, like jQuery, it is a base library that is
+ // popular enough to be bundled in a third party lib, but not be part of
+ // an AMD load request. Those cases could generate an error when an
+ // anonymous define() is called outside of a loader request.
+ if (typeof define == 'function' && define.amd) {
+ define('underscore', [], function() {
+ return _;
+ });
+ }
+}());
diff --git a/src/manifest.json b/src/manifest.json
new file mode 100644
index 0000000..e9f34e3
--- /dev/null
+++ b/src/manifest.json
@@ -0,0 +1,522 @@
+{
+ "version": "2020.10.7",
+ "author": {
+ "email": "eff.software.projects@gmail.com"
+ },
+ "applications": {
+ "gecko": {
+ "id": "jid1-MnnxcxisBPnSXQ@jetpack",
+ "strict_min_version": "52.0"
+ }
+ },
+ "incognito": "spanning",
+ "permissions": [
+ "tabs",
+ "http://*/*",
+ "https://*/*",
+ "webNavigation",
+ "webRequest",
+ "webRequestBlocking",
+ "storage",
+ "cookies",
+ "privacy"
+ ],
+ "background": {
+ "scripts": [
+ "js/bootstrap.js",
+ "lib/vendor/punycode-1.4.1.js",
+ "lib/publicSuffixList.js",
+ "lib/basedomain.js",
+ "lib/vendor/underscore-1.9.1.js",
+ "data/surrogates.js",
+ "js/surrogates.js",
+ "js/multiDomainFirstParties.js",
+ "js/incognito.js",
+ "js/constants.js",
+ "js/storage.js",
+ "js/utils.js",
+ "js/heuristicblocking.js",
+ "js/socialwidgetloader.js",
+ "js/migrations.js",
+ "js/firefoxandroid.js",
+ "js/webrequest.js",
+ "js/background.js"
+ ]
+ },
+ "content_scripts": [
+ {
+ "js": [
+ "js/firstparties/lib/utils.js",
+ "js/firstparties/facebook.js"
+ ],
+ "matches": [
+ "https://*.facebook.com/*",
+ "http://*.facebook.com/*",
+ "https://*.messenger.com/*",
+ "http://*.messenger.com/*",
+ "*://*.facebookcorewwwi.onion/*"
+ ],
+ "run_at": "document_idle"
+ },
+ {
+ "js": [
+ "js/firstparties/lib/utils.js",
+ "js/firstparties/google-search.js"
+ ],
+ "matches": [
+ "https://www.google.com/*",
+ "http://www.google.com/*",
+ "https://www.google.ad/*",
+ "http://www.google.ad/*",
+ "https://www.google.ae/*",
+ "http://www.google.ae/*",
+ "https://www.google.com.af/*",
+ "http://www.google.com.af/*",
+ "https://www.google.com.ag/*",
+ "http://www.google.com.ag/*",
+ "https://www.google.com.ai/*",
+ "http://www.google.com.ai/*",
+ "https://www.google.al/*",
+ "http://www.google.al/*",
+ "https://www.google.am/*",
+ "http://www.google.am/*",
+ "https://www.google.co.ao/*",
+ "http://www.google.co.ao/*",
+ "https://www.google.com.ar/*",
+ "http://www.google.com.ar/*",
+ "https://www.google.as/*",
+ "http://www.google.as/*",
+ "https://www.google.at/*",
+ "http://www.google.at/*",
+ "https://www.google.com.au/*",
+ "http://www.google.com.au/*",
+ "https://www.google.az/*",
+ "http://www.google.az/*",
+ "https://www.google.ba/*",
+ "http://www.google.ba/*",
+ "https://www.google.com.bd/*",
+ "http://www.google.com.bd/*",
+ "https://www.google.be/*",
+ "http://www.google.be/*",
+ "https://www.google.bf/*",
+ "http://www.google.bf/*",
+ "https://www.google.bg/*",
+ "http://www.google.bg/*",
+ "https://www.google.com.bh/*",
+ "http://www.google.com.bh/*",
+ "https://www.google.bi/*",
+ "http://www.google.bi/*",
+ "https://www.google.bj/*",
+ "http://www.google.bj/*",
+ "https://www.google.com.bn/*",
+ "http://www.google.com.bn/*",
+ "https://www.google.com.bo/*",
+ "http://www.google.com.bo/*",
+ "https://www.google.com.br/*",
+ "http://www.google.com.br/*",
+ "https://www.google.bs/*",
+ "http://www.google.bs/*",
+ "https://www.google.bt/*",
+ "http://www.google.bt/*",
+ "https://www.google.co.bw/*",
+ "http://www.google.co.bw/*",
+ "https://www.google.by/*",
+ "http://www.google.by/*",
+ "https://www.google.com.bz/*",
+ "http://www.google.com.bz/*",
+ "https://www.google.ca/*",
+ "http://www.google.ca/*",
+ "https://www.google.cd/*",
+ "http://www.google.cd/*",
+ "https://www.google.cf/*",
+ "http://www.google.cf/*",
+ "https://www.google.cg/*",
+ "http://www.google.cg/*",
+ "https://www.google.ch/*",
+ "http://www.google.ch/*",
+ "https://www.google.ci/*",
+ "http://www.google.ci/*",
+ "https://www.google.co.ck/*",
+ "http://www.google.co.ck/*",
+ "https://www.google.cl/*",
+ "http://www.google.cl/*",
+ "https://www.google.cm/*",
+ "http://www.google.cm/*",
+ "https://www.google.cn/*",
+ "http://www.google.cn/*",
+ "https://www.google.com.co/*",
+ "http://www.google.com.co/*",
+ "https://www.google.co.cr/*",
+ "http://www.google.co.cr/*",
+ "https://www.google.com.cu/*",
+ "http://www.google.com.cu/*",
+ "https://www.google.cv/*",
+ "http://www.google.cv/*",
+ "https://www.google.com.cy/*",
+ "http://www.google.com.cy/*",
+ "https://www.google.cz/*",
+ "http://www.google.cz/*",
+ "https://www.google.de/*",
+ "http://www.google.de/*",
+ "https://www.google.dj/*",
+ "http://www.google.dj/*",
+ "https://www.google.dk/*",
+ "http://www.google.dk/*",
+ "https://www.google.dm/*",
+ "http://www.google.dm/*",
+ "https://www.google.com.do/*",
+ "http://www.google.com.do/*",
+ "https://www.google.dz/*",
+ "http://www.google.dz/*",
+ "https://www.google.com.ec/*",
+ "http://www.google.com.ec/*",
+ "https://www.google.ee/*",
+ "http://www.google.ee/*",
+ "https://www.google.com.eg/*",
+ "http://www.google.com.eg/*",
+ "https://www.google.es/*",
+ "http://www.google.es/*",
+ "https://www.google.com.et/*",
+ "http://www.google.com.et/*",
+ "https://www.google.fi/*",
+ "http://www.google.fi/*",
+ "https://www.google.com.fj/*",
+ "http://www.google.com.fj/*",
+ "https://www.google.fm/*",
+ "http://www.google.fm/*",
+ "https://www.google.fr/*",
+ "http://www.google.fr/*",
+ "https://www.google.ga/*",
+ "http://www.google.ga/*",
+ "https://www.google.ge/*",
+ "http://www.google.ge/*",
+ "https://www.google.gg/*",
+ "http://www.google.gg/*",
+ "https://www.google.com.gh/*",
+ "http://www.google.com.gh/*",
+ "https://www.google.com.gi/*",
+ "http://www.google.com.gi/*",
+ "https://www.google.gl/*",
+ "http://www.google.gl/*",
+ "https://www.google.gm/*",
+ "http://www.google.gm/*",
+ "https://www.google.gr/*",
+ "http://www.google.gr/*",
+ "https://www.google.com.gt/*",
+ "http://www.google.com.gt/*",
+ "https://www.google.gy/*",
+ "http://www.google.gy/*",
+ "https://www.google.com.hk/*",
+ "http://www.google.com.hk/*",
+ "https://www.google.hn/*",
+ "http://www.google.hn/*",
+ "https://www.google.hr/*",
+ "http://www.google.hr/*",
+ "https://www.google.ht/*",
+ "http://www.google.ht/*",
+ "https://www.google.hu/*",
+ "http://www.google.hu/*",
+ "https://www.google.co.id/*",
+ "http://www.google.co.id/*",
+ "https://www.google.ie/*",
+ "http://www.google.ie/*",
+ "https://www.google.co.il/*",
+ "http://www.google.co.il/*",
+ "https://www.google.im/*",
+ "http://www.google.im/*",
+ "https://www.google.co.in/*",
+ "http://www.google.co.in/*",
+ "https://www.google.iq/*",
+ "http://www.google.iq/*",
+ "https://www.google.is/*",
+ "http://www.google.is/*",
+ "https://www.google.it/*",
+ "http://www.google.it/*",
+ "https://www.google.je/*",
+ "http://www.google.je/*",
+ "https://www.google.com.jm/*",
+ "http://www.google.com.jm/*",
+ "https://www.google.jo/*",
+ "http://www.google.jo/*",
+ "https://www.google.co.jp/*",
+ "http://www.google.co.jp/*",
+ "https://www.google.co.ke/*",
+ "http://www.google.co.ke/*",
+ "https://www.google.com.kh/*",
+ "http://www.google.com.kh/*",
+ "https://www.google.ki/*",
+ "http://www.google.ki/*",
+ "https://www.google.kg/*",
+ "http://www.google.kg/*",
+ "https://www.google.co.kr/*",
+ "http://www.google.co.kr/*",
+ "https://www.google.com.kw/*",
+ "http://www.google.com.kw/*",
+ "https://www.google.kz/*",
+ "http://www.google.kz/*",
+ "https://www.google.la/*",
+ "http://www.google.la/*",
+ "https://www.google.com.lb/*",
+ "http://www.google.com.lb/*",
+ "https://www.google.li/*",
+ "http://www.google.li/*",
+ "https://www.google.lk/*",
+ "http://www.google.lk/*",
+ "https://www.google.co.ls/*",
+ "http://www.google.co.ls/*",
+ "https://www.google.lt/*",
+ "http://www.google.lt/*",
+ "https://www.google.lu/*",
+ "http://www.google.lu/*",
+ "https://www.google.lv/*",
+ "http://www.google.lv/*",
+ "https://www.google.com.ly/*",
+ "http://www.google.com.ly/*",
+ "https://www.google.co.ma/*",
+ "http://www.google.co.ma/*",
+ "https://www.google.md/*",
+ "http://www.google.md/*",
+ "https://www.google.me/*",
+ "http://www.google.me/*",
+ "https://www.google.mg/*",
+ "http://www.google.mg/*",
+ "https://www.google.mk/*",
+ "http://www.google.mk/*",
+ "https://www.google.ml/*",
+ "http://www.google.ml/*",
+ "https://www.google.com.mm/*",
+ "http://www.google.com.mm/*",
+ "https://www.google.mn/*",
+ "http://www.google.mn/*",
+ "https://www.google.ms/*",
+ "http://www.google.ms/*",
+ "https://www.google.com.mt/*",
+ "http://www.google.com.mt/*",
+ "https://www.google.mu/*",
+ "http://www.google.mu/*",
+ "https://www.google.mv/*",
+ "http://www.google.mv/*",
+ "https://www.google.mw/*",
+ "http://www.google.mw/*",
+ "https://www.google.com.mx/*",
+ "http://www.google.com.mx/*",
+ "https://www.google.com.my/*",
+ "http://www.google.com.my/*",
+ "https://www.google.co.mz/*",
+ "http://www.google.co.mz/*",
+ "https://www.google.com.na/*",
+ "http://www.google.com.na/*",
+ "https://www.google.com.ng/*",
+ "http://www.google.com.ng/*",
+ "https://www.google.com.ni/*",
+ "http://www.google.com.ni/*",
+ "https://www.google.ne/*",
+ "http://www.google.ne/*",
+ "https://www.google.nl/*",
+ "http://www.google.nl/*",
+ "https://www.google.no/*",
+ "http://www.google.no/*",
+ "https://www.google.com.np/*",
+ "http://www.google.com.np/*",
+ "https://www.google.nr/*",
+ "http://www.google.nr/*",
+ "https://www.google.nu/*",
+ "http://www.google.nu/*",
+ "https://www.google.co.nz/*",
+ "http://www.google.co.nz/*",
+ "https://www.google.com.om/*",
+ "http://www.google.com.om/*",
+ "https://www.google.com.pa/*",
+ "http://www.google.com.pa/*",
+ "https://www.google.com.pe/*",
+ "http://www.google.com.pe/*",
+ "https://www.google.com.pg/*",
+ "http://www.google.com.pg/*",
+ "https://www.google.com.ph/*",
+ "http://www.google.com.ph/*",
+ "https://www.google.com.pk/*",
+ "http://www.google.com.pk/*",
+ "https://www.google.pl/*",
+ "http://www.google.pl/*",
+ "https://www.google.pn/*",
+ "http://www.google.pn/*",
+ "https://www.google.com.pr/*",
+ "http://www.google.com.pr/*",
+ "https://www.google.ps/*",
+ "http://www.google.ps/*",
+ "https://www.google.pt/*",
+ "http://www.google.pt/*",
+ "https://www.google.com.py/*",
+ "http://www.google.com.py/*",
+ "https://www.google.com.qa/*",
+ "http://www.google.com.qa/*",
+ "https://www.google.ro/*",
+ "http://www.google.ro/*",
+ "https://www.google.ru/*",
+ "http://www.google.ru/*",
+ "https://www.google.rw/*",
+ "http://www.google.rw/*",
+ "https://www.google.com.sa/*",
+ "http://www.google.com.sa/*",
+ "https://www.google.com.sb/*",
+ "http://www.google.com.sb/*",
+ "https://www.google.sc/*",
+ "http://www.google.sc/*",
+ "https://www.google.se/*",
+ "http://www.google.se/*",
+ "https://www.google.com.sg/*",
+ "http://www.google.com.sg/*",
+ "https://www.google.sh/*",
+ "http://www.google.sh/*",
+ "https://www.google.si/*",
+ "http://www.google.si/*",
+ "https://www.google.sk/*",
+ "http://www.google.sk/*",
+ "https://www.google.com.sl/*",
+ "http://www.google.com.sl/*",
+ "https://www.google.sn/*",
+ "http://www.google.sn/*",
+ "https://www.google.so/*",
+ "http://www.google.so/*",
+ "https://www.google.sm/*",
+ "http://www.google.sm/*",
+ "https://www.google.sr/*",
+ "http://www.google.sr/*",
+ "https://www.google.st/*",
+ "http://www.google.st/*",
+ "https://www.google.com.sv/*",
+ "http://www.google.com.sv/*",
+ "https://www.google.td/*",
+ "http://www.google.td/*",
+ "https://www.google.tg/*",
+ "http://www.google.tg/*",
+ "https://www.google.co.th/*",
+ "http://www.google.co.th/*",
+ "https://www.google.com.tj/*",
+ "http://www.google.com.tj/*",
+ "https://www.google.tl/*",
+ "http://www.google.tl/*",
+ "https://www.google.tm/*",
+ "http://www.google.tm/*",
+ "https://www.google.tn/*",
+ "http://www.google.tn/*",
+ "https://www.google.to/*",
+ "http://www.google.to/*",
+ "https://www.google.com.tr/*",
+ "http://www.google.com.tr/*",
+ "https://www.google.tt/*",
+ "http://www.google.tt/*",
+ "https://www.google.com.tw/*",
+ "http://www.google.com.tw/*",
+ "https://www.google.co.tz/*",
+ "http://www.google.co.tz/*",
+ "https://www.google.com.ua/*",
+ "http://www.google.com.ua/*",
+ "https://www.google.co.ug/*",
+ "http://www.google.co.ug/*",
+ "https://www.google.co.uk/*",
+ "http://www.google.co.uk/*",
+ "https://www.google.com.uy/*",
+ "http://www.google.com.uy/*",
+ "https://www.google.co.uz/*",
+ "http://www.google.co.uz/*",
+ "https://www.google.com.vc/*",
+ "http://www.google.com.vc/*",
+ "https://www.google.co.ve/*",
+ "http://www.google.co.ve/*",
+ "https://www.google.vg/*",
+ "http://www.google.vg/*",
+ "https://www.google.co.vi/*",
+ "http://www.google.co.vi/*",
+ "https://www.google.com.vn/*",
+ "http://www.google.com.vn/*",
+ "https://www.google.vu/*",
+ "http://www.google.vu/*",
+ "https://www.google.ws/*",
+ "http://www.google.ws/*",
+ "https://www.google.rs/*",
+ "http://www.google.rs/*",
+ "https://www.google.co.za/*",
+ "http://www.google.co.za/*",
+ "https://www.google.co.zm/*",
+ "http://www.google.co.zm/*",
+ "https://www.google.co.zw/*",
+ "http://www.google.co.zw/*",
+ "https://www.google.cat/*",
+ "http://www.google.cat/*"
+ ],
+ "run_at": "document_idle"
+ },
+ {
+ "js": [
+ "js/firstparties/lib/utils.js",
+ "js/firstparties/google-static.js"
+ ],
+ "matches": [
+ "https://hangouts.google.com/*",
+ "http://hangouts.google.com/*",
+ "https://docs.google.com/*",
+ "http://docs.google.com/*"
+ ],
+ "all_frames": true,
+ "run_at": "document_idle"
+ },
+ {
+ "js": [
+ "js/contentscripts/utils.js",
+ "js/contentscripts/clobbercookie.js",
+ "js/contentscripts/clobberlocalstorage.js",
+ "js/contentscripts/dnt.js",
+ "js/contentscripts/fingerprinting.js"
+ ],
+ "matches": [
+ "<all_urls>"
+ ],
+ "all_frames": true,
+ "match_about_blank": true,
+ "run_at": "document_start"
+ },
+ {
+ "js": [
+ "js/contentscripts/collapser.js",
+ "js/contentscripts/socialwidgets.js",
+ "js/contentscripts/supercookie.js"
+ ],
+ "matches": [
+ "<all_urls>"
+ ],
+ "all_frames": true,
+ "match_about_blank": true,
+ "run_at": "document_idle"
+ }
+ ],
+ "default_locale": "en_US",
+ "description": "__MSG_description__",
+ "icons": {
+ "16": "icons/badger-16.png",
+ "19": "icons/badger-19.png",
+ "38": "icons/badger-38.png",
+ "48": "icons/badger-48.png",
+ "64": "icons/badger-64.png",
+ "128": "icons/badger-128.png"
+ },
+ "manifest_version": 2,
+ "minimum_chrome_version": "18.0",
+ "name": "__MSG_name__",
+ "browser_action": {
+ "default_icon": {
+ "19": "icons/badger-19-disabled.png",
+ "38": "icons/badger-38-disabled.png"
+ },
+ "default_popup": "skin/popup.html",
+ "default_title": "__MSG_name__"
+ },
+ "options_ui": {
+ "page": "/skin/options.html",
+ "open_in_tab": true
+ },
+ "storage": {
+ "managed_schema": "data/schema.json"
+ },
+ "update_url": "https://clients2.google.com/service/update2/crx"
+}
diff --git a/src/skin/background.png b/src/skin/background.png
new file mode 100644
index 0000000..fb88958
--- /dev/null
+++ b/src/skin/background.png
Binary files differ
diff --git a/src/skin/css/firstRun.css b/src/skin/css/firstRun.css
new file mode 100644
index 0000000..28880a8
--- /dev/null
+++ b/src/skin/css/firstRun.css
@@ -0,0 +1,798 @@
+/* base styles, using foundation 6 defaults */
+html {
+ font-family:sans-serif;
+ line-height:1.15;
+ -ms-text-size-adjust:100%;
+ -webkit-text-size-adjust:100%;
+}
+
+article,aside,footer,header,nav,section {
+ display:block;
+}
+
+a {
+ background-color:transparent;
+ -webkit-text-decoration-skip:objects;
+}
+a:active,a:hover {
+ outline-width:0;
+}
+
+img {
+ border-style:none;
+}
+
+html {
+ box-sizing:border-box;
+ font-size:100%;
+}
+*,*::before,*::after {
+ box-sizing:inherit;
+}
+body /* base font and color for privacy badger */ {
+ margin:0;
+ padding:0;
+ background:#fefefe;
+ font-family:"OpenSans-Light",sans-serif;
+ font-weight:normal;
+ line-height:1.5;
+ color:#000;
+ -webkit-font-smoothing:antialiased;
+ -moz-osx-font-smoothing:grayscale;
+}
+img {
+ display:inline-block;
+ vertical-align:middle;
+ max-width:100%;
+ height:auto;
+ -ms-interpolation-mode:bicubic;
+}
+
+/* xy grid, selected foundation classes */
+.small-12 {
+ -ms-flex:0 0 100%;
+ flex:0 0 100%;
+ max-width:100%;
+}
+.grid-container {
+ padding-right:.625rem;
+ padding-left:.625rem;
+ max-width:75rem;
+ margin:0 auto;
+}
+@media print, screen and (min-width: 40em) {
+ .grid-container {
+ padding-right:.9375rem;
+ padding-left:.9375rem;
+ }
+}
+
+.grid-container.full {
+ padding-right:0;
+ padding-left:0;
+ max-width:100%;
+ margin:0 auto;
+}
+.grid-x {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-flow:row wrap;
+ flex-flow:row wrap;
+}
+.cell {
+ -ms-flex:0 0 auto;
+ flex:0 0 auto;
+ min-height:0px;
+ min-width:0px;
+ width:100%;
+}
+
+.grid-x>.small-shrink,.grid-x>.small-full,.grid-x>.small-1,.grid-x>.small-2,.grid-x>.small-3,.grid-x>.small-4,.grid-x>.small-5,.grid-x>.small-6,.grid-x>.small-7,.grid-x>.small-8,.grid-x>.small-9,.grid-x>.small-10,.grid-x>.small-11,.grid-x>.small-12 {
+ -ms-flex-preferred-size:auto;
+ flex-basis:auto;
+}
+@media print, screen and (min-width: 40em) {
+ .grid-x>.medium-10 {
+ -ms-flex-preferred-size:auto;
+ flex-basis:auto;
+ }
+
+}
+@media print, screen and (min-width: 64em) {
+ .grid-x>.large-3,.grid-x>.large-4 {
+ -ms-flex-preferred-size:auto;
+ flex-basis:auto;
+ }
+}
+.grid-x>.small-12 {
+ width:100%;
+}
+@media print, screen and (min-width: 40em) {
+ .grid-x>.medium-10 {
+ width:83.33333%;
+ }
+}
+@media print, screen and (min-width: 64em) {
+ .grid-x>.large-3 {
+ width:25%;
+ }
+ .grid-x>.large-4 {
+ width:33.33333%;
+ }
+}
+.grid-margin-x {
+ margin-left:-.625rem;
+ margin-right:-.625rem;
+}
+@media print, screen and (min-width: 40em) {
+ .grid-margin-x {
+ margin-left:-.9375rem;
+ margin-right:-.9375rem;
+ }
+}
+
+.grid-margin-x>.small-12 {
+ width:calc(100% - 1.25rem);
+}
+@media print, screen and (min-width: 40em) {
+
+ .grid-margin-x>.small-12 {
+ width:calc(100% - 1.875rem);
+ }
+ .grid-margin-x>.medium-10 {
+ width:calc(83.33333% - 1.875rem);
+ }
+}
+@media print, screen and (min-width: 64em) {
+ .grid-margin-x>.large-3 {
+ width:calc(25% - 1.875rem);
+ }
+ .grid-margin-x>.large-4 {
+ width:calc(33.33333% - 1.875rem);
+ }
+}
+.grid-padding-x .grid-padding-x {
+ margin-right:-.625rem;
+ margin-left:-.625rem;
+}
+@media print, screen and (min-width: 40em) {
+ .grid-padding-x .grid-padding-x {
+ margin-right:-.9375rem;
+ margin-left:-.9375rem;
+ }
+}
+
+.grid-padding-x>.cell {
+ padding-right:.625rem;
+ padding-left:.625rem;
+}
+@media print, screen and (min-width: 40em) {
+ .grid-padding-x>.cell {
+ padding-right:.9375rem;
+ padding-left:.9375rem;
+ }
+}
+
+@media print, screen and (min-width: 64em) {
+ .large-up-3>.cell {
+ width:33.33333%;
+ }
+ .large-up-4>.cell {
+ width:25%;
+ }
+}
+
+@media print, screen and (min-width: 64em) {
+ .grid-margin-x.large-up-3>.cell {
+ width:calc(33.33333% - 1.875rem);
+ }
+ .grid-margin-x.large-up-4>.cell {
+ width:calc(25% - 1.875rem);
+ }
+}
+
+.grid-padding-y {
+ margin-top:-.625rem;
+ margin-bottom:-.625rem;
+}
+@media print, screen and (min-width: 40em){
+ .grid-padding-y {
+ margin-top:-.9375rem;
+ margin-bottom:-.9375rem;
+ }
+}
+
+/* end xy grid */
+div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,p,blockquote,th,td {
+ margin:0;
+ padding:0;
+}
+p {
+ margin-bottom:1rem;
+ font-size:inherit;
+ line-height:1.6;
+ text-rendering:optimizeLegibility;
+}
+
+/* Privacy Badger header fonts */
+h1,
+h2,
+h3{
+ font-family:"OpenSans-Bold",sans-serif;
+ font-style:normal;
+ font-weight:normal;
+ color:inherit;
+ text-rendering:optimizeLegibility;
+}
+
+h1 {
+ font-size:1.875rem;
+ line-height:1.4;
+ margin-top:0;
+ margin-bottom:.5rem;
+}
+h2 {
+ font-size:1.25rem;
+ line-height:1.4;
+ margin-top:0;
+ margin-bottom:.5rem;
+}
+h3 {
+ font-size:1.1875rem;
+ line-height:1.4;
+ margin-top:0;
+ margin-bottom:.5rem;
+}
+
+@media print, screen and (min-width: 40em) {
+ h1 {
+ font-size:3.5rem;
+ }
+ h2 {
+ font-size:2.5rem;
+ }
+ h3 {
+ font-size:1.9375rem;
+ }
+}
+
+p {
+ font-family:"OpenSans-Light",sans-serif;
+}
+
+a {
+ line-height:inherit;
+ color:#F06A0A;
+ font-weight: bold;
+ text-decoration:none;
+ cursor:pointer;
+}
+a:hover,a:focus {
+ color:#000;
+}
+a img {
+ border:0;
+}
+
+hr {
+ border-top:0;
+ border-right:0;
+ border-bottom:1px solid #cacaca;
+ border-left:0;
+ box-sizing:content-box;
+ clear:both;
+ height:0;
+ margin:1.25rem auto;
+ max-width:75rem;
+ overflow:visible;
+}
+ul,ol,dl {
+ margin-bottom:1rem;
+ list-style-position:outside;
+ line-height:1.6;
+}
+li {
+ font-size:inherit;
+}
+ul {
+ margin-left:1.25rem;
+ list-style-type:disc;
+}
+ol {
+ margin-left:1.25rem;
+}
+ul ul,ol ul,ul ol,ol ol {
+ margin-left:1.25rem;
+ margin-bottom:0;
+}
+.text-left {
+ text-align:left;
+}
+.text-right {
+ text-align:right;
+}
+.text-center {
+ text-align:center;
+}
+.text-justify {
+ text-align:justify;
+}
+
+/* buttons */
+.button {
+ display:inline-block;
+ vertical-align:middle;
+ margin:0 0 1rem 0;
+ font-family:"OpenSans-Bold";
+ padding:0.85em 1em;
+ -webkit-appearance:none;
+ border:1px solid transparent;
+ border-radius:0;
+ transition:background-color 0.25s ease-out,color 0.25s ease-out;
+ font-size:0.9rem;
+ line-height:1;
+ text-align:center;
+ cursor:pointer;
+ background-color:#F06A0A;
+ color:#fefefe;
+}
+button:hover,.button:focus {
+ background-color:#cc5a09;
+ color:#fefefe;
+}
+
+.button.large {
+ font-size:1rem;
+ padding:0.8rem 2rem;
+ margin-top:1rem;
+ text-transform:uppercase;
+}
+
+/* top-bar and header*/
+.top-bar {
+ align-items: center;
+ background-color: #F06A0A;
+ color: white;
+ display: -ms-flexbox;
+ display :flex;
+ flex-flow: row wrap;
+ flex-wrap: wrap;
+ font-family: "OpenSans-Bold",sans-serif;
+ font-size: 0.6rem;
+ justify-content: center;
+ padding: 0.5rem 0.5rem 1rem;
+ -ms-flex-flow: row wrap;
+ -ms-flex-wrap: wrap;
+ -ms-flex-align: center;
+ -ms-flex-pack: justify;
+ text-transform: uppercase;
+}
+@media print, screen and (min-width: 40em) {
+ .top-bar {
+ font-size: 0.9rem;
+ padding: 1rem 0.5rem 1.5rem;
+ }
+}
+.top-bar img {
+ max-width: 3rem;
+ margin-inline-end: 0.2rem;
+}
+@media print, screen and (min-width: 40em) {
+ .top-bar img {
+ margin-inline-end: 1rem;
+ }
+}
+
+@media print, screen and (min-width: 40em) {
+ .top-bar {
+ -ms-flex-wrap:nowrap;
+ flex-wrap:nowrap;
+ }
+}
+
+.top-bar-title {
+ -ms-flex:0 0 auto;
+ flex:0 0 auto;
+ margin:0.5rem 1rem 0.5rem 0;
+}
+
+header {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-flow:row wrap;
+ flex-flow:row wrap;
+ background-color:#EC9329;
+}
+header img {
+ width:7rem;
+}
+@media print, screen and (min-width: 40em) {
+ header img {
+ margin:1rem 0 0;
+ width:15rem;
+ }
+}
+header .title-bar h1 {
+ color:white;
+ font-family:"ChunkFive",serif;
+}
+
+/* visibility classes */
+.hide {
+ display:none !important;
+}
+.invisible {
+ visibility:hidden;
+}
+@media screen and (max-width: 39.9375em) {
+ .hide-for-small-only {
+ display:none !important;
+ }
+}
+@media screen and (max-width: 0em), screen and (min-width: 40em) {
+ .show-for-small-only {
+ display:none !important;
+ }
+}
+@media print, screen and (min-width: 40em) {
+ .hide-for-medium {
+ display:none !important;
+ }
+}
+@media screen and (max-width: 39.9375em) {
+ .show-for-medium {
+ display:none !important;
+ }
+}
+@media screen and (min-width: 40em) and (max-width: 63.9375em) {
+ .hide-for-medium-only {
+ display:none !important;
+ }
+}
+@media screen and (max-width: 39.9375em), screen and (min-width: 64em) {
+ .show-for-medium-only {
+ display:none !important;
+ }
+}
+@media print, screen and (min-width: 64em) {
+ .hide-for-large {
+ display:none !important;
+ }
+}
+@media screen and (max-width: 63.9375em) {
+ .show-for-large {
+ display:none !important;
+ }
+}
+@media screen and (min-width: 64em) and (max-width: 74.9375em) {
+ .hide-for-large-only {
+ display:none !important;
+ }
+}
+@media screen and (max-width: 63.9375em), screen and (min-width: 75em) {
+ .show-for-large-only {
+ display:none !important;
+ }
+}
+
+.align-right {
+ -ms-flex-pack:end;
+ justify-content:flex-end;
+}
+.align-center {
+ -ms-flex-pack:center;
+ justify-content:center;
+}
+.align-justify {
+ -ms-flex-pack:justify;
+ justify-content:space-between;
+}
+.align-spaced {
+ -ms-flex-pack:distribute;
+ justify-content:space-around;
+}
+
+/* share links */
+.share-links {
+ display:block;
+ margin:2.5rem auto 2rem;
+ padding-bottom:3rem;
+ width:94px;
+ z-index:3;
+}
+.share-links>a {
+ position:relative;
+ width:2.6rem;
+ height:2.6rem;
+ overflow:hidden;
+}
+.share-links>a:hover {
+ background-color:transparent !important;
+}
+.share-links>a i {
+ position:relative;
+ display:inline-block;
+ height:2.6rem;
+ width:2.6rem;
+ z-index:2;
+}
+.share-links>a span {
+ position:absolute;
+ visibility:hidden;
+ display:inline-block;
+ top:0;
+ right:0;
+ z-index:1;
+ opacity:0.9;
+ width:12.5rem;
+ height:2.6rem;
+ box-sizing:content-box;
+ line-height:2.6rem;
+ padding-left:.45614rem;
+ text-align:left;
+ text-transform:uppercase;
+ font-size:0.9rem;
+ background-color:white;
+ border-left:0.312rem solid #fff;
+}
+.share-links>a:first-child {
+ margin-top:0;
+ margin-left:0;
+}
+.share-links>a.share-twitter i {
+ background:url("../images/twitter.svg");
+}
+.share-links>a.share-twitter i:hover {
+ opacity:0.7;
+}
+.share-links>a.share-facebook i {
+ background:url("../images/facebook.svg");
+}
+.share-links>a.share-facebook i:hover {
+ opacity:0.7;
+}
+.share-links>a {
+ display:inline-block;
+ float:left;
+ margin-left:.65rem;
+}
+.share-links>a.share-clipboard {
+ display:none;
+}
+@media print, screen and (min-width: 40em) {
+ .share-links {
+ padding-bottom:0;
+ position:fixed;
+ top:5rem;
+ width:55px;
+ }
+ .share-links>a {
+ position:relative;
+ width:3.5625rem;
+ height:3.5625rem;
+ overflow:hidden;
+ }
+ .share-links>a:hover {
+ background-color:transparent !important;
+ }
+ .share-links>a i {
+ position:relative;
+ display:inline-block;
+ height:3.5625rem;
+ width:3.5625rem;
+ z-index:2;
+ }
+ .share-links>a span {
+ position:absolute;
+ visibility:hidden;
+ display:inline-block;
+ top:0;
+ right:0;
+ z-index:1;
+ opacity:0.9;
+ width:12.5rem;
+ height:3.5625rem;
+ box-sizing:content-box;
+ line-height:3.5625rem;
+ padding-left:.625rem;
+ text-align:left;
+ text-transform:uppercase;
+ font-size:0.9rem;
+ background-color:white;
+ border-left:0.4275rem solid #fff;
+ }
+ .share-links>a:first-child {
+ margin-top:0;
+ margin-left:0;
+ }
+ .share-links>a.share-twitter i {
+ background:url("../images/twitter.svg");
+ }
+ .share-links>a.share-twitter i:hover {
+ opacity:0.7;
+ }
+ .share-links>a.share-facebook i {
+ background:url("../images/facebook.svg");
+ }
+ .share-links>a.share-facebook i:hover {
+ opacity:0.7;
+ }
+ .share-links>a {
+ display:block;
+ float:none;
+ margin-left:0;
+ margin-top:.45614rem;
+ }
+ .share-links>a:hover,.share-links>a:focus {
+ width:17.115rem;
+ transition:width 130ms;
+ }
+ .share-links>a:hover i,.share-links>a:focus i {
+ position:relative;
+ z-index:2;
+ }
+ .share-links>a:hover span,.share-links>a:focus span {
+ visibility:visible;
+ }
+}
+/* fonts */
+@font-face {
+ font-family:'ChunkFive';
+ src:url("../fonts/Chunk.ttf") format("truetype");
+ font-weight:900;
+ font-style:normal;
+}
+@font-face {
+ font-family:'OpenSans-Light';
+ src:url("../fonts/OpenSans-Light.ttf") format("truetype");
+ font-weight:300;
+ font-style:normal;
+}
+@font-face {
+ font-family:'OpenSans-Bold';
+ src:url("../fonts/OpenSans-Bold.ttf") format("truetype");
+ font-weight:600;
+ font-style:normal;
+}
+
+/* pb specific */
+body {
+ font-size:16px;
+ padding-bottom:3rem;
+}
+
+.text {
+ margin:1rem 0;
+}
+.caret-down {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-flow:row wrap;
+ flex-flow:row wrap;
+ padding:3rem 0 5rem;
+}
+.caret-down img {
+ width:5rem;
+}
+.grid-container.full {
+ margin-bottom: 5rem;
+}
+#intro {
+ padding:2rem 0rem 4rem;
+}
+@media print, screen and (min-width: 40em) {
+ #intro {
+ padding:4rem 0rem 14rem;
+ }
+}
+[id*="pb-features-"],#pb-settings {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-flow:row wrap;
+ flex-flow:row wrap;
+ padding:3rem 0 2rem;
+}
+@media print, screen and (min-width: 40em) {
+ [id*="pb-features-"],#pb-settings {
+ padding:3rem 0 5rem;
+ }
+}
+[id*="pb-features-"] div,#pb-settings div {
+ width:calc(100% - 1.875rem);
+ margin-right:.9375rem;
+ margin-left:.9375rem;
+ text-align:center;
+}
+@media print, screen and (min-width: 40em) {
+ [id*="pb-features-"] div,#pb-settings div {
+ width:calc(33.33333% - 1.875rem);
+ margin-right:.9375rem;
+ margin-left:.9375rem;
+ }
+
+}
+[id*="pb-features-"] h3,#pb-settings h3 {
+ font-size:1.5rem;
+ text-align:center;
+ margin-top:1rem;
+}
+@media print, screen and (min-width: 40em) {
+ [id*="pb-features-"] h3, #pb-settings h3 {
+ text-align: start;
+ font-size: 1.9375rem;
+ }
+}
+[id*="pb-features-"] .text, [id*="pb-features-"] p, #pb-settings .text, #pb-settings p {
+ text-align: start;
+}
+#pb-settings {
+ background-image:linear-gradient(#EC9329, #EC9329 30%, #fff 30%);
+}
+[id*="pb-donate"] {
+ display:-ms-flexbox;
+ display:flex;
+ -ms-flex-flow:row wrap;
+ flex-flow:row wrap;
+}
+[id*="pb-donate"] img {
+ max-width:200px;
+}
+@media print, screen and (min-width: 40em) {
+ [id*="pb-donate"] img {
+ max-width:250px;
+ }
+}
+[id*="pb-donate"] div {
+ width:calc(100% - 1.875rem);
+ margin-right:.9375rem;
+ margin-left:.9375rem;
+}
+@media print, screen and (min-width: 40em) {
+ [id*="pb-donate"] div {
+ width:calc(33.33333% - 1.875rem);
+ margin-right:.9375rem;
+ margin-left:.9375rem;
+ }
+
+}
+[id*="pb-donate"] h3 {
+ font-size:1.5rem;
+ text-align:center;
+ margin-top:1rem;
+}
+@media print, screen and (min-width: 40em) {
+ [id*="pb-donate"] h3 {
+ font-size:1.9375rem;
+ }
+}
+[id*="pb-donate"] span {
+ color:#F06A0A;
+ font-family:"OpenSans-Bold",sans-serif;
+ font-size:0.9rem;
+ text-align:center;
+ text-transform:uppercase;
+}
+#pb-donate {
+ background-image:linear-gradient(#DFDFE6, #DFDFE6 30%, #fff 30%);
+ padding:4rem 0;
+}
+#pb-privacy-policy, #pb-privacy-policy a {
+ color:#707070;
+ font-family:"OpenSans-Light",sans-serif;
+ font-size:0.9rem;
+ text-align:center;
+}
+@media print, screen and (min-width: 40em) {
+ #pb-donate {
+ background-image:linear-gradient(#DFDFE6, #DFDFE6 45%, #fff 45%);
+ padding:7rem 0;
+ }
+}
+#pb-donate-help {
+ margin-bottom:0;
+}
+@media print, screen and (min-width: 40em) {
+ #pb-donate-help {
+ margin-bottom:5rem;
+ }
+}
diff --git a/src/skin/firstRun.html b/src/skin/firstRun.html
new file mode 100644
index 0000000..307a90a
--- /dev/null
+++ b/src/skin/firstRun.html
@@ -0,0 +1,131 @@
+<!doctype html>
+<html>
+<head>
+ <title class="i18n_firstRun_title"></title>
+ <meta charset="utf-8">
+ <meta http-equiv="x-ua-compatible" content="ie=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <link type="text/css" href="css/firstRun.css" rel="stylesheet" />
+ <script type="text/javascript" src="/lib/vendor/jquery-3.5.1.js"></script>
+ <script type="text/javascript" src="/lib/vendor/jquery.smooth-scroll.js"></script>
+ <script type="text/javascript" src="/lib/i18n.js"></script>
+ <script type="text/javascript" src="js/firstRun.js"></script>
+</head>
+<body>
+ <div class="grid-container full">
+
+ <div class="top-bar small-12 align-center cell">
+ <img src ="images/eff-logo.png" alt="">
+ <span class="i18n_intro_by_eff"></span>
+ </div>
+
+ <header class="grid-padding-y align-center">
+ <div class="small-12 text-center cell">
+ <img src="../icons/badger-bw-noborder.svg" alt="">
+ </div>
+ <div class="title-bar small-12 text-center cell">
+ <h1 class="i18n_name"></h1>
+ </div>
+ </header>
+
+ <!-- intro -->
+ <div id="intro" class="grid-x grid-padding-x align-center">
+ <div class="small-12 medium-10 text-center cell">
+ <h3 class="i18n_firstRun_title"></h3>
+ </div>
+ <div class="small-12 medium-10 large-4 text cell">
+ <p class="i18n_intro_welcome"></p>
+ </div>
+ <div class="small-12 text-center cell">
+ <a href="#pb-features-1" class="i18n_intro_next_button button large scroll-it"></a>
+ </div>
+ </div>
+
+ <!-- privacy badger features -->
+ <div id="pb-features-1" class="align-center">
+ <div>
+ <img src="images/learns-trackers.png" alt="">
+ </div>
+ <div>
+ <h3 class="i18n_intro_learns"></h3>
+ <p class="i18n_intro_learns_paragraph"></p>
+ </div>
+ </div>
+ <div id="pb-features-2" class="align-center">
+ <div class="cell hide-for-small-only">
+ <h3 class="i18n_intro_beyond_ads"></h3>
+ <p class="i18n_intro_beyond_ads_paragraph"></p>
+ </div>
+ <div class="small-12 large-3 cell">
+ <img src="images/catches-trackers.png" alt="">
+ </div>
+ <div class="cell hide-for-large hide-for-medium">
+ <h3 class="i18n_intro_beyond_ads"></h3>
+ <p class="i18n_intro_beyond_ads_paragraph"></p>
+ </div>
+ </div>
+ <div id="pb-features-3" class="align-center">
+ <div class="cell">
+ <img src="images/not-ad-blocker.png" alt="">
+ </div>
+ <div class="cell">
+ <h3 class="i18n_intro_not_an_adblocker"></h3>
+ <p class="i18n_intro_not_an_adblocker_paragraph"></p>
+ </div>
+ </div>
+ <div class="caret-down align-center">
+ <a href="#pb-settings" class="scroll-it"><img src="images/carrot-down.svg" alt="i18n_next_section"></a>
+ </div>
+
+ <!-- privacy badger settings -->
+ <div id="pb-settings" class="align-center">
+ <div class="text">
+ <img src="images/disable-badger.png" alt="">
+ <p class="i18n_intro_disable_button text"></p>
+ <p class="i18n_intro_report_button"></p>
+ <p class="i18n_intro_privacy_note"></p>
+ </div>
+ </div>
+ <div class="caret-down align-center">
+ <a href="#pb-donate" class="scroll-it"><img src="images/carrot-down.svg" alt="i18n_next_section"></a>
+ </div>
+
+ <!-- donate ask -->
+ <div id="pb-donate" class="align-center">
+ <div class="text-center">
+ <img src="images/pb-logo-outline.svg" alt="">
+ <h3 class="i18n_intro_donate_heading"></h3>
+ <p class="i18n_intro_donate1 text"></p>
+ </div>
+ </div>
+ <div id="pb-donate-button" class="align-center">
+ <div class="text-center">
+ <a class="i18n_donate_to_eff button large" target="_blank" href="https://supporters.eff.org/donate/support-privacy-badger"></a>
+ </div>
+ </div>
+ <div id="pb-donate-help" class="align-center">
+ <span class="i18n_intro_donate_subheading"></span>
+ </div>
+ </div>
+
+ <!-- social media icons -->
+ <div class="share-links">
+ <a class="share-facebook" target="_blank" rel="noopener noreferrer" href="https://www.facebook.com/share.php?u=https%3A%2F%2Feff.org%2Fprivacybadger">
+ <i></i>
+ <span class="i18n_share_button_title_facebook"></span>
+ </a>
+ <a class="share-twitter" target="_blank" rel="noopener noreferrer" href="https://twitter.com/home?status=I%20just%20installed%20Privacy%20Badger%2C%20a%20new%20tool%20from%20@EFF%20to%20stop%20companies%20from%20spying%20on%20your%20browsing%20habits%20https%3A%2F%2Feff.org%2Fprivacybadger&related=eff">
+ <i></i>
+ <span class="i18n_share_button_title_twitter"></span>
+ </a>
+ </div>
+
+ <!-- privacy policy link -->
+ <div class="grid-container full">
+ <div id="pb-privacy-policy">
+ <a class="i18n_intro_link_policy" target="_blank" href="https://www.eff.org/code/privacy/policy"></a>
+ </div>
+ </div>
+
+</body>
+</html>
diff --git a/src/skin/fonts/Chunk.ttf b/src/skin/fonts/Chunk.ttf
new file mode 100644
index 0000000..989342b
--- /dev/null
+++ b/src/skin/fonts/Chunk.ttf
Binary files differ
diff --git a/src/skin/fonts/OpenSans-Bold.ttf b/src/skin/fonts/OpenSans-Bold.ttf
new file mode 100644
index 0000000..7b52945
--- /dev/null
+++ b/src/skin/fonts/OpenSans-Bold.ttf
Binary files differ
diff --git a/src/skin/fonts/OpenSans-Light.ttf b/src/skin/fonts/OpenSans-Light.ttf
new file mode 100644
index 0000000..563872c
--- /dev/null
+++ b/src/skin/fonts/OpenSans-Light.ttf
Binary files differ
diff --git a/src/skin/images/EFF-red.svg b/src/skin/images/EFF-red.svg
new file mode 100644
index 0000000..aed0c85
--- /dev/null
+++ b/src/skin/images/EFF-red.svg
@@ -0,0 +1,7 @@
+<svg id="Group_925" data-name="Group 925" xmlns="http://www.w3.org/2000/svg" width="253.447" height="62" viewBox="0 0 253.447 62">
+ <g id="Group_8" data-name="Group 8" transform="translate(0 0)">
+ <path id="Path_13" data-name="Path 13" d="M100,17.6v62h81.543V61.854h-54.98v-4.38h54.98V39.727h-54.98V35.29h54.98V17.6Z" transform="translate(-100 -17.6)" fill="#ec1e1e"/>
+ <path id="Path_14" data-name="Path 14" d="M253.1,17.6v62h26.564V57.473h54.924V39.727H279.664V35.29h54.924V17.6Z" transform="translate(-167.12 -17.6)" fill="#ec1e1e"/>
+ <path id="Path_15" data-name="Path 15" d="M406.1,17.6v62h26.563V57.473h54.98V39.727h-54.98V35.29h54.98V17.6Z" transform="translate(-234.196 -17.6)" fill="#ec1e1e"/>
+ </g>
+</svg>
diff --git a/src/skin/images/carrot-down.svg b/src/skin/images/carrot-down.svg
new file mode 100644
index 0000000..a5dba24
--- /dev/null
+++ b/src/skin/images/carrot-down.svg
@@ -0,0 +1,10 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="-1621.307 714.102 105.583 46.301">
+ <defs>
+ <style>
+ .cls-1 {
+ fill: #f06a0a;
+ }
+ </style>
+ </defs>
+ <path id="Path_31" data-name="Path 31" class="cls-1" d="M778.693,864.478l51.766,46.3,53.816-46.3H778.693Z" transform="translate(-2400 -150.376)"/>
+</svg>
diff --git a/src/skin/images/catches-trackers.png b/src/skin/images/catches-trackers.png
new file mode 100644
index 0000000..378d59d
--- /dev/null
+++ b/src/skin/images/catches-trackers.png
Binary files differ
diff --git a/src/skin/images/disable-badger.png b/src/skin/images/disable-badger.png
new file mode 100644
index 0000000..f9cd1ec
--- /dev/null
+++ b/src/skin/images/disable-badger.png
Binary files differ
diff --git a/src/skin/images/eff-logo.png b/src/skin/images/eff-logo.png
new file mode 100644
index 0000000..885ae3c
--- /dev/null
+++ b/src/skin/images/eff-logo.png
Binary files differ
diff --git a/src/skin/images/facebook.svg b/src/skin/images/facebook.svg
new file mode 100644
index 0000000..357448f
--- /dev/null
+++ b/src/skin/images/facebook.svg
@@ -0,0 +1,19 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="702 -1123.104 61.5 61.418">
+ <defs>
+ <style>
+ .cls-1 {
+ fill: #f06a0a;
+ }
+
+ .cls-2 {
+ fill: #fff;
+ }
+ </style>
+ </defs>
+ <g id="facebook" transform="translate(296 -1877)">
+ <g id="XMLID_44_" transform="translate(406 753.896)">
+ <path id="XMLID_45_" class="cls-1" d="M0,96.6v61.418H61.5V96.6Z" transform="translate(0 -96.6)"/>
+ </g>
+ <path id="XMLID_3_" class="cls-2" d="M44.025,118.139h-4.2a1.763,1.763,0,0,0-1.647,1.482v4.2H43.86c-.247,3.211-.741,6.175-.741,6.175H38.1v18.359H30.6V129.995H26.9V123.9h3.7V118.88c0-.906-.247-7.08,7.739-7.08h5.6l.082,6.339Z" transform="translate(401.247 654.609)"/>
+ </g>
+</svg>
diff --git a/src/skin/images/learns-trackers.png b/src/skin/images/learns-trackers.png
new file mode 100644
index 0000000..0917971
--- /dev/null
+++ b/src/skin/images/learns-trackers.png
Binary files differ
diff --git a/src/skin/images/not-ad-blocker.png b/src/skin/images/not-ad-blocker.png
new file mode 100644
index 0000000..36730d3
--- /dev/null
+++ b/src/skin/images/not-ad-blocker.png
Binary files differ
diff --git a/src/skin/images/pb-logo-outline.svg b/src/skin/images/pb-logo-outline.svg
new file mode 100644
index 0000000..9e014cc
--- /dev/null
+++ b/src/skin/images/pb-logo-outline.svg
@@ -0,0 +1,41 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="-1747.579 2191.24 365.35 264.081">
+ <defs>
+ <style>
+ .cls-1, .cls-2 {
+ fill: none;
+ }
+
+ .cls-1 {
+ stroke: #f2aa27;
+ stroke-miterlimit: 10;
+ stroke-width: 25.08px;
+ }
+
+ .cls-3 {
+ fill: #fff;
+ }
+ </style>
+ </defs>
+ <g id="privacy-badger-logo" transform="translate(-1747.511 2191.229)">
+ <path id="_Path_" data-name="&lt;Path&gt;" class="cls-1" d="M535.9,424.321,534.42,418.6c-7.373-28.442-27.122-47.848-27.959-48.663h0l-.483-.461a78.865,78.865,0,0,0-13-41.73c4.293-.8,9.5-1.728,15.445-2.7l-1.492-8.372,11.624,5.012c13.953-8.275,19.062-25.5,9.9-40.055-7.739-12.289-33.97-15.1-48.534-7.513-8.2,4.293-16.561,13.62-22.314,21a124.427,124.427,0,0,0-58.076-16.293,160.49,160.49,0,0,0-33.97,2.662c-1.138-14.028-10.389-29.151-27.476-30.052-21.037-1.073-32.36,12.944-31.823,26.425.3,7.513,6.526,15.273,11.935,20.6a111.279,111.279,0,0,0-45.755,48.3c-20.135,40.71-46.152,58.237-54.738,63.99a18.248,18.248,0,0,0-3.628,2.769c-12.987,6.032-13.953,18.772-6.493,29.419a19.706,19.706,0,0,0,7.513,5.957,33.263,33.263,0,0,0,2.6,4.046c13.266,17.688,42.664,21.4,64.988,21.4a184.848,184.848,0,0,0,20.393-1.073l24.943,2.029c5.152,6.44,13.384,10.636,23.054,11.1,8.49.408,15.1-2.415,17.173-3.027,12.386,3.81,20.221,7.009,32.736,7.009,20.21,0,41.311-4.722,58.784-14.3,15.091-8.264,27.09-21.616,33.991-33.347.354-.59.687-1.2,1.073-1.814,14.543-3.649,23.494,4.669,23.612,4.733l4.6,3.327-1.073-5.9c-2.694-14.447-8.189-23.248-12.3-28.475,9.864.816,21.058,6.644,21.208,6.74Z" transform="translate(-190.39 -238.82)"/>
+ <g id="_Group_" data-name="&lt;Group&gt;" transform="translate(12.511 12.556)">
+ <g id="_Group_2" data-name="&lt;Group&gt;">
+ <path id="_Path_2" data-name="&lt;Path&gt;" class="cls-2" d="M507.421,403.6c-5.549-2.715-14.65-5.485-22.131-5.452a61.692,61.692,0,0,1,22.131,5.452Z" transform="translate(-182.203 -240.618)"/>
+ <path id="_Path_3" data-name="&lt;Path&gt;" class="cls-3" d="M338.826,284.912c-.708-5.8-2.866-14.1-9.4-15.735-10.25-2.565-19.47,4.1-16.9,12.8a24.847,24.847,0,0,0,6.73,10.572l.419-.2a162.544,162.544,0,0,1,19.158-7.438Z" transform="translate(-194.898 -250.112)"/>
+ <path id="_Path_4" data-name="&lt;Path&gt;" class="cls-3" d="M466.405,314.361c1.664-.462,3.574-.955,5.774-1.481,14.854-3.585,21.466-10.733,19.985-16.4s-12.3-10.25-22.539-4.1a65.926,65.926,0,0,0-13.7,11.678,100.691,100.691,0,0,1,10.475,10.3Z" transform="translate(-184.355 -248.585)"/>
+ <path id="_Path_5" data-name="&lt;Path&gt;" class="cls-3" d="M315.616,454.628a92.4,92.4,0,0,0,10.239.494,119.914,119.914,0,0,0,14.758-.923L334.6,447.19a116.457,116.457,0,0,1-19.663,7.62Z" transform="translate(-194.689 -237.024)"/>
+ <path id="_Path_6" data-name="&lt;Path&gt;" class="cls-3" d="M343.752,454.337c2.3-.4,4.647-.869,7.041-1.449a58.4,58.4,0,0,0,14.65-5.646L352.188,435.78A100.894,100.894,0,0,1,336.7,446.116Z" transform="translate(-193.094 -237.86)"/>
+ <path id="_Path_7" data-name="&lt;Path&gt;" class="cls-3" d="M299.967,314.084a152.746,152.746,0,0,0-15.885,27l8.9-1.213a208.906,208.906,0,0,1-59.16,66.169,64.666,64.666,0,0,1,29.762,5.967,27.523,27.523,0,0,1,4.787,2.941c6.794-5.163,38.864-29.945,52.924-47.976,15.777-20.221,25.083-27.509,25.083-27.509l2.479,10.937s46.152-47.729,86.154-45.3c0,0-5.259,3.22-8.093,11.731,0,0,27.187-6.88,54.566,6.644A109.48,109.48,0,0,0,465.6,307.483c-18.761-15.337-42.932-23.258-65.063-25.083-41.215,11.6-89.706,63.55-89.706,63.55s6.515-11.806,20.017-29.322c10.883-14.146,26.188-27.455,32.682-32.854a147.393,147.393,0,0,0-38.95,12.3A73.992,73.992,0,0,0,299.967,314.084Z" transform="translate(-200.635 -249.102)"/>
+ <path id="_Path_8" data-name="&lt;Path&gt;" class="cls-3" d="M377,436.072c1.138-2.147,1.46-4.154.923-5.56-1.073-2.64-3.156-3.982-6.332-3.982S363,427.6,354.8,433.442l13.6,11.806a27.971,27.971,0,0,0,8.6-9.177Z" transform="translate(-191.767 -238.538)"/>
+ <ellipse id="_Path_9" data-name="&lt;Path&gt;" class="cls-3" cx="12.944" cy="5.388" rx="12.944" ry="5.388" transform="translate(33.293 168.308)"/>
+ <path id="_Path_10" data-name="&lt;Path&gt;" d="M359.54,417.7l.537.268c7.352-3.435,23.194-3.778,29.666,3.22,8.082,8.758.784,19.716-1.073,21.573h.537c5.366-2.694,8.436-6.1,9.434-10.518,1.288-5.71.633-9.917-3.22-14.5C388.1,409.094,371.411,408.257,359.54,417.7Z" transform="translate(-191.42 -239.681)"/>
+ <path id="_Compound_Path_" data-name="&lt;Compound Path&gt;" class="cls-3" d="M501.681,364.794v-.408a54.61,54.61,0,0,0-26.457-12.74h0c-11.162-1.792-24.686-.408-38.639,9.123,0,0,23.462-2.018,36,10.11,0,0-17.4-4.454-31.952,3.22s-33.573,32.36-70.376,30.739c-30.75-1.352-39.24-3.22-57.035,3.638-11.5,4.443-26.339,11.914-35.419,16.647-.182,5.216-3.617,10.54-12.3,14.769-13.749,6.7-30.138,7.6-42.492,4.808,13.577,14.393,42.02,16.625,58.323,16.625a178.769,178.769,0,0,0,19.942-1.073h.29l.794.064,2.812-.429c.3,0,30.406-4.776,52.473-21.766,9.381-7.223,17.334-10.894,23.613-10.894,5.152,0,9.112,2.576,10.862,7.084,1.073,2.758.676,6.064-1.138,9.552-4.508,8.661-16.55,16.507-30.686,19.974a118.136,118.136,0,0,1-26.832,3.22c4.068,3.531,9.66,5.678,16.1,6.365a36.333,36.333,0,0,0,17.1-2.4l.88-.3h0c3.07-1.148,13.019-6.8,13.019-6.8s-3.95,6.44-7.706,8.9c10.475,3.037,16.389,3.714,27.058,3.714,30.729,0,68.82-19.491,85.552-47.933l.215-.386v.075c13.191-4.69,22.292-.622,27.283,2.479-4.433-16.872-12.708-25.244-12.815-25.351l-3.327-3.22,3.6-.419a29.07,29.07,0,0,1,4.046-.118c7.513,0,16.582,2.737,22.131,5.452a92.433,92.433,0,0,0-24.911-42.309Zm-93,71.857c-1,4.422-4.046,7.814-9.434,10.518h-.537c1.857-1.857,9.155-12.815,1.073-21.573-6.44-7.009-22.3-6.665-29.666-3.22l-.537-.268c11.86-9.434,28.56-8.586,35.87.064C409.291,426.734,409.946,430.941,408.68,436.651Z" transform="translate(-201.427 -244.076)"/>
+ <path id="_Compound_Path_2" data-name="&lt;Compound Path&gt;" d="M535.9,424.321,534.42,418.6c-7.373-28.442-27.122-47.848-27.959-48.663h0l-.483-.461a78.865,78.865,0,0,0-13-41.73c4.293-.8,9.5-1.728,15.445-2.7l-1.492-8.372,11.624,5.012c13.953-8.275,19.062-25.5,9.9-40.055-7.739-12.289-33.97-15.1-48.534-7.513-8.2,4.293-16.561,13.62-22.314,21a124.427,124.427,0,0,0-58.076-16.293,160.475,160.475,0,0,0-33.97,2.662c-1.138-14.028-10.39-29.151-27.476-30.052-21.037-1.073-32.36,12.944-31.823,26.425.3,7.513,6.526,15.273,11.935,20.6a111.279,111.279,0,0,0-45.755,48.3c-20.135,40.71-46.152,58.237-54.738,63.99a18.248,18.248,0,0,0-3.628,2.769c-12.987,6.032-13.953,18.772-6.493,29.419a19.706,19.706,0,0,0,7.513,5.957,33.263,33.263,0,0,0,2.6,4.046c13.266,17.688,42.664,21.4,64.988,21.4a184.833,184.833,0,0,0,20.393-1.073l24.943,2.029c5.152,6.44,13.384,10.636,23.054,11.1,8.49.408,15.1-2.415,17.173-3.027,12.386,3.81,20.221,7.009,32.736,7.009,20.21,0,41.311-4.722,58.784-14.3,15.091-8.264,27.09-21.616,33.991-33.347.354-.59.687-1.2,1.073-1.814,14.543-3.649,23.494,4.669,23.612,4.733l4.6,3.327-1.073-5.9c-2.694-14.447-8.189-23.248-12.3-28.475,9.864.816,21.058,6.644,21.208,6.74ZM488.15,295.171c10.25-6.15,21-1.535,22.539,4.1s-5.12,12.815-19.985,16.4c-2.147.526-4.1,1.073-5.774,1.481a100.717,100.717,0,0,0-10.486-10.3A65.923,65.923,0,0,1,488.15,295.171Zm-122.356-9.134c-6.493,5.366-21.8,18.708-32.682,32.854C319.6,336.45,313.1,348.213,313.1,348.213s48.492-51.958,89.706-63.55c22.11,1.825,46.291,9.735,65.063,25.083a109.488,109.488,0,0,1,15.885,15.992c-27.391-13.524-54.566-6.644-54.566-6.644,2.833-8.49,8.093-11.731,8.093-11.731-40.1-2.415-86.154,45.315-86.154,45.315L348.7,341.752s-9.305,7.277-25.083,27.509c-14.06,18.031-46.152,42.814-52.924,47.976A27.516,27.516,0,0,0,265.9,414.3a64.664,64.664,0,0,0-29.763-5.968A208.905,208.905,0,0,0,295.246,342.2l-8.9,1.213a152.748,152.748,0,0,1,15.885-27A73.992,73.992,0,0,1,326.8,298.391a147.394,147.394,0,0,1,38.95-12.343Zm37.63,96.425a15.8,15.8,0,1,0-.043.011ZM262.039,425.083c0,2.984-5.8,5.366-12.944,5.366s-12.944-2.415-12.944-5.366,5.8-5.366,12.944-5.366S262.039,422.1,262.039,425.083Zm58.4-141.825c-2.565-8.715,6.665-15.37,16.9-12.8,6.536,1.631,8.694,9.939,9.4,15.735a162.531,162.531,0,0,0-19.158,7.427l-.419.2a24.847,24.847,0,0,1-6.687-10.561Zm59.031,174.786-13.534-11.731c8.189-5.839,13.674-6.912,16.786-6.912s5.3,1.342,6.333,3.982c.547,1.4.215,3.37-.923,5.56a27.969,27.969,0,0,1-8.6,9.091ZM361.93,449.3l13.255,11.463a58.4,58.4,0,0,1-14.651,5.646q-3.59.885-7.041,1.449l-7.052-8.232a100.89,100.89,0,0,0,15.552-10.336Zm-19.18,12.257,6.01,7.009a119.925,119.925,0,0,1-14.758.923,92.367,92.367,0,0,1-10.239-.494l-.665.182a116.452,116.452,0,0,0,19.727-7.631Zm163.141-52.591a29.069,29.069,0,0,0-4.046.118l-3.6.419,3.327,3.22c.107.107,8.382,8.49,12.815,25.351-4.98-3.1-14.092-7.17-27.283-2.479v-.064l-.215.386c-16.733,28.442-54.813,47.933-85.552,47.933-10.669,0-16.582-.665-27.058-3.714,3.767-2.512,7.706-8.9,7.706-8.9s-9.96,5.656-13.019,6.8h0l-.88.3a36.33,36.33,0,0,1-16.969,2.318c-6.44-.687-12.032-2.833-16.1-6.365a118.14,118.14,0,0,0,26.832-3.22c14.135-3.467,26.178-11.3,30.685-19.974,1.814-3.488,2.211-6.794,1.138-9.552-1.749-4.5-5.71-7.084-10.862-7.084-6.29,0-14.243,3.66-23.613,10.894-22.067,16.99-52.173,21.723-52.473,21.766l-2.812.429-.794-.064h-.29a178.739,178.739,0,0,1-19.942,1.073c-16.314,0-44.756-2.243-58.323-16.625,12.354,2.8,28.743,1.889,42.492-4.808,8.672-4.229,12.107-9.552,12.3-14.769,9.091-4.744,23.945-12.214,35.419-16.647,17.8-6.88,26.274-4.991,57.035-3.638,36.8,1.621,55.811-23.054,70.376-30.739s31.952-3.22,31.952-3.22c-12.536-12.139-36-10.111-36-10.111,13.953-9.531,27.466-10.915,38.639-9.123h0a54.609,54.609,0,0,1,26.489,12.74v.408A92.433,92.433,0,0,1,528.238,414.3a61.694,61.694,0,0,0-22.249-5.388Z" transform="translate(-202.901 -251.376)"/>
+ </g>
+ <path id="_Compound_Path_3" data-name="&lt;Compound Path&gt;" class="cls-3" d="M354,374.828a19.148,19.148,0,1,0,19.148-19.148A19.148,19.148,0,0,0,354,374.828Zm30.149,1a11.066,11.066,0,1,1-4.186-9.66l-6.826,8.683Z" transform="translate(-191.826 -243.731)"/>
+ <path id="_Path_11" data-name="&lt;Path&gt;" d="M372.606,363.22a11.055,11.055,0,1,0,11,12.053l-11-1,6.826-8.683a10.98,10.98,0,0,0-6.826-2.372Z" transform="translate(-191.273 -243.178)"/>
+ <path id="_Compound_Path_4" data-name="&lt;Compound Path&gt;" class="cls-3" d="M349,369.162a24.482,24.482,0,1,0,24.482-24.482A24.482,24.482,0,0,0,349,369.162Zm38.639,1.277a14.146,14.146,0,1,1-5.367-12.386l-8.726,11.109Z" transform="translate(-192.192 -244.537)"/>
+ <path id="_Path_12" data-name="&lt;Path&gt;" d="M372.813,354.32a14.135,14.135,0,1,0,14.114,15.412l-14.071-1.277,8.7-11.109a14.081,14.081,0,0,0-8.747-3.027Z" transform="translate(-191.48 -243.831)"/>
+ </g>
+ </g>
+</svg>
diff --git a/src/skin/images/twitter.svg b/src/skin/images/twitter.svg
new file mode 100644
index 0000000..493b77e
--- /dev/null
+++ b/src/skin/images/twitter.svg
@@ -0,0 +1,19 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="620 -1124 61.5 61.5">
+ <defs>
+ <style>
+ .cls-1 {
+ fill: #f06a0a;
+ }
+
+ .cls-2 {
+ fill: #fff;
+ }
+ </style>
+ </defs>
+ <g id="twitter" transform="translate(296 -1877)">
+ <g id="XMLID_48_" transform="translate(324 753)">
+ <path id="XMLID_49_" class="cls-1" d="M0,3.2V64.7H61.5V3.2Z" transform="translate(0 -3.2)"/>
+ </g>
+ <path id="XMLID_2_" class="cls-2" d="M50.067,29.421v1.07c0,10.291-7.9,22.229-22.229,22.229A21.808,21.808,0,0,1,15.9,49.263a13.955,13.955,0,0,0,1.894.082,15.463,15.463,0,0,0,9.715-3.375,7.71,7.71,0,0,1-7.245-5.434,8.157,8.157,0,0,0,1.482.165,5.684,5.684,0,0,0,2.058-.329,7.856,7.856,0,0,1-6.257-7.657v-.082a7.36,7.36,0,0,0,3.54.988,8.03,8.03,0,0,1-3.458-6.586,8.359,8.359,0,0,1,1.07-3.952,21.945,21.945,0,0,0,16.137,8.151,6.42,6.42,0,0,1-.247-1.811,7.805,7.805,0,0,1,13.5-5.351,17.075,17.075,0,0,0,4.94-1.894,7.731,7.731,0,0,1-3.376,4.281A15.417,15.417,0,0,0,54.1,25.222,15.138,15.138,0,0,1,50.067,29.421Z" transform="translate(321.19 746.548)"/>
+ </g>
+</svg>
diff --git a/src/skin/js/firstRun.js b/src/skin/js/firstRun.js
new file mode 100644
index 0000000..a21b24c
--- /dev/null
+++ b/src/skin/js/firstRun.js
@@ -0,0 +1,25 @@
+(function($) {
+
+$(window).on("load", function () {
+
+ function setSeenComic() {
+ var badger = chrome.extension.getBackgroundPage().badger;
+ var settings = badger.getSettings();
+ settings.setItem("seenComic", true);
+ }
+
+ $(".scroll-it").smoothScroll();
+
+ var alreadySet = false;
+ $(window).scroll(function () {
+ if (!alreadySet) {
+ if ($(window).scrollTop() > 400) {
+ alreadySet = true;
+ setSeenComic();
+ }
+ }
+ });
+});
+
+
+}(jQuery));
diff --git a/src/skin/options-layout.css b/src/skin/options-layout.css
new file mode 100644
index 0000000..0776e6f
--- /dev/null
+++ b/src/skin/options-layout.css
@@ -0,0 +1,260 @@
+body {
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 13px;
+ line-height: 1.6;
+ width: 100%;
+}
+
+body.options a:not(.ui-tabs-anchor):not(.honeybadgerPowered):not(.removeOrigin) {
+ text-decoration: underline;
+}
+body.options a:hover:not(.ui-tabs-anchor):not(.honeybadgerPowered):not(.removeOrigin),
+body.options a:focus:not(.ui-tabs-anchor):not(.honeybadgerPowered):not(.removeOrigin) {
+ color: #f06a0a;
+}
+
+h1 {
+ font-size: 20px;
+ font-weight: bold;
+ margin: 10px 8px;
+}
+
+h3 {
+ margin: 10px 0;
+}
+
+h4 {
+ display: flex;
+ flex-direction: row;
+ margin: 30px 0 15px 0;
+}
+h4:after {
+ content: "";
+ flex: 1 1;
+ border-bottom: 1px solid #d3d3d3;
+ margin: auto;
+ margin-inline-start: 10px;
+}
+
+div.checkbox {
+ max-width: 600px;
+ white-space: nowrap;
+}
+
+div.checkbox span[class^=i18n_] {
+ white-space: normal;
+ white-space: break-spaces;
+}
+
+div.checkbox + div.checkbox, div#learning-setting-divs div:first-child, div#learning-setting-divs + div.checkbox {
+ margin-top: 5px;
+}
+
+input[type=checkbox] {
+ flex: none;
+ margin-inline-end: 0.8em;
+}
+
+div.checkbox .ui-icon {
+ margin-inline-start: 0.2em;
+ font-size: 1.2em;
+}
+
+div.checkbox .ui-icon-alert {
+ color: #cc0000;
+}
+
+td
+{
+ font-size: 13px;
+ vertical-align: top;
+ text-align: left;
+}
+
+button
+{
+ white-space: pre;
+}
+
+label {
+ cursor: pointer;
+ display: inline-flex;
+ align-items: center;
+}
+#tracking-domains-filters label {
+ display: inline;
+}
+
+p, #settingsForm {
+ margin: 10px 0;
+}
+
+#allowlist-form {
+ margin: 20px 0 0;
+}
+
+#pbInstructions {
+ margin-bottom: 20px;
+}
+
+#tab-manage-data {
+ overflow: auto;
+}
+
+.btn-silo {
+ float: left;
+ clear: both;
+ margin-bottom: 20px;
+ max-width: 700px;
+ width: 100%;
+}
+
+.btn-silo + .btn-silo {
+ border-top: 1px solid #d3d3d3;
+ margin-top: 10px;
+ padding-top: 10px;
+}
+
+.btn-silo div {
+ max-width: 350px;
+ width: 100%;
+ float: left;
+}
+
+.btn-danger {
+ color: #e02431;
+ border-width: 1px;
+ border-color: #e02431;
+}
+
+.btn-danger:hover {
+ color: white;
+ background: #e02431;
+}
+
+.importInput{
+ visibility: hidden;
+ height: 0;
+ width: 0;
+}
+
+#tracking-domains-loader {
+ position: absolute;
+ width: 95%;
+ height: 60vh;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+#tracking-domains-loader .spinner {
+ border: 0.5em solid #222;
+ border-bottom-color: #fff;
+ height: 5em;
+ width: 5em;
+ border-radius: 5em;
+ animation: spin 1s infinite linear;
+}
+@keyframes spin {
+ 0% {
+ transform: rotate(0);
+ }
+ 100% {
+ transform: rotate(359deg);
+ }
+}
+
+#blockedResources {
+ width: 390px;
+}
+
+#tracking-domains-filters {
+ color: #505050;
+ font-size: 14px;
+ list-style-type: none;
+ padding: 10px;
+ border: 1px solid #d3d3d3;
+}
+
+#tracking-domains-filters li {
+ margin: 10px 0;
+
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+}
+
+#tracking-domains-filters > li > label {
+ flex: 1 0 150px; /* at least this wide */
+ max-width: 300px; /* at most this wide */
+}
+
+#tracking-domains-filters > li > label + * {
+ flex: 1 0 300px; /* at least this wide or wrap */
+ max-width: 300px;
+}
+
+#tracking-domains-filters > li > label + input[type=checkbox] {
+ flex: none;
+}
+
+.clickerContainer {
+ max-height: 400px; /* override popup.css */
+}
+
+#hide-widgets-row {
+ width: 100%;
+ margin-top: 5px;
+}
+
+#hide-widgets-select {
+ width: 300px;
+}
+
+#tabs, header {
+ background: transparent;
+ border: none;
+ max-width: 800px;
+ margin: 0 auto;
+ padding: 0;
+}
+#tabs .ui-widget-header {
+ background: transparent;
+ border: none;
+ border-bottom: 1px solid #d3d3d3;
+ border-radius: 0px;
+ padding: 0;
+}
+#tabs .ui-tabs-nav .ui-state-default {
+ background: transparent;
+ border: none;
+ border-radius: 0px;
+ margin: 0;
+ padding: 0;
+}
+#tabs .ui-tabs-nav .ui-state-hover {
+ box-shadow: inset 0 -3px 0 0 #ccc;
+}
+#tabs .ui-tabs-nav .ui-state-active {
+ box-shadow: inset 0 -3px 0 0 #f06a0a;
+}
+#tabs .ui-tabs-nav li a.ui-tabs-anchor {
+ padding: 1em;
+}
+#tabs .ui-tabs-nav .ui-state-hover a,
+#tabs .ui-tabs-nav .ui-state-active a {
+ color: #000;
+}
+#tabs .ui-tabs-nav li a:focus {
+ outline: none;
+}
+
+.indent1 {
+ margin-inline-start: 25px;
+}
+
+@media screen and (max-width: 500px){
+ .ui-tabs .ui-tabs-panel {
+ padding: 0.5em 0;
+ }
+}
diff --git a/src/skin/options.html b/src/skin/options.html
new file mode 100644
index 0000000..428d0fb
--- /dev/null
+++ b/src/skin/options.html
@@ -0,0 +1,307 @@
+<!DOCTYPE html>
+
+<!--
+ - This file is part of Adblock Plus <http://adblockplus.org/>,
+ - Copyright (C) 2006-2013 Eyeo GmbH
+ -
+ - Adblock Plus 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.
+ -
+ - Adblock Plus 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 Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
+ -->
+
+<html style="visibility:hidden; overflow:hidden">
+<head>
+<meta name="google" content="notranslate">
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<link type="text/css" href="/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.structure.css" rel="stylesheet" />
+<link type="text/css" href="/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.theme.css" rel="stylesheet" />
+<link type="text/css" href="/lib/vendor/jquery-ui-iconfont-2.3.2/jquery-ui-1.12.icon-font.css" rel="stylesheet" />
+<link type="text/css" href="/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.css" rel="stylesheet" />
+<link type="text/css" href="/lib/vendor/select2-4.0.11/select2-4.0.11.css" rel="stylesheet" />
+<link type="text/css" media="screen" href="/lib/vendor/toggle-switch.css" rel="stylesheet" />
+<link type="text/css" media="screen" href="/skin/popup.css" rel="stylesheet" />
+<link type="text/css" media="screen" href="/skin/options-layout.css" rel="stylesheet" />
+
+<script type="text/javascript" src="/lib/vendor/jquery-3.5.1.js"></script>
+<script type="text/javascript" src="/lib/vendor/jquery-ui-1.12.1.custom/jquery-ui.js"></script>
+<script type="text/javascript" src="/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.js"></script>
+<script type="text/javascript" src="/lib/vendor/underscore-1.9.1.js"></script>
+<script type="text/javascript" src="/lib/vendor/select2-4.0.11/select2-4.0.11.js"></script>
+
+<!-- required because of window.getBaseDomain() in htmlutils.js -->
+<script type="text/javascript" src="/lib/vendor/punycode-1.4.1.js"></script>
+<script type="text/javascript" src="/lib/publicSuffixList.js"></script>
+<script type="text/javascript" src="/lib/basedomain.js"></script>
+
+<script type="text/javascript" src="/lib/i18n.js" charset="utf-8"></script>
+<script type="text/javascript" src="/js/bootstrap.js"></script>
+<script type="text/javascript" src="/js/constants.js"></script>
+<script type="text/javascript" src="/js/utils.js"></script>
+<script type="text/javascript" src="/js/htmlutils.js"></script>
+<script type="text/javascript" src="/lib/options.js"></script>
+<script type="text/javascript" src="/js/options.js" charset="utf-8"></script>
+
+<title class="i18n_options_title"></title>
+</head>
+<body class="options">
+<header>
+ <table>
+ <tr>
+ <td style="vertical-align:middle;">
+ <img src="/icons/badger-48.png" srcset="/icons/badger-128.png 2x" width="48" alt="">
+ </td>
+ <td>
+ <h1><span class="i18n_options_title"></span></h1>
+ </td>
+ </tr>
+ </table>
+</header>
+
+<div id="tabs">
+ <ul>
+ <li><a href="#tab-general-settings"><span class="i18n_options_general_settings"></span></a></li>
+ <li><a href="#tab-allowlist"><span class="i18n_whitelisted_domains"></span></a></li>
+ <li><a href="#tab-manage-widgets"><span class="i18n_options_widget_replacement_tab"></span></a></li>
+ <li><a href="#tab-tracking-domains"><span class="i18n_options_domain_list_tab"></span></a></li>
+ <li><a href="#tab-manage-data"><span class="i18n_data_settings"></span></a></li>
+ </ul>
+
+ <div id="tab-tracking-domains">
+ <div id="tracking-domains-overlay">
+ <p class="i18n_description"></p>
+ <p class="i18n_intro_not_an_adblocker_paragraph"></p>
+ <p class="i18n_show_tracking_domains_message"></p>
+ <p>
+ <label>
+ <input type="checkbox" id="show-tracking-domains-checkbox">
+ <span class="i18n_show_tracking_domains_acknowledgement"></span>
+ </label>
+ </p>
+ </div>
+ <div id="blockedResourcesContainer">
+ <p id="pbInstructions">
+ <span id="options_domain_list_trackers"></span>
+ <span id="options_domain_list_no_trackers" class="i18n_options_domain_list_no_trackers" style="display:none"></span>
+ </p>
+ <div id="tracking-domains-loader" style="display:none">
+ <div class="spinner"></div>
+ </div>
+ <div id="tracking-domains-div">
+ <ul id="tracking-domains-filters">
+ <li>
+ <label for="trackingDomainSearch">
+ <span class="i18n_options_domain_search"></span>
+ <span class="ui-icon ui-icon-info tooltip" title="i18n_options_domain_search_tooltip"></span>
+ </label>
+ <input id="trackingDomainSearch" type="text" value="" autocomplete="off">
+ </li>
+ <li>
+ <label for="tracking-domains-type-filter">
+ <span class="i18n_options_domain_type_filter"></span>
+ </label>
+ <select id="tracking-domains-type-filter">
+ <option value="" class="i18n_options_domain_filter_all"></option>
+ <option value="user" class="i18n_options_domain_filter_user"></option>
+ <option value="dnt" class="i18n_options_domain_filter_dnt"></option>
+ </select>
+ </li>
+ <li>
+ <label for="tracking-domains-status-filter">
+ <span class="i18n_options_domain_status_filter"></span>
+ </label>
+ <select id="tracking-domains-status-filter">
+ <option value="" class="i18n_options_domain_filter_all"></option>
+ <option value="block" class="i18n_options_domain_filter_block"></option>
+ <option value="cookieblock" class="i18n_options_domain_filter_cookieblock"></option>
+ <option value="allow" class="i18n_options_domain_filter_allow"></option>
+ </select>
+ </li>
+ <li id="not-yet-blocked-filter" style="display:none">
+ <label for="tracking-domains-show-not-yet-blocked">
+ <span class="i18n_options_show_not_yet_blocked"></span>
+ <span class="ui-icon ui-icon-info tooltip" title="i18n_intro_not_an_adblocker_paragraph"></span>
+ </label>
+ <input type="checkbox" id="tracking-domains-show-not-yet-blocked">
+ </li>
+ </ul>
+ <div id="blockedResources"></div>
+ </div>
+ </div>
+ </div>
+
+ <div id="tab-allowlist">
+ <div class="i18n_disabled_for_these_domains"></div>
+
+ <form id="allowlist-form" action="#">
+ <div>
+ <div>
+ <div style="float: left; max-width: 400px; width: 100%; margin-inline-end: 30px; padding-top: 5px">
+ <input type="text" value="" id="new-disabled-site-input" style="width:100%" placeholder="i18n_whitelist_form_domain_input_placeholder" autocomplete="off">
+ </div>
+ <div style="float: left; padding: 5px 0 10px">
+ <button id="add-disabled-site" type="submit"><span class="i18n_add_domain_button"></span></button>
+ </div>
+ </div>
+ <div style="clear: both; overflow: hidden">
+ <div style="float: left; max-width: 420px; width: 100%; margin-inline-end: 10px; padding-top: 5px">
+ <select id="allowlist-select" size="10" multiple style="width: 100%; background: white;"></select>
+ </div>
+ <div style="float: left; padding-top: 5px">
+ <button id="remove-disabled-site"><span class="i18n_remove_button"></span></button>
+ </div>
+ </div>
+ </div>
+ </form>
+ </div>
+
+ <div id="tab-general-settings">
+ <form id="settingsForm" action="#">
+
+ <div class="checkbox">
+ <label>
+ <input type="checkbox" id="show_counter_checkbox">
+ <span class="i18n_show_counter_checkbox"></span>
+ </label>
+ </div>
+ <div class="checkbox">
+ <label>
+ <input type="checkbox" id="enable_dnt_checkbox">
+ <span class="i18n_options_enable_dnt_checkbox"></span>
+ </label>
+ </div>
+ <div class="checkbox indent1">
+ <label>
+ <input type="checkbox" id="check_dnt_policy_checkbox">
+ <span class="i18n_options_dnt_policy_setting"></span>
+ </label>
+ </div>
+
+ <h4 id="privacy-settings-header" class="i18n_options_privacy_settings" style="display:none"></h4>
+
+ <div class="checkbox" id="disable-hyperlink-auditing" style="display:none">
+ <label>
+ <input type="checkbox" id="disable-hyperlink-auditing-checkbox">
+ <span>
+ <span class="i18n_options_disable_hyperlink_auditing"></span>
+ <a href="https://www.bleepingcomputer.com/news/software/major-browsers-to-prevent-disabling-of-click-tracking-privacy-risk/" target="_blank"><span class="ui-icon ui-icon-circle-b-help"></span></a>
+ </span>
+ </label>
+ </div>
+ <div class="checkbox" id="disable-google-nav-error-service" style="display:none">
+ <label>
+ <input type="checkbox" id="disable-google-nav-error-service-checkbox">
+ <span>
+ <span class="i18n_options_disable_google_nav_error_service"></span>
+ <a href="https://www.google.com/chrome/privacy/#how-chrome-handles-your-information" target="_blank"><span class="ui-icon ui-icon-circle-b-help"></span></a>
+ </span>
+ </label>
+ </div>
+
+ <h4 class="i18n_options_advanced_settings"></h4>
+
+ <div class="checkbox">
+ <label>
+ <input type="checkbox" id="local-learning-checkbox">
+ <span>
+ <span class="i18n_options_learn_setting"></span>
+ <span class="ui-icon ui-icon-alert tooltip" title="i18n_local_learning_warning"></span>
+ <a href="https://www.eff.org/badger-evolution" target="_blank"><span class="ui-icon ui-icon-circle-b-help"></span></a>
+ </span>
+ </label>
+ </div>
+ <div id="learning-setting-divs" style="display:none">
+ <div class="checkbox indent1">
+ <label>
+ <input type="checkbox" id="show-nontracking-domains-checkbox" disabled>
+ <span class="i18n_options_show_nontracking_domains_checkbox"></span>
+ </label>
+ </div>
+ <div class="checkbox indent1">
+ <label>
+ <input type="checkbox" id="learn-in-incognito-checkbox" disabled>
+ <span>
+ <span class="i18n_options_incognito_setting"></span>
+ <span class="ui-icon ui-icon-alert tooltip" title="i18n_options_incognito_warning"></span>
+ </span>
+ </label>
+ </div>
+ </div>
+ <div class="checkbox" id="webRTCToggle" style="display:none">
+ <label>
+ <input type="checkbox" id="toggle_webrtc_mode">
+ <span>
+ <span class="i18n_options_webrtc_setting"></span>
+ <span class="ui-icon ui-icon-alert tooltip" title="i18n_options_webrtc_warning"></span>
+ </span>
+ </label>
+ </div>
+
+ </form>
+ </div>
+
+ <div id="tab-manage-widgets">
+ <p><span class="i18n_options_widget_replacement_desc"></span></p>
+ <p>
+ <label>
+ <input type="checkbox" id="replace-widgets-checkbox">
+ <span class="i18n_options_social_widgets_checkbox"></span>
+ </label>
+ </p>
+ <div id="hide-widgets-row" class="indent1">
+ <label for="hide-widgets-select">
+ <span class="i18n_options_hide_social_widgets"></span>
+ </label>
+ <select name="states[]" multiple="multiple" id="hide-widgets-select"></select>
+ </div>
+ </div>
+
+ <div id="tab-manage-data">
+ <div class="btn-silo">
+ <p class="i18n_manage_data_intro"></p>
+ <div id="export">
+ <h3><span class="i18n_export_user_data"></span></h3>
+ <button id="exportTrackers"><span class="i18n_download"></span></button>
+ </div>
+ <div id="import">
+ <h3><span class="i18n_import_user_data"></span></h3>
+ <input type="file" class="importInput" id="importTrackers" accept=".json">
+ <button id="importTrackerButton" class="importButton" type="submit"><span class="i18n_import"></span></button>
+ </div>
+ </div>
+ <div class="btn-silo">
+ <p class="i18n_sync_intro"></p>
+ <div id="upload">
+ <h3><span class="i18n_upload_cloud"></span></h3>
+ <button id="cloud-upload"><span class="i18n_upload"></span></button>
+ </div>
+ <div id="download">
+ <h3><span class="i18n_download_cloud"></span></h3>
+ <button id="cloud-download"><span class="i18n_download"></span></button>
+ </div>
+ </div>
+ <div class="btn-silo">
+ <div id="reset">
+ <h3><span class="i18n_reset_data"></span></h3>
+ <button id="resetData" class="btn-danger"><span class="i18n_reset"></span></button>
+ </div>
+ <div id="remove">
+ <h3><span class="i18n_remove_all_data"></span></h3>
+ <button id="removeAllData" class="btn-danger"><span class="i18n_remove_all"></span></button>
+ </div>
+ </div>
+ </div>
+
+
+</div>
+
+</body>
+</html>
diff --git a/src/skin/popup.css b/src/skin/popup.css
new file mode 100644
index 0000000..24d8832
--- /dev/null
+++ b/src/skin/popup.css
@@ -0,0 +1,488 @@
+/*
+ * This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ * Copyright (C) 2014 Electronic Frontier Foundation
+ *
+ * Privacy Badger 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.
+ *
+ * Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ */
+ /*adjoining-classes:ignore*/
+ /*csslint ids:ignore*/
+
+body {
+ box-sizing: border-box;
+
+ background: #fefefe;
+ color: #333;
+ font-family: helvetica, arial, sans-serif;
+ font-size: 12px;
+
+ margin: 0;
+ padding: 7px 12px;
+
+ min-width: 430px; /* Chrome */
+ max-width: 100%; /* FF android */
+ min-height: 270px;
+}
+@media screen and (min--moz-device-pixel-ratio:0) {
+ body {
+ min-width: 200px; /* FF android */
+ width: 430px; /* FF desktop */
+ }
+}
+
+@font-face {
+ font-family: "Chunk-Five";
+ src: url("./fonts/Chunk.ttf");
+}
+
+a { text-decoration: none }
+
+a:hover { color: #ec9329 }
+
+.spacer {
+ height: 7px;
+ width: 5px;
+ display: block;
+ clear: both;
+}
+.clear {
+ clear: both;
+}
+
+.clicker {
+ border-top: 1px solid #aaaaaa;
+ padding: 5px;
+ height: 40px;
+ overflow: hidden;
+ line-height: normal;
+}
+.clicker:not(#not-yet-blocked-header):not(#non-trackers-header) {
+ direction: ltr;
+}
+.origin{
+ max-width: 210px;
+ color: #555555;
+ float: left;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.switch-container {
+ width: 115px;
+ display: block;
+ margin-left: 220px;
+}
+.switch-toggle {
+ background-color: #515050;
+ height: 16px;
+}
+.switch-toggle > label {
+ cursor: pointer;
+}
+.options .switch-container {
+ max-width: 114px;
+}
+
+.switch-candy:hover {
+ background-color: #868686;
+}
+.block .switch-candy a {
+ background-color: #c61223;
+}
+.cookieblock .switch-candy a {
+ background-color: #ffcc00;
+}
+.allow .switch-candy a, .noaction .switch-candy a {
+ background-color: #339900;
+}
+
+.honeybadgerPowered {
+ display: none;
+ margin-right: 10px;
+ width: 20px;
+ height: 20px;
+ position: relative;
+ left: 340px;
+ bottom: 15px;
+}
+.userset .honeybadgerPowered {
+ display: block;
+ background: url('/icons/badger-pin.png') no-repeat;
+}
+
+.removeOrigin {
+ float: right;
+ margin-right: 0;
+ width: 10px;
+}
+.removeOrigin:hover {
+ color: red;
+}
+
+#blockedResources .breakage-warning {
+ color: red;
+ display: none;
+ font-size: 1.3em;
+ margin: 0 2px 2px 0;
+}
+#blockedResources .show-breakage-warning .breakage-warning {
+ display: inline-block;
+}
+
+#privacyBadgerHeader{
+color: #505050;
+font-size: 16px;
+}
+
+#title {
+ padding-top: 4px;
+}
+
+#header-image-stack {
+ display: table;
+ float: left;
+ margin: 2px 10px 0 10px;
+ line-height: 1.0;
+}
+
+#privacyBadgerHeader h2{
+ display: table-row;
+ color: #000;
+ font-size: 24px;
+ font-weight: normal;
+ clear: initial;
+ font-family: "Chunk-Five", serif;
+ margin-top: 5px;
+}
+
+#privacyBadgerHeader img {
+ float: left;
+}
+
+#blockedResourcesContainer {
+ min-height: 70px;
+}
+
+#intro-reminder-btn, #critical-error-link, #learning-prompt-btn {
+ background-color: #ff641c;
+ border: 2px solid #ff641c;
+ color: #fff;
+ font-weight: bold;
+ font-size: 17px;
+ line-height: 1.5;
+ padding: 1.2em 1em;
+ transition: background-color 0.3s ease;
+ width: 100%;
+}
+
+#critical-error-link {
+ border-radius: 3px;
+}
+
+#intro-reminder-btn:hover, #critical-error-link:hover, #learning-prompt-btn:hover {
+ background-color: #f58728;
+}
+.clickerContainer {
+ max-height: 290px;
+ overflow-y: auto;
+ background-color: #E8E9EA;
+ position: relative;
+ margin-top: 25px;
+}
+.keyContainer{
+ direction: ltr;
+ position: relative;
+}
+.key {
+ position: absolute;
+ height: 25px;
+ left: 215px;
+ right: 0;
+ z-index: 30;
+ background: #fefefe;
+ padding-top: 4px;
+ width: 117px;
+}
+.key img {
+ margin-left: 19px;
+}
+
+.flex-wrapper {
+ display: flex;
+ align-items: center;
+}
+
+#instruction-outer {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 99;
+ background-color: #000;
+ opacity: 0.1;
+ width: 100%;
+ height: 100%;
+}
+#instruction {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ z-index: 100;
+ background-color: #fff;
+ color: #333;
+ text-align: start;
+ margin: 8px;
+ padding: 15px;
+ font-size: 15px;
+ box-shadow:
+ 0 2.8px 2.2px rgba(0, 0, 0, 0.034),
+ 0 6.7px 5.3px rgba(0, 0, 0, 0.048),
+ 0 12.5px 10px rgba(0, 0, 0, 0.06),
+ 0 22.3px 17.9px rgba(0, 0, 0, 0.072),
+ 0 41.8px 33.4px rgba(0, 0, 0, 0.086),
+ 0 100px 80px rgba(0, 0, 0, 0.12);
+ border-radius: 4px;
+ width: calc(100% - 46px);
+}
+.instruction-logo {
+ align-self: center;
+ flex-shrink: 0;
+ padding-inline-end: 15px;
+}
+#instruction .flex-wrapper > div {
+ padding-inline-end: 5px;
+}
+#intro-reminder-btn, #error-message, #learning-prompt-btn {
+ margin-top: 1em;
+}
+#error-message {
+ text-align: center;
+}
+#fittslaw {
+ float: right;
+}
+#options, #share, #help {
+ float: right;
+ margin-top: 7px;
+}
+#share {
+ margin-left: 10px;
+ margin-right: 12px;
+}
+#options {
+ margin-inline-end: 3px;
+}
+#pbInstructions, #special-browser-page, #disabled-site-message {
+ color: #505050;
+ font-size: 16px;
+ margin: 0;
+ padding-top: 10px;
+}
+#pbInstructions :not(#options_domain_list_trackers):not(#options_domain_list_no_trackers) a {
+ text-decoration: underline;
+ color: black;
+ font-weight: bold;
+}
+#pbInstructions :not(#options_domain_list_trackers):not(#options_domain_list_no_trackers) a:hover {
+ color: #ec9329
+}
+#instructions-no-trackers, #special-browser-page, #disabled-site-message {
+ text-align: center;
+ margin: 45px 0;
+ padding: 0;
+}
+#instructions-many-trackers {
+ text-align: center;
+ margin: 10px 0;
+}
+#instructions-many-trackers, #instructions-no-trackers, #no-third-parties {
+ display: block;
+}
+#no-third-parties {
+ font-size: 12px;
+}
+
+#siteControls, #report-controls {
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ margin-top: 5px;
+ text-align: center;
+}
+button {
+ color: #333;
+}
+.pbButton {
+ background-color: #fefefe;
+ border: 2px solid;
+ border-radius: 3px;
+ cursor: pointer;
+ font-family: 'Lucida Grande', 'Segoe UI', Tahoma, 'DejaVu Sans', Arial, sans-serif;
+ font-size: 12px;
+ font-weight: bold;
+ line-height: 16px;
+ margin-top: 8px;
+ padding: 10px;
+ text-align: center;
+ width: 49%;
+}
+.pbButton:hover:enabled {
+ border: 2px solid #F06A0A;
+}
+.pbButton:disabled {
+ background-color: #ccc;
+ color: #666;
+ cursor: auto;
+}
+#donate {
+ width: 100%;
+}
+
+#not-yet-blocked-header, #non-trackers-header {
+ text-align: center;
+ color: #f9f9f9;
+ background: #555;
+ height: auto;
+ font-size: 14px;
+ font-weight: bold;
+}
+.overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ display: block;
+ font-size: 0.8em;
+ z-index: -1;
+ opacity: 0;
+ padding: 3%;
+ box-sizing: border-box;
+ color: #ccc;
+ background: url("/skin/background.png");
+ transition: opacity .1s ease;
+ overflow-y: auto;
+}
+div.overlay.active {
+ z-index: 31;
+ opacity: 1;
+}
+#error_input {
+ display: block;
+ width: 98%;
+}
+.overlay_title {
+ display: inline-block;
+ padding: 0;
+ margin: 0 0 10px;
+}
+#report_label {
+ display: block;
+ margin: 1% 0;
+ font-weight: bold;
+}
+#report-success, #report-fail {
+ font-size: 12px;
+ font-weight: bold;
+ margin: 10px 0;
+}
+#report-success {
+ color: green;
+}
+#report-fail {
+ color: red;
+}
+#report-terms {
+ margin: 10px 0 !important;
+}
+.overlay_close {
+ display: inline-block;
+ float: right;
+ background: none;
+ border: 0;
+ font-size: 1.4em;
+ color: #ccc;
+}
+.overlay_close:before {
+ content: '\2716';
+ margin: 4px;
+}
+#share_output {
+ display: block;
+ width: 98%;
+ height: 60%;
+}
+#dnt-compliant {
+ float: left;
+ display: inline;
+ padding-right: 5px;
+}
+#overlay p {
+ font-size: 12px;
+ margin: 0 0 10px;
+}
+#overlay label {
+ font-size: 13px;
+}
+
+#version{
+ color: #707070;
+ font-size: 10px;
+ float: left;
+}
+.faded-bw-color-scheme {
+ filter: grayscale(1) opacity(0.6);
+}
+
+.tooltipster-sidetip .tooltipster-box {
+ color: #fcfcfc;
+ font-size: 13px;
+ background: #555;
+ border: none;
+ border-radius: 7px;
+}
+.tooltipster-sidetip .tooltipster-arrow-border {
+ border: none;
+}
+
+@media screen and (max-width: 400px){
+ .origin {
+ max-width: 150px;
+ }
+
+ .switch-container{
+ width: 100px;
+ display: block;
+ margin-left: 150px;
+ }
+
+ .key {
+ left: 150px;
+ }
+ .key img {
+ margin-left: 12px;
+ }
+
+ .honeybadgerPowered {
+ left: 255px;
+ }
+
+ #share {
+ margin-left: 6px;
+ margin-right: 8px;
+ }
+ #options {
+ margin-right: 0px;
+ }
+}
diff --git a/src/skin/popup.html b/src/skin/popup.html
new file mode 100644
index 0000000..c38fd60
--- /dev/null
+++ b/src/skin/popup.html
@@ -0,0 +1,155 @@
+<!DOCTYPE html>
+
+<!--
+ - This file was part of Adblock Plus <http://adblockplus.org/>,
+ - Copyright (C) 2006-2013 Eyeo GmbH
+
+ - Modified for Privacy Badger
+ - Copyright (C) 2013- Electronic Frontier Foundation & others
+
+ -
+ - Adblock Plus 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.
+ -
+ - Adblock Plus 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 Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
+ -->
+
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1.0">
+<link type="text/css" href="/lib/vendor/jquery-ui-iconfont-2.3.2/jquery-ui-1.12.icon-font.css" rel="stylesheet" />
+<link rel="stylesheet" type="text/css" href="/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.css" />
+<link type="text/css" media="screen" href="/lib/vendor/toggle-switch.css" rel="stylesheet" />
+<link type="text/css" media="screen" href="/skin/popup.css" rel="stylesheet" />
+
+<script type="text/javascript" src="/lib/vendor/jquery-3.5.1.js"></script>
+<script type="text/javascript" src="/lib/vendor/tooltipster-4.2.6/tooltipster.bundle.js"></script>
+<script type="text/javascript" src="/lib/vendor/underscore-1.9.1.js"></script>
+
+<!-- required because of window.getBaseDomain() in htmlutils.js -->
+<script type="text/javascript" src="/lib/vendor/punycode-1.4.1.js"></script>
+<script type="text/javascript" src="/lib/publicSuffixList.js"></script>
+<script type="text/javascript" src="/lib/basedomain.js"></script>
+
+<script type="text/javascript" src="/lib/i18n.js"></script>
+<script type="text/javascript" src="/js/bootstrap.js"></script>
+<script type="text/javascript" src="/js/constants.js"></script>
+<script type="text/javascript" src="/js/htmlutils.js"></script>
+<script type="text/javascript" src="/js/firefoxandroid.js"></script>
+<script type="text/javascript" src="/js/popup.js"></script>
+</head>
+<body id="main">
+ <div id="instruction-outer">
+ </div>
+ <div id="instruction">
+ <a href="" id="fittslaw"><svg width="26" height="22" fill="white">
+ <line x1="5" y1="5" x2="20" y2="20" style="stroke:rgb(22,22,22);stroke-width:3;fill:transparent"/>
+ <line x1="5" y1="20" x2="20" y2="5" style="stroke:rgb(22,22,22);stroke-width:3;fill:transparent"/>
+ </svg></a>
+
+ <div id="instruction-text">
+ <div class="flex-wrapper">
+ <img class="instruction-logo" src="/icons/badger-48.png" srcset="/icons/badger-128.png 2x" width="48" alt="">
+ <div>
+ <div class="i18n_intro_text1"></div>
+ <div class="i18n_intro_text2" style="margin-top:0.5em"></div>
+ </div>
+ </div>
+ <button id="intro-reminder-btn" class="i18n_first_run_text pbButton"></button>
+ </div>
+
+ <div id="error-text" style="display:none">
+ <div class="flex-wrapper">
+ <img class="instruction-logo" src="/icons/badger-48.png" srcset="/icons/badger-128.png 2x" width="48" alt="">
+ <div class="i18n_extension_error_text"></div>
+ </div>
+ <div style="color:#cc0000" id="error-message"></div>
+ </div>
+
+ <div id="learning-prompt-div" style="display:none">
+ <div class="flex-wrapper">
+ <img class="instruction-logo" src="/icons/badger-48.png" srcset="/icons/badger-128.png 2x" width="48" alt="">
+ <div>
+ <div class="i18n_learning_prompt_text1"></div>
+ <div class="i18n_learning_prompt_text2" style="margin-top:0.5em"></div>
+ </div>
+ </div>
+ <button id="learning-prompt-btn" class="i18n_learning_prompt_button pbButton"></button>
+ </div>
+
+ </div><!-- end of div#instruction -->
+
+ <div id="overlay" class="overlay">
+ <h1 id="report_title" class="i18n_report_title overlay_title"></h1>
+ <a href="" id="report_close" class="i18n_report_close overlay_close"></a>
+ <p id="report_text" class="i18n_report_text"></p>
+ <label id="report_label" for="error_input" class="i18n_report_input_label"></label>
+ <textarea id="error_input" name="error_input" maxlength="300" rows=3 placeholder="i18n_error_input"></textarea>
+ <div id="report-controls">
+ <button id="report-button" class="i18n_report_button pbButton"></button>
+ <button id="report-cancel" class="i18n_report_cancel pbButton"></button>
+ </div>
+ <div id="report-success" class="i18n_report_success" style="display:none"></div>
+ <div id="report-fail" class="i18n_report_fail" style="display:none"></div>
+ <p id="report-terms" class="i18n_report_terms"></p>
+ </div>
+ <div id="share_overlay" class="overlay">
+ <h1 id="share_title" class="i18n_share_title overlay_title"></h1>
+ <a href="" id="share_close" class="i18n_report_close overlay_close"></a>
+ <textarea id="share_output" name="share_output"></textarea>
+ <button id="copy-button" class="i18n_copy_button_initial pbButton"></button>
+ </div>
+
+<div id='privacyBadgerHeader'>
+ <a id="options" title="i18n_popup_options_button" href='/skin/options.html' class="tooltip" target="_blank"><img width="25" src="/icons/options.svg" alt="i18n_popup_options_button"></a>
+ <a id="share" href="" title="i18n_popup_share_button" class="tooltip" target="_blank"><img width="23" height="auto" src="/icons/share.svg" alt="i18n_popup_share_button"></a>
+ <a id="help" title="i18n_popup_help_button" href='https://privacybadger.org/#faq' class="tooltip" target="_blank"><img width="25" src="/icons/help.svg" alt="i18n_popup_help_button"></a>
+ <div id='title'>
+ <img src="../icons/badger-bw-noborder.svg" width="48" alt="" id="badger-header-logo">
+ <div id='header-image-stack'>
+ <a href="https://www.eff.org/" target="_blank"><img id='header-red-eff-logo' src="./images/EFF-red.svg" width="48" alt="" title="i18n_intro_by_eff" class="tooltip" data-tooltipster='{"distance":20,"maxWidth":180}'></a>
+ <h2 id="title-name"><span class="i18n_name"></span></h2>
+ </div>
+ </div>
+ <div class='clear'></div>
+</div>
+
+<div id="blockedResourcesContainer">
+ <p id="pbInstructions">
+ <span id="instructions-many-trackers"></span>
+ <span id="instructions-no-trackers" style="display:none">
+ <span class="i18n_popup_instructions_no_trackers" data-i18n_contents_placeholders="<a target='_blank' title='i18n_what_is_a_tracker' class='tooltip' href='https://privacybadger.org/#What-is-a-third-party-tracker'>"></span>
+ <span id="no-third-parties" class="i18n_popup_blocked" style="display:none"></span>
+ </span>
+ </p>
+ <div class="spacer"></div>
+ <div id="blockedResources"></div>
+</div>
+
+<div id="special-browser-page" style="display:none">
+ <p><b><span class="i18n_popup_special_page_header"></span></b></p>
+ <p><span class="i18n_popup_special_page_paragraph"></span></p>
+</div>
+
+<div id="disabled-site-message" style="display:none">
+ <p><b><span class="i18n_popup_disabled_site_header"></span></b></p>
+</div>
+
+<div id="siteControls">
+ <button id="deactivate_site_btn" class="i18n_popup_disable_for_site pbButton"></button>
+ <button id="activate_site_btn" class="i18n_popup_enable_for_site pbButton" style="display:none"></button>
+ <button id="error" class="i18n_report_broken_site pbButton"></button>
+ <button id="donate" class="pbButton" target="_blank"><span class="ui-icon ui-icon-heart" style="color:#ec1e1e"></span> <span class="i18n_donate_to_eff"></span></button>
+</div>
+<span id="version" class="i18n_version"></span>
+<div class='clear'></div>
+</body>
+</html>
diff --git a/src/skin/socialwidgets/AddThis.svg b/src/skin/socialwidgets/AddThis.svg
new file mode 100644
index 0000000..aae4796
--- /dev/null
+++ b/src/skin/socialwidgets/AddThis.svg
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="77.709106"
+ height="27.523844"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="AddThis.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3785">
+ <stop
+ style="stop-color:#fefefe;stop-opacity:1;"
+ offset="0"
+ id="stop3787" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3789" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3785"
+ id="linearGradient3791"
+ x1="39.280788"
+ y1="12.902368"
+ x2="39.280788"
+ y2="32.148937"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.66264012,0,0,1,0.37825171,0)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="5.6568542"
+ inkscape:cx="21.742285"
+ inkscape:cy="-12.594547"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="1344"
+ inkscape:window-height="1419"
+ inkscape:window-x="0"
+ inkscape:window-y="19"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-0.64200988,-12.505455)">
+ <rect
+ style="fill:url(#linearGradient3791);fill-opacity:1;stroke:#e2e2e2;stroke-width:0.95840281;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect2985"
+ width="68.890198"
+ height="19"
+ x="1.1212113"
+ y="12.984656"
+ ry="2.1487894"
+ rx="1.9737403" />
+ <image
+ y="24.247705"
+ x="62.569523"
+ id="image3002"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKoAAACqCAYAAAA9dtSCAAAABHNCSVQICAgIfAhkiAAAIABJREFU eJztnXl4E9Xex7+zJE2TbqQLBGiBIrQFikUWsSxWKSIoFMSFRa6yiYoXFMUFxKuooKIICq8ioiJC uQIioCDWAlcB2ZRVoBVQCrR0oXRvtpnz/pFm2mmWJmmWUefzPHkeOJmZnGS+PXPObzuAjIyMjIyM jIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjJehAt0BV+DLLhPjyqGAWR/orvx9YFVQTt0BOqLt X0IDdKA74Arm3W/JIvU2Zr3ld/2LIHmhcnmHCH92R6C78beEP7sDXN4hEuh+uAIb6A44g+fMxPTp yEB342+N+fv54DkzoRlW0lMAaQv12HqQ4hxRG7uxEMxvVQHq0V8frmsIzPe2FP5PinPAH1sfwB65 hmSFSmrLiHHFYFEbdVkP5peKAPXo7wHzSwW4vuEgbVVCG/fTUpDaMkIFR0h2VJXsHNX803sgtWWi NnZbcYB68/ei8e9Iastg/um9APXGNSQpVL44l3C/rhO1MYfKQefJK39vQOfpwRwqF7Vxv64DX5wr 2YWVJIVq/n4+QLj6BgMPJuta4Dr0N4TJugYY+PoGwll+d4kiOaFyOTsJn3dQ1MZmXQNVxTk4Q8YT qCoObKM/fj7vILicnZIcVSUlVGKqJebsN0RtVJERzIFyB2fINAfmQDmoIqOozZz9BoipVnJilZRQ uUOfgJRfFrWxO0oATnK/298Djlh+3waQ8svgDn0SoA45RjJC5csuE/P+D0VtdG4N6LPVAerRPwP6 bDXo3BpRm3n/h+DLLktqdJCMUG38+RyRzVF+gt1WLH5qSTAOQBJCtefPZ/aXgSoxOjhDxptQJUYw +8U2a6nFAQRcqDxnJo3NIlQVB3ZXaYB69M+E3VVqY1mxxgEEqEsiAi9UO/585rsSQM87OEPGJ+h5 y+/eACnFAQRUqKS2jHA/LRW1yf78wMH8UgHqstj7Z40DCFCXBAIqVNmfLz2kGgcQMKHa9ecfrZT9 +QGGztODOVopapNCHEDAhGrXn79dHk2lALO9WHJxAAERquzPlzZSjAPwu1Blf/5fA6nFAfhdqLI/ /y+CxOIA/CpU2Z//10JKcQB+Farsz//rIZU4AL8l93F5h4hp7XhRmxT8+SRKCT5BDb59MEgEC6gZ yxtmAqrMDPpiLegz1aAKDAHtZ6CwxgFwA1oIbdY4ACauj9+SAf0iVMJzxPhJhqgt0P58PlED8yCt KBuzMSRGCb6zGhgcCeqyHmx26T9ymsLuKgXfIwwkhBHazN/PB+E5QtGMX8TqF6FyRzOl489X0TCN bgm+W4ioOafYiFNXjSip5lBt5BGtYZAQo0SP1kFQMBRIWxVMD7UGc6gc7Nbif9biry4OoHE9AO5o pt+64HOhSik/n4SzME1qAxKjBAAUVXH48OcyfHigAqU1ZrvnaNUsxqaE4LnbtIgJYcD1CQeJUEDx ef4/SqyBrgfg88WUZPz5Klok0jW/VKDzW39iwa5ShyIFgNIaM5bvL0PKu3nIPmdZAfOd1TCNaeWX bkuJQMYB+FSoUvLnm4dGCSJd/ON1TN1YCL3J9alHaY0Zd626gk0nLeWE+G4h4PpF+KSvUiWQcQA+ ffRLxZ9PdEHg+oQDADadrMKcRoZsd5i8oRDdWimREK2EeXAk6OOV0nX9MhT4NkEgsSqQcBYIYUEU FCgTAUw8qCIjqGsmUJf1Ln8HZnsxuC4aIKhujPNTHIDPhMrl7CSmr54Qf1iA/PlcX4tITRzBC99d b9a19CYes7YV49tJbYAgGtzAFmC3ey58X8AnasD1DAOfoAEUrk0fqct6MGeqLSkpTha51jgA893R 9Z9XFwfAJAzx2VzVJ0IlplpiXDlM1EaVmgLmz+e7WFb4W09XI6/U8bRDq2YRomJRVGl0Oi3I/r0G 2edqMOgGNfgeYYBEhEp0QTDdE2PX5FZUxeF6LYdyPQ+1gkKYioEulIGizrpE2qpgbquCOU0Ldk8p mP9dd7hYZA6Ug0uNANEqhDZrHAClCPaJWH0iVLv+/MYeDj9BopSC/W+HAxvouPQU/GfxSnRO7gUA MBqNyFz2Gh59/nWHgs08WolBN6hBQhhwPcNAVXMgkQogiLY8ZhU0iJ3RjKrhAAMPqtxseeyWmy3B H838bbh+ETAPjQLqhFdUxeGLXyuQfa4GR68Y7S4YVQoa3WIjcHMrHg+khKJPrApQUDAPjgSXpIFi db79J2CdR9H0UGuhyddxAF5XP19x1WKOauAqpXNroPj0irc/yrX+xKlgeiwWAHDXJ1eQ/bvYdz1z TDqWZGbZPXfjijdw36Mv2H1Pq2ZxcU57YURqFhwBVWAAnW8AlacHfa4GVLljS4QIhoJ5dEtwPUIB AJUGHu/+eB2Lfypza7EIAEk6DVaM0loEC0tUm/KDSw6nAqaJbSwOESusCsppWaDDWnldV16/oHHz DHHqM0egXJIXMFcpn6gR/vJ7vJePMwXiUbWkqBCR0TEOz+/dMRJHLtj3oB2f1Q4J0UpRW6WBx/Va HhV6DjUmgsoGAcihQTTCVTRaBDOIaeDlsQdVZARzvNK5+5ahYPpXa0Esp64acM+aIqfTG1dYMDQK swZaXKbM0UqwX161exyJUsL4ZJwwigMAnTgUylHveV1XXn30S9GfT5WYhH/31DE4U1D/nkpBOxUp ADwweiSOLLL/SPuobs59ttiI/CoKf5TUujyKqRQ0YkKV6NmaRVKMEl1bBWFAh2BBwCTGYlWwum+Z Y5UWJ4l1dGMomMa0EkSafa4Goz8vcHsUtcecHSVo10KB0ckh4HqEgj5QZtek6M84AK9djPAcMX52 D0jh6fqLV3FQvvNnwFOfjXPjQUIYbDpZhfHrCkTvnTqyF1179nN47p6t63BbxniH77uDK4u1JJ0G t3dQYFiSBgM7BIunFgYezKFyMPvKwA2JEh733hRpw77mPNsOoUG001EVKhrGp9uL4gColl2gfPgr eDMOwGsGf+74BpFIAenk59OnLUb6EV00SNJpRO8tfdX+HJTjOOzI/Agr318kak/SaTAuPQVTMwa4 9NkqBY2pGQPww6bVKKrQ4+K1WtQaOeRfysMPm1Zj0exJGJeegjitZV54pqAay/eX4a5VV9BuwZ94 elsxTl2te/QH0eAGtIDx+Q4+FSlgcXCsqzPuc91DAJUDqdirB1B4GtzxDV7tj1cUb/XnN3SVUpf1 UC6/5I3LN5uGc6nsczW4a5V4YffT9i/Rf+h9AIDfftmHlW+/jDVb96C0xow4rQr9b0rEqHsfwOD7 piBcG4UdmR/hwSnTnbpe47QqPP3YQ5g4+w2EhrvmwbqY+xuyNq3G1m++QdbhHJH4esVr8VTfIIxO rg+mOXXVgDtW5jvtR3MY1EltsRcDUKzOdxo5ZpweKzKLUcERUE7LgqT2BTB9P5/oF3YSvbg4FSGA ZF6mYVFC3+bcriUAhJdWzZLP3plH0pJjhf+PS08hP2xaTXjOTBry2TvzROc2fsVpVWTlgtnEbBaf 5y5l14rJygWzSa94cV+TdBqydpyO5M2NJ3FaldO+NPx+49JTyPKXZ5CVC2aTOZMzbK5r76VS0MJv Zu4X4fT35eJUNhowfT9fOlE7fHEu0b+RKO7g/a0CLkybF0MRw+z2Qh8fvCnM5sb0iteSlQtmk6qq CrviWTR7klMxLJo9iRgMhmYJ1B5H/vcdGZeeYiMiR31p+Jo5Jp2UXSu2uSbP806/j/VV/HJHyz0d FtX0YHB/K7FY30gk3ooDaPYc1Zy9EDb+/J3S8NQIMBTMQyJFnpRH+oZDpbB8/bTkWOzeshaHz1/D lBfegkYTKjqdEIK5U0ZitoPV/7j0FJw8k4Nn3loFpVJp95jm0HPgEKzNOoqcE4cxLj0FAJqck2rV LHZvWYslmVkI10bZvE9RFJ55axWGpya51AfKhbUGs7PEth5A9kKXrt8UzRIql7OT8H/sFbWxP153 3VjtB0iUEsZH2womlKIqDlM2FGLg/11Ct9gI7N6yFrtP5CFtxDj75xOCaaNuxYJVW2zei9OqsPO/ K7E26yhax8X79HsAQOfkXlibdRQ//7AFveK1Do9L0mlw9MQph9+pIa2ibUVsRatmEWoNPjE0LVSq 3Az2R3EsBf/HXq/UA/BYqHbz80tNFh+xROATNTA+UT/Jzz5Xg/4f5GPjySosmj0JB3KLmryZ00bd ipVbfrJpn5oxAKcuFOCO+6f4pO/O6DtoBA7kFmHR7EnCU8FKkk6D/x05g7iOCU1ep7K8DDt/Ouzw /VvjGyyOLrnmRGD+dx1UqUnU5o16AB4b/KXkz7cH1zMM5lExFsM4R7BwVykW7CpFnFaFAz9m48a+ aU1eY+6UkTYi1apZrF6xBHc/ON1rfa2ursTh7G04ffQgcs+eRnFJCSprDHj1nf9z2E+GYfDMW6tw 2933455RIwVvVP8+NyFK17bJz6wsL8OIAd2derHu7V43BTLwoK+4mNwYgDgAh/AVV4l+UbJo4myc 2CbwC6a6l7lfhNCv4pc7kkGd1AQASUuOJUVX811awNhbaKQlx5IrF897ZYF05eJ5smj2JJKWHGt3 YbRo9iSXr1VRdp0MT00Szh2XnuJ0UbdtzTKSpNM4XUQl6TSk8rUbLAupUTFu3wPjxDbihdWiZMJX XPXvKGbcOkvcidduIHyUMuACbSzS3Oc6CDckLTnW4Wq+MRs+XGhz4+ZMzmi2yYnnebJtzTKRqOy9 0pJj3b622WwmUzMGCNcYnpok6u/Fc2fJ0rnTXDZL/fh4bP29DWfdvg98lJLo64QuDGZbZ3ksVLeN sXb9+T9dl0TwMNczTMiUzCszI31lAfJK9egVr8WeE3/arObt8cuPO9E/fZiwqvbGo57wHD5f8gre fHuxTVCMPY787zsk970Nl86fQcGfuTDU1uJ6cT7CWkRBHRqOFjGt0T6xu13rxItTRwkLv+GpSWgV HYW9h361+7lJOo3d9rXjdIJjgc26BsbDtHbzsChRHAAAKMavhSdxAG6dIGV/Pp+ogelBHcBQKKri 0P+DfOSV6qFS0Dj+y0Eh1tQZ14qLcFNiO2HelqTTYMO2nU5jAZrimy+W45X/vOQwAssejgTUmDit CvFtonFj1wSk3zUSt436FzSaUDw5djCWrv+hyfNX3tsSt3ZU47PD5fjwgCUreM3Ylhh0gyXQhc6t aV62rRfjANw62Hx0PTF/N0/Uxm4sDHgpcxLOwvhUOyCIRqWBx8AVV4UbvfzlGXj8P0ubuIJlNMro 3xXb9p8BYLGtfr3nV7s2SFc4f+Y4npoyVrieP1ApaAzunYBHHpuOzNUfY90Px5wePz01Au8Mt6SU mDgCvZkI5ig6twaKzIJmD0ANn3JW2DtfBdtjjG+ESmrLiPGjO0Fq6utmSsKfz1AwPtpWMEE1DI5O S47FruMXQVFNf823n50sGPTHpafg028PemS85zgO777wCOYt+czrgSLuEKdV2V3Rx2lV6BRJIzFa iWFJGmH0bIi3i2zYxAGoI6F85Du34gBcNk+Zf3pPJFJAGvX2zUMihR9hftY1UQT/ko8+d0mkB7K3 Yt6SzyzXmD4GL76/zqXzGpN78gjGjxzi1mPeVzQWaa94Lb4aG+EwYJsqNQE1HNhtxV5PZ2e3FQtZ FgBAaq65XQ/AJYO/lPLzG8LHqcClWiKTss/VYEGDSf/UjAEu2Uory8vwwP0PQG/i8dk78zBvWaZH Iv144bO4sefNkhCpPY5cKMXJq2JbKFVqAn2qyrIY/u9VKJdf8sk99UY9AJdGVEn68+tyhcBQqDTw eGxz/WivVbNYuHKjS5d5+qERKKo0YvMnizFy4lNud6O6uhKPjBzY5HxQCjyzvQxHZ1ge9cyhcrCb i/z22czOEtt6AG7EATQ5okrVn8/1DRcqn7z8/TXRo+7Jifc2mWICADsyP8KmrJ/xzfpPPRLp+TPH 0buT7i8hUsASlG2t9ML1CHMcDO0DmhsH4LSnxGyQpj9fRYNLswRlnLpqwPIG+3hq1SyefP2DJi9R WV6Gp5+ehW+3bsKge/7l9Fij0Tbna++ODejTq5dLZiQp8e6Buse/ggLXM8yvn+0wDsBsaFKsToXK HfxYkv58LjVCsM0918jR0DI8CCMGdEeX1iHYu8NxOsSSuY/hkzXr0HfQCKeftWfrOky862ZR2+rF L2FwxhifRdb7kiMXSoXUFuv83m/YqTBOyi+DO/hxk6c6FCpfcVWS9fZJCANzXSpv9rkamzz9MwXV 2HPyEnp07SSklzQmNycHw+5/uEmR7sj8CEPvnYDv9p8Cx1nm6K8+MRYPP/1qQE1PzeXTwxa7N9Eq wMc5LmTsCxzuC9BEHIBDoZr3SLPePjewhTAh/8/uWrvHaNUsFq3a5PAaHW+4AT0HDnH6OdlffY57 HnoMehOP0hozTh3+CU+OHYyXlktjE9vmsO1s/X0lsf4VKuBgX4A9zvcFsLvql2J+PgCQKKXIHOXI FPTmi085DWRmGOfFHw5kb8XdYyaKRs2x99ztdD46PDUJwybMQLt27dC6dWtUV1fjxIkT2LZtK3Zl 7ZTUCJxXqkdemRlxESz49sFg9pU1fZIXsVsP4LdtTusB2DRK2Z9vLSFj4gj6LC+wKxx3vFH2OH5g D24fNNjl+Wdyty548623MXToUIfH5Obk4KlZT2H79h0Oj/E31sATqtQE5aI//d8BN+MAbEZUqebn 84kaoSrIJ4cr7IpUq2axenOWxyLNz7uAEXcNdVmkw4YNxfp165pMh+6ckIBvv92OJ5+ciaVLvVOh OU6rwo2JHdAqOgrRURYLSHV1NS7kXcG5P/KatEbs/7MWo5NDLHlkDOX/BbK9fQGc1AMQCZXXVxKT ROrti1DRFuM+LDlPr2TZf+SvWPyqSykY9qiurkTGbb1drtuU3K2LjUg5jsOGL/+LAwcPIjExCRMm jBeF4i1ZshS///67xyNrr3gtHhg9EvdNmYV2nbs6PfZacRE2f/w21maux56TtvEY+RX1f4ykhSIg 0zq7+wL8uAS8vpLQqlDHo41U8/NNo2KE/ozqFmI32HdqxoBmBTQ3Tkdu6rV9+3bRNTLXrSUx0VGi Y7RqlnzwwQei4/Iv5bmc6mx9pSXHku3rVnj8/Y79vNsmWLtXvFYS99jVegDCql+y/vxEjais+eZT VTbH9IrXYtmXTcdfOuK1f49zy7uU3K2LaE66Y8cOTHxoAoqKxTZdVhOB0aPE+2vp2sZi2uPiStzO GJ6ahOnTH4dBX40D2VtRcNn9aLUb+6Zh677T+GHTaqF0UHVtvd+f7xu4vQjcjgMwrp8oVvZ8z1IQ vPniw1miryuAkDc3nmjVrM1oo1Wz5OK5sx6PNps/WezW6AaAzJw5Q3SN5G5dbI5RKWiyb98+u5+5 fft2tz+z8XdOS44ly1+e4XYOlzW/SpRu4mKBCZ/e5/mN0lbWTxQJlQYc+PP3lAbWn89Qloj9Opvp xC+v2ixyVAoaWzau83heeiB7K8ZOe8bt8xIT64s2FBcW4OSp0zbHTHv8CaSmpto9v2N882oAlNaY sefkJUx/+T20adcR4wf3wPkzx106NzQ8Aht3H8Pg3gm4Y+WVei/VgBZ+d6laocrNYPeI1x2N4wBo qfrzzaNbOowztbLm/dcdep+aIvfkEdw1YrRH9s127doJ/86/aj8C6cLhLDz55Eysz1yHHTt2oLiw vtxlpLaF3XNcRatm0Stei7TkWKQlxyL3Qh6GD+qH1Ytfcul8pVKJjbuPoW9iG9yxMh9FdeXPzRkx ILqgZvXNU5qKA2Cl6M/nbteKyiousJNctmj2JNw77XmPrp978ggGpw3w2Fd/8eJF4d/tY9vYPWbb /jPA/jOwJsFs374dQ4fqAADXSt0fBIanJmH06Hsx+N6HHTozKsvLQHgOFO3coQFYxPr1nl9xS7f2 uCezDLsnaaFQWIoDK9/L8//9d1QPoC4OgOaOrBEdT1VxAfXncz3DLJWWYdmfdEJmoc0x86ePwTNv rfLo+laRNqd8+Nmz9XlQ4dooDBvm2NgPADHRURg0aJDw/19//cXlzxqemoScE4exdd9pPDRrvlOP W2h4hEsitRKujcKGbTtx6lIZnq8L7iExSpiHRLp8DW9Cn6222dzCqk+a6TVB9AYJYcAniovd+gs+ USMYgIuqOAz/rNBm1JszOQPzlnm2WezxA3uaLVIAyFy3TghSAYAP3nvXprROQ5YuXSrKv1rzxRdN foZWzWLDhwuxdd9plzJoPaVrz3748I25WL6/TNhCkxvQwu/BKoDl/pNGqTJWfdLMzVNAhYtLwJiH R4s2EPAHXM8wy+IJlg0bhnxSaCOoOZMz8PrHX3t0/QPZW3H7oMHNFikAFBWXYOXKlcL/4zom4PjJ 00ju1kV0XEx0FDLXrcWYsfX1rY4fP96kwb9XvBa/Hj3m8dTGXR6aNR/DU5Pw2OZrwuYYVgeL32Ao i+4aQIW3BXOzpbYXBTjeZc/TwgPuwvWLEHaCqzTwGPr5dZuAk/nTx3g8ku7I/EiIhPIWMdFROPbr r9C1jRW1V5aX4eRvp9EhLtbmPY7j0COlu10rgZU5kzMwf8WmJgNnvE3e+RwkJHXB5N5hQgq1P1Ph udu1wpTPiuKeZbDuBkgDAJMwhKI79BcdZE7TWjb28iUMBfOwKEGkRVUcBq64aiPSlQtmeyzSjxc+ i2Hjpnk9eqmouARDht6JynJx5FFoeARSU1NtREp4DiNGDHcoUq2axfZ1K/D6x1/7XaSA5akw55H7 sepwBXKKLe5U7s4ovzxZSTgLc5q4jCbdoT8ablkp/IMvziXGVSPQMInP6W4YzUVFwzRWJwSaNCzB IxyioLHhk/c8KqdDGpW38RUx0VE4tHePU997ZXkZ+vXv51Ckw1OTsGrDTkS3jrX7vr+orq5EXIwW t8arkDneMg1jvyn2eRig+f5WgpUHAEAxUE7eCjq6s6BPYQVAR3emmJvEtUK5HqE+mVTzcSoY/x0n iPTQJT36vn9JJFJreUhPRFpZXoaM/l19LlLAMrK2T+iGR0YOROHZQ/XB5pwRxfmX8H+vzERYRAu7 Io3TqoQFU6BFCsBSDmjivdh8qgqH6uqhcmlan46qfJxKLFIAzE3jRCIFGsWjWqOnfFYNhaHA3doC 5tvrv/yaXyrw7y3FokdzWnIsvsw6iOiWOrc/4vyZ4xg+qJ+kk+5UChqz/jUcz7/zmcs7pviL4sIC xMW2xdAEdf2o6sO5qr0qKoppWWgcPSWyqdCqUIoZ+KToQqStyiuuNWuJcvPgSCEXf8qGQkzdWCgS 6fzpY7Dr2B8eiTT7q88lnRkap1Vh/vQxyLt0Ga9//LXkRAoA0S11mDCsHzafqkJemcU0yHdvugqi J3A9w2x2wmYGPmkjUsAfEf7WUTRNK+wdf+iSHtM2l9oIyrrbcYhGg9DQECQndUaHjp1xyx0ZTVbU e+/FRzHz9RXu98/HJOk06N/nJjzwrylIyxgfkIVSQ3ZkfoSdWy3ByRqNBi1btUJi9164OX2kUBDO ulvhnNu1eKluJa584w/vxn64GeFvd/LhtRqo1v06u9Vv4jU/65pdl2hTxGlVGDKgN6bNmitKzGtu pRKVgkbfxDZI7XMTOnfpjo5JyQhtEY0IrcUSYTDUovL6NdRWV6CmshwV10tQVlqKmuoKlJeVQ6+v RXV1/R9cZGQUIqNjkJDcE937DfboyeBLivMv4dZeSXafOr3itbjjtgGY9PQr6NOrF0JULHJnW+bO 3l5UuVs71eEs2bh1FuF/21bf4MEu0Q1Xc45GUU/oFa/FonffR+sOnTFySJrb11QpaNxza3eMfWgK 7rh/qk+23JEy+XkXkJyUgNIaM0Z1C0HrMBa7/jCJfkeVgobexOPIzDh0axXk1a3s7e5K3XU4lCMW O9Sjwzf4iqvEuGKwKGXanc423H7cV/t1Wn9MV0nSafDopAfx0KzXPK57+nfhmy+WY/iEJxCnVWHv Y60RE8Igp9iIb89U48ODVYIFRtgSnSMIeu2CV3LnrEmaAqwKymlZoMNaOdSjQwc1HdaKYlMfFbXx ndUuxwGYB1kMuEVVHCZkFrosqF7xWiydOw0//7AF504fQ86Jw/hh02rMmZwhRKdbcfWaacmx2LZm GX67UokZr334jxcpANz94HSMS09BXqkeb+62TMUSopWYNbAFcmfH4tvJbZCk0wj+fzAU+PbBzf7c hkmaVtjUR52KFGiikC8xGyzFexuEAVKlJigXX3QaBkZCGBjnWqJ83JmTDk9Nwpa9vznMIi0vLUF8 rM7l8LzhqUmYM/+NJiuieAtiqMKpvduxc+dO/LjvZxRcLYRB3QrDb+6Eu4YNxS13jQcVFNL0hfxE 7skjSOjeGwBwfFY7JETbToE2nawS6vk3e68GhoJxVjvRDopUeFtLUV82yKkWndaeotggih0kDowg WgW4W50H/jbsyEEXN9ICgIKrhSgpuOzw/TNH96PGhVF0XHoKjv28G1v3nfaPSM16fP3pu3jq4VHY uXMnlEoFBva7Bf363ITCwiIsWLUF/UY/ilaxHXAy+0vf98dFOif3ErasXLSnPkaWuqwXdupruJs1 36F5Iyp3awuRNgCAHfR8kyIFXCyNblw/UZyqYuChfPeiQ3NFw/lpj/fy3VrsWOvQ9+5xI3RtYmE0 GnDl0kXsP/Sr3bTfhoxLT8GcN5Y1a3MITygvLUF4eBjA2F+UFZ49hHnPPyNsrnbih/8iedD9/uyi Qw5kb8Ut6RlQKWjkPtseMSEM6FNVYLcUgRsWbeM1CnrlvEfz1Ib7LFihO/SHcsynLmnQpYPcjQMg uiAYZ8QBAMauLbCbOeptjv2826UK04Hk/16Ziekvv4eY6CgU5p0DVOF++VyO43Dq8E/448xRlF+/ jsiYlkjq2R8dk24EAHRpHYIzBdVYmhGDaX3DAROxCJIj4ONUMA+PFgzUxYyAAAAOQElEQVTzitX5 HgXWu+LPd4ZLlVzdjQOgioyAyTKHTetou5mBt0nSaQIq0vy8C3j1ibHo3TESwUoGkRoFeneMxI7M j0THPTZvMZK7dUFRcQlO7tvpl77NnTISMWEqpNxyG0ZNmoWHn34Vwyc8gRu6pKBdZDBefWIs7rj1 FgDA1tN1A4qCAt+pbgufPD2UH14Gu7EQMPDgk9wPqnfVn+8Ml0sOMwOfAqUWxws2DnQV4AjoPyyV 9kZ1C3Ea/e4NZv37cZ9e3xHFhQV4cuxgdLyhE15avh6nLpWhb2IbdO+ow6lLZRg2bhq++WK5cDxF M1jwnKWvOecu+Lx/33yxHAtWbREtPlUKGlo1C5WCRl6pHi8tXy/sSbXvTz1MdYtk0rpBkh9HwPxS gaA3/rAMQm5iExCtjgQ7YIZb13BZQe7GATA/W7wYMSEMXkp3vGV3c5k5Jh1TXnBestAXbFzxBhLj 47B0/Q/oFhuBDR8uRHlVLXafyMPuE3k48GM2VAoazz77nOi8djrLTWsd3bxM1KYouHwJ02fWp4LH aVU4PqsdyuZ3RP68Diib3xG5z3XA0owYJOkso6TexONoviV9mm9nZ+Gk5932Tjny57uzdQ/g5jbo zI33gWopTrfg7oyyWwu+YcHWf/eLwKhu3jXLaNUsVi6YjSWZWV69blOUl5Zg/OAeuO/RFwAAn70z D4fOleDeac+LPFw39k1D38Q2NgvJynLL6rpjlx4+6yPHcRg3rJ8obHLhnS1szE9xESym9Q3H0Rmt sTQjBioFjaN1u0iLRlRPUdEWfTSAatkFzI3up7i7JVSKZig2fa6ojYQwlrA9O7DbigEDDwVDIXO8 DkszYqBVNy9rIE6rwpzJGTh7Ic/vI+neHRvQvVOsEFcQomLRrVc/u3bf6upKnDhfYOOk+Hb7DkzN GICWiX180kdCCB4bfZvIQvLgTWGCmYk+VQV2YyHYb4pBn6oS7OHT+oZj7+P1uXMkhLFJtHMX8+1a m2uw6XPd3l4ScFOoAMDE9aHorsNFbVxqBEiUrWmGKjFC8ckVIQV2Wt9wrBnrftJYkk6DqRkDsH3d CvxeUI7XP/7ar8EexfmX8MjIgRgw7H7kleoxf/oYLH95BvJK9eifPkw0D7WyYOYElNaYMWXsSKGt vLQEJ8/kYsUax3sLNJcXp44SzGCA5Q/73RGW6QZVaoJikyW2lNlXBsXaAigX/Sk8+bq1CrKs+uto /Mh2h4ZFl63QXYd7tGEv4MHu0oD7cQAkhIH5vlaC6+zpbcVYvr8MWjWLxa++AF3bOBRczkN5aRGM RhMiWkQiQqtFh6Qe6HzjzQGL2ywvLcFbz07B4s+3QW/iEadVYfWnq5A2wmIBaZg0uHTuNMx4zbLn werFL+Hhp19Fkk6DY3+WClOCwrOH0LJTikN7a3Owl3qjUtDY+3hbdGtleYwrPnC84RnXLwLmoeIc qeZETHniz/cJ5n3LbUtUJmocF8NiKGJ4qh3RL+xEKl+7gTx4U5hQ9Gv+9DHEYDB4UuPMJ1y5eJ7M mZwhFGVTKWgyZ3IGqaqqsDn22M+7SZxWZSmeNiadzJ8+RihklnPisF/6azAYbMpmqhQ0+XZyG+He mG/XNl2sTBck3CP9wk7EdH8rz0pJJmpstGHet7xZpVc8Vjcx1RLjymFuxQGQKCVM09qChDAwcQQL d5UKcQBJOg2ee2YWxj7xYkDC7oxGI7I3fYYPli1B1uEcUcDLzz9sceqKzc+7gPS+3YWFU5JOg693 7vFp4YiGnz3+7jQbr5219DngZpImQ8E8Ihpcn3DP0pAc+fOnbgelCPbvaGqFy9lp+5fTxF8urwsi hrnxwvHfTm5DknQaYSSI06rInMkZ5Mj/viM8Z/bpSFRVVUG2rVlGpmYMsClpOS49hWz4cCFRKWiS lhzrcMT/afuXoiK5UzMGkIqy6z7tt5Vta5bZ9FuloMnacbr68o0T2xDCUB6Nioa58W6fa75da/uk dXF3Pmc0W+HuxgEAFr+v6UGdMFk3cQTrj1Vi8b4qkTlHq2bRL6UTBva7Bd173YLk1CE2+fLucK24 CL/s3oqDP2Zj14/7cODsFdHIGadV4cFRQzDthTeFUpY7Mj/CsHHTMC49BV98/ytKS4px6IevsXPr Bmz+fq9gAkpLjsXCd5f5JQimvLQEjz8w2CarQatmsWZsS2Frc+qyHspVVzyOISXhLCgD7/L5zfXn O6PZF/C4HoCdjFTAkgnw32OV2HZWb7f8jkpBo0NUMFpGaREaGoJQdRCio8S2uppaA6qrK1FZY0DB 1UJU1xpQWG5wGB5oFWiP3n3RIro1amsqoa+uRFlpKQquXELmV9twpqAaWjUruoZWzWL04Fts0mN8 BeE5rHrzBTz32rs23yVJp8H6sVGCrZTOrYHi83y/VuVrrj/fGV6ZM5i+n0+4X8RVAZ2tMBtCwllw Q6LAdQ+xyR/PKTbiUJ4ex/INOHiVRlFZjVdqR3mKdSeSgf1uQf8hGeiddpcoWa+6uhL7vv0v7rh/ ilc/lxCCLZ8twZy58+xGok1PjcDLd0QitG4kY45Wgt1U6FeR8nEqmB4TP+2YnhOguOMlr2jMKxch tWXEuGIwSG29KcPdiTgJYcD3CQd3Y6iwa7Q9TBzBhVITyvU8Kg088htMMWpMBGoFBbXScsMigmmE BtFoFcpCxVIoqjKjsIpDWS2PkmoOhZVmlOt55FeYcfYaEUQwPDUJI+6+GxFaLaJ0cYjt1BWxHZMc LvKMRiM+Xjgby1aswoZtO70WZlhdXYnVb7+IZStW2RVokk6Dt4dFCI96cATsjhK/b3AG2MnPD46A clqW265SR3htFWY+up6Yv5snavO0cAGJUoJPUINvHwzSOsgm2NYXmDiCkavzhcrW49JT8Oyr7zqN yirOv4TVS17G+6vWoajS6HH5oYYQnsO+nV/h8xXvY1PWz3anK3FaFebdHo4xKaFQ1D2FqCIjFOuv giow2Bzva7ieYaL9ogCAvfNVsD3GeE1fXruQL3f8IyEMiFYBEq0EwlmQcBZEzQBKGkRdN3FX0gBL AWYCGC2fR9XwgJEHVcNZItZDWBANYzlHzYBoGNHEv7HJDLCIov9NiWjfrh1aaCNRW1ODszlnkXsh T1TMrVe8FtOmTMZtI8cLcZ4ufTdCcOHsCez+ei1278rCd/tPOZxLD+qkxqTe4aKoe3AE7K5SSyn7 QFQJdzM/31O8atfyWj0Af8JYYi9NY1oJos0pNmLRnuvYeLLKYQKhSkFjaIIarcNYm4WfVs2ie0cd WreMRHRUFDQaDVSqYASr1bheeg3V1dUoLilB7oU8XLha4TQHLEmnwYSUYNzbPRRxEQ3iJOpC75hd gd0UxN38fE/xugHWuHkG4c82KFTrQT2AQECilDA90FI0zzJxBEfzDcgpMqK42mLViNYwSIhRokfr IOGxCwCnrhrw1ckqfP8nHG4m7ApJOg166hjcGh+MWzuqxeIEAAMP5lA5mH1lgd21Bg7y8xOHQjnq Pa/ryusXbG49gEDD9QwDN7CF0wVdU1QaeBy6pMfxfANOFxpRUGlGOadCda0BrUMsj+ewIBqtw1iE q2h00CqQEKNEUoxSWLmLO0VAn68FfaISzLHKgG4E0hB/+vN94tIy71tOzD8uEbV5mmsTKPg4FcgN avDtgkEiWEBdNwcrM4EqM4MuMIA6VwOq3Ay+Wwj4zhrwHYO9VqKRquJA/14D6nwNmN+qAr5pcmMa JnBaYQc+CbbfdJ9oyicX9SQO4G+BigbfPhh8fDBIyyDw7VSixZpdDDyocjOoIiOo6ybQF2pBFRgC /lh3SgD8+T6pfU4pgqnG+wJY6wH4a1+AgKDnLZkNDZ4cJIQBQlmQukqGVF3SI2o4S5zuX/AP12F+ vg+DTnyWdcckDKHouJtFbeaBLZodNf5Xg6riQBUYQOfpQefpLaOldcT8C4qUhDAwDxSv8um4m0X1 9n2BT9ND2TteAqgGwgyiwQ1zkLkq85eAGxYtns5QjOU++xifCtWf+wLI+B5v5Od7im8T7gGwA2aA ChankjisByAjaWzy84Mj3M7P9xSfC5UKjqCYATNFbd7aF0DGf9jNzx8w02tBJ03hc6ECANNjLKjo BFGbo3oAMhLEXn5+dAKYHmP91gW/KIWiGarxhNtZPQAZaWE3P/+Ol7wadNIUfhvSmLg+FJ0o3i7c UT0AGelgNz8/cajXg06awq/PXva2ZwG2wTzHzo7CMtLCZqdxVmW5j37Gr0KlI9o2a18AGf/isN5+ RFu/pz37fTXD9JkEKrytqK1xhQ4ZCcBQlvvSACq8LZg+kwLSHb8LlVIE2+4LEKME19c/1ZdlXIPr G24T6uhrf74zAmIfshsHMDjyHxcHIFVICGPZs7YB/vDnOyNghkw5DkC6BMqf74yACVWOA5AmgfTn OyOgriE5DkB6BNKf74yAClWOA5AWgfbnOyPgznY6ZYwcByAFHPjz6ZQxAeqQmICrgWZYOQ5AAjjy 59MMG/DRFJCAUAE5DiDQSMWf7wxJCBWQ4wACiVT8+c6QjFDlOIDAICV/vjMkI1RAjgPwOxLz5ztD UkKV4wD8i9T8+c6QlFABOQ7AX0jRn+8MyQkVcBAH0OhHlWke3OBIyfnznSFJodqNA+gTLscBeAk+ TgWuj3g6JQV/vjMkKVRAjgPwJVL15zvDJ0XSvAEVHEGZf/mCmL9/RWizxgEwv1UFsGd/bbiuIZL1 5ztD0p3jOTMxfToSpDgn0F3520JFJ0Ax8WvJuEodIdlHP2A/DkDGu0jJn+8MSQsVsB8HIOMdpObP d4bkhQrYiQOQaT4S9OfLyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjI/H34f4DnQZLCUbKg AAAAAElFTkSuQmCC "
+ height="15.781592"
+ width="15.781592" />
+ <text
+ xml:space="preserve"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="21.661425"
+ y="26.843145"
+ id="text2990"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2992"
+ x="21.661425"
+ y="26.843145"
+ style="font-size:11px;font-weight:bold;font-family:Arial;-inkscape-font-specification:Arial">AddThis</tspan></text>
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#fd8363"
+ d="m 19.392263,29.202057 c 0,0.470446 -0.381554,0.852 -0.852,0.852 H 6.0442638 c -0.470446,0 -0.852,-0.381554 -0.852,-0.852 V 16.706058 c 0,-0.470446 0.381554,-0.852 0.852,-0.852 H 18.540263 c 0.470446,0 0.852,0.381554 0.852,0.852 v 12.495999 z"
+ id="path3" />
+ <g
+ id="g5"
+ transform="matrix(0.142,0,0,0.142,5.1922638,15.854058)">
+ <rect
+ x="41"
+ y="12"
+ style="fill:#ffffff"
+ width="19"
+ height="75"
+ id="rect7" />
+ <rect
+ x="13"
+ y="40"
+ style="fill:#ffffff"
+ width="75"
+ height="19"
+ id="rect9" />
+ </g>
+ </g>
+</svg>
diff --git a/src/skin/socialwidgets/Digg.svg b/src/skin/socialwidgets/Digg.svg
new file mode 100644
index 0000000..84cd1c9
--- /dev/null
+++ b/src/skin/socialwidgets/Digg.svg
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="34.751911"
+ height="26.782953"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="Digg.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient4052">
+ <stop
+ style="stop-color:#fdfefe;stop-opacity:1;"
+ offset="0"
+ id="stop4054" />
+ <stop
+ style="stop-color:#ccdced;stop-opacity:1;"
+ offset="1"
+ id="stop4056" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient4052"
+ id="linearGradient4058"
+ x1="81.797302"
+ y1="3.8279617"
+ x2="81.797302"
+ y2="31.885172"
+ gradientUnits="userSpaceOnUse"
+ spreadMethod="pad"
+ gradientTransform="matrix(0.29003228,0,0,0.59819028,0.73696251,12.934008)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2555"
+ id="linearGradient2449"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.06036153,0,0,0.05323126,-16.605495,-35.042981)"
+ x1="-344.15295"
+ y1="274.711"
+ x2="-395.84943"
+ y2="425.39993" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2555">
+ <stop
+ style="stop-color: rgb(255, 255, 255); stop-opacity: 1;"
+ offset="0"
+ id="stop2557" />
+ <stop
+ style="stop-color: rgb(255, 255, 255); stop-opacity: 0;"
+ offset="1"
+ id="stop2559" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2555"
+ id="linearGradient3090"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.06615488,0,0,0.05323126,-18.310968,-35.042981)"
+ x1="-344.15295"
+ y1="274.711"
+ x2="-395.84943"
+ y2="425.39993" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="5.6474939"
+ inkscape:cx="25.160986"
+ inkscape:cy="-16.32327"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="1344"
+ inkscape:window-height="1419"
+ inkscape:window-x="0"
+ inkscape:window-y="19"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-1.1640244,18.247469)"
+ style="display:inline">
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot4044"
+ style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ transform="translate(0.68711385,2.5916514)"><flowRegion
+ id="flowRegion4046"><rect
+ id="rect4048"
+ width="297.62234"
+ height="113.86864"
+ x="63.531864"
+ y="-216.95096" /></flowRegion><flowPara
+ id="flowPara4050" /></flowRoot> <rect
+ inkscape:export-ydpi="7.7063322"
+ inkscape:export-xdpi="7.7063322"
+ inkscape:export-filename="C:\Documents and Settings\Molumen\Desktop\path3511111.png"
+ transform="scale(-1,1)"
+ ry="3.1938753"
+ rx="3.9692924"
+ y="-18.247469"
+ x="-27.449751"
+ height="21.149059"
+ width="26.285727"
+ id="rect1942"
+ style="fill:#4e83b7;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ inkscape:export-ydpi="7.7063322"
+ inkscape:export-xdpi="7.7063322"
+ inkscape:export-filename="C:\Documents and Settings\Molumen\Desktop\path3511111.png"
+ sodipodi:nodetypes="ccccsssc"
+ id="path1950"
+ d="m 20.505048,-17.343331 -12.3963196,0 c -3.2813425,0 -5.922999,2.142877 -5.922999,4.804657 l 0,9.7314623 c 0.1062134,2.0777436 0.5147671,0.7642386 1.292434,-1.5367248 0.903814,-2.6741826 3.8472608,-5.0114574 7.4318566,-6.7631125 2.73601,-1.336972 5.798449,-2.190712 11.372901,-2.271929 3.161432,-0.04606 2.88233,-3.301463 -1.777873,-3.964353 z"
+ style="opacity:0.55364805;fill:url(#linearGradient3090);fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 7.8994652,-10.006508 -2.7022435,-0.0074 -0.014093,5.1181777 4.5539095,0 0.016554,-7.3379837 -1.8375414,-0.01134 -0.016554,2.238636 z"
+ id="path4533"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#4e83b7;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 6.9806945,-8.5581307 0,2.1837654 0.958717,0 0,-2.1857148 -0.958717,0.00198 z"
+ id="path4535"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 10.575884,-10.070795 1.835122,-0.002 0.0025,5.1448069 -1.797597,0 -0.03995,-5.1428569 z"
+ id="path4537"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 10.587584,-12.23573 -0.01163,1.489935 1.87749,0 -0.02824,-1.487984 -1.837544,-0.002 z"
+ id="path4539"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 13.252306,-10.070795 0.0092,5.1636367 2.784562,0.01134 0.01655,0.7071444 -2.784561,0.024678 -0.02581,1.4217498 4.633804,0 0,-7.3285719 -4.633804,0 z"
+ id="path4541"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#4e83b7;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 15.08985,-8.5922227 -0.0025,2.1535722 0.916347,-0.00198 0.0049,-2.1516228 -0.918771,0 z"
+ id="path4543"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 18.844827,-10.102937 0.0092,5.1636361 2.784561,0.01134 0.01655,0.7071444 -2.784561,0.024678 -0.02581,1.4217498 4.633802,0 0,-7.3285723 -4.633802,0 z"
+ id="path4545"
+ sodipodi:nodetypes="ccccccccc" />
+ <path
+ inkscape:connector-curvature="0"
+ style="fill:#4e83b7;fill-opacity:1;fill-rule:evenodd;stroke:none"
+ d="m 20.682372,-8.6243653 -0.0025,2.1535722 0.916347,-0.00198 0.0049,-2.1516228 -0.918771,0 z"
+ id="path4547"
+ sodipodi:nodetypes="ccccc" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Layer"
+ transform="translate(-0.58003759,32.544319)">
+ <image
+ style="display:inline"
+ y="-20.117104"
+ x="20.97621"
+ id="image3112-9"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKoAAACqCAYAAAA9dtSCAAAABHNCSVQICAgIfAhkiAAAIABJREFU eJztnXl4E9Xex7+zJE2TbqQLBGiBIrQFikUWsSxWKSIoFMSFRa6yiYoXFMUFxKuooKIICq8ioiJC uQIioCDWAlcB2ZRVoBVQCrR0oXRvtpnz/pFm2mmWJmmWUefzPHkeOJmZnGS+PXPObzuAjIyMjIyM jIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjJehAt0BV+DLLhPjyqGAWR/orvx9YFVQTt0BOqLt X0IDdKA74Arm3W/JIvU2Zr3ld/2LIHmhcnmHCH92R6C78beEP7sDXN4hEuh+uAIb6A44g+fMxPTp yEB342+N+fv54DkzoRlW0lMAaQv12HqQ4hxRG7uxEMxvVQHq0V8frmsIzPe2FP5PinPAH1sfwB65 hmSFSmrLiHHFYFEbdVkP5peKAPXo7wHzSwW4vuEgbVVCG/fTUpDaMkIFR0h2VJXsHNX803sgtWWi NnZbcYB68/ei8e9Iastg/um9APXGNSQpVL44l3C/rhO1MYfKQefJK39vQOfpwRwqF7Vxv64DX5wr 2YWVJIVq/n4+QLj6BgMPJuta4Dr0N4TJugYY+PoGwll+d4kiOaFyOTsJn3dQ1MZmXQNVxTk4Q8YT qCoObKM/fj7vILicnZIcVSUlVGKqJebsN0RtVJERzIFyB2fINAfmQDmoIqOozZz9BoipVnJilZRQ uUOfgJRfFrWxO0oATnK/298Djlh+3waQ8svgDn0SoA45RjJC5csuE/P+D0VtdG4N6LPVAerRPwP6 bDXo3BpRm3n/h+DLLktqdJCMUG38+RyRzVF+gt1WLH5qSTAOQBJCtefPZ/aXgSoxOjhDxptQJUYw +8U2a6nFAQRcqDxnJo3NIlQVB3ZXaYB69M+E3VVqY1mxxgEEqEsiAi9UO/585rsSQM87OEPGJ+h5 y+/eACnFAQRUqKS2jHA/LRW1yf78wMH8UgHqstj7Z40DCFCXBAIqVNmfLz2kGgcQMKHa9ecfrZT9 +QGGztODOVopapNCHEDAhGrXn79dHk2lALO9WHJxAAERquzPlzZSjAPwu1Blf/5fA6nFAfhdqLI/ /y+CxOIA/CpU2Z//10JKcQB+Farsz//rIZU4AL8l93F5h4hp7XhRmxT8+SRKCT5BDb59MEgEC6gZ yxtmAqrMDPpiLegz1aAKDAHtZ6CwxgFwA1oIbdY4ACauj9+SAf0iVMJzxPhJhqgt0P58PlED8yCt KBuzMSRGCb6zGhgcCeqyHmx26T9ymsLuKgXfIwwkhBHazN/PB+E5QtGMX8TqF6FyRzOl489X0TCN bgm+W4ioOafYiFNXjSip5lBt5BGtYZAQo0SP1kFQMBRIWxVMD7UGc6gc7Nbif9biry4OoHE9AO5o pt+64HOhSik/n4SzME1qAxKjBAAUVXH48OcyfHigAqU1ZrvnaNUsxqaE4LnbtIgJYcD1CQeJUEDx ef4/SqyBrgfg88WUZPz5Klok0jW/VKDzW39iwa5ShyIFgNIaM5bvL0PKu3nIPmdZAfOd1TCNaeWX bkuJQMYB+FSoUvLnm4dGCSJd/ON1TN1YCL3J9alHaY0Zd626gk0nLeWE+G4h4PpF+KSvUiWQcQA+ ffRLxZ9PdEHg+oQDADadrMKcRoZsd5i8oRDdWimREK2EeXAk6OOV0nX9MhT4NkEgsSqQcBYIYUEU FCgTAUw8qCIjqGsmUJf1Ln8HZnsxuC4aIKhujPNTHIDPhMrl7CSmr54Qf1iA/PlcX4tITRzBC99d b9a19CYes7YV49tJbYAgGtzAFmC3ey58X8AnasD1DAOfoAEUrk0fqct6MGeqLSkpTha51jgA893R 9Z9XFwfAJAzx2VzVJ0IlplpiXDlM1EaVmgLmz+e7WFb4W09XI6/U8bRDq2YRomJRVGl0Oi3I/r0G 2edqMOgGNfgeYYBEhEp0QTDdE2PX5FZUxeF6LYdyPQ+1gkKYioEulIGizrpE2qpgbquCOU0Ldk8p mP9dd7hYZA6Ug0uNANEqhDZrHAClCPaJWH0iVLv+/MYeDj9BopSC/W+HAxvouPQU/GfxSnRO7gUA MBqNyFz2Gh59/nWHgs08WolBN6hBQhhwPcNAVXMgkQogiLY8ZhU0iJ3RjKrhAAMPqtxseeyWmy3B H838bbh+ETAPjQLqhFdUxeGLXyuQfa4GR68Y7S4YVQoa3WIjcHMrHg+khKJPrApQUDAPjgSXpIFi db79J2CdR9H0UGuhyddxAF5XP19x1WKOauAqpXNroPj0irc/yrX+xKlgeiwWAHDXJ1eQ/bvYdz1z TDqWZGbZPXfjijdw36Mv2H1Pq2ZxcU57YURqFhwBVWAAnW8AlacHfa4GVLljS4QIhoJ5dEtwPUIB AJUGHu/+eB2Lfypza7EIAEk6DVaM0loEC0tUm/KDSw6nAqaJbSwOESusCsppWaDDWnldV16/oHHz DHHqM0egXJIXMFcpn6gR/vJ7vJePMwXiUbWkqBCR0TEOz+/dMRJHLtj3oB2f1Q4J0UpRW6WBx/Va HhV6DjUmgsoGAcihQTTCVTRaBDOIaeDlsQdVZARzvNK5+5ahYPpXa0Esp64acM+aIqfTG1dYMDQK swZaXKbM0UqwX161exyJUsL4ZJwwigMAnTgUylHveV1XXn30S9GfT5WYhH/31DE4U1D/nkpBOxUp ADwweiSOLLL/SPuobs59ttiI/CoKf5TUujyKqRQ0YkKV6NmaRVKMEl1bBWFAh2BBwCTGYlWwum+Z Y5UWJ4l1dGMomMa0EkSafa4Goz8vcHsUtcecHSVo10KB0ckh4HqEgj5QZtek6M84AK9djPAcMX52 D0jh6fqLV3FQvvNnwFOfjXPjQUIYbDpZhfHrCkTvnTqyF1179nN47p6t63BbxniH77uDK4u1JJ0G t3dQYFiSBgM7BIunFgYezKFyMPvKwA2JEh733hRpw77mPNsOoUG001EVKhrGp9uL4gColl2gfPgr eDMOwGsGf+74BpFIAenk59OnLUb6EV00SNJpRO8tfdX+HJTjOOzI/Agr318kak/SaTAuPQVTMwa4 9NkqBY2pGQPww6bVKKrQ4+K1WtQaOeRfysMPm1Zj0exJGJeegjitZV54pqAay/eX4a5VV9BuwZ94 elsxTl2te/QH0eAGtIDx+Q4+FSlgcXCsqzPuc91DAJUDqdirB1B4GtzxDV7tj1cUb/XnN3SVUpf1 UC6/5I3LN5uGc6nsczW4a5V4YffT9i/Rf+h9AIDfftmHlW+/jDVb96C0xow4rQr9b0rEqHsfwOD7 piBcG4UdmR/hwSnTnbpe47QqPP3YQ5g4+w2EhrvmwbqY+xuyNq3G1m++QdbhHJH4esVr8VTfIIxO rg+mOXXVgDtW5jvtR3MY1EltsRcDUKzOdxo5ZpweKzKLUcERUE7LgqT2BTB9P5/oF3YSvbg4FSGA ZF6mYVFC3+bcriUAhJdWzZLP3plH0pJjhf+PS08hP2xaTXjOTBry2TvzROc2fsVpVWTlgtnEbBaf 5y5l14rJygWzSa94cV+TdBqydpyO5M2NJ3FaldO+NPx+49JTyPKXZ5CVC2aTOZMzbK5r76VS0MJv Zu4X4fT35eJUNhowfT9fOlE7fHEu0b+RKO7g/a0CLkybF0MRw+z2Qh8fvCnM5sb0iteSlQtmk6qq CrviWTR7klMxLJo9iRgMhmYJ1B5H/vcdGZeeYiMiR31p+Jo5Jp2UXSu2uSbP806/j/VV/HJHyz0d FtX0YHB/K7FY30gk3ooDaPYc1Zy9EDb+/J3S8NQIMBTMQyJFnpRH+oZDpbB8/bTkWOzeshaHz1/D lBfegkYTKjqdEIK5U0ZitoPV/7j0FJw8k4Nn3loFpVJp95jm0HPgEKzNOoqcE4cxLj0FAJqck2rV LHZvWYslmVkI10bZvE9RFJ55axWGpya51AfKhbUGs7PEth5A9kKXrt8UzRIql7OT8H/sFbWxP153 3VjtB0iUEsZH2womlKIqDlM2FGLg/11Ct9gI7N6yFrtP5CFtxDj75xOCaaNuxYJVW2zei9OqsPO/ K7E26yhax8X79HsAQOfkXlibdRQ//7AFveK1Do9L0mlw9MQph9+pIa2ibUVsRatmEWoNPjE0LVSq 3Az2R3EsBf/HXq/UA/BYqHbz80tNFh+xROATNTA+UT/Jzz5Xg/4f5GPjySosmj0JB3KLmryZ00bd ipVbfrJpn5oxAKcuFOCO+6f4pO/O6DtoBA7kFmHR7EnCU8FKkk6D/x05g7iOCU1ep7K8DDt/Ouzw /VvjGyyOLrnmRGD+dx1UqUnU5o16AB4b/KXkz7cH1zMM5lExFsM4R7BwVykW7CpFnFaFAz9m48a+ aU1eY+6UkTYi1apZrF6xBHc/ON1rfa2ursTh7G04ffQgcs+eRnFJCSprDHj1nf9z2E+GYfDMW6tw 2933455RIwVvVP8+NyFK17bJz6wsL8OIAd2derHu7V43BTLwoK+4mNwYgDgAh/AVV4l+UbJo4myc 2CbwC6a6l7lfhNCv4pc7kkGd1AQASUuOJUVX811awNhbaKQlx5IrF897ZYF05eJ5smj2JJKWHGt3 YbRo9iSXr1VRdp0MT00Szh2XnuJ0UbdtzTKSpNM4XUQl6TSk8rUbLAupUTFu3wPjxDbihdWiZMJX XPXvKGbcOkvcidduIHyUMuACbSzS3Oc6CDckLTnW4Wq+MRs+XGhz4+ZMzmi2yYnnebJtzTKRqOy9 0pJj3b622WwmUzMGCNcYnpok6u/Fc2fJ0rnTXDZL/fh4bP29DWfdvg98lJLo64QuDGZbZ3ksVLeN sXb9+T9dl0TwMNczTMiUzCszI31lAfJK9egVr8WeE3/arObt8cuPO9E/fZiwqvbGo57wHD5f8gre fHuxTVCMPY787zsk970Nl86fQcGfuTDU1uJ6cT7CWkRBHRqOFjGt0T6xu13rxItTRwkLv+GpSWgV HYW9h361+7lJOo3d9rXjdIJjgc26BsbDtHbzsChRHAAAKMavhSdxAG6dIGV/Pp+ogelBHcBQKKri 0P+DfOSV6qFS0Dj+y0Eh1tQZ14qLcFNiO2HelqTTYMO2nU5jAZrimy+W45X/vOQwAssejgTUmDit CvFtonFj1wSk3zUSt436FzSaUDw5djCWrv+hyfNX3tsSt3ZU47PD5fjwgCUreM3Ylhh0gyXQhc6t aV62rRfjANw62Hx0PTF/N0/Uxm4sDHgpcxLOwvhUOyCIRqWBx8AVV4UbvfzlGXj8P0ubuIJlNMro 3xXb9p8BYLGtfr3nV7s2SFc4f+Y4npoyVrieP1ApaAzunYBHHpuOzNUfY90Px5wePz01Au8Mt6SU mDgCvZkI5ig6twaKzIJmD0ANn3JW2DtfBdtjjG+ESmrLiPGjO0Fq6utmSsKfz1AwPtpWMEE1DI5O S47FruMXQVFNf823n50sGPTHpafg028PemS85zgO777wCOYt+czrgSLuEKdV2V3Rx2lV6BRJIzFa iWFJGmH0bIi3i2zYxAGoI6F85Du34gBcNk+Zf3pPJFJAGvX2zUMihR9hftY1UQT/ko8+d0mkB7K3 Yt6SzyzXmD4GL76/zqXzGpN78gjGjxzi1mPeVzQWaa94Lb4aG+EwYJsqNQE1HNhtxV5PZ2e3FQtZ FgBAaq65XQ/AJYO/lPLzG8LHqcClWiKTss/VYEGDSf/UjAEu2Uory8vwwP0PQG/i8dk78zBvWaZH Iv144bO4sefNkhCpPY5cKMXJq2JbKFVqAn2qyrIY/u9VKJdf8sk99UY9AJdGVEn68+tyhcBQqDTw eGxz/WivVbNYuHKjS5d5+qERKKo0YvMnizFy4lNud6O6uhKPjBzY5HxQCjyzvQxHZ1ge9cyhcrCb i/z22czOEtt6AG7EATQ5okrVn8/1DRcqn7z8/TXRo+7Jifc2mWICADsyP8KmrJ/xzfpPPRLp+TPH 0buT7i8hUsASlG2t9ML1CHMcDO0DmhsH4LSnxGyQpj9fRYNLswRlnLpqwPIG+3hq1SyefP2DJi9R WV6Gp5+ehW+3bsKge/7l9Fij0Tbna++ODejTq5dLZiQp8e6Buse/ggLXM8yvn+0wDsBsaFKsToXK HfxYkv58LjVCsM0918jR0DI8CCMGdEeX1iHYu8NxOsSSuY/hkzXr0HfQCKeftWfrOky862ZR2+rF L2FwxhifRdb7kiMXSoXUFuv83m/YqTBOyi+DO/hxk6c6FCpfcVWS9fZJCANzXSpv9rkamzz9MwXV 2HPyEnp07SSklzQmNycHw+5/uEmR7sj8CEPvnYDv9p8Cx1nm6K8+MRYPP/1qQE1PzeXTwxa7N9Eq wMc5LmTsCxzuC9BEHIBDoZr3SLPePjewhTAh/8/uWrvHaNUsFq3a5PAaHW+4AT0HDnH6OdlffY57 HnoMehOP0hozTh3+CU+OHYyXlktjE9vmsO1s/X0lsf4VKuBgX4A9zvcFsLvql2J+PgCQKKXIHOXI FPTmi085DWRmGOfFHw5kb8XdYyaKRs2x99ztdD46PDUJwybMQLt27dC6dWtUV1fjxIkT2LZtK3Zl 7ZTUCJxXqkdemRlxESz49sFg9pU1fZIXsVsP4LdtTusB2DRK2Z9vLSFj4gj6LC+wKxx3vFH2OH5g D24fNNjl+Wdyty548623MXToUIfH5Obk4KlZT2H79h0Oj/E31sATqtQE5aI//d8BN+MAbEZUqebn 84kaoSrIJ4cr7IpUq2axenOWxyLNz7uAEXcNdVmkw4YNxfp165pMh+6ckIBvv92OJ5+ciaVLvVOh OU6rwo2JHdAqOgrRURYLSHV1NS7kXcG5P/KatEbs/7MWo5NDLHlkDOX/BbK9fQGc1AMQCZXXVxKT ROrti1DRFuM+LDlPr2TZf+SvWPyqSykY9qiurkTGbb1drtuU3K2LjUg5jsOGL/+LAwcPIjExCRMm jBeF4i1ZshS///67xyNrr3gtHhg9EvdNmYV2nbs6PfZacRE2f/w21maux56TtvEY+RX1f4ykhSIg 0zq7+wL8uAS8vpLQqlDHo41U8/NNo2KE/ozqFmI32HdqxoBmBTQ3Tkdu6rV9+3bRNTLXrSUx0VGi Y7RqlnzwwQei4/Iv5bmc6mx9pSXHku3rVnj8/Y79vNsmWLtXvFYS99jVegDCql+y/vxEjais+eZT VTbH9IrXYtmXTcdfOuK1f49zy7uU3K2LaE66Y8cOTHxoAoqKxTZdVhOB0aPE+2vp2sZi2uPiStzO GJ6ahOnTH4dBX40D2VtRcNn9aLUb+6Zh677T+GHTaqF0UHVtvd+f7xu4vQjcjgMwrp8oVvZ8z1IQ vPniw1miryuAkDc3nmjVrM1oo1Wz5OK5sx6PNps/WezW6AaAzJw5Q3SN5G5dbI5RKWiyb98+u5+5 fft2tz+z8XdOS44ly1+e4XYOlzW/SpRu4mKBCZ/e5/mN0lbWTxQJlQYc+PP3lAbWn89Qloj9Opvp xC+v2ixyVAoaWzau83heeiB7K8ZOe8bt8xIT64s2FBcW4OSp0zbHTHv8CaSmpto9v2N882oAlNaY sefkJUx/+T20adcR4wf3wPkzx106NzQ8Aht3H8Pg3gm4Y+WVei/VgBZ+d6laocrNYPeI1x2N4wBo qfrzzaNbOowztbLm/dcdep+aIvfkEdw1YrRH9s127doJ/86/aj8C6cLhLDz55Eysz1yHHTt2oLiw vtxlpLaF3XNcRatm0Stei7TkWKQlxyL3Qh6GD+qH1Ytfcul8pVKJjbuPoW9iG9yxMh9FdeXPzRkx ILqgZvXNU5qKA2Cl6M/nbteKyiousJNctmj2JNw77XmPrp978ggGpw3w2Fd/8eJF4d/tY9vYPWbb /jPA/jOwJsFs374dQ4fqAADXSt0fBIanJmH06Hsx+N6HHTozKsvLQHgOFO3coQFYxPr1nl9xS7f2 uCezDLsnaaFQWIoDK9/L8//9d1QPoC4OgOaOrBEdT1VxAfXncz3DLJWWYdmfdEJmoc0x86ePwTNv rfLo+laRNqd8+Nmz9XlQ4dooDBvm2NgPADHRURg0aJDw/19//cXlzxqemoScE4exdd9pPDRrvlOP W2h4hEsitRKujcKGbTtx6lIZnq8L7iExSpiHRLp8DW9Cn6222dzCqk+a6TVB9AYJYcAniovd+gs+ USMYgIuqOAz/rNBm1JszOQPzlnm2WezxA3uaLVIAyFy3TghSAYAP3nvXprROQ5YuXSrKv1rzxRdN foZWzWLDhwuxdd9plzJoPaVrz3748I25WL6/TNhCkxvQwu/BKoDl/pNGqTJWfdLMzVNAhYtLwJiH R4s2EPAHXM8wy+IJlg0bhnxSaCOoOZMz8PrHX3t0/QPZW3H7oMHNFikAFBWXYOXKlcL/4zom4PjJ 00ju1kV0XEx0FDLXrcWYsfX1rY4fP96kwb9XvBa/Hj3m8dTGXR6aNR/DU5Pw2OZrwuYYVgeL32Ao i+4aQIW3BXOzpbYXBTjeZc/TwgPuwvWLEHaCqzTwGPr5dZuAk/nTx3g8ku7I/EiIhPIWMdFROPbr r9C1jRW1V5aX4eRvp9EhLtbmPY7j0COlu10rgZU5kzMwf8WmJgNnvE3e+RwkJHXB5N5hQgq1P1Ph udu1wpTPiuKeZbDuBkgDAJMwhKI79BcdZE7TWjb28iUMBfOwKEGkRVUcBq64aiPSlQtmeyzSjxc+ i2Hjpnk9eqmouARDht6JynJx5FFoeARSU1NtREp4DiNGDHcoUq2axfZ1K/D6x1/7XaSA5akw55H7 sepwBXKKLe5U7s4ovzxZSTgLc5q4jCbdoT8ablkp/IMvziXGVSPQMInP6W4YzUVFwzRWJwSaNCzB IxyioLHhk/c8KqdDGpW38RUx0VE4tHePU997ZXkZ+vXv51Ckw1OTsGrDTkS3jrX7vr+orq5EXIwW t8arkDneMg1jvyn2eRig+f5WgpUHAEAxUE7eCjq6s6BPYQVAR3emmJvEtUK5HqE+mVTzcSoY/x0n iPTQJT36vn9JJFJreUhPRFpZXoaM/l19LlLAMrK2T+iGR0YOROHZQ/XB5pwRxfmX8H+vzERYRAu7 Io3TqoQFU6BFCsBSDmjivdh8qgqH6uqhcmlan46qfJxKLFIAzE3jRCIFGsWjWqOnfFYNhaHA3doC 5tvrv/yaXyrw7y3FokdzWnIsvsw6iOiWOrc/4vyZ4xg+qJ+kk+5UChqz/jUcz7/zmcs7pviL4sIC xMW2xdAEdf2o6sO5qr0qKoppWWgcPSWyqdCqUIoZ+KToQqStyiuuNWuJcvPgSCEXf8qGQkzdWCgS 6fzpY7Dr2B8eiTT7q88lnRkap1Vh/vQxyLt0Ga9//LXkRAoA0S11mDCsHzafqkJemcU0yHdvugqi J3A9w2x2wmYGPmkjUsAfEf7WUTRNK+wdf+iSHtM2l9oIyrrbcYhGg9DQECQndUaHjp1xyx0ZTVbU e+/FRzHz9RXu98/HJOk06N/nJjzwrylIyxgfkIVSQ3ZkfoSdWy3ByRqNBi1btUJi9164OX2kUBDO ulvhnNu1eKluJa584w/vxn64GeFvd/LhtRqo1v06u9Vv4jU/65pdl2hTxGlVGDKgN6bNmitKzGtu pRKVgkbfxDZI7XMTOnfpjo5JyQhtEY0IrcUSYTDUovL6NdRWV6CmshwV10tQVlqKmuoKlJeVQ6+v RXV1/R9cZGQUIqNjkJDcE937DfboyeBLivMv4dZeSXafOr3itbjjtgGY9PQr6NOrF0JULHJnW+bO 3l5UuVs71eEs2bh1FuF/21bf4MEu0Q1Xc45GUU/oFa/FonffR+sOnTFySJrb11QpaNxza3eMfWgK 7rh/qk+23JEy+XkXkJyUgNIaM0Z1C0HrMBa7/jCJfkeVgobexOPIzDh0axXk1a3s7e5K3XU4lCMW O9Sjwzf4iqvEuGKwKGXanc423H7cV/t1Wn9MV0nSafDopAfx0KzXPK57+nfhmy+WY/iEJxCnVWHv Y60RE8Igp9iIb89U48ODVYIFRtgSnSMIeu2CV3LnrEmaAqwKymlZoMNaOdSjQwc1HdaKYlMfFbXx ndUuxwGYB1kMuEVVHCZkFrosqF7xWiydOw0//7AF504fQ86Jw/hh02rMmZwhRKdbcfWaacmx2LZm GX67UokZr334jxcpANz94HSMS09BXqkeb+62TMUSopWYNbAFcmfH4tvJbZCk0wj+fzAU+PbBzf7c hkmaVtjUR52KFGiikC8xGyzFexuEAVKlJigXX3QaBkZCGBjnWqJ83JmTDk9Nwpa9vznMIi0vLUF8 rM7l8LzhqUmYM/+NJiuieAtiqMKpvduxc+dO/LjvZxRcLYRB3QrDb+6Eu4YNxS13jQcVFNL0hfxE 7skjSOjeGwBwfFY7JETbToE2nawS6vk3e68GhoJxVjvRDopUeFtLUV82yKkWndaeotggih0kDowg WgW4W50H/jbsyEEXN9ICgIKrhSgpuOzw/TNH96PGhVF0XHoKjv28G1v3nfaPSM16fP3pu3jq4VHY uXMnlEoFBva7Bf363ITCwiIsWLUF/UY/ilaxHXAy+0vf98dFOif3ErasXLSnPkaWuqwXdupruJs1 36F5Iyp3awuRNgCAHfR8kyIFXCyNblw/UZyqYuChfPeiQ3NFw/lpj/fy3VrsWOvQ9+5xI3RtYmE0 GnDl0kXsP/Sr3bTfhoxLT8GcN5Y1a3MITygvLUF4eBjA2F+UFZ49hHnPPyNsrnbih/8iedD9/uyi Qw5kb8Ut6RlQKWjkPtseMSEM6FNVYLcUgRsWbeM1CnrlvEfz1Ib7LFihO/SHcsynLmnQpYPcjQMg uiAYZ8QBAMauLbCbOeptjv2826UK04Hk/16Ziekvv4eY6CgU5p0DVOF++VyO43Dq8E/448xRlF+/ jsiYlkjq2R8dk24EAHRpHYIzBdVYmhGDaX3DAROxCJIj4ONUMA+PFgzUxYyAAAAOQElEQVTzitX5 HgXWu+LPd4ZLlVzdjQOgioyAyTKHTetou5mBt0nSaQIq0vy8C3j1ibHo3TESwUoGkRoFeneMxI7M j0THPTZvMZK7dUFRcQlO7tvpl77NnTISMWEqpNxyG0ZNmoWHn34Vwyc8gRu6pKBdZDBefWIs7rj1 FgDA1tN1A4qCAt+pbgufPD2UH14Gu7EQMPDgk9wPqnfVn+8Ml0sOMwOfAqUWxws2DnQV4AjoPyyV 9kZ1C3Ea/e4NZv37cZ9e3xHFhQV4cuxgdLyhE15avh6nLpWhb2IbdO+ow6lLZRg2bhq++WK5cDxF M1jwnKWvOecu+Lx/33yxHAtWbREtPlUKGlo1C5WCRl6pHi8tXy/sSbXvTz1MdYtk0rpBkh9HwPxS gaA3/rAMQm5iExCtjgQ7YIZb13BZQe7GATA/W7wYMSEMXkp3vGV3c5k5Jh1TXnBestAXbFzxBhLj 47B0/Q/oFhuBDR8uRHlVLXafyMPuE3k48GM2VAoazz77nOi8djrLTWsd3bxM1KYouHwJ02fWp4LH aVU4PqsdyuZ3RP68Diib3xG5z3XA0owYJOkso6TexONoviV9mm9nZ+Gk5932Tjny57uzdQ/g5jbo zI33gWopTrfg7oyyWwu+YcHWf/eLwKhu3jXLaNUsVi6YjSWZWV69blOUl5Zg/OAeuO/RFwAAn70z D4fOleDeac+LPFw39k1D38Q2NgvJynLL6rpjlx4+6yPHcRg3rJ8obHLhnS1szE9xESym9Q3H0Rmt sTQjBioFjaN1u0iLRlRPUdEWfTSAatkFzI3up7i7JVSKZig2fa6ojYQwlrA9O7DbigEDDwVDIXO8 DkszYqBVNy9rIE6rwpzJGTh7Ic/vI+neHRvQvVOsEFcQomLRrVc/u3bf6upKnDhfYOOk+Hb7DkzN GICWiX180kdCCB4bfZvIQvLgTWGCmYk+VQV2YyHYb4pBn6oS7OHT+oZj7+P1uXMkhLFJtHMX8+1a m2uw6XPd3l4ScFOoAMDE9aHorsNFbVxqBEiUrWmGKjFC8ckVIQV2Wt9wrBnrftJYkk6DqRkDsH3d CvxeUI7XP/7ar8EexfmX8MjIgRgw7H7kleoxf/oYLH95BvJK9eifPkw0D7WyYOYElNaYMWXsSKGt vLQEJ8/kYsUax3sLNJcXp44SzGCA5Q/73RGW6QZVaoJikyW2lNlXBsXaAigX/Sk8+bq1CrKs+uto /Mh2h4ZFl63QXYd7tGEv4MHu0oD7cQAkhIH5vlaC6+zpbcVYvr8MWjWLxa++AF3bOBRczkN5aRGM RhMiWkQiQqtFh6Qe6HzjzQGL2ywvLcFbz07B4s+3QW/iEadVYfWnq5A2wmIBaZg0uHTuNMx4zbLn werFL+Hhp19Fkk6DY3+WClOCwrOH0LJTikN7a3Owl3qjUtDY+3hbdGtleYwrPnC84RnXLwLmoeIc qeZETHniz/cJ5n3LbUtUJmocF8NiKGJ4qh3RL+xEKl+7gTx4U5hQ9Gv+9DHEYDB4UuPMJ1y5eJ7M mZwhFGVTKWgyZ3IGqaqqsDn22M+7SZxWZSmeNiadzJ8+RihklnPisF/6azAYbMpmqhQ0+XZyG+He mG/XNl2sTBck3CP9wk7EdH8rz0pJJmpstGHet7xZpVc8Vjcx1RLjymFuxQGQKCVM09qChDAwcQQL d5UKcQBJOg2ee2YWxj7xYkDC7oxGI7I3fYYPli1B1uEcUcDLzz9sceqKzc+7gPS+3YWFU5JOg693 7vFp4YiGnz3+7jQbr5219DngZpImQ8E8Ihpcn3DP0pAc+fOnbgelCPbvaGqFy9lp+5fTxF8urwsi hrnxwvHfTm5DknQaYSSI06rInMkZ5Mj/viM8Z/bpSFRVVUG2rVlGpmYMsClpOS49hWz4cCFRKWiS lhzrcMT/afuXoiK5UzMGkIqy6z7tt5Vta5bZ9FuloMnacbr68o0T2xDCUB6Nioa58W6fa75da/uk dXF3Pmc0W+HuxgEAFr+v6UGdMFk3cQTrj1Vi8b4qkTlHq2bRL6UTBva7Bd173YLk1CE2+fLucK24 CL/s3oqDP2Zj14/7cODsFdHIGadV4cFRQzDthTeFUpY7Mj/CsHHTMC49BV98/ytKS4px6IevsXPr Bmz+fq9gAkpLjsXCd5f5JQimvLQEjz8w2CarQatmsWZsS2Frc+qyHspVVzyOISXhLCgD7/L5zfXn O6PZF/C4HoCdjFTAkgnw32OV2HZWb7f8jkpBo0NUMFpGaREaGoJQdRCio8S2uppaA6qrK1FZY0DB 1UJU1xpQWG5wGB5oFWiP3n3RIro1amsqoa+uRFlpKQquXELmV9twpqAaWjUruoZWzWL04Fts0mN8 BeE5rHrzBTz32rs23yVJp8H6sVGCrZTOrYHi83y/VuVrrj/fGV6ZM5i+n0+4X8RVAZ2tMBtCwllw Q6LAdQ+xyR/PKTbiUJ4ex/INOHiVRlFZjVdqR3mKdSeSgf1uQf8hGeiddpcoWa+6uhL7vv0v7rh/ ilc/lxCCLZ8twZy58+xGok1PjcDLd0QitG4kY45Wgt1U6FeR8nEqmB4TP+2YnhOguOMlr2jMKxch tWXEuGIwSG29KcPdiTgJYcD3CQd3Y6iwa7Q9TBzBhVITyvU8Kg088htMMWpMBGoFBbXScsMigmmE BtFoFcpCxVIoqjKjsIpDWS2PkmoOhZVmlOt55FeYcfYaEUQwPDUJI+6+GxFaLaJ0cYjt1BWxHZMc LvKMRiM+Xjgby1aswoZtO70WZlhdXYnVb7+IZStW2RVokk6Dt4dFCI96cATsjhK/b3AG2MnPD46A clqW265SR3htFWY+up6Yv5snavO0cAGJUoJPUINvHwzSOsgm2NYXmDiCkavzhcrW49JT8Oyr7zqN yirOv4TVS17G+6vWoajS6HH5oYYQnsO+nV/h8xXvY1PWz3anK3FaFebdHo4xKaFQ1D2FqCIjFOuv giow2Bzva7ieYaL9ogCAvfNVsD3GeE1fXruQL3f8IyEMiFYBEq0EwlmQcBZEzQBKGkRdN3FX0gBL AWYCGC2fR9XwgJEHVcNZItZDWBANYzlHzYBoGNHEv7HJDLCIov9NiWjfrh1aaCNRW1ODszlnkXsh T1TMrVe8FtOmTMZtI8cLcZ4ufTdCcOHsCez+ei1278rCd/tPOZxLD+qkxqTe4aKoe3AE7K5SSyn7 QFQJdzM/31O8atfyWj0Af8JYYi9NY1oJos0pNmLRnuvYeLLKYQKhSkFjaIIarcNYm4WfVs2ie0cd WreMRHRUFDQaDVSqYASr1bheeg3V1dUoLilB7oU8XLha4TQHLEmnwYSUYNzbPRRxEQ3iJOpC75hd gd0UxN38fE/xugHWuHkG4c82KFTrQT2AQECilDA90FI0zzJxBEfzDcgpMqK42mLViNYwSIhRokfr IOGxCwCnrhrw1ckqfP8nHG4m7ApJOg166hjcGh+MWzuqxeIEAAMP5lA5mH1lgd21Bg7y8xOHQjnq Pa/ryusXbG49gEDD9QwDN7CF0wVdU1QaeBy6pMfxfANOFxpRUGlGOadCda0BrUMsj+ewIBqtw1iE q2h00CqQEKNEUoxSWLmLO0VAn68FfaISzLHKgG4E0hB/+vN94tIy71tOzD8uEbV5mmsTKPg4FcgN avDtgkEiWEBdNwcrM4EqM4MuMIA6VwOq3Ay+Wwj4zhrwHYO9VqKRquJA/14D6nwNmN+qAr5pcmMa JnBaYQc+CbbfdJ9oyicX9SQO4G+BigbfPhh8fDBIyyDw7VSixZpdDDyocjOoIiOo6ybQF2pBFRgC /lh3SgD8+T6pfU4pgqnG+wJY6wH4a1+AgKDnLZkNDZ4cJIQBQlmQukqGVF3SI2o4S5zuX/AP12F+ vg+DTnyWdcckDKHouJtFbeaBLZodNf5Xg6riQBUYQOfpQefpLaOldcT8C4qUhDAwDxSv8um4m0X1 9n2BT9ND2TteAqgGwgyiwQ1zkLkq85eAGxYtns5QjOU++xifCtWf+wLI+B5v5Od7im8T7gGwA2aA ChankjisByAjaWzy84Mj3M7P9xSfC5UKjqCYATNFbd7aF0DGf9jNzx8w02tBJ03hc6ECANNjLKjo BFGbo3oAMhLEXn5+dAKYHmP91gW/KIWiGarxhNtZPQAZaWE3P/+Ol7wadNIUfhvSmLg+FJ0o3i7c UT0AGelgNz8/cajXg06awq/PXva2ZwG2wTzHzo7CMtLCZqdxVmW5j37Gr0KlI9o2a18AGf/isN5+ RFu/pz37fTXD9JkEKrytqK1xhQ4ZCcBQlvvSACq8LZg+kwLSHb8LlVIE2+4LEKME19c/1ZdlXIPr G24T6uhrf74zAmIfshsHMDjyHxcHIFVICGPZs7YB/vDnOyNghkw5DkC6BMqf74yACVWOA5AmgfTn OyOgriE5DkB6BNKf74yAClWOA5AWgfbnOyPgznY6ZYwcByAFHPjz6ZQxAeqQmICrgWZYOQ5AAjjy 59MMG/DRFJCAUAE5DiDQSMWf7wxJCBWQ4wACiVT8+c6QjFDlOIDAICV/vjMkI1RAjgPwOxLz5ztD UkKV4wD8i9T8+c6QlFABOQ7AX0jRn+8MyQkVcBAH0OhHlWke3OBIyfnznSFJodqNA+gTLscBeAk+ TgWuj3g6JQV/vjMkKVRAjgPwJVL15zvDJ0XSvAEVHEGZf/mCmL9/RWizxgEwv1UFsGd/bbiuIZL1 5ztD0p3jOTMxfToSpDgn0F3520JFJ0Ax8WvJuEodIdlHP2A/DkDGu0jJn+8MSQsVsB8HIOMdpObP d4bkhQrYiQOQaT4S9OfLyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjI/H34f4DnQZLCUbKg AAAAAElFTkSuQmCC "
+ height="14.355739"
+ width="14.355739" />
+ </g>
+</svg>
diff --git a/src/skin/socialwidgets/FacebookLike.svg b/src/skin/socialwidgets/FacebookLike.svg
new file mode 100644
index 0000000..553d030
--- /dev/null
+++ b/src/skin/socialwidgets/FacebookLike.svg
@@ -0,0 +1,216 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="64.607384"
+ height="31.538702"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="Facebook.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="12.03"
+ inkscape:cx="25.018943"
+ inkscape:cy="27.000707"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="1222"
+ inkscape:window-height="1419"
+ inkscape:window-x="0"
+ inkscape:window-y="19"
+ inkscape:window-maximized="0">
+ <sodipodi:guide
+ position="53.472539,0.8733177"
+ orientation="0,53.46875"
+ id="guide3203" />
+ <sodipodi:guide
+ position="64.675443,34.289776"
+ orientation="-24,0"
+ id="guide3205" />
+ <sodipodi:guide
+ position="53.472539,31.62976"
+ orientation="0,-53.46875"
+ id="guide3207" />
+ <sodipodi:guide
+ position="0.00378865,31.523359"
+ orientation="24,0"
+ id="guide3209" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-0.62121135,-8.4846564)">
+ <rect
+ style="fill:#f0f0f0;fill-opacity:1;stroke:#d7d7d7;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect2985"
+ width="52.482887"
+ height="23"
+ x="1.1212113"
+ y="8.9846563"
+ ry="2.1487894"
+ rx="2.1487894" />
+ <text
+ xml:space="preserve"
+ style="font-size:14.40710354px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#535353;fill-opacity:1;stroke:none;font-family:Sans"
+ x="25.624592"
+ y="24.967773"
+ id="text4002"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4004"
+ x="25.624592"
+ y="24.967773"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#535353;fill-opacity:1;font-family:Tahoma;-inkscape-font-specification:Tahoma">Like</tspan></text>
+ <image
+ y="21.60157"
+ x="46.806808"
+ id="image3042"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKoAAACqCAYAAAA9dtSCAAAABHNCSVQICAgIfAhkiAAAIABJREFU eJztnXl4E9Xex7+zJE2TbqQLBGiBIrQFikUWsSxWKSIoFMSFRa6yiYoXFMUFxKuooKIICq8ioiJC uQIioCDWAlcB2ZRVoBVQCrR0oXRvtpnz/pFm2mmWJmmWUefzPHkeOJmZnGS+PXPObzuAjIyMjIyM jIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjJehAt0BV+DLLhPjyqGAWR/orvx9YFVQTt0BOqLt X0IDdKA74Arm3W/JIvU2Zr3ld/2LIHmhcnmHCH92R6C78beEP7sDXN4hEuh+uAIb6A44g+fMxPTp yEB342+N+fv54DkzoRlW0lMAaQv12HqQ4hxRG7uxEMxvVQHq0V8frmsIzPe2FP5PinPAH1sfwB65 hmSFSmrLiHHFYFEbdVkP5peKAPXo7wHzSwW4vuEgbVVCG/fTUpDaMkIFR0h2VJXsHNX803sgtWWi NnZbcYB68/ei8e9Iastg/um9APXGNSQpVL44l3C/rhO1MYfKQefJK39vQOfpwRwqF7Vxv64DX5wr 2YWVJIVq/n4+QLj6BgMPJuta4Dr0N4TJugYY+PoGwll+d4kiOaFyOTsJn3dQ1MZmXQNVxTk4Q8YT qCoObKM/fj7vILicnZIcVSUlVGKqJebsN0RtVJERzIFyB2fINAfmQDmoIqOozZz9BoipVnJilZRQ uUOfgJRfFrWxO0oATnK/298Djlh+3waQ8svgDn0SoA45RjJC5csuE/P+D0VtdG4N6LPVAerRPwP6 bDXo3BpRm3n/h+DLLktqdJCMUG38+RyRzVF+gt1WLH5qSTAOQBJCtefPZ/aXgSoxOjhDxptQJUYw +8U2a6nFAQRcqDxnJo3NIlQVB3ZXaYB69M+E3VVqY1mxxgEEqEsiAi9UO/585rsSQM87OEPGJ+h5 y+/eACnFAQRUqKS2jHA/LRW1yf78wMH8UgHqstj7Z40DCFCXBAIqVNmfLz2kGgcQMKHa9ecfrZT9 +QGGztODOVopapNCHEDAhGrXn79dHk2lALO9WHJxAAERquzPlzZSjAPwu1Blf/5fA6nFAfhdqLI/ /y+CxOIA/CpU2Z//10JKcQB+Farsz//rIZU4AL8l93F5h4hp7XhRmxT8+SRKCT5BDb59MEgEC6gZ yxtmAqrMDPpiLegz1aAKDAHtZ6CwxgFwA1oIbdY4ACauj9+SAf0iVMJzxPhJhqgt0P58PlED8yCt KBuzMSRGCb6zGhgcCeqyHmx26T9ymsLuKgXfIwwkhBHazN/PB+E5QtGMX8TqF6FyRzOl489X0TCN bgm+W4ioOafYiFNXjSip5lBt5BGtYZAQo0SP1kFQMBRIWxVMD7UGc6gc7Nbif9biry4OoHE9AO5o pt+64HOhSik/n4SzME1qAxKjBAAUVXH48OcyfHigAqU1ZrvnaNUsxqaE4LnbtIgJYcD1CQeJUEDx ef4/SqyBrgfg88WUZPz5Klok0jW/VKDzW39iwa5ShyIFgNIaM5bvL0PKu3nIPmdZAfOd1TCNaeWX bkuJQMYB+FSoUvLnm4dGCSJd/ON1TN1YCL3J9alHaY0Zd626gk0nLeWE+G4h4PpF+KSvUiWQcQA+ ffRLxZ9PdEHg+oQDADadrMKcRoZsd5i8oRDdWimREK2EeXAk6OOV0nX9MhT4NkEgsSqQcBYIYUEU FCgTAUw8qCIjqGsmUJf1Ln8HZnsxuC4aIKhujPNTHIDPhMrl7CSmr54Qf1iA/PlcX4tITRzBC99d b9a19CYes7YV49tJbYAgGtzAFmC3ey58X8AnasD1DAOfoAEUrk0fqct6MGeqLSkpTha51jgA893R 9Z9XFwfAJAzx2VzVJ0IlplpiXDlM1EaVmgLmz+e7WFb4W09XI6/U8bRDq2YRomJRVGl0Oi3I/r0G 2edqMOgGNfgeYYBEhEp0QTDdE2PX5FZUxeF6LYdyPQ+1gkKYioEulIGizrpE2qpgbquCOU0Ldk8p mP9dd7hYZA6Ug0uNANEqhDZrHAClCPaJWH0iVLv+/MYeDj9BopSC/W+HAxvouPQU/GfxSnRO7gUA MBqNyFz2Gh59/nWHgs08WolBN6hBQhhwPcNAVXMgkQogiLY8ZhU0iJ3RjKrhAAMPqtxseeyWmy3B H838bbh+ETAPjQLqhFdUxeGLXyuQfa4GR68Y7S4YVQoa3WIjcHMrHg+khKJPrApQUDAPjgSXpIFi db79J2CdR9H0UGuhyddxAF5XP19x1WKOauAqpXNroPj0irc/yrX+xKlgeiwWAHDXJ1eQ/bvYdz1z TDqWZGbZPXfjijdw36Mv2H1Pq2ZxcU57YURqFhwBVWAAnW8AlacHfa4GVLljS4QIhoJ5dEtwPUIB AJUGHu/+eB2Lfypza7EIAEk6DVaM0loEC0tUm/KDSw6nAqaJbSwOESusCsppWaDDWnldV16/oHHz DHHqM0egXJIXMFcpn6gR/vJ7vJePMwXiUbWkqBCR0TEOz+/dMRJHLtj3oB2f1Q4J0UpRW6WBx/Va HhV6DjUmgsoGAcihQTTCVTRaBDOIaeDlsQdVZARzvNK5+5ahYPpXa0Esp64acM+aIqfTG1dYMDQK swZaXKbM0UqwX161exyJUsL4ZJwwigMAnTgUylHveV1XXn30S9GfT5WYhH/31DE4U1D/nkpBOxUp ADwweiSOLLL/SPuobs59ttiI/CoKf5TUujyKqRQ0YkKV6NmaRVKMEl1bBWFAh2BBwCTGYlWwum+Z Y5UWJ4l1dGMomMa0EkSafa4Goz8vcHsUtcecHSVo10KB0ckh4HqEgj5QZtek6M84AK9djPAcMX52 D0jh6fqLV3FQvvNnwFOfjXPjQUIYbDpZhfHrCkTvnTqyF1179nN47p6t63BbxniH77uDK4u1JJ0G t3dQYFiSBgM7BIunFgYezKFyMPvKwA2JEh733hRpw77mPNsOoUG001EVKhrGp9uL4gColl2gfPgr eDMOwGsGf+74BpFIAenk59OnLUb6EV00SNJpRO8tfdX+HJTjOOzI/Agr318kak/SaTAuPQVTMwa4 9NkqBY2pGQPww6bVKKrQ4+K1WtQaOeRfysMPm1Zj0exJGJeegjitZV54pqAay/eX4a5VV9BuwZ94 elsxTl2te/QH0eAGtIDx+Q4+FSlgcXCsqzPuc91DAJUDqdirB1B4GtzxDV7tj1cUb/XnN3SVUpf1 UC6/5I3LN5uGc6nsczW4a5V4YffT9i/Rf+h9AIDfftmHlW+/jDVb96C0xow4rQr9b0rEqHsfwOD7 piBcG4UdmR/hwSnTnbpe47QqPP3YQ5g4+w2EhrvmwbqY+xuyNq3G1m++QdbhHJH4esVr8VTfIIxO rg+mOXXVgDtW5jvtR3MY1EltsRcDUKzOdxo5ZpweKzKLUcERUE7LgqT2BTB9P5/oF3YSvbg4FSGA ZF6mYVFC3+bcriUAhJdWzZLP3plH0pJjhf+PS08hP2xaTXjOTBry2TvzROc2fsVpVWTlgtnEbBaf 5y5l14rJygWzSa94cV+TdBqydpyO5M2NJ3FaldO+NPx+49JTyPKXZ5CVC2aTOZMzbK5r76VS0MJv Zu4X4fT35eJUNhowfT9fOlE7fHEu0b+RKO7g/a0CLkybF0MRw+z2Qh8fvCnM5sb0iteSlQtmk6qq CrviWTR7klMxLJo9iRgMhmYJ1B5H/vcdGZeeYiMiR31p+Jo5Jp2UXSu2uSbP806/j/VV/HJHyz0d FtX0YHB/K7FY30gk3ooDaPYc1Zy9EDb+/J3S8NQIMBTMQyJFnpRH+oZDpbB8/bTkWOzeshaHz1/D lBfegkYTKjqdEIK5U0ZitoPV/7j0FJw8k4Nn3loFpVJp95jm0HPgEKzNOoqcE4cxLj0FAJqck2rV LHZvWYslmVkI10bZvE9RFJ55axWGpya51AfKhbUGs7PEth5A9kKXrt8UzRIql7OT8H/sFbWxP153 3VjtB0iUEsZH2womlKIqDlM2FGLg/11Ct9gI7N6yFrtP5CFtxDj75xOCaaNuxYJVW2zei9OqsPO/ K7E26yhax8X79HsAQOfkXlibdRQ//7AFveK1Do9L0mlw9MQph9+pIa2ibUVsRatmEWoNPjE0LVSq 3Az2R3EsBf/HXq/UA/BYqHbz80tNFh+xROATNTA+UT/Jzz5Xg/4f5GPjySosmj0JB3KLmryZ00bd ipVbfrJpn5oxAKcuFOCO+6f4pO/O6DtoBA7kFmHR7EnCU8FKkk6D/x05g7iOCU1ep7K8DDt/Ouzw /VvjGyyOLrnmRGD+dx1UqUnU5o16AB4b/KXkz7cH1zMM5lExFsM4R7BwVykW7CpFnFaFAz9m48a+ aU1eY+6UkTYi1apZrF6xBHc/ON1rfa2ursTh7G04ffQgcs+eRnFJCSprDHj1nf9z2E+GYfDMW6tw 2933455RIwVvVP8+NyFK17bJz6wsL8OIAd2derHu7V43BTLwoK+4mNwYgDgAh/AVV4l+UbJo4myc 2CbwC6a6l7lfhNCv4pc7kkGd1AQASUuOJUVX811awNhbaKQlx5IrF897ZYF05eJ5smj2JJKWHGt3 YbRo9iSXr1VRdp0MT00Szh2XnuJ0UbdtzTKSpNM4XUQl6TSk8rUbLAupUTFu3wPjxDbihdWiZMJX XPXvKGbcOkvcidduIHyUMuACbSzS3Oc6CDckLTnW4Wq+MRs+XGhz4+ZMzmi2yYnnebJtzTKRqOy9 0pJj3b622WwmUzMGCNcYnpok6u/Fc2fJ0rnTXDZL/fh4bP29DWfdvg98lJLo64QuDGZbZ3ksVLeN sXb9+T9dl0TwMNczTMiUzCszI31lAfJK9egVr8WeE3/arObt8cuPO9E/fZiwqvbGo57wHD5f8gre fHuxTVCMPY787zsk970Nl86fQcGfuTDU1uJ6cT7CWkRBHRqOFjGt0T6xu13rxItTRwkLv+GpSWgV HYW9h361+7lJOo3d9rXjdIJjgc26BsbDtHbzsChRHAAAKMavhSdxAG6dIGV/Pp+ogelBHcBQKKri 0P+DfOSV6qFS0Dj+y0Eh1tQZ14qLcFNiO2HelqTTYMO2nU5jAZrimy+W45X/vOQwAssejgTUmDit CvFtonFj1wSk3zUSt436FzSaUDw5djCWrv+hyfNX3tsSt3ZU47PD5fjwgCUreM3Ylhh0gyXQhc6t aV62rRfjANw62Hx0PTF/N0/Uxm4sDHgpcxLOwvhUOyCIRqWBx8AVV4UbvfzlGXj8P0ubuIJlNMro 3xXb9p8BYLGtfr3nV7s2SFc4f+Y4npoyVrieP1ApaAzunYBHHpuOzNUfY90Px5wePz01Au8Mt6SU mDgCvZkI5ig6twaKzIJmD0ANn3JW2DtfBdtjjG+ESmrLiPGjO0Fq6utmSsKfz1AwPtpWMEE1DI5O S47FruMXQVFNf823n50sGPTHpafg028PemS85zgO777wCOYt+czrgSLuEKdV2V3Rx2lV6BRJIzFa iWFJGmH0bIi3i2zYxAGoI6F85Du34gBcNk+Zf3pPJFJAGvX2zUMihR9hftY1UQT/ko8+d0mkB7K3 Yt6SzyzXmD4GL76/zqXzGpN78gjGjxzi1mPeVzQWaa94Lb4aG+EwYJsqNQE1HNhtxV5PZ2e3FQtZ FgBAaq65XQ/AJYO/lPLzG8LHqcClWiKTss/VYEGDSf/UjAEu2Uory8vwwP0PQG/i8dk78zBvWaZH Iv144bO4sefNkhCpPY5cKMXJq2JbKFVqAn2qyrIY/u9VKJdf8sk99UY9AJdGVEn68+tyhcBQqDTw eGxz/WivVbNYuHKjS5d5+qERKKo0YvMnizFy4lNud6O6uhKPjBzY5HxQCjyzvQxHZ1ge9cyhcrCb i/z22czOEtt6AG7EATQ5okrVn8/1DRcqn7z8/TXRo+7Jifc2mWICADsyP8KmrJ/xzfpPPRLp+TPH 0buT7i8hUsASlG2t9ML1CHMcDO0DmhsH4LSnxGyQpj9fRYNLswRlnLpqwPIG+3hq1SyefP2DJi9R WV6Gp5+ehW+3bsKge/7l9Fij0Tbna++ODejTq5dLZiQp8e6Buse/ggLXM8yvn+0wDsBsaFKsToXK HfxYkv58LjVCsM0918jR0DI8CCMGdEeX1iHYu8NxOsSSuY/hkzXr0HfQCKeftWfrOky862ZR2+rF L2FwxhifRdb7kiMXSoXUFuv83m/YqTBOyi+DO/hxk6c6FCpfcVWS9fZJCANzXSpv9rkamzz9MwXV 2HPyEnp07SSklzQmNycHw+5/uEmR7sj8CEPvnYDv9p8Cx1nm6K8+MRYPP/1qQE1PzeXTwxa7N9Eq wMc5LmTsCxzuC9BEHIBDoZr3SLPePjewhTAh/8/uWrvHaNUsFq3a5PAaHW+4AT0HDnH6OdlffY57 HnoMehOP0hozTh3+CU+OHYyXlktjE9vmsO1s/X0lsf4VKuBgX4A9zvcFsLvql2J+PgCQKKXIHOXI FPTmi085DWRmGOfFHw5kb8XdYyaKRs2x99ztdD46PDUJwybMQLt27dC6dWtUV1fjxIkT2LZtK3Zl 7ZTUCJxXqkdemRlxESz49sFg9pU1fZIXsVsP4LdtTusB2DRK2Z9vLSFj4gj6LC+wKxx3vFH2OH5g D24fNNjl+Wdyty548623MXToUIfH5Obk4KlZT2H79h0Oj/E31sATqtQE5aI//d8BN+MAbEZUqebn 84kaoSrIJ4cr7IpUq2axenOWxyLNz7uAEXcNdVmkw4YNxfp165pMh+6ckIBvv92OJ5+ciaVLvVOh OU6rwo2JHdAqOgrRURYLSHV1NS7kXcG5P/KatEbs/7MWo5NDLHlkDOX/BbK9fQGc1AMQCZXXVxKT ROrti1DRFuM+LDlPr2TZf+SvWPyqSykY9qiurkTGbb1drtuU3K2LjUg5jsOGL/+LAwcPIjExCRMm jBeF4i1ZshS///67xyNrr3gtHhg9EvdNmYV2nbs6PfZacRE2f/w21maux56TtvEY+RX1f4ykhSIg 0zq7+wL8uAS8vpLQqlDHo41U8/NNo2KE/ozqFmI32HdqxoBmBTQ3Tkdu6rV9+3bRNTLXrSUx0VGi Y7RqlnzwwQei4/Iv5bmc6mx9pSXHku3rVnj8/Y79vNsmWLtXvFYS99jVegDCql+y/vxEjais+eZT VTbH9IrXYtmXTcdfOuK1f49zy7uU3K2LaE66Y8cOTHxoAoqKxTZdVhOB0aPE+2vp2sZi2uPiStzO GJ6ahOnTH4dBX40D2VtRcNn9aLUb+6Zh677T+GHTaqF0UHVtvd+f7xu4vQjcjgMwrp8oVvZ8z1IQ vPniw1miryuAkDc3nmjVrM1oo1Wz5OK5sx6PNps/WezW6AaAzJw5Q3SN5G5dbI5RKWiyb98+u5+5 fft2tz+z8XdOS44ly1+e4XYOlzW/SpRu4mKBCZ/e5/mN0lbWTxQJlQYc+PP3lAbWn89Qloj9Opvp xC+v2ixyVAoaWzau83heeiB7K8ZOe8bt8xIT64s2FBcW4OSp0zbHTHv8CaSmpto9v2N882oAlNaY sefkJUx/+T20adcR4wf3wPkzx106NzQ8Aht3H8Pg3gm4Y+WVei/VgBZ+d6laocrNYPeI1x2N4wBo qfrzzaNbOowztbLm/dcdep+aIvfkEdw1YrRH9s127doJ/86/aj8C6cLhLDz55Eysz1yHHTt2oLiw vtxlpLaF3XNcRatm0Stei7TkWKQlxyL3Qh6GD+qH1Ytfcul8pVKJjbuPoW9iG9yxMh9FdeXPzRkx ILqgZvXNU5qKA2Cl6M/nbteKyiousJNctmj2JNw77XmPrp978ggGpw3w2Fd/8eJF4d/tY9vYPWbb /jPA/jOwJsFs374dQ4fqAADXSt0fBIanJmH06Hsx+N6HHTozKsvLQHgOFO3coQFYxPr1nl9xS7f2 uCezDLsnaaFQWIoDK9/L8//9d1QPoC4OgOaOrBEdT1VxAfXncz3DLJWWYdmfdEJmoc0x86ePwTNv rfLo+laRNqd8+Nmz9XlQ4dooDBvm2NgPADHRURg0aJDw/19//cXlzxqemoScE4exdd9pPDRrvlOP W2h4hEsitRKujcKGbTtx6lIZnq8L7iExSpiHRLp8DW9Cn6222dzCqk+a6TVB9AYJYcAniovd+gs+ USMYgIuqOAz/rNBm1JszOQPzlnm2WezxA3uaLVIAyFy3TghSAYAP3nvXprROQ5YuXSrKv1rzxRdN foZWzWLDhwuxdd9plzJoPaVrz3748I25WL6/TNhCkxvQwu/BKoDl/pNGqTJWfdLMzVNAhYtLwJiH R4s2EPAHXM8wy+IJlg0bhnxSaCOoOZMz8PrHX3t0/QPZW3H7oMHNFikAFBWXYOXKlcL/4zom4PjJ 00ju1kV0XEx0FDLXrcWYsfX1rY4fP96kwb9XvBa/Hj3m8dTGXR6aNR/DU5Pw2OZrwuYYVgeL32Ao i+4aQIW3BXOzpbYXBTjeZc/TwgPuwvWLEHaCqzTwGPr5dZuAk/nTx3g8ku7I/EiIhPIWMdFROPbr r9C1jRW1V5aX4eRvp9EhLtbmPY7j0COlu10rgZU5kzMwf8WmJgNnvE3e+RwkJHXB5N5hQgq1P1Ph udu1wpTPiuKeZbDuBkgDAJMwhKI79BcdZE7TWjb28iUMBfOwKEGkRVUcBq64aiPSlQtmeyzSjxc+ i2Hjpnk9eqmouARDht6JynJx5FFoeARSU1NtREp4DiNGDHcoUq2axfZ1K/D6x1/7XaSA5akw55H7 sepwBXKKLe5U7s4ovzxZSTgLc5q4jCbdoT8ablkp/IMvziXGVSPQMInP6W4YzUVFwzRWJwSaNCzB IxyioLHhk/c8KqdDGpW38RUx0VE4tHePU997ZXkZ+vXv51Ckw1OTsGrDTkS3jrX7vr+orq5EXIwW t8arkDneMg1jvyn2eRig+f5WgpUHAEAxUE7eCjq6s6BPYQVAR3emmJvEtUK5HqE+mVTzcSoY/x0n iPTQJT36vn9JJFJreUhPRFpZXoaM/l19LlLAMrK2T+iGR0YOROHZQ/XB5pwRxfmX8H+vzERYRAu7 Io3TqoQFU6BFCsBSDmjivdh8qgqH6uqhcmlan46qfJxKLFIAzE3jRCIFGsWjWqOnfFYNhaHA3doC 5tvrv/yaXyrw7y3FokdzWnIsvsw6iOiWOrc/4vyZ4xg+qJ+kk+5UChqz/jUcz7/zmcs7pviL4sIC xMW2xdAEdf2o6sO5qr0qKoppWWgcPSWyqdCqUIoZ+KToQqStyiuuNWuJcvPgSCEXf8qGQkzdWCgS 6fzpY7Dr2B8eiTT7q88lnRkap1Vh/vQxyLt0Ga9//LXkRAoA0S11mDCsHzafqkJemcU0yHdvugqi J3A9w2x2wmYGPmkjUsAfEf7WUTRNK+wdf+iSHtM2l9oIyrrbcYhGg9DQECQndUaHjp1xyx0ZTVbU e+/FRzHz9RXu98/HJOk06N/nJjzwrylIyxgfkIVSQ3ZkfoSdWy3ByRqNBi1btUJi9164OX2kUBDO ulvhnNu1eKluJa584w/vxn64GeFvd/LhtRqo1v06u9Vv4jU/65pdl2hTxGlVGDKgN6bNmitKzGtu pRKVgkbfxDZI7XMTOnfpjo5JyQhtEY0IrcUSYTDUovL6NdRWV6CmshwV10tQVlqKmuoKlJeVQ6+v RXV1/R9cZGQUIqNjkJDcE937DfboyeBLivMv4dZeSXafOr3itbjjtgGY9PQr6NOrF0JULHJnW+bO 3l5UuVs71eEs2bh1FuF/21bf4MEu0Q1Xc45GUU/oFa/FonffR+sOnTFySJrb11QpaNxza3eMfWgK 7rh/qk+23JEy+XkXkJyUgNIaM0Z1C0HrMBa7/jCJfkeVgobexOPIzDh0axXk1a3s7e5K3XU4lCMW O9Sjwzf4iqvEuGKwKGXanc423H7cV/t1Wn9MV0nSafDopAfx0KzXPK57+nfhmy+WY/iEJxCnVWHv Y60RE8Igp9iIb89U48ODVYIFRtgSnSMIeu2CV3LnrEmaAqwKymlZoMNaOdSjQwc1HdaKYlMfFbXx ndUuxwGYB1kMuEVVHCZkFrosqF7xWiydOw0//7AF504fQ86Jw/hh02rMmZwhRKdbcfWaacmx2LZm GX67UokZr334jxcpANz94HSMS09BXqkeb+62TMUSopWYNbAFcmfH4tvJbZCk0wj+fzAU+PbBzf7c hkmaVtjUR52KFGiikC8xGyzFexuEAVKlJigXX3QaBkZCGBjnWqJ83JmTDk9Nwpa9vznMIi0vLUF8 rM7l8LzhqUmYM/+NJiuieAtiqMKpvduxc+dO/LjvZxRcLYRB3QrDb+6Eu4YNxS13jQcVFNL0hfxE 7skjSOjeGwBwfFY7JETbToE2nawS6vk3e68GhoJxVjvRDopUeFtLUV82yKkWndaeotggih0kDowg WgW4W50H/jbsyEEXN9ICgIKrhSgpuOzw/TNH96PGhVF0XHoKjv28G1v3nfaPSM16fP3pu3jq4VHY uXMnlEoFBva7Bf363ITCwiIsWLUF/UY/ilaxHXAy+0vf98dFOif3ErasXLSnPkaWuqwXdupruJs1 36F5Iyp3awuRNgCAHfR8kyIFXCyNblw/UZyqYuChfPeiQ3NFw/lpj/fy3VrsWOvQ9+5xI3RtYmE0 GnDl0kXsP/Sr3bTfhoxLT8GcN5Y1a3MITygvLUF4eBjA2F+UFZ49hHnPPyNsrnbih/8iedD9/uyi Qw5kb8Ut6RlQKWjkPtseMSEM6FNVYLcUgRsWbeM1CnrlvEfz1Ib7LFihO/SHcsynLmnQpYPcjQMg uiAYZ8QBAMauLbCbOeptjv2826UK04Hk/16Ziekvv4eY6CgU5p0DVOF++VyO43Dq8E/448xRlF+/ jsiYlkjq2R8dk24EAHRpHYIzBdVYmhGDaX3DAROxCJIj4ONUMA+PFgzUxYyAAAAOQElEQVTzitX5 HgXWu+LPd4ZLlVzdjQOgioyAyTKHTetou5mBt0nSaQIq0vy8C3j1ibHo3TESwUoGkRoFeneMxI7M j0THPTZvMZK7dUFRcQlO7tvpl77NnTISMWEqpNxyG0ZNmoWHn34Vwyc8gRu6pKBdZDBefWIs7rj1 FgDA1tN1A4qCAt+pbgufPD2UH14Gu7EQMPDgk9wPqnfVn+8Ml0sOMwOfAqUWxws2DnQV4AjoPyyV 9kZ1C3Ea/e4NZv37cZ9e3xHFhQV4cuxgdLyhE15avh6nLpWhb2IbdO+ow6lLZRg2bhq++WK5cDxF M1jwnKWvOecu+Lx/33yxHAtWbREtPlUKGlo1C5WCRl6pHi8tXy/sSbXvTz1MdYtk0rpBkh9HwPxS gaA3/rAMQm5iExCtjgQ7YIZb13BZQe7GATA/W7wYMSEMXkp3vGV3c5k5Jh1TXnBestAXbFzxBhLj 47B0/Q/oFhuBDR8uRHlVLXafyMPuE3k48GM2VAoazz77nOi8djrLTWsd3bxM1KYouHwJ02fWp4LH aVU4PqsdyuZ3RP68Diib3xG5z3XA0owYJOkso6TexONoviV9mm9nZ+Gk5932Tjny57uzdQ/g5jbo zI33gWopTrfg7oyyWwu+YcHWf/eLwKhu3jXLaNUsVi6YjSWZWV69blOUl5Zg/OAeuO/RFwAAn70z D4fOleDeac+LPFw39k1D38Q2NgvJynLL6rpjlx4+6yPHcRg3rJ8obHLhnS1szE9xESym9Q3H0Rmt sTQjBioFjaN1u0iLRlRPUdEWfTSAatkFzI3up7i7JVSKZig2fa6ojYQwlrA9O7DbigEDDwVDIXO8 DkszYqBVNy9rIE6rwpzJGTh7Ic/vI+neHRvQvVOsEFcQomLRrVc/u3bf6upKnDhfYOOk+Hb7DkzN GICWiX180kdCCB4bfZvIQvLgTWGCmYk+VQV2YyHYb4pBn6oS7OHT+oZj7+P1uXMkhLFJtHMX8+1a m2uw6XPd3l4ScFOoAMDE9aHorsNFbVxqBEiUrWmGKjFC8ckVIQV2Wt9wrBnrftJYkk6DqRkDsH3d CvxeUI7XP/7ar8EexfmX8MjIgRgw7H7kleoxf/oYLH95BvJK9eifPkw0D7WyYOYElNaYMWXsSKGt vLQEJ8/kYsUax3sLNJcXp44SzGCA5Q/73RGW6QZVaoJikyW2lNlXBsXaAigX/Sk8+bq1CrKs+uto /Mh2h4ZFl63QXYd7tGEv4MHu0oD7cQAkhIH5vlaC6+zpbcVYvr8MWjWLxa++AF3bOBRczkN5aRGM RhMiWkQiQqtFh6Qe6HzjzQGL2ywvLcFbz07B4s+3QW/iEadVYfWnq5A2wmIBaZg0uHTuNMx4zbLn werFL+Hhp19Fkk6DY3+WClOCwrOH0LJTikN7a3Owl3qjUtDY+3hbdGtleYwrPnC84RnXLwLmoeIc qeZETHniz/cJ5n3LbUtUJmocF8NiKGJ4qh3RL+xEKl+7gTx4U5hQ9Gv+9DHEYDB4UuPMJ1y5eJ7M mZwhFGVTKWgyZ3IGqaqqsDn22M+7SZxWZSmeNiadzJ8+RihklnPisF/6azAYbMpmqhQ0+XZyG+He mG/XNl2sTBck3CP9wk7EdH8rz0pJJmpstGHet7xZpVc8Vjcx1RLjymFuxQGQKCVM09qChDAwcQQL d5UKcQBJOg2ee2YWxj7xYkDC7oxGI7I3fYYPli1B1uEcUcDLzz9sceqKzc+7gPS+3YWFU5JOg693 7vFp4YiGnz3+7jQbr5219DngZpImQ8E8Ihpcn3DP0pAc+fOnbgelCPbvaGqFy9lp+5fTxF8urwsi hrnxwvHfTm5DknQaYSSI06rInMkZ5Mj/viM8Z/bpSFRVVUG2rVlGpmYMsClpOS49hWz4cCFRKWiS lhzrcMT/afuXoiK5UzMGkIqy6z7tt5Vta5bZ9FuloMnacbr68o0T2xDCUB6Nioa58W6fa75da/uk dXF3Pmc0W+HuxgEAFr+v6UGdMFk3cQTrj1Vi8b4qkTlHq2bRL6UTBva7Bd173YLk1CE2+fLucK24 CL/s3oqDP2Zj14/7cODsFdHIGadV4cFRQzDthTeFUpY7Mj/CsHHTMC49BV98/ytKS4px6IevsXPr Bmz+fq9gAkpLjsXCd5f5JQimvLQEjz8w2CarQatmsWZsS2Frc+qyHspVVzyOISXhLCgD7/L5zfXn O6PZF/C4HoCdjFTAkgnw32OV2HZWb7f8jkpBo0NUMFpGaREaGoJQdRCio8S2uppaA6qrK1FZY0DB 1UJU1xpQWG5wGB5oFWiP3n3RIro1amsqoa+uRFlpKQquXELmV9twpqAaWjUruoZWzWL04Fts0mN8 BeE5rHrzBTz32rs23yVJp8H6sVGCrZTOrYHi83y/VuVrrj/fGV6ZM5i+n0+4X8RVAZ2tMBtCwllw Q6LAdQ+xyR/PKTbiUJ4ex/INOHiVRlFZjVdqR3mKdSeSgf1uQf8hGeiddpcoWa+6uhL7vv0v7rh/ ilc/lxCCLZ8twZy58+xGok1PjcDLd0QitG4kY45Wgt1U6FeR8nEqmB4TP+2YnhOguOMlr2jMKxch tWXEuGIwSG29KcPdiTgJYcD3CQd3Y6iwa7Q9TBzBhVITyvU8Kg088htMMWpMBGoFBbXScsMigmmE BtFoFcpCxVIoqjKjsIpDWS2PkmoOhZVmlOt55FeYcfYaEUQwPDUJI+6+GxFaLaJ0cYjt1BWxHZMc LvKMRiM+Xjgby1aswoZtO70WZlhdXYnVb7+IZStW2RVokk6Dt4dFCI96cATsjhK/b3AG2MnPD46A clqW265SR3htFWY+up6Yv5snavO0cAGJUoJPUINvHwzSOsgm2NYXmDiCkavzhcrW49JT8Oyr7zqN yirOv4TVS17G+6vWoajS6HH5oYYQnsO+nV/h8xXvY1PWz3anK3FaFebdHo4xKaFQ1D2FqCIjFOuv giow2Bzva7ieYaL9ogCAvfNVsD3GeE1fXruQL3f8IyEMiFYBEq0EwlmQcBZEzQBKGkRdN3FX0gBL AWYCGC2fR9XwgJEHVcNZItZDWBANYzlHzYBoGNHEv7HJDLCIov9NiWjfrh1aaCNRW1ODszlnkXsh T1TMrVe8FtOmTMZtI8cLcZ4ufTdCcOHsCez+ei1278rCd/tPOZxLD+qkxqTe4aKoe3AE7K5SSyn7 QFQJdzM/31O8atfyWj0Af8JYYi9NY1oJos0pNmLRnuvYeLLKYQKhSkFjaIIarcNYm4WfVs2ie0cd WreMRHRUFDQaDVSqYASr1bheeg3V1dUoLilB7oU8XLha4TQHLEmnwYSUYNzbPRRxEQ3iJOpC75hd gd0UxN38fE/xugHWuHkG4c82KFTrQT2AQECilDA90FI0zzJxBEfzDcgpMqK42mLViNYwSIhRokfr IOGxCwCnrhrw1ckqfP8nHG4m7ApJOg166hjcGh+MWzuqxeIEAAMP5lA5mH1lgd21Bg7y8xOHQjnq Pa/ryusXbG49gEDD9QwDN7CF0wVdU1QaeBy6pMfxfANOFxpRUGlGOadCda0BrUMsj+ewIBqtw1iE q2h00CqQEKNEUoxSWLmLO0VAn68FfaISzLHKgG4E0hB/+vN94tIy71tOzD8uEbV5mmsTKPg4FcgN avDtgkEiWEBdNwcrM4EqM4MuMIA6VwOq3Ay+Wwj4zhrwHYO9VqKRquJA/14D6nwNmN+qAr5pcmMa JnBaYQc+CbbfdJ9oyicX9SQO4G+BigbfPhh8fDBIyyDw7VSixZpdDDyocjOoIiOo6ybQF2pBFRgC /lh3SgD8+T6pfU4pgqnG+wJY6wH4a1+AgKDnLZkNDZ4cJIQBQlmQukqGVF3SI2o4S5zuX/AP12F+ vg+DTnyWdcckDKHouJtFbeaBLZodNf5Xg6riQBUYQOfpQefpLaOldcT8C4qUhDAwDxSv8um4m0X1 9n2BT9ND2TteAqgGwgyiwQ1zkLkq85eAGxYtns5QjOU++xifCtWf+wLI+B5v5Od7im8T7gGwA2aA ChankjisByAjaWzy84Mj3M7P9xSfC5UKjqCYATNFbd7aF0DGf9jNzx8w02tBJ03hc6ECANNjLKjo BFGbo3oAMhLEXn5+dAKYHmP91gW/KIWiGarxhNtZPQAZaWE3P/+Ol7wadNIUfhvSmLg+FJ0o3i7c UT0AGelgNz8/cajXg06awq/PXva2ZwG2wTzHzo7CMtLCZqdxVmW5j37Gr0KlI9o2a18AGf/isN5+ RFu/pz37fTXD9JkEKrytqK1xhQ4ZCcBQlvvSACq8LZg+kwLSHb8LlVIE2+4LEKME19c/1ZdlXIPr G24T6uhrf74zAmIfshsHMDjyHxcHIFVICGPZs7YB/vDnOyNghkw5DkC6BMqf74yACVWOA5AmgfTn OyOgriE5DkB6BNKf74yAClWOA5AWgfbnOyPgznY6ZYwcByAFHPjz6ZQxAeqQmICrgWZYOQ5AAjjy 59MMG/DRFJCAUAE5DiDQSMWf7wxJCBWQ4wACiVT8+c6QjFDlOIDAICV/vjMkI1RAjgPwOxLz5ztD UkKV4wD8i9T8+c6QlFABOQ7AX0jRn+8MyQkVcBAH0OhHlWke3OBIyfnznSFJodqNA+gTLscBeAk+ TgWuj3g6JQV/vjMkKVRAjgPwJVL15zvDJ0XSvAEVHEGZf/mCmL9/RWizxgEwv1UFsGd/bbiuIZL1 5ztD0p3jOTMxfToSpDgn0F3520JFJ0Ax8WvJuEodIdlHP2A/DkDGu0jJn+8MSQsVsB8HIOMdpObP d4bkhQrYiQOQaT4S9OfLyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjI/H34f4DnQZLCUbKg AAAAAElFTkSuQmCC "
+ height="18.421789"
+ width="18.421789" />
+ <path
+ style="fill:#455c91;fill-opacity:1;stroke:#485c90;stroke-width:0.065px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 13.984312,12.726634 0.03325,2.630469 c -0.626212,1.348342 -1.864809,3.416425 -2.757403,4.184964 l -0.113641,-0.140573 -6.1504829,-0.01206 c -0.316416,-0.01349 -0.654604,0.350565 -0.635432,0.60017 l 0.605343,7.881219 c 0.01985,0.258488 0.294567,0.581835 0.581835,0.581835 l 5.4774769,0 c 0.214377,0 0.508195,-0.213055 0.517186,-0.476047 l 0.02351,-0.687624 c 0.177836,0.252545 0.659175,0.628853 1.075513,0.628853 l 7.381664,0 c 0.924147,0 2.348823,-0.984515 1.880679,-2.644705 0.529304,-0.423588 0.842626,-1.143065 0.52894,-2.056992 0.555062,-0.453627 0.95877,-1.306413 0.493678,-2.068746 1.479159,-1.239472 0.519291,-2.973824 -0.622974,-2.973824 l -4.972045,0 c 0.185997,-0.813338 0.477909,-1.644292 0.458416,-2.738738 -0.01684,-0.945207 -0.644701,-2.322763 -1.093145,-3.056102 -0.187053,-0.30589 -1.913467,-0.895396 -2.712363,0.347897 z"
+ id="path3009"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccssssscsccccscssc" />
+ <path
+ style="fill:#6e7fb3;fill-opacity:1;stroke:none"
+ d="m 5.0692251,20.14975 5.1806329,0 0.0121,7.613594 -4.6117319,0 z"
+ id="path3764"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:#6475ab;fill-opacity:1;stroke:none"
+ d="m 5.6260221,21.178614 4.1033522,0 0,6.124767 -3.5828682,0 z"
+ id="path2994"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#edf5f7;fill-opacity:1;stroke:none"
+ d="m 16.482302,18.888451 c 0.237198,-0.953632 0.410241,-2.014256 0.524972,-3.030803 0.0282,-0.249886 0.02697,-0.465789 -0.01088,-0.672916 -0.149763,-0.819429 -0.492693,-1.551175 -0.814688,-2.288077 -0.318932,-0.250948 -0.943214,-0.350861 -1.411378,0.02979 l 0,2.586337 c -0.785404,1.538476 -1.671195,3.019589 -2.765007,4.381833 l -1.031019,0.719827 0,5.987243 0.714095,0.0028 c 0,0 0.946752,0.578944 0.99646,0.55409 0.08285,0.04142 7.381163,0.02059 7.381163,0.02059 0.395654,0.0082 1.82301,-1.034467 0.913858,-1.848307 -0.121149,-0.07432 -0.105237,-0.297756 0.0083,-0.372073 0.568248,-0.102002 1.256969,-1.17096 0.537522,-1.733988 -0.122527,-0.136544 -0.03468,-0.350662 0.110298,-0.366631 0.425004,-0.205227 1.152864,-0.892181 0.492078,-1.721683 -0.13333,-0.0679 -0.13908,-0.24295 -0.01515,-0.348641 0.639145,-0.08914 1.448755,-1.545236 0.108634,-1.89517 z"
+ id="path2987"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cssccccccccccccccccc" />
+ <path
+ style="fill:#dce4e7;fill-opacity:1;stroke:none"
+ d="m 11.500825,26.603743 0,-6.359462 -0.528281,0.358422 0.0024,6.000473 z"
+ id="path3002"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:#dce4e7;fill-opacity:1;stroke:none"
+ d="m 15.460842,12.670845 0.613058,2.64244 -1.623773,2.883025 c -0.168273,0.29877 0.03515,0.601651 0.277532,0.613058 l 1.760469,0.08284 c 0.268792,-1.21509 0.593159,-2.696958 0.527037,-3.612067 -0.120278,-0.638095 -0.379047,-1.44522 -0.833741,-2.393188 -0.253938,-0.172262 -0.464918,-0.216113 -0.720582,-0.216113 z"
+ id="path3000"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccsscccc" />
+ <path
+ style="fill:#dce4e7;fill-opacity:1;stroke:none"
+ d="m 19.967851,18.884443 c 0.576951,0.54845 0.230529,1.581917 -0.27675,1.947465 -0.09622,0.0555 -0.11695,0.192137 -0.04686,0.281187 0.559147,0.639226 -0.184326,1.716857 -0.421781,1.827717 -0.07698,0.06918 -0.08661,0.149591 -0.0703,0.234322 0.636824,0.892478 -0.09901,1.635413 -0.351484,1.804285 -0.08352,0.07488 -0.109404,0.204568 -0.04686,0.328051 0.555499,0.87442 -0.08777,1.493624 -0.454649,1.878505 l 1.812641,0.0038 c 0.348549,0.01747 1.811331,-1.045389 0.841892,-1.880176 -0.108877,-0.09376 -0.03864,-0.336024 0.0358,-0.349382 0.479935,-0.08613 1.327001,-1.100218 0.534201,-1.743525 -0.05537,-0.04493 -0.102552,-0.267797 0.108928,-0.361267 0.655022,-0.28951 1.059493,-0.985784 0.49944,-1.725413 -0.148962,-0.08391 -0.130345,-0.265904 -0.01336,-0.338019 1.094277,-0.325978 1.119441,-1.776095 0.103493,-1.903211 z"
+ id="path2985"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccsssscccc" />
+ <g
+ transform="matrix(0.065,0,0,0.065,4.3429681,11.929852)"
+ id="g3779">
+ <path
+ transform="matrix(0.59806884,0,0,0.59806884,30.309966,82.598928)"
+ sodipodi:open="true"
+ sodipodi:end="12.541589"
+ sodipodi:start="6.2585156"
+ d="m 80.03736,237.47695 c 0.188395,7.63513 -5.848379,13.97735 -13.483511,14.16575 -7.635132,0.18839 -13.977353,-5.84838 -14.165748,-13.48351 -0.188395,-7.63513 5.848379,-13.97736 13.483511,-14.16575 7.634528,-0.18838 13.976476,5.84746 14.16571,13.48196"
+ sodipodi:ry="13.828837"
+ sodipodi:rx="13.828837"
+ sodipodi:cy="237.81807"
+ sodipodi:cx="66.21273"
+ id="path3780"
+ style="fill:#ffffff;fill-opacity:1;stroke:none"
+ sodipodi:type="arc" />
+ <path
+ transform="translate(-0.24218783,0.04882811)"
+ sodipodi:open="true"
+ sodipodi:end="12.541589"
+ sodipodi:start="6.2585156"
+ d="m 69.384446,223.01414 c 0.0143,0.57962 -0.443975,1.06108 -1.023589,1.07538 -0.579615,0.0143 -1.061079,-0.44397 -1.075381,-1.02359 -0.0143,-0.57961 0.443974,-1.06107 1.023589,-1.07538 0.579569,-0.0143 1.061013,0.44391 1.075378,1.02348"
+ sodipodi:ry="1.0498047"
+ sodipodi:rx="1.0498047"
+ sodipodi:cy="223.04004"
+ sodipodi:cx="68.334961"
+ id="path3782"
+ style="fill:#000000;fill-opacity:1;stroke:none"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:type="arc"
+ style="fill:#000000;fill-opacity:1;stroke:none"
+ id="path3790"
+ sodipodi:cx="68.334961"
+ sodipodi:cy="223.04004"
+ sodipodi:rx="1.0498047"
+ sodipodi:ry="1.0498047"
+ d="m 69.384446,223.01414 c 0.0143,0.57962 -0.443975,1.06108 -1.023589,1.07538 -0.579615,0.0143 -1.061079,-0.44397 -1.075381,-1.02359 -0.0143,-0.57961 0.443974,-1.06107 1.023589,-1.07538 0.579569,-0.0143 1.061013,0.44391 1.075378,1.02348"
+ sodipodi:start="6.2585156"
+ sodipodi:end="12.541589"
+ sodipodi:open="true"
+ transform="translate(3.3466792,0.04882811)" />
+ <path
+ transform="translate(3.3466792,3.6865236)"
+ sodipodi:open="true"
+ sodipodi:end="12.541589"
+ sodipodi:start="6.2585156"
+ d="m 69.384446,223.01414 c 0.0143,0.57962 -0.443975,1.06108 -1.023589,1.07538 -0.579615,0.0143 -1.061079,-0.44397 -1.075381,-1.02359 -0.0143,-0.57961 0.443974,-1.06107 1.023589,-1.07538 0.579569,-0.0143 1.061013,0.44391 1.075378,1.02348"
+ sodipodi:ry="1.0498047"
+ sodipodi:rx="1.0498047"
+ sodipodi:cy="223.04004"
+ sodipodi:cx="68.334961"
+ id="path3792"
+ style="fill:#000000;fill-opacity:1;stroke:none"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:type="arc"
+ style="fill:#000000;fill-opacity:1;stroke:none"
+ id="path3794"
+ sodipodi:cx="68.334961"
+ sodipodi:cy="223.04004"
+ sodipodi:rx="1.0498047"
+ sodipodi:ry="1.0498047"
+ d="m 69.384446,223.01414 c 0.0143,0.57962 -0.443975,1.06108 -1.023589,1.07538 -0.579615,0.0143 -1.061079,-0.44397 -1.075381,-1.02359 -0.0143,-0.57961 0.443974,-1.06107 1.023589,-1.07538 0.579569,-0.0143 1.061013,0.44391 1.075378,1.02348"
+ sodipodi:start="6.2585156"
+ sodipodi:end="12.541589"
+ sodipodi:open="true"
+ transform="translate(-0.24218783,3.6865236)" />
+ </g>
+ </g>
+</svg>
diff --git a/src/skin/socialwidgets/FacebookShare.svg b/src/skin/socialwidgets/FacebookShare.svg
new file mode 100644
index 0000000..21439c0
--- /dev/null
+++ b/src/skin/socialwidgets/FacebookShare.svg
@@ -0,0 +1,214 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="80.97097"
+ height="31.697708"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.92.1 r"
+ sodipodi:docname="FacebookShare.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="12.03"
+ inkscape:cx="4.5433649"
+ inkscape:cy="25.000711"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="2560"
+ inkscape:window-height="1598"
+ inkscape:window-x="0"
+ inkscape:window-y="54"
+ inkscape:window-maximized="1">
+ <sodipodi:guide
+ position="57.0938,-1.0684576"
+ orientation="0,53.46875"
+ id="guide3203"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="69.043564,34.575765"
+ orientation="-24,0"
+ id="guide3205"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="57.0938,31.738415"
+ orientation="0,-53.46875"
+ id="guide3207"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="0.06046645,31.62492"
+ orientation="24,0"
+ id="guide3209"
+ inkscape:locked="false" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-0.60620022,-8.9938749)">
+ <rect
+ style="fill:#f0f0f0;fill-opacity:1;stroke:#d7d7d7;stroke-width:1.17951703;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="rect2985"
+ width="68.453804"
+ height="24.533333"
+ x="1.1959587"
+ y="9.5836334"
+ ry="2.292042"
+ rx="2.8026814" />
+ <text
+ xml:space="preserve"
+ style="font-style:normal;font-weight:normal;font-size:12.80000019px;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#535353;fill-opacity:1;stroke:none;stroke-width:1.06666672"
+ x="27.332897"
+ y="26.632292"
+ id="text4002"><tspan
+ sodipodi:role="line"
+ id="tspan4004"
+ x="27.332897"
+ y="26.632292"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.80000019px;line-height:1.25;font-family:Tahoma;-inkscape-font-specification:Tahoma;fill:#535353;fill-opacity:1;stroke-width:1.06666672">Share</tspan></text>
+ <image
+ y="21.041676"
+ x="61.927261"
+ id="image3042"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKoAAACqCAYAAAA9dtSCAAAABHNCSVQICAgIfAhkiAAAIABJREFU eJztnXl4E9Xex7+zJE2TbqQLBGiBIrQFikUWsSxWKSIoFMSFRa6yiYoXFMUFxKuooKIICq8ioiJC uQIioCDWAlcB2ZRVoBVQCrR0oXRvtpnz/pFm2mmWJmmWUefzPHkeOJmZnGS+PXPObzuAjIyMjIyM jIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjJehAt0BV+DLLhPjyqGAWR/orvx9YFVQTt0BOqLt X0IDdKA74Arm3W/JIvU2Zr3ld/2LIHmhcnmHCH92R6C78beEP7sDXN4hEuh+uAIb6A44g+fMxPTp yEB342+N+fv54DkzoRlW0lMAaQv12HqQ4hxRG7uxEMxvVQHq0V8frmsIzPe2FP5PinPAH1sfwB65 hmSFSmrLiHHFYFEbdVkP5peKAPXo7wHzSwW4vuEgbVVCG/fTUpDaMkIFR0h2VJXsHNX803sgtWWi NnZbcYB68/ei8e9Iastg/um9APXGNSQpVL44l3C/rhO1MYfKQefJK39vQOfpwRwqF7Vxv64DX5wr 2YWVJIVq/n4+QLj6BgMPJuta4Dr0N4TJugYY+PoGwll+d4kiOaFyOTsJn3dQ1MZmXQNVxTk4Q8YT qCoObKM/fj7vILicnZIcVSUlVGKqJebsN0RtVJERzIFyB2fINAfmQDmoIqOozZz9BoipVnJilZRQ uUOfgJRfFrWxO0oATnK/298Djlh+3waQ8svgDn0SoA45RjJC5csuE/P+D0VtdG4N6LPVAerRPwP6 bDXo3BpRm3n/h+DLLktqdJCMUG38+RyRzVF+gt1WLH5qSTAOQBJCtefPZ/aXgSoxOjhDxptQJUYw +8U2a6nFAQRcqDxnJo3NIlQVB3ZXaYB69M+E3VVqY1mxxgEEqEsiAi9UO/585rsSQM87OEPGJ+h5 y+/eACnFAQRUqKS2jHA/LRW1yf78wMH8UgHqstj7Z40DCFCXBAIqVNmfLz2kGgcQMKHa9ecfrZT9 +QGGztODOVopapNCHEDAhGrXn79dHk2lALO9WHJxAAERquzPlzZSjAPwu1Blf/5fA6nFAfhdqLI/ /y+CxOIA/CpU2Z//10JKcQB+Farsz//rIZU4AL8l93F5h4hp7XhRmxT8+SRKCT5BDb59MEgEC6gZ yxtmAqrMDPpiLegz1aAKDAHtZ6CwxgFwA1oIbdY4ACauj9+SAf0iVMJzxPhJhqgt0P58PlED8yCt KBuzMSRGCb6zGhgcCeqyHmx26T9ymsLuKgXfIwwkhBHazN/PB+E5QtGMX8TqF6FyRzOl489X0TCN bgm+W4ioOafYiFNXjSip5lBt5BGtYZAQo0SP1kFQMBRIWxVMD7UGc6gc7Nbif9biry4OoHE9AO5o pt+64HOhSik/n4SzME1qAxKjBAAUVXH48OcyfHigAqU1ZrvnaNUsxqaE4LnbtIgJYcD1CQeJUEDx ef4/SqyBrgfg88WUZPz5Klok0jW/VKDzW39iwa5ShyIFgNIaM5bvL0PKu3nIPmdZAfOd1TCNaeWX bkuJQMYB+FSoUvLnm4dGCSJd/ON1TN1YCL3J9alHaY0Zd626gk0nLeWE+G4h4PpF+KSvUiWQcQA+ ffRLxZ9PdEHg+oQDADadrMKcRoZsd5i8oRDdWimREK2EeXAk6OOV0nX9MhT4NkEgsSqQcBYIYUEU FCgTAUw8qCIjqGsmUJf1Ln8HZnsxuC4aIKhujPNTHIDPhMrl7CSmr54Qf1iA/PlcX4tITRzBC99d b9a19CYes7YV49tJbYAgGtzAFmC3ey58X8AnasD1DAOfoAEUrk0fqct6MGeqLSkpTha51jgA893R 9Z9XFwfAJAzx2VzVJ0IlplpiXDlM1EaVmgLmz+e7WFb4W09XI6/U8bRDq2YRomJRVGl0Oi3I/r0G 2edqMOgGNfgeYYBEhEp0QTDdE2PX5FZUxeF6LYdyPQ+1gkKYioEulIGizrpE2qpgbquCOU0Ldk8p mP9dd7hYZA6Ug0uNANEqhDZrHAClCPaJWH0iVLv+/MYeDj9BopSC/W+HAxvouPQU/GfxSnRO7gUA MBqNyFz2Gh59/nWHgs08WolBN6hBQhhwPcNAVXMgkQogiLY8ZhU0iJ3RjKrhAAMPqtxseeyWmy3B H838bbh+ETAPjQLqhFdUxeGLXyuQfa4GR68Y7S4YVQoa3WIjcHMrHg+khKJPrApQUDAPjgSXpIFi db79J2CdR9H0UGuhyddxAF5XP19x1WKOauAqpXNroPj0irc/yrX+xKlgeiwWAHDXJ1eQ/bvYdz1z TDqWZGbZPXfjijdw36Mv2H1Pq2ZxcU57YURqFhwBVWAAnW8AlacHfa4GVLljS4QIhoJ5dEtwPUIB AJUGHu/+eB2Lfypza7EIAEk6DVaM0loEC0tUm/KDSw6nAqaJbSwOESusCsppWaDDWnldV16/oHHz DHHqM0egXJIXMFcpn6gR/vJ7vJePMwXiUbWkqBCR0TEOz+/dMRJHLtj3oB2f1Q4J0UpRW6WBx/Va HhV6DjUmgsoGAcihQTTCVTRaBDOIaeDlsQdVZARzvNK5+5ahYPpXa0Esp64acM+aIqfTG1dYMDQK swZaXKbM0UqwX161exyJUsL4ZJwwigMAnTgUylHveV1XXn30S9GfT5WYhH/31DE4U1D/nkpBOxUp ADwweiSOLLL/SPuobs59ttiI/CoKf5TUujyKqRQ0YkKV6NmaRVKMEl1bBWFAh2BBwCTGYlWwum+Z Y5UWJ4l1dGMomMa0EkSafa4Goz8vcHsUtcecHSVo10KB0ckh4HqEgj5QZtek6M84AK9djPAcMX52 D0jh6fqLV3FQvvNnwFOfjXPjQUIYbDpZhfHrCkTvnTqyF1179nN47p6t63BbxniH77uDK4u1JJ0G t3dQYFiSBgM7BIunFgYezKFyMPvKwA2JEh733hRpw77mPNsOoUG001EVKhrGp9uL4gColl2gfPgr eDMOwGsGf+74BpFIAenk59OnLUb6EV00SNJpRO8tfdX+HJTjOOzI/Agr318kak/SaTAuPQVTMwa4 9NkqBY2pGQPww6bVKKrQ4+K1WtQaOeRfysMPm1Zj0exJGJeegjitZV54pqAay/eX4a5VV9BuwZ94 elsxTl2te/QH0eAGtIDx+Q4+FSlgcXCsqzPuc91DAJUDqdirB1B4GtzxDV7tj1cUb/XnN3SVUpf1 UC6/5I3LN5uGc6nsczW4a5V4YffT9i/Rf+h9AIDfftmHlW+/jDVb96C0xow4rQr9b0rEqHsfwOD7 piBcG4UdmR/hwSnTnbpe47QqPP3YQ5g4+w2EhrvmwbqY+xuyNq3G1m++QdbhHJH4esVr8VTfIIxO rg+mOXXVgDtW5jvtR3MY1EltsRcDUKzOdxo5ZpweKzKLUcERUE7LgqT2BTB9P5/oF3YSvbg4FSGA ZF6mYVFC3+bcriUAhJdWzZLP3plH0pJjhf+PS08hP2xaTXjOTBry2TvzROc2fsVpVWTlgtnEbBaf 5y5l14rJygWzSa94cV+TdBqydpyO5M2NJ3FaldO+NPx+49JTyPKXZ5CVC2aTOZMzbK5r76VS0MJv Zu4X4fT35eJUNhowfT9fOlE7fHEu0b+RKO7g/a0CLkybF0MRw+z2Qh8fvCnM5sb0iteSlQtmk6qq CrviWTR7klMxLJo9iRgMhmYJ1B5H/vcdGZeeYiMiR31p+Jo5Jp2UXSu2uSbP806/j/VV/HJHyz0d FtX0YHB/K7FY30gk3ooDaPYc1Zy9EDb+/J3S8NQIMBTMQyJFnpRH+oZDpbB8/bTkWOzeshaHz1/D lBfegkYTKjqdEIK5U0ZitoPV/7j0FJw8k4Nn3loFpVJp95jm0HPgEKzNOoqcE4cxLj0FAJqck2rV LHZvWYslmVkI10bZvE9RFJ55axWGpya51AfKhbUGs7PEth5A9kKXrt8UzRIql7OT8H/sFbWxP153 3VjtB0iUEsZH2womlKIqDlM2FGLg/11Ct9gI7N6yFrtP5CFtxDj75xOCaaNuxYJVW2zei9OqsPO/ K7E26yhax8X79HsAQOfkXlibdRQ//7AFveK1Do9L0mlw9MQph9+pIa2ibUVsRatmEWoNPjE0LVSq 3Az2R3EsBf/HXq/UA/BYqHbz80tNFh+xROATNTA+UT/Jzz5Xg/4f5GPjySosmj0JB3KLmryZ00bd ipVbfrJpn5oxAKcuFOCO+6f4pO/O6DtoBA7kFmHR7EnCU8FKkk6D/x05g7iOCU1ep7K8DDt/Ouzw /VvjGyyOLrnmRGD+dx1UqUnU5o16AB4b/KXkz7cH1zMM5lExFsM4R7BwVykW7CpFnFaFAz9m48a+ aU1eY+6UkTYi1apZrF6xBHc/ON1rfa2ursTh7G04ffQgcs+eRnFJCSprDHj1nf9z2E+GYfDMW6tw 2933455RIwVvVP8+NyFK17bJz6wsL8OIAd2derHu7V43BTLwoK+4mNwYgDgAh/AVV4l+UbJo4myc 2CbwC6a6l7lfhNCv4pc7kkGd1AQASUuOJUVX811awNhbaKQlx5IrF897ZYF05eJ5smj2JJKWHGt3 YbRo9iSXr1VRdp0MT00Szh2XnuJ0UbdtzTKSpNM4XUQl6TSk8rUbLAupUTFu3wPjxDbihdWiZMJX XPXvKGbcOkvcidduIHyUMuACbSzS3Oc6CDckLTnW4Wq+MRs+XGhz4+ZMzmi2yYnnebJtzTKRqOy9 0pJj3b622WwmUzMGCNcYnpok6u/Fc2fJ0rnTXDZL/fh4bP29DWfdvg98lJLo64QuDGZbZ3ksVLeN sXb9+T9dl0TwMNczTMiUzCszI31lAfJK9egVr8WeE3/arObt8cuPO9E/fZiwqvbGo57wHD5f8gre fHuxTVCMPY787zsk970Nl86fQcGfuTDU1uJ6cT7CWkRBHRqOFjGt0T6xu13rxItTRwkLv+GpSWgV HYW9h361+7lJOo3d9rXjdIJjgc26BsbDtHbzsChRHAAAKMavhSdxAG6dIGV/Pp+ogelBHcBQKKri 0P+DfOSV6qFS0Dj+y0Eh1tQZ14qLcFNiO2HelqTTYMO2nU5jAZrimy+W45X/vOQwAssejgTUmDit CvFtonFj1wSk3zUSt436FzSaUDw5djCWrv+hyfNX3tsSt3ZU47PD5fjwgCUreM3Ylhh0gyXQhc6t aV62rRfjANw62Hx0PTF/N0/Uxm4sDHgpcxLOwvhUOyCIRqWBx8AVV4UbvfzlGXj8P0ubuIJlNMro 3xXb9p8BYLGtfr3nV7s2SFc4f+Y4npoyVrieP1ApaAzunYBHHpuOzNUfY90Px5wePz01Au8Mt6SU mDgCvZkI5ig6twaKzIJmD0ANn3JW2DtfBdtjjG+ESmrLiPGjO0Fq6utmSsKfz1AwPtpWMEE1DI5O S47FruMXQVFNf823n50sGPTHpafg028PemS85zgO777wCOYt+czrgSLuEKdV2V3Rx2lV6BRJIzFa iWFJGmH0bIi3i2zYxAGoI6F85Du34gBcNk+Zf3pPJFJAGvX2zUMihR9hftY1UQT/ko8+d0mkB7K3 Yt6SzyzXmD4GL76/zqXzGpN78gjGjxzi1mPeVzQWaa94Lb4aG+EwYJsqNQE1HNhtxV5PZ2e3FQtZ FgBAaq65XQ/AJYO/lPLzG8LHqcClWiKTss/VYEGDSf/UjAEu2Uory8vwwP0PQG/i8dk78zBvWaZH Iv144bO4sefNkhCpPY5cKMXJq2JbKFVqAn2qyrIY/u9VKJdf8sk99UY9AJdGVEn68+tyhcBQqDTw eGxz/WivVbNYuHKjS5d5+qERKKo0YvMnizFy4lNud6O6uhKPjBzY5HxQCjyzvQxHZ1ge9cyhcrCb i/z22czOEtt6AG7EATQ5okrVn8/1DRcqn7z8/TXRo+7Jifc2mWICADsyP8KmrJ/xzfpPPRLp+TPH 0buT7i8hUsASlG2t9ML1CHMcDO0DmhsH4LSnxGyQpj9fRYNLswRlnLpqwPIG+3hq1SyefP2DJi9R WV6Gp5+ehW+3bsKge/7l9Fij0Tbna++ODejTq5dLZiQp8e6Buse/ggLXM8yvn+0wDsBsaFKsToXK HfxYkv58LjVCsM0918jR0DI8CCMGdEeX1iHYu8NxOsSSuY/hkzXr0HfQCKeftWfrOky862ZR2+rF L2FwxhifRdb7kiMXSoXUFuv83m/YqTBOyi+DO/hxk6c6FCpfcVWS9fZJCANzXSpv9rkamzz9MwXV 2HPyEnp07SSklzQmNycHw+5/uEmR7sj8CEPvnYDv9p8Cx1nm6K8+MRYPP/1qQE1PzeXTwxa7N9Eq wMc5LmTsCxzuC9BEHIBDoZr3SLPePjewhTAh/8/uWrvHaNUsFq3a5PAaHW+4AT0HDnH6OdlffY57 HnoMehOP0hozTh3+CU+OHYyXlktjE9vmsO1s/X0lsf4VKuBgX4A9zvcFsLvql2J+PgCQKKXIHOXI FPTmi085DWRmGOfFHw5kb8XdYyaKRs2x99ztdD46PDUJwybMQLt27dC6dWtUV1fjxIkT2LZtK3Zl 7ZTUCJxXqkdemRlxESz49sFg9pU1fZIXsVsP4LdtTusB2DRK2Z9vLSFj4gj6LC+wKxx3vFH2OH5g D24fNNjl+Wdyty548623MXToUIfH5Obk4KlZT2H79h0Oj/E31sATqtQE5aI//d8BN+MAbEZUqebn 84kaoSrIJ4cr7IpUq2axenOWxyLNz7uAEXcNdVmkw4YNxfp165pMh+6ckIBvv92OJ5+ciaVLvVOh OU6rwo2JHdAqOgrRURYLSHV1NS7kXcG5P/KatEbs/7MWo5NDLHlkDOX/BbK9fQGc1AMQCZXXVxKT ROrti1DRFuM+LDlPr2TZf+SvWPyqSykY9qiurkTGbb1drtuU3K2LjUg5jsOGL/+LAwcPIjExCRMm jBeF4i1ZshS///67xyNrr3gtHhg9EvdNmYV2nbs6PfZacRE2f/w21maux56TtvEY+RX1f4ykhSIg 0zq7+wL8uAS8vpLQqlDHo41U8/NNo2KE/ozqFmI32HdqxoBmBTQ3Tkdu6rV9+3bRNTLXrSUx0VGi Y7RqlnzwwQei4/Iv5bmc6mx9pSXHku3rVnj8/Y79vNsmWLtXvFYS99jVegDCql+y/vxEjais+eZT VTbH9IrXYtmXTcdfOuK1f49zy7uU3K2LaE66Y8cOTHxoAoqKxTZdVhOB0aPE+2vp2sZi2uPiStzO GJ6ahOnTH4dBX40D2VtRcNn9aLUb+6Zh677T+GHTaqF0UHVtvd+f7xu4vQjcjgMwrp8oVvZ8z1IQ vPniw1miryuAkDc3nmjVrM1oo1Wz5OK5sx6PNps/WezW6AaAzJw5Q3SN5G5dbI5RKWiyb98+u5+5 fft2tz+z8XdOS44ly1+e4XYOlzW/SpRu4mKBCZ/e5/mN0lbWTxQJlQYc+PP3lAbWn89Qloj9Opvp xC+v2ixyVAoaWzau83heeiB7K8ZOe8bt8xIT64s2FBcW4OSp0zbHTHv8CaSmpto9v2N882oAlNaY sefkJUx/+T20adcR4wf3wPkzx106NzQ8Aht3H8Pg3gm4Y+WVei/VgBZ+d6laocrNYPeI1x2N4wBo qfrzzaNbOowztbLm/dcdep+aIvfkEdw1YrRH9s127doJ/86/aj8C6cLhLDz55Eysz1yHHTt2oLiw vtxlpLaF3XNcRatm0Stei7TkWKQlxyL3Qh6GD+qH1Ytfcul8pVKJjbuPoW9iG9yxMh9FdeXPzRkx ILqgZvXNU5qKA2Cl6M/nbteKyiousJNctmj2JNw77XmPrp978ggGpw3w2Fd/8eJF4d/tY9vYPWbb /jPA/jOwJsFs374dQ4fqAADXSt0fBIanJmH06Hsx+N6HHTozKsvLQHgOFO3coQFYxPr1nl9xS7f2 uCezDLsnaaFQWIoDK9/L8//9d1QPoC4OgOaOrBEdT1VxAfXncz3DLJWWYdmfdEJmoc0x86ePwTNv rfLo+laRNqd8+Nmz9XlQ4dooDBvm2NgPADHRURg0aJDw/19//cXlzxqemoScE4exdd9pPDRrvlOP W2h4hEsitRKujcKGbTtx6lIZnq8L7iExSpiHRLp8DW9Cn6222dzCqk+a6TVB9AYJYcAniovd+gs+ USMYgIuqOAz/rNBm1JszOQPzlnm2WezxA3uaLVIAyFy3TghSAYAP3nvXprROQ5YuXSrKv1rzxRdN foZWzWLDhwuxdd9plzJoPaVrz3748I25WL6/TNhCkxvQwu/BKoDl/pNGqTJWfdLMzVNAhYtLwJiH R4s2EPAHXM8wy+IJlg0bhnxSaCOoOZMz8PrHX3t0/QPZW3H7oMHNFikAFBWXYOXKlcL/4zom4PjJ 00ju1kV0XEx0FDLXrcWYsfX1rY4fP96kwb9XvBa/Hj3m8dTGXR6aNR/DU5Pw2OZrwuYYVgeL32Ao i+4aQIW3BXOzpbYXBTjeZc/TwgPuwvWLEHaCqzTwGPr5dZuAk/nTx3g8ku7I/EiIhPIWMdFROPbr r9C1jRW1V5aX4eRvp9EhLtbmPY7j0COlu10rgZU5kzMwf8WmJgNnvE3e+RwkJHXB5N5hQgq1P1Ph udu1wpTPiuKeZbDuBkgDAJMwhKI79BcdZE7TWjb28iUMBfOwKEGkRVUcBq64aiPSlQtmeyzSjxc+ i2Hjpnk9eqmouARDht6JynJx5FFoeARSU1NtREp4DiNGDHcoUq2axfZ1K/D6x1/7XaSA5akw55H7 sepwBXKKLe5U7s4ovzxZSTgLc5q4jCbdoT8ablkp/IMvziXGVSPQMInP6W4YzUVFwzRWJwSaNCzB IxyioLHhk/c8KqdDGpW38RUx0VE4tHePU997ZXkZ+vXv51Ckw1OTsGrDTkS3jrX7vr+orq5EXIwW t8arkDneMg1jvyn2eRig+f5WgpUHAEAxUE7eCjq6s6BPYQVAR3emmJvEtUK5HqE+mVTzcSoY/x0n iPTQJT36vn9JJFJreUhPRFpZXoaM/l19LlLAMrK2T+iGR0YOROHZQ/XB5pwRxfmX8H+vzERYRAu7 Io3TqoQFU6BFCsBSDmjivdh8qgqH6uqhcmlan46qfJxKLFIAzE3jRCIFGsWjWqOnfFYNhaHA3doC 5tvrv/yaXyrw7y3FokdzWnIsvsw6iOiWOrc/4vyZ4xg+qJ+kk+5UChqz/jUcz7/zmcs7pviL4sIC xMW2xdAEdf2o6sO5qr0qKoppWWgcPSWyqdCqUIoZ+KToQqStyiuuNWuJcvPgSCEXf8qGQkzdWCgS 6fzpY7Dr2B8eiTT7q88lnRkap1Vh/vQxyLt0Ga9//LXkRAoA0S11mDCsHzafqkJemcU0yHdvugqi J3A9w2x2wmYGPmkjUsAfEf7WUTRNK+wdf+iSHtM2l9oIyrrbcYhGg9DQECQndUaHjp1xyx0ZTVbU e+/FRzHz9RXu98/HJOk06N/nJjzwrylIyxgfkIVSQ3ZkfoSdWy3ByRqNBi1btUJi9164OX2kUBDO ulvhnNu1eKluJa584w/vxn64GeFvd/LhtRqo1v06u9Vv4jU/65pdl2hTxGlVGDKgN6bNmitKzGtu pRKVgkbfxDZI7XMTOnfpjo5JyQhtEY0IrcUSYTDUovL6NdRWV6CmshwV10tQVlqKmuoKlJeVQ6+v RXV1/R9cZGQUIqNjkJDcE937DfboyeBLivMv4dZeSXafOr3itbjjtgGY9PQr6NOrF0JULHJnW+bO 3l5UuVs71eEs2bh1FuF/21bf4MEu0Q1Xc45GUU/oFa/FonffR+sOnTFySJrb11QpaNxza3eMfWgK 7rh/qk+23JEy+XkXkJyUgNIaM0Z1C0HrMBa7/jCJfkeVgobexOPIzDh0axXk1a3s7e5K3XU4lCMW O9Sjwzf4iqvEuGKwKGXanc423H7cV/t1Wn9MV0nSafDopAfx0KzXPK57+nfhmy+WY/iEJxCnVWHv Y60RE8Igp9iIb89U48ODVYIFRtgSnSMIeu2CV3LnrEmaAqwKymlZoMNaOdSjQwc1HdaKYlMfFbXx ndUuxwGYB1kMuEVVHCZkFrosqF7xWiydOw0//7AF504fQ86Jw/hh02rMmZwhRKdbcfWaacmx2LZm GX67UokZr334jxcpANz94HSMS09BXqkeb+62TMUSopWYNbAFcmfH4tvJbZCk0wj+fzAU+PbBzf7c hkmaVtjUR52KFGiikC8xGyzFexuEAVKlJigXX3QaBkZCGBjnWqJ83JmTDk9Nwpa9vznMIi0vLUF8 rM7l8LzhqUmYM/+NJiuieAtiqMKpvduxc+dO/LjvZxRcLYRB3QrDb+6Eu4YNxS13jQcVFNL0hfxE 7skjSOjeGwBwfFY7JETbToE2nawS6vk3e68GhoJxVjvRDopUeFtLUV82yKkWndaeotggih0kDowg WgW4W50H/jbsyEEXN9ICgIKrhSgpuOzw/TNH96PGhVF0XHoKjv28G1v3nfaPSM16fP3pu3jq4VHY uXMnlEoFBva7Bf363ITCwiIsWLUF/UY/ilaxHXAy+0vf98dFOif3ErasXLSnPkaWuqwXdupruJs1 36F5Iyp3awuRNgCAHfR8kyIFXCyNblw/UZyqYuChfPeiQ3NFw/lpj/fy3VrsWOvQ9+5xI3RtYmE0 GnDl0kXsP/Sr3bTfhoxLT8GcN5Y1a3MITygvLUF4eBjA2F+UFZ49hHnPPyNsrnbih/8iedD9/uyi Qw5kb8Ut6RlQKWjkPtseMSEM6FNVYLcUgRsWbeM1CnrlvEfz1Ib7LFihO/SHcsynLmnQpYPcjQMg uiAYZ8QBAMauLbCbOeptjv2826UK04Hk/16Ziekvv4eY6CgU5p0DVOF++VyO43Dq8E/448xRlF+/ jsiYlkjq2R8dk24EAHRpHYIzBdVYmhGDaX3DAROxCJIj4ONUMA+PFgzUxYyAAAAOQElEQVTzitX5 HgXWu+LPd4ZLlVzdjQOgioyAyTKHTetou5mBt0nSaQIq0vy8C3j1ibHo3TESwUoGkRoFeneMxI7M j0THPTZvMZK7dUFRcQlO7tvpl77NnTISMWEqpNxyG0ZNmoWHn34Vwyc8gRu6pKBdZDBefWIs7rj1 FgDA1tN1A4qCAt+pbgufPD2UH14Gu7EQMPDgk9wPqnfVn+8Ml0sOMwOfAqUWxws2DnQV4AjoPyyV 9kZ1C3Ea/e4NZv37cZ9e3xHFhQV4cuxgdLyhE15avh6nLpWhb2IbdO+ow6lLZRg2bhq++WK5cDxF M1jwnKWvOecu+Lx/33yxHAtWbREtPlUKGlo1C5WCRl6pHi8tXy/sSbXvTz1MdYtk0rpBkh9HwPxS gaA3/rAMQm5iExCtjgQ7YIZb13BZQe7GATA/W7wYMSEMXkp3vGV3c5k5Jh1TXnBestAXbFzxBhLj 47B0/Q/oFhuBDR8uRHlVLXafyMPuE3k48GM2VAoazz77nOi8djrLTWsd3bxM1KYouHwJ02fWp4LH aVU4PqsdyuZ3RP68Diib3xG5z3XA0owYJOkso6TexONoviV9mm9nZ+Gk5932Tjny57uzdQ/g5jbo zI33gWopTrfg7oyyWwu+YcHWf/eLwKhu3jXLaNUsVi6YjSWZWV69blOUl5Zg/OAeuO/RFwAAn70z D4fOleDeac+LPFw39k1D38Q2NgvJynLL6rpjlx4+6yPHcRg3rJ8obHLhnS1szE9xESym9Q3H0Rmt sTQjBioFjaN1u0iLRlRPUdEWfTSAatkFzI3up7i7JVSKZig2fa6ojYQwlrA9O7DbigEDDwVDIXO8 DkszYqBVNy9rIE6rwpzJGTh7Ic/vI+neHRvQvVOsEFcQomLRrVc/u3bf6upKnDhfYOOk+Hb7DkzN GICWiX180kdCCB4bfZvIQvLgTWGCmYk+VQV2YyHYb4pBn6oS7OHT+oZj7+P1uXMkhLFJtHMX8+1a m2uw6XPd3l4ScFOoAMDE9aHorsNFbVxqBEiUrWmGKjFC8ckVIQV2Wt9wrBnrftJYkk6DqRkDsH3d CvxeUI7XP/7ar8EexfmX8MjIgRgw7H7kleoxf/oYLH95BvJK9eifPkw0D7WyYOYElNaYMWXsSKGt vLQEJ8/kYsUax3sLNJcXp44SzGCA5Q/73RGW6QZVaoJikyW2lNlXBsXaAigX/Sk8+bq1CrKs+uto /Mh2h4ZFl63QXYd7tGEv4MHu0oD7cQAkhIH5vlaC6+zpbcVYvr8MWjWLxa++AF3bOBRczkN5aRGM RhMiWkQiQqtFh6Qe6HzjzQGL2ywvLcFbz07B4s+3QW/iEadVYfWnq5A2wmIBaZg0uHTuNMx4zbLn werFL+Hhp19Fkk6DY3+WClOCwrOH0LJTikN7a3Owl3qjUtDY+3hbdGtleYwrPnC84RnXLwLmoeIc qeZETHniz/cJ5n3LbUtUJmocF8NiKGJ4qh3RL+xEKl+7gTx4U5hQ9Gv+9DHEYDB4UuPMJ1y5eJ7M mZwhFGVTKWgyZ3IGqaqqsDn22M+7SZxWZSmeNiadzJ8+RihklnPisF/6azAYbMpmqhQ0+XZyG+He mG/XNl2sTBck3CP9wk7EdH8rz0pJJmpstGHet7xZpVc8Vjcx1RLjymFuxQGQKCVM09qChDAwcQQL d5UKcQBJOg2ee2YWxj7xYkDC7oxGI7I3fYYPli1B1uEcUcDLzz9sceqKzc+7gPS+3YWFU5JOg693 7vFp4YiGnz3+7jQbr5219DngZpImQ8E8Ihpcn3DP0pAc+fOnbgelCPbvaGqFy9lp+5fTxF8urwsi hrnxwvHfTm5DknQaYSSI06rInMkZ5Mj/viM8Z/bpSFRVVUG2rVlGpmYMsClpOS49hWz4cCFRKWiS lhzrcMT/afuXoiK5UzMGkIqy6z7tt5Vta5bZ9FuloMnacbr68o0T2xDCUB6Nioa58W6fa75da/uk dXF3Pmc0W+HuxgEAFr+v6UGdMFk3cQTrj1Vi8b4qkTlHq2bRL6UTBva7Bd173YLk1CE2+fLucK24 CL/s3oqDP2Zj14/7cODsFdHIGadV4cFRQzDthTeFUpY7Mj/CsHHTMC49BV98/ytKS4px6IevsXPr Bmz+fq9gAkpLjsXCd5f5JQimvLQEjz8w2CarQatmsWZsS2Frc+qyHspVVzyOISXhLCgD7/L5zfXn O6PZF/C4HoCdjFTAkgnw32OV2HZWb7f8jkpBo0NUMFpGaREaGoJQdRCio8S2uppaA6qrK1FZY0DB 1UJU1xpQWG5wGB5oFWiP3n3RIro1amsqoa+uRFlpKQquXELmV9twpqAaWjUruoZWzWL04Fts0mN8 BeE5rHrzBTz32rs23yVJp8H6sVGCrZTOrYHi83y/VuVrrj/fGV6ZM5i+n0+4X8RVAZ2tMBtCwllw Q6LAdQ+xyR/PKTbiUJ4ex/INOHiVRlFZjVdqR3mKdSeSgf1uQf8hGeiddpcoWa+6uhL7vv0v7rh/ ilc/lxCCLZ8twZy58+xGok1PjcDLd0QitG4kY45Wgt1U6FeR8nEqmB4TP+2YnhOguOMlr2jMKxch tWXEuGIwSG29KcPdiTgJYcD3CQd3Y6iwa7Q9TBzBhVITyvU8Kg088htMMWpMBGoFBbXScsMigmmE BtFoFcpCxVIoqjKjsIpDWS2PkmoOhZVmlOt55FeYcfYaEUQwPDUJI+6+GxFaLaJ0cYjt1BWxHZMc LvKMRiM+Xjgby1aswoZtO70WZlhdXYnVb7+IZStW2RVokk6Dt4dFCI96cATsjhK/b3AG2MnPD46A clqW265SR3htFWY+up6Yv5snavO0cAGJUoJPUINvHwzSOsgm2NYXmDiCkavzhcrW49JT8Oyr7zqN yirOv4TVS17G+6vWoajS6HH5oYYQnsO+nV/h8xXvY1PWz3anK3FaFebdHo4xKaFQ1D2FqCIjFOuv giow2Bzva7ieYaL9ogCAvfNVsD3GeE1fXruQL3f8IyEMiFYBEq0EwlmQcBZEzQBKGkRdN3FX0gBL AWYCGC2fR9XwgJEHVcNZItZDWBANYzlHzYBoGNHEv7HJDLCIov9NiWjfrh1aaCNRW1ODszlnkXsh T1TMrVe8FtOmTMZtI8cLcZ4ufTdCcOHsCez+ei1278rCd/tPOZxLD+qkxqTe4aKoe3AE7K5SSyn7 QFQJdzM/31O8atfyWj0Af8JYYi9NY1oJos0pNmLRnuvYeLLKYQKhSkFjaIIarcNYm4WfVs2ie0cd WreMRHRUFDQaDVSqYASr1bheeg3V1dUoLilB7oU8XLha4TQHLEmnwYSUYNzbPRRxEQ3iJOpC75hd gd0UxN38fE/xugHWuHkG4c82KFTrQT2AQECilDA90FI0zzJxBEfzDcgpMqK42mLViNYwSIhRokfr IOGxCwCnrhrw1ckqfP8nHG4m7ApJOg166hjcGh+MWzuqxeIEAAMP5lA5mH1lgd21Bg7y8xOHQjnq Pa/ryusXbG49gEDD9QwDN7CF0wVdU1QaeBy6pMfxfANOFxpRUGlGOadCda0BrUMsj+ewIBqtw1iE q2h00CqQEKNEUoxSWLmLO0VAn68FfaISzLHKgG4E0hB/+vN94tIy71tOzD8uEbV5mmsTKPg4FcgN avDtgkEiWEBdNwcrM4EqM4MuMIA6VwOq3Ay+Wwj4zhrwHYO9VqKRquJA/14D6nwNmN+qAr5pcmMa JnBaYQc+CbbfdJ9oyicX9SQO4G+BigbfPhh8fDBIyyDw7VSixZpdDDyocjOoIiOo6ybQF2pBFRgC /lh3SgD8+T6pfU4pgqnG+wJY6wH4a1+AgKDnLZkNDZ4cJIQBQlmQukqGVF3SI2o4S5zuX/AP12F+ vg+DTnyWdcckDKHouJtFbeaBLZodNf5Xg6riQBUYQOfpQefpLaOldcT8C4qUhDAwDxSv8um4m0X1 9n2BT9ND2TteAqgGwgyiwQ1zkLkq85eAGxYtns5QjOU++xifCtWf+wLI+B5v5Od7im8T7gGwA2aA ChankjisByAjaWzy84Mj3M7P9xSfC5UKjqCYATNFbd7aF0DGf9jNzx8w02tBJ03hc6ECANNjLKjo BFGbo3oAMhLEXn5+dAKYHmP91gW/KIWiGarxhNtZPQAZaWE3P/+Ol7wadNIUfhvSmLg+FJ0o3i7c UT0AGelgNz8/cajXg06awq/PXva2ZwG2wTzHzo7CMtLCZqdxVmW5j37Gr0KlI9o2a18AGf/isN5+ RFu/pz37fTXD9JkEKrytqK1xhQ4ZCcBQlvvSACq8LZg+kwLSHb8LlVIE2+4LEKME19c/1ZdlXIPr G24T6uhrf74zAmIfshsHMDjyHxcHIFVICGPZs7YB/vDnOyNghkw5DkC6BMqf74yACVWOA5AmgfTn OyOgriE5DkB6BNKf74yAClWOA5AWgfbnOyPgznY6ZYwcByAFHPjz6ZQxAeqQmICrgWZYOQ5AAjjy 59MMG/DRFJCAUAE5DiDQSMWf7wxJCBWQ4wACiVT8+c6QjFDlOIDAICV/vjMkI1RAjgPwOxLz5ztD UkKV4wD8i9T8+c6QlFABOQ7AX0jRn+8MyQkVcBAH0OhHlWke3OBIyfnznSFJodqNA+gTLscBeAk+ TgWuj3g6JQV/vjMkKVRAjgPwJVL15zvDJ0XSvAEVHEGZf/mCmL9/RWizxgEwv1UFsGd/bbiuIZL1 5ztD0p3jOTMxfToSpDgn0F3520JFJ0Ax8WvJuEodIdlHP2A/DkDGu0jJn+8MSQsVsB8HIOMdpObP d4bkhQrYiQOQaT4S9OfLyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjI/H34f4DnQZLCUbKg AAAAAElFTkSuQmCC "
+ height="19.649908"
+ width="19.649908" />
+ <path
+ style="fill:#455c91;fill-opacity:1;stroke:#485c90;stroke-width:0.06933333px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 14.916599,13.575076 0.03547,2.805834 c -0.667959,1.438231 -1.989129,3.644187 -2.94123,4.463961 l -0.12122,-0.149944 -6.5605149,-0.01286 C 4.9915937,20.667674 4.6308598,21.055999 4.65131,21.322244 l 0.6456992,8.406634 c 0.021173,0.27572 0.3142048,0.620624 0.620624,0.620624 h 5.8426418 c 0.228669,0 0.542075,-0.227259 0.551665,-0.507784 l 0.02508,-0.733465 c 0.189691,0.269381 0.70312,0.670776 1.147213,0.670776 h 7.873775 c 0.985757,0 2.505412,-1.050149 2.006058,-2.821018 0.564591,-0.451828 0.898801,-1.21927 0.564203,-2.194125 0.592066,-0.483869 1.022688,-1.393507 0.52659,-2.206663 1.577769,-1.322103 0.55391,-3.172078 -0.664506,-3.172078 h -5.303515 c 0.198397,-0.867561 0.50977,-1.753912 0.488977,-2.921321 -0.01796,-1.008221 -0.687681,-2.477614 -1.166021,-3.259842 -0.199523,-0.326283 -2.041031,-0.955089 -2.893187,0.37109 z"
+ id="path3009"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccssssscsccccscssc" />
+ <path
+ style="fill:#6e7fb3;fill-opacity:1;stroke:none;stroke-width:1.06666672"
+ d="m 5.4071734,21.493067 h 5.5260086 l 0.01291,8.121167 H 6.0269078 Z"
+ id="path3764"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:#6475ab;fill-opacity:1;stroke:none;stroke-width:1.06666672"
+ d="m 6.0010902,22.590522 h 4.3769088 v 6.533084 H 6.5562732 Z"
+ id="path2994"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#edf5f7;fill-opacity:1;stroke:none;stroke-width:1.06666672"
+ d="m 17.581122,20.147681 c 0.253011,-1.017207 0.437591,-2.14854 0.55997,-3.232856 0.03008,-0.266546 0.02877,-0.496842 -0.0116,-0.717778 -0.159747,-0.874057 -0.525539,-1.654586 -0.869001,-2.440615 -0.340194,-0.267678 -1.006095,-0.374252 -1.505469,0.03178 v 2.758759 c -0.837765,1.641042 -1.782608,3.220895 -2.949341,4.673956 l -1.099754,0.767815 v 6.386393 l 0.761701,0.003 c 0,0 1.009869,0.617541 1.062891,0.59103 0.08837,0.04418 7.873241,0.02196 7.873241,0.02196 0.422031,0.0087 1.944544,-1.103431 0.974782,-1.971527 -0.129226,-0.07927 -0.112253,-0.317607 0.0089,-0.396878 0.606131,-0.108802 1.340767,-1.249024 0.573357,-1.849587 -0.130696,-0.145647 -0.03699,-0.37404 0.117651,-0.391073 0.453337,-0.218909 1.229721,-0.95166 0.524883,-1.836462 -0.142219,-0.07243 -0.148352,-0.259147 -0.01616,-0.371884 0.681755,-0.09508 1.545339,-1.648252 0.115876,-2.021515 z"
+ id="path2987"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cssccccccccccccccccc" />
+ <path
+ style="fill:#dce4e7;fill-opacity:1;stroke:none;stroke-width:1.06666672"
+ d="M 12.267547,28.377326 V 21.5939 l -0.5635,0.382317 0.0026,6.400504 z"
+ id="path3002"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccc" />
+ <path
+ style="fill:#dce4e7;fill-opacity:1;stroke:none;stroke-width:1.06666672"
+ d="m 16.491565,13.515568 0.653928,2.818603 -1.732024,3.075226 c -0.179491,0.318688 0.03749,0.641761 0.296034,0.653929 l 1.877834,0.08836 c 0.286711,-1.296096 0.632702,-2.876756 0.562172,-3.852872 -0.128296,-0.680635 -0.404316,-1.541568 -0.889323,-2.552734 -0.270868,-0.183746 -0.495913,-0.23052 -0.768621,-0.23052 z"
+ id="path3000"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccsscccc" />
+ <path
+ style="fill:#dce4e7;fill-opacity:1;stroke:none;stroke-width:1.06666672"
+ d="m 21.299041,20.143406 c 0.615414,0.585013 0.245898,1.687378 -0.2952,2.077296 -0.102635,0.0592 -0.124747,0.204946 -0.04998,0.299933 0.596424,0.681841 -0.196614,1.831314 -0.4499,1.949564 -0.08211,0.07379 -0.09238,0.159564 -0.07499,0.249944 0.679279,0.951976 -0.105611,1.74444 -0.374917,1.924571 -0.08909,0.07987 -0.116697,0.218205 -0.04998,0.349921 0.592533,0.932714 -0.09362,1.593199 -0.484959,2.003738 l 1.933484,0.0041 c 0.371786,0.01863 1.932087,-1.115082 0.898018,-2.005521 -0.116135,-0.100011 -0.04122,-0.358426 0.03819,-0.372675 0.511931,-0.09187 1.415468,-1.173565 0.569814,-1.85976 -0.05906,-0.04792 -0.109388,-0.28565 0.11619,-0.385351 0.69869,-0.308811 1.130126,-1.051503 0.532736,-1.840441 -0.158893,-0.0895 -0.139034,-0.28363 -0.01425,-0.360553 1.167228,-0.34771 1.19407,-1.894501 0.110392,-2.030092 z"
+ id="path2985"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccsssscccc" />
+ <g
+ transform="matrix(0.065,0,0,0.065,4.6324993,12.725175)"
+ id="g3779">
+ <path
+ sodipodi:open="true"
+ sodipodi:end="6.2584037"
+ sodipodi:start="6.2585156"
+ d="m 83.389674,239.60159 a 8.82197,8.82197 0 0 1 -8.601425,9.03689 8.82197,8.82197 0 0 1 -9.037134,-8.60117 8.82197,8.82197 0 0 1 8.60092,-9.03738 8.82197,8.82197 0 0 1 9.037615,8.60067"
+ sodipodi:ry="8.82197"
+ sodipodi:rx="8.82197"
+ sodipodi:cy="239.8192"
+ sodipodi:cx="74.570389"
+ id="path3780"
+ style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.63794011"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:open="true"
+ sodipodi:end="6.2584037"
+ sodipodi:start="6.2585156"
+ d="m 73.751745,237.93383 a 1.1197916,1.1197916 0 0 1 -1.091798,1.14708 1.1197916,1.1197916 0 0 1 -1.147103,-1.09177 1.1197916,1.1197916 0 0 1 1.091734,-1.14713 1.1197916,1.1197916 0 0 1 1.147163,1.0917"
+ sodipodi:ry="1.1197916"
+ sodipodi:rx="1.1197916"
+ sodipodi:cy="237.96146"
+ sodipodi:cx="72.632294"
+ id="path3782"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:type="arc"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"
+ id="path3790"
+ sodipodi:cx="76.460419"
+ sodipodi:cy="237.96146"
+ sodipodi:rx="1.1197916"
+ sodipodi:ry="1.1197916"
+ d="m 77.57987,237.93383 a 1.1197916,1.1197916 0 0 1 -1.091798,1.14708 1.1197916,1.1197916 0 0 1 -1.147103,-1.09177 1.1197916,1.1197916 0 0 1 1.091734,-1.14713 1.1197916,1.1197916 0 0 1 1.147163,1.0917"
+ sodipodi:start="6.2585156"
+ sodipodi:end="6.2584037"
+ sodipodi:open="true" />
+ <path
+ sodipodi:open="true"
+ sodipodi:end="6.2584037"
+ sodipodi:start="6.2585156"
+ d="m 77.57987,241.81404 a 1.1197916,1.1197916 0 0 1 -1.091798,1.14707 1.1197916,1.1197916 0 0 1 -1.147103,-1.09177 1.1197916,1.1197916 0 0 1 1.091734,-1.14713 1.1197916,1.1197916 0 0 1 1.147163,1.0917"
+ sodipodi:ry="1.1197916"
+ sodipodi:rx="1.1197916"
+ sodipodi:cy="241.84166"
+ sodipodi:cx="76.460419"
+ id="path3792"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:type="arc"
+ style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.06666672"
+ id="path3794"
+ sodipodi:cx="72.632294"
+ sodipodi:cy="241.84166"
+ sodipodi:rx="1.1197916"
+ sodipodi:ry="1.1197916"
+ d="m 73.751745,241.81404 a 1.1197916,1.1197916 0 0 1 -1.091798,1.14707 1.1197916,1.1197916 0 0 1 -1.147103,-1.09177 1.1197916,1.1197916 0 0 1 1.091734,-1.14713 1.1197916,1.1197916 0 0 1 1.147163,1.0917"
+ sodipodi:start="6.2585156"
+ sodipodi:end="6.2584037"
+ sodipodi:open="true" />
+ </g>
+ </g>
+</svg>
diff --git a/src/skin/socialwidgets/LinkedIn.svg b/src/skin/socialwidgets/LinkedIn.svg
new file mode 100644
index 0000000..4f58f02
--- /dev/null
+++ b/src/skin/socialwidgets/LinkedIn.svg
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="85.018593"
+ height="25.977255"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="LinkedIn.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3785">
+ <stop
+ style="stop-color:#fefefe;stop-opacity:1;"
+ offset="0"
+ id="stop3787" />
+ <stop
+ style="stop-color:#ececec;stop-opacity:1;"
+ offset="1"
+ id="stop3789" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3785"
+ id="linearGradient3791"
+ x1="39.280788"
+ y1="12.902368"
+ x2="39.280788"
+ y2="32.148937"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.721409,0,0,1,0.31235938,0)" />
+ <linearGradient
+ id="linearGradient3003"
+ y2="425.39999"
+ gradientUnits="userSpaceOnUse"
+ x2="-395.85001"
+ gradientTransform="matrix(-0.50335197,0,0,0.50335205,-148.17928,-158.8132)"
+ y1="274.70999"
+ x1="-344.14999">
+ <stop
+ stop-color="#FFF"
+ offset="0"
+ id="stop7" />
+ <stop
+ stop-color="#FFF"
+ stop-opacity="0"
+ offset="1"
+ id="stop9" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3003"
+ id="linearGradient3377"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.00402682,0,0,0.00402682,-13.36043,23.42958)"
+ x1="-344.14999"
+ y1="274.70999"
+ x2="-395.85001"
+ y2="425.39999" />
+ <linearGradient
+ id="linearGradient3003-3"
+ y2="425.39999"
+ gradientUnits="userSpaceOnUse"
+ x2="-395.85001"
+ gradientTransform="matrix(-0.03674469,0,0,0.0367447,-5.012456,4.0033664)"
+ y1="274.70999"
+ x1="-344.14999">
+ <stop
+ stop-color="#FFF"
+ offset="0"
+ id="stop7-6" />
+ <stop
+ stop-color="#FFF"
+ stop-opacity="0"
+ offset="1"
+ id="stop9-8" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="8"
+ inkscape:cx="35.729906"
+ inkscape:cy="7.9624676"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="1222"
+ inkscape:window-height="708"
+ inkscape:window-x="1224"
+ inkscape:window-y="19"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-0.62121129,-12.484656)">
+ <rect
+ style="fill:url(#linearGradient3791);fill-opacity:1;stroke:#e2e2e2;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect2985"
+ width="75"
+ height="19"
+ x="1.1212113"
+ y="12.984656"
+ ry="2.1487894"
+ rx="2.1487894" />
+ <text
+ xml:space="preserve"
+ style="font-size:14.40710354px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;font-family:Sans"
+ x="22.602589"
+ y="26.791992"
+ id="text4002"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4004"
+ x="22.602589"
+ y="26.791992"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#333333;fill-opacity:1;font-family:Arial;-inkscape-font-specification:Arial Bold">LinkedIn</tspan></text>
+ <image
+ y="22.680319"
+ x="69.858215"
+ id="image3002"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKoAAACqCAYAAAA9dtSCAAAABHNCSVQICAgIfAhkiAAAIABJREFU eJztnXl4E9Xex7+zJE2TbqQLBGiBIrQFikUWsSxWKSIoFMSFRa6yiYoXFMUFxKuooKIICq8ioiJC uQIioCDWAlcB2ZRVoBVQCrR0oXRvtpnz/pFm2mmWJmmWUefzPHkeOJmZnGS+PXPObzuAjIyMjIyM jIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjJehAt0BV+DLLhPjyqGAWR/orvx9YFVQTt0BOqLt X0IDdKA74Arm3W/JIvU2Zr3ld/2LIHmhcnmHCH92R6C78beEP7sDXN4hEuh+uAIb6A44g+fMxPTp yEB342+N+fv54DkzoRlW0lMAaQv12HqQ4hxRG7uxEMxvVQHq0V8frmsIzPe2FP5PinPAH1sfwB65 hmSFSmrLiHHFYFEbdVkP5peKAPXo7wHzSwW4vuEgbVVCG/fTUpDaMkIFR0h2VJXsHNX803sgtWWi NnZbcYB68/ei8e9Iastg/um9APXGNSQpVL44l3C/rhO1MYfKQefJK39vQOfpwRwqF7Vxv64DX5wr 2YWVJIVq/n4+QLj6BgMPJuta4Dr0N4TJugYY+PoGwll+d4kiOaFyOTsJn3dQ1MZmXQNVxTk4Q8YT qCoObKM/fj7vILicnZIcVSUlVGKqJebsN0RtVJERzIFyB2fINAfmQDmoIqOozZz9BoipVnJilZRQ uUOfgJRfFrWxO0oATnK/298Djlh+3waQ8svgDn0SoA45RjJC5csuE/P+D0VtdG4N6LPVAerRPwP6 bDXo3BpRm3n/h+DLLktqdJCMUG38+RyRzVF+gt1WLH5qSTAOQBJCtefPZ/aXgSoxOjhDxptQJUYw +8U2a6nFAQRcqDxnJo3NIlQVB3ZXaYB69M+E3VVqY1mxxgEEqEsiAi9UO/585rsSQM87OEPGJ+h5 y+/eACnFAQRUqKS2jHA/LRW1yf78wMH8UgHqstj7Z40DCFCXBAIqVNmfLz2kGgcQMKHa9ecfrZT9 +QGGztODOVopapNCHEDAhGrXn79dHk2lALO9WHJxAAERquzPlzZSjAPwu1Blf/5fA6nFAfhdqLI/ /y+CxOIA/CpU2Z//10JKcQB+Farsz//rIZU4AL8l93F5h4hp7XhRmxT8+SRKCT5BDb59MEgEC6gZ yxtmAqrMDPpiLegz1aAKDAHtZ6CwxgFwA1oIbdY4ACauj9+SAf0iVMJzxPhJhqgt0P58PlED8yCt KBuzMSRGCb6zGhgcCeqyHmx26T9ymsLuKgXfIwwkhBHazN/PB+E5QtGMX8TqF6FyRzOl489X0TCN bgm+W4ioOafYiFNXjSip5lBt5BGtYZAQo0SP1kFQMBRIWxVMD7UGc6gc7Nbif9biry4OoHE9AO5o pt+64HOhSik/n4SzME1qAxKjBAAUVXH48OcyfHigAqU1ZrvnaNUsxqaE4LnbtIgJYcD1CQeJUEDx ef4/SqyBrgfg88WUZPz5Klok0jW/VKDzW39iwa5ShyIFgNIaM5bvL0PKu3nIPmdZAfOd1TCNaeWX bkuJQMYB+FSoUvLnm4dGCSJd/ON1TN1YCL3J9alHaY0Zd626gk0nLeWE+G4h4PpF+KSvUiWQcQA+ ffRLxZ9PdEHg+oQDADadrMKcRoZsd5i8oRDdWimREK2EeXAk6OOV0nX9MhT4NkEgsSqQcBYIYUEU FCgTAUw8qCIjqGsmUJf1Ln8HZnsxuC4aIKhujPNTHIDPhMrl7CSmr54Qf1iA/PlcX4tITRzBC99d b9a19CYes7YV49tJbYAgGtzAFmC3ey58X8AnasD1DAOfoAEUrk0fqct6MGeqLSkpTha51jgA893R 9Z9XFwfAJAzx2VzVJ0IlplpiXDlM1EaVmgLmz+e7WFb4W09XI6/U8bRDq2YRomJRVGl0Oi3I/r0G 2edqMOgGNfgeYYBEhEp0QTDdE2PX5FZUxeF6LYdyPQ+1gkKYioEulIGizrpE2qpgbquCOU0Ldk8p mP9dd7hYZA6Ug0uNANEqhDZrHAClCPaJWH0iVLv+/MYeDj9BopSC/W+HAxvouPQU/GfxSnRO7gUA MBqNyFz2Gh59/nWHgs08WolBN6hBQhhwPcNAVXMgkQogiLY8ZhU0iJ3RjKrhAAMPqtxseeyWmy3B H838bbh+ETAPjQLqhFdUxeGLXyuQfa4GR68Y7S4YVQoa3WIjcHMrHg+khKJPrApQUDAPjgSXpIFi db79J2CdR9H0UGuhyddxAF5XP19x1WKOauAqpXNroPj0irc/yrX+xKlgeiwWAHDXJ1eQ/bvYdz1z TDqWZGbZPXfjijdw36Mv2H1Pq2ZxcU57YURqFhwBVWAAnW8AlacHfa4GVLljS4QIhoJ5dEtwPUIB AJUGHu/+eB2Lfypza7EIAEk6DVaM0loEC0tUm/KDSw6nAqaJbSwOESusCsppWaDDWnldV16/oHHz DHHqM0egXJIXMFcpn6gR/vJ7vJePMwXiUbWkqBCR0TEOz+/dMRJHLtj3oB2f1Q4J0UpRW6WBx/Va HhV6DjUmgsoGAcihQTTCVTRaBDOIaeDlsQdVZARzvNK5+5ahYPpXa0Esp64acM+aIqfTG1dYMDQK swZaXKbM0UqwX161exyJUsL4ZJwwigMAnTgUylHveV1XXn30S9GfT5WYhH/31DE4U1D/nkpBOxUp ADwweiSOLLL/SPuobs59ttiI/CoKf5TUujyKqRQ0YkKV6NmaRVKMEl1bBWFAh2BBwCTGYlWwum+Z Y5UWJ4l1dGMomMa0EkSafa4Goz8vcHsUtcecHSVo10KB0ckh4HqEgj5QZtek6M84AK9djPAcMX52 D0jh6fqLV3FQvvNnwFOfjXPjQUIYbDpZhfHrCkTvnTqyF1179nN47p6t63BbxniH77uDK4u1JJ0G t3dQYFiSBgM7BIunFgYezKFyMPvKwA2JEh733hRpw77mPNsOoUG001EVKhrGp9uL4gColl2gfPgr eDMOwGsGf+74BpFIAenk59OnLUb6EV00SNJpRO8tfdX+HJTjOOzI/Agr318kak/SaTAuPQVTMwa4 9NkqBY2pGQPww6bVKKrQ4+K1WtQaOeRfysMPm1Zj0exJGJeegjitZV54pqAay/eX4a5VV9BuwZ94 elsxTl2te/QH0eAGtIDx+Q4+FSlgcXCsqzPuc91DAJUDqdirB1B4GtzxDV7tj1cUb/XnN3SVUpf1 UC6/5I3LN5uGc6nsczW4a5V4YffT9i/Rf+h9AIDfftmHlW+/jDVb96C0xow4rQr9b0rEqHsfwOD7 piBcG4UdmR/hwSnTnbpe47QqPP3YQ5g4+w2EhrvmwbqY+xuyNq3G1m++QdbhHJH4esVr8VTfIIxO rg+mOXXVgDtW5jvtR3MY1EltsRcDUKzOdxo5ZpweKzKLUcERUE7LgqT2BTB9P5/oF3YSvbg4FSGA ZF6mYVFC3+bcriUAhJdWzZLP3plH0pJjhf+PS08hP2xaTXjOTBry2TvzROc2fsVpVWTlgtnEbBaf 5y5l14rJygWzSa94cV+TdBqydpyO5M2NJ3FaldO+NPx+49JTyPKXZ5CVC2aTOZMzbK5r76VS0MJv Zu4X4fT35eJUNhowfT9fOlE7fHEu0b+RKO7g/a0CLkybF0MRw+z2Qh8fvCnM5sb0iteSlQtmk6qq CrviWTR7klMxLJo9iRgMhmYJ1B5H/vcdGZeeYiMiR31p+Jo5Jp2UXSu2uSbP806/j/VV/HJHyz0d FtX0YHB/K7FY30gk3ooDaPYc1Zy9EDb+/J3S8NQIMBTMQyJFnpRH+oZDpbB8/bTkWOzeshaHz1/D lBfegkYTKjqdEIK5U0ZitoPV/7j0FJw8k4Nn3loFpVJp95jm0HPgEKzNOoqcE4cxLj0FAJqck2rV LHZvWYslmVkI10bZvE9RFJ55axWGpya51AfKhbUGs7PEth5A9kKXrt8UzRIql7OT8H/sFbWxP153 3VjtB0iUEsZH2womlKIqDlM2FGLg/11Ct9gI7N6yFrtP5CFtxDj75xOCaaNuxYJVW2zei9OqsPO/ K7E26yhax8X79HsAQOfkXlibdRQ//7AFveK1Do9L0mlw9MQph9+pIa2ibUVsRatmEWoNPjE0LVSq 3Az2R3EsBf/HXq/UA/BYqHbz80tNFh+xROATNTA+UT/Jzz5Xg/4f5GPjySosmj0JB3KLmryZ00bd ipVbfrJpn5oxAKcuFOCO+6f4pO/O6DtoBA7kFmHR7EnCU8FKkk6D/x05g7iOCU1ep7K8DDt/Ouzw /VvjGyyOLrnmRGD+dx1UqUnU5o16AB4b/KXkz7cH1zMM5lExFsM4R7BwVykW7CpFnFaFAz9m48a+ aU1eY+6UkTYi1apZrF6xBHc/ON1rfa2ursTh7G04ffQgcs+eRnFJCSprDHj1nf9z2E+GYfDMW6tw 2933455RIwVvVP8+NyFK17bJz6wsL8OIAd2derHu7V43BTLwoK+4mNwYgDgAh/AVV4l+UbJo4myc 2CbwC6a6l7lfhNCv4pc7kkGd1AQASUuOJUVX811awNhbaKQlx5IrF897ZYF05eJ5smj2JJKWHGt3 YbRo9iSXr1VRdp0MT00Szh2XnuJ0UbdtzTKSpNM4XUQl6TSk8rUbLAupUTFu3wPjxDbihdWiZMJX XPXvKGbcOkvcidduIHyUMuACbSzS3Oc6CDckLTnW4Wq+MRs+XGhz4+ZMzmi2yYnnebJtzTKRqOy9 0pJj3b622WwmUzMGCNcYnpok6u/Fc2fJ0rnTXDZL/fh4bP29DWfdvg98lJLo64QuDGZbZ3ksVLeN sXb9+T9dl0TwMNczTMiUzCszI31lAfJK9egVr8WeE3/arObt8cuPO9E/fZiwqvbGo57wHD5f8gre fHuxTVCMPY787zsk970Nl86fQcGfuTDU1uJ6cT7CWkRBHRqOFjGt0T6xu13rxItTRwkLv+GpSWgV HYW9h361+7lJOo3d9rXjdIJjgc26BsbDtHbzsChRHAAAKMavhSdxAG6dIGV/Pp+ogelBHcBQKKri 0P+DfOSV6qFS0Dj+y0Eh1tQZ14qLcFNiO2HelqTTYMO2nU5jAZrimy+W45X/vOQwAssejgTUmDit CvFtonFj1wSk3zUSt436FzSaUDw5djCWrv+hyfNX3tsSt3ZU47PD5fjwgCUreM3Ylhh0gyXQhc6t aV62rRfjANw62Hx0PTF/N0/Uxm4sDHgpcxLOwvhUOyCIRqWBx8AVV4UbvfzlGXj8P0ubuIJlNMro 3xXb9p8BYLGtfr3nV7s2SFc4f+Y4npoyVrieP1ApaAzunYBHHpuOzNUfY90Px5wePz01Au8Mt6SU mDgCvZkI5ig6twaKzIJmD0ANn3JW2DtfBdtjjG+ESmrLiPGjO0Fq6utmSsKfz1AwPtpWMEE1DI5O S47FruMXQVFNf823n50sGPTHpafg028PemS85zgO777wCOYt+czrgSLuEKdV2V3Rx2lV6BRJIzFa iWFJGmH0bIi3i2zYxAGoI6F85Du34gBcNk+Zf3pPJFJAGvX2zUMihR9hftY1UQT/ko8+d0mkB7K3 Yt6SzyzXmD4GL76/zqXzGpN78gjGjxzi1mPeVzQWaa94Lb4aG+EwYJsqNQE1HNhtxV5PZ2e3FQtZ FgBAaq65XQ/AJYO/lPLzG8LHqcClWiKTss/VYEGDSf/UjAEu2Uory8vwwP0PQG/i8dk78zBvWaZH Iv144bO4sefNkhCpPY5cKMXJq2JbKFVqAn2qyrIY/u9VKJdf8sk99UY9AJdGVEn68+tyhcBQqDTw eGxz/WivVbNYuHKjS5d5+qERKKo0YvMnizFy4lNud6O6uhKPjBzY5HxQCjyzvQxHZ1ge9cyhcrCb i/z22czOEtt6AG7EATQ5okrVn8/1DRcqn7z8/TXRo+7Jifc2mWICADsyP8KmrJ/xzfpPPRLp+TPH 0buT7i8hUsASlG2t9ML1CHMcDO0DmhsH4LSnxGyQpj9fRYNLswRlnLpqwPIG+3hq1SyefP2DJi9R WV6Gp5+ehW+3bsKge/7l9Fij0Tbna++ODejTq5dLZiQp8e6Buse/ggLXM8yvn+0wDsBsaFKsToXK HfxYkv58LjVCsM0918jR0DI8CCMGdEeX1iHYu8NxOsSSuY/hkzXr0HfQCKeftWfrOky862ZR2+rF L2FwxhifRdb7kiMXSoXUFuv83m/YqTBOyi+DO/hxk6c6FCpfcVWS9fZJCANzXSpv9rkamzz9MwXV 2HPyEnp07SSklzQmNycHw+5/uEmR7sj8CEPvnYDv9p8Cx1nm6K8+MRYPP/1qQE1PzeXTwxa7N9Eq wMc5LmTsCxzuC9BEHIBDoZr3SLPePjewhTAh/8/uWrvHaNUsFq3a5PAaHW+4AT0HDnH6OdlffY57 HnoMehOP0hozTh3+CU+OHYyXlktjE9vmsO1s/X0lsf4VKuBgX4A9zvcFsLvql2J+PgCQKKXIHOXI FPTmi085DWRmGOfFHw5kb8XdYyaKRs2x99ztdD46PDUJwybMQLt27dC6dWtUV1fjxIkT2LZtK3Zl 7ZTUCJxXqkdemRlxESz49sFg9pU1fZIXsVsP4LdtTusB2DRK2Z9vLSFj4gj6LC+wKxx3vFH2OH5g D24fNNjl+Wdyty548623MXToUIfH5Obk4KlZT2H79h0Oj/E31sATqtQE5aI//d8BN+MAbEZUqebn 84kaoSrIJ4cr7IpUq2axenOWxyLNz7uAEXcNdVmkw4YNxfp165pMh+6ckIBvv92OJ5+ciaVLvVOh OU6rwo2JHdAqOgrRURYLSHV1NS7kXcG5P/KatEbs/7MWo5NDLHlkDOX/BbK9fQGc1AMQCZXXVxKT ROrti1DRFuM+LDlPr2TZf+SvWPyqSykY9qiurkTGbb1drtuU3K2LjUg5jsOGL/+LAwcPIjExCRMm jBeF4i1ZshS///67xyNrr3gtHhg9EvdNmYV2nbs6PfZacRE2f/w21maux56TtvEY+RX1f4ykhSIg 0zq7+wL8uAS8vpLQqlDHo41U8/NNo2KE/ozqFmI32HdqxoBmBTQ3Tkdu6rV9+3bRNTLXrSUx0VGi Y7RqlnzwwQei4/Iv5bmc6mx9pSXHku3rVnj8/Y79vNsmWLtXvFYS99jVegDCql+y/vxEjais+eZT VTbH9IrXYtmXTcdfOuK1f49zy7uU3K2LaE66Y8cOTHxoAoqKxTZdVhOB0aPE+2vp2sZi2uPiStzO GJ6ahOnTH4dBX40D2VtRcNn9aLUb+6Zh677T+GHTaqF0UHVtvd+f7xu4vQjcjgMwrp8oVvZ8z1IQ vPniw1miryuAkDc3nmjVrM1oo1Wz5OK5sx6PNps/WezW6AaAzJw5Q3SN5G5dbI5RKWiyb98+u5+5 fft2tz+z8XdOS44ly1+e4XYOlzW/SpRu4mKBCZ/e5/mN0lbWTxQJlQYc+PP3lAbWn89Qloj9Opvp xC+v2ixyVAoaWzau83heeiB7K8ZOe8bt8xIT64s2FBcW4OSp0zbHTHv8CaSmpto9v2N882oAlNaY sefkJUx/+T20adcR4wf3wPkzx106NzQ8Aht3H8Pg3gm4Y+WVei/VgBZ+d6laocrNYPeI1x2N4wBo qfrzzaNbOowztbLm/dcdep+aIvfkEdw1YrRH9s127doJ/86/aj8C6cLhLDz55Eysz1yHHTt2oLiw vtxlpLaF3XNcRatm0Stei7TkWKQlxyL3Qh6GD+qH1Ytfcul8pVKJjbuPoW9iG9yxMh9FdeXPzRkx ILqgZvXNU5qKA2Cl6M/nbteKyiousJNctmj2JNw77XmPrp978ggGpw3w2Fd/8eJF4d/tY9vYPWbb /jPA/jOwJsFs374dQ4fqAADXSt0fBIanJmH06Hsx+N6HHTozKsvLQHgOFO3coQFYxPr1nl9xS7f2 uCezDLsnaaFQWIoDK9/L8//9d1QPoC4OgOaOrBEdT1VxAfXncz3DLJWWYdmfdEJmoc0x86ePwTNv rfLo+laRNqd8+Nmz9XlQ4dooDBvm2NgPADHRURg0aJDw/19//cXlzxqemoScE4exdd9pPDRrvlOP W2h4hEsitRKujcKGbTtx6lIZnq8L7iExSpiHRLp8DW9Cn6222dzCqk+a6TVB9AYJYcAniovd+gs+ USMYgIuqOAz/rNBm1JszOQPzlnm2WezxA3uaLVIAyFy3TghSAYAP3nvXprROQ5YuXSrKv1rzxRdN foZWzWLDhwuxdd9plzJoPaVrz3748I25WL6/TNhCkxvQwu/BKoDl/pNGqTJWfdLMzVNAhYtLwJiH R4s2EPAHXM8wy+IJlg0bhnxSaCOoOZMz8PrHX3t0/QPZW3H7oMHNFikAFBWXYOXKlcL/4zom4PjJ 00ju1kV0XEx0FDLXrcWYsfX1rY4fP96kwb9XvBa/Hj3m8dTGXR6aNR/DU5Pw2OZrwuYYVgeL32Ao i+4aQIW3BXOzpbYXBTjeZc/TwgPuwvWLEHaCqzTwGPr5dZuAk/nTx3g8ku7I/EiIhPIWMdFROPbr r9C1jRW1V5aX4eRvp9EhLtbmPY7j0COlu10rgZU5kzMwf8WmJgNnvE3e+RwkJHXB5N5hQgq1P1Ph udu1wpTPiuKeZbDuBkgDAJMwhKI79BcdZE7TWjb28iUMBfOwKEGkRVUcBq64aiPSlQtmeyzSjxc+ i2Hjpnk9eqmouARDht6JynJx5FFoeARSU1NtREp4DiNGDHcoUq2axfZ1K/D6x1/7XaSA5akw55H7 sepwBXKKLe5U7s4ovzxZSTgLc5q4jCbdoT8ablkp/IMvziXGVSPQMInP6W4YzUVFwzRWJwSaNCzB IxyioLHhk/c8KqdDGpW38RUx0VE4tHePU997ZXkZ+vXv51Ckw1OTsGrDTkS3jrX7vr+orq5EXIwW t8arkDneMg1jvyn2eRig+f5WgpUHAEAxUE7eCjq6s6BPYQVAR3emmJvEtUK5HqE+mVTzcSoY/x0n iPTQJT36vn9JJFJreUhPRFpZXoaM/l19LlLAMrK2T+iGR0YOROHZQ/XB5pwRxfmX8H+vzERYRAu7 Io3TqoQFU6BFCsBSDmjivdh8qgqH6uqhcmlan46qfJxKLFIAzE3jRCIFGsWjWqOnfFYNhaHA3doC 5tvrv/yaXyrw7y3FokdzWnIsvsw6iOiWOrc/4vyZ4xg+qJ+kk+5UChqz/jUcz7/zmcs7pviL4sIC xMW2xdAEdf2o6sO5qr0qKoppWWgcPSWyqdCqUIoZ+KToQqStyiuuNWuJcvPgSCEXf8qGQkzdWCgS 6fzpY7Dr2B8eiTT7q88lnRkap1Vh/vQxyLt0Ga9//LXkRAoA0S11mDCsHzafqkJemcU0yHdvugqi J3A9w2x2wmYGPmkjUsAfEf7WUTRNK+wdf+iSHtM2l9oIyrrbcYhGg9DQECQndUaHjp1xyx0ZTVbU e+/FRzHz9RXu98/HJOk06N/nJjzwrylIyxgfkIVSQ3ZkfoSdWy3ByRqNBi1btUJi9164OX2kUBDO ulvhnNu1eKluJa584w/vxn64GeFvd/LhtRqo1v06u9Vv4jU/65pdl2hTxGlVGDKgN6bNmitKzGtu pRKVgkbfxDZI7XMTOnfpjo5JyQhtEY0IrcUSYTDUovL6NdRWV6CmshwV10tQVlqKmuoKlJeVQ6+v RXV1/R9cZGQUIqNjkJDcE937DfboyeBLivMv4dZeSXafOr3itbjjtgGY9PQr6NOrF0JULHJnW+bO 3l5UuVs71eEs2bh1FuF/21bf4MEu0Q1Xc45GUU/oFa/FonffR+sOnTFySJrb11QpaNxza3eMfWgK 7rh/qk+23JEy+XkXkJyUgNIaM0Z1C0HrMBa7/jCJfkeVgobexOPIzDh0axXk1a3s7e5K3XU4lCMW O9Sjwzf4iqvEuGKwKGXanc423H7cV/t1Wn9MV0nSafDopAfx0KzXPK57+nfhmy+WY/iEJxCnVWHv Y60RE8Igp9iIb89U48ODVYIFRtgSnSMIeu2CV3LnrEmaAqwKymlZoMNaOdSjQwc1HdaKYlMfFbXx ndUuxwGYB1kMuEVVHCZkFrosqF7xWiydOw0//7AF504fQ86Jw/hh02rMmZwhRKdbcfWaacmx2LZm GX67UokZr334jxcpANz94HSMS09BXqkeb+62TMUSopWYNbAFcmfH4tvJbZCk0wj+fzAU+PbBzf7c hkmaVtjUR52KFGiikC8xGyzFexuEAVKlJigXX3QaBkZCGBjnWqJ83JmTDk9Nwpa9vznMIi0vLUF8 rM7l8LzhqUmYM/+NJiuieAtiqMKpvduxc+dO/LjvZxRcLYRB3QrDb+6Eu4YNxS13jQcVFNL0hfxE 7skjSOjeGwBwfFY7JETbToE2nawS6vk3e68GhoJxVjvRDopUeFtLUV82yKkWndaeotggih0kDowg WgW4W50H/jbsyEEXN9ICgIKrhSgpuOzw/TNH96PGhVF0XHoKjv28G1v3nfaPSM16fP3pu3jq4VHY uXMnlEoFBva7Bf363ITCwiIsWLUF/UY/ilaxHXAy+0vf98dFOif3ErasXLSnPkaWuqwXdupruJs1 36F5Iyp3awuRNgCAHfR8kyIFXCyNblw/UZyqYuChfPeiQ3NFw/lpj/fy3VrsWOvQ9+5xI3RtYmE0 GnDl0kXsP/Sr3bTfhoxLT8GcN5Y1a3MITygvLUF4eBjA2F+UFZ49hHnPPyNsrnbih/8iedD9/uyi Qw5kb8Ut6RlQKWjkPtseMSEM6FNVYLcUgRsWbeM1CnrlvEfz1Ib7LFihO/SHcsynLmnQpYPcjQMg uiAYZ8QBAMauLbCbOeptjv2826UK04Hk/16Ziekvv4eY6CgU5p0DVOF++VyO43Dq8E/448xRlF+/ jsiYlkjq2R8dk24EAHRpHYIzBdVYmhGDaX3DAROxCJIj4ONUMA+PFgzUxYyAAAAOQElEQVTzitX5 HgXWu+LPd4ZLlVzdjQOgioyAyTKHTetou5mBt0nSaQIq0vy8C3j1ibHo3TESwUoGkRoFeneMxI7M j0THPTZvMZK7dUFRcQlO7tvpl77NnTISMWEqpNxyG0ZNmoWHn34Vwyc8gRu6pKBdZDBefWIs7rj1 FgDA1tN1A4qCAt+pbgufPD2UH14Gu7EQMPDgk9wPqnfVn+8Ml0sOMwOfAqUWxws2DnQV4AjoPyyV 9kZ1C3Ea/e4NZv37cZ9e3xHFhQV4cuxgdLyhE15avh6nLpWhb2IbdO+ow6lLZRg2bhq++WK5cDxF M1jwnKWvOecu+Lx/33yxHAtWbREtPlUKGlo1C5WCRl6pHi8tXy/sSbXvTz1MdYtk0rpBkh9HwPxS gaA3/rAMQm5iExCtjgQ7YIZb13BZQe7GATA/W7wYMSEMXkp3vGV3c5k5Jh1TXnBestAXbFzxBhLj 47B0/Q/oFhuBDR8uRHlVLXafyMPuE3k48GM2VAoazz77nOi8djrLTWsd3bxM1KYouHwJ02fWp4LH aVU4PqsdyuZ3RP68Diib3xG5z3XA0owYJOkso6TexONoviV9mm9nZ+Gk5932Tjny57uzdQ/g5jbo zI33gWopTrfg7oyyWwu+YcHWf/eLwKhu3jXLaNUsVi6YjSWZWV69blOUl5Zg/OAeuO/RFwAAn70z D4fOleDeac+LPFw39k1D38Q2NgvJynLL6rpjlx4+6yPHcRg3rJ8obHLhnS1szE9xESym9Q3H0Rmt sTQjBioFjaN1u0iLRlRPUdEWfTSAatkFzI3up7i7JVSKZig2fa6ojYQwlrA9O7DbigEDDwVDIXO8 DkszYqBVNy9rIE6rwpzJGTh7Ic/vI+neHRvQvVOsEFcQomLRrVc/u3bf6upKnDhfYOOk+Hb7DkzN GICWiX180kdCCB4bfZvIQvLgTWGCmYk+VQV2YyHYb4pBn6oS7OHT+oZj7+P1uXMkhLFJtHMX8+1a m2uw6XPd3l4ScFOoAMDE9aHorsNFbVxqBEiUrWmGKjFC8ckVIQV2Wt9wrBnrftJYkk6DqRkDsH3d CvxeUI7XP/7ar8EexfmX8MjIgRgw7H7kleoxf/oYLH95BvJK9eifPkw0D7WyYOYElNaYMWXsSKGt vLQEJ8/kYsUax3sLNJcXp44SzGCA5Q/73RGW6QZVaoJikyW2lNlXBsXaAigX/Sk8+bq1CrKs+uto /Mh2h4ZFl63QXYd7tGEv4MHu0oD7cQAkhIH5vlaC6+zpbcVYvr8MWjWLxa++AF3bOBRczkN5aRGM RhMiWkQiQqtFh6Qe6HzjzQGL2ywvLcFbz07B4s+3QW/iEadVYfWnq5A2wmIBaZg0uHTuNMx4zbLn werFL+Hhp19Fkk6DY3+WClOCwrOH0LJTikN7a3Owl3qjUtDY+3hbdGtleYwrPnC84RnXLwLmoeIc qeZETHniz/cJ5n3LbUtUJmocF8NiKGJ4qh3RL+xEKl+7gTx4U5hQ9Gv+9DHEYDB4UuPMJ1y5eJ7M mZwhFGVTKWgyZ3IGqaqqsDn22M+7SZxWZSmeNiadzJ8+RihklnPisF/6azAYbMpmqhQ0+XZyG+He mG/XNl2sTBck3CP9wk7EdH8rz0pJJmpstGHet7xZpVc8Vjcx1RLjymFuxQGQKCVM09qChDAwcQQL d5UKcQBJOg2ee2YWxj7xYkDC7oxGI7I3fYYPli1B1uEcUcDLzz9sceqKzc+7gPS+3YWFU5JOg693 7vFp4YiGnz3+7jQbr5219DngZpImQ8E8Ihpcn3DP0pAc+fOnbgelCPbvaGqFy9lp+5fTxF8urwsi hrnxwvHfTm5DknQaYSSI06rInMkZ5Mj/viM8Z/bpSFRVVUG2rVlGpmYMsClpOS49hWz4cCFRKWiS lhzrcMT/afuXoiK5UzMGkIqy6z7tt5Vta5bZ9FuloMnacbr68o0T2xDCUB6Nioa58W6fa75da/uk dXF3Pmc0W+HuxgEAFr+v6UGdMFk3cQTrj1Vi8b4qkTlHq2bRL6UTBva7Bd173YLk1CE2+fLucK24 CL/s3oqDP2Zj14/7cODsFdHIGadV4cFRQzDthTeFUpY7Mj/CsHHTMC49BV98/ytKS4px6IevsXPr Bmz+fq9gAkpLjsXCd5f5JQimvLQEjz8w2CarQatmsWZsS2Frc+qyHspVVzyOISXhLCgD7/L5zfXn O6PZF/C4HoCdjFTAkgnw32OV2HZWb7f8jkpBo0NUMFpGaREaGoJQdRCio8S2uppaA6qrK1FZY0DB 1UJU1xpQWG5wGB5oFWiP3n3RIro1amsqoa+uRFlpKQquXELmV9twpqAaWjUruoZWzWL04Fts0mN8 BeE5rHrzBTz32rs23yVJp8H6sVGCrZTOrYHi83y/VuVrrj/fGV6ZM5i+n0+4X8RVAZ2tMBtCwllw Q6LAdQ+xyR/PKTbiUJ4ex/INOHiVRlFZjVdqR3mKdSeSgf1uQf8hGeiddpcoWa+6uhL7vv0v7rh/ ilc/lxCCLZ8twZy58+xGok1PjcDLd0QitG4kY45Wgt1U6FeR8nEqmB4TP+2YnhOguOMlr2jMKxch tWXEuGIwSG29KcPdiTgJYcD3CQd3Y6iwa7Q9TBzBhVITyvU8Kg088htMMWpMBGoFBbXScsMigmmE BtFoFcpCxVIoqjKjsIpDWS2PkmoOhZVmlOt55FeYcfYaEUQwPDUJI+6+GxFaLaJ0cYjt1BWxHZMc LvKMRiM+Xjgby1aswoZtO70WZlhdXYnVb7+IZStW2RVokk6Dt4dFCI96cATsjhK/b3AG2MnPD46A clqW265SR3htFWY+up6Yv5snavO0cAGJUoJPUINvHwzSOsgm2NYXmDiCkavzhcrW49JT8Oyr7zqN yirOv4TVS17G+6vWoajS6HH5oYYQnsO+nV/h8xXvY1PWz3anK3FaFebdHo4xKaFQ1D2FqCIjFOuv giow2Bzva7ieYaL9ogCAvfNVsD3GeE1fXruQL3f8IyEMiFYBEq0EwlmQcBZEzQBKGkRdN3FX0gBL AWYCGC2fR9XwgJEHVcNZItZDWBANYzlHzYBoGNHEv7HJDLCIov9NiWjfrh1aaCNRW1ODszlnkXsh T1TMrVe8FtOmTMZtI8cLcZ4ufTdCcOHsCez+ei1278rCd/tPOZxLD+qkxqTe4aKoe3AE7K5SSyn7 QFQJdzM/31O8atfyWj0Af8JYYi9NY1oJos0pNmLRnuvYeLLKYQKhSkFjaIIarcNYm4WfVs2ie0cd WreMRHRUFDQaDVSqYASr1bheeg3V1dUoLilB7oU8XLha4TQHLEmnwYSUYNzbPRRxEQ3iJOpC75hd gd0UxN38fE/xugHWuHkG4c82KFTrQT2AQECilDA90FI0zzJxBEfzDcgpMqK42mLViNYwSIhRokfr IOGxCwCnrhrw1ckqfP8nHG4m7ApJOg166hjcGh+MWzuqxeIEAAMP5lA5mH1lgd21Bg7y8xOHQjnq Pa/ryusXbG49gEDD9QwDN7CF0wVdU1QaeBy6pMfxfANOFxpRUGlGOadCda0BrUMsj+ewIBqtw1iE q2h00CqQEKNEUoxSWLmLO0VAn68FfaISzLHKgG4E0hB/+vN94tIy71tOzD8uEbV5mmsTKPg4FcgN avDtgkEiWEBdNwcrM4EqM4MuMIA6VwOq3Ay+Wwj4zhrwHYO9VqKRquJA/14D6nwNmN+qAr5pcmMa JnBaYQc+CbbfdJ9oyicX9SQO4G+BigbfPhh8fDBIyyDw7VSixZpdDDyocjOoIiOo6ybQF2pBFRgC /lh3SgD8+T6pfU4pgqnG+wJY6wH4a1+AgKDnLZkNDZ4cJIQBQlmQukqGVF3SI2o4S5zuX/AP12F+ vg+DTnyWdcckDKHouJtFbeaBLZodNf5Xg6riQBUYQOfpQefpLaOldcT8C4qUhDAwDxSv8um4m0X1 9n2BT9ND2TteAqgGwgyiwQ1zkLkq85eAGxYtns5QjOU++xifCtWf+wLI+B5v5Od7im8T7gGwA2aA ChankjisByAjaWzy84Mj3M7P9xSfC5UKjqCYATNFbd7aF0DGf9jNzx8w02tBJ03hc6ECANNjLKjo BFGbo3oAMhLEXn5+dAKYHmP91gW/KIWiGarxhNtZPQAZaWE3P/+Ol7wadNIUfhvSmLg+FJ0o3i7c UT0AGelgNz8/cajXg06awq/PXva2ZwG2wTzHzo7CMtLCZqdxVmW5j37Gr0KlI9o2a18AGf/isN5+ RFu/pz37fTXD9JkEKrytqK1xhQ4ZCcBQlvvSACq8LZg+kwLSHb8LlVIE2+4LEKME19c/1ZdlXIPr G24T6uhrf74zAmIfshsHMDjyHxcHIFVICGPZs7YB/vDnOyNghkw5DkC6BMqf74yACVWOA5AmgfTn OyOgriE5DkB6BNKf74yAClWOA5AWgfbnOyPgznY6ZYwcByAFHPjz6ZQxAeqQmICrgWZYOQ5AAjjy 59MMG/DRFJCAUAE5DiDQSMWf7wxJCBWQ4wACiVT8+c6QjFDlOIDAICV/vjMkI1RAjgPwOxLz5ztD UkKV4wD8i9T8+c6QlFABOQ7AX0jRn+8MyQkVcBAH0OhHlWke3OBIyfnznSFJodqNA+gTLscBeAk+ TgWuj3g6JQV/vjMkKVRAjgPwJVL15zvDJ0XSvAEVHEGZf/mCmL9/RWizxgEwv1UFsGd/bbiuIZL1 5ztD0p3jOTMxfToSpDgn0F3520JFJ0Ax8WvJuEodIdlHP2A/DkDGu0jJn+8MSQsVsB8HIOMdpObP d4bkhQrYiQOQaT4S9OfLyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjI/H34f4DnQZLCUbKg AAAAAElFTkSuQmCC "
+ height="15.781592"
+ width="15.781592" />
+ <rect
+ style="fill:#006699"
+ transform="scale(-1,1)"
+ rx="2.2046731"
+ ry="2.2046731"
+ height="14.598539"
+ width="14.6"
+ y="15.596729"
+ x="-20.404631"
+ id="rect11" />
+ <path
+ style="opacity:0.7811159;fill:url(#linearGradient3003-3)"
+ inkscape:connector-curvature="0"
+ d="m 16.547311,16.220877 -6.8853601,0 c -1.822591,0 -3.289818,1.479199 -3.289818,3.316609 v 6.71746 c 0.05899,1.434231 0.285919,0.527542 0.71786,-1.060763 0.502007,-1.845951 2.136929,-3.459324 4.1279311,-4.668496 1.519641,-0.922866 3.220687,-1.512195 6.316909,-1.568259 1.755942,-0.03179 1.600963,-2.278914 -0.987471,-2.736551 z"
+ id="path13" />
+ <path
+ style="fill:#ffffff"
+ inkscape:connector-curvature="0"
+ d="m 10.476047,27.848959 0,-6.634531 -2.2051841,0 0,6.634531 2.2051841,0 z M 9.3737469,20.30806 c 0.7689821,0 1.2476431,-0.50946 1.2476431,-1.1461 -0.01433,-0.651007 -0.478632,-1.146319 -1.2330431,-1.146319 -0.754309,0 -1.24757,0.495319 -1.24757,1.146319 0,0.636676 0.478537,1.1461 1.218589,1.1461 h 0.01433 z"
+ id="path15" />
+ <path
+ style="fill:#ffffff"
+ inkscape:connector-curvature="0"
+ d="m 11.696607,27.848959 2.205184,0 0,-3.705042 c 0,-0.19829 0.01433,-0.396375 0.07256,-0.538119 0.159417,-0.396178 0.522256,-0.806504 1.131427,-0.806504 0.797962,0 1.117191,0.608404 1.117191,1.500296 v 3.549333 h 2.205038 v -3.804176 c 0,-2.037868 -1.087919,-2.986065 -2.538794,-2.986065 -1.189607,0 -1.711922,0.66495 -2.002097,1.117849 h 0.01472 v -0.962213 h -2.205184 c 0.02894,0.622544 0,6.634532 0,6.634532 z"
+ id="path17" />
+ </g>
+</svg>
diff --git a/src/skin/socialwidgets/Pinterest.svg b/src/skin/socialwidgets/Pinterest.svg
new file mode 100644
index 0000000..9b7c9e5
--- /dev/null
+++ b/src/skin/socialwidgets/Pinterest.svg
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="65.675446"
+ height="26.173176"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="Pinterest.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3785">
+ <stop
+ style="stop-color:#fcf9f9;stop-opacity:1;"
+ offset="0"
+ id="stop3787" />
+ <stop
+ style="stop-color:#f1efef;stop-opacity:1;"
+ offset="1"
+ id="stop3789" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3785"
+ id="linearGradient3791"
+ x1="39.280788"
+ y1="12.902368"
+ x2="39.280788"
+ y2="32.148937"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.31100674,0,0,1,0.772507,0)" />
+ <linearGradient
+ id="SVGID_1_"
+ gradientUnits="userSpaceOnUse"
+ x1="94.999496"
+ y1="1181.167"
+ x2="94.999496"
+ y2="1308.795"
+ gradientTransform="matrix(0.056,0,0,0.056,7.3169971,-50.015884)">
+ <stop
+ offset="0"
+ style="stop-color:#FFFFFF;stop-opacity:0.85"
+ id="stop5" />
+ <stop
+ offset="0.66"
+ style="stop-color:#FFFFFF;stop-opacity:0"
+ id="stop7" />
+ </linearGradient>
+ <linearGradient
+ id="SVGID_2_"
+ gradientUnits="userSpaceOnUse"
+ x1="94.999496"
+ y1="1308.001"
+ x2="94.999496"
+ y2="1415.5118"
+ gradientTransform="translate(34,-1170)">
+ <stop
+ offset="0"
+ style="stop-color:#000000;stop-opacity:0.15"
+ id="stop16" />
+ <stop
+ offset="0.6626"
+ style="stop-color:#000000;stop-opacity:0"
+ id="stop18" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="4.5787681"
+ inkscape:cx="-11.149684"
+ inkscape:cy="29.222115"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="1344"
+ inkscape:window-height="1419"
+ inkscape:window-x="0"
+ inkscape:window-y="19"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-0.62121129,-12.484656)">
+ <rect
+ style="fill:url(#linearGradient3791);fill-opacity:1;stroke:#e8e4e4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect2985"
+ width="56.068317"
+ height="19"
+ x="1.1212113"
+ y="12.984656"
+ ry="2.1487894"
+ rx="2.1487894" />
+ <text
+ xml:space="preserve"
+ style="font-size:14.40710354px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="22.633839"
+ y="26.724609"
+ id="text4002"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4004"
+ x="22.633839"
+ y="26.724609"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;font-family:Arial;-inkscape-font-specification:Arial Bold">Pin it</tspan></text>
+ <image
+ y="22.847776"
+ x="50.486599"
+ id="image3193"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKoAAACqCAYAAAA9dtSCAAAABHNCSVQICAgIfAhkiAAAIABJREFU eJztnXl4E9Xex7+zJE2TbqQLBGiBIrQFikUWsSxWKSIoFMSFRa6yiYoXFMUFxKuooKIICq8ioiJC uQIioCDWAlcB2ZRVoBVQCrR0oXRvtpnz/pFm2mmWJmmWUefzPHkeOJmZnGS+PXPObzuAjIyMjIyM jIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjJehAt0BV+DLLhPjyqGAWR/orvx9YFVQTt0BOqLt X0IDdKA74Arm3W/JIvU2Zr3ld/2LIHmhcnmHCH92R6C78beEP7sDXN4hEuh+uAIb6A44g+fMxPTp yEB342+N+fv54DkzoRlW0lMAaQv12HqQ4hxRG7uxEMxvVQHq0V8frmsIzPe2FP5PinPAH1sfwB65 hmSFSmrLiHHFYFEbdVkP5peKAPXo7wHzSwW4vuEgbVVCG/fTUpDaMkIFR0h2VJXsHNX803sgtWWi NnZbcYB68/ei8e9Iastg/um9APXGNSQpVL44l3C/rhO1MYfKQefJK39vQOfpwRwqF7Vxv64DX5wr 2YWVJIVq/n4+QLj6BgMPJuta4Dr0N4TJugYY+PoGwll+d4kiOaFyOTsJn3dQ1MZmXQNVxTk4Q8YT qCoObKM/fj7vILicnZIcVSUlVGKqJebsN0RtVJERzIFyB2fINAfmQDmoIqOozZz9BoipVnJilZRQ uUOfgJRfFrWxO0oATnK/298Djlh+3waQ8svgDn0SoA45RjJC5csuE/P+D0VtdG4N6LPVAerRPwP6 bDXo3BpRm3n/h+DLLktqdJCMUG38+RyRzVF+gt1WLH5qSTAOQBJCtefPZ/aXgSoxOjhDxptQJUYw +8U2a6nFAQRcqDxnJo3NIlQVB3ZXaYB69M+E3VVqY1mxxgEEqEsiAi9UO/585rsSQM87OEPGJ+h5 y+/eACnFAQRUqKS2jHA/LRW1yf78wMH8UgHqstj7Z40DCFCXBAIqVNmfLz2kGgcQMKHa9ecfrZT9 +QGGztODOVopapNCHEDAhGrXn79dHk2lALO9WHJxAAERquzPlzZSjAPwu1Blf/5fA6nFAfhdqLI/ /y+CxOIA/CpU2Z//10JKcQB+Farsz//rIZU4AL8l93F5h4hp7XhRmxT8+SRKCT5BDb59MEgEC6gZ yxtmAqrMDPpiLegz1aAKDAHtZ6CwxgFwA1oIbdY4ACauj9+SAf0iVMJzxPhJhqgt0P58PlED8yCt KBuzMSRGCb6zGhgcCeqyHmx26T9ymsLuKgXfIwwkhBHazN/PB+E5QtGMX8TqF6FyRzOl489X0TCN bgm+W4ioOafYiFNXjSip5lBt5BGtYZAQo0SP1kFQMBRIWxVMD7UGc6gc7Nbif9biry4OoHE9AO5o pt+64HOhSik/n4SzME1qAxKjBAAUVXH48OcyfHigAqU1ZrvnaNUsxqaE4LnbtIgJYcD1CQeJUEDx ef4/SqyBrgfg88WUZPz5Klok0jW/VKDzW39iwa5ShyIFgNIaM5bvL0PKu3nIPmdZAfOd1TCNaeWX bkuJQMYB+FSoUvLnm4dGCSJd/ON1TN1YCL3J9alHaY0Zd626gk0nLeWE+G4h4PpF+KSvUiWQcQA+ ffRLxZ9PdEHg+oQDADadrMKcRoZsd5i8oRDdWimREK2EeXAk6OOV0nX9MhT4NkEgsSqQcBYIYUEU FCgTAUw8qCIjqGsmUJf1Ln8HZnsxuC4aIKhujPNTHIDPhMrl7CSmr54Qf1iA/PlcX4tITRzBC99d b9a19CYes7YV49tJbYAgGtzAFmC3ey58X8AnasD1DAOfoAEUrk0fqct6MGeqLSkpTha51jgA893R 9Z9XFwfAJAzx2VzVJ0IlplpiXDlM1EaVmgLmz+e7WFb4W09XI6/U8bRDq2YRomJRVGl0Oi3I/r0G 2edqMOgGNfgeYYBEhEp0QTDdE2PX5FZUxeF6LYdyPQ+1gkKYioEulIGizrpE2qpgbquCOU0Ldk8p mP9dd7hYZA6Ug0uNANEqhDZrHAClCPaJWH0iVLv+/MYeDj9BopSC/W+HAxvouPQU/GfxSnRO7gUA MBqNyFz2Gh59/nWHgs08WolBN6hBQhhwPcNAVXMgkQogiLY8ZhU0iJ3RjKrhAAMPqtxseeyWmy3B H838bbh+ETAPjQLqhFdUxeGLXyuQfa4GR68Y7S4YVQoa3WIjcHMrHg+khKJPrApQUDAPjgSXpIFi db79J2CdR9H0UGuhyddxAF5XP19x1WKOauAqpXNroPj0irc/yrX+xKlgeiwWAHDXJ1eQ/bvYdz1z TDqWZGbZPXfjijdw36Mv2H1Pq2ZxcU57YURqFhwBVWAAnW8AlacHfa4GVLljS4QIhoJ5dEtwPUIB AJUGHu/+eB2Lfypza7EIAEk6DVaM0loEC0tUm/KDSw6nAqaJbSwOESusCsppWaDDWnldV16/oHHz DHHqM0egXJIXMFcpn6gR/vJ7vJePMwXiUbWkqBCR0TEOz+/dMRJHLtj3oB2f1Q4J0UpRW6WBx/Va HhV6DjUmgsoGAcihQTTCVTRaBDOIaeDlsQdVZARzvNK5+5ahYPpXa0Esp64acM+aIqfTG1dYMDQK swZaXKbM0UqwX161exyJUsL4ZJwwigMAnTgUylHveV1XXn30S9GfT5WYhH/31DE4U1D/nkpBOxUp ADwweiSOLLL/SPuobs59ttiI/CoKf5TUujyKqRQ0YkKV6NmaRVKMEl1bBWFAh2BBwCTGYlWwum+Z Y5UWJ4l1dGMomMa0EkSafa4Goz8vcHsUtcecHSVo10KB0ckh4HqEgj5QZtek6M84AK9djPAcMX52 D0jh6fqLV3FQvvNnwFOfjXPjQUIYbDpZhfHrCkTvnTqyF1179nN47p6t63BbxniH77uDK4u1JJ0G t3dQYFiSBgM7BIunFgYezKFyMPvKwA2JEh733hRpw77mPNsOoUG001EVKhrGp9uL4gColl2gfPgr eDMOwGsGf+74BpFIAenk59OnLUb6EV00SNJpRO8tfdX+HJTjOOzI/Agr318kak/SaTAuPQVTMwa4 9NkqBY2pGQPww6bVKKrQ4+K1WtQaOeRfysMPm1Zj0exJGJeegjitZV54pqAay/eX4a5VV9BuwZ94 elsxTl2te/QH0eAGtIDx+Q4+FSlgcXCsqzPuc91DAJUDqdirB1B4GtzxDV7tj1cUb/XnN3SVUpf1 UC6/5I3LN5uGc6nsczW4a5V4YffT9i/Rf+h9AIDfftmHlW+/jDVb96C0xow4rQr9b0rEqHsfwOD7 piBcG4UdmR/hwSnTnbpe47QqPP3YQ5g4+w2EhrvmwbqY+xuyNq3G1m++QdbhHJH4esVr8VTfIIxO rg+mOXXVgDtW5jvtR3MY1EltsRcDUKzOdxo5ZpweKzKLUcERUE7LgqT2BTB9P5/oF3YSvbg4FSGA ZF6mYVFC3+bcriUAhJdWzZLP3plH0pJjhf+PS08hP2xaTXjOTBry2TvzROc2fsVpVWTlgtnEbBaf 5y5l14rJygWzSa94cV+TdBqydpyO5M2NJ3FaldO+NPx+49JTyPKXZ5CVC2aTOZMzbK5r76VS0MJv Zu4X4fT35eJUNhowfT9fOlE7fHEu0b+RKO7g/a0CLkybF0MRw+z2Qh8fvCnM5sb0iteSlQtmk6qq CrviWTR7klMxLJo9iRgMhmYJ1B5H/vcdGZeeYiMiR31p+Jo5Jp2UXSu2uSbP806/j/VV/HJHyz0d FtX0YHB/K7FY30gk3ooDaPYc1Zy9EDb+/J3S8NQIMBTMQyJFnpRH+oZDpbB8/bTkWOzeshaHz1/D lBfegkYTKjqdEIK5U0ZitoPV/7j0FJw8k4Nn3loFpVJp95jm0HPgEKzNOoqcE4cxLj0FAJqck2rV LHZvWYslmVkI10bZvE9RFJ55axWGpya51AfKhbUGs7PEth5A9kKXrt8UzRIql7OT8H/sFbWxP153 3VjtB0iUEsZH2womlKIqDlM2FGLg/11Ct9gI7N6yFrtP5CFtxDj75xOCaaNuxYJVW2zei9OqsPO/ K7E26yhax8X79HsAQOfkXlibdRQ//7AFveK1Do9L0mlw9MQph9+pIa2ibUVsRatmEWoNPjE0LVSq 3Az2R3EsBf/HXq/UA/BYqHbz80tNFh+xROATNTA+UT/Jzz5Xg/4f5GPjySosmj0JB3KLmryZ00bd ipVbfrJpn5oxAKcuFOCO+6f4pO/O6DtoBA7kFmHR7EnCU8FKkk6D/x05g7iOCU1ep7K8DDt/Ouzw /VvjGyyOLrnmRGD+dx1UqUnU5o16AB4b/KXkz7cH1zMM5lExFsM4R7BwVykW7CpFnFaFAz9m48a+ aU1eY+6UkTYi1apZrF6xBHc/ON1rfa2ursTh7G04ffQgcs+eRnFJCSprDHj1nf9z2E+GYfDMW6tw 2933455RIwVvVP8+NyFK17bJz6wsL8OIAd2derHu7V43BTLwoK+4mNwYgDgAh/AVV4l+UbJo4myc 2CbwC6a6l7lfhNCv4pc7kkGd1AQASUuOJUVX811awNhbaKQlx5IrF897ZYF05eJ5smj2JJKWHGt3 YbRo9iSXr1VRdp0MT00Szh2XnuJ0UbdtzTKSpNM4XUQl6TSk8rUbLAupUTFu3wPjxDbihdWiZMJX XPXvKGbcOkvcidduIHyUMuACbSzS3Oc6CDckLTnW4Wq+MRs+XGhz4+ZMzmi2yYnnebJtzTKRqOy9 0pJj3b622WwmUzMGCNcYnpok6u/Fc2fJ0rnTXDZL/fh4bP29DWfdvg98lJLo64QuDGZbZ3ksVLeN sXb9+T9dl0TwMNczTMiUzCszI31lAfJK9egVr8WeE3/arObt8cuPO9E/fZiwqvbGo57wHD5f8gre fHuxTVCMPY787zsk970Nl86fQcGfuTDU1uJ6cT7CWkRBHRqOFjGt0T6xu13rxItTRwkLv+GpSWgV HYW9h361+7lJOo3d9rXjdIJjgc26BsbDtHbzsChRHAAAKMavhSdxAG6dIGV/Pp+ogelBHcBQKKri 0P+DfOSV6qFS0Dj+y0Eh1tQZ14qLcFNiO2HelqTTYMO2nU5jAZrimy+W45X/vOQwAssejgTUmDit CvFtonFj1wSk3zUSt436FzSaUDw5djCWrv+hyfNX3tsSt3ZU47PD5fjwgCUreM3Ylhh0gyXQhc6t aV62rRfjANw62Hx0PTF/N0/Uxm4sDHgpcxLOwvhUOyCIRqWBx8AVV4UbvfzlGXj8P0ubuIJlNMro 3xXb9p8BYLGtfr3nV7s2SFc4f+Y4npoyVrieP1ApaAzunYBHHpuOzNUfY90Px5wePz01Au8Mt6SU mDgCvZkI5ig6twaKzIJmD0ANn3JW2DtfBdtjjG+ESmrLiPGjO0Fq6utmSsKfz1AwPtpWMEE1DI5O S47FruMXQVFNf823n50sGPTHpafg028PemS85zgO777wCOYt+czrgSLuEKdV2V3Rx2lV6BRJIzFa iWFJGmH0bIi3i2zYxAGoI6F85Du34gBcNk+Zf3pPJFJAGvX2zUMihR9hftY1UQT/ko8+d0mkB7K3 Yt6SzyzXmD4GL76/zqXzGpN78gjGjxzi1mPeVzQWaa94Lb4aG+EwYJsqNQE1HNhtxV5PZ2e3FQtZ FgBAaq65XQ/AJYO/lPLzG8LHqcClWiKTss/VYEGDSf/UjAEu2Uory8vwwP0PQG/i8dk78zBvWaZH Iv144bO4sefNkhCpPY5cKMXJq2JbKFVqAn2qyrIY/u9VKJdf8sk99UY9AJdGVEn68+tyhcBQqDTw eGxz/WivVbNYuHKjS5d5+qERKKo0YvMnizFy4lNud6O6uhKPjBzY5HxQCjyzvQxHZ1ge9cyhcrCb i/z22czOEtt6AG7EATQ5okrVn8/1DRcqn7z8/TXRo+7Jifc2mWICADsyP8KmrJ/xzfpPPRLp+TPH 0buT7i8hUsASlG2t9ML1CHMcDO0DmhsH4LSnxGyQpj9fRYNLswRlnLpqwPIG+3hq1SyefP2DJi9R WV6Gp5+ehW+3bsKge/7l9Fij0Tbna++ODejTq5dLZiQp8e6Buse/ggLXM8yvn+0wDsBsaFKsToXK HfxYkv58LjVCsM0918jR0DI8CCMGdEeX1iHYu8NxOsSSuY/hkzXr0HfQCKeftWfrOky862ZR2+rF L2FwxhifRdb7kiMXSoXUFuv83m/YqTBOyi+DO/hxk6c6FCpfcVWS9fZJCANzXSpv9rkamzz9MwXV 2HPyEnp07SSklzQmNycHw+5/uEmR7sj8CEPvnYDv9p8Cx1nm6K8+MRYPP/1qQE1PzeXTwxa7N9Eq wMc5LmTsCxzuC9BEHIBDoZr3SLPePjewhTAh/8/uWrvHaNUsFq3a5PAaHW+4AT0HDnH6OdlffY57 HnoMehOP0hozTh3+CU+OHYyXlktjE9vmsO1s/X0lsf4VKuBgX4A9zvcFsLvql2J+PgCQKKXIHOXI FPTmi085DWRmGOfFHw5kb8XdYyaKRs2x99ztdD46PDUJwybMQLt27dC6dWtUV1fjxIkT2LZtK3Zl 7ZTUCJxXqkdemRlxESz49sFg9pU1fZIXsVsP4LdtTusB2DRK2Z9vLSFj4gj6LC+wKxx3vFH2OH5g D24fNNjl+Wdyty548623MXToUIfH5Obk4KlZT2H79h0Oj/E31sATqtQE5aI//d8BN+MAbEZUqebn 84kaoSrIJ4cr7IpUq2axenOWxyLNz7uAEXcNdVmkw4YNxfp165pMh+6ckIBvv92OJ5+ciaVLvVOh OU6rwo2JHdAqOgrRURYLSHV1NS7kXcG5P/KatEbs/7MWo5NDLHlkDOX/BbK9fQGc1AMQCZXXVxKT ROrti1DRFuM+LDlPr2TZf+SvWPyqSykY9qiurkTGbb1drtuU3K2LjUg5jsOGL/+LAwcPIjExCRMm jBeF4i1ZshS///67xyNrr3gtHhg9EvdNmYV2nbs6PfZacRE2f/w21maux56TtvEY+RX1f4ykhSIg 0zq7+wL8uAS8vpLQqlDHo41U8/NNo2KE/ozqFmI32HdqxoBmBTQ3Tkdu6rV9+3bRNTLXrSUx0VGi Y7RqlnzwwQei4/Iv5bmc6mx9pSXHku3rVnj8/Y79vNsmWLtXvFYS99jVegDCql+y/vxEjais+eZT VTbH9IrXYtmXTcdfOuK1f49zy7uU3K2LaE66Y8cOTHxoAoqKxTZdVhOB0aPE+2vp2sZi2uPiStzO GJ6ahOnTH4dBX40D2VtRcNn9aLUb+6Zh677T+GHTaqF0UHVtvd+f7xu4vQjcjgMwrp8oVvZ8z1IQ vPniw1miryuAkDc3nmjVrM1oo1Wz5OK5sx6PNps/WezW6AaAzJw5Q3SN5G5dbI5RKWiyb98+u5+5 fft2tz+z8XdOS44ly1+e4XYOlzW/SpRu4mKBCZ/e5/mN0lbWTxQJlQYc+PP3lAbWn89Qloj9Opvp xC+v2ixyVAoaWzau83heeiB7K8ZOe8bt8xIT64s2FBcW4OSp0zbHTHv8CaSmpto9v2N882oAlNaY sefkJUx/+T20adcR4wf3wPkzx106NzQ8Aht3H8Pg3gm4Y+WVei/VgBZ+d6laocrNYPeI1x2N4wBo qfrzzaNbOowztbLm/dcdep+aIvfkEdw1YrRH9s127doJ/86/aj8C6cLhLDz55Eysz1yHHTt2oLiw vtxlpLaF3XNcRatm0Stei7TkWKQlxyL3Qh6GD+qH1Ytfcul8pVKJjbuPoW9iG9yxMh9FdeXPzRkx ILqgZvXNU5qKA2Cl6M/nbteKyiousJNctmj2JNw77XmPrp978ggGpw3w2Fd/8eJF4d/tY9vYPWbb /jPA/jOwJsFs374dQ4fqAADXSt0fBIanJmH06Hsx+N6HHTozKsvLQHgOFO3coQFYxPr1nl9xS7f2 uCezDLsnaaFQWIoDK9/L8//9d1QPoC4OgOaOrBEdT1VxAfXncz3DLJWWYdmfdEJmoc0x86ePwTNv rfLo+laRNqd8+Nmz9XlQ4dooDBvm2NgPADHRURg0aJDw/19//cXlzxqemoScE4exdd9pPDRrvlOP W2h4hEsitRKujcKGbTtx6lIZnq8L7iExSpiHRLp8DW9Cn6222dzCqk+a6TVB9AYJYcAniovd+gs+ USMYgIuqOAz/rNBm1JszOQPzlnm2WezxA3uaLVIAyFy3TghSAYAP3nvXprROQ5YuXSrKv1rzxRdN foZWzWLDhwuxdd9plzJoPaVrz3748I25WL6/TNhCkxvQwu/BKoDl/pNGqTJWfdLMzVNAhYtLwJiH R4s2EPAHXM8wy+IJlg0bhnxSaCOoOZMz8PrHX3t0/QPZW3H7oMHNFikAFBWXYOXKlcL/4zom4PjJ 00ju1kV0XEx0FDLXrcWYsfX1rY4fP96kwb9XvBa/Hj3m8dTGXR6aNR/DU5Pw2OZrwuYYVgeL32Ao i+4aQIW3BXOzpbYXBTjeZc/TwgPuwvWLEHaCqzTwGPr5dZuAk/nTx3g8ku7I/EiIhPIWMdFROPbr r9C1jRW1V5aX4eRvp9EhLtbmPY7j0COlu10rgZU5kzMwf8WmJgNnvE3e+RwkJHXB5N5hQgq1P1Ph udu1wpTPiuKeZbDuBkgDAJMwhKI79BcdZE7TWjb28iUMBfOwKEGkRVUcBq64aiPSlQtmeyzSjxc+ i2Hjpnk9eqmouARDht6JynJx5FFoeARSU1NtREp4DiNGDHcoUq2axfZ1K/D6x1/7XaSA5akw55H7 sepwBXKKLe5U7s4ovzxZSTgLc5q4jCbdoT8ablkp/IMvziXGVSPQMInP6W4YzUVFwzRWJwSaNCzB IxyioLHhk/c8KqdDGpW38RUx0VE4tHePU997ZXkZ+vXv51Ckw1OTsGrDTkS3jrX7vr+orq5EXIwW t8arkDneMg1jvyn2eRig+f5WgpUHAEAxUE7eCjq6s6BPYQVAR3emmJvEtUK5HqE+mVTzcSoY/x0n iPTQJT36vn9JJFJreUhPRFpZXoaM/l19LlLAMrK2T+iGR0YOROHZQ/XB5pwRxfmX8H+vzERYRAu7 Io3TqoQFU6BFCsBSDmjivdh8qgqH6uqhcmlan46qfJxKLFIAzE3jRCIFGsWjWqOnfFYNhaHA3doC 5tvrv/yaXyrw7y3FokdzWnIsvsw6iOiWOrc/4vyZ4xg+qJ+kk+5UChqz/jUcz7/zmcs7pviL4sIC xMW2xdAEdf2o6sO5qr0qKoppWWgcPSWyqdCqUIoZ+KToQqStyiuuNWuJcvPgSCEXf8qGQkzdWCgS 6fzpY7Dr2B8eiTT7q88lnRkap1Vh/vQxyLt0Ga9//LXkRAoA0S11mDCsHzafqkJemcU0yHdvugqi J3A9w2x2wmYGPmkjUsAfEf7WUTRNK+wdf+iSHtM2l9oIyrrbcYhGg9DQECQndUaHjp1xyx0ZTVbU e+/FRzHz9RXu98/HJOk06N/nJjzwrylIyxgfkIVSQ3ZkfoSdWy3ByRqNBi1btUJi9164OX2kUBDO ulvhnNu1eKluJa584w/vxn64GeFvd/LhtRqo1v06u9Vv4jU/65pdl2hTxGlVGDKgN6bNmitKzGtu pRKVgkbfxDZI7XMTOnfpjo5JyQhtEY0IrcUSYTDUovL6NdRWV6CmshwV10tQVlqKmuoKlJeVQ6+v RXV1/R9cZGQUIqNjkJDcE937DfboyeBLivMv4dZeSXafOr3itbjjtgGY9PQr6NOrF0JULHJnW+bO 3l5UuVs71eEs2bh1FuF/21bf4MEu0Q1Xc45GUU/oFa/FonffR+sOnTFySJrb11QpaNxza3eMfWgK 7rh/qk+23JEy+XkXkJyUgNIaM0Z1C0HrMBa7/jCJfkeVgobexOPIzDh0axXk1a3s7e5K3XU4lCMW O9Sjwzf4iqvEuGKwKGXanc423H7cV/t1Wn9MV0nSafDopAfx0KzXPK57+nfhmy+WY/iEJxCnVWHv Y60RE8Igp9iIb89U48ODVYIFRtgSnSMIeu2CV3LnrEmaAqwKymlZoMNaOdSjQwc1HdaKYlMfFbXx ndUuxwGYB1kMuEVVHCZkFrosqF7xWiydOw0//7AF504fQ86Jw/hh02rMmZwhRKdbcfWaacmx2LZm GX67UokZr334jxcpANz94HSMS09BXqkeb+62TMUSopWYNbAFcmfH4tvJbZCk0wj+fzAU+PbBzf7c hkmaVtjUR52KFGiikC8xGyzFexuEAVKlJigXX3QaBkZCGBjnWqJ83JmTDk9Nwpa9vznMIi0vLUF8 rM7l8LzhqUmYM/+NJiuieAtiqMKpvduxc+dO/LjvZxRcLYRB3QrDb+6Eu4YNxS13jQcVFNL0hfxE 7skjSOjeGwBwfFY7JETbToE2nawS6vk3e68GhoJxVjvRDopUeFtLUV82yKkWndaeotggih0kDowg WgW4W50H/jbsyEEXN9ICgIKrhSgpuOzw/TNH96PGhVF0XHoKjv28G1v3nfaPSM16fP3pu3jq4VHY uXMnlEoFBva7Bf363ITCwiIsWLUF/UY/ilaxHXAy+0vf98dFOif3ErasXLSnPkaWuqwXdupruJs1 36F5Iyp3awuRNgCAHfR8kyIFXCyNblw/UZyqYuChfPeiQ3NFw/lpj/fy3VrsWOvQ9+5xI3RtYmE0 GnDl0kXsP/Sr3bTfhoxLT8GcN5Y1a3MITygvLUF4eBjA2F+UFZ49hHnPPyNsrnbih/8iedD9/uyi Qw5kb8Ut6RlQKWjkPtseMSEM6FNVYLcUgRsWbeM1CnrlvEfz1Ib7LFihO/SHcsynLmnQpYPcjQMg uiAYZ8QBAMauLbCbOeptjv2826UK04Hk/16Ziekvv4eY6CgU5p0DVOF++VyO43Dq8E/448xRlF+/ jsiYlkjq2R8dk24EAHRpHYIzBdVYmhGDaX3DAROxCJIj4ONUMA+PFgzUxYyAAAAOQElEQVTzitX5 HgXWu+LPd4ZLlVzdjQOgioyAyTKHTetou5mBt0nSaQIq0vy8C3j1ibHo3TESwUoGkRoFeneMxI7M j0THPTZvMZK7dUFRcQlO7tvpl77NnTISMWEqpNxyG0ZNmoWHn34Vwyc8gRu6pKBdZDBefWIs7rj1 FgDA1tN1A4qCAt+pbgufPD2UH14Gu7EQMPDgk9wPqnfVn+8Ml0sOMwOfAqUWxws2DnQV4AjoPyyV 9kZ1C3Ea/e4NZv37cZ9e3xHFhQV4cuxgdLyhE15avh6nLpWhb2IbdO+ow6lLZRg2bhq++WK5cDxF M1jwnKWvOecu+Lx/33yxHAtWbREtPlUKGlo1C5WCRl6pHi8tXy/sSbXvTz1MdYtk0rpBkh9HwPxS gaA3/rAMQm5iExCtjgQ7YIZb13BZQe7GATA/W7wYMSEMXkp3vGV3c5k5Jh1TXnBestAXbFzxBhLj 47B0/Q/oFhuBDR8uRHlVLXafyMPuE3k48GM2VAoazz77nOi8djrLTWsd3bxM1KYouHwJ02fWp4LH aVU4PqsdyuZ3RP68Diib3xG5z3XA0owYJOkso6TexONoviV9mm9nZ+Gk5932Tjny57uzdQ/g5jbo zI33gWopTrfg7oyyWwu+YcHWf/eLwKhu3jXLaNUsVi6YjSWZWV69blOUl5Zg/OAeuO/RFwAAn70z D4fOleDeac+LPFw39k1D38Q2NgvJynLL6rpjlx4+6yPHcRg3rJ8obHLhnS1szE9xESym9Q3H0Rmt sTQjBioFjaN1u0iLRlRPUdEWfTSAatkFzI3up7i7JVSKZig2fa6ojYQwlrA9O7DbigEDDwVDIXO8 DkszYqBVNy9rIE6rwpzJGTh7Ic/vI+neHRvQvVOsEFcQomLRrVc/u3bf6upKnDhfYOOk+Hb7DkzN GICWiX180kdCCB4bfZvIQvLgTWGCmYk+VQV2YyHYb4pBn6oS7OHT+oZj7+P1uXMkhLFJtHMX8+1a m2uw6XPd3l4ScFOoAMDE9aHorsNFbVxqBEiUrWmGKjFC8ckVIQV2Wt9wrBnrftJYkk6DqRkDsH3d CvxeUI7XP/7ar8EexfmX8MjIgRgw7H7kleoxf/oYLH95BvJK9eifPkw0D7WyYOYElNaYMWXsSKGt vLQEJ8/kYsUax3sLNJcXp44SzGCA5Q/73RGW6QZVaoJikyW2lNlXBsXaAigX/Sk8+bq1CrKs+uto /Mh2h4ZFl63QXYd7tGEv4MHu0oD7cQAkhIH5vlaC6+zpbcVYvr8MWjWLxa++AF3bOBRczkN5aRGM RhMiWkQiQqtFh6Qe6HzjzQGL2ywvLcFbz07B4s+3QW/iEadVYfWnq5A2wmIBaZg0uHTuNMx4zbLn werFL+Hhp19Fkk6DY3+WClOCwrOH0LJTikN7a3Owl3qjUtDY+3hbdGtleYwrPnC84RnXLwLmoeIc qeZETHniz/cJ5n3LbUtUJmocF8NiKGJ4qh3RL+xEKl+7gTx4U5hQ9Gv+9DHEYDB4UuPMJ1y5eJ7M mZwhFGVTKWgyZ3IGqaqqsDn22M+7SZxWZSmeNiadzJ8+RihklnPisF/6azAYbMpmqhQ0+XZyG+He mG/XNl2sTBck3CP9wk7EdH8rz0pJJmpstGHet7xZpVc8Vjcx1RLjymFuxQGQKCVM09qChDAwcQQL d5UKcQBJOg2ee2YWxj7xYkDC7oxGI7I3fYYPli1B1uEcUcDLzz9sceqKzc+7gPS+3YWFU5JOg693 7vFp4YiGnz3+7jQbr5219DngZpImQ8E8Ihpcn3DP0pAc+fOnbgelCPbvaGqFy9lp+5fTxF8urwsi hrnxwvHfTm5DknQaYSSI06rInMkZ5Mj/viM8Z/bpSFRVVUG2rVlGpmYMsClpOS49hWz4cCFRKWiS lhzrcMT/afuXoiK5UzMGkIqy6z7tt5Vta5bZ9FuloMnacbr68o0T2xDCUB6Nioa58W6fa75da/uk dXF3Pmc0W+HuxgEAFr+v6UGdMFk3cQTrj1Vi8b4qkTlHq2bRL6UTBva7Bd173YLk1CE2+fLucK24 CL/s3oqDP2Zj14/7cODsFdHIGadV4cFRQzDthTeFUpY7Mj/CsHHTMC49BV98/ytKS4px6IevsXPr Bmz+fq9gAkpLjsXCd5f5JQimvLQEjz8w2CarQatmsWZsS2Frc+qyHspVVzyOISXhLCgD7/L5zfXn O6PZF/C4HoCdjFTAkgnw32OV2HZWb7f8jkpBo0NUMFpGaREaGoJQdRCio8S2uppaA6qrK1FZY0DB 1UJU1xpQWG5wGB5oFWiP3n3RIro1amsqoa+uRFlpKQquXELmV9twpqAaWjUruoZWzWL04Fts0mN8 BeE5rHrzBTz32rs23yVJp8H6sVGCrZTOrYHi83y/VuVrrj/fGV6ZM5i+n0+4X8RVAZ2tMBtCwllw Q6LAdQ+xyR/PKTbiUJ4ex/INOHiVRlFZjVdqR3mKdSeSgf1uQf8hGeiddpcoWa+6uhL7vv0v7rh/ ilc/lxCCLZ8twZy58+xGok1PjcDLd0QitG4kY45Wgt1U6FeR8nEqmB4TP+2YnhOguOMlr2jMKxch tWXEuGIwSG29KcPdiTgJYcD3CQd3Y6iwa7Q9TBzBhVITyvU8Kg088htMMWpMBGoFBbXScsMigmmE BtFoFcpCxVIoqjKjsIpDWS2PkmoOhZVmlOt55FeYcfYaEUQwPDUJI+6+GxFaLaJ0cYjt1BWxHZMc LvKMRiM+Xjgby1aswoZtO70WZlhdXYnVb7+IZStW2RVokk6Dt4dFCI96cATsjhK/b3AG2MnPD46A clqW265SR3htFWY+up6Yv5snavO0cAGJUoJPUINvHwzSOsgm2NYXmDiCkavzhcrW49JT8Oyr7zqN yirOv4TVS17G+6vWoajS6HH5oYYQnsO+nV/h8xXvY1PWz3anK3FaFebdHo4xKaFQ1D2FqCIjFOuv giow2Bzva7ieYaL9ogCAvfNVsD3GeE1fXruQL3f8IyEMiFYBEq0EwlmQcBZEzQBKGkRdN3FX0gBL AWYCGC2fR9XwgJEHVcNZItZDWBANYzlHzYBoGNHEv7HJDLCIov9NiWjfrh1aaCNRW1ODszlnkXsh T1TMrVe8FtOmTMZtI8cLcZ4ufTdCcOHsCez+ei1278rCd/tPOZxLD+qkxqTe4aKoe3AE7K5SSyn7 QFQJdzM/31O8atfyWj0Af8JYYi9NY1oJos0pNmLRnuvYeLLKYQKhSkFjaIIarcNYm4WfVs2ie0cd WreMRHRUFDQaDVSqYASr1bheeg3V1dUoLilB7oU8XLha4TQHLEmnwYSUYNzbPRRxEQ3iJOpC75hd gd0UxN38fE/xugHWuHkG4c82KFTrQT2AQECilDA90FI0zzJxBEfzDcgpMqK42mLViNYwSIhRokfr IOGxCwCnrhrw1ckqfP8nHG4m7ApJOg166hjcGh+MWzuqxeIEAAMP5lA5mH1lgd21Bg7y8xOHQjnq Pa/ryusXbG49gEDD9QwDN7CF0wVdU1QaeBy6pMfxfANOFxpRUGlGOadCda0BrUMsj+ewIBqtw1iE q2h00CqQEKNEUoxSWLmLO0VAn68FfaISzLHKgG4E0hB/+vN94tIy71tOzD8uEbV5mmsTKPg4FcgN avDtgkEiWEBdNwcrM4EqM4MuMIA6VwOq3Ay+Wwj4zhrwHYO9VqKRquJA/14D6nwNmN+qAr5pcmMa JnBaYQc+CbbfdJ9oyicX9SQO4G+BigbfPhh8fDBIyyDw7VSixZpdDDyocjOoIiOo6ybQF2pBFRgC /lh3SgD8+T6pfU4pgqnG+wJY6wH4a1+AgKDnLZkNDZ4cJIQBQlmQukqGVF3SI2o4S5zuX/AP12F+ vg+DTnyWdcckDKHouJtFbeaBLZodNf5Xg6riQBUYQOfpQefpLaOldcT8C4qUhDAwDxSv8um4m0X1 9n2BT9ND2TteAqgGwgyiwQ1zkLkq85eAGxYtns5QjOU++xifCtWf+wLI+B5v5Od7im8T7gGwA2aA ChankjisByAjaWzy84Mj3M7P9xSfC5UKjqCYATNFbd7aF0DGf9jNzx8w02tBJ03hc6ECANNjLKjo BFGbo3oAMhLEXn5+dAKYHmP91gW/KIWiGarxhNtZPQAZaWE3P/+Ol7wadNIUfhvSmLg+FJ0o3i7c UT0AGelgNz8/cajXg06awq/PXva2ZwG2wTzHzo7CMtLCZqdxVmW5j37Gr0KlI9o2a18AGf/isN5+ RFu/pz37fTXD9JkEKrytqK1xhQ4ZCcBQlvvSACq8LZg+kwLSHb8LlVIE2+4LEKME19c/1ZdlXIPr G24T6uhrf74zAmIfshsHMDjyHxcHIFVICGPZs7YB/vDnOyNghkw5DkC6BMqf74yACVWOA5AmgfTn OyOgriE5DkB6BNKf74yAClWOA5AWgfbnOyPgznY6ZYwcByAFHPjz6ZQxAeqQmICrgWZYOQ5AAjjy 59MMG/DRFJCAUAE5DiDQSMWf7wxJCBWQ4wACiVT8+c6QjFDlOIDAICV/vjMkI1RAjgPwOxLz5ztD UkKV4wD8i9T8+c6QlFABOQ7AX0jRn+8MyQkVcBAH0OhHlWke3OBIyfnznSFJodqNA+gTLscBeAk+ TgWuj3g6JQV/vjMkKVRAjgPwJVL15zvDJ0XSvAEVHEGZf/mCmL9/RWizxgEwv1UFsGd/bbiuIZL1 5ztD0p3jOTMxfToSpDgn0F3520JFJ0Ax8WvJuEodIdlHP2A/DkDGu0jJn+8MSQsVsB8HIOMdpObP d4bkhQrYiQOQaT4S9OfLyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjI/H34f4DnQZLCUbKg AAAAAElFTkSuQmCC "
+ height="15.810055"
+ width="15.810055" />
+ <path
+ style="fill:#cb2124"
+ inkscape:connector-curvature="0"
+ id="rect1942"
+ inkscape:export-xdpi="7.7063322"
+ inkscape:export-ydpi="7.7063322"
+ inkscape:export-filename="C:\Documents and Settings\Molumen\Desktop\path3511111.png"
+ d="M 17.174005,16.09239 H 7.9880451 c -1.097544,0 -1.987272,0.889728 -1.987272,1.987272 v 9.18484 c 0,1.097544 0.889728,1.987216 1.987272,1.987216 h 9.1858479 c 1.097824,0 1.987272,-0.889728 2.099272,-1.949864 V 18.11707 c -0.111944,-1.134896 -1.001728,-2.02468 -2.09916,-2.02468 z" />
+ <path
+ style="fill:url(#SVGID_1_)"
+ inkscape:connector-curvature="0"
+ d="M 17.174005,16.09239 H 7.9880451 c -1.097544,0 -1.987272,0.889784 -1.987272,1.987272 v 3.886904 c 2.03448,0.826056 4.2585759,1.282176 6.5895759,1.282176 2.366728,0 4.623248,-0.47012 6.682816,-1.320256 V 18.11707 c -0.111944,-1.134896 -1.001728,-2.02468 -2.09916,-2.02468 z"
+ id="path9" />
+ <path
+ style="fill:#ffffff"
+ inkscape:connector-curvature="0"
+ d="m 13.208141,25.222126 c -0.666456,-0.05191 -0.946064,-0.381976 -1.468488,-0.699272 -0.287392,1.506848 -0.6384,2.95148 -1.678152,3.706304 -0.3209919,-2.27752 0.471184,-3.988152 0.839104,-5.804008 -0.627312,-1.05588 0.07549,-3.18108 1.3986,-2.657256 1.627808,0.643944 -1.409744,3.9256 0.629272,4.335464 2.129176,0.427784 2.998408,-3.69432 1.678264,-5.034792 -1.907696,-1.935584 -5.5529599,-0.04413 -5.1046799,2.727088 0.109144,0.677488 0.8090319,0.883176 0.279664,1.818096 -1.2208,-0.270592 -1.585192,-1.233456 -1.53832,-2.517312 0.07554,-2.101232 1.8880959,-3.572464 3.7060799,-3.775968 2.299136,-0.257376 4.456984,0.84392 4.755072,3.006808 0.335384,2.44104 -1.03796,5.084912 -3.496416,4.894848 z"
+ id="path11" />
+ <g
+ transform="matrix(0.056,0,0,0.056,5.4129971,15.50411)"
+ id="g13">
+ <linearGradient
+ id="linearGradient3033"
+ gradientUnits="userSpaceOnUse"
+ x1="94.999496"
+ y1="1308.001"
+ x2="94.999496"
+ y2="1415.5118"
+ gradientTransform="translate(34,-1170)">
+ <stop
+ offset="0"
+ style="stop-color:#000000;stop-opacity:0.15"
+ id="stop3035" />
+ <stop
+ offset="0.6626"
+ style="stop-color:#000000;stop-opacity:0"
+ id="stop3037" />
+ </linearGradient>
+ <path
+ style="fill:url(#SVGID_2_)"
+ inkscape:connector-curvature="0"
+ d="m 10.496,115.401 v 94.605 c 0,19.6 15.888,35.486 35.487,35.486 h 164.033 c 19.604,0 35.488,-15.889 37.488,-34.819 v -95.952 c -36.779,15.181 -77.074,23.576 -119.337,23.576 -41.625,0.001 -81.342,-8.145 -117.671,-22.896 z"
+ id="path20" />
+ </g>
+ <path
+ style="fill:none;stroke:#cb2124;stroke-width:0.112;stroke-miterlimit:10"
+ inkscape:connector-curvature="0"
+ stroke-miterlimit="10"
+ d="M 19.273165,21.928486 V 18.11707 c -0.111944,-1.134896 -1.001728,-2.02468 -2.09916,-2.02468 H 7.9879891 c -1.097544,0 -1.987216,0.889784 -1.987216,1.987272 v 3.886904"
+ id="path22" />
+ <g
+ transform="matrix(0.056,0,0,0.056,5.4129971,15.50411)"
+ id="g24">
+ <g
+ id="g26">
+ <g
+ id="g28">
+ <path
+ style="fill:none;stroke:#a11a1c;stroke-width:2;stroke-miterlimit:10"
+ inkscape:connector-curvature="0"
+ stroke-miterlimit="10"
+ d="m 10.496,115.401 v 94.605 c 0,19.6 15.888,35.486 35.486,35.486 h 164.034 c 19.604,0 35.487,-15.889 37.487,-34.819 v -95.952"
+ id="path30" />
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/src/skin/socialwidgets/Twitter.svg b/src/skin/socialwidgets/Twitter.svg
new file mode 100644
index 0000000..ce720bf
--- /dev/null
+++ b/src/skin/socialwidgets/Twitter.svg
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="68.003784"
+ height="25.348675"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="Twitter.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3785">
+ <stop
+ style="stop-color:#fefefe;stop-opacity:1;"
+ offset="0"
+ id="stop3787" />
+ <stop
+ style="stop-color:#dfdfdf;stop-opacity:1;"
+ offset="1"
+ id="stop3789" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3785"
+ id="linearGradient3791"
+ x1="39.280788"
+ y1="12.902368"
+ x2="39.280788"
+ y2="32.148937"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.32703118,0,0,1,0.75454017,0)" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="9"
+ inkscape:cx="26.556664"
+ inkscape:cy="16.694151"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="1344"
+ inkscape:window-height="1419"
+ inkscape:window-x="0"
+ inkscape:window-y="19"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-0.62121129,-12.484656)">
+ <rect
+ style="fill:url(#linearGradient3791);fill-opacity:1;stroke:#cccccc;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="rect2985"
+ width="58.957203"
+ height="19"
+ x="1.1212113"
+ y="12.984656"
+ ry="2.1487894"
+ rx="2.1487894" />
+ <text
+ xml:space="preserve"
+ style="font-size:14.40710354px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#333333;fill-opacity:1;stroke:none;font-family:Sans"
+ x="22.176807"
+ y="26.724609"
+ id="text4002"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4004"
+ x="22.176807"
+ y="26.724609"
+ style="font-size:12px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#333333;fill-opacity:1;font-family:Arial;-inkscape-font-specification:Arial Bold">Tweet</tspan></text>
+ <image
+ y="23.166666"
+ x="53.958332"
+ id="image3353"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKoAAACqCAYAAAA9dtSCAAAABHNCSVQICAgIfAhkiAAAIABJREFU eJztnXl4E9Xex7+zJE2TbqQLBGiBIrQFikUWsSxWKSIoFMSFRa6yiYoXFMUFxKuooKIICq8ioiJC uQIioCDWAlcB2ZRVoBVQCrR0oXRvtpnz/pFm2mmWJmmWUefzPHkeOJmZnGS+PXPObzuAjIyMjIyM jIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjJehAt0BV+DLLhPjyqGAWR/orvx9YFVQTt0BOqLt X0IDdKA74Arm3W/JIvU2Zr3ld/2LIHmhcnmHCH92R6C78beEP7sDXN4hEuh+uAIb6A44g+fMxPTp yEB342+N+fv54DkzoRlW0lMAaQv12HqQ4hxRG7uxEMxvVQHq0V8frmsIzPe2FP5PinPAH1sfwB65 hmSFSmrLiHHFYFEbdVkP5peKAPXo7wHzSwW4vuEgbVVCG/fTUpDaMkIFR0h2VJXsHNX803sgtWWi NnZbcYB68/ei8e9Iastg/um9APXGNSQpVL44l3C/rhO1MYfKQefJK39vQOfpwRwqF7Vxv64DX5wr 2YWVJIVq/n4+QLj6BgMPJuta4Dr0N4TJugYY+PoGwll+d4kiOaFyOTsJn3dQ1MZmXQNVxTk4Q8YT qCoObKM/fj7vILicnZIcVSUlVGKqJebsN0RtVJERzIFyB2fINAfmQDmoIqOozZz9BoipVnJilZRQ uUOfgJRfFrWxO0oATnK/298Djlh+3waQ8svgDn0SoA45RjJC5csuE/P+D0VtdG4N6LPVAerRPwP6 bDXo3BpRm3n/h+DLLktqdJCMUG38+RyRzVF+gt1WLH5qSTAOQBJCtefPZ/aXgSoxOjhDxptQJUYw +8U2a6nFAQRcqDxnJo3NIlQVB3ZXaYB69M+E3VVqY1mxxgEEqEsiAi9UO/585rsSQM87OEPGJ+h5 y+/eACnFAQRUqKS2jHA/LRW1yf78wMH8UgHqstj7Z40DCFCXBAIqVNmfLz2kGgcQMKHa9ecfrZT9 +QGGztODOVopapNCHEDAhGrXn79dHk2lALO9WHJxAAERquzPlzZSjAPwu1Blf/5fA6nFAfhdqLI/ /y+CxOIA/CpU2Z//10JKcQB+Farsz//rIZU4AL8l93F5h4hp7XhRmxT8+SRKCT5BDb59MEgEC6gZ yxtmAqrMDPpiLegz1aAKDAHtZ6CwxgFwA1oIbdY4ACauj9+SAf0iVMJzxPhJhqgt0P58PlED8yCt KBuzMSRGCb6zGhgcCeqyHmx26T9ymsLuKgXfIwwkhBHazN/PB+E5QtGMX8TqF6FyRzOl489X0TCN bgm+W4ioOafYiFNXjSip5lBt5BGtYZAQo0SP1kFQMBRIWxVMD7UGc6gc7Nbif9biry4OoHE9AO5o pt+64HOhSik/n4SzME1qAxKjBAAUVXH48OcyfHigAqU1ZrvnaNUsxqaE4LnbtIgJYcD1CQeJUEDx ef4/SqyBrgfg88WUZPz5Klok0jW/VKDzW39iwa5ShyIFgNIaM5bvL0PKu3nIPmdZAfOd1TCNaeWX bkuJQMYB+FSoUvLnm4dGCSJd/ON1TN1YCL3J9alHaY0Zd626gk0nLeWE+G4h4PpF+KSvUiWQcQA+ ffRLxZ9PdEHg+oQDADadrMKcRoZsd5i8oRDdWimREK2EeXAk6OOV0nX9MhT4NkEgsSqQcBYIYUEU FCgTAUw8qCIjqGsmUJf1Ln8HZnsxuC4aIKhujPNTHIDPhMrl7CSmr54Qf1iA/PlcX4tITRzBC99d b9a19CYes7YV49tJbYAgGtzAFmC3ey58X8AnasD1DAOfoAEUrk0fqct6MGeqLSkpTha51jgA893R 9Z9XFwfAJAzx2VzVJ0IlplpiXDlM1EaVmgLmz+e7WFb4W09XI6/U8bRDq2YRomJRVGl0Oi3I/r0G 2edqMOgGNfgeYYBEhEp0QTDdE2PX5FZUxeF6LYdyPQ+1gkKYioEulIGizrpE2qpgbquCOU0Ldk8p mP9dd7hYZA6Ug0uNANEqhDZrHAClCPaJWH0iVLv+/MYeDj9BopSC/W+HAxvouPQU/GfxSnRO7gUA MBqNyFz2Gh59/nWHgs08WolBN6hBQhhwPcNAVXMgkQogiLY8ZhU0iJ3RjKrhAAMPqtxseeyWmy3B H838bbh+ETAPjQLqhFdUxeGLXyuQfa4GR68Y7S4YVQoa3WIjcHMrHg+khKJPrApQUDAPjgSXpIFi db79J2CdR9H0UGuhyddxAF5XP19x1WKOauAqpXNroPj0irc/yrX+xKlgeiwWAHDXJ1eQ/bvYdz1z TDqWZGbZPXfjijdw36Mv2H1Pq2ZxcU57YURqFhwBVWAAnW8AlacHfa4GVLljS4QIhoJ5dEtwPUIB AJUGHu/+eB2Lfypza7EIAEk6DVaM0loEC0tUm/KDSw6nAqaJbSwOESusCsppWaDDWnldV16/oHHz DHHqM0egXJIXMFcpn6gR/vJ7vJePMwXiUbWkqBCR0TEOz+/dMRJHLtj3oB2f1Q4J0UpRW6WBx/Va HhV6DjUmgsoGAcihQTTCVTRaBDOIaeDlsQdVZARzvNK5+5ahYPpXa0Esp64acM+aIqfTG1dYMDQK swZaXKbM0UqwX161exyJUsL4ZJwwigMAnTgUylHveV1XXn30S9GfT5WYhH/31DE4U1D/nkpBOxUp ADwweiSOLLL/SPuobs59ttiI/CoKf5TUujyKqRQ0YkKV6NmaRVKMEl1bBWFAh2BBwCTGYlWwum+Z Y5UWJ4l1dGMomMa0EkSafa4Goz8vcHsUtcecHSVo10KB0ckh4HqEgj5QZtek6M84AK9djPAcMX52 D0jh6fqLV3FQvvNnwFOfjXPjQUIYbDpZhfHrCkTvnTqyF1179nN47p6t63BbxniH77uDK4u1JJ0G t3dQYFiSBgM7BIunFgYezKFyMPvKwA2JEh733hRpw77mPNsOoUG001EVKhrGp9uL4gColl2gfPgr eDMOwGsGf+74BpFIAenk59OnLUb6EV00SNJpRO8tfdX+HJTjOOzI/Agr318kak/SaTAuPQVTMwa4 9NkqBY2pGQPww6bVKKrQ4+K1WtQaOeRfysMPm1Zj0exJGJeegjitZV54pqAay/eX4a5VV9BuwZ94 elsxTl2te/QH0eAGtIDx+Q4+FSlgcXCsqzPuc91DAJUDqdirB1B4GtzxDV7tj1cUb/XnN3SVUpf1 UC6/5I3LN5uGc6nsczW4a5V4YffT9i/Rf+h9AIDfftmHlW+/jDVb96C0xow4rQr9b0rEqHsfwOD7 piBcG4UdmR/hwSnTnbpe47QqPP3YQ5g4+w2EhrvmwbqY+xuyNq3G1m++QdbhHJH4esVr8VTfIIxO rg+mOXXVgDtW5jvtR3MY1EltsRcDUKzOdxo5ZpweKzKLUcERUE7LgqT2BTB9P5/oF3YSvbg4FSGA ZF6mYVFC3+bcriUAhJdWzZLP3plH0pJjhf+PS08hP2xaTXjOTBry2TvzROc2fsVpVWTlgtnEbBaf 5y5l14rJygWzSa94cV+TdBqydpyO5M2NJ3FaldO+NPx+49JTyPKXZ5CVC2aTOZMzbK5r76VS0MJv Zu4X4fT35eJUNhowfT9fOlE7fHEu0b+RKO7g/a0CLkybF0MRw+z2Qh8fvCnM5sb0iteSlQtmk6qq CrviWTR7klMxLJo9iRgMhmYJ1B5H/vcdGZeeYiMiR31p+Jo5Jp2UXSu2uSbP806/j/VV/HJHyz0d FtX0YHB/K7FY30gk3ooDaPYc1Zy9EDb+/J3S8NQIMBTMQyJFnpRH+oZDpbB8/bTkWOzeshaHz1/D lBfegkYTKjqdEIK5U0ZitoPV/7j0FJw8k4Nn3loFpVJp95jm0HPgEKzNOoqcE4cxLj0FAJqck2rV LHZvWYslmVkI10bZvE9RFJ55axWGpya51AfKhbUGs7PEth5A9kKXrt8UzRIql7OT8H/sFbWxP153 3VjtB0iUEsZH2womlKIqDlM2FGLg/11Ct9gI7N6yFrtP5CFtxDj75xOCaaNuxYJVW2zei9OqsPO/ K7E26yhax8X79HsAQOfkXlibdRQ//7AFveK1Do9L0mlw9MQph9+pIa2ibUVsRatmEWoNPjE0LVSq 3Az2R3EsBf/HXq/UA/BYqHbz80tNFh+xROATNTA+UT/Jzz5Xg/4f5GPjySosmj0JB3KLmryZ00bd ipVbfrJpn5oxAKcuFOCO+6f4pO/O6DtoBA7kFmHR7EnCU8FKkk6D/x05g7iOCU1ep7K8DDt/Ouzw /VvjGyyOLrnmRGD+dx1UqUnU5o16AB4b/KXkz7cH1zMM5lExFsM4R7BwVykW7CpFnFaFAz9m48a+ aU1eY+6UkTYi1apZrF6xBHc/ON1rfa2ursTh7G04ffQgcs+eRnFJCSprDHj1nf9z2E+GYfDMW6tw 2933455RIwVvVP8+NyFK17bJz6wsL8OIAd2derHu7V43BTLwoK+4mNwYgDgAh/AVV4l+UbJo4myc 2CbwC6a6l7lfhNCv4pc7kkGd1AQASUuOJUVX811awNhbaKQlx5IrF897ZYF05eJ5smj2JJKWHGt3 YbRo9iSXr1VRdp0MT00Szh2XnuJ0UbdtzTKSpNM4XUQl6TSk8rUbLAupUTFu3wPjxDbihdWiZMJX XPXvKGbcOkvcidduIHyUMuACbSzS3Oc6CDckLTnW4Wq+MRs+XGhz4+ZMzmi2yYnnebJtzTKRqOy9 0pJj3b622WwmUzMGCNcYnpok6u/Fc2fJ0rnTXDZL/fh4bP29DWfdvg98lJLo64QuDGZbZ3ksVLeN sXb9+T9dl0TwMNczTMiUzCszI31lAfJK9egVr8WeE3/arObt8cuPO9E/fZiwqvbGo57wHD5f8gre fHuxTVCMPY787zsk970Nl86fQcGfuTDU1uJ6cT7CWkRBHRqOFjGt0T6xu13rxItTRwkLv+GpSWgV HYW9h361+7lJOo3d9rXjdIJjgc26BsbDtHbzsChRHAAAKMavhSdxAG6dIGV/Pp+ogelBHcBQKKri 0P+DfOSV6qFS0Dj+y0Eh1tQZ14qLcFNiO2HelqTTYMO2nU5jAZrimy+W45X/vOQwAssejgTUmDit CvFtonFj1wSk3zUSt436FzSaUDw5djCWrv+hyfNX3tsSt3ZU47PD5fjwgCUreM3Ylhh0gyXQhc6t aV62rRfjANw62Hx0PTF/N0/Uxm4sDHgpcxLOwvhUOyCIRqWBx8AVV4UbvfzlGXj8P0ubuIJlNMro 3xXb9p8BYLGtfr3nV7s2SFc4f+Y4npoyVrieP1ApaAzunYBHHpuOzNUfY90Px5wePz01Au8Mt6SU mDgCvZkI5ig6twaKzIJmD0ANn3JW2DtfBdtjjG+ESmrLiPGjO0Fq6utmSsKfz1AwPtpWMEE1DI5O S47FruMXQVFNf823n50sGPTHpafg028PemS85zgO777wCOYt+czrgSLuEKdV2V3Rx2lV6BRJIzFa iWFJGmH0bIi3i2zYxAGoI6F85Du34gBcNk+Zf3pPJFJAGvX2zUMihR9hftY1UQT/ko8+d0mkB7K3 Yt6SzyzXmD4GL76/zqXzGpN78gjGjxzi1mPeVzQWaa94Lb4aG+EwYJsqNQE1HNhtxV5PZ2e3FQtZ FgBAaq65XQ/AJYO/lPLzG8LHqcClWiKTss/VYEGDSf/UjAEu2Uory8vwwP0PQG/i8dk78zBvWaZH Iv144bO4sefNkhCpPY5cKMXJq2JbKFVqAn2qyrIY/u9VKJdf8sk99UY9AJdGVEn68+tyhcBQqDTw eGxz/WivVbNYuHKjS5d5+qERKKo0YvMnizFy4lNud6O6uhKPjBzY5HxQCjyzvQxHZ1ge9cyhcrCb i/z22czOEtt6AG7EATQ5okrVn8/1DRcqn7z8/TXRo+7Jifc2mWICADsyP8KmrJ/xzfpPPRLp+TPH 0buT7i8hUsASlG2t9ML1CHMcDO0DmhsH4LSnxGyQpj9fRYNLswRlnLpqwPIG+3hq1SyefP2DJi9R WV6Gp5+ehW+3bsKge/7l9Fij0Tbna++ODejTq5dLZiQp8e6Buse/ggLXM8yvn+0wDsBsaFKsToXK HfxYkv58LjVCsM0918jR0DI8CCMGdEeX1iHYu8NxOsSSuY/hkzXr0HfQCKeftWfrOky862ZR2+rF L2FwxhifRdb7kiMXSoXUFuv83m/YqTBOyi+DO/hxk6c6FCpfcVWS9fZJCANzXSpv9rkamzz9MwXV 2HPyEnp07SSklzQmNycHw+5/uEmR7sj8CEPvnYDv9p8Cx1nm6K8+MRYPP/1qQE1PzeXTwxa7N9Eq wMc5LmTsCxzuC9BEHIBDoZr3SLPePjewhTAh/8/uWrvHaNUsFq3a5PAaHW+4AT0HDnH6OdlffY57 HnoMehOP0hozTh3+CU+OHYyXlktjE9vmsO1s/X0lsf4VKuBgX4A9zvcFsLvql2J+PgCQKKXIHOXI FPTmi085DWRmGOfFHw5kb8XdYyaKRs2x99ztdD46PDUJwybMQLt27dC6dWtUV1fjxIkT2LZtK3Zl 7ZTUCJxXqkdemRlxESz49sFg9pU1fZIXsVsP4LdtTusB2DRK2Z9vLSFj4gj6LC+wKxx3vFH2OH5g D24fNNjl+Wdyty548623MXToUIfH5Obk4KlZT2H79h0Oj/E31sATqtQE5aI//d8BN+MAbEZUqebn 84kaoSrIJ4cr7IpUq2axenOWxyLNz7uAEXcNdVmkw4YNxfp165pMh+6ckIBvv92OJ5+ciaVLvVOh OU6rwo2JHdAqOgrRURYLSHV1NS7kXcG5P/KatEbs/7MWo5NDLHlkDOX/BbK9fQGc1AMQCZXXVxKT ROrti1DRFuM+LDlPr2TZf+SvWPyqSykY9qiurkTGbb1drtuU3K2LjUg5jsOGL/+LAwcPIjExCRMm jBeF4i1ZshS///67xyNrr3gtHhg9EvdNmYV2nbs6PfZacRE2f/w21maux56TtvEY+RX1f4ykhSIg 0zq7+wL8uAS8vpLQqlDHo41U8/NNo2KE/ozqFmI32HdqxoBmBTQ3Tkdu6rV9+3bRNTLXrSUx0VGi Y7RqlnzwwQei4/Iv5bmc6mx9pSXHku3rVnj8/Y79vNsmWLtXvFYS99jVegDCql+y/vxEjais+eZT VTbH9IrXYtmXTcdfOuK1f49zy7uU3K2LaE66Y8cOTHxoAoqKxTZdVhOB0aPE+2vp2sZi2uPiStzO GJ6ahOnTH4dBX40D2VtRcNn9aLUb+6Zh677T+GHTaqF0UHVtvd+f7xu4vQjcjgMwrp8oVvZ8z1IQ vPniw1miryuAkDc3nmjVrM1oo1Wz5OK5sx6PNps/WezW6AaAzJw5Q3SN5G5dbI5RKWiyb98+u5+5 fft2tz+z8XdOS44ly1+e4XYOlzW/SpRu4mKBCZ/e5/mN0lbWTxQJlQYc+PP3lAbWn89Qloj9Opvp xC+v2ixyVAoaWzau83heeiB7K8ZOe8bt8xIT64s2FBcW4OSp0zbHTHv8CaSmpto9v2N882oAlNaY sefkJUx/+T20adcR4wf3wPkzx106NzQ8Aht3H8Pg3gm4Y+WVei/VgBZ+d6laocrNYPeI1x2N4wBo qfrzzaNbOowztbLm/dcdep+aIvfkEdw1YrRH9s127doJ/86/aj8C6cLhLDz55Eysz1yHHTt2oLiw vtxlpLaF3XNcRatm0Stei7TkWKQlxyL3Qh6GD+qH1Ytfcul8pVKJjbuPoW9iG9yxMh9FdeXPzRkx ILqgZvXNU5qKA2Cl6M/nbteKyiousJNctmj2JNw77XmPrp978ggGpw3w2Fd/8eJF4d/tY9vYPWbb /jPA/jOwJsFs374dQ4fqAADXSt0fBIanJmH06Hsx+N6HHTozKsvLQHgOFO3coQFYxPr1nl9xS7f2 uCezDLsnaaFQWIoDK9/L8//9d1QPoC4OgOaOrBEdT1VxAfXncz3DLJWWYdmfdEJmoc0x86ePwTNv rfLo+laRNqd8+Nmz9XlQ4dooDBvm2NgPADHRURg0aJDw/19//cXlzxqemoScE4exdd9pPDRrvlOP W2h4hEsitRKujcKGbTtx6lIZnq8L7iExSpiHRLp8DW9Cn6222dzCqk+a6TVB9AYJYcAniovd+gs+ USMYgIuqOAz/rNBm1JszOQPzlnm2WezxA3uaLVIAyFy3TghSAYAP3nvXprROQ5YuXSrKv1rzxRdN foZWzWLDhwuxdd9plzJoPaVrz3748I25WL6/TNhCkxvQwu/BKoDl/pNGqTJWfdLMzVNAhYtLwJiH R4s2EPAHXM8wy+IJlg0bhnxSaCOoOZMz8PrHX3t0/QPZW3H7oMHNFikAFBWXYOXKlcL/4zom4PjJ 00ju1kV0XEx0FDLXrcWYsfX1rY4fP96kwb9XvBa/Hj3m8dTGXR6aNR/DU5Pw2OZrwuYYVgeL32Ao i+4aQIW3BXOzpbYXBTjeZc/TwgPuwvWLEHaCqzTwGPr5dZuAk/nTx3g8ku7I/EiIhPIWMdFROPbr r9C1jRW1V5aX4eRvp9EhLtbmPY7j0COlu10rgZU5kzMwf8WmJgNnvE3e+RwkJHXB5N5hQgq1P1Ph udu1wpTPiuKeZbDuBkgDAJMwhKI79BcdZE7TWjb28iUMBfOwKEGkRVUcBq64aiPSlQtmeyzSjxc+ i2Hjpnk9eqmouARDht6JynJx5FFoeARSU1NtREp4DiNGDHcoUq2axfZ1K/D6x1/7XaSA5akw55H7 sepwBXKKLe5U7s4ovzxZSTgLc5q4jCbdoT8ablkp/IMvziXGVSPQMInP6W4YzUVFwzRWJwSaNCzB IxyioLHhk/c8KqdDGpW38RUx0VE4tHePU997ZXkZ+vXv51Ckw1OTsGrDTkS3jrX7vr+orq5EXIwW t8arkDneMg1jvyn2eRig+f5WgpUHAEAxUE7eCjq6s6BPYQVAR3emmJvEtUK5HqE+mVTzcSoY/x0n iPTQJT36vn9JJFJreUhPRFpZXoaM/l19LlLAMrK2T+iGR0YOROHZQ/XB5pwRxfmX8H+vzERYRAu7 Io3TqoQFU6BFCsBSDmjivdh8qgqH6uqhcmlan46qfJxKLFIAzE3jRCIFGsWjWqOnfFYNhaHA3doC 5tvrv/yaXyrw7y3FokdzWnIsvsw6iOiWOrc/4vyZ4xg+qJ+kk+5UChqz/jUcz7/zmcs7pviL4sIC xMW2xdAEdf2o6sO5qr0qKoppWWgcPSWyqdCqUIoZ+KToQqStyiuuNWuJcvPgSCEXf8qGQkzdWCgS 6fzpY7Dr2B8eiTT7q88lnRkap1Vh/vQxyLt0Ga9//LXkRAoA0S11mDCsHzafqkJemcU0yHdvugqi J3A9w2x2wmYGPmkjUsAfEf7WUTRNK+wdf+iSHtM2l9oIyrrbcYhGg9DQECQndUaHjp1xyx0ZTVbU e+/FRzHz9RXu98/HJOk06N/nJjzwrylIyxgfkIVSQ3ZkfoSdWy3ByRqNBi1btUJi9164OX2kUBDO ulvhnNu1eKluJa584w/vxn64GeFvd/LhtRqo1v06u9Vv4jU/65pdl2hTxGlVGDKgN6bNmitKzGtu pRKVgkbfxDZI7XMTOnfpjo5JyQhtEY0IrcUSYTDUovL6NdRWV6CmshwV10tQVlqKmuoKlJeVQ6+v RXV1/R9cZGQUIqNjkJDcE937DfboyeBLivMv4dZeSXafOr3itbjjtgGY9PQr6NOrF0JULHJnW+bO 3l5UuVs71eEs2bh1FuF/21bf4MEu0Q1Xc45GUU/oFa/FonffR+sOnTFySJrb11QpaNxza3eMfWgK 7rh/qk+23JEy+XkXkJyUgNIaM0Z1C0HrMBa7/jCJfkeVgobexOPIzDh0axXk1a3s7e5K3XU4lCMW O9Sjwzf4iqvEuGKwKGXanc423H7cV/t1Wn9MV0nSafDopAfx0KzXPK57+nfhmy+WY/iEJxCnVWHv Y60RE8Igp9iIb89U48ODVYIFRtgSnSMIeu2CV3LnrEmaAqwKymlZoMNaOdSjQwc1HdaKYlMfFbXx ndUuxwGYB1kMuEVVHCZkFrosqF7xWiydOw0//7AF504fQ86Jw/hh02rMmZwhRKdbcfWaacmx2LZm GX67UokZr334jxcpANz94HSMS09BXqkeb+62TMUSopWYNbAFcmfH4tvJbZCk0wj+fzAU+PbBzf7c hkmaVtjUR52KFGiikC8xGyzFexuEAVKlJigXX3QaBkZCGBjnWqJ83JmTDk9Nwpa9vznMIi0vLUF8 rM7l8LzhqUmYM/+NJiuieAtiqMKpvduxc+dO/LjvZxRcLYRB3QrDb+6Eu4YNxS13jQcVFNL0hfxE 7skjSOjeGwBwfFY7JETbToE2nawS6vk3e68GhoJxVjvRDopUeFtLUV82yKkWndaeotggih0kDowg WgW4W50H/jbsyEEXN9ICgIKrhSgpuOzw/TNH96PGhVF0XHoKjv28G1v3nfaPSM16fP3pu3jq4VHY uXMnlEoFBva7Bf363ITCwiIsWLUF/UY/ilaxHXAy+0vf98dFOif3ErasXLSnPkaWuqwXdupruJs1 36F5Iyp3awuRNgCAHfR8kyIFXCyNblw/UZyqYuChfPeiQ3NFw/lpj/fy3VrsWOvQ9+5xI3RtYmE0 GnDl0kXsP/Sr3bTfhoxLT8GcN5Y1a3MITygvLUF4eBjA2F+UFZ49hHnPPyNsrnbih/8iedD9/uyi Qw5kb8Ut6RlQKWjkPtseMSEM6FNVYLcUgRsWbeM1CnrlvEfz1Ib7LFihO/SHcsynLmnQpYPcjQMg uiAYZ8QBAMauLbCbOeptjv2826UK04Hk/16Ziekvv4eY6CgU5p0DVOF++VyO43Dq8E/448xRlF+/ jsiYlkjq2R8dk24EAHRpHYIzBdVYmhGDaX3DAROxCJIj4ONUMA+PFgzUxYyAAAAOQElEQVTzitX5 HgXWu+LPd4ZLlVzdjQOgioyAyTKHTetou5mBt0nSaQIq0vy8C3j1ibHo3TESwUoGkRoFeneMxI7M j0THPTZvMZK7dUFRcQlO7tvpl77NnTISMWEqpNxyG0ZNmoWHn34Vwyc8gRu6pKBdZDBefWIs7rj1 FgDA1tN1A4qCAt+pbgufPD2UH14Gu7EQMPDgk9wPqnfVn+8Ml0sOMwOfAqUWxws2DnQV4AjoPyyV 9kZ1C3Ea/e4NZv37cZ9e3xHFhQV4cuxgdLyhE15avh6nLpWhb2IbdO+ow6lLZRg2bhq++WK5cDxF M1jwnKWvOecu+Lx/33yxHAtWbREtPlUKGlo1C5WCRl6pHi8tXy/sSbXvTz1MdYtk0rpBkh9HwPxS gaA3/rAMQm5iExCtjgQ7YIZb13BZQe7GATA/W7wYMSEMXkp3vGV3c5k5Jh1TXnBestAXbFzxBhLj 47B0/Q/oFhuBDR8uRHlVLXafyMPuE3k48GM2VAoazz77nOi8djrLTWsd3bxM1KYouHwJ02fWp4LH aVU4PqsdyuZ3RP68Diib3xG5z3XA0owYJOkso6TexONoviV9mm9nZ+Gk5932Tjny57uzdQ/g5jbo zI33gWopTrfg7oyyWwu+YcHWf/eLwKhu3jXLaNUsVi6YjSWZWV69blOUl5Zg/OAeuO/RFwAAn70z D4fOleDeac+LPFw39k1D38Q2NgvJynLL6rpjlx4+6yPHcRg3rJ8obHLhnS1szE9xESym9Q3H0Rmt sTQjBioFjaN1u0iLRlRPUdEWfTSAatkFzI3up7i7JVSKZig2fa6ojYQwlrA9O7DbigEDDwVDIXO8 DkszYqBVNy9rIE6rwpzJGTh7Ic/vI+neHRvQvVOsEFcQomLRrVc/u3bf6upKnDhfYOOk+Hb7DkzN GICWiX180kdCCB4bfZvIQvLgTWGCmYk+VQV2YyHYb4pBn6oS7OHT+oZj7+P1uXMkhLFJtHMX8+1a m2uw6XPd3l4ScFOoAMDE9aHorsNFbVxqBEiUrWmGKjFC8ckVIQV2Wt9wrBnrftJYkk6DqRkDsH3d CvxeUI7XP/7ar8EexfmX8MjIgRgw7H7kleoxf/oYLH95BvJK9eifPkw0D7WyYOYElNaYMWXsSKGt vLQEJ8/kYsUax3sLNJcXp44SzGCA5Q/73RGW6QZVaoJikyW2lNlXBsXaAigX/Sk8+bq1CrKs+uto /Mh2h4ZFl63QXYd7tGEv4MHu0oD7cQAkhIH5vlaC6+zpbcVYvr8MWjWLxa++AF3bOBRczkN5aRGM RhMiWkQiQqtFh6Qe6HzjzQGL2ywvLcFbz07B4s+3QW/iEadVYfWnq5A2wmIBaZg0uHTuNMx4zbLn werFL+Hhp19Fkk6DY3+WClOCwrOH0LJTikN7a3Owl3qjUtDY+3hbdGtleYwrPnC84RnXLwLmoeIc qeZETHniz/cJ5n3LbUtUJmocF8NiKGJ4qh3RL+xEKl+7gTx4U5hQ9Gv+9DHEYDB4UuPMJ1y5eJ7M mZwhFGVTKWgyZ3IGqaqqsDn22M+7SZxWZSmeNiadzJ8+RihklnPisF/6azAYbMpmqhQ0+XZyG+He mG/XNl2sTBck3CP9wk7EdH8rz0pJJmpstGHet7xZpVc8Vjcx1RLjymFuxQGQKCVM09qChDAwcQQL d5UKcQBJOg2ee2YWxj7xYkDC7oxGI7I3fYYPli1B1uEcUcDLzz9sceqKzc+7gPS+3YWFU5JOg693 7vFp4YiGnz3+7jQbr5219DngZpImQ8E8Ihpcn3DP0pAc+fOnbgelCPbvaGqFy9lp+5fTxF8urwsi hrnxwvHfTm5DknQaYSSI06rInMkZ5Mj/viM8Z/bpSFRVVUG2rVlGpmYMsClpOS49hWz4cCFRKWiS lhzrcMT/afuXoiK5UzMGkIqy6z7tt5Vta5bZ9FuloMnacbr68o0T2xDCUB6Nioa58W6fa75da/uk dXF3Pmc0W+HuxgEAFr+v6UGdMFk3cQTrj1Vi8b4qkTlHq2bRL6UTBva7Bd173YLk1CE2+fLucK24 CL/s3oqDP2Zj14/7cODsFdHIGadV4cFRQzDthTeFUpY7Mj/CsHHTMC49BV98/ytKS4px6IevsXPr Bmz+fq9gAkpLjsXCd5f5JQimvLQEjz8w2CarQatmsWZsS2Frc+qyHspVVzyOISXhLCgD7/L5zfXn O6PZF/C4HoCdjFTAkgnw32OV2HZWb7f8jkpBo0NUMFpGaREaGoJQdRCio8S2uppaA6qrK1FZY0DB 1UJU1xpQWG5wGB5oFWiP3n3RIro1amsqoa+uRFlpKQquXELmV9twpqAaWjUruoZWzWL04Fts0mN8 BeE5rHrzBTz32rs23yVJp8H6sVGCrZTOrYHi83y/VuVrrj/fGV6ZM5i+n0+4X8RVAZ2tMBtCwllw Q6LAdQ+xyR/PKTbiUJ4ex/INOHiVRlFZjVdqR3mKdSeSgf1uQf8hGeiddpcoWa+6uhL7vv0v7rh/ ilc/lxCCLZ8twZy58+xGok1PjcDLd0QitG4kY45Wgt1U6FeR8nEqmB4TP+2YnhOguOMlr2jMKxch tWXEuGIwSG29KcPdiTgJYcD3CQd3Y6iwa7Q9TBzBhVITyvU8Kg088htMMWpMBGoFBbXScsMigmmE BtFoFcpCxVIoqjKjsIpDWS2PkmoOhZVmlOt55FeYcfYaEUQwPDUJI+6+GxFaLaJ0cYjt1BWxHZMc LvKMRiM+Xjgby1aswoZtO70WZlhdXYnVb7+IZStW2RVokk6Dt4dFCI96cATsjhK/b3AG2MnPD46A clqW265SR3htFWY+up6Yv5snavO0cAGJUoJPUINvHwzSOsgm2NYXmDiCkavzhcrW49JT8Oyr7zqN yirOv4TVS17G+6vWoajS6HH5oYYQnsO+nV/h8xXvY1PWz3anK3FaFebdHo4xKaFQ1D2FqCIjFOuv giow2Bzva7ieYaL9ogCAvfNVsD3GeE1fXruQL3f8IyEMiFYBEq0EwlmQcBZEzQBKGkRdN3FX0gBL AWYCGC2fR9XwgJEHVcNZItZDWBANYzlHzYBoGNHEv7HJDLCIov9NiWjfrh1aaCNRW1ODszlnkXsh T1TMrVe8FtOmTMZtI8cLcZ4ufTdCcOHsCez+ei1278rCd/tPOZxLD+qkxqTe4aKoe3AE7K5SSyn7 QFQJdzM/31O8atfyWj0Af8JYYi9NY1oJos0pNmLRnuvYeLLKYQKhSkFjaIIarcNYm4WfVs2ie0cd WreMRHRUFDQaDVSqYASr1bheeg3V1dUoLilB7oU8XLha4TQHLEmnwYSUYNzbPRRxEQ3iJOpC75hd gd0UxN38fE/xugHWuHkG4c82KFTrQT2AQECilDA90FI0zzJxBEfzDcgpMqK42mLViNYwSIhRokfr IOGxCwCnrhrw1ckqfP8nHG4m7ApJOg166hjcGh+MWzuqxeIEAAMP5lA5mH1lgd21Bg7y8xOHQjnq Pa/ryusXbG49gEDD9QwDN7CF0wVdU1QaeBy6pMfxfANOFxpRUGlGOadCda0BrUMsj+ewIBqtw1iE q2h00CqQEKNEUoxSWLmLO0VAn68FfaISzLHKgG4E0hB/+vN94tIy71tOzD8uEbV5mmsTKPg4FcgN avDtgkEiWEBdNwcrM4EqM4MuMIA6VwOq3Ay+Wwj4zhrwHYO9VqKRquJA/14D6nwNmN+qAr5pcmMa JnBaYQc+CbbfdJ9oyicX9SQO4G+BigbfPhh8fDBIyyDw7VSixZpdDDyocjOoIiOo6ybQF2pBFRgC /lh3SgD8+T6pfU4pgqnG+wJY6wH4a1+AgKDnLZkNDZ4cJIQBQlmQukqGVF3SI2o4S5zuX/AP12F+ vg+DTnyWdcckDKHouJtFbeaBLZodNf5Xg6riQBUYQOfpQefpLaOldcT8C4qUhDAwDxSv8um4m0X1 9n2BT9ND2TteAqgGwgyiwQ1zkLkq85eAGxYtns5QjOU++xifCtWf+wLI+B5v5Od7im8T7gGwA2aA ChankjisByAjaWzy84Mj3M7P9xSfC5UKjqCYATNFbd7aF0DGf9jNzx8w02tBJ03hc6ECANNjLKjo BFGbo3oAMhLEXn5+dAKYHmP91gW/KIWiGarxhNtZPQAZaWE3P/+Ol7wadNIUfhvSmLg+FJ0o3i7c UT0AGelgNz8/cajXg06awq/PXva2ZwG2wTzHzo7CMtLCZqdxVmW5j37Gr0KlI9o2a18AGf/isN5+ RFu/pz37fTXD9JkEKrytqK1xhQ4ZCcBQlvvSACq8LZg+kwLSHb8LlVIE2+4LEKME19c/1ZdlXIPr G24T6uhrf74zAmIfshsHMDjyHxcHIFVICGPZs7YB/vDnOyNghkw5DkC6BMqf74yACVWOA5AmgfTn OyOgriE5DkB6BNKf74yAClWOA5AWgfbnOyPgznY6ZYwcByAFHPjz6ZQxAeqQmICrgWZYOQ5AAjjy 59MMG/DRFJCAUAE5DiDQSMWf7wxJCBWQ4wACiVT8+c6QjFDlOIDAICV/vjMkI1RAjgPwOxLz5ztD UkKV4wD8i9T8+c6QlFABOQ7AX0jRn+8MyQkVcBAH0OhHlWke3OBIyfnznSFJodqNA+gTLscBeAk+ TgWuj3g6JQV/vjMkKVRAjgPwJVL15zvDJ0XSvAEVHEGZf/mCmL9/RWizxgEwv1UFsGd/bbiuIZL1 5ztD0p3jOTMxfToSpDgn0F3520JFJ0Ax8WvJuEodIdlHP2A/DkDGu0jJn+8MSQsVsB8HIOMdpObP d4bkhQrYiQOQaT4S9OfLyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjI/H34f4DnQZLCUbKg AAAAAElFTkSuQmCC "
+ height="14.666666"
+ width="14.666666" />
+ <path
+ inkscape:connector-curvature="0"
+ d="m 20.069438,17.426646 c -0.58864,0.26112 -1.22136,0.43752 -1.885279,0.51688 0.677599,-0.40624 1.198159,-1.04952 1.443279,-1.81608 -0.63432,0.37624 -1.336799,0.64936 -2.084559,0.79656 -0.59872,-0.638 -1.45184,-1.03656 -2.396,-1.03656 -1.8128,0 -3.282624,1.46968 -3.282624,3.28248 0,0.25728 0.02902,0.50784 0.085,0.74808 -2.7281291,-0.13688 -5.1469451,-1.44376 -6.7659131,-3.42976 -0.282592,0.4848 -0.444467,1.04872 -0.444467,1.65032 0,1.13888 0.579499,2.1436 1.460347,2.73224 -0.538096,-0.01704 -1.04428,-0.16472 -1.486816,-0.41056 -3.12e-4,0.01368 -3.12e-4,0.02736 -3.12e-4,0.04128 0,1.590424 1.131528,2.91708 2.63316,3.218736 -0.275408,0.075 -0.565408,0.11516 -0.864784,0.11516 -0.211528,0 -0.41716,-0.02062 -0.617624,-0.05891 0.41772,1.304064 1.63,2.253192 3.066432,2.279568 -1.123432,0.880496 -2.538808,1.40528 -4.076777,1.40528 -0.264969,0 -0.526281,-0.01559 -0.783063,-0.0459 1.452688,0.931341 3.17816,1.474872 5.031904,1.474872 6.0378571,0 9.3396971,-5.001904 9.3396971,-9.33976 0,-0.14232 -0.0033,-0.28384 -0.0096,-0.42464 0.641439,-0.46288 1.197919,-1.04096 1.637999,-1.69928"
+ style="fill:#00aced"
+ id="path4" />
+ </g>
+</svg>
diff --git a/src/tests/.eslintrc.yml b/src/tests/.eslintrc.yml
new file mode 100644
index 0000000..86d159b
--- /dev/null
+++ b/src/tests/.eslintrc.yml
@@ -0,0 +1,4 @@
+globals:
+ # false to disallow overwriting
+ QUnit: false
+ sinon: false
diff --git a/src/tests/index.html b/src/tests/index.html
new file mode 100644
index 0000000..3adc2ec
--- /dev/null
+++ b/src/tests/index.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<!--
+ - This file is part of Privacy Badger <https://www.eff.org/privacybadger>
+ - Copyright (C) 2014 Electronic Frontier Foundation
+ -
+ - Derived from Adblock Plus
+ - Copyright (C) 2006-2013 Eyeo GmbH
+ -
+ - Privacy Badger 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.
+ -
+ - Privacy Badger 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 Privacy Badger. If not, see <http://www.gnu.org/licenses/>.
+ -->
+
+<html>
+ <head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width">
+
+ <title>Privacy Badger unit tests</title>
+
+ <link rel="stylesheet" href="lib/vendor/qunit-2.9.2.css"/>
+ </head>
+ <body>
+ <div id="qunit"></div>
+ <div id="qunit-fixture"></div>
+
+ <script src="../lib/vendor/jquery-3.5.1.js"></script>
+ <script src="../lib/vendor/underscore-1.9.1.js"></script>
+
+ <script src="lib/vendor/qunit-2.9.2.js"></script>
+ <script src="lib/qunit_config.js"></script>
+ <script src="lib/vendor/sinon-2.0.0.js"></script>
+
+ <script src="../js/bootstrap.js"></script>
+ <script src="../data/surrogates.js"></script>
+ <script src="../js/surrogates.js"></script>
+ <script src="../js/multiDomainFirstParties.js"></script>
+ <script src="../js/storage.js"></script>
+ <script src="../js/utils.js"></script>
+ <script src="../js/constants.js"></script>
+ <script src="../js/incognito.js"></script>
+ <script src="../js/heuristicblocking.js"></script>
+
+ <script src="../lib/publicSuffixList.js"></script>
+ <script src="../lib/vendor/punycode-1.4.1.js"></script>
+ <script src="../lib/basedomain.js"></script>
+
+ <script src="../lib/options.js"></script>
+ <script src="../js/socialwidgetloader.js"></script>
+ <script src="../js/htmlutils.js"></script>
+ <script src="../js/migrations.js"></script>
+ <script src="../js/firefoxandroid.js"></script>
+ <script src="../js/webrequest.js"></script>
+ <script src="../js/background.js"></script>
+
+ <script src="tests/background.js"></script>
+ <script src="tests/firstparties.js"></script>
+ <script src="tests/heuristic.js"></script>
+ <script src="tests/htmlutils.js"></script>
+ <script src="tests/multiDomainFirstParties.js"></script>
+ <script src="tests/options.js"></script>
+ <script src="tests/storage.js"></script>
+ <script src="tests/tabData.js"></script>
+ <!-- URL/host tools: --><script src="tests/baseDomain.js"></script>
+ <script src="tests/utils.js"></script>
+ <script src="tests/yellowlist.js"></script>
+ </body>
+</html>
diff --git a/src/tests/lib/qunit_config.js b/src/tests/lib/qunit_config.js
new file mode 100644
index 0000000..36e58ae
--- /dev/null
+++ b/src/tests/lib/qunit_config.js
@@ -0,0 +1,74 @@
+/* globals badger:false */
+
+(function () {
+
+let BACKUP = {};
+
+QUnit.config.autostart = false;
+QUnit.config.testTimeout = 6400;
+
+// disable storage persistence
+// unit tests shouldn't be able to affect your Badger's storage
+chrome.storage.local.set = () => {};
+
+// make it seem like there is nothing in storage
+// unit tests shouldn't read from your Badger's storage either
+chrome.storage.local.get = (keys, callback) => {
+ // callback has to be async
+ setTimeout(function () {
+ callback({
+ // don't open the new user intro page or load seed data
+ private_storage: {
+ badgerVersion: chrome.runtime.getManifest().version,
+ }
+ });
+ }, 0);
+};
+
+// reset state between tests
+// to prevent tests affecting each other via side effects
+QUnit.testStart(() => {
+ // back up settings and heuristic learning
+ // TODO any other state we should reset? tabData?
+ badger.storage.KEYS.forEach(item => {
+ let obj = badger.storage.getStore(item);
+ BACKUP[item] = obj.getItemClones();
+ });
+});
+
+QUnit.testDone(() => {
+ // restore original settings and heuristic learning
+ badger.storage.KEYS.forEach(item => {
+ let obj = badger.storage.getStore(item);
+ obj.updateObject(BACKUP[item]);
+ });
+});
+
+// kick off tests when we have what we need from Badger
+(function () {
+
+ const WAIT_INTERVAL = 10,
+ MAX_WAIT = 1000;
+
+ let elapsed = 0;
+
+ function wait_for_badger() {
+ elapsed += WAIT_INTERVAL;
+
+ if (elapsed >= MAX_WAIT) {
+ // give up
+ QUnit.start();
+ }
+
+ if (typeof badger == "object" && badger.INITIALIZED) {
+ QUnit.start();
+ } else {
+ setTimeout(wait_for_badger, WAIT_INTERVAL);
+ }
+ }
+
+ setTimeout(wait_for_badger, WAIT_INTERVAL);
+
+}());
+
+}());
diff --git a/src/tests/lib/vendor/qunit-2.9.2.css b/src/tests/lib/vendor/qunit-2.9.2.css
new file mode 100644
index 0000000..1f54593
--- /dev/null
+++ b/src/tests/lib/vendor/qunit-2.9.2.css
@@ -0,0 +1,436 @@
+/*!
+ * QUnit 2.9.2
+ * https://qunitjs.com/
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license
+ * https://jquery.org/license
+ *
+ * Date: 2019-02-21T22:49Z
+ */
+
+/** Font Family and Sizes */
+
+#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult {
+ font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
+}
+
+#qunit-testrunner-toolbar, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
+#qunit-tests { font-size: smaller; }
+
+
+/** Resets */
+
+#qunit-tests, #qunit-header, #qunit-banner, #qunit-filteredTest, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
+ margin: 0;
+ padding: 0;
+}
+
+
+/** Header (excluding toolbar) */
+
+#qunit-header {
+ padding: 0.5em 0 0.5em 1em;
+
+ color: #8699A4;
+ background-color: #0D3349;
+
+ font-size: 1.5em;
+ line-height: 1em;
+ font-weight: 400;
+
+ border-radius: 5px 5px 0 0;
+}
+
+#qunit-header a {
+ text-decoration: none;
+ color: #C2CCD1;
+}
+
+#qunit-header a:hover,
+#qunit-header a:focus {
+ color: #FFF;
+}
+
+#qunit-banner {
+ height: 5px;
+}
+
+#qunit-filteredTest {
+ padding: 0.5em 1em 0.5em 1em;
+ color: #366097;
+ background-color: #F4FF77;
+}
+
+#qunit-userAgent {
+ padding: 0.5em 1em 0.5em 1em;
+ color: #FFF;
+ background-color: #2B81AF;
+ text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
+}
+
+
+/** Toolbar */
+
+#qunit-testrunner-toolbar {
+ padding: 0.5em 1em 0.5em 1em;
+ color: #5E740B;
+ background-color: #EEE;
+}
+
+#qunit-testrunner-toolbar .clearfix {
+ height: 0;
+ clear: both;
+}
+
+#qunit-testrunner-toolbar label {
+ display: inline-block;
+}
+
+#qunit-testrunner-toolbar input[type=checkbox],
+#qunit-testrunner-toolbar input[type=radio] {
+ margin: 3px;
+ vertical-align: -2px;
+}
+
+#qunit-testrunner-toolbar input[type=text] {
+ box-sizing: border-box;
+ height: 1.6em;
+}
+
+.qunit-url-config,
+.qunit-filter,
+#qunit-modulefilter {
+ display: inline-block;
+ line-height: 2.1em;
+}
+
+.qunit-filter,
+#qunit-modulefilter {
+ float: right;
+ position: relative;
+ margin-left: 1em;
+}
+
+.qunit-url-config label {
+ margin-right: 0.5em;
+}
+
+#qunit-modulefilter-search {
+ box-sizing: border-box;
+ width: 400px;
+}
+
+#qunit-modulefilter-search-container:after {
+ position: absolute;
+ right: 0.3em;
+ content: "\25bc";
+ color: black;
+}
+
+#qunit-modulefilter-dropdown {
+ /* align with #qunit-modulefilter-search */
+ box-sizing: border-box;
+ width: 400px;
+ position: absolute;
+ right: 0;
+ top: 50%;
+ margin-top: 0.8em;
+
+ border: 1px solid #D3D3D3;
+ border-top: none;
+ border-radius: 0 0 .25em .25em;
+ color: #000;
+ background-color: #F5F5F5;
+ z-index: 99;
+}
+
+#qunit-modulefilter-dropdown a {
+ color: inherit;
+ text-decoration: none;
+}
+
+#qunit-modulefilter-dropdown .clickable.checked {
+ font-weight: bold;
+ color: #000;
+ background-color: #D2E0E6;
+}
+
+#qunit-modulefilter-dropdown .clickable:hover {
+ color: #FFF;
+ background-color: #0D3349;
+}
+
+#qunit-modulefilter-actions {
+ display: block;
+ overflow: auto;
+
+ /* align with #qunit-modulefilter-dropdown-list */
+ font: smaller/1.5em sans-serif;
+}
+
+#qunit-modulefilter-dropdown #qunit-modulefilter-actions > * {
+ box-sizing: border-box;
+ max-height: 2.8em;
+ display: block;
+ padding: 0.4em;
+}
+
+#qunit-modulefilter-dropdown #qunit-modulefilter-actions > button {
+ float: right;
+ font: inherit;
+}
+
+#qunit-modulefilter-dropdown #qunit-modulefilter-actions > :last-child {
+ /* insert padding to align with checkbox margins */
+ padding-left: 3px;
+}
+
+#qunit-modulefilter-dropdown-list {
+ max-height: 200px;
+ overflow-y: auto;
+ margin: 0;
+ border-top: 2px groove threedhighlight;
+ padding: 0.4em 0 0;
+ font: smaller/1.5em sans-serif;
+}
+
+#qunit-modulefilter-dropdown-list li {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+#qunit-modulefilter-dropdown-list .clickable {
+ display: block;
+ padding-left: 0.15em;
+}
+
+
+/** Tests: Pass/Fail */
+
+#qunit-tests {
+ list-style-position: inside;
+}
+
+#qunit-tests li {
+ padding: 0.4em 1em 0.4em 1em;
+ border-bottom: 1px solid #FFF;
+ list-style-position: inside;
+}
+
+#qunit-tests > li {
+ display: none;
+}
+
+#qunit-tests li.running,
+#qunit-tests li.pass,
+#qunit-tests li.fail,
+#qunit-tests li.skipped,
+#qunit-tests li.aborted {
+ display: list-item;
+}
+
+#qunit-tests.hidepass {
+ position: relative;
+}
+
+#qunit-tests.hidepass li.running,
+#qunit-tests.hidepass li.pass:not(.todo) {
+ visibility: hidden;
+ position: absolute;
+ width: 0;
+ height: 0;
+ padding: 0;
+ border: 0;
+ margin: 0;
+}
+
+#qunit-tests li strong {
+ cursor: pointer;
+}
+
+#qunit-tests li.skipped strong {
+ cursor: default;
+}
+
+#qunit-tests li a {
+ padding: 0.5em;
+ color: #C2CCD1;
+ text-decoration: none;
+}
+
+#qunit-tests li p a {
+ padding: 0.25em;
+ color: #6B6464;
+}
+#qunit-tests li a:hover,
+#qunit-tests li a:focus {
+ color: #000;
+}
+
+#qunit-tests li .runtime {
+ float: right;
+ font-size: smaller;
+}
+
+.qunit-assert-list {
+ margin-top: 0.5em;
+ padding: 0.5em;
+
+ background-color: #FFF;
+
+ border-radius: 5px;
+}
+
+.qunit-source {
+ margin: 0.6em 0 0.3em;
+}
+
+.qunit-collapsed {
+ display: none;
+}
+
+#qunit-tests table {
+ border-collapse: collapse;
+ margin-top: 0.2em;
+}
+
+#qunit-tests th {
+ text-align: right;
+ vertical-align: top;
+ padding: 0 0.5em 0 0;
+}
+
+#qunit-tests td {
+ vertical-align: top;
+}
+
+#qunit-tests pre {
+ margin: 0;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+#qunit-tests del {
+ color: #374E0C;
+ background-color: #E0F2BE;
+ text-decoration: none;
+}
+
+#qunit-tests ins {
+ color: #500;
+ background-color: #FFCACA;
+ text-decoration: none;
+}
+
+/*** Test Counts */
+
+#qunit-tests b.counts { color: #000; }
+#qunit-tests b.passed { color: #5E740B; }
+#qunit-tests b.failed { color: #710909; }
+
+#qunit-tests li li {
+ padding: 5px;
+ background-color: #FFF;
+ border-bottom: none;
+ list-style-position: inside;
+}
+
+/*** Passing Styles */
+
+#qunit-tests li li.pass {
+ color: #3C510C;
+ background-color: #FFF;
+ border-left: 10px solid #C6E746;
+}
+
+#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
+#qunit-tests .pass .test-name { color: #366097; }
+
+#qunit-tests .pass .test-actual,
+#qunit-tests .pass .test-expected { color: #999; }
+
+#qunit-banner.qunit-pass { background-color: #C6E746; }
+
+/*** Failing Styles */
+
+#qunit-tests li li.fail {
+ color: #710909;
+ background-color: #FFF;
+ border-left: 10px solid #EE5757;
+ white-space: pre;
+}
+
+#qunit-tests > li:last-child {
+ border-radius: 0 0 5px 5px;
+}
+
+#qunit-tests .fail { color: #000; background-color: #EE5757; }
+#qunit-tests .fail .test-name,
+#qunit-tests .fail .module-name { color: #000; }
+
+#qunit-tests .fail .test-actual { color: #EE5757; }
+#qunit-tests .fail .test-expected { color: #008000; }
+
+#qunit-banner.qunit-fail { background-color: #EE5757; }
+
+
+/*** Aborted tests */
+#qunit-tests .aborted { color: #000; background-color: orange; }
+/*** Skipped tests */
+
+#qunit-tests .skipped {
+ background-color: #EBECE9;
+}
+
+#qunit-tests .qunit-todo-label,
+#qunit-tests .qunit-skipped-label {
+ background-color: #F4FF77;
+ display: inline-block;
+ font-style: normal;
+ color: #366097;
+ line-height: 1.8em;
+ padding: 0 0.5em;
+ margin: -0.4em 0.4em -0.4em 0;
+}
+
+#qunit-tests .qunit-todo-label {
+ background-color: #EEE;
+}
+
+/** Result */
+
+#qunit-testresult {
+ color: #2B81AF;
+ background-color: #D2E0E6;
+
+ border-bottom: 1px solid #FFF;
+}
+#qunit-testresult .clearfix {
+ height: 0;
+ clear: both;
+}
+#qunit-testresult .module-name {
+ font-weight: 700;
+}
+#qunit-testresult-display {
+ padding: 0.5em 1em 0.5em 1em;
+ width: 85%;
+ float:left;
+}
+#qunit-testresult-controls {
+ padding: 0.5em 1em 0.5em 1em;
+ width: 10%;
+ float:left;
+}
+
+/** Fixture */
+
+#qunit-fixture {
+ position: absolute;
+ top: -10000px;
+ left: -10000px;
+ width: 1000px;
+ height: 1000px;
+}
diff --git a/src/tests/lib/vendor/qunit-2.9.2.js b/src/tests/lib/vendor/qunit-2.9.2.js
new file mode 100644
index 0000000..f66e5c7
--- /dev/null
+++ b/src/tests/lib/vendor/qunit-2.9.2.js
@@ -0,0 +1,6604 @@
+/*!
+ * QUnit 2.9.2
+ * https://qunitjs.com/
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license
+ * https://jquery.org/license
+ *
+ * Date: 2019-02-21T22:49Z
+ */
+(function (global$1) {
+ 'use strict';
+
+ global$1 = global$1 && global$1.hasOwnProperty('default') ? global$1['default'] : global$1;
+
+ var window$1 = global$1.window;
+ var self$1 = global$1.self;
+ var console = global$1.console;
+ var setTimeout$1 = global$1.setTimeout;
+ var clearTimeout = global$1.clearTimeout;
+
+ var document$1 = window$1 && window$1.document;
+ var navigator = window$1 && window$1.navigator;
+
+ var localSessionStorage = function () {
+ var x = "qunit-test-string";
+ try {
+ global$1.sessionStorage.setItem(x, x);
+ global$1.sessionStorage.removeItem(x);
+ return global$1.sessionStorage;
+ } catch (e) {
+ return undefined;
+ }
+ }();
+
+ /**
+ * Returns a function that proxies to the given method name on the globals
+ * console object. The proxy will also detect if the console doesn't exist and
+ * will appropriately no-op. This allows support for IE9, which doesn't have a
+ * console if the developer tools are not open.
+ */
+ function consoleProxy(method) {
+ return function () {
+ if (console) {
+ console[method].apply(console, arguments);
+ }
+ };
+ }
+
+ var Logger = {
+ warn: consoleProxy("warn")
+ };
+
+ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
+ return typeof obj;
+ } : function (obj) {
+ return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
+ };
+
+
+
+
+
+
+
+
+
+
+
+ var classCallCheck = function (instance, Constructor) {
+ if (!(instance instanceof Constructor)) {
+ throw new TypeError("Cannot call a class as a function");
+ }
+ };
+
+ var createClass = function () {
+ function defineProperties(target, props) {
+ for (var i = 0; i < props.length; i++) {
+ var descriptor = props[i];
+ descriptor.enumerable = descriptor.enumerable || false;
+ descriptor.configurable = true;
+ if ("value" in descriptor) descriptor.writable = true;
+ Object.defineProperty(target, descriptor.key, descriptor);
+ }
+ }
+
+ return function (Constructor, protoProps, staticProps) {
+ if (protoProps) defineProperties(Constructor.prototype, protoProps);
+ if (staticProps) defineProperties(Constructor, staticProps);
+ return Constructor;
+ };
+ }();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ var toConsumableArray = function (arr) {
+ if (Array.isArray(arr)) {
+ for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i];
+
+ return arr2;
+ } else {
+ return Array.from(arr);
+ }
+ };
+
+ var toString = Object.prototype.toString;
+ var hasOwn = Object.prototype.hasOwnProperty;
+ var now = Date.now || function () {
+ return new Date().getTime();
+ };
+
+ var hasPerformanceApi = detectPerformanceApi();
+ var performance = hasPerformanceApi ? window$1.performance : undefined;
+ var performanceNow = hasPerformanceApi ? performance.now.bind(performance) : now;
+
+ function detectPerformanceApi() {
+ return window$1 && typeof window$1.performance !== "undefined" && typeof window$1.performance.mark === "function" && typeof window$1.performance.measure === "function";
+ }
+
+ function measure(comment, startMark, endMark) {
+
+ // `performance.measure` may fail if the mark could not be found.
+ // reasons a specific mark could not be found include: outside code invoking `performance.clearMarks()`
+ try {
+ performance.measure(comment, startMark, endMark);
+ } catch (ex) {
+ Logger.warn("performance.measure could not be executed because of ", ex.message);
+ }
+ }
+
+ var defined = {
+ document: window$1 && window$1.document !== undefined,
+ setTimeout: setTimeout$1 !== undefined
+ };
+
+ // Returns a new Array with the elements that are in a but not in b
+ function diff(a, b) {
+ var i,
+ j,
+ result = a.slice();
+
+ for (i = 0; i < result.length; i++) {
+ for (j = 0; j < b.length; j++) {
+ if (result[i] === b[j]) {
+ result.splice(i, 1);
+ i--;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Determines whether an element exists in a given array or not.
+ *
+ * @method inArray
+ * @param {Any} elem
+ * @param {Array} array
+ * @return {Boolean}
+ */
+ function inArray(elem, array) {
+ return array.indexOf(elem) !== -1;
+ }
+
+ /**
+ * Makes a clone of an object using only Array or Object as base,
+ * and copies over the own enumerable properties.
+ *
+ * @param {Object} obj
+ * @return {Object} New object with only the own properties (recursively).
+ */
+ function objectValues(obj) {
+ var key,
+ val,
+ vals = is("array", obj) ? [] : {};
+ for (key in obj) {
+ if (hasOwn.call(obj, key)) {
+ val = obj[key];
+ vals[key] = val === Object(val) ? objectValues(val) : val;
+ }
+ }
+ return vals;
+ }
+
+ function extend(a, b, undefOnly) {
+ for (var prop in b) {
+ if (hasOwn.call(b, prop)) {
+ if (b[prop] === undefined) {
+ delete a[prop];
+ } else if (!(undefOnly && typeof a[prop] !== "undefined")) {
+ a[prop] = b[prop];
+ }
+ }
+ }
+
+ return a;
+ }
+
+ function objectType(obj) {
+ if (typeof obj === "undefined") {
+ return "undefined";
+ }
+
+ // Consider: typeof null === object
+ if (obj === null) {
+ return "null";
+ }
+
+ var match = toString.call(obj).match(/^\[object\s(.*)\]$/),
+ type = match && match[1];
+
+ switch (type) {
+ case "Number":
+ if (isNaN(obj)) {
+ return "nan";
+ }
+ return "number";
+ case "String":
+ case "Boolean":
+ case "Array":
+ case "Set":
+ case "Map":
+ case "Date":
+ case "RegExp":
+ case "Function":
+ case "Symbol":
+ return type.toLowerCase();
+ default:
+ return typeof obj === "undefined" ? "undefined" : _typeof(obj);
+ }
+ }
+
+ // Safe object type checking
+ function is(type, obj) {
+ return objectType(obj) === type;
+ }
+
+ // Based on Java's String.hashCode, a simple but not
+ // rigorously collision resistant hashing function
+ function generateHash(module, testName) {
+ var str = module + "\x1C" + testName;
+ var hash = 0;
+
+ for (var i = 0; i < str.length; i++) {
+ hash = (hash << 5) - hash + str.charCodeAt(i);
+ hash |= 0;
+ }
+
+ // Convert the possibly negative integer hash code into an 8 character hex string, which isn't
+ // strictly necessary but increases user understanding that the id is a SHA-like hash
+ var hex = (0x100000000 + hash).toString(16);
+ if (hex.length < 8) {
+ hex = "0000000" + hex;
+ }
+
+ return hex.slice(-8);
+ }
+
+ // Test for equality any JavaScript type.
+ // Authors: Philippe Rathé <prathe@gmail.com>, David Chan <david@troi.org>
+ var equiv = (function () {
+
+ // Value pairs queued for comparison. Used for breadth-first processing order, recursion
+ // detection and avoiding repeated comparison (see below for details).
+ // Elements are { a: val, b: val }.
+ var pairs = [];
+
+ var getProto = Object.getPrototypeOf || function (obj) {
+ return obj.__proto__;
+ };
+
+ function useStrictEquality(a, b) {
+
+ // This only gets called if a and b are not strict equal, and is used to compare on
+ // the primitive values inside object wrappers. For example:
+ // `var i = 1;`
+ // `var j = new Number(1);`
+ // Neither a nor b can be null, as a !== b and they have the same type.
+ if ((typeof a === "undefined" ? "undefined" : _typeof(a)) === "object") {
+ a = a.valueOf();
+ }
+ if ((typeof b === "undefined" ? "undefined" : _typeof(b)) === "object") {
+ b = b.valueOf();
+ }
+
+ return a === b;
+ }
+
+ function compareConstructors(a, b) {
+ var protoA = getProto(a);
+ var protoB = getProto(b);
+
+ // Comparing constructors is more strict than using `instanceof`
+ if (a.constructor === b.constructor) {
+ return true;
+ }
+
+ // Ref #851
+ // If the obj prototype descends from a null constructor, treat it
+ // as a null prototype.
+ if (protoA && protoA.constructor === null) {
+ protoA = null;
+ }
+ if (protoB && protoB.constructor === null) {
+ protoB = null;
+ }
+
+ // Allow objects with no prototype to be equivalent to
+ // objects with Object as their constructor.
+ if (protoA === null && protoB === Object.prototype || protoB === null && protoA === Object.prototype) {
+ return true;
+ }
+
+ return false;
+ }
+
+ function getRegExpFlags(regexp) {
+ return "flags" in regexp ? regexp.flags : regexp.toString().match(/[gimuy]*$/)[0];
+ }
+
+ function isContainer(val) {
+ return ["object", "array", "map", "set"].indexOf(objectType(val)) !== -1;
+ }
+
+ function breadthFirstCompareChild(a, b) {
+
+ // If a is a container not reference-equal to b, postpone the comparison to the
+ // end of the pairs queue -- unless (a, b) has been seen before, in which case skip
+ // over the pair.
+ if (a === b) {
+ return true;
+ }
+ if (!isContainer(a)) {
+ return typeEquiv(a, b);
+ }
+ if (pairs.every(function (pair) {
+ return pair.a !== a || pair.b !== b;
+ })) {
+
+ // Not yet started comparing this pair
+ pairs.push({ a: a, b: b });
+ }
+ return true;
+ }
+
+ var callbacks = {
+ "string": useStrictEquality,
+ "boolean": useStrictEquality,
+ "number": useStrictEquality,
+ "null": useStrictEquality,
+ "undefined": useStrictEquality,
+ "symbol": useStrictEquality,
+ "date": useStrictEquality,
+
+ "nan": function nan() {
+ return true;
+ },
+
+ "regexp": function regexp(a, b) {
+ return a.source === b.source &&
+
+ // Include flags in the comparison
+ getRegExpFlags(a) === getRegExpFlags(b);
+ },
+
+ // abort (identical references / instance methods were skipped earlier)
+ "function": function _function() {
+ return false;
+ },
+
+ "array": function array(a, b) {
+ var i, len;
+
+ len = a.length;
+ if (len !== b.length) {
+
+ // Safe and faster
+ return false;
+ }
+
+ for (i = 0; i < len; i++) {
+
+ // Compare non-containers; queue non-reference-equal containers
+ if (!breadthFirstCompareChild(a[i], b[i])) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ // Define sets a and b to be equivalent if for each element aVal in a, there
+ // is some element bVal in b such that aVal and bVal are equivalent. Element
+ // repetitions are not counted, so these are equivalent:
+ // a = new Set( [ {}, [], [] ] );
+ // b = new Set( [ {}, {}, [] ] );
+ "set": function set$$1(a, b) {
+ var innerEq,
+ outerEq = true;
+
+ if (a.size !== b.size) {
+
+ // This optimization has certain quirks because of the lack of
+ // repetition counting. For instance, adding the same
+ // (reference-identical) element to two equivalent sets can
+ // make them non-equivalent.
+ return false;
+ }
+
+ a.forEach(function (aVal) {
+
+ // Short-circuit if the result is already known. (Using for...of
+ // with a break clause would be cleaner here, but it would cause
+ // a syntax error on older Javascript implementations even if
+ // Set is unused)
+ if (!outerEq) {
+ return;
+ }
+
+ innerEq = false;
+
+ b.forEach(function (bVal) {
+ var parentPairs;
+
+ // Likewise, short-circuit if the result is already known
+ if (innerEq) {
+ return;
+ }
+
+ // Swap out the global pairs list, as the nested call to
+ // innerEquiv will clobber its contents
+ parentPairs = pairs;
+ if (innerEquiv(bVal, aVal)) {
+ innerEq = true;
+ }
+
+ // Replace the global pairs list
+ pairs = parentPairs;
+ });
+
+ if (!innerEq) {
+ outerEq = false;
+ }
+ });
+
+ return outerEq;
+ },
+
+ // Define maps a and b to be equivalent if for each key-value pair (aKey, aVal)
+ // in a, there is some key-value pair (bKey, bVal) in b such that
+ // [ aKey, aVal ] and [ bKey, bVal ] are equivalent. Key repetitions are not
+ // counted, so these are equivalent:
+ // a = new Map( [ [ {}, 1 ], [ {}, 1 ], [ [], 1 ] ] );
+ // b = new Map( [ [ {}, 1 ], [ [], 1 ], [ [], 1 ] ] );
+ "map": function map(a, b) {
+ var innerEq,
+ outerEq = true;
+
+ if (a.size !== b.size) {
+
+ // This optimization has certain quirks because of the lack of
+ // repetition counting. For instance, adding the same
+ // (reference-identical) key-value pair to two equivalent maps
+ // can make them non-equivalent.
+ return false;
+ }
+
+ a.forEach(function (aVal, aKey) {
+
+ // Short-circuit if the result is already known. (Using for...of
+ // with a break clause would be cleaner here, but it would cause
+ // a syntax error on older Javascript implementations even if
+ // Map is unused)
+ if (!outerEq) {
+ return;
+ }
+
+ innerEq = false;
+
+ b.forEach(function (bVal, bKey) {
+ var parentPairs;
+
+ // Likewise, short-circuit if the result is already known
+ if (innerEq) {
+ return;
+ }
+
+ // Swap out the global pairs list, as the nested call to
+ // innerEquiv will clobber its contents
+ parentPairs = pairs;
+ if (innerEquiv([bVal, bKey], [aVal, aKey])) {
+ innerEq = true;
+ }
+
+ // Replace the global pairs list
+ pairs = parentPairs;
+ });
+
+ if (!innerEq) {
+ outerEq = false;
+ }
+ });
+
+ return outerEq;
+ },
+
+ "object": function object(a, b) {
+ var i,
+ aProperties = [],
+ bProperties = [];
+
+ if (compareConstructors(a, b) === false) {
+ return false;
+ }
+
+ // Be strict: don't ensure hasOwnProperty and go deep
+ for (i in a) {
+
+ // Collect a's properties
+ aProperties.push(i);
+
+ // Skip OOP methods that look the same
+ if (a.constructor !== Object && typeof a.constructor !== "undefined" && typeof a[i] === "function" && typeof b[i] === "function" && a[i].toString() === b[i].toString()) {
+ continue;
+ }
+
+ // Compare non-containers; queue non-reference-equal containers
+ if (!breadthFirstCompareChild(a[i], b[i])) {
+ return false;
+ }
+ }
+
+ for (i in b) {
+
+ // Collect b's properties
+ bProperties.push(i);
+ }
+
+ // Ensures identical properties name
+ return typeEquiv(aProperties.sort(), bProperties.sort());
+ }
+ };
+
+ function typeEquiv(a, b) {
+ var type = objectType(a);
+
+ // Callbacks for containers will append to the pairs queue to achieve breadth-first
+ // search order. The pairs queue is also used to avoid reprocessing any pair of
+ // containers that are reference-equal to a previously visited pair (a special case
+ // this being recursion detection).
+ //
+ // Because of this approach, once typeEquiv returns a false value, it should not be
+ // called again without clearing the pair queue else it may wrongly report a visited
+ // pair as being equivalent.
+ return objectType(b) === type && callbacks[type](a, b);
+ }
+
+ function innerEquiv(a, b) {
+ var i, pair;
+
+ // We're done when there's nothing more to compare
+ if (arguments.length < 2) {
+ return true;
+ }
+
+ // Clear the global pair queue and add the top-level values being compared
+ pairs = [{ a: a, b: b }];
+
+ for (i = 0; i < pairs.length; i++) {
+ pair = pairs[i];
+
+ // Perform type-specific comparison on any pairs that are not strictly
+ // equal. For container types, that comparison will postpone comparison
+ // of any sub-container pair to the end of the pair queue. This gives
+ // breadth-first search order. It also avoids the reprocessing of
+ // reference-equal siblings, cousins etc, which can have a significant speed
+ // impact when comparing a container of small objects each of which has a
+ // reference to the same (singleton) large object.
+ if (pair.a !== pair.b && !typeEquiv(pair.a, pair.b)) {
+ return false;
+ }
+ }
+
+ // ...across all consecutive argument pairs
+ return arguments.length === 2 || innerEquiv.apply(this, [].slice.call(arguments, 1));
+ }
+
+ return function () {
+ var result = innerEquiv.apply(undefined, arguments);
+
+ // Release any retained objects
+ pairs.length = 0;
+ return result;
+ };
+ })();
+
+ /**
+ * Config object: Maintain internal state
+ * Later exposed as QUnit.config
+ * `config` initialized at top of scope
+ */
+ var config = {
+
+ // The queue of tests to run
+ queue: [],
+
+ // Block until document ready
+ blocking: true,
+
+ // By default, run previously failed tests first
+ // very useful in combination with "Hide passed tests" checked
+ reorder: true,
+
+ // By default, modify document.title when suite is done
+ altertitle: true,
+
+ // HTML Reporter: collapse every test except the first failing test
+ // If false, all failing tests will be expanded
+ collapse: true,
+
+ // By default, scroll to top of the page when suite is done
+ scrolltop: true,
+
+ // Depth up-to which object will be dumped
+ maxDepth: 5,
+
+ // When enabled, all tests must call expect()
+ requireExpects: false,
+
+ // Placeholder for user-configurable form-exposed URL parameters
+ urlConfig: [],
+
+ // Set of all modules.
+ modules: [],
+
+ // The first unnamed module
+ currentModule: {
+ name: "",
+ tests: [],
+ childModules: [],
+ testsRun: 0,
+ unskippedTestsRun: 0,
+ hooks: {
+ before: [],
+ beforeEach: [],
+ afterEach: [],
+ after: []
+ }
+ },
+
+ callbacks: {},
+
+ // The storage module to use for reordering tests
+ storage: localSessionStorage
+ };
+
+ // take a predefined QUnit.config and extend the defaults
+ var globalConfig = window$1 && window$1.QUnit && window$1.QUnit.config;
+
+ // only extend the global config if there is no QUnit overload
+ if (window$1 && window$1.QUnit && !window$1.QUnit.version) {
+ extend(config, globalConfig);
+ }
+
+ // Push a loose unnamed module to the modules collection
+ config.modules.push(config.currentModule);
+
+ // Based on jsDump by Ariel Flesler
+ // http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html
+ var dump = (function () {
+ function quote(str) {
+ return "\"" + str.toString().replace(/\\/g, "\\\\").replace(/"/g, "\\\"") + "\"";
+ }
+ function literal(o) {
+ return o + "";
+ }
+ function join(pre, arr, post) {
+ var s = dump.separator(),
+ base = dump.indent(),
+ inner = dump.indent(1);
+ if (arr.join) {
+ arr = arr.join("," + s + inner);
+ }
+ if (!arr) {
+ return pre + post;
+ }
+ return [pre, inner + arr, base + post].join(s);
+ }
+ function array(arr, stack) {
+ var i = arr.length,
+ ret = new Array(i);
+
+ if (dump.maxDepth && dump.depth > dump.maxDepth) {
+ return "[object Array]";
+ }
+
+ this.up();
+ while (i--) {
+ ret[i] = this.parse(arr[i], undefined, stack);
+ }
+ this.down();
+ return join("[", ret, "]");
+ }
+
+ function isArray(obj) {
+ return (
+
+ //Native Arrays
+ toString.call(obj) === "[object Array]" ||
+
+ // NodeList objects
+ typeof obj.length === "number" && obj.item !== undefined && (obj.length ? obj.item(0) === obj[0] : obj.item(0) === null && obj[0] === undefined)
+ );
+ }
+
+ var reName = /^function (\w+)/,
+ dump = {
+
+ // The objType is used mostly internally, you can fix a (custom) type in advance
+ parse: function parse(obj, objType, stack) {
+ stack = stack || [];
+ var res,
+ parser,
+ parserType,
+ objIndex = stack.indexOf(obj);
+
+ if (objIndex !== -1) {
+ return "recursion(" + (objIndex - stack.length) + ")";
+ }
+
+ objType = objType || this.typeOf(obj);
+ parser = this.parsers[objType];
+ parserType = typeof parser === "undefined" ? "undefined" : _typeof(parser);
+
+ if (parserType === "function") {
+ stack.push(obj);
+ res = parser.call(this, obj, stack);
+ stack.pop();
+ return res;
+ }
+ return parserType === "string" ? parser : this.parsers.error;
+ },
+ typeOf: function typeOf(obj) {
+ var type;
+
+ if (obj === null) {
+ type = "null";
+ } else if (typeof obj === "undefined") {
+ type = "undefined";
+ } else if (is("regexp", obj)) {
+ type = "regexp";
+ } else if (is("date", obj)) {
+ type = "date";
+ } else if (is("function", obj)) {
+ type = "function";
+ } else if (obj.setInterval !== undefined && obj.document !== undefined && obj.nodeType === undefined) {
+ type = "window";
+ } else if (obj.nodeType === 9) {
+ type = "document";
+ } else if (obj.nodeType) {
+ type = "node";
+ } else if (isArray(obj)) {
+ type = "array";
+ } else if (obj.constructor === Error.prototype.constructor) {
+ type = "error";
+ } else {
+ type = typeof obj === "undefined" ? "undefined" : _typeof(obj);
+ }
+ return type;
+ },
+
+ separator: function separator() {
+ if (this.multiline) {
+ return this.HTML ? "<br />" : "\n";
+ } else {
+ return this.HTML ? "&#160;" : " ";
+ }
+ },
+
+ // Extra can be a number, shortcut for increasing-calling-decreasing
+ indent: function indent(extra) {
+ if (!this.multiline) {
+ return "";
+ }
+ var chr = this.indentChar;
+ if (this.HTML) {
+ chr = chr.replace(/\t/g, " ").replace(/ /g, "&#160;");
+ }
+ return new Array(this.depth + (extra || 0)).join(chr);
+ },
+ up: function up(a) {
+ this.depth += a || 1;
+ },
+ down: function down(a) {
+ this.depth -= a || 1;
+ },
+ setParser: function setParser(name, parser) {
+ this.parsers[name] = parser;
+ },
+
+ // The next 3 are exposed so you can use them
+ quote: quote,
+ literal: literal,
+ join: join,
+ depth: 1,
+ maxDepth: config.maxDepth,
+
+ // This is the list of parsers, to modify them, use dump.setParser
+ parsers: {
+ window: "[Window]",
+ document: "[Document]",
+ error: function error(_error) {
+ return "Error(\"" + _error.message + "\")";
+ },
+ unknown: "[Unknown]",
+ "null": "null",
+ "undefined": "undefined",
+ "function": function _function(fn) {
+ var ret = "function",
+
+
+ // Functions never have name in IE
+ name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
+
+ if (name) {
+ ret += " " + name;
+ }
+ ret += "(";
+
+ ret = [ret, dump.parse(fn, "functionArgs"), "){"].join("");
+ return join(ret, dump.parse(fn, "functionCode"), "}");
+ },
+ array: array,
+ nodelist: array,
+ "arguments": array,
+ object: function object(map, stack) {
+ var keys,
+ key,
+ val,
+ i,
+ nonEnumerableProperties,
+ ret = [];
+
+ if (dump.maxDepth && dump.depth > dump.maxDepth) {
+ return "[object Object]";
+ }
+
+ dump.up();
+ keys = [];
+ for (key in map) {
+ keys.push(key);
+ }
+
+ // Some properties are not always enumerable on Error objects.
+ nonEnumerableProperties = ["message", "name"];
+ for (i in nonEnumerableProperties) {
+ key = nonEnumerableProperties[i];
+ if (key in map && !inArray(key, keys)) {
+ keys.push(key);
+ }
+ }
+ keys.sort();
+ for (i = 0; i < keys.length; i++) {
+ key = keys[i];
+ val = map[key];
+ ret.push(dump.parse(key, "key") + ": " + dump.parse(val, undefined, stack));
+ }
+ dump.down();
+ return join("{", ret, "}");
+ },
+ node: function node(_node) {
+ var len,
+ i,
+ val,
+ open = dump.HTML ? "&lt;" : "<",
+ close = dump.HTML ? "&gt;" : ">",
+ tag = _node.nodeName.toLowerCase(),
+ ret = open + tag,
+ attrs = _node.attributes;
+
+ if (attrs) {
+ for (i = 0, len = attrs.length; i < len; i++) {
+ val = attrs[i].nodeValue;
+
+ // IE6 includes all attributes in .attributes, even ones not explicitly
+ // set. Those have values like undefined, null, 0, false, "" or
+ // "inherit".
+ if (val && val !== "inherit") {
+ ret += " " + attrs[i].nodeName + "=" + dump.parse(val, "attribute");
+ }
+ }
+ }
+ ret += close;
+
+ // Show content of TextNode or CDATASection
+ if (_node.nodeType === 3 || _node.nodeType === 4) {
+ ret += _node.nodeValue;
+ }
+
+ return ret + open + "/" + tag + close;
+ },
+
+ // Function calls it internally, it's the arguments part of the function
+ functionArgs: function functionArgs(fn) {
+ var args,
+ l = fn.length;
+
+ if (!l) {
+ return "";
+ }
+
+ args = new Array(l);
+ while (l--) {
+
+ // 97 is 'a'
+ args[l] = String.fromCharCode(97 + l);
+ }
+ return " " + args.join(", ") + " ";
+ },
+
+ // Object calls it internally, the key part of an item in a map
+ key: quote,
+
+ // Function calls it internally, it's the content of the function
+ functionCode: "[code]",
+
+ // Node calls it internally, it's a html attribute value
+ attribute: quote,
+ string: quote,
+ date: quote,
+ regexp: literal,
+ number: literal,
+ "boolean": literal,
+ symbol: function symbol(sym) {
+ return sym.toString();
+ }
+ },
+
+ // If true, entities are escaped ( <, >, \t, space and \n )
+ HTML: false,
+
+ // Indentation unit
+ indentChar: " ",
+
+ // If true, items in a collection, are separated by a \n, else just a space.
+ multiline: true
+ };
+
+ return dump;
+ })();
+
+ var SuiteReport = function () {
+ function SuiteReport(name, parentSuite) {
+ classCallCheck(this, SuiteReport);
+
+ this.name = name;
+ this.fullName = parentSuite ? parentSuite.fullName.concat(name) : [];
+
+ this.tests = [];
+ this.childSuites = [];
+
+ if (parentSuite) {
+ parentSuite.pushChildSuite(this);
+ }
+ }
+
+ createClass(SuiteReport, [{
+ key: "start",
+ value: function start(recordTime) {
+ if (recordTime) {
+ this._startTime = performanceNow();
+
+ if (performance) {
+ var suiteLevel = this.fullName.length;
+ performance.mark("qunit_suite_" + suiteLevel + "_start");
+ }
+ }
+
+ return {
+ name: this.name,
+ fullName: this.fullName.slice(),
+ tests: this.tests.map(function (test) {
+ return test.start();
+ }),
+ childSuites: this.childSuites.map(function (suite) {
+ return suite.start();
+ }),
+ testCounts: {
+ total: this.getTestCounts().total
+ }
+ };
+ }
+ }, {
+ key: "end",
+ value: function end(recordTime) {
+ if (recordTime) {
+ this._endTime = performanceNow();
+
+ if (performance) {
+ var suiteLevel = this.fullName.length;
+ performance.mark("qunit_suite_" + suiteLevel + "_end");
+
+ var suiteName = this.fullName.join(" – ");
+
+ measure(suiteLevel === 0 ? "QUnit Test Run" : "QUnit Test Suite: " + suiteName, "qunit_suite_" + suiteLevel + "_start", "qunit_suite_" + suiteLevel + "_end");
+ }
+ }
+
+ return {
+ name: this.name,
+ fullName: this.fullName.slice(),
+ tests: this.tests.map(function (test) {
+ return test.end();
+ }),
+ childSuites: this.childSuites.map(function (suite) {
+ return suite.end();
+ }),
+ testCounts: this.getTestCounts(),
+ runtime: this.getRuntime(),
+ status: this.getStatus()
+ };
+ }
+ }, {
+ key: "pushChildSuite",
+ value: function pushChildSuite(suite) {
+ this.childSuites.push(suite);
+ }
+ }, {
+ key: "pushTest",
+ value: function pushTest(test) {
+ this.tests.push(test);
+ }
+ }, {
+ key: "getRuntime",
+ value: function getRuntime() {
+ return this._endTime - this._startTime;
+ }
+ }, {
+ key: "getTestCounts",
+ value: function getTestCounts() {
+ var counts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : { passed: 0, failed: 0, skipped: 0, todo: 0, total: 0 };
+
+ counts = this.tests.reduce(function (counts, test) {
+ if (test.valid) {
+ counts[test.getStatus()]++;
+ counts.total++;
+ }
+
+ return counts;
+ }, counts);
+
+ return this.childSuites.reduce(function (counts, suite) {
+ return suite.getTestCounts(counts);
+ }, counts);
+ }
+ }, {
+ key: "getStatus",
+ value: function getStatus() {
+ var _getTestCounts = this.getTestCounts(),
+ total = _getTestCounts.total,
+ failed = _getTestCounts.failed,
+ skipped = _getTestCounts.skipped,
+ todo = _getTestCounts.todo;
+
+ if (failed) {
+ return "failed";
+ } else {
+ if (skipped === total) {
+ return "skipped";
+ } else if (todo === total) {
+ return "todo";
+ } else {
+ return "passed";
+ }
+ }
+ }
+ }]);
+ return SuiteReport;
+ }();
+
+ var focused = false;
+
+ var moduleStack = [];
+
+ function createModule(name, testEnvironment, modifiers) {
+ var parentModule = moduleStack.length ? moduleStack.slice(-1)[0] : null;
+ var moduleName = parentModule !== null ? [parentModule.name, name].join(" > ") : name;
+ var parentSuite = parentModule ? parentModule.suiteReport : globalSuite;
+
+ var skip = parentModule !== null && parentModule.skip || modifiers.skip;
+ var todo = parentModule !== null && parentModule.todo || modifiers.todo;
+
+ var module = {
+ name: moduleName,
+ parentModule: parentModule,
+ tests: [],
+ moduleId: generateHash(moduleName),
+ testsRun: 0,
+ unskippedTestsRun: 0,
+ childModules: [],
+ suiteReport: new SuiteReport(name, parentSuite),
+
+ // Pass along `skip` and `todo` properties from parent module, in case
+ // there is one, to childs. And use own otherwise.
+ // This property will be used to mark own tests and tests of child suites
+ // as either `skipped` or `todo`.
+ skip: skip,
+ todo: skip ? false : todo
+ };
+
+ var env = {};
+ if (parentModule) {
+ parentModule.childModules.push(module);
+ extend(env, parentModule.testEnvironment);
+ }
+ extend(env, testEnvironment);
+ module.testEnvironment = env;
+
+ config.modules.push(module);
+ return module;
+ }
+
+ function processModule(name, options, executeNow) {
+ var modifiers = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
+
+ if (objectType(options) === "function") {
+ executeNow = options;
+ options = undefined;
+ }
+
+ var module = createModule(name, options, modifiers);
+
+ // Move any hooks to a 'hooks' object
+ var testEnvironment = module.testEnvironment;
+ var hooks = module.hooks = {};
+
+ setHookFromEnvironment(hooks, testEnvironment, "before");
+ setHookFromEnvironment(hooks, testEnvironment, "beforeEach");
+ setHookFromEnvironment(hooks, testEnvironment, "afterEach");
+ setHookFromEnvironment(hooks, testEnvironment, "after");
+
+ var moduleFns = {
+ before: setHookFunction(module, "before"),
+ beforeEach: setHookFunction(module, "beforeEach"),
+ afterEach: setHookFunction(module, "afterEach"),
+ after: setHookFunction(module, "after")
+ };
+
+ var currentModule = config.currentModule;
+ if (objectType(executeNow) === "function") {
+ moduleStack.push(module);
+ config.currentModule = module;
+ executeNow.call(module.testEnvironment, moduleFns);
+ moduleStack.pop();
+ module = module.parentModule || currentModule;
+ }
+
+ config.currentModule = module;
+
+ function setHookFromEnvironment(hooks, environment, name) {
+ var potentialHook = environment[name];
+ hooks[name] = typeof potentialHook === "function" ? [potentialHook] : [];
+ delete environment[name];
+ }
+
+ function setHookFunction(module, hookName) {
+ return function setHook(callback) {
+ module.hooks[hookName].push(callback);
+ };
+ }
+ }
+
+ function module$1(name, options, executeNow) {
+ if (focused) {
+ return;
+ }
+
+ processModule(name, options, executeNow);
+ }
+
+ module$1.only = function () {
+ if (focused) {
+ return;
+ }
+
+ config.modules.length = 0;
+ config.queue.length = 0;
+
+ module$1.apply(undefined, arguments);
+
+ focused = true;
+ };
+
+ module$1.skip = function (name, options, executeNow) {
+ if (focused) {
+ return;
+ }
+
+ processModule(name, options, executeNow, { skip: true });
+ };
+
+ module$1.todo = function (name, options, executeNow) {
+ if (focused) {
+ return;
+ }
+
+ processModule(name, options, executeNow, { todo: true });
+ };
+
+ var LISTENERS = Object.create(null);
+ var SUPPORTED_EVENTS = ["runStart", "suiteStart", "testStart", "assertion", "testEnd", "suiteEnd", "runEnd"];
+
+ /**
+ * Emits an event with the specified data to all currently registered listeners.
+ * Callbacks will fire in the order in which they are registered (FIFO). This
+ * function is not exposed publicly; it is used by QUnit internals to emit
+ * logging events.
+ *
+ * @private
+ * @method emit
+ * @param {String} eventName
+ * @param {Object} data
+ * @return {Void}
+ */
+ function emit(eventName, data) {
+ if (objectType(eventName) !== "string") {
+ throw new TypeError("eventName must be a string when emitting an event");
+ }
+
+ // Clone the callbacks in case one of them registers a new callback
+ var originalCallbacks = LISTENERS[eventName];
+ var callbacks = originalCallbacks ? [].concat(toConsumableArray(originalCallbacks)) : [];
+
+ for (var i = 0; i < callbacks.length; i++) {
+ callbacks[i](data);
+ }
+ }
+
+ /**
+ * Registers a callback as a listener to the specified event.
+ *
+ * @public
+ * @method on
+ * @param {String} eventName
+ * @param {Function} callback
+ * @return {Void}
+ */
+ function on(eventName, callback) {
+ if (objectType(eventName) !== "string") {
+ throw new TypeError("eventName must be a string when registering a listener");
+ } else if (!inArray(eventName, SUPPORTED_EVENTS)) {
+ var events = SUPPORTED_EVENTS.join(", ");
+ throw new Error("\"" + eventName + "\" is not a valid event; must be one of: " + events + ".");
+ } else if (objectType(callback) !== "function") {
+ throw new TypeError("callback must be a function when registering a listener");
+ }
+
+ if (!LISTENERS[eventName]) {
+ LISTENERS[eventName] = [];
+ }
+
+ // Don't register the same callback more than once
+ if (!inArray(callback, LISTENERS[eventName])) {
+ LISTENERS[eventName].push(callback);
+ }
+ }
+
+ function objectOrFunction(x) {
+ var type = typeof x === 'undefined' ? 'undefined' : _typeof(x);
+ return x !== null && (type === 'object' || type === 'function');
+ }
+
+ function isFunction(x) {
+ return typeof x === 'function';
+ }
+
+
+
+ var _isArray = void 0;
+ if (Array.isArray) {
+ _isArray = Array.isArray;
+ } else {
+ _isArray = function _isArray(x) {
+ return Object.prototype.toString.call(x) === '[object Array]';
+ };
+ }
+
+ var isArray = _isArray;
+
+ var len = 0;
+ var vertxNext = void 0;
+ var customSchedulerFn = void 0;
+
+ var asap = function asap(callback, arg) {
+ queue[len] = callback;
+ queue[len + 1] = arg;
+ len += 2;
+ if (len === 2) {
+ // If len is 2, that means that we need to schedule an async flush.
+ // If additional callbacks are queued before the queue is flushed, they
+ // will be processed by this flush that we are scheduling.
+ if (customSchedulerFn) {
+ customSchedulerFn(flush);
+ } else {
+ scheduleFlush();
+ }
+ }
+ };
+
+ function setScheduler(scheduleFn) {
+ customSchedulerFn = scheduleFn;
+ }
+
+ function setAsap(asapFn) {
+ asap = asapFn;
+ }
+
+ var browserWindow = typeof window !== 'undefined' ? window : undefined;
+ var browserGlobal = browserWindow || {};
+ var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
+ var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';
+
+ // test for web worker but not in IE10
+ var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';
+
+ // node
+ function useNextTick() {
+ // node version 0.10.x displays a deprecation warning when nextTick is used recursively
+ // see https://github.com/cujojs/when/issues/410 for details
+ return function () {
+ return process.nextTick(flush);
+ };
+ }
+
+ // vertx
+ function useVertxTimer() {
+ if (typeof vertxNext !== 'undefined') {
+ return function () {
+ vertxNext(flush);
+ };
+ }
+
+ return useSetTimeout();
+ }
+
+ function useMutationObserver() {
+ var iterations = 0;
+ var observer = new BrowserMutationObserver(flush);
+ var node = document.createTextNode('');
+ observer.observe(node, { characterData: true });
+
+ return function () {
+ node.data = iterations = ++iterations % 2;
+ };
+ }
+
+ // web worker
+ function useMessageChannel() {
+ var channel = new MessageChannel();
+ channel.port1.onmessage = flush;
+ return function () {
+ return channel.port2.postMessage(0);
+ };
+ }
+
+ function useSetTimeout() {
+ // Store setTimeout reference so es6-promise will be unaffected by
+ // other code modifying setTimeout (like sinon.useFakeTimers())
+ var globalSetTimeout = setTimeout;
+ return function () {
+ return globalSetTimeout(flush, 1);
+ };
+ }
+
+ var queue = new Array(1000);
+ function flush() {
+ for (var i = 0; i < len; i += 2) {
+ var callback = queue[i];
+ var arg = queue[i + 1];
+
+ callback(arg);
+
+ queue[i] = undefined;
+ queue[i + 1] = undefined;
+ }
+
+ len = 0;
+ }
+
+ function attemptVertx() {
+ try {
+ var vertx = Function('return this')().require('vertx');
+ vertxNext = vertx.runOnLoop || vertx.runOnContext;
+ return useVertxTimer();
+ } catch (e) {
+ return useSetTimeout();
+ }
+ }
+
+ var scheduleFlush = void 0;
+ // Decide what async method to use to triggering processing of queued callbacks:
+ if (isNode) {
+ scheduleFlush = useNextTick();
+ } else if (BrowserMutationObserver) {
+ scheduleFlush = useMutationObserver();
+ } else if (isWorker) {
+ scheduleFlush = useMessageChannel();
+ } else if (browserWindow === undefined && typeof require === 'function') {
+ scheduleFlush = attemptVertx();
+ } else {
+ scheduleFlush = useSetTimeout();
+ }
+
+ function then(onFulfillment, onRejection) {
+ var parent = this;
+
+ var child = new this.constructor(noop);
+
+ if (child[PROMISE_ID] === undefined) {
+ makePromise(child);
+ }
+
+ var _state = parent._state;
+
+
+ if (_state) {
+ var callback = arguments[_state - 1];
+ asap(function () {
+ return invokeCallback(_state, child, callback, parent._result);
+ });
+ } else {
+ subscribe(parent, child, onFulfillment, onRejection);
+ }
+
+ return child;
+ }
+
+ /**
+ `Promise.resolve` returns a promise that will become resolved with the
+ passed `value`. It is shorthand for the following:
+
+ ```javascript
+ let promise = new Promise(function(resolve, reject){
+ resolve(1);
+ });
+
+ promise.then(function(value){
+ // value === 1
+ });
+ ```
+
+ Instead of writing the above, your code now simply becomes the following:
+
+ ```javascript
+ let promise = Promise.resolve(1);
+
+ promise.then(function(value){
+ // value === 1
+ });
+ ```
+
+ @method resolve
+ @static
+ @param {Any} value value that the returned promise will be resolved with
+ Useful for tooling.
+ @return {Promise} a promise that will become fulfilled with the given
+ `value`
+ */
+ function resolve$1(object) {
+ /*jshint validthis:true */
+ var Constructor = this;
+
+ if (object && (typeof object === 'undefined' ? 'undefined' : _typeof(object)) === 'object' && object.constructor === Constructor) {
+ return object;
+ }
+
+ var promise = new Constructor(noop);
+ resolve(promise, object);
+ return promise;
+ }
+
+ var PROMISE_ID = Math.random().toString(36).substring(2);
+
+ function noop() {}
+
+ var PENDING = void 0;
+ var FULFILLED = 1;
+ var REJECTED = 2;
+
+ var TRY_CATCH_ERROR = { error: null };
+
+ function selfFulfillment() {
+ return new TypeError("You cannot resolve a promise with itself");
+ }
+
+ function cannotReturnOwn() {
+ return new TypeError('A promises callback cannot return that same promise.');
+ }
+
+ function getThen(promise) {
+ try {
+ return promise.then;
+ } catch (error) {
+ TRY_CATCH_ERROR.error = error;
+ return TRY_CATCH_ERROR;
+ }
+ }
+
+ function tryThen(then$$1, value, fulfillmentHandler, rejectionHandler) {
+ try {
+ then$$1.call(value, fulfillmentHandler, rejectionHandler);
+ } catch (e) {
+ return e;
+ }
+ }
+
+ function handleForeignThenable(promise, thenable, then$$1) {
+ asap(function (promise) {
+ var sealed = false;
+ var error = tryThen(then$$1, thenable, function (value) {
+ if (sealed) {
+ return;
+ }
+ sealed = true;
+ if (thenable !== value) {
+ resolve(promise, value);
+ } else {
+ fulfill(promise, value);
+ }
+ }, function (reason) {
+ if (sealed) {
+ return;
+ }
+ sealed = true;
+
+ reject(promise, reason);
+ }, 'Settle: ' + (promise._label || ' unknown promise'));
+
+ if (!sealed && error) {
+ sealed = true;
+ reject(promise, error);
+ }
+ }, promise);
+ }
+
+ function handleOwnThenable(promise, thenable) {
+ if (thenable._state === FULFILLED) {
+ fulfill(promise, thenable._result);
+ } else if (thenable._state === REJECTED) {
+ reject(promise, thenable._result);
+ } else {
+ subscribe(thenable, undefined, function (value) {
+ return resolve(promise, value);
+ }, function (reason) {
+ return reject(promise, reason);
+ });
+ }
+ }
+
+ function handleMaybeThenable(promise, maybeThenable, then$$1) {
+ if (maybeThenable.constructor === promise.constructor && then$$1 === then && maybeThenable.constructor.resolve === resolve$1) {
+ handleOwnThenable(promise, maybeThenable);
+ } else {
+ if (then$$1 === TRY_CATCH_ERROR) {
+ reject(promise, TRY_CATCH_ERROR.error);
+ TRY_CATCH_ERROR.error = null;
+ } else if (then$$1 === undefined) {
+ fulfill(promise, maybeThenable);
+ } else if (isFunction(then$$1)) {
+ handleForeignThenable(promise, maybeThenable, then$$1);
+ } else {
+ fulfill(promise, maybeThenable);
+ }
+ }
+ }
+
+ function resolve(promise, value) {
+ if (promise === value) {
+ reject(promise, selfFulfillment());
+ } else if (objectOrFunction(value)) {
+ handleMaybeThenable(promise, value, getThen(value));
+ } else {
+ fulfill(promise, value);
+ }
+ }
+
+ function publishRejection(promise) {
+ if (promise._onerror) {
+ promise._onerror(promise._result);
+ }
+
+ publish(promise);
+ }
+
+ function fulfill(promise, value) {
+ if (promise._state !== PENDING) {
+ return;
+ }
+
+ promise._result = value;
+ promise._state = FULFILLED;
+
+ if (promise._subscribers.length !== 0) {
+ asap(publish, promise);
+ }
+ }
+
+ function reject(promise, reason) {
+ if (promise._state !== PENDING) {
+ return;
+ }
+ promise._state = REJECTED;
+ promise._result = reason;
+
+ asap(publishRejection, promise);
+ }
+
+ function subscribe(parent, child, onFulfillment, onRejection) {
+ var _subscribers = parent._subscribers;
+ var length = _subscribers.length;
+
+
+ parent._onerror = null;
+
+ _subscribers[length] = child;
+ _subscribers[length + FULFILLED] = onFulfillment;
+ _subscribers[length + REJECTED] = onRejection;
+
+ if (length === 0 && parent._state) {
+ asap(publish, parent);
+ }
+ }
+
+ function publish(promise) {
+ var subscribers = promise._subscribers;
+ var settled = promise._state;
+
+ if (subscribers.length === 0) {
+ return;
+ }
+
+ var child = void 0,
+ callback = void 0,
+ detail = promise._result;
+
+ for (var i = 0; i < subscribers.length; i += 3) {
+ child = subscribers[i];
+ callback = subscribers[i + settled];
+
+ if (child) {
+ invokeCallback(settled, child, callback, detail);
+ } else {
+ callback(detail);
+ }
+ }
+
+ promise._subscribers.length = 0;
+ }
+
+ function tryCatch(callback, detail) {
+ try {
+ return callback(detail);
+ } catch (e) {
+ TRY_CATCH_ERROR.error = e;
+ return TRY_CATCH_ERROR;
+ }
+ }
+
+ function invokeCallback(settled, promise, callback, detail) {
+ var hasCallback = isFunction(callback),
+ value = void 0,
+ error = void 0,
+ succeeded = void 0,
+ failed = void 0;
+
+ if (hasCallback) {
+ value = tryCatch(callback, detail);
+
+ if (value === TRY_CATCH_ERROR) {
+ failed = true;
+ error = value.error;
+ value.error = null;
+ } else {
+ succeeded = true;
+ }
+
+ if (promise === value) {
+ reject(promise, cannotReturnOwn());
+ return;
+ }
+ } else {
+ value = detail;
+ succeeded = true;
+ }
+
+ if (promise._state !== PENDING) {
+ // noop
+ } else if (hasCallback && succeeded) {
+ resolve(promise, value);
+ } else if (failed) {
+ reject(promise, error);
+ } else if (settled === FULFILLED) {
+ fulfill(promise, value);
+ } else if (settled === REJECTED) {
+ reject(promise, value);
+ }
+ }
+
+ function initializePromise(promise, resolver) {
+ try {
+ resolver(function resolvePromise(value) {
+ resolve(promise, value);
+ }, function rejectPromise(reason) {
+ reject(promise, reason);
+ });
+ } catch (e) {
+ reject(promise, e);
+ }
+ }
+
+ var id = 0;
+ function nextId() {
+ return id++;
+ }
+
+ function makePromise(promise) {
+ promise[PROMISE_ID] = id++;
+ promise._state = undefined;
+ promise._result = undefined;
+ promise._subscribers = [];
+ }
+
+ function validationError() {
+ return new Error('Array Methods must be provided an Array');
+ }
+
+ var Enumerator = function () {
+ function Enumerator(Constructor, input) {
+ classCallCheck(this, Enumerator);
+
+ this._instanceConstructor = Constructor;
+ this.promise = new Constructor(noop);
+
+ if (!this.promise[PROMISE_ID]) {
+ makePromise(this.promise);
+ }
+
+ if (isArray(input)) {
+ this.length = input.length;
+ this._remaining = input.length;
+
+ this._result = new Array(this.length);
+
+ if (this.length === 0) {
+ fulfill(this.promise, this._result);
+ } else {
+ this.length = this.length || 0;
+ this._enumerate(input);
+ if (this._remaining === 0) {
+ fulfill(this.promise, this._result);
+ }
+ }
+ } else {
+ reject(this.promise, validationError());
+ }
+ }
+
+ createClass(Enumerator, [{
+ key: '_enumerate',
+ value: function _enumerate(input) {
+ for (var i = 0; this._state === PENDING && i < input.length; i++) {
+ this._eachEntry(input[i], i);
+ }
+ }
+ }, {
+ key: '_eachEntry',
+ value: function _eachEntry(entry, i) {
+ var c = this._instanceConstructor;
+ var resolve$$1 = c.resolve;
+
+
+ if (resolve$$1 === resolve$1) {
+ var _then = getThen(entry);
+
+ if (_then === then && entry._state !== PENDING) {
+ this._settledAt(entry._state, i, entry._result);
+ } else if (typeof _then !== 'function') {
+ this._remaining--;
+ this._result[i] = entry;
+ } else if (c === Promise$2) {
+ var promise = new c(noop);
+ handleMaybeThenable(promise, entry, _then);
+ this._willSettleAt(promise, i);
+ } else {
+ this._willSettleAt(new c(function (resolve$$1) {
+ return resolve$$1(entry);
+ }), i);
+ }
+ } else {
+ this._willSettleAt(resolve$$1(entry), i);
+ }
+ }
+ }, {
+ key: '_settledAt',
+ value: function _settledAt(state, i, value) {
+ var promise = this.promise;
+
+
+ if (promise._state === PENDING) {
+ this._remaining--;
+
+ if (state === REJECTED) {
+ reject(promise, value);
+ } else {
+ this._result[i] = value;
+ }
+ }
+
+ if (this._remaining === 0) {
+ fulfill(promise, this._result);
+ }
+ }
+ }, {
+ key: '_willSettleAt',
+ value: function _willSettleAt(promise, i) {
+ var enumerator = this;
+
+ subscribe(promise, undefined, function (value) {
+ return enumerator._settledAt(FULFILLED, i, value);
+ }, function (reason) {
+ return enumerator._settledAt(REJECTED, i, reason);
+ });
+ }
+ }]);
+ return Enumerator;
+ }();
+
+ /**
+ `Promise.all` accepts an array of promises, and returns a new promise which
+ is fulfilled with an array of fulfillment values for the passed promises, or
+ rejected with the reason of the first passed promise to be rejected. It casts all
+ elements of the passed iterable to promises as it runs this algorithm.
+
+ Example:
+
+ ```javascript
+ let promise1 = resolve(1);
+ let promise2 = resolve(2);
+ let promise3 = resolve(3);
+ let promises = [ promise1, promise2, promise3 ];
+
+ Promise.all(promises).then(function(array){
+ // The array here would be [ 1, 2, 3 ];
+ });
+ ```
+
+ If any of the `promises` given to `all` are rejected, the first promise
+ that is rejected will be given as an argument to the returned promises's
+ rejection handler. For example:
+
+ Example:
+
+ ```javascript
+ let promise1 = resolve(1);
+ let promise2 = reject(new Error("2"));
+ let promise3 = reject(new Error("3"));
+ let promises = [ promise1, promise2, promise3 ];
+
+ Promise.all(promises).then(function(array){
+ // Code here never runs because there are rejected promises!
+ }, function(error) {
+ // error.message === "2"
+ });
+ ```
+
+ @method all
+ @static
+ @param {Array} entries array of promises
+ @param {String} label optional string for labeling the promise.
+ Useful for tooling.
+ @return {Promise} promise that is fulfilled when all `promises` have been
+ fulfilled, or rejected if any of them become rejected.
+ @static
+ */
+ function all(entries) {
+ return new Enumerator(this, entries).promise;
+ }
+
+ /**
+ `Promise.race` returns a new promise which is settled in the same way as the
+ first passed promise to settle.
+
+ Example:
+
+ ```javascript
+ let promise1 = new Promise(function(resolve, reject){
+ setTimeout(function(){
+ resolve('promise 1');
+ }, 200);
+ });
+
+ let promise2 = new Promise(function(resolve, reject){
+ setTimeout(function(){
+ resolve('promise 2');
+ }, 100);
+ });
+
+ Promise.race([promise1, promise2]).then(function(result){
+ // result === 'promise 2' because it was resolved before promise1
+ // was resolved.
+ });
+ ```
+
+ `Promise.race` is deterministic in that only the state of the first
+ settled promise matters. For example, even if other promises given to the
+ `promises` array argument are resolved, but the first settled promise has
+ become rejected before the other promises became fulfilled, the returned
+ promise will become rejected:
+
+ ```javascript
+ let promise1 = new Promise(function(resolve, reject){
+ setTimeout(function(){
+ resolve('promise 1');
+ }, 200);
+ });
+
+ let promise2 = new Promise(function(resolve, reject){
+ setTimeout(function(){
+ reject(new Error('promise 2'));
+ }, 100);
+ });
+
+ Promise.race([promise1, promise2]).then(function(result){
+ // Code here never runs
+ }, function(reason){
+ // reason.message === 'promise 2' because promise 2 became rejected before
+ // promise 1 became fulfilled
+ });
+ ```
+
+ An example real-world use case is implementing timeouts:
+
+ ```javascript
+ Promise.race([ajax('foo.json'), timeout(5000)])
+ ```
+
+ @method race
+ @static
+ @param {Array} promises array of promises to observe
+ Useful for tooling.
+ @return {Promise} a promise which settles in the same way as the first passed
+ promise to settle.
+ */
+ function race(entries) {
+ /*jshint validthis:true */
+ var Constructor = this;
+
+ if (!isArray(entries)) {
+ return new Constructor(function (_, reject) {
+ return reject(new TypeError('You must pass an array to race.'));
+ });
+ } else {
+ return new Constructor(function (resolve, reject) {
+ var length = entries.length;
+ for (var i = 0; i < length; i++) {
+ Constructor.resolve(entries[i]).then(resolve, reject);
+ }
+ });
+ }
+ }
+
+ /**
+ `Promise.reject` returns a promise rejected with the passed `reason`.
+ It is shorthand for the following:
+
+ ```javascript
+ let promise = new Promise(function(resolve, reject){
+ reject(new Error('WHOOPS'));
+ });
+
+ promise.then(function(value){
+ // Code here doesn't run because the promise is rejected!
+ }, function(reason){
+ // reason.message === 'WHOOPS'
+ });
+ ```
+
+ Instead of writing the above, your code now simply becomes the following:
+
+ ```javascript
+ let promise = Promise.reject(new Error('WHOOPS'));
+
+ promise.then(function(value){
+ // Code here doesn't run because the promise is rejected!
+ }, function(reason){
+ // reason.message === 'WHOOPS'
+ });
+ ```
+
+ @method reject
+ @static
+ @param {Any} reason value that the returned promise will be rejected with.
+ Useful for tooling.
+ @return {Promise} a promise rejected with the given `reason`.
+ */
+ function reject$1(reason) {
+ /*jshint validthis:true */
+ var Constructor = this;
+ var promise = new Constructor(noop);
+ reject(promise, reason);
+ return promise;
+ }
+
+ function needsResolver() {
+ throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
+ }
+
+ function needsNew() {
+ throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
+ }
+
+ /**
+ Promise objects represent the eventual result of an asynchronous operation. The
+ primary way of interacting with a promise is through its `then` method, which
+ registers callbacks to receive either a promise's eventual value or the reason
+ why the promise cannot be fulfilled.
+
+ Terminology
+ -----------
+
+ - `promise` is an object or function with a `then` method whose behavior conforms to this specification.
+ - `thenable` is an object or function that defines a `then` method.
+ - `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
+ - `exception` is a value that is thrown using the throw statement.
+ - `reason` is a value that indicates why a promise was rejected.
+ - `settled` the final resting state of a promise, fulfilled or rejected.
+
+ A promise can be in one of three states: pending, fulfilled, or rejected.
+
+ Promises that are fulfilled have a fulfillment value and are in the fulfilled
+ state. Promises that are rejected have a rejection reason and are in the
+ rejected state. A fulfillment value is never a thenable.
+
+ Promises can also be said to *resolve* a value. If this value is also a
+ promise, then the original promise's settled state will match the value's
+ settled state. So a promise that *resolves* a promise that rejects will
+ itself reject, and a promise that *resolves* a promise that fulfills will
+ itself fulfill.
+
+
+ Basic Usage:
+ ------------
+
+ ```js
+ let promise = new Promise(function(resolve, reject) {
+ // on success
+ resolve(value);
+
+ // on failure
+ reject(reason);
+ });
+
+ promise.then(function(value) {
+ // on fulfillment
+ }, function(reason) {
+ // on rejection
+ });
+ ```
+
+ Advanced Usage:
+ ---------------
+
+ Promises shine when abstracting away asynchronous interactions such as
+ `XMLHttpRequest`s.
+
+ ```js
+ function getJSON(url) {
+ return new Promise(function(resolve, reject){
+ let xhr = new XMLHttpRequest();
+
+ xhr.open('GET', url);
+ xhr.onreadystatechange = handler;
+ xhr.responseType = 'json';
+ xhr.setRequestHeader('Accept', 'application/json');
+ xhr.send();
+
+ function handler() {
+ if (this.readyState === this.DONE) {
+ if (this.status === 200) {
+ resolve(this.response);
+ } else {
+ reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
+ }
+ }
+ };
+ });
+ }
+
+ getJSON('/posts.json').then(function(json) {
+ // on fulfillment
+ }, function(reason) {
+ // on rejection
+ });
+ ```
+
+ Unlike callbacks, promises are great composable primitives.
+
+ ```js
+ Promise.all([
+ getJSON('/posts'),
+ getJSON('/comments')
+ ]).then(function(values){
+ values[0] // => postsJSON
+ values[1] // => commentsJSON
+
+ return values;
+ });
+ ```
+
+ @class Promise
+ @param {Function} resolver
+ Useful for tooling.
+ @constructor
+ */
+
+ var Promise$2 = function () {
+ function Promise(resolver) {
+ classCallCheck(this, Promise);
+
+ this[PROMISE_ID] = nextId();
+ this._result = this._state = undefined;
+ this._subscribers = [];
+
+ if (noop !== resolver) {
+ typeof resolver !== 'function' && needsResolver();
+ this instanceof Promise ? initializePromise(this, resolver) : needsNew();
+ }
+ }
+
+ /**
+ The primary way of interacting with a promise is through its `then` method,
+ which registers callbacks to receive either a promise's eventual value or the
+ reason why the promise cannot be fulfilled.
+ ```js
+ findUser().then(function(user){
+ // user is available
+ }, function(reason){
+ // user is unavailable, and you are given the reason why
+ });
+ ```
+ Chaining
+ --------
+ The return value of `then` is itself a promise. This second, 'downstream'
+ promise is resolved with the return value of the first promise's fulfillment
+ or rejection handler, or rejected if the handler throws an exception.
+ ```js
+ findUser().then(function (user) {
+ return user.name;
+ }, function (reason) {
+ return 'default name';
+ }).then(function (userName) {
+ // If `findUser` fulfilled, `userName` will be the user's name, otherwise it
+ // will be `'default name'`
+ });
+ findUser().then(function (user) {
+ throw new Error('Found user, but still unhappy');
+ }, function (reason) {
+ throw new Error('`findUser` rejected and we're unhappy');
+ }).then(function (value) {
+ // never reached
+ }, function (reason) {
+ // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
+ // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
+ });
+ ```
+ If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
+ ```js
+ findUser().then(function (user) {
+ throw new PedagogicalException('Upstream error');
+ }).then(function (value) {
+ // never reached
+ }).then(function (value) {
+ // never reached
+ }, function (reason) {
+ // The `PedgagocialException` is propagated all the way down to here
+ });
+ ```
+ Assimilation
+ ------------
+ Sometimes the value you want to propagate to a downstream promise can only be
+ retrieved asynchronously. This can be achieved by returning a promise in the
+ fulfillment or rejection handler. The downstream promise will then be pending
+ until the returned promise is settled. This is called *assimilation*.
+ ```js
+ findUser().then(function (user) {
+ return findCommentsByAuthor(user);
+ }).then(function (comments) {
+ // The user's comments are now available
+ });
+ ```
+ If the assimliated promise rejects, then the downstream promise will also reject.
+ ```js
+ findUser().then(function (user) {
+ return findCommentsByAuthor(user);
+ }).then(function (comments) {
+ // If `findCommentsByAuthor` fulfills, we'll have the value here
+ }, function (reason) {
+ // If `findCommentsByAuthor` rejects, we'll have the reason here
+ });
+ ```
+ Simple Example
+ --------------
+ Synchronous Example
+ ```javascript
+ let result;
+ try {
+ result = findResult();
+ // success
+ } catch(reason) {
+ // failure
+ }
+ ```
+ Errback Example
+ ```js
+ findResult(function(result, err){
+ if (err) {
+ // failure
+ } else {
+ // success
+ }
+ });
+ ```
+ Promise Example;
+ ```javascript
+ findResult().then(function(result){
+ // success
+ }, function(reason){
+ // failure
+ });
+ ```
+ Advanced Example
+ --------------
+ Synchronous Example
+ ```javascript
+ let author, books;
+ try {
+ author = findAuthor();
+ books = findBooksByAuthor(author);
+ // success
+ } catch(reason) {
+ // failure
+ }
+ ```
+ Errback Example
+ ```js
+ function foundBooks(books) {
+ }
+ function failure(reason) {
+ }
+ findAuthor(function(author, err){
+ if (err) {
+ failure(err);
+ // failure
+ } else {
+ try {
+ findBoooksByAuthor(author, function(books, err) {
+ if (err) {
+ failure(err);
+ } else {
+ try {
+ foundBooks(books);
+ } catch(reason) {
+ failure(reason);
+ }
+ }
+ });
+ } catch(error) {
+ failure(err);
+ }
+ // success
+ }
+ });
+ ```
+ Promise Example;
+ ```javascript
+ findAuthor().
+ then(findBooksByAuthor).
+ then(function(books){
+ // found books
+ }).catch(function(reason){
+ // something went wrong
+ });
+ ```
+ @method then
+ @param {Function} onFulfilled
+ @param {Function} onRejected
+ Useful for tooling.
+ @return {Promise}
+ */
+
+ /**
+ `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
+ as the catch block of a try/catch statement.
+ ```js
+ function findAuthor(){
+ throw new Error('couldn't find that author');
+ }
+ // synchronous
+ try {
+ findAuthor();
+ } catch(reason) {
+ // something went wrong
+ }
+ // async with promises
+ findAuthor().catch(function(reason){
+ // something went wrong
+ });
+ ```
+ @method catch
+ @param {Function} onRejection
+ Useful for tooling.
+ @return {Promise}
+ */
+
+
+ createClass(Promise, [{
+ key: 'catch',
+ value: function _catch(onRejection) {
+ return this.then(null, onRejection);
+ }
+
+ /**
+ `finally` will be invoked regardless of the promise's fate just as native
+ try/catch/finally behaves
+
+ Synchronous example:
+
+ ```js
+ findAuthor() {
+ if (Math.random() > 0.5) {
+ throw new Error();
+ }
+ return new Author();
+ }
+
+ try {
+ return findAuthor(); // succeed or fail
+ } catch(error) {
+ return findOtherAuther();
+ } finally {
+ // always runs
+ // doesn't affect the return value
+ }
+ ```
+
+ Asynchronous example:
+
+ ```js
+ findAuthor().catch(function(reason){
+ return findOtherAuther();
+ }).finally(function(){
+ // author was either found, or not
+ });
+ ```
+
+ @method finally
+ @param {Function} callback
+ @return {Promise}
+ */
+
+ }, {
+ key: 'finally',
+ value: function _finally(callback) {
+ var promise = this;
+ var constructor = promise.constructor;
+
+ if (isFunction(callback)) {
+ return promise.then(function (value) {
+ return constructor.resolve(callback()).then(function () {
+ return value;
+ });
+ }, function (reason) {
+ return constructor.resolve(callback()).then(function () {
+ throw reason;
+ });
+ });
+ }
+
+ return promise.then(callback, callback);
+ }
+ }]);
+ return Promise;
+ }();
+
+ Promise$2.prototype.then = then;
+ Promise$2.all = all;
+ Promise$2.race = race;
+ Promise$2.resolve = resolve$1;
+ Promise$2.reject = reject$1;
+ Promise$2._setScheduler = setScheduler;
+ Promise$2._setAsap = setAsap;
+ Promise$2._asap = asap;
+
+ /*global self*/
+ function polyfill() {
+ var local = void 0;
+
+ if (typeof global !== 'undefined') {
+ local = global;
+ } else if (typeof self !== 'undefined') {
+ local = self;
+ } else {
+ try {
+ local = Function('return this')();
+ } catch (e) {
+ throw new Error('polyfill failed because global object is unavailable in this environment');
+ }
+ }
+
+ var P = local.Promise;
+
+ if (P) {
+ var promiseToString = null;
+ try {
+ promiseToString = Object.prototype.toString.call(P.resolve());
+ } catch (e) {
+ // silently ignored
+ }
+
+ if (promiseToString === '[object Promise]' && !P.cast) {
+ return;
+ }
+ }
+
+ local.Promise = Promise$2;
+ }
+
+ // Strange compat..
+ Promise$2.polyfill = polyfill;
+ Promise$2.Promise = Promise$2;
+
+ var Promise$1 = typeof Promise !== "undefined" ? Promise : Promise$2;
+
+ // Register logging callbacks
+ function registerLoggingCallbacks(obj) {
+ var i,
+ l,
+ key,
+ callbackNames = ["begin", "done", "log", "testStart", "testDone", "moduleStart", "moduleDone"];
+
+ function registerLoggingCallback(key) {
+ var loggingCallback = function loggingCallback(callback) {
+ if (objectType(callback) !== "function") {
+ throw new Error("QUnit logging methods require a callback function as their first parameters.");
+ }
+
+ config.callbacks[key].push(callback);
+ };
+
+ return loggingCallback;
+ }
+
+ for (i = 0, l = callbackNames.length; i < l; i++) {
+ key = callbackNames[i];
+
+ // Initialize key collection of logging callback
+ if (objectType(config.callbacks[key]) === "undefined") {
+ config.callbacks[key] = [];
+ }
+
+ obj[key] = registerLoggingCallback(key);
+ }
+ }
+
+ function runLoggingCallbacks(key, args) {
+ var callbacks = config.callbacks[key];
+
+ // Handling 'log' callbacks separately. Unlike the other callbacks,
+ // the log callback is not controlled by the processing queue,
+ // but rather used by asserts. Hence to promisfy the 'log' callback
+ // would mean promisfying each step of a test
+ if (key === "log") {
+ callbacks.map(function (callback) {
+ return callback(args);
+ });
+ return;
+ }
+
+ // ensure that each callback is executed serially
+ return callbacks.reduce(function (promiseChain, callback) {
+ return promiseChain.then(function () {
+ return Promise$1.resolve(callback(args));
+ });
+ }, Promise$1.resolve([]));
+ }
+
+ // Doesn't support IE9, it will return undefined on these browsers
+ // See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
+ var fileName = (sourceFromStacktrace(0) || "").replace(/(:\d+)+\)?/, "").replace(/.+\//, "");
+
+ function extractStacktrace(e, offset) {
+ offset = offset === undefined ? 4 : offset;
+
+ var stack, include, i;
+
+ if (e && e.stack) {
+ stack = e.stack.split("\n");
+ if (/^error$/i.test(stack[0])) {
+ stack.shift();
+ }
+ if (fileName) {
+ include = [];
+ for (i = offset; i < stack.length; i++) {
+ if (stack[i].indexOf(fileName) !== -1) {
+ break;
+ }
+ include.push(stack[i]);
+ }
+ if (include.length) {
+ return include.join("\n");
+ }
+ }
+ return stack[offset];
+ }
+ }
+
+ function sourceFromStacktrace(offset) {
+ var error = new Error();
+
+ // Support: Safari <=7 only, IE <=10 - 11 only
+ // Not all browsers generate the `stack` property for `new Error()`, see also #636
+ if (!error.stack) {
+ try {
+ throw error;
+ } catch (err) {
+ error = err;
+ }
+ }
+
+ return extractStacktrace(error, offset);
+ }
+
+ var priorityCount = 0;
+ var unitSampler = void 0;
+
+ // This is a queue of functions that are tasks within a single test.
+ // After tests are dequeued from config.queue they are expanded into
+ // a set of tasks in this queue.
+ var taskQueue = [];
+
+ /**
+ * Advances the taskQueue to the next task. If the taskQueue is empty,
+ * process the testQueue
+ */
+ function advance() {
+ advanceTaskQueue();
+
+ if (!taskQueue.length && !config.blocking && !config.current) {
+ advanceTestQueue();
+ }
+ }
+
+ /**
+ * Advances the taskQueue with an increased depth
+ */
+ function advanceTaskQueue() {
+ var start = now();
+ config.depth = (config.depth || 0) + 1;
+
+ processTaskQueue(start);
+
+ config.depth--;
+ }
+
+ /**
+ * Process the first task on the taskQueue as a promise.
+ * Each task is a function returned by https://github.com/qunitjs/qunit/blob/master/src/test.js#L381
+ */
+ function processTaskQueue(start) {
+ if (taskQueue.length && !config.blocking) {
+ var elapsedTime = now() - start;
+
+ if (!defined.setTimeout || config.updateRate <= 0 || elapsedTime < config.updateRate) {
+ var task = taskQueue.shift();
+ Promise$1.resolve(task()).then(function () {
+ if (!taskQueue.length) {
+ advance();
+ } else {
+ processTaskQueue(start);
+ }
+ });
+ } else {
+ setTimeout$1(advance);
+ }
+ }
+ }
+
+ /**
+ * Advance the testQueue to the next test to process. Call done() if testQueue completes.
+ */
+ function advanceTestQueue() {
+ if (!config.blocking && !config.queue.length && config.depth === 0) {
+ done();
+ return;
+ }
+
+ var testTasks = config.queue.shift();
+ addToTaskQueue(testTasks());
+
+ if (priorityCount > 0) {
+ priorityCount--;
+ }
+
+ advance();
+ }
+
+ /**
+ * Enqueue the tasks for a test into the task queue.
+ * @param {Array} tasksArray
+ */
+ function addToTaskQueue(tasksArray) {
+ taskQueue.push.apply(taskQueue, toConsumableArray(tasksArray));
+ }
+
+ /**
+ * Return the number of tasks remaining in the task queue to be processed.
+ * @return {Number}
+ */
+ function taskQueueLength() {
+ return taskQueue.length;
+ }
+
+ /**
+ * Adds a test to the TestQueue for execution.
+ * @param {Function} testTasksFunc
+ * @param {Boolean} prioritize
+ * @param {String} seed
+ */
+ function addToTestQueue(testTasksFunc, prioritize, seed) {
+ if (prioritize) {
+ config.queue.splice(priorityCount++, 0, testTasksFunc);
+ } else if (seed) {
+ if (!unitSampler) {
+ unitSampler = unitSamplerGenerator(seed);
+ }
+
+ // Insert into a random position after all prioritized items
+ var index = Math.floor(unitSampler() * (config.queue.length - priorityCount + 1));
+ config.queue.splice(priorityCount + index, 0, testTasksFunc);
+ } else {
+ config.queue.push(testTasksFunc);
+ }
+ }
+
+ /**
+ * Creates a seeded "sample" generator which is used for randomizing tests.
+ */
+ function unitSamplerGenerator(seed) {
+
+ // 32-bit xorshift, requires only a nonzero seed
+ // http://excamera.com/sphinx/article-xorshift.html
+ var sample = parseInt(generateHash(seed), 16) || -1;
+ return function () {
+ sample ^= sample << 13;
+ sample ^= sample >>> 17;
+ sample ^= sample << 5;
+
+ // ECMAScript has no unsigned number type
+ if (sample < 0) {
+ sample += 0x100000000;
+ }
+
+ return sample / 0x100000000;
+ };
+ }
+
+ /**
+ * This function is called when the ProcessingQueue is done processing all
+ * items. It handles emitting the final run events.
+ */
+ function done() {
+ var storage = config.storage;
+
+ ProcessingQueue.finished = true;
+
+ var runtime = now() - config.started;
+ var passed = config.stats.all - config.stats.bad;
+
+ if (config.stats.all === 0) {
+
+ if (config.filter && config.filter.length) {
+ throw new Error("No tests matched the filter \"" + config.filter + "\".");
+ }
+
+ if (config.module && config.module.length) {
+ throw new Error("No tests matched the module \"" + config.module + "\".");
+ }
+
+ if (config.moduleId && config.moduleId.length) {
+ throw new Error("No tests matched the moduleId \"" + config.moduleId + "\".");
+ }
+
+ if (config.testId && config.testId.length) {
+ throw new Error("No tests matched the testId \"" + config.testId + "\".");
+ }
+
+ throw new Error("No tests were run.");
+ }
+
+ emit("runEnd", globalSuite.end(true));
+ runLoggingCallbacks("done", {
+ passed: passed,
+ failed: config.stats.bad,
+ total: config.stats.all,
+ runtime: runtime
+ }).then(function () {
+
+ // Clear own storage items if all tests passed
+ if (storage && config.stats.bad === 0) {
+ for (var i = storage.length - 1; i >= 0; i--) {
+ var key = storage.key(i);
+
+ if (key.indexOf("qunit-test-") === 0) {
+ storage.removeItem(key);
+ }
+ }
+ }
+ });
+ }
+
+ var ProcessingQueue = {
+ finished: false,
+ add: addToTestQueue,
+ advance: advance,
+ taskCount: taskQueueLength
+ };
+
+ var TestReport = function () {
+ function TestReport(name, suite, options) {
+ classCallCheck(this, TestReport);
+
+ this.name = name;
+ this.suiteName = suite.name;
+ this.fullName = suite.fullName.concat(name);
+ this.runtime = 0;
+ this.assertions = [];
+
+ this.skipped = !!options.skip;
+ this.todo = !!options.todo;
+
+ this.valid = options.valid;
+
+ this._startTime = 0;
+ this._endTime = 0;
+
+ suite.pushTest(this);
+ }
+
+ createClass(TestReport, [{
+ key: "start",
+ value: function start(recordTime) {
+ if (recordTime) {
+ this._startTime = performanceNow();
+ if (performance) {
+ performance.mark("qunit_test_start");
+ }
+ }
+
+ return {
+ name: this.name,
+ suiteName: this.suiteName,
+ fullName: this.fullName.slice()
+ };
+ }
+ }, {
+ key: "end",
+ value: function end(recordTime) {
+ if (recordTime) {
+ this._endTime = performanceNow();
+ if (performance) {
+ performance.mark("qunit_test_end");
+
+ var testName = this.fullName.join(" – ");
+
+ measure("QUnit Test: " + testName, "qunit_test_start", "qunit_test_end");
+ }
+ }
+
+ return extend(this.start(), {
+ runtime: this.getRuntime(),
+ status: this.getStatus(),
+ errors: this.getFailedAssertions(),
+ assertions: this.getAssertions()
+ });
+ }
+ }, {
+ key: "pushAssertion",
+ value: function pushAssertion(assertion) {
+ this.assertions.push(assertion);
+ }
+ }, {
+ key: "getRuntime",
+ value: function getRuntime() {
+ return this._endTime - this._startTime;
+ }
+ }, {
+ key: "getStatus",
+ value: function getStatus() {
+ if (this.skipped) {
+ return "skipped";
+ }
+
+ var testPassed = this.getFailedAssertions().length > 0 ? this.todo : !this.todo;
+
+ if (!testPassed) {
+ return "failed";
+ } else if (this.todo) {
+ return "todo";
+ } else {
+ return "passed";
+ }
+ }
+ }, {
+ key: "getFailedAssertions",
+ value: function getFailedAssertions() {
+ return this.assertions.filter(function (assertion) {
+ return !assertion.passed;
+ });
+ }
+ }, {
+ key: "getAssertions",
+ value: function getAssertions() {
+ return this.assertions.slice();
+ }
+
+ // Remove actual and expected values from assertions. This is to prevent
+ // leaking memory throughout a test suite.
+
+ }, {
+ key: "slimAssertions",
+ value: function slimAssertions() {
+ this.assertions = this.assertions.map(function (assertion) {
+ delete assertion.actual;
+ delete assertion.expected;
+ return assertion;
+ });
+ }
+ }]);
+ return TestReport;
+ }();
+
+ var focused$1 = false;
+
+ function Test(settings) {
+ var i, l;
+
+ ++Test.count;
+
+ this.expected = null;
+ this.assertions = [];
+ this.semaphore = 0;
+ this.module = config.currentModule;
+ this.stack = sourceFromStacktrace(3);
+ this.steps = [];
+ this.timeout = undefined;
+
+ // If a module is skipped, all its tests and the tests of the child suites
+ // should be treated as skipped even if they are defined as `only` or `todo`.
+ // As for `todo` module, all its tests will be treated as `todo` except for
+ // tests defined as `skip` which will be left intact.
+ //
+ // So, if a test is defined as `todo` and is inside a skipped module, we should
+ // then treat that test as if was defined as `skip`.
+ if (this.module.skip) {
+ settings.skip = true;
+ settings.todo = false;
+
+ // Skipped tests should be left intact
+ } else if (this.module.todo && !settings.skip) {
+ settings.todo = true;
+ }
+
+ extend(this, settings);
+
+ this.testReport = new TestReport(settings.testName, this.module.suiteReport, {
+ todo: settings.todo,
+ skip: settings.skip,
+ valid: this.valid()
+ });
+
+ // Register unique strings
+ for (i = 0, l = this.module.tests; i < l.length; i++) {
+ if (this.module.tests[i].name === this.testName) {
+ this.testName += " ";
+ }
+ }
+
+ this.testId = generateHash(this.module.name, this.testName);
+
+ this.module.tests.push({
+ name: this.testName,
+ testId: this.testId,
+ skip: !!settings.skip
+ });
+
+ if (settings.skip) {
+
+ // Skipped tests will fully ignore any sent callback
+ this.callback = function () {};
+ this.async = false;
+ this.expected = 0;
+ } else {
+ if (typeof this.callback !== "function") {
+ var method = this.todo ? "todo" : "test";
+
+ // eslint-disable-next-line max-len
+ throw new TypeError("You must provide a function as a test callback to QUnit." + method + "(\"" + settings.testName + "\")");
+ }
+
+ this.assert = new Assert(this);
+ }
+ }
+
+ Test.count = 0;
+
+ function getNotStartedModules(startModule) {
+ var module = startModule,
+ modules = [];
+
+ while (module && module.testsRun === 0) {
+ modules.push(module);
+ module = module.parentModule;
+ }
+
+ // The above push modules from the child to the parent
+ // return a reversed order with the top being the top most parent module
+ return modules.reverse();
+ }
+
+ Test.prototype = {
+ before: function before() {
+ var _this = this;
+
+ var module = this.module,
+ notStartedModules = getNotStartedModules(module);
+
+ // ensure the callbacks are executed serially for each module
+ var callbackPromises = notStartedModules.reduce(function (promiseChain, startModule) {
+ return promiseChain.then(function () {
+ startModule.stats = { all: 0, bad: 0, started: now() };
+ emit("suiteStart", startModule.suiteReport.start(true));
+ return runLoggingCallbacks("moduleStart", {
+ name: startModule.name,
+ tests: startModule.tests
+ });
+ });
+ }, Promise$1.resolve([]));
+
+ return callbackPromises.then(function () {
+ config.current = _this;
+
+ _this.testEnvironment = extend({}, module.testEnvironment);
+
+ _this.started = now();
+ emit("testStart", _this.testReport.start(true));
+ return runLoggingCallbacks("testStart", {
+ name: _this.testName,
+ module: module.name,
+ testId: _this.testId,
+ previousFailure: _this.previousFailure
+ }).then(function () {
+ if (!config.pollution) {
+ saveGlobal();
+ }
+ });
+ });
+ },
+
+ run: function run() {
+ var promise;
+
+ config.current = this;
+
+ this.callbackStarted = now();
+
+ if (config.notrycatch) {
+ runTest(this);
+ return;
+ }
+
+ try {
+ runTest(this);
+ } catch (e) {
+ this.pushFailure("Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + (e.message || e), extractStacktrace(e, 0));
+
+ // Else next test will carry the responsibility
+ saveGlobal();
+
+ // Restart the tests if they're blocking
+ if (config.blocking) {
+ internalRecover(this);
+ }
+ }
+
+ function runTest(test) {
+ promise = test.callback.call(test.testEnvironment, test.assert);
+ test.resolvePromise(promise);
+
+ // If the test has a "lock" on it, but the timeout is 0, then we push a
+ // failure as the test should be synchronous.
+ if (test.timeout === 0 && test.semaphore !== 0) {
+ pushFailure("Test did not finish synchronously even though assert.timeout( 0 ) was used.", sourceFromStacktrace(2));
+ }
+ }
+ },
+
+ after: function after() {
+ checkPollution();
+ },
+
+ queueHook: function queueHook(hook, hookName, hookOwner) {
+ var _this2 = this;
+
+ var callHook = function callHook() {
+ var promise = hook.call(_this2.testEnvironment, _this2.assert);
+ _this2.resolvePromise(promise, hookName);
+ };
+
+ var runHook = function runHook() {
+ if (hookName === "before") {
+ if (hookOwner.unskippedTestsRun !== 0) {
+ return;
+ }
+
+ _this2.preserveEnvironment = true;
+ }
+
+ // The 'after' hook should only execute when there are not tests left and
+ // when the 'after' and 'finish' tasks are the only tasks left to process
+ if (hookName === "after" && hookOwner.unskippedTestsRun !== numberOfUnskippedTests(hookOwner) - 1 && (config.queue.length > 0 || ProcessingQueue.taskCount() > 2)) {
+ return;
+ }
+
+ config.current = _this2;
+ if (config.notrycatch) {
+ callHook();
+ return;
+ }
+ try {
+ callHook();
+ } catch (error) {
+ _this2.pushFailure(hookName + " failed on " + _this2.testName + ": " + (error.message || error), extractStacktrace(error, 0));
+ }
+ };
+
+ return runHook;
+ },
+
+
+ // Currently only used for module level hooks, can be used to add global level ones
+ hooks: function hooks(handler) {
+ var hooks = [];
+
+ function processHooks(test, module) {
+ if (module.parentModule) {
+ processHooks(test, module.parentModule);
+ }
+
+ if (module.hooks[handler].length) {
+ for (var i = 0; i < module.hooks[handler].length; i++) {
+ hooks.push(test.queueHook(module.hooks[handler][i], handler, module));
+ }
+ }
+ }
+
+ // Hooks are ignored on skipped tests
+ if (!this.skip) {
+ processHooks(this, this.module);
+ }
+
+ return hooks;
+ },
+
+
+ finish: function finish() {
+ config.current = this;
+
+ // Release the test callback to ensure that anything referenced has been
+ // released to be garbage collected.
+ this.callback = undefined;
+
+ if (this.steps.length) {
+ var stepsList = this.steps.join(", ");
+ this.pushFailure("Expected assert.verifySteps() to be called before end of test " + ("after using assert.step(). Unverified steps: " + stepsList), this.stack);
+ }
+
+ if (config.requireExpects && this.expected === null) {
+ this.pushFailure("Expected number of assertions to be defined, but expect() was " + "not called.", this.stack);
+ } else if (this.expected !== null && this.expected !== this.assertions.length) {
+ this.pushFailure("Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack);
+ } else if (this.expected === null && !this.assertions.length) {
+ this.pushFailure("Expected at least one assertion, but none were run - call " + "expect(0) to accept zero assertions.", this.stack);
+ }
+
+ var i,
+ module = this.module,
+ moduleName = module.name,
+ testName = this.testName,
+ skipped = !!this.skip,
+ todo = !!this.todo,
+ bad = 0,
+ storage = config.storage;
+
+ this.runtime = now() - this.started;
+
+ config.stats.all += this.assertions.length;
+ module.stats.all += this.assertions.length;
+
+ for (i = 0; i < this.assertions.length; i++) {
+ if (!this.assertions[i].result) {
+ bad++;
+ config.stats.bad++;
+ module.stats.bad++;
+ }
+ }
+
+ notifyTestsRan(module, skipped);
+
+ // Store result when possible
+ if (storage) {
+ if (bad) {
+ storage.setItem("qunit-test-" + moduleName + "-" + testName, bad);
+ } else {
+ storage.removeItem("qunit-test-" + moduleName + "-" + testName);
+ }
+ }
+
+ // After emitting the js-reporters event we cleanup the assertion data to
+ // avoid leaking it. It is not used by the legacy testDone callbacks.
+ emit("testEnd", this.testReport.end(true));
+ this.testReport.slimAssertions();
+
+ return runLoggingCallbacks("testDone", {
+ name: testName,
+ module: moduleName,
+ skipped: skipped,
+ todo: todo,
+ failed: bad,
+ passed: this.assertions.length - bad,
+ total: this.assertions.length,
+ runtime: skipped ? 0 : this.runtime,
+
+ // HTML Reporter use
+ assertions: this.assertions,
+ testId: this.testId,
+
+ // Source of Test
+ source: this.stack
+ }).then(function () {
+ if (module.testsRun === numberOfTests(module)) {
+ var completedModules = [module];
+
+ // Check if the parent modules, iteratively, are done. If that the case,
+ // we emit the `suiteEnd` event and trigger `moduleDone` callback.
+ var parent = module.parentModule;
+ while (parent && parent.testsRun === numberOfTests(parent)) {
+ completedModules.push(parent);
+ parent = parent.parentModule;
+ }
+
+ return completedModules.reduce(function (promiseChain, completedModule) {
+ return promiseChain.then(function () {
+ return logSuiteEnd(completedModule);
+ });
+ }, Promise$1.resolve([]));
+ }
+ }).then(function () {
+ config.current = undefined;
+ });
+
+ function logSuiteEnd(module) {
+
+ // Reset `module.hooks` to ensure that anything referenced in these hooks
+ // has been released to be garbage collected.
+ module.hooks = {};
+
+ emit("suiteEnd", module.suiteReport.end(true));
+ return runLoggingCallbacks("moduleDone", {
+ name: module.name,
+ tests: module.tests,
+ failed: module.stats.bad,
+ passed: module.stats.all - module.stats.bad,
+ total: module.stats.all,
+ runtime: now() - module.stats.started
+ });
+ }
+ },
+
+ preserveTestEnvironment: function preserveTestEnvironment() {
+ if (this.preserveEnvironment) {
+ this.module.testEnvironment = this.testEnvironment;
+ this.testEnvironment = extend({}, this.module.testEnvironment);
+ }
+ },
+
+ queue: function queue() {
+ var test = this;
+
+ if (!this.valid()) {
+ return;
+ }
+
+ function runTest() {
+ return [function () {
+ return test.before();
+ }].concat(toConsumableArray(test.hooks("before")), [function () {
+ test.preserveTestEnvironment();
+ }], toConsumableArray(test.hooks("beforeEach")), [function () {
+ test.run();
+ }], toConsumableArray(test.hooks("afterEach").reverse()), toConsumableArray(test.hooks("after").reverse()), [function () {
+ test.after();
+ }, function () {
+ return test.finish();
+ }]);
+ }
+
+ var previousFailCount = config.storage && +config.storage.getItem("qunit-test-" + this.module.name + "-" + this.testName);
+
+ // Prioritize previously failed tests, detected from storage
+ var prioritize = config.reorder && !!previousFailCount;
+
+ this.previousFailure = !!previousFailCount;
+
+ ProcessingQueue.add(runTest, prioritize, config.seed);
+
+ // If the queue has already finished, we manually process the new test
+ if (ProcessingQueue.finished) {
+ ProcessingQueue.advance();
+ }
+ },
+
+
+ pushResult: function pushResult(resultInfo) {
+ if (this !== config.current) {
+ throw new Error("Assertion occurred after test had finished.");
+ }
+
+ // Destructure of resultInfo = { result, actual, expected, message, negative }
+ var source,
+ details = {
+ module: this.module.name,
+ name: this.testName,
+ result: resultInfo.result,
+ message: resultInfo.message,
+ actual: resultInfo.actual,
+ testId: this.testId,
+ negative: resultInfo.negative || false,
+ runtime: now() - this.started,
+ todo: !!this.todo
+ };
+
+ if (hasOwn.call(resultInfo, "expected")) {
+ details.expected = resultInfo.expected;
+ }
+
+ if (!resultInfo.result) {
+ source = resultInfo.source || sourceFromStacktrace();
+
+ if (source) {
+ details.source = source;
+ }
+ }
+
+ this.logAssertion(details);
+
+ this.assertions.push({
+ result: !!resultInfo.result,
+ message: resultInfo.message
+ });
+ },
+
+ pushFailure: function pushFailure(message, source, actual) {
+ if (!(this instanceof Test)) {
+ throw new Error("pushFailure() assertion outside test context, was " + sourceFromStacktrace(2));
+ }
+
+ this.pushResult({
+ result: false,
+ message: message || "error",
+ actual: actual || null,
+ source: source
+ });
+ },
+
+ /**
+ * Log assertion details using both the old QUnit.log interface and
+ * QUnit.on( "assertion" ) interface.
+ *
+ * @private
+ */
+ logAssertion: function logAssertion(details) {
+ runLoggingCallbacks("log", details);
+
+ var assertion = {
+ passed: details.result,
+ actual: details.actual,
+ expected: details.expected,
+ message: details.message,
+ stack: details.source,
+ todo: details.todo
+ };
+ this.testReport.pushAssertion(assertion);
+ emit("assertion", assertion);
+ },
+
+
+ resolvePromise: function resolvePromise(promise, phase) {
+ var then,
+ resume,
+ message,
+ test = this;
+ if (promise != null) {
+ then = promise.then;
+ if (objectType(then) === "function") {
+ resume = internalStop(test);
+ if (config.notrycatch) {
+ then.call(promise, function () {
+ resume();
+ });
+ } else {
+ then.call(promise, function () {
+ resume();
+ }, function (error) {
+ message = "Promise rejected " + (!phase ? "during" : phase.replace(/Each$/, "")) + " \"" + test.testName + "\": " + (error && error.message || error);
+ test.pushFailure(message, extractStacktrace(error, 0));
+
+ // Else next test will carry the responsibility
+ saveGlobal();
+
+ // Unblock
+ internalRecover(test);
+ });
+ }
+ }
+ }
+ },
+
+ valid: function valid() {
+ var filter = config.filter,
+ regexFilter = /^(!?)\/([\w\W]*)\/(i?$)/.exec(filter),
+ module = config.module && config.module.toLowerCase(),
+ fullName = this.module.name + ": " + this.testName;
+
+ function moduleChainNameMatch(testModule) {
+ var testModuleName = testModule.name ? testModule.name.toLowerCase() : null;
+ if (testModuleName === module) {
+ return true;
+ } else if (testModule.parentModule) {
+ return moduleChainNameMatch(testModule.parentModule);
+ } else {
+ return false;
+ }
+ }
+
+ function moduleChainIdMatch(testModule) {
+ return inArray(testModule.moduleId, config.moduleId) || testModule.parentModule && moduleChainIdMatch(testModule.parentModule);
+ }
+
+ // Internally-generated tests are always valid
+ if (this.callback && this.callback.validTest) {
+ return true;
+ }
+
+ if (config.moduleId && config.moduleId.length > 0 && !moduleChainIdMatch(this.module)) {
+
+ return false;
+ }
+
+ if (config.testId && config.testId.length > 0 && !inArray(this.testId, config.testId)) {
+
+ return false;
+ }
+
+ if (module && !moduleChainNameMatch(this.module)) {
+ return false;
+ }
+
+ if (!filter) {
+ return true;
+ }
+
+ return regexFilter ? this.regexFilter(!!regexFilter[1], regexFilter[2], regexFilter[3], fullName) : this.stringFilter(filter, fullName);
+ },
+
+ regexFilter: function regexFilter(exclude, pattern, flags, fullName) {
+ var regex = new RegExp(pattern, flags);
+ var match = regex.test(fullName);
+
+ return match !== exclude;
+ },
+
+ stringFilter: function stringFilter(filter, fullName) {
+ filter = filter.toLowerCase();
+ fullName = fullName.toLowerCase();
+
+ var include = filter.charAt(0) !== "!";
+ if (!include) {
+ filter = filter.slice(1);
+ }
+
+ // If the filter matches, we need to honour include
+ if (fullName.indexOf(filter) !== -1) {
+ return include;
+ }
+
+ // Otherwise, do the opposite
+ return !include;
+ }
+ };
+
+ function pushFailure() {
+ if (!config.current) {
+ throw new Error("pushFailure() assertion outside test context, in " + sourceFromStacktrace(2));
+ }
+
+ // Gets current test obj
+ var currentTest = config.current;
+
+ return currentTest.pushFailure.apply(currentTest, arguments);
+ }
+
+ function saveGlobal() {
+ config.pollution = [];
+
+ if (config.noglobals) {
+ for (var key in global$1) {
+ if (hasOwn.call(global$1, key)) {
+
+ // In Opera sometimes DOM element ids show up here, ignore them
+ if (/^qunit-test-output/.test(key)) {
+ continue;
+ }
+ config.pollution.push(key);
+ }
+ }
+ }
+ }
+
+ function checkPollution() {
+ var newGlobals,
+ deletedGlobals,
+ old = config.pollution;
+
+ saveGlobal();
+
+ newGlobals = diff(config.pollution, old);
+ if (newGlobals.length > 0) {
+ pushFailure("Introduced global variable(s): " + newGlobals.join(", "));
+ }
+
+ deletedGlobals = diff(old, config.pollution);
+ if (deletedGlobals.length > 0) {
+ pushFailure("Deleted global variable(s): " + deletedGlobals.join(", "));
+ }
+ }
+
+ // Will be exposed as QUnit.test
+ function test(testName, callback) {
+ if (focused$1) {
+ return;
+ }
+
+ var newTest = new Test({
+ testName: testName,
+ callback: callback
+ });
+
+ newTest.queue();
+ }
+
+ function todo(testName, callback) {
+ if (focused$1) {
+ return;
+ }
+
+ var newTest = new Test({
+ testName: testName,
+ callback: callback,
+ todo: true
+ });
+
+ newTest.queue();
+ }
+
+ // Will be exposed as QUnit.skip
+ function skip(testName) {
+ if (focused$1) {
+ return;
+ }
+
+ var test = new Test({
+ testName: testName,
+ skip: true
+ });
+
+ test.queue();
+ }
+
+ // Will be exposed as QUnit.only
+ function only(testName, callback) {
+ if (focused$1) {
+ return;
+ }
+
+ config.queue.length = 0;
+ focused$1 = true;
+
+ var newTest = new Test({
+ testName: testName,
+ callback: callback
+ });
+
+ newTest.queue();
+ }
+
+ // Put a hold on processing and return a function that will release it.
+ function internalStop(test) {
+ var released = false;
+ test.semaphore += 1;
+ config.blocking = true;
+
+ // Set a recovery timeout, if so configured.
+ if (defined.setTimeout) {
+ var timeoutDuration = void 0;
+
+ if (typeof test.timeout === "number") {
+ timeoutDuration = test.timeout;
+ } else if (typeof config.testTimeout === "number") {
+ timeoutDuration = config.testTimeout;
+ }
+
+ if (typeof timeoutDuration === "number" && timeoutDuration > 0) {
+ clearTimeout(config.timeout);
+ config.timeout = setTimeout$1(function () {
+ pushFailure("Test took longer than " + timeoutDuration + "ms; test timed out.", sourceFromStacktrace(2));
+ released = true;
+ internalRecover(test);
+ }, timeoutDuration);
+ }
+ }
+
+ return function resume() {
+ if (released) {
+ return;
+ }
+
+ released = true;
+ test.semaphore -= 1;
+ internalStart(test);
+ };
+ }
+
+ // Forcefully release all processing holds.
+ function internalRecover(test) {
+ test.semaphore = 0;
+ internalStart(test);
+ }
+
+ // Release a processing hold, scheduling a resumption attempt if no holds remain.
+ function internalStart(test) {
+
+ // If semaphore is non-numeric, throw error
+ if (isNaN(test.semaphore)) {
+ test.semaphore = 0;
+
+ pushFailure("Invalid value on test.semaphore", sourceFromStacktrace(2));
+ return;
+ }
+
+ // Don't start until equal number of stop-calls
+ if (test.semaphore > 0) {
+ return;
+ }
+
+ // Throw an Error if start is called more often than stop
+ if (test.semaphore < 0) {
+ test.semaphore = 0;
+
+ pushFailure("Tried to restart test while already started (test's semaphore was 0 already)", sourceFromStacktrace(2));
+ return;
+ }
+
+ // Add a slight delay to allow more assertions etc.
+ if (defined.setTimeout) {
+ if (config.timeout) {
+ clearTimeout(config.timeout);
+ }
+ config.timeout = setTimeout$1(function () {
+ if (test.semaphore > 0) {
+ return;
+ }
+
+ if (config.timeout) {
+ clearTimeout(config.timeout);
+ }
+
+ begin();
+ });
+ } else {
+ begin();
+ }
+ }
+
+ function collectTests(module) {
+ var tests = [].concat(module.tests);
+ var modules = [].concat(toConsumableArray(module.childModules));
+
+ // Do a breadth-first traversal of the child modules
+ while (modules.length) {
+ var nextModule = modules.shift();
+ tests.push.apply(tests, nextModule.tests);
+ modules.push.apply(modules, toConsumableArray(nextModule.childModules));
+ }
+
+ return tests;
+ }
+
+ function numberOfTests(module) {
+ return collectTests(module).length;
+ }
+
+ function numberOfUnskippedTests(module) {
+ return collectTests(module).filter(function (test) {
+ return !test.skip;
+ }).length;
+ }
+
+ function notifyTestsRan(module, skipped) {
+ module.testsRun++;
+ if (!skipped) {
+ module.unskippedTestsRun++;
+ }
+ while (module = module.parentModule) {
+ module.testsRun++;
+ if (!skipped) {
+ module.unskippedTestsRun++;
+ }
+ }
+ }
+
+ var Assert = function () {
+ function Assert(testContext) {
+ classCallCheck(this, Assert);
+
+ this.test = testContext;
+ }
+
+ // Assert helpers
+
+ createClass(Assert, [{
+ key: "timeout",
+ value: function timeout(duration) {
+ if (typeof duration !== "number") {
+ throw new Error("You must pass a number as the duration to assert.timeout");
+ }
+
+ this.test.timeout = duration;
+ }
+
+ // Documents a "step", which is a string value, in a test as a passing assertion
+
+ }, {
+ key: "step",
+ value: function step(message) {
+ var assertionMessage = message;
+ var result = !!message;
+
+ this.test.steps.push(message);
+
+ if (objectType(message) === "undefined" || message === "") {
+ assertionMessage = "You must provide a message to assert.step";
+ } else if (objectType(message) !== "string") {
+ assertionMessage = "You must provide a string value to assert.step";
+ result = false;
+ }
+
+ this.pushResult({
+ result: result,
+ message: assertionMessage
+ });
+ }
+
+ // Verifies the steps in a test match a given array of string values
+
+ }, {
+ key: "verifySteps",
+ value: function verifySteps(steps, message) {
+
+ // Since the steps array is just string values, we can clone with slice
+ var actualStepsClone = this.test.steps.slice();
+ this.deepEqual(actualStepsClone, steps, message);
+ this.test.steps.length = 0;
+ }
+
+ // Specify the number of expected assertions to guarantee that failed test
+ // (no assertions are run at all) don't slip through.
+
+ }, {
+ key: "expect",
+ value: function expect(asserts) {
+ if (arguments.length === 1) {
+ this.test.expected = asserts;
+ } else {
+ return this.test.expected;
+ }
+ }
+
+ // Put a hold on processing and return a function that will release it a maximum of once.
+
+ }, {
+ key: "async",
+ value: function async(count) {
+ var test$$1 = this.test;
+
+ var popped = false,
+ acceptCallCount = count;
+
+ if (typeof acceptCallCount === "undefined") {
+ acceptCallCount = 1;
+ }
+
+ var resume = internalStop(test$$1);
+
+ return function done() {
+ if (config.current !== test$$1) {
+ throw Error("assert.async callback called after test finished.");
+ }
+
+ if (popped) {
+ test$$1.pushFailure("Too many calls to the `assert.async` callback", sourceFromStacktrace(2));
+ return;
+ }
+
+ acceptCallCount -= 1;
+ if (acceptCallCount > 0) {
+ return;
+ }
+
+ popped = true;
+ resume();
+ };
+ }
+
+ // Exports test.push() to the user API
+ // Alias of pushResult.
+
+ }, {
+ key: "push",
+ value: function push(result, actual, expected, message, negative) {
+ Logger.warn("assert.push is deprecated and will be removed in QUnit 3.0." + " Please use assert.pushResult instead (https://api.qunitjs.com/assert/pushResult).");
+
+ var currentAssert = this instanceof Assert ? this : config.current.assert;
+ return currentAssert.pushResult({
+ result: result,
+ actual: actual,
+ expected: expected,
+ message: message,
+ negative: negative
+ });
+ }
+ }, {
+ key: "pushResult",
+ value: function pushResult(resultInfo) {
+
+ // Destructure of resultInfo = { result, actual, expected, message, negative }
+ var assert = this;
+ var currentTest = assert instanceof Assert && assert.test || config.current;
+
+ // Backwards compatibility fix.
+ // Allows the direct use of global exported assertions and QUnit.assert.*
+ // Although, it's use is not recommended as it can leak assertions
+ // to other tests from async tests, because we only get a reference to the current test,
+ // not exactly the test where assertion were intended to be called.
+ if (!currentTest) {
+ throw new Error("assertion outside test context, in " + sourceFromStacktrace(2));
+ }
+
+ if (!(assert instanceof Assert)) {
+ assert = currentTest.assert;
+ }
+
+ return assert.test.pushResult(resultInfo);
+ }
+ }, {
+ key: "ok",
+ value: function ok(result, message) {
+ if (!message) {
+ message = result ? "okay" : "failed, expected argument to be truthy, was: " + dump.parse(result);
+ }
+
+ this.pushResult({
+ result: !!result,
+ actual: result,
+ expected: true,
+ message: message
+ });
+ }
+ }, {
+ key: "notOk",
+ value: function notOk(result, message) {
+ if (!message) {
+ message = !result ? "okay" : "failed, expected argument to be falsy, was: " + dump.parse(result);
+ }
+
+ this.pushResult({
+ result: !result,
+ actual: result,
+ expected: false,
+ message: message
+ });
+ }
+ }, {
+ key: "equal",
+ value: function equal(actual, expected, message) {
+
+ // eslint-disable-next-line eqeqeq
+ var result = expected == actual;
+
+ this.pushResult({
+ result: result,
+ actual: actual,
+ expected: expected,
+ message: message
+ });
+ }
+ }, {
+ key: "notEqual",
+ value: function notEqual(actual, expected, message) {
+
+ // eslint-disable-next-line eqeqeq
+ var result = expected != actual;
+
+ this.pushResult({
+ result: result,
+ actual: actual,
+ expected: expected,
+ message: message,
+ negative: true
+ });
+ }
+ }, {
+ key: "propEqual",
+ value: function propEqual(actual, expected, message) {
+ actual = objectValues(actual);
+ expected = objectValues(expected);
+
+ this.pushResult({
+ result: equiv(actual, expected),
+ actual: actual,
+ expected: expected,
+ message: message
+ });
+ }
+ }, {
+ key: "notPropEqual",
+ value: function notPropEqual(actual, expected, message) {
+ actual = objectValues(actual);
+ expected = objectValues(expected);
+
+ this.pushResult({
+ result: !equiv(actual, expected),
+ actual: actual,
+ expected: expected,
+ message: message,
+ negative: true
+ });
+ }
+ }, {
+ key: "deepEqual",
+ value: function deepEqual(actual, expected, message) {
+ this.pushResult({
+ result: equiv(actual, expected),
+ actual: actual,
+ expected: expected,
+ message: message
+ });
+ }
+ }, {
+ key: "notDeepEqual",
+ value: function notDeepEqual(actual, expected, message) {
+ this.pushResult({
+ result: !equiv(actual, expected),
+ actual: actual,
+ expected: expected,
+ message: message,
+ negative: true
+ });
+ }
+ }, {
+ key: "strictEqual",
+ value: function strictEqual(actual, expected, message) {
+ this.pushResult({
+ result: expected === actual,
+ actual: actual,
+ expected: expected,
+ message: message
+ });
+ }
+ }, {
+ key: "notStrictEqual",
+ value: function notStrictEqual(actual, expected, message) {
+ this.pushResult({
+ result: expected !== actual,
+ actual: actual,
+ expected: expected,
+ message: message,
+ negative: true
+ });
+ }
+ }, {
+ key: "throws",
+ value: function throws(block, expected, message) {
+ var actual = void 0,
+ result = false;
+
+ var currentTest = this instanceof Assert && this.test || config.current;
+
+ // 'expected' is optional unless doing string comparison
+ if (objectType(expected) === "string") {
+ if (message == null) {
+ message = expected;
+ expected = null;
+ } else {
+ throw new Error("throws/raises does not accept a string value for the expected argument.\n" + "Use a non-string object value (e.g. regExp) instead if it's necessary.");
+ }
+ }
+
+ currentTest.ignoreGlobalErrors = true;
+ try {
+ block.call(currentTest.testEnvironment);
+ } catch (e) {
+ actual = e;
+ }
+ currentTest.ignoreGlobalErrors = false;
+
+ if (actual) {
+ var expectedType = objectType(expected);
+
+ // We don't want to validate thrown error
+ if (!expected) {
+ result = true;
+
+ // Expected is a regexp
+ } else if (expectedType === "regexp") {
+ result = expected.test(errorString(actual));
+
+ // Log the string form of the regexp
+ expected = String(expected);
+
+ // Expected is a constructor, maybe an Error constructor
+ } else if (expectedType === "function" && actual instanceof expected) {
+ result = true;
+
+ // Expected is an Error object
+ } else if (expectedType === "object") {
+ result = actual instanceof expected.constructor && actual.name === expected.name && actual.message === expected.message;
+
+ // Log the string form of the Error object
+ expected = errorString(expected);
+
+ // Expected is a validation function which returns true if validation passed
+ } else if (expectedType === "function" && expected.call({}, actual) === true) {
+ expected = null;
+ result = true;
+ }
+ }
+
+ currentTest.assert.pushResult({
+ result: result,
+
+ // undefined if it didn't throw
+ actual: actual && errorString(actual),
+ expected: expected,
+ message: message
+ });
+ }
+ }, {
+ key: "rejects",
+ value: function rejects(promise, expected, message) {
+ var result = false;
+
+ var currentTest = this instanceof Assert && this.test || config.current;
+
+ // 'expected' is optional unless doing string comparison
+ if (objectType(expected) === "string") {
+ if (message === undefined) {
+ message = expected;
+ expected = undefined;
+ } else {
+ message = "assert.rejects does not accept a string value for the expected " + "argument.\nUse a non-string object value (e.g. validator function) instead " + "if necessary.";
+
+ currentTest.assert.pushResult({
+ result: false,
+ message: message
+ });
+
+ return;
+ }
+ }
+
+ var then = promise && promise.then;
+ if (objectType(then) !== "function") {
+ var _message = "The value provided to `assert.rejects` in " + "\"" + currentTest.testName + "\" was not a promise.";
+
+ currentTest.assert.pushResult({
+ result: false,
+ message: _message,
+ actual: promise
+ });
+
+ return;
+ }
+
+ var done = this.async();
+
+ return then.call(promise, function handleFulfillment() {
+ var message = "The promise returned by the `assert.rejects` callback in " + "\"" + currentTest.testName + "\" did not reject.";
+
+ currentTest.assert.pushResult({
+ result: false,
+ message: message,
+ actual: promise
+ });
+
+ done();
+ }, function handleRejection(actual) {
+ var expectedType = objectType(expected);
+
+ // We don't want to validate
+ if (expected === undefined) {
+ result = true;
+
+ // Expected is a regexp
+ } else if (expectedType === "regexp") {
+ result = expected.test(errorString(actual));
+
+ // Log the string form of the regexp
+ expected = String(expected);
+
+ // Expected is a constructor, maybe an Error constructor
+ } else if (expectedType === "function" && actual instanceof expected) {
+ result = true;
+
+ // Expected is an Error object
+ } else if (expectedType === "object") {
+ result = actual instanceof expected.constructor && actual.name === expected.name && actual.message === expected.message;
+
+ // Log the string form of the Error object
+ expected = errorString(expected);
+
+ // Expected is a validation function which returns true if validation passed
+ } else {
+ if (expectedType === "function") {
+ result = expected.call({}, actual) === true;
+ expected = null;
+
+ // Expected is some other invalid type
+ } else {
+ result = false;
+ message = "invalid expected value provided to `assert.rejects` " + "callback in \"" + currentTest.testName + "\": " + expectedType + ".";
+ }
+ }
+
+ currentTest.assert.pushResult({
+ result: result,
+
+ // leave rejection value of undefined as-is
+ actual: actual && errorString(actual),
+ expected: expected,
+ message: message
+ });
+
+ done();
+ });
+ }
+ }]);
+ return Assert;
+ }();
+
+ // Provide an alternative to assert.throws(), for environments that consider throws a reserved word
+ // Known to us are: Closure Compiler, Narwhal
+ // eslint-disable-next-line dot-notation
+
+
+ Assert.prototype.raises = Assert.prototype["throws"];
+
+ /**
+ * Converts an error into a simple string for comparisons.
+ *
+ * @param {Error|Object} error
+ * @return {String}
+ */
+ function errorString(error) {
+ var resultErrorString = error.toString();
+
+ // If the error wasn't a subclass of Error but something like
+ // an object literal with name and message properties...
+ if (resultErrorString.substring(0, 7) === "[object") {
+ var name = error.name ? error.name.toString() : "Error";
+ var message = error.message ? error.message.toString() : "";
+
+ if (name && message) {
+ return name + ": " + message;
+ } else if (name) {
+ return name;
+ } else if (message) {
+ return message;
+ } else {
+ return "Error";
+ }
+ } else {
+ return resultErrorString;
+ }
+ }
+
+ /* global module, exports, define */
+ function exportQUnit(QUnit) {
+
+ if (defined.document) {
+
+ // QUnit may be defined when it is preconfigured but then only QUnit and QUnit.config may be defined.
+ if (window$1.QUnit && window$1.QUnit.version) {
+ throw new Error("QUnit has already been defined.");
+ }
+
+ window$1.QUnit = QUnit;
+ }
+
+ // For nodejs
+ if (typeof module !== "undefined" && module && module.exports) {
+ module.exports = QUnit;
+
+ // For consistency with CommonJS environments' exports
+ module.exports.QUnit = QUnit;
+ }
+
+ // For CommonJS with exports, but without module.exports, like Rhino
+ if (typeof exports !== "undefined" && exports) {
+ exports.QUnit = QUnit;
+ }
+
+ if (typeof define === "function" && define.amd) {
+ define(function () {
+ return QUnit;
+ });
+ QUnit.config.autostart = false;
+ }
+
+ // For Web/Service Workers
+ if (self$1 && self$1.WorkerGlobalScope && self$1 instanceof self$1.WorkerGlobalScope) {
+ self$1.QUnit = QUnit;
+ }
+ }
+
+ // Handle an unhandled exception. By convention, returns true if further
+ // error handling should be suppressed and false otherwise.
+ // In this case, we will only suppress further error handling if the
+ // "ignoreGlobalErrors" configuration option is enabled.
+ function onError(error) {
+ for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
+ args[_key - 1] = arguments[_key];
+ }
+
+ if (config.current) {
+ if (config.current.ignoreGlobalErrors) {
+ return true;
+ }
+ pushFailure.apply(undefined, [error.message, error.stacktrace || error.fileName + ":" + error.lineNumber].concat(args));
+ } else {
+ test("global failure", extend(function () {
+ pushFailure.apply(undefined, [error.message, error.stacktrace || error.fileName + ":" + error.lineNumber].concat(args));
+ }, { validTest: true }));
+ }
+
+ return false;
+ }
+
+ // Handle an unhandled rejection
+ function onUnhandledRejection(reason) {
+ var resultInfo = {
+ result: false,
+ message: reason.message || "error",
+ actual: reason,
+ source: reason.stack || sourceFromStacktrace(3)
+ };
+
+ var currentTest = config.current;
+ if (currentTest) {
+ currentTest.assert.pushResult(resultInfo);
+ } else {
+ test("global failure", extend(function (assert) {
+ assert.pushResult(resultInfo);
+ }, { validTest: true }));
+ }
+ }
+
+ var QUnit = {};
+ var globalSuite = new SuiteReport();
+
+ // The initial "currentModule" represents the global (or top-level) module that
+ // is not explicitly defined by the user, therefore we add the "globalSuite" to
+ // it since each module has a suiteReport associated with it.
+ config.currentModule.suiteReport = globalSuite;
+
+ var globalStartCalled = false;
+ var runStarted = false;
+
+ // Figure out if we're running the tests from a server or not
+ QUnit.isLocal = !(defined.document && window$1.location.protocol !== "file:");
+
+ // Expose the current QUnit version
+ QUnit.version = "2.9.2";
+
+ extend(QUnit, {
+ on: on,
+
+ module: module$1,
+
+ test: test,
+
+ todo: todo,
+
+ skip: skip,
+
+ only: only,
+
+ start: function start(count) {
+ var globalStartAlreadyCalled = globalStartCalled;
+
+ if (!config.current) {
+ globalStartCalled = true;
+
+ if (runStarted) {
+ throw new Error("Called start() while test already started running");
+ } else if (globalStartAlreadyCalled || count > 1) {
+ throw new Error("Called start() outside of a test context too many times");
+ } else if (config.autostart) {
+ throw new Error("Called start() outside of a test context when " + "QUnit.config.autostart was true");
+ } else if (!config.pageLoaded) {
+
+ // The page isn't completely loaded yet, so we set autostart and then
+ // load if we're in Node or wait for the browser's load event.
+ config.autostart = true;
+
+ // Starts from Node even if .load was not previously called. We still return
+ // early otherwise we'll wind up "beginning" twice.
+ if (!defined.document) {
+ QUnit.load();
+ }
+
+ return;
+ }
+ } else {
+ throw new Error("QUnit.start cannot be called inside a test context.");
+ }
+
+ scheduleBegin();
+ },
+
+ config: config,
+
+ is: is,
+
+ objectType: objectType,
+
+ extend: extend,
+
+ load: function load() {
+ config.pageLoaded = true;
+
+ // Initialize the configuration options
+ extend(config, {
+ stats: { all: 0, bad: 0 },
+ started: 0,
+ updateRate: 1000,
+ autostart: true,
+ filter: ""
+ }, true);
+
+ if (!runStarted) {
+ config.blocking = false;
+
+ if (config.autostart) {
+ scheduleBegin();
+ }
+ }
+ },
+
+ stack: function stack(offset) {
+ offset = (offset || 0) + 2;
+ return sourceFromStacktrace(offset);
+ },
+
+ onError: onError,
+
+ onUnhandledRejection: onUnhandledRejection
+ });
+
+ QUnit.pushFailure = pushFailure;
+ QUnit.assert = Assert.prototype;
+ QUnit.equiv = equiv;
+ QUnit.dump = dump;
+
+ registerLoggingCallbacks(QUnit);
+
+ function scheduleBegin() {
+
+ runStarted = true;
+
+ // Add a slight delay to allow definition of more modules and tests.
+ if (defined.setTimeout) {
+ setTimeout$1(function () {
+ begin();
+ });
+ } else {
+ begin();
+ }
+ }
+
+ function unblockAndAdvanceQueue() {
+ config.blocking = false;
+ ProcessingQueue.advance();
+ }
+
+ function begin() {
+ var i,
+ l,
+ modulesLog = [];
+
+ // If the test run hasn't officially begun yet
+ if (!config.started) {
+
+ // Record the time of the test run's beginning
+ config.started = now();
+
+ // Delete the loose unnamed module if unused.
+ if (config.modules[0].name === "" && config.modules[0].tests.length === 0) {
+ config.modules.shift();
+ }
+
+ // Avoid unnecessary information by not logging modules' test environments
+ for (i = 0, l = config.modules.length; i < l; i++) {
+ modulesLog.push({
+ name: config.modules[i].name,
+ tests: config.modules[i].tests
+ });
+ }
+
+ // The test run is officially beginning now
+ emit("runStart", globalSuite.start(true));
+ runLoggingCallbacks("begin", {
+ totalTests: Test.count,
+ modules: modulesLog
+ }).then(unblockAndAdvanceQueue);
+ } else {
+ unblockAndAdvanceQueue();
+ }
+ }
+
+ exportQUnit(QUnit);
+
+ (function () {
+
+ if (typeof window$1 === "undefined" || typeof document$1 === "undefined") {
+ return;
+ }
+
+ var config = QUnit.config,
+ hasOwn = Object.prototype.hasOwnProperty;
+
+ // Stores fixture HTML for resetting later
+ function storeFixture() {
+
+ // Avoid overwriting user-defined values
+ if (hasOwn.call(config, "fixture")) {
+ return;
+ }
+
+ var fixture = document$1.getElementById("qunit-fixture");
+ if (fixture) {
+ config.fixture = fixture.cloneNode(true);
+ }
+ }
+
+ QUnit.begin(storeFixture);
+
+ // Resets the fixture DOM element if available.
+ function resetFixture() {
+ if (config.fixture == null) {
+ return;
+ }
+
+ var fixture = document$1.getElementById("qunit-fixture");
+ var resetFixtureType = _typeof(config.fixture);
+ if (resetFixtureType === "string") {
+
+ // support user defined values for `config.fixture`
+ var newFixture = document$1.createElement("div");
+ newFixture.setAttribute("id", "qunit-fixture");
+ newFixture.innerHTML = config.fixture;
+ fixture.parentNode.replaceChild(newFixture, fixture);
+ } else {
+ var clonedFixture = config.fixture.cloneNode(true);
+ fixture.parentNode.replaceChild(clonedFixture, fixture);
+ }
+ }
+
+ QUnit.testStart(resetFixture);
+ })();
+
+ (function () {
+
+ // Only interact with URLs via window.location
+ var location = typeof window$1 !== "undefined" && window$1.location;
+ if (!location) {
+ return;
+ }
+
+ var urlParams = getUrlParams();
+
+ QUnit.urlParams = urlParams;
+
+ // Match module/test by inclusion in an array
+ QUnit.config.moduleId = [].concat(urlParams.moduleId || []);
+ QUnit.config.testId = [].concat(urlParams.testId || []);
+
+ // Exact case-insensitive match of the module name
+ QUnit.config.module = urlParams.module;
+
+ // Regular expression or case-insenstive substring match against "moduleName: testName"
+ QUnit.config.filter = urlParams.filter;
+
+ // Test order randomization
+ if (urlParams.seed === true) {
+
+ // Generate a random seed if the option is specified without a value
+ QUnit.config.seed = Math.random().toString(36).slice(2);
+ } else if (urlParams.seed) {
+ QUnit.config.seed = urlParams.seed;
+ }
+
+ // Add URL-parameter-mapped config values with UI form rendering data
+ QUnit.config.urlConfig.push({
+ id: "hidepassed",
+ label: "Hide passed tests",
+ tooltip: "Only show tests and assertions that fail. Stored as query-strings."
+ }, {
+ id: "noglobals",
+ label: "Check for Globals",
+ tooltip: "Enabling this will test if any test introduces new properties on the " + "global object (`window` in Browsers). Stored as query-strings."
+ }, {
+ id: "notrycatch",
+ label: "No try-catch",
+ tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging " + "exceptions in IE reasonable. Stored as query-strings."
+ });
+
+ QUnit.begin(function () {
+ var i,
+ option,
+ urlConfig = QUnit.config.urlConfig;
+
+ for (i = 0; i < urlConfig.length; i++) {
+
+ // Options can be either strings or objects with nonempty "id" properties
+ option = QUnit.config.urlConfig[i];
+ if (typeof option !== "string") {
+ option = option.id;
+ }
+
+ if (QUnit.config[option] === undefined) {
+ QUnit.config[option] = urlParams[option];
+ }
+ }
+ });
+
+ function getUrlParams() {
+ var i, param, name, value;
+ var urlParams = Object.create(null);
+ var params = location.search.slice(1).split("&");
+ var length = params.length;
+
+ for (i = 0; i < length; i++) {
+ if (params[i]) {
+ param = params[i].split("=");
+ name = decodeQueryParam(param[0]);
+
+ // Allow just a key to turn on a flag, e.g., test.html?noglobals
+ value = param.length === 1 || decodeQueryParam(param.slice(1).join("="));
+ if (name in urlParams) {
+ urlParams[name] = [].concat(urlParams[name], value);
+ } else {
+ urlParams[name] = value;
+ }
+ }
+ }
+
+ return urlParams;
+ }
+
+ function decodeQueryParam(param) {
+ return decodeURIComponent(param.replace(/\+/g, "%20"));
+ }
+ })();
+
+ var stats = {
+ passedTests: 0,
+ failedTests: 0,
+ skippedTests: 0,
+ todoTests: 0
+ };
+
+ // Escape text for attribute or text content.
+ function escapeText(s) {
+ if (!s) {
+ return "";
+ }
+ s = s + "";
+
+ // Both single quotes and double quotes (for attributes)
+ return s.replace(/['"<>&]/g, function (s) {
+ switch (s) {
+ case "'":
+ return "&#039;";
+ case "\"":
+ return "&quot;";
+ case "<":
+ return "&lt;";
+ case ">":
+ return "&gt;";
+ case "&":
+ return "&amp;";
+ }
+ });
+ }
+
+ (function () {
+
+ // Don't load the HTML Reporter on non-browser environments
+ if (typeof window$1 === "undefined" || !window$1.document) {
+ return;
+ }
+
+ var config = QUnit.config,
+ hiddenTests = [],
+ document = window$1.document,
+ collapseNext = false,
+ hasOwn = Object.prototype.hasOwnProperty,
+ unfilteredUrl = setUrl({ filter: undefined, module: undefined,
+ moduleId: undefined, testId: undefined }),
+ modulesList = [];
+
+ function addEvent(elem, type, fn) {
+ elem.addEventListener(type, fn, false);
+ }
+
+ function removeEvent(elem, type, fn) {
+ elem.removeEventListener(type, fn, false);
+ }
+
+ function addEvents(elems, type, fn) {
+ var i = elems.length;
+ while (i--) {
+ addEvent(elems[i], type, fn);
+ }
+ }
+
+ function hasClass(elem, name) {
+ return (" " + elem.className + " ").indexOf(" " + name + " ") >= 0;
+ }
+
+ function addClass(elem, name) {
+ if (!hasClass(elem, name)) {
+ elem.className += (elem.className ? " " : "") + name;
+ }
+ }
+
+ function toggleClass(elem, name, force) {
+ if (force || typeof force === "undefined" && !hasClass(elem, name)) {
+ addClass(elem, name);
+ } else {
+ removeClass(elem, name);
+ }
+ }
+
+ function removeClass(elem, name) {
+ var set = " " + elem.className + " ";
+
+ // Class name may appear multiple times
+ while (set.indexOf(" " + name + " ") >= 0) {
+ set = set.replace(" " + name + " ", " ");
+ }
+
+ // Trim for prettiness
+ elem.className = typeof set.trim === "function" ? set.trim() : set.replace(/^\s+|\s+$/g, "");
+ }
+
+ function id(name) {
+ return document.getElementById && document.getElementById(name);
+ }
+
+ function abortTests() {
+ var abortButton = id("qunit-abort-tests-button");
+ if (abortButton) {
+ abortButton.disabled = true;
+ abortButton.innerHTML = "Aborting...";
+ }
+ QUnit.config.queue.length = 0;
+ return false;
+ }
+
+ function interceptNavigation(ev) {
+ applyUrlParams();
+
+ if (ev && ev.preventDefault) {
+ ev.preventDefault();
+ }
+
+ return false;
+ }
+
+ function getUrlConfigHtml() {
+ var i,
+ j,
+ val,
+ escaped,
+ escapedTooltip,
+ selection = false,
+ urlConfig = config.urlConfig,
+ urlConfigHtml = "";
+
+ for (i = 0; i < urlConfig.length; i++) {
+
+ // Options can be either strings or objects with nonempty "id" properties
+ val = config.urlConfig[i];
+ if (typeof val === "string") {
+ val = {
+ id: val,
+ label: val
+ };
+ }
+
+ escaped = escapeText(val.id);
+ escapedTooltip = escapeText(val.tooltip);
+
+ if (!val.value || typeof val.value === "string") {
+ urlConfigHtml += "<label for='qunit-urlconfig-" + escaped + "' title='" + escapedTooltip + "'><input id='qunit-urlconfig-" + escaped + "' name='" + escaped + "' type='checkbox'" + (val.value ? " value='" + escapeText(val.value) + "'" : "") + (config[val.id] ? " checked='checked'" : "") + " title='" + escapedTooltip + "' />" + escapeText(val.label) + "</label>";
+ } else {
+ urlConfigHtml += "<label for='qunit-urlconfig-" + escaped + "' title='" + escapedTooltip + "'>" + val.label + ": </label><select id='qunit-urlconfig-" + escaped + "' name='" + escaped + "' title='" + escapedTooltip + "'><option></option>";
+
+ if (QUnit.is("array", val.value)) {
+ for (j = 0; j < val.value.length; j++) {
+ escaped = escapeText(val.value[j]);
+ urlConfigHtml += "<option value='" + escaped + "'" + (config[val.id] === val.value[j] ? (selection = true) && " selected='selected'" : "") + ">" + escaped + "</option>";
+ }
+ } else {
+ for (j in val.value) {
+ if (hasOwn.call(val.value, j)) {
+ urlConfigHtml += "<option value='" + escapeText(j) + "'" + (config[val.id] === j ? (selection = true) && " selected='selected'" : "") + ">" + escapeText(val.value[j]) + "</option>";
+ }
+ }
+ }
+ if (config[val.id] && !selection) {
+ escaped = escapeText(config[val.id]);
+ urlConfigHtml += "<option value='" + escaped + "' selected='selected' disabled='disabled'>" + escaped + "</option>";
+ }
+ urlConfigHtml += "</select>";
+ }
+ }
+
+ return urlConfigHtml;
+ }
+
+ // Handle "click" events on toolbar checkboxes and "change" for select menus.
+ // Updates the URL with the new state of `config.urlConfig` values.
+ function toolbarChanged() {
+ var updatedUrl,
+ value,
+ tests,
+ field = this,
+ params = {};
+
+ // Detect if field is a select menu or a checkbox
+ if ("selectedIndex" in field) {
+ value = field.options[field.selectedIndex].value || undefined;
+ } else {
+ value = field.checked ? field.defaultValue || true : undefined;
+ }
+
+ params[field.name] = value;
+ updatedUrl = setUrl(params);
+
+ // Check if we can apply the change without a page refresh
+ if ("hidepassed" === field.name && "replaceState" in window$1.history) {
+ QUnit.urlParams[field.name] = value;
+ config[field.name] = value || false;
+ tests = id("qunit-tests");
+ if (tests) {
+ var length = tests.children.length;
+ var children = tests.children;
+
+ if (field.checked) {
+ for (var i = 0; i < length; i++) {
+ var test = children[i];
+
+ if (test && test.className.indexOf("pass") > -1) {
+ hiddenTests.push(test);
+ }
+ }
+
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = hiddenTests[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var hiddenTest = _step.value;
+
+ tests.removeChild(hiddenTest);
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+ } else {
+ while ((test = hiddenTests.pop()) != null) {
+ tests.appendChild(test);
+ }
+ }
+ }
+ window$1.history.replaceState(null, "", updatedUrl);
+ } else {
+ window$1.location = updatedUrl;
+ }
+ }
+
+ function setUrl(params) {
+ var key,
+ arrValue,
+ i,
+ querystring = "?",
+ location = window$1.location;
+
+ params = QUnit.extend(QUnit.extend({}, QUnit.urlParams), params);
+
+ for (key in params) {
+
+ // Skip inherited or undefined properties
+ if (hasOwn.call(params, key) && params[key] !== undefined) {
+
+ // Output a parameter for each value of this key
+ // (but usually just one)
+ arrValue = [].concat(params[key]);
+ for (i = 0; i < arrValue.length; i++) {
+ querystring += encodeURIComponent(key);
+ if (arrValue[i] !== true) {
+ querystring += "=" + encodeURIComponent(arrValue[i]);
+ }
+ querystring += "&";
+ }
+ }
+ }
+ return location.protocol + "//" + location.host + location.pathname + querystring.slice(0, -1);
+ }
+
+ function applyUrlParams() {
+ var i,
+ selectedModules = [],
+ modulesList = id("qunit-modulefilter-dropdown-list").getElementsByTagName("input"),
+ filter = id("qunit-filter-input").value;
+
+ for (i = 0; i < modulesList.length; i++) {
+ if (modulesList[i].checked) {
+ selectedModules.push(modulesList[i].value);
+ }
+ }
+
+ window$1.location = setUrl({
+ filter: filter === "" ? undefined : filter,
+ moduleId: selectedModules.length === 0 ? undefined : selectedModules,
+
+ // Remove module and testId filter
+ module: undefined,
+ testId: undefined
+ });
+ }
+
+ function toolbarUrlConfigContainer() {
+ var urlConfigContainer = document.createElement("span");
+
+ urlConfigContainer.innerHTML = getUrlConfigHtml();
+ addClass(urlConfigContainer, "qunit-url-config");
+
+ addEvents(urlConfigContainer.getElementsByTagName("input"), "change", toolbarChanged);
+ addEvents(urlConfigContainer.getElementsByTagName("select"), "change", toolbarChanged);
+
+ return urlConfigContainer;
+ }
+
+ function abortTestsButton() {
+ var button = document.createElement("button");
+ button.id = "qunit-abort-tests-button";
+ button.innerHTML = "Abort";
+ addEvent(button, "click", abortTests);
+ return button;
+ }
+
+ function toolbarLooseFilter() {
+ var filter = document.createElement("form"),
+ label = document.createElement("label"),
+ input = document.createElement("input"),
+ button = document.createElement("button");
+
+ addClass(filter, "qunit-filter");
+
+ label.innerHTML = "Filter: ";
+
+ input.type = "text";
+ input.value = config.filter || "";
+ input.name = "filter";
+ input.id = "qunit-filter-input";
+
+ button.innerHTML = "Go";
+
+ label.appendChild(input);
+
+ filter.appendChild(label);
+ filter.appendChild(document.createTextNode(" "));
+ filter.appendChild(button);
+ addEvent(filter, "submit", interceptNavigation);
+
+ return filter;
+ }
+
+ function moduleListHtml() {
+ var i,
+ checked,
+ html = "";
+
+ for (i = 0; i < config.modules.length; i++) {
+ if (config.modules[i].name !== "") {
+ checked = config.moduleId.indexOf(config.modules[i].moduleId) > -1;
+ html += "<li><label class='clickable" + (checked ? " checked" : "") + "'><input type='checkbox' " + "value='" + config.modules[i].moduleId + "'" + (checked ? " checked='checked'" : "") + " />" + escapeText(config.modules[i].name) + "</label></li>";
+ }
+ }
+
+ return html;
+ }
+
+ function toolbarModuleFilter() {
+ var commit,
+ reset,
+ moduleFilter = document.createElement("form"),
+ label = document.createElement("label"),
+ moduleSearch = document.createElement("input"),
+ dropDown = document.createElement("div"),
+ actions = document.createElement("span"),
+ applyButton = document.createElement("button"),
+ resetButton = document.createElement("button"),
+ allModulesLabel = document.createElement("label"),
+ allCheckbox = document.createElement("input"),
+ dropDownList = document.createElement("ul"),
+ dirty = false;
+
+ moduleSearch.id = "qunit-modulefilter-search";
+ moduleSearch.autocomplete = "off";
+ addEvent(moduleSearch, "input", searchInput);
+ addEvent(moduleSearch, "input", searchFocus);
+ addEvent(moduleSearch, "focus", searchFocus);
+ addEvent(moduleSearch, "click", searchFocus);
+
+ label.id = "qunit-modulefilter-search-container";
+ label.innerHTML = "Module: ";
+ label.appendChild(moduleSearch);
+
+ applyButton.textContent = "Apply";
+ applyButton.style.display = "none";
+
+ resetButton.textContent = "Reset";
+ resetButton.type = "reset";
+ resetButton.style.display = "none";
+
+ allCheckbox.type = "checkbox";
+ allCheckbox.checked = config.moduleId.length === 0;
+
+ allModulesLabel.className = "clickable";
+ if (config.moduleId.length) {
+ allModulesLabel.className = "checked";
+ }
+ allModulesLabel.appendChild(allCheckbox);
+ allModulesLabel.appendChild(document.createTextNode("All modules"));
+
+ actions.id = "qunit-modulefilter-actions";
+ actions.appendChild(applyButton);
+ actions.appendChild(resetButton);
+ actions.appendChild(allModulesLabel);
+ commit = actions.firstChild;
+ reset = commit.nextSibling;
+ addEvent(commit, "click", applyUrlParams);
+
+ dropDownList.id = "qunit-modulefilter-dropdown-list";
+ dropDownList.innerHTML = moduleListHtml();
+
+ dropDown.id = "qunit-modulefilter-dropdown";
+ dropDown.style.display = "none";
+ dropDown.appendChild(actions);
+ dropDown.appendChild(dropDownList);
+ addEvent(dropDown, "change", selectionChange);
+ selectionChange();
+
+ moduleFilter.id = "qunit-modulefilter";
+ moduleFilter.appendChild(label);
+ moduleFilter.appendChild(dropDown);
+ addEvent(moduleFilter, "submit", interceptNavigation);
+ addEvent(moduleFilter, "reset", function () {
+
+ // Let the reset happen, then update styles
+ window$1.setTimeout(selectionChange);
+ });
+
+ // Enables show/hide for the dropdown
+ function searchFocus() {
+ if (dropDown.style.display !== "none") {
+ return;
+ }
+
+ dropDown.style.display = "block";
+ addEvent(document, "click", hideHandler);
+ addEvent(document, "keydown", hideHandler);
+
+ // Hide on Escape keydown or outside-container click
+ function hideHandler(e) {
+ var inContainer = moduleFilter.contains(e.target);
+
+ if (e.keyCode === 27 || !inContainer) {
+ if (e.keyCode === 27 && inContainer) {
+ moduleSearch.focus();
+ }
+ dropDown.style.display = "none";
+ removeEvent(document, "click", hideHandler);
+ removeEvent(document, "keydown", hideHandler);
+ moduleSearch.value = "";
+ searchInput();
+ }
+ }
+ }
+
+ // Processes module search box input
+ function searchInput() {
+ var i,
+ item,
+ searchText = moduleSearch.value.toLowerCase(),
+ listItems = dropDownList.children;
+
+ for (i = 0; i < listItems.length; i++) {
+ item = listItems[i];
+ if (!searchText || item.textContent.toLowerCase().indexOf(searchText) > -1) {
+ item.style.display = "";
+ } else {
+ item.style.display = "none";
+ }
+ }
+ }
+
+ // Processes selection changes
+ function selectionChange(evt) {
+ var i,
+ item,
+ checkbox = evt && evt.target || allCheckbox,
+ modulesList = dropDownList.getElementsByTagName("input"),
+ selectedNames = [];
+
+ toggleClass(checkbox.parentNode, "checked", checkbox.checked);
+
+ dirty = false;
+ if (checkbox.checked && checkbox !== allCheckbox) {
+ allCheckbox.checked = false;
+ removeClass(allCheckbox.parentNode, "checked");
+ }
+ for (i = 0; i < modulesList.length; i++) {
+ item = modulesList[i];
+ if (!evt) {
+ toggleClass(item.parentNode, "checked", item.checked);
+ } else if (checkbox === allCheckbox && checkbox.checked) {
+ item.checked = false;
+ removeClass(item.parentNode, "checked");
+ }
+ dirty = dirty || item.checked !== item.defaultChecked;
+ if (item.checked) {
+ selectedNames.push(item.parentNode.textContent);
+ }
+ }
+
+ commit.style.display = reset.style.display = dirty ? "" : "none";
+ moduleSearch.placeholder = selectedNames.join(", ") || allCheckbox.parentNode.textContent;
+ moduleSearch.title = "Type to filter list. Current selection:\n" + (selectedNames.join("\n") || allCheckbox.parentNode.textContent);
+ }
+
+ return moduleFilter;
+ }
+
+ function appendToolbar() {
+ var toolbar = id("qunit-testrunner-toolbar");
+
+ if (toolbar) {
+ toolbar.appendChild(toolbarUrlConfigContainer());
+ toolbar.appendChild(toolbarModuleFilter());
+ toolbar.appendChild(toolbarLooseFilter());
+ toolbar.appendChild(document.createElement("div")).className = "clearfix";
+ }
+ }
+
+ function appendHeader() {
+ var header = id("qunit-header");
+
+ if (header) {
+ header.innerHTML = "<a href='" + escapeText(unfilteredUrl) + "'>" + header.innerHTML + "</a> ";
+ }
+ }
+
+ function appendBanner() {
+ var banner = id("qunit-banner");
+
+ if (banner) {
+ banner.className = "";
+ }
+ }
+
+ function appendTestResults() {
+ var tests = id("qunit-tests"),
+ result = id("qunit-testresult"),
+ controls;
+
+ if (result) {
+ result.parentNode.removeChild(result);
+ }
+
+ if (tests) {
+ tests.innerHTML = "";
+ result = document.createElement("p");
+ result.id = "qunit-testresult";
+ result.className = "result";
+ tests.parentNode.insertBefore(result, tests);
+ result.innerHTML = "<div id=\"qunit-testresult-display\">Running...<br />&#160;</div>" + "<div id=\"qunit-testresult-controls\"></div>" + "<div class=\"clearfix\"></div>";
+ controls = id("qunit-testresult-controls");
+ }
+
+ if (controls) {
+ controls.appendChild(abortTestsButton());
+ }
+ }
+
+ function appendFilteredTest() {
+ var testId = QUnit.config.testId;
+ if (!testId || testId.length <= 0) {
+ return "";
+ }
+ return "<div id='qunit-filteredTest'>Rerunning selected tests: " + escapeText(testId.join(", ")) + " <a id='qunit-clearFilter' href='" + escapeText(unfilteredUrl) + "'>Run all tests</a></div>";
+ }
+
+ function appendUserAgent() {
+ var userAgent = id("qunit-userAgent");
+
+ if (userAgent) {
+ userAgent.innerHTML = "";
+ userAgent.appendChild(document.createTextNode("QUnit " + QUnit.version + "; " + navigator.userAgent));
+ }
+ }
+
+ function appendInterface() {
+ var qunit = id("qunit");
+
+ if (qunit) {
+ qunit.innerHTML = "<h1 id='qunit-header'>" + escapeText(document.title) + "</h1>" + "<h2 id='qunit-banner'></h2>" + "<div id='qunit-testrunner-toolbar'></div>" + appendFilteredTest() + "<h2 id='qunit-userAgent'></h2>" + "<ol id='qunit-tests'></ol>";
+ }
+
+ appendHeader();
+ appendBanner();
+ appendTestResults();
+ appendUserAgent();
+ appendToolbar();
+ }
+
+ function appendTest(name, testId, moduleName) {
+ var title,
+ rerunTrigger,
+ testBlock,
+ assertList,
+ tests = id("qunit-tests");
+
+ if (!tests) {
+ return;
+ }
+
+ title = document.createElement("strong");
+ title.innerHTML = getNameHtml(name, moduleName);
+
+ rerunTrigger = document.createElement("a");
+ rerunTrigger.innerHTML = "Rerun";
+ rerunTrigger.href = setUrl({ testId: testId });
+
+ testBlock = document.createElement("li");
+ testBlock.appendChild(title);
+ testBlock.appendChild(rerunTrigger);
+ testBlock.id = "qunit-test-output-" + testId;
+
+ assertList = document.createElement("ol");
+ assertList.className = "qunit-assert-list";
+
+ testBlock.appendChild(assertList);
+
+ tests.appendChild(testBlock);
+ }
+
+ // HTML Reporter initialization and load
+ QUnit.begin(function (details) {
+ var i, moduleObj;
+
+ // Sort modules by name for the picker
+ for (i = 0; i < details.modules.length; i++) {
+ moduleObj = details.modules[i];
+ if (moduleObj.name) {
+ modulesList.push(moduleObj.name);
+ }
+ }
+ modulesList.sort(function (a, b) {
+ return a.localeCompare(b);
+ });
+
+ // Initialize QUnit elements
+ appendInterface();
+ });
+
+ QUnit.done(function (details) {
+ var banner = id("qunit-banner"),
+ tests = id("qunit-tests"),
+ abortButton = id("qunit-abort-tests-button"),
+ totalTests = stats.passedTests + stats.skippedTests + stats.todoTests + stats.failedTests,
+ html = [totalTests, " tests completed in ", details.runtime, " milliseconds, with ", stats.failedTests, " failed, ", stats.skippedTests, " skipped, and ", stats.todoTests, " todo.<br />", "<span class='passed'>", details.passed, "</span> assertions of <span class='total'>", details.total, "</span> passed, <span class='failed'>", details.failed, "</span> failed."].join(""),
+ test,
+ assertLi,
+ assertList;
+
+ // Update remaing tests to aborted
+ if (abortButton && abortButton.disabled) {
+ html = "Tests aborted after " + details.runtime + " milliseconds.";
+
+ for (var i = 0; i < tests.children.length; i++) {
+ test = tests.children[i];
+ if (test.className === "" || test.className === "running") {
+ test.className = "aborted";
+ assertList = test.getElementsByTagName("ol")[0];
+ assertLi = document.createElement("li");
+ assertLi.className = "fail";
+ assertLi.innerHTML = "Test aborted.";
+ assertList.appendChild(assertLi);
+ }
+ }
+ }
+
+ if (banner && (!abortButton || abortButton.disabled === false)) {
+ banner.className = stats.failedTests ? "qunit-fail" : "qunit-pass";
+ }
+
+ if (abortButton) {
+ abortButton.parentNode.removeChild(abortButton);
+ }
+
+ if (tests) {
+ id("qunit-testresult-display").innerHTML = html;
+ }
+
+ if (config.altertitle && document.title) {
+
+ // Show ✖ for good, ✔ for bad suite result in title
+ // use escape sequences in case file gets loaded with non-utf-8
+ // charset
+ document.title = [stats.failedTests ? "\u2716" : "\u2714", document.title.replace(/^[\u2714\u2716] /i, "")].join(" ");
+ }
+
+ // Scroll back to top to show results
+ if (config.scrolltop && window$1.scrollTo) {
+ window$1.scrollTo(0, 0);
+ }
+ });
+
+ function getNameHtml(name, module) {
+ var nameHtml = "";
+
+ if (module) {
+ nameHtml = "<span class='module-name'>" + escapeText(module) + "</span>: ";
+ }
+
+ nameHtml += "<span class='test-name'>" + escapeText(name) + "</span>";
+
+ return nameHtml;
+ }
+
+ QUnit.testStart(function (details) {
+ var running, bad;
+
+ appendTest(details.name, details.testId, details.module);
+
+ running = id("qunit-testresult-display");
+
+ if (running) {
+ addClass(running, "running");
+
+ bad = QUnit.config.reorder && details.previousFailure;
+
+ running.innerHTML = [bad ? "Rerunning previously failed test: <br />" : "Running: <br />", getNameHtml(details.name, details.module)].join("");
+ }
+ });
+
+ function stripHtml(string) {
+
+ // Strip tags, html entity and whitespaces
+ return string.replace(/<\/?[^>]+(>|$)/g, "").replace(/&quot;/g, "").replace(/\s+/g, "");
+ }
+
+ QUnit.log(function (details) {
+ var assertList,
+ assertLi,
+ message,
+ expected,
+ actual,
+ diff,
+ showDiff = false,
+ testItem = id("qunit-test-output-" + details.testId);
+
+ if (!testItem) {
+ return;
+ }
+
+ message = escapeText(details.message) || (details.result ? "okay" : "failed");
+ message = "<span class='test-message'>" + message + "</span>";
+ message += "<span class='runtime'>@ " + details.runtime + " ms</span>";
+
+ // The pushFailure doesn't provide details.expected
+ // when it calls, it's implicit to also not show expected and diff stuff
+ // Also, we need to check details.expected existence, as it can exist and be undefined
+ if (!details.result && hasOwn.call(details, "expected")) {
+ if (details.negative) {
+ expected = "NOT " + QUnit.dump.parse(details.expected);
+ } else {
+ expected = QUnit.dump.parse(details.expected);
+ }
+
+ actual = QUnit.dump.parse(details.actual);
+ message += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + escapeText(expected) + "</pre></td></tr>";
+
+ if (actual !== expected) {
+
+ message += "<tr class='test-actual'><th>Result: </th><td><pre>" + escapeText(actual) + "</pre></td></tr>";
+
+ if (typeof details.actual === "number" && typeof details.expected === "number") {
+ if (!isNaN(details.actual) && !isNaN(details.expected)) {
+ showDiff = true;
+ diff = details.actual - details.expected;
+ diff = (diff > 0 ? "+" : "") + diff;
+ }
+ } else if (typeof details.actual !== "boolean" && typeof details.expected !== "boolean") {
+ diff = QUnit.diff(expected, actual);
+
+ // don't show diff if there is zero overlap
+ showDiff = stripHtml(diff).length !== stripHtml(expected).length + stripHtml(actual).length;
+ }
+
+ if (showDiff) {
+ message += "<tr class='test-diff'><th>Diff: </th><td><pre>" + diff + "</pre></td></tr>";
+ }
+ } else if (expected.indexOf("[object Array]") !== -1 || expected.indexOf("[object Object]") !== -1) {
+ message += "<tr class='test-message'><th>Message: </th><td>" + "Diff suppressed as the depth of object is more than current max depth (" + QUnit.config.maxDepth + ").<p>Hint: Use <code>QUnit.dump.maxDepth</code> to " + " run with a higher max depth or <a href='" + escapeText(setUrl({ maxDepth: -1 })) + "'>" + "Rerun</a> without max depth.</p></td></tr>";
+ } else {
+ message += "<tr class='test-message'><th>Message: </th><td>" + "Diff suppressed as the expected and actual results have an equivalent" + " serialization</td></tr>";
+ }
+
+ if (details.source) {
+ message += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText(details.source) + "</pre></td></tr>";
+ }
+
+ message += "</table>";
+
+ // This occurs when pushFailure is set and we have an extracted stack trace
+ } else if (!details.result && details.source) {
+ message += "<table>" + "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText(details.source) + "</pre></td></tr>" + "</table>";
+ }
+
+ assertList = testItem.getElementsByTagName("ol")[0];
+
+ assertLi = document.createElement("li");
+ assertLi.className = details.result ? "pass" : "fail";
+ assertLi.innerHTML = message;
+ assertList.appendChild(assertLi);
+ });
+
+ QUnit.testDone(function (details) {
+ var testTitle,
+ time,
+ testItem,
+ assertList,
+ status,
+ good,
+ bad,
+ testCounts,
+ skipped,
+ sourceName,
+ tests = id("qunit-tests");
+
+ if (!tests) {
+ return;
+ }
+
+ testItem = id("qunit-test-output-" + details.testId);
+
+ removeClass(testItem, "running");
+
+ if (details.failed > 0) {
+ status = "failed";
+ } else if (details.todo) {
+ status = "todo";
+ } else {
+ status = details.skipped ? "skipped" : "passed";
+ }
+
+ assertList = testItem.getElementsByTagName("ol")[0];
+
+ good = details.passed;
+ bad = details.failed;
+
+ // This test passed if it has no unexpected failed assertions
+ var testPassed = details.failed > 0 ? details.todo : !details.todo;
+
+ if (testPassed) {
+
+ // Collapse the passing tests
+ addClass(assertList, "qunit-collapsed");
+ } else if (config.collapse) {
+ if (!collapseNext) {
+
+ // Skip collapsing the first failing test
+ collapseNext = true;
+ } else {
+
+ // Collapse remaining tests
+ addClass(assertList, "qunit-collapsed");
+ }
+ }
+
+ // The testItem.firstChild is the test name
+ testTitle = testItem.firstChild;
+
+ testCounts = bad ? "<b class='failed'>" + bad + "</b>, " + "<b class='passed'>" + good + "</b>, " : "";
+
+ testTitle.innerHTML += " <b class='counts'>(" + testCounts + details.assertions.length + ")</b>";
+
+ if (details.skipped) {
+ stats.skippedTests++;
+
+ testItem.className = "skipped";
+ skipped = document.createElement("em");
+ skipped.className = "qunit-skipped-label";
+ skipped.innerHTML = "skipped";
+ testItem.insertBefore(skipped, testTitle);
+ } else {
+ addEvent(testTitle, "click", function () {
+ toggleClass(assertList, "qunit-collapsed");
+ });
+
+ testItem.className = testPassed ? "pass" : "fail";
+
+ if (details.todo) {
+ var todoLabel = document.createElement("em");
+ todoLabel.className = "qunit-todo-label";
+ todoLabel.innerHTML = "todo";
+ testItem.className += " todo";
+ testItem.insertBefore(todoLabel, testTitle);
+ }
+
+ time = document.createElement("span");
+ time.className = "runtime";
+ time.innerHTML = details.runtime + " ms";
+ testItem.insertBefore(time, assertList);
+
+ if (!testPassed) {
+ stats.failedTests++;
+ } else if (details.todo) {
+ stats.todoTests++;
+ } else {
+ stats.passedTests++;
+ }
+ }
+
+ // Show the source of the test when showing assertions
+ if (details.source) {
+ sourceName = document.createElement("p");
+ sourceName.innerHTML = "<strong>Source: </strong>" + escapeText(details.source);
+ addClass(sourceName, "qunit-source");
+ if (testPassed) {
+ addClass(sourceName, "qunit-collapsed");
+ }
+ addEvent(testTitle, "click", function () {
+ toggleClass(sourceName, "qunit-collapsed");
+ });
+ testItem.appendChild(sourceName);
+ }
+
+ if (config.hidepassed && status === "passed") {
+
+ // use removeChild instead of remove because of support
+ hiddenTests.push(testItem);
+
+ tests.removeChild(testItem);
+ }
+ });
+
+ // Avoid readyState issue with phantomjs
+ // Ref: #818
+ var notPhantom = function (p) {
+ return !(p && p.version && p.version.major > 0);
+ }(window$1.phantom);
+
+ if (notPhantom && document.readyState === "complete") {
+ QUnit.load();
+ } else {
+ addEvent(window$1, "load", QUnit.load);
+ }
+
+ // Wrap window.onerror. We will call the original window.onerror to see if
+ // the existing handler fully handles the error; if not, we will call the
+ // QUnit.onError function.
+ var originalWindowOnError = window$1.onerror;
+
+ // Cover uncaught exceptions
+ // Returning true will suppress the default browser handler,
+ // returning false will let it run.
+ window$1.onerror = function (message, fileName, lineNumber, columnNumber, errorObj) {
+ var ret = false;
+ if (originalWindowOnError) {
+ for (var _len = arguments.length, args = Array(_len > 5 ? _len - 5 : 0), _key = 5; _key < _len; _key++) {
+ args[_key - 5] = arguments[_key];
+ }
+
+ ret = originalWindowOnError.call.apply(originalWindowOnError, [this, message, fileName, lineNumber, columnNumber, errorObj].concat(args));
+ }
+
+ // Treat return value as window.onerror itself does,
+ // Only do our handling if not suppressed.
+ if (ret !== true) {
+ var error = {
+ message: message,
+ fileName: fileName,
+ lineNumber: lineNumber
+ };
+
+ // According to
+ // https://blog.sentry.io/2016/01/04/client-javascript-reporting-window-onerror,
+ // most modern browsers support an errorObj argument; use that to
+ // get a full stack trace if it's available.
+ if (errorObj && errorObj.stack) {
+ error.stacktrace = extractStacktrace(errorObj, 0);
+ }
+
+ ret = QUnit.onError(error);
+ }
+
+ return ret;
+ };
+
+ // Listen for unhandled rejections, and call QUnit.onUnhandledRejection
+ window$1.addEventListener("unhandledrejection", function (event) {
+ QUnit.onUnhandledRejection(event.reason);
+ });
+ })();
+
+ /*
+ * This file is a modified version of google-diff-match-patch's JavaScript implementation
+ * (https://code.google.com/p/google-diff-match-patch/source/browse/trunk/javascript/diff_match_patch_uncompressed.js),
+ * modifications are licensed as more fully set forth in LICENSE.txt.
+ *
+ * The original source of google-diff-match-patch is attributable and licensed as follows:
+ *
+ * Copyright 2006 Google Inc.
+ * https://code.google.com/p/google-diff-match-patch/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * More Info:
+ * https://code.google.com/p/google-diff-match-patch/
+ *
+ * Usage: QUnit.diff(expected, actual)
+ *
+ */
+ QUnit.diff = function () {
+ function DiffMatchPatch() {}
+
+ // DIFF FUNCTIONS
+
+ /**
+ * The data structure representing a diff is an array of tuples:
+ * [[DIFF_DELETE, 'Hello'], [DIFF_INSERT, 'Goodbye'], [DIFF_EQUAL, ' world.']]
+ * which means: delete 'Hello', add 'Goodbye' and keep ' world.'
+ */
+ var DIFF_DELETE = -1,
+ DIFF_INSERT = 1,
+ DIFF_EQUAL = 0;
+
+ /**
+ * Find the differences between two texts. Simplifies the problem by stripping
+ * any common prefix or suffix off the texts before diffing.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @param {boolean=} optChecklines Optional speedup flag. If present and false,
+ * then don't run a line-level diff first to identify the changed areas.
+ * Defaults to true, which does a faster, slightly less optimal diff.
+ * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
+ */
+ DiffMatchPatch.prototype.DiffMain = function (text1, text2, optChecklines) {
+ var deadline, checklines, commonlength, commonprefix, commonsuffix, diffs;
+
+ // The diff must be complete in up to 1 second.
+ deadline = new Date().getTime() + 1000;
+
+ // Check for null inputs.
+ if (text1 === null || text2 === null) {
+ throw new Error("Null input. (DiffMain)");
+ }
+
+ // Check for equality (speedup).
+ if (text1 === text2) {
+ if (text1) {
+ return [[DIFF_EQUAL, text1]];
+ }
+ return [];
+ }
+
+ if (typeof optChecklines === "undefined") {
+ optChecklines = true;
+ }
+
+ checklines = optChecklines;
+
+ // Trim off common prefix (speedup).
+ commonlength = this.diffCommonPrefix(text1, text2);
+ commonprefix = text1.substring(0, commonlength);
+ text1 = text1.substring(commonlength);
+ text2 = text2.substring(commonlength);
+
+ // Trim off common suffix (speedup).
+ commonlength = this.diffCommonSuffix(text1, text2);
+ commonsuffix = text1.substring(text1.length - commonlength);
+ text1 = text1.substring(0, text1.length - commonlength);
+ text2 = text2.substring(0, text2.length - commonlength);
+
+ // Compute the diff on the middle block.
+ diffs = this.diffCompute(text1, text2, checklines, deadline);
+
+ // Restore the prefix and suffix.
+ if (commonprefix) {
+ diffs.unshift([DIFF_EQUAL, commonprefix]);
+ }
+ if (commonsuffix) {
+ diffs.push([DIFF_EQUAL, commonsuffix]);
+ }
+ this.diffCleanupMerge(diffs);
+ return diffs;
+ };
+
+ /**
+ * Reduce the number of edits by eliminating operationally trivial equalities.
+ * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
+ */
+ DiffMatchPatch.prototype.diffCleanupEfficiency = function (diffs) {
+ var changes, equalities, equalitiesLength, lastequality, pointer, preIns, preDel, postIns, postDel;
+ changes = false;
+ equalities = []; // Stack of indices where equalities are found.
+ equalitiesLength = 0; // Keeping our own length var is faster in JS.
+ /** @type {?string} */
+ lastequality = null;
+
+ // Always equal to diffs[equalities[equalitiesLength - 1]][1]
+ pointer = 0; // Index of current position.
+
+ // Is there an insertion operation before the last equality.
+ preIns = false;
+
+ // Is there a deletion operation before the last equality.
+ preDel = false;
+
+ // Is there an insertion operation after the last equality.
+ postIns = false;
+
+ // Is there a deletion operation after the last equality.
+ postDel = false;
+ while (pointer < diffs.length) {
+
+ // Equality found.
+ if (diffs[pointer][0] === DIFF_EQUAL) {
+ if (diffs[pointer][1].length < 4 && (postIns || postDel)) {
+
+ // Candidate found.
+ equalities[equalitiesLength++] = pointer;
+ preIns = postIns;
+ preDel = postDel;
+ lastequality = diffs[pointer][1];
+ } else {
+
+ // Not a candidate, and can never become one.
+ equalitiesLength = 0;
+ lastequality = null;
+ }
+ postIns = postDel = false;
+
+ // An insertion or deletion.
+ } else {
+
+ if (diffs[pointer][0] === DIFF_DELETE) {
+ postDel = true;
+ } else {
+ postIns = true;
+ }
+
+ /*
+ * Five types to be split:
+ * <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del>
+ * <ins>A</ins>X<ins>C</ins><del>D</del>
+ * <ins>A</ins><del>B</del>X<ins>C</ins>
+ * <ins>A</del>X<ins>C</ins><del>D</del>
+ * <ins>A</ins><del>B</del>X<del>C</del>
+ */
+ if (lastequality && (preIns && preDel && postIns && postDel || lastequality.length < 2 && preIns + preDel + postIns + postDel === 3)) {
+
+ // Duplicate record.
+ diffs.splice(equalities[equalitiesLength - 1], 0, [DIFF_DELETE, lastequality]);
+
+ // Change second copy to insert.
+ diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT;
+ equalitiesLength--; // Throw away the equality we just deleted;
+ lastequality = null;
+ if (preIns && preDel) {
+
+ // No changes made which could affect previous entry, keep going.
+ postIns = postDel = true;
+ equalitiesLength = 0;
+ } else {
+ equalitiesLength--; // Throw away the previous equality.
+ pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1;
+ postIns = postDel = false;
+ }
+ changes = true;
+ }
+ }
+ pointer++;
+ }
+
+ if (changes) {
+ this.diffCleanupMerge(diffs);
+ }
+ };
+
+ /**
+ * Convert a diff array into a pretty HTML report.
+ * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
+ * @param {integer} string to be beautified.
+ * @return {string} HTML representation.
+ */
+ DiffMatchPatch.prototype.diffPrettyHtml = function (diffs) {
+ var op,
+ data,
+ x,
+ html = [];
+ for (x = 0; x < diffs.length; x++) {
+ op = diffs[x][0]; // Operation (insert, delete, equal)
+ data = diffs[x][1]; // Text of change.
+ switch (op) {
+ case DIFF_INSERT:
+ html[x] = "<ins>" + escapeText(data) + "</ins>";
+ break;
+ case DIFF_DELETE:
+ html[x] = "<del>" + escapeText(data) + "</del>";
+ break;
+ case DIFF_EQUAL:
+ html[x] = "<span>" + escapeText(data) + "</span>";
+ break;
+ }
+ }
+ return html.join("");
+ };
+
+ /**
+ * Determine the common prefix of two strings.
+ * @param {string} text1 First string.
+ * @param {string} text2 Second string.
+ * @return {number} The number of characters common to the start of each
+ * string.
+ */
+ DiffMatchPatch.prototype.diffCommonPrefix = function (text1, text2) {
+ var pointermid, pointermax, pointermin, pointerstart;
+
+ // Quick check for common null cases.
+ if (!text1 || !text2 || text1.charAt(0) !== text2.charAt(0)) {
+ return 0;
+ }
+
+ // Binary search.
+ // Performance analysis: https://neil.fraser.name/news/2007/10/09/
+ pointermin = 0;
+ pointermax = Math.min(text1.length, text2.length);
+ pointermid = pointermax;
+ pointerstart = 0;
+ while (pointermin < pointermid) {
+ if (text1.substring(pointerstart, pointermid) === text2.substring(pointerstart, pointermid)) {
+ pointermin = pointermid;
+ pointerstart = pointermin;
+ } else {
+ pointermax = pointermid;
+ }
+ pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
+ }
+ return pointermid;
+ };
+
+ /**
+ * Determine the common suffix of two strings.
+ * @param {string} text1 First string.
+ * @param {string} text2 Second string.
+ * @return {number} The number of characters common to the end of each string.
+ */
+ DiffMatchPatch.prototype.diffCommonSuffix = function (text1, text2) {
+ var pointermid, pointermax, pointermin, pointerend;
+
+ // Quick check for common null cases.
+ if (!text1 || !text2 || text1.charAt(text1.length - 1) !== text2.charAt(text2.length - 1)) {
+ return 0;
+ }
+
+ // Binary search.
+ // Performance analysis: https://neil.fraser.name/news/2007/10/09/
+ pointermin = 0;
+ pointermax = Math.min(text1.length, text2.length);
+ pointermid = pointermax;
+ pointerend = 0;
+ while (pointermin < pointermid) {
+ if (text1.substring(text1.length - pointermid, text1.length - pointerend) === text2.substring(text2.length - pointermid, text2.length - pointerend)) {
+ pointermin = pointermid;
+ pointerend = pointermin;
+ } else {
+ pointermax = pointermid;
+ }
+ pointermid = Math.floor((pointermax - pointermin) / 2 + pointermin);
+ }
+ return pointermid;
+ };
+
+ /**
+ * Find the differences between two texts. Assumes that the texts do not
+ * have any common prefix or suffix.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @param {boolean} checklines Speedup flag. If false, then don't run a
+ * line-level diff first to identify the changed areas.
+ * If true, then run a faster, slightly less optimal diff.
+ * @param {number} deadline Time when the diff should be complete by.
+ * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
+ * @private
+ */
+ DiffMatchPatch.prototype.diffCompute = function (text1, text2, checklines, deadline) {
+ var diffs, longtext, shorttext, i, hm, text1A, text2A, text1B, text2B, midCommon, diffsA, diffsB;
+
+ if (!text1) {
+
+ // Just add some text (speedup).
+ return [[DIFF_INSERT, text2]];
+ }
+
+ if (!text2) {
+
+ // Just delete some text (speedup).
+ return [[DIFF_DELETE, text1]];
+ }
+
+ longtext = text1.length > text2.length ? text1 : text2;
+ shorttext = text1.length > text2.length ? text2 : text1;
+ i = longtext.indexOf(shorttext);
+ if (i !== -1) {
+
+ // Shorter text is inside the longer text (speedup).
+ diffs = [[DIFF_INSERT, longtext.substring(0, i)], [DIFF_EQUAL, shorttext], [DIFF_INSERT, longtext.substring(i + shorttext.length)]];
+
+ // Swap insertions for deletions if diff is reversed.
+ if (text1.length > text2.length) {
+ diffs[0][0] = diffs[2][0] = DIFF_DELETE;
+ }
+ return diffs;
+ }
+
+ if (shorttext.length === 1) {
+
+ // Single character string.
+ // After the previous speedup, the character can't be an equality.
+ return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]];
+ }
+
+ // Check to see if the problem can be split in two.
+ hm = this.diffHalfMatch(text1, text2);
+ if (hm) {
+
+ // A half-match was found, sort out the return data.
+ text1A = hm[0];
+ text1B = hm[1];
+ text2A = hm[2];
+ text2B = hm[3];
+ midCommon = hm[4];
+
+ // Send both pairs off for separate processing.
+ diffsA = this.DiffMain(text1A, text2A, checklines, deadline);
+ diffsB = this.DiffMain(text1B, text2B, checklines, deadline);
+
+ // Merge the results.
+ return diffsA.concat([[DIFF_EQUAL, midCommon]], diffsB);
+ }
+
+ if (checklines && text1.length > 100 && text2.length > 100) {
+ return this.diffLineMode(text1, text2, deadline);
+ }
+
+ return this.diffBisect(text1, text2, deadline);
+ };
+
+ /**
+ * Do the two texts share a substring which is at least half the length of the
+ * longer text?
+ * This speedup can produce non-minimal diffs.
+ * @param {string} text1 First string.
+ * @param {string} text2 Second string.
+ * @return {Array.<string>} Five element Array, containing the prefix of
+ * text1, the suffix of text1, the prefix of text2, the suffix of
+ * text2 and the common middle. Or null if there was no match.
+ * @private
+ */
+ DiffMatchPatch.prototype.diffHalfMatch = function (text1, text2) {
+ var longtext, shorttext, dmp, text1A, text2B, text2A, text1B, midCommon, hm1, hm2, hm;
+
+ longtext = text1.length > text2.length ? text1 : text2;
+ shorttext = text1.length > text2.length ? text2 : text1;
+ if (longtext.length < 4 || shorttext.length * 2 < longtext.length) {
+ return null; // Pointless.
+ }
+ dmp = this; // 'this' becomes 'window' in a closure.
+
+ /**
+ * Does a substring of shorttext exist within longtext such that the substring
+ * is at least half the length of longtext?
+ * Closure, but does not reference any external variables.
+ * @param {string} longtext Longer string.
+ * @param {string} shorttext Shorter string.
+ * @param {number} i Start index of quarter length substring within longtext.
+ * @return {Array.<string>} Five element Array, containing the prefix of
+ * longtext, the suffix of longtext, the prefix of shorttext, the suffix
+ * of shorttext and the common middle. Or null if there was no match.
+ * @private
+ */
+ function diffHalfMatchI(longtext, shorttext, i) {
+ var seed, j, bestCommon, prefixLength, suffixLength, bestLongtextA, bestLongtextB, bestShorttextA, bestShorttextB;
+
+ // Start with a 1/4 length substring at position i as a seed.
+ seed = longtext.substring(i, i + Math.floor(longtext.length / 4));
+ j = -1;
+ bestCommon = "";
+ while ((j = shorttext.indexOf(seed, j + 1)) !== -1) {
+ prefixLength = dmp.diffCommonPrefix(longtext.substring(i), shorttext.substring(j));
+ suffixLength = dmp.diffCommonSuffix(longtext.substring(0, i), shorttext.substring(0, j));
+ if (bestCommon.length < suffixLength + prefixLength) {
+ bestCommon = shorttext.substring(j - suffixLength, j) + shorttext.substring(j, j + prefixLength);
+ bestLongtextA = longtext.substring(0, i - suffixLength);
+ bestLongtextB = longtext.substring(i + prefixLength);
+ bestShorttextA = shorttext.substring(0, j - suffixLength);
+ bestShorttextB = shorttext.substring(j + prefixLength);
+ }
+ }
+ if (bestCommon.length * 2 >= longtext.length) {
+ return [bestLongtextA, bestLongtextB, bestShorttextA, bestShorttextB, bestCommon];
+ } else {
+ return null;
+ }
+ }
+
+ // First check if the second quarter is the seed for a half-match.
+ hm1 = diffHalfMatchI(longtext, shorttext, Math.ceil(longtext.length / 4));
+
+ // Check again based on the third quarter.
+ hm2 = diffHalfMatchI(longtext, shorttext, Math.ceil(longtext.length / 2));
+ if (!hm1 && !hm2) {
+ return null;
+ } else if (!hm2) {
+ hm = hm1;
+ } else if (!hm1) {
+ hm = hm2;
+ } else {
+
+ // Both matched. Select the longest.
+ hm = hm1[4].length > hm2[4].length ? hm1 : hm2;
+ }
+
+ // A half-match was found, sort out the return data.
+ if (text1.length > text2.length) {
+ text1A = hm[0];
+ text1B = hm[1];
+ text2A = hm[2];
+ text2B = hm[3];
+ } else {
+ text2A = hm[0];
+ text2B = hm[1];
+ text1A = hm[2];
+ text1B = hm[3];
+ }
+ midCommon = hm[4];
+ return [text1A, text1B, text2A, text2B, midCommon];
+ };
+
+ /**
+ * Do a quick line-level diff on both strings, then rediff the parts for
+ * greater accuracy.
+ * This speedup can produce non-minimal diffs.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @param {number} deadline Time when the diff should be complete by.
+ * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
+ * @private
+ */
+ DiffMatchPatch.prototype.diffLineMode = function (text1, text2, deadline) {
+ var a, diffs, linearray, pointer, countInsert, countDelete, textInsert, textDelete, j;
+
+ // Scan the text on a line-by-line basis first.
+ a = this.diffLinesToChars(text1, text2);
+ text1 = a.chars1;
+ text2 = a.chars2;
+ linearray = a.lineArray;
+
+ diffs = this.DiffMain(text1, text2, false, deadline);
+
+ // Convert the diff back to original text.
+ this.diffCharsToLines(diffs, linearray);
+
+ // Eliminate freak matches (e.g. blank lines)
+ this.diffCleanupSemantic(diffs);
+
+ // Rediff any replacement blocks, this time character-by-character.
+ // Add a dummy entry at the end.
+ diffs.push([DIFF_EQUAL, ""]);
+ pointer = 0;
+ countDelete = 0;
+ countInsert = 0;
+ textDelete = "";
+ textInsert = "";
+ while (pointer < diffs.length) {
+ switch (diffs[pointer][0]) {
+ case DIFF_INSERT:
+ countInsert++;
+ textInsert += diffs[pointer][1];
+ break;
+ case DIFF_DELETE:
+ countDelete++;
+ textDelete += diffs[pointer][1];
+ break;
+ case DIFF_EQUAL:
+
+ // Upon reaching an equality, check for prior redundancies.
+ if (countDelete >= 1 && countInsert >= 1) {
+
+ // Delete the offending records and add the merged ones.
+ diffs.splice(pointer - countDelete - countInsert, countDelete + countInsert);
+ pointer = pointer - countDelete - countInsert;
+ a = this.DiffMain(textDelete, textInsert, false, deadline);
+ for (j = a.length - 1; j >= 0; j--) {
+ diffs.splice(pointer, 0, a[j]);
+ }
+ pointer = pointer + a.length;
+ }
+ countInsert = 0;
+ countDelete = 0;
+ textDelete = "";
+ textInsert = "";
+ break;
+ }
+ pointer++;
+ }
+ diffs.pop(); // Remove the dummy entry at the end.
+
+ return diffs;
+ };
+
+ /**
+ * Find the 'middle snake' of a diff, split the problem in two
+ * and return the recursively constructed diff.
+ * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @param {number} deadline Time at which to bail if not yet complete.
+ * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
+ * @private
+ */
+ DiffMatchPatch.prototype.diffBisect = function (text1, text2, deadline) {
+ var text1Length, text2Length, maxD, vOffset, vLength, v1, v2, x, delta, front, k1start, k1end, k2start, k2end, k2Offset, k1Offset, x1, x2, y1, y2, d, k1, k2;
+
+ // Cache the text lengths to prevent multiple calls.
+ text1Length = text1.length;
+ text2Length = text2.length;
+ maxD = Math.ceil((text1Length + text2Length) / 2);
+ vOffset = maxD;
+ vLength = 2 * maxD;
+ v1 = new Array(vLength);
+ v2 = new Array(vLength);
+
+ // Setting all elements to -1 is faster in Chrome & Firefox than mixing
+ // integers and undefined.
+ for (x = 0; x < vLength; x++) {
+ v1[x] = -1;
+ v2[x] = -1;
+ }
+ v1[vOffset + 1] = 0;
+ v2[vOffset + 1] = 0;
+ delta = text1Length - text2Length;
+
+ // If the total number of characters is odd, then the front path will collide
+ // with the reverse path.
+ front = delta % 2 !== 0;
+
+ // Offsets for start and end of k loop.
+ // Prevents mapping of space beyond the grid.
+ k1start = 0;
+ k1end = 0;
+ k2start = 0;
+ k2end = 0;
+ for (d = 0; d < maxD; d++) {
+
+ // Bail out if deadline is reached.
+ if (new Date().getTime() > deadline) {
+ break;
+ }
+
+ // Walk the front path one step.
+ for (k1 = -d + k1start; k1 <= d - k1end; k1 += 2) {
+ k1Offset = vOffset + k1;
+ if (k1 === -d || k1 !== d && v1[k1Offset - 1] < v1[k1Offset + 1]) {
+ x1 = v1[k1Offset + 1];
+ } else {
+ x1 = v1[k1Offset - 1] + 1;
+ }
+ y1 = x1 - k1;
+ while (x1 < text1Length && y1 < text2Length && text1.charAt(x1) === text2.charAt(y1)) {
+ x1++;
+ y1++;
+ }
+ v1[k1Offset] = x1;
+ if (x1 > text1Length) {
+
+ // Ran off the right of the graph.
+ k1end += 2;
+ } else if (y1 > text2Length) {
+
+ // Ran off the bottom of the graph.
+ k1start += 2;
+ } else if (front) {
+ k2Offset = vOffset + delta - k1;
+ if (k2Offset >= 0 && k2Offset < vLength && v2[k2Offset] !== -1) {
+
+ // Mirror x2 onto top-left coordinate system.
+ x2 = text1Length - v2[k2Offset];
+ if (x1 >= x2) {
+
+ // Overlap detected.
+ return this.diffBisectSplit(text1, text2, x1, y1, deadline);
+ }
+ }
+ }
+ }
+
+ // Walk the reverse path one step.
+ for (k2 = -d + k2start; k2 <= d - k2end; k2 += 2) {
+ k2Offset = vOffset + k2;
+ if (k2 === -d || k2 !== d && v2[k2Offset - 1] < v2[k2Offset + 1]) {
+ x2 = v2[k2Offset + 1];
+ } else {
+ x2 = v2[k2Offset - 1] + 1;
+ }
+ y2 = x2 - k2;
+ while (x2 < text1Length && y2 < text2Length && text1.charAt(text1Length - x2 - 1) === text2.charAt(text2Length - y2 - 1)) {
+ x2++;
+ y2++;
+ }
+ v2[k2Offset] = x2;
+ if (x2 > text1Length) {
+
+ // Ran off the left of the graph.
+ k2end += 2;
+ } else if (y2 > text2Length) {
+
+ // Ran off the top of the graph.
+ k2start += 2;
+ } else if (!front) {
+ k1Offset = vOffset + delta - k2;
+ if (k1Offset >= 0 && k1Offset < vLength && v1[k1Offset] !== -1) {
+ x1 = v1[k1Offset];
+ y1 = vOffset + x1 - k1Offset;
+
+ // Mirror x2 onto top-left coordinate system.
+ x2 = text1Length - x2;
+ if (x1 >= x2) {
+
+ // Overlap detected.
+ return this.diffBisectSplit(text1, text2, x1, y1, deadline);
+ }
+ }
+ }
+ }
+ }
+
+ // Diff took too long and hit the deadline or
+ // number of diffs equals number of characters, no commonality at all.
+ return [[DIFF_DELETE, text1], [DIFF_INSERT, text2]];
+ };
+
+ /**
+ * Given the location of the 'middle snake', split the diff in two parts
+ * and recurse.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @param {number} x Index of split point in text1.
+ * @param {number} y Index of split point in text2.
+ * @param {number} deadline Time at which to bail if not yet complete.
+ * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
+ * @private
+ */
+ DiffMatchPatch.prototype.diffBisectSplit = function (text1, text2, x, y, deadline) {
+ var text1a, text1b, text2a, text2b, diffs, diffsb;
+ text1a = text1.substring(0, x);
+ text2a = text2.substring(0, y);
+ text1b = text1.substring(x);
+ text2b = text2.substring(y);
+
+ // Compute both diffs serially.
+ diffs = this.DiffMain(text1a, text2a, false, deadline);
+ diffsb = this.DiffMain(text1b, text2b, false, deadline);
+
+ return diffs.concat(diffsb);
+ };
+
+ /**
+ * Reduce the number of edits by eliminating semantically trivial equalities.
+ * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
+ */
+ DiffMatchPatch.prototype.diffCleanupSemantic = function (diffs) {
+ var changes, equalities, equalitiesLength, lastequality, pointer, lengthInsertions2, lengthDeletions2, lengthInsertions1, lengthDeletions1, deletion, insertion, overlapLength1, overlapLength2;
+ changes = false;
+ equalities = []; // Stack of indices where equalities are found.
+ equalitiesLength = 0; // Keeping our own length var is faster in JS.
+ /** @type {?string} */
+ lastequality = null;
+
+ // Always equal to diffs[equalities[equalitiesLength - 1]][1]
+ pointer = 0; // Index of current position.
+
+ // Number of characters that changed prior to the equality.
+ lengthInsertions1 = 0;
+ lengthDeletions1 = 0;
+
+ // Number of characters that changed after the equality.
+ lengthInsertions2 = 0;
+ lengthDeletions2 = 0;
+ while (pointer < diffs.length) {
+ if (diffs[pointer][0] === DIFF_EQUAL) {
+ // Equality found.
+ equalities[equalitiesLength++] = pointer;
+ lengthInsertions1 = lengthInsertions2;
+ lengthDeletions1 = lengthDeletions2;
+ lengthInsertions2 = 0;
+ lengthDeletions2 = 0;
+ lastequality = diffs[pointer][1];
+ } else {
+ // An insertion or deletion.
+ if (diffs[pointer][0] === DIFF_INSERT) {
+ lengthInsertions2 += diffs[pointer][1].length;
+ } else {
+ lengthDeletions2 += diffs[pointer][1].length;
+ }
+
+ // Eliminate an equality that is smaller or equal to the edits on both
+ // sides of it.
+ if (lastequality && lastequality.length <= Math.max(lengthInsertions1, lengthDeletions1) && lastequality.length <= Math.max(lengthInsertions2, lengthDeletions2)) {
+
+ // Duplicate record.
+ diffs.splice(equalities[equalitiesLength - 1], 0, [DIFF_DELETE, lastequality]);
+
+ // Change second copy to insert.
+ diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT;
+
+ // Throw away the equality we just deleted.
+ equalitiesLength--;
+
+ // Throw away the previous equality (it needs to be reevaluated).
+ equalitiesLength--;
+ pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1;
+
+ // Reset the counters.
+ lengthInsertions1 = 0;
+ lengthDeletions1 = 0;
+ lengthInsertions2 = 0;
+ lengthDeletions2 = 0;
+ lastequality = null;
+ changes = true;
+ }
+ }
+ pointer++;
+ }
+
+ // Normalize the diff.
+ if (changes) {
+ this.diffCleanupMerge(diffs);
+ }
+
+ // Find any overlaps between deletions and insertions.
+ // e.g: <del>abcxxx</del><ins>xxxdef</ins>
+ // -> <del>abc</del>xxx<ins>def</ins>
+ // e.g: <del>xxxabc</del><ins>defxxx</ins>
+ // -> <ins>def</ins>xxx<del>abc</del>
+ // Only extract an overlap if it is as big as the edit ahead or behind it.
+ pointer = 1;
+ while (pointer < diffs.length) {
+ if (diffs[pointer - 1][0] === DIFF_DELETE && diffs[pointer][0] === DIFF_INSERT) {
+ deletion = diffs[pointer - 1][1];
+ insertion = diffs[pointer][1];
+ overlapLength1 = this.diffCommonOverlap(deletion, insertion);
+ overlapLength2 = this.diffCommonOverlap(insertion, deletion);
+ if (overlapLength1 >= overlapLength2) {
+ if (overlapLength1 >= deletion.length / 2 || overlapLength1 >= insertion.length / 2) {
+
+ // Overlap found. Insert an equality and trim the surrounding edits.
+ diffs.splice(pointer, 0, [DIFF_EQUAL, insertion.substring(0, overlapLength1)]);
+ diffs[pointer - 1][1] = deletion.substring(0, deletion.length - overlapLength1);
+ diffs[pointer + 1][1] = insertion.substring(overlapLength1);
+ pointer++;
+ }
+ } else {
+ if (overlapLength2 >= deletion.length / 2 || overlapLength2 >= insertion.length / 2) {
+
+ // Reverse overlap found.
+ // Insert an equality and swap and trim the surrounding edits.
+ diffs.splice(pointer, 0, [DIFF_EQUAL, deletion.substring(0, overlapLength2)]);
+
+ diffs[pointer - 1][0] = DIFF_INSERT;
+ diffs[pointer - 1][1] = insertion.substring(0, insertion.length - overlapLength2);
+ diffs[pointer + 1][0] = DIFF_DELETE;
+ diffs[pointer + 1][1] = deletion.substring(overlapLength2);
+ pointer++;
+ }
+ }
+ pointer++;
+ }
+ pointer++;
+ }
+ };
+
+ /**
+ * Determine if the suffix of one string is the prefix of another.
+ * @param {string} text1 First string.
+ * @param {string} text2 Second string.
+ * @return {number} The number of characters common to the end of the first
+ * string and the start of the second string.
+ * @private
+ */
+ DiffMatchPatch.prototype.diffCommonOverlap = function (text1, text2) {
+ var text1Length, text2Length, textLength, best, length, pattern, found;
+
+ // Cache the text lengths to prevent multiple calls.
+ text1Length = text1.length;
+ text2Length = text2.length;
+
+ // Eliminate the null case.
+ if (text1Length === 0 || text2Length === 0) {
+ return 0;
+ }
+
+ // Truncate the longer string.
+ if (text1Length > text2Length) {
+ text1 = text1.substring(text1Length - text2Length);
+ } else if (text1Length < text2Length) {
+ text2 = text2.substring(0, text1Length);
+ }
+ textLength = Math.min(text1Length, text2Length);
+
+ // Quick check for the worst case.
+ if (text1 === text2) {
+ return textLength;
+ }
+
+ // Start by looking for a single character match
+ // and increase length until no match is found.
+ // Performance analysis: https://neil.fraser.name/news/2010/11/04/
+ best = 0;
+ length = 1;
+ while (true) {
+ pattern = text1.substring(textLength - length);
+ found = text2.indexOf(pattern);
+ if (found === -1) {
+ return best;
+ }
+ length += found;
+ if (found === 0 || text1.substring(textLength - length) === text2.substring(0, length)) {
+ best = length;
+ length++;
+ }
+ }
+ };
+
+ /**
+ * Split two texts into an array of strings. Reduce the texts to a string of
+ * hashes where each Unicode character represents one line.
+ * @param {string} text1 First string.
+ * @param {string} text2 Second string.
+ * @return {{chars1: string, chars2: string, lineArray: !Array.<string>}}
+ * An object containing the encoded text1, the encoded text2 and
+ * the array of unique strings.
+ * The zeroth element of the array of unique strings is intentionally blank.
+ * @private
+ */
+ DiffMatchPatch.prototype.diffLinesToChars = function (text1, text2) {
+ var lineArray, lineHash, chars1, chars2;
+ lineArray = []; // E.g. lineArray[4] === 'Hello\n'
+ lineHash = {}; // E.g. lineHash['Hello\n'] === 4
+
+ // '\x00' is a valid character, but various debuggers don't like it.
+ // So we'll insert a junk entry to avoid generating a null character.
+ lineArray[0] = "";
+
+ /**
+ * Split a text into an array of strings. Reduce the texts to a string of
+ * hashes where each Unicode character represents one line.
+ * Modifies linearray and linehash through being a closure.
+ * @param {string} text String to encode.
+ * @return {string} Encoded string.
+ * @private
+ */
+ function diffLinesToCharsMunge(text) {
+ var chars, lineStart, lineEnd, lineArrayLength, line;
+ chars = "";
+
+ // Walk the text, pulling out a substring for each line.
+ // text.split('\n') would would temporarily double our memory footprint.
+ // Modifying text would create many large strings to garbage collect.
+ lineStart = 0;
+ lineEnd = -1;
+
+ // Keeping our own length variable is faster than looking it up.
+ lineArrayLength = lineArray.length;
+ while (lineEnd < text.length - 1) {
+ lineEnd = text.indexOf("\n", lineStart);
+ if (lineEnd === -1) {
+ lineEnd = text.length - 1;
+ }
+ line = text.substring(lineStart, lineEnd + 1);
+ lineStart = lineEnd + 1;
+
+ var lineHashExists = lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) : lineHash[line] !== undefined;
+
+ if (lineHashExists) {
+ chars += String.fromCharCode(lineHash[line]);
+ } else {
+ chars += String.fromCharCode(lineArrayLength);
+ lineHash[line] = lineArrayLength;
+ lineArray[lineArrayLength++] = line;
+ }
+ }
+ return chars;
+ }
+
+ chars1 = diffLinesToCharsMunge(text1);
+ chars2 = diffLinesToCharsMunge(text2);
+ return {
+ chars1: chars1,
+ chars2: chars2,
+ lineArray: lineArray
+ };
+ };
+
+ /**
+ * Rehydrate the text in a diff from a string of line hashes to real lines of
+ * text.
+ * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
+ * @param {!Array.<string>} lineArray Array of unique strings.
+ * @private
+ */
+ DiffMatchPatch.prototype.diffCharsToLines = function (diffs, lineArray) {
+ var x, chars, text, y;
+ for (x = 0; x < diffs.length; x++) {
+ chars = diffs[x][1];
+ text = [];
+ for (y = 0; y < chars.length; y++) {
+ text[y] = lineArray[chars.charCodeAt(y)];
+ }
+ diffs[x][1] = text.join("");
+ }
+ };
+
+ /**
+ * Reorder and merge like edit sections. Merge equalities.
+ * Any edit section can move as long as it doesn't cross an equality.
+ * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
+ */
+ DiffMatchPatch.prototype.diffCleanupMerge = function (diffs) {
+ var pointer, countDelete, countInsert, textInsert, textDelete, commonlength, changes, diffPointer, position;
+ diffs.push([DIFF_EQUAL, ""]); // Add a dummy entry at the end.
+ pointer = 0;
+ countDelete = 0;
+ countInsert = 0;
+ textDelete = "";
+ textInsert = "";
+
+ while (pointer < diffs.length) {
+ switch (diffs[pointer][0]) {
+ case DIFF_INSERT:
+ countInsert++;
+ textInsert += diffs[pointer][1];
+ pointer++;
+ break;
+ case DIFF_DELETE:
+ countDelete++;
+ textDelete += diffs[pointer][1];
+ pointer++;
+ break;
+ case DIFF_EQUAL:
+
+ // Upon reaching an equality, check for prior redundancies.
+ if (countDelete + countInsert > 1) {
+ if (countDelete !== 0 && countInsert !== 0) {
+
+ // Factor out any common prefixes.
+ commonlength = this.diffCommonPrefix(textInsert, textDelete);
+ if (commonlength !== 0) {
+ if (pointer - countDelete - countInsert > 0 && diffs[pointer - countDelete - countInsert - 1][0] === DIFF_EQUAL) {
+ diffs[pointer - countDelete - countInsert - 1][1] += textInsert.substring(0, commonlength);
+ } else {
+ diffs.splice(0, 0, [DIFF_EQUAL, textInsert.substring(0, commonlength)]);
+ pointer++;
+ }
+ textInsert = textInsert.substring(commonlength);
+ textDelete = textDelete.substring(commonlength);
+ }
+
+ // Factor out any common suffixies.
+ commonlength = this.diffCommonSuffix(textInsert, textDelete);
+ if (commonlength !== 0) {
+ diffs[pointer][1] = textInsert.substring(textInsert.length - commonlength) + diffs[pointer][1];
+ textInsert = textInsert.substring(0, textInsert.length - commonlength);
+ textDelete = textDelete.substring(0, textDelete.length - commonlength);
+ }
+ }
+
+ // Delete the offending records and add the merged ones.
+ if (countDelete === 0) {
+ diffs.splice(pointer - countInsert, countDelete + countInsert, [DIFF_INSERT, textInsert]);
+ } else if (countInsert === 0) {
+ diffs.splice(pointer - countDelete, countDelete + countInsert, [DIFF_DELETE, textDelete]);
+ } else {
+ diffs.splice(pointer - countDelete - countInsert, countDelete + countInsert, [DIFF_DELETE, textDelete], [DIFF_INSERT, textInsert]);
+ }
+ pointer = pointer - countDelete - countInsert + (countDelete ? 1 : 0) + (countInsert ? 1 : 0) + 1;
+ } else if (pointer !== 0 && diffs[pointer - 1][0] === DIFF_EQUAL) {
+
+ // Merge this equality with the previous one.
+ diffs[pointer - 1][1] += diffs[pointer][1];
+ diffs.splice(pointer, 1);
+ } else {
+ pointer++;
+ }
+ countInsert = 0;
+ countDelete = 0;
+ textDelete = "";
+ textInsert = "";
+ break;
+ }
+ }
+ if (diffs[diffs.length - 1][1] === "") {
+ diffs.pop(); // Remove the dummy entry at the end.
+ }
+
+ // Second pass: look for single edits surrounded on both sides by equalities
+ // which can be shifted sideways to eliminate an equality.
+ // e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC
+ changes = false;
+ pointer = 1;
+
+ // Intentionally ignore the first and last element (don't need checking).
+ while (pointer < diffs.length - 1) {
+ if (diffs[pointer - 1][0] === DIFF_EQUAL && diffs[pointer + 1][0] === DIFF_EQUAL) {
+
+ diffPointer = diffs[pointer][1];
+ position = diffPointer.substring(diffPointer.length - diffs[pointer - 1][1].length);
+
+ // This is a single edit surrounded by equalities.
+ if (position === diffs[pointer - 1][1]) {
+
+ // Shift the edit over the previous equality.
+ diffs[pointer][1] = diffs[pointer - 1][1] + diffs[pointer][1].substring(0, diffs[pointer][1].length - diffs[pointer - 1][1].length);
+ diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1];
+ diffs.splice(pointer - 1, 1);
+ changes = true;
+ } else if (diffPointer.substring(0, diffs[pointer + 1][1].length) === diffs[pointer + 1][1]) {
+
+ // Shift the edit over the next equality.
+ diffs[pointer - 1][1] += diffs[pointer + 1][1];
+ diffs[pointer][1] = diffs[pointer][1].substring(diffs[pointer + 1][1].length) + diffs[pointer + 1][1];
+ diffs.splice(pointer + 1, 1);
+ changes = true;
+ }
+ }
+ pointer++;
+ }
+
+ // If shifts were made, the diff needs reordering and another shift sweep.
+ if (changes) {
+ this.diffCleanupMerge(diffs);
+ }
+ };
+
+ return function (o, n) {
+ var diff, output, text;
+ diff = new DiffMatchPatch();
+ output = diff.DiffMain(o, n);
+ diff.diffCleanupEfficiency(output);
+ text = diff.diffPrettyHtml(output);
+
+ return text;
+ };
+ }();
+
+}((function() { return this; }())));
diff --git a/src/tests/lib/vendor/sinon-2.0.0.js b/src/tests/lib/vendor/sinon-2.0.0.js
new file mode 100644
index 0000000..2b0d483
--- /dev/null
+++ b/src/tests/lib/vendor/sinon-2.0.0.js
@@ -0,0 +1,11586 @@
+/* Sinon.JS 2.0.0, 2017-03-15, @license BSD-3 */(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.sinon = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+"use strict";
+
+var match = require("./sinon/match");
+var deepEqual = require("./sinon/util/core/deep-equal");
+var deprecated = require("./sinon/util/core/deprecated");
+
+function exposeCoreUtils(target, utils) {
+ var keys = Object.keys(utils);
+
+ keys.forEach(function (key) {
+ var value = utils[key];
+
+ // allow deepEqual to check equality of matchers through dependency injection. Otherwise we get a circular
+ // dependency
+ if (key === "deepEqual") {
+ value = deepEqual.use(match);
+ }
+ if (typeof value === "function") {
+ value = deprecated.wrap(value, deprecated.defaultMsg(key));
+ }
+ target[key] = value;
+ });
+}
+
+function exposeEventTarget(target, eventTarget) {
+ var keys = Object.keys(eventTarget);
+
+ keys.forEach(function (key) {
+ target[key] = deprecated.wrap(eventTarget[key], deprecated.defaultMsg("EventTarget"));
+ });
+}
+
+// Expose internal utilities on `sinon` global for backwards compatibility.
+exposeCoreUtils(exports, require("./sinon/util/core/index"));
+
+exports.assert = require("./sinon/assert");
+exports.collection = require("./sinon/collection");
+exports.match = match;
+exports.spy = require("./sinon/spy");
+exports.spyCall = require("./sinon/call");
+exports.stub = require("./sinon/stub");
+exports.mock = require("./sinon/mock");
+exports.sandbox = require("./sinon/sandbox");
+exports.expectation = require("./sinon/mock-expectation");
+exports.createStubInstance = require("./sinon/stub").createStubInstance;
+
+var fakeTimers = require("./sinon/util/fake_timers");
+exports.useFakeTimers = fakeTimers.useFakeTimers;
+exports.clock = fakeTimers.clock;
+exports.timers = fakeTimers.timers;
+
+var event = require("./sinon/util/event");
+exports.Event = deprecated.wrap(event.Event, deprecated.defaultMsg("Event"));
+exports.CustomEvent = deprecated.wrap(event.CustomEvent, deprecated.defaultMsg("CustomEvent"));
+exports.ProgressEvent = deprecated.wrap(event.ProgressEvent, deprecated.defaultMsg("ProgressEvent"));
+exports.EventTarget = {};
+exposeEventTarget(exports.EventTarget, event.EventTarget);
+
+var fakeXhr = require("./sinon/util/fake_xml_http_request");
+exports.xhr = fakeXhr.xhr;
+exports.FakeXMLHttpRequest = fakeXhr.FakeXMLHttpRequest;
+exports.useFakeXMLHttpRequest = fakeXhr.useFakeXMLHttpRequest;
+
+exports.fakeServer = require("./sinon/util/fake_server");
+exports.fakeServerWithClock = require("./sinon/util/fake_server_with_clock");
+
+var behavior = require("./sinon/behavior");
+
+exports.addBehavior = function (name, fn) {
+ behavior.addBehavior(exports.stub, name, fn);
+};
+
+},{"./sinon/assert":2,"./sinon/behavior":3,"./sinon/call":5,"./sinon/collection":7,"./sinon/match":10,"./sinon/mock":12,"./sinon/mock-expectation":11,"./sinon/sandbox":13,"./sinon/spy":15,"./sinon/stub":19,"./sinon/util/core/deep-equal":22,"./sinon/util/core/deprecated":24,"./sinon/util/core/index":32,"./sinon/util/event":42,"./sinon/util/fake_server":43,"./sinon/util/fake_server_with_clock":44,"./sinon/util/fake_timers":45,"./sinon/util/fake_xml_http_request":46}],2:[function(require,module,exports){
+(function (global){
+"use strict";
+
+var calledInOrder = require("./util/core/called-in-order");
+var orderByFirstCall = require("./util/core/order-by-first-call");
+var timesInWords = require("./util/core/times-in-words");
+var format = require("./util/core/format");
+var sinonMatch = require("./match");
+
+var slice = Array.prototype.slice;
+
+var assert;
+
+function verifyIsStub() {
+ var args = Array.prototype.slice.call(arguments);
+
+ args.forEach(function (method) {
+ if (!method) {
+ assert.fail("fake is not a spy");
+ }
+
+ if (method.proxy && method.proxy.isSinonProxy) {
+ verifyIsStub(method.proxy);
+ } else {
+ if (typeof method !== "function") {
+ assert.fail(method + " is not a function");
+ }
+
+ if (typeof method.getCall !== "function") {
+ assert.fail(method + " is not stubbed");
+ }
+ }
+ });
+}
+
+function verifyIsValidAssertion(assertionMethod, assertionArgs) {
+ switch (assertionMethod) {
+ case "notCalled":
+ case "called":
+ case "calledOnce":
+ case "calledTwice":
+ case "calledThrice":
+ if (assertionArgs.length !== 0) {
+ assert.fail(assertionMethod +
+ " takes 1 argument but was called with " + (assertionArgs.length + 1) + " arguments");
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+function failAssertion(object, msg) {
+ object = object || global;
+ var failMethod = object.fail || assert.fail;
+ failMethod.call(object, msg);
+}
+
+function mirrorPropAsAssertion(name, method, message) {
+ if (arguments.length === 2) {
+ message = method;
+ method = name;
+ }
+
+ assert[name] = function (fake) {
+ verifyIsStub(fake);
+
+ var args = slice.call(arguments, 1);
+ var failed = false;
+
+ verifyIsValidAssertion(name, args);
+
+ if (typeof method === "function") {
+ failed = !method(fake);
+ } else {
+ failed = typeof fake[method] === "function" ?
+ !fake[method].apply(fake, args) : !fake[method];
+ }
+
+ if (failed) {
+ failAssertion(this, (fake.printf || fake.proxy.printf).apply(fake, [message].concat(args)));
+ } else {
+ assert.pass(name);
+ }
+ };
+}
+
+function exposedName(prefix, prop) {
+ return !prefix || /^fail/.test(prop) ? prop :
+ prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);
+}
+
+assert = {
+ failException: "AssertError",
+
+ fail: function fail(message) {
+ var error = new Error(message);
+ error.name = this.failException || assert.failException;
+
+ throw error;
+ },
+
+ pass: function pass() {},
+
+ callOrder: function assertCallOrder() {
+ verifyIsStub.apply(null, arguments);
+ var expected = "";
+ var actual = "";
+
+ if (!calledInOrder(arguments)) {
+ try {
+ expected = [].join.call(arguments, ", ");
+ var calls = slice.call(arguments);
+ var i = calls.length;
+ while (i) {
+ if (!calls[--i].called) {
+ calls.splice(i, 1);
+ }
+ }
+ actual = orderByFirstCall(calls).join(", ");
+ } catch (e) {
+ // If this fails, we'll just fall back to the blank string
+ }
+
+ failAssertion(this, "expected " + expected + " to be " +
+ "called in order but were called as " + actual);
+ } else {
+ assert.pass("callOrder");
+ }
+ },
+
+ callCount: function assertCallCount(method, count) {
+ verifyIsStub(method);
+
+ if (method.callCount !== count) {
+ var msg = "expected %n to be called " + timesInWords(count) +
+ " but was called %c%C";
+ failAssertion(this, method.printf(msg));
+ } else {
+ assert.pass("callCount");
+ }
+ },
+
+ expose: function expose(target, options) {
+ if (!target) {
+ throw new TypeError("target is null or undefined");
+ }
+
+ var o = options || {};
+ var prefix = typeof o.prefix === "undefined" && "assert" || o.prefix;
+ var includeFail = typeof o.includeFail === "undefined" || !!o.includeFail;
+ var instance = this;
+
+ Object.keys(instance).forEach(function (method) {
+ if (method !== "expose" && (includeFail || !/^(fail)/.test(method))) {
+ target[exposedName(prefix, method)] = instance[method];
+ }
+ });
+
+ return target;
+ },
+
+ match: function match(actual, expectation) {
+ var matcher = sinonMatch(expectation);
+ if (matcher.test(actual)) {
+ assert.pass("match");
+ } else {
+ var formatted = [
+ "expected value to match",
+ " expected = " + format(expectation),
+ " actual = " + format(actual)
+ ];
+
+ failAssertion(this, formatted.join("\n"));
+ }
+ }
+};
+
+mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called");
+mirrorPropAsAssertion("notCalled", function (spy) {
+ return !spy.called;
+}, "expected %n to not have been called but was called %c%C");
+mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C");
+mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C");
+mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C");
+mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t");
+mirrorPropAsAssertion(
+ "alwaysCalledOn",
+ "expected %n to always be called with %1 as this but was called with %t"
+);
+mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new");
+mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new");
+mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %D");
+mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %D");
+mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %D");
+mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %D");
+mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %D");
+mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %D");
+mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C");
+mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C");
+mirrorPropAsAssertion("threw", "%n did not throw exception%C");
+mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C");
+
+module.exports = assert;
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+
+},{"./match":10,"./util/core/called-in-order":21,"./util/core/format":27,"./util/core/order-by-first-call":35,"./util/core/times-in-words":37}],3:[function(require,module,exports){
+(function (process){
+"use strict";
+
+var extend = require("./util/core/extend");
+var functionName = require("./util/core/function-name");
+var valueToString = require("./util/core/value-to-string");
+
+var slice = Array.prototype.slice;
+var join = Array.prototype.join;
+var useLeftMostCallback = -1;
+var useRightMostCallback = -2;
+
+var nextTick = (function () {
+ if (typeof process === "object" && typeof process.nextTick === "function") {
+ return process.nextTick;
+ }
+
+ if (typeof setImmediate === "function") {
+ return setImmediate;
+ }
+
+ return function (callback) {
+ setTimeout(callback, 0);
+ };
+})();
+
+function getCallback(behavior, args) {
+ var callArgAt = behavior.callArgAt;
+
+ if (callArgAt >= 0) {
+ return args[callArgAt];
+ }
+
+ var argumentList;
+
+ if (callArgAt === useLeftMostCallback) {
+ argumentList = args;
+ }
+
+ if (callArgAt === useRightMostCallback) {
+ argumentList = slice.call(args).reverse();
+ }
+
+ var callArgProp = behavior.callArgProp;
+
+ for (var i = 0, l = argumentList.length; i < l; ++i) {
+ if (!callArgProp && typeof argumentList[i] === "function") {
+ return argumentList[i];
+ }
+
+ if (callArgProp && argumentList[i] &&
+ typeof argumentList[i][callArgProp] === "function") {
+ return argumentList[i][callArgProp];
+ }
+ }
+
+ return null;
+}
+
+function getCallbackError(behavior, func, args) {
+ if (behavior.callArgAt < 0) {
+ var msg;
+
+ if (behavior.callArgProp) {
+ msg = functionName(behavior.stub) +
+ " expected to yield to '" + valueToString(behavior.callArgProp) +
+ "', but no object with such a property was passed.";
+ } else {
+ msg = functionName(behavior.stub) +
+ " expected to yield, but no callback was passed.";
+ }
+
+ if (args.length > 0) {
+ msg += " Received [" + join.call(args, ", ") + "]";
+ }
+
+ return msg;
+ }
+
+ return "argument at index " + behavior.callArgAt + " is not a function: " + func;
+}
+
+function callCallback(behavior, args) {
+ if (typeof behavior.callArgAt === "number") {
+ var func = getCallback(behavior, args);
+
+ if (typeof func !== "function") {
+ throw new TypeError(getCallbackError(behavior, func, args));
+ }
+
+ if (behavior.callbackAsync) {
+ nextTick(function () {
+ func.apply(behavior.callbackContext, behavior.callbackArguments);
+ });
+ } else {
+ func.apply(behavior.callbackContext, behavior.callbackArguments);
+ }
+ }
+}
+
+var proto = {
+ create: function create(stub) {
+ var behavior = extend({}, proto);
+ delete behavior.create;
+ delete behavior.addBehavior;
+ delete behavior.createBehavior;
+ behavior.stub = stub;
+
+ return behavior;
+ },
+
+ isPresent: function isPresent() {
+ return (typeof this.callArgAt === "number" ||
+ this.exception ||
+ typeof this.returnArgAt === "number" ||
+ this.returnThis ||
+ this.fakeFn ||
+ this.returnValueDefined);
+ },
+
+ invoke: function invoke(context, args) {
+ callCallback(this, args);
+
+ if (this.exception) {
+ throw this.exception;
+ } else if (typeof this.returnArgAt === "number") {
+ return args[this.returnArgAt];
+ } else if (this.returnThis) {
+ return context;
+ } else if (this.fakeFn) {
+ return this.fakeFn.apply(context, args);
+ } else if (this.resolve) {
+ return Promise.resolve(this.returnValue);
+ } else if (this.reject) {
+ return Promise.reject(this.returnValue);
+ } else if (this.callsThrough) {
+ return this.stub.wrappedMethod.apply(context, args);
+ }
+ return this.returnValue;
+ },
+
+ onCall: function onCall(index) {
+ return this.stub.onCall(index);
+ },
+
+ onFirstCall: function onFirstCall() {
+ return this.stub.onFirstCall();
+ },
+
+ onSecondCall: function onSecondCall() {
+ return this.stub.onSecondCall();
+ },
+
+ onThirdCall: function onThirdCall() {
+ return this.stub.onThirdCall();
+ },
+
+ withArgs: function withArgs(/* arguments */) {
+ throw new Error(
+ "Defining a stub by invoking \"stub.onCall(...).withArgs(...)\" " +
+ "is not supported. Use \"stub.withArgs(...).onCall(...)\" " +
+ "to define sequential behavior for calls with certain arguments."
+ );
+ }
+};
+
+function createAsyncVersion(syncFnName) {
+ return function () {
+ var result = this[syncFnName].apply(this, arguments);
+ this.callbackAsync = true;
+ return result;
+ };
+}
+
+// create asynchronous versions of callsArg* and yields* methods
+Object.keys(proto).forEach(function (method) {
+ // need to avoid creating anotherasync versions of the newly added async methods
+ if (method.match(/^(callsArg|yields)/) && !method.match(/Async/)) {
+ proto[method + "Async"] = createAsyncVersion(method);
+ }
+});
+
+function createBehavior(behaviorMethod) {
+ return function () {
+ this.defaultBehavior = this.defaultBehavior || proto.create(this);
+ this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments);
+ return this;
+ };
+}
+
+function addBehavior(stub, name, fn) {
+ proto[name] = function () {
+ fn.apply(this, [this].concat([].slice.call(arguments)));
+ return this.stub || this;
+ };
+
+ stub[name] = createBehavior(name);
+}
+
+proto.addBehavior = addBehavior;
+proto.createBehavior = createBehavior;
+module.exports = proto;
+
+}).call(this,require('_process'))
+
+},{"./util/core/extend":26,"./util/core/function-name":28,"./util/core/value-to-string":39,"_process":67}],4:[function(require,module,exports){
+/*global Blob */
+"use strict";
+
+exports.isSupported = (function () {
+ try {
+ return !!new Blob();
+ } catch (e) {
+ return false;
+ }
+}());
+
+},{}],5:[function(require,module,exports){
+"use strict";
+
+var sinonMatch = require("./match");
+var deepEqual = require("./util/core/deep-equal").use(sinonMatch);
+var functionName = require("./util/core/function-name");
+var sinonFormat = require("./util/core/format");
+var valueToString = require("./util/core/value-to-string");
+var slice = Array.prototype.slice;
+
+function throwYieldError(proxy, text, args) {
+ var msg = functionName(proxy) + text;
+ if (args.length) {
+ msg += " Received [" + slice.call(args).join(", ") + "]";
+ }
+ throw new Error(msg);
+}
+
+var callProto = {
+ calledOn: function calledOn(thisValue) {
+ if (sinonMatch && sinonMatch.isMatcher(thisValue)) {
+ return thisValue.test(this.thisValue);
+ }
+ return this.thisValue === thisValue;
+ },
+
+ calledWith: function calledWith() {
+ var self = this;
+ var calledWithArgs = slice.call(arguments);
+
+ if (calledWithArgs.length > self.args.length) {
+ return false;
+ }
+
+ return calledWithArgs.reduce(function (prev, arg, i) {
+ return prev && deepEqual(arg, self.args[i]);
+ }, true);
+ },
+
+ calledWithMatch: function calledWithMatch() {
+ var self = this;
+ var calledWithMatchArgs = slice.call(arguments);
+
+ if (calledWithMatchArgs.length > self.args.length) {
+ return false;
+ }
+
+ return calledWithMatchArgs.reduce(function (prev, expectation, i) {
+ var actual = self.args[i];
+
+ return prev && (sinonMatch && sinonMatch(expectation).test(actual));
+ }, true);
+ },
+
+ calledWithExactly: function calledWithExactly() {
+ return arguments.length === this.args.length &&
+ this.calledWith.apply(this, arguments);
+ },
+
+ notCalledWith: function notCalledWith() {
+ return !this.calledWith.apply(this, arguments);
+ },
+
+ notCalledWithMatch: function notCalledWithMatch() {
+ return !this.calledWithMatch.apply(this, arguments);
+ },
+
+ returned: function returned(value) {
+ return deepEqual(value, this.returnValue);
+ },
+
+ threw: function threw(error) {
+ if (typeof error === "undefined" || !this.exception) {
+ return !!this.exception;
+ }
+
+ return this.exception === error || this.exception.name === error;
+ },
+
+ calledWithNew: function calledWithNew() {
+ return this.proxy.prototype && this.thisValue instanceof this.proxy;
+ },
+
+ calledBefore: function (other) {
+ return this.callId < other.callId;
+ },
+
+ calledAfter: function (other) {
+ return this.callId > other.callId;
+ },
+
+ callArg: function (pos) {
+ this.args[pos]();
+ },
+
+ callArgOn: function (pos, thisValue) {
+ this.args[pos].apply(thisValue);
+ },
+
+ callArgWith: function (pos) {
+ this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1)));
+ },
+
+ callArgOnWith: function (pos, thisValue) {
+ var args = slice.call(arguments, 2);
+ this.args[pos].apply(thisValue, args);
+ },
+
+ "yield": function () {
+ this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0)));
+ },
+
+ yieldOn: function (thisValue) {
+ var args = slice.call(this.args);
+ var yieldFn = args.filter(function (arg) {
+ return typeof arg === "function";
+ })[0];
+
+ if (!yieldFn) {
+ throwYieldError(this.proxy, " cannot yield since no callback was passed.", args);
+ }
+
+ yieldFn.apply(thisValue, slice.call(arguments, 1));
+ },
+
+ yieldTo: function (prop) {
+ this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1)));
+ },
+
+ yieldToOn: function (prop, thisValue) {
+ var args = slice.call(this.args);
+ var yieldArg = args.filter(function (arg) {
+ return arg && typeof arg[prop] === "function";
+ })[0];
+ var yieldFn = yieldArg && yieldArg[prop];
+
+ if (!yieldFn) {
+ throwYieldError(this.proxy, " cannot yield to '" + valueToString(prop) +
+ "' since no callback was passed.", args);
+ }
+
+ yieldFn.apply(thisValue, slice.call(arguments, 2));
+ },
+
+ toString: function () {
+ var callStr = this.proxy ? this.proxy.toString() + "(" : "";
+ var formattedArgs;
+
+ if (!this.args) {
+ return ":(";
+ }
+
+ formattedArgs = slice.call(this.args).map(function (arg) {
+ return sinonFormat(arg);
+ });
+
+ callStr = callStr + formattedArgs.join(", ") + ")";
+
+ if (typeof this.returnValue !== "undefined") {
+ callStr += " => " + sinonFormat(this.returnValue);
+ }
+
+ if (this.exception) {
+ callStr += " !" + this.exception.name;
+
+ if (this.exception.message) {
+ callStr += "(" + this.exception.message + ")";
+ }
+ }
+ if (this.stack) {
+ // Omit the error message and the two top stack frames in sinon itself:
+ callStr += this.stack.split("\n")[3].replace(/^\s*(?:at\s+|@)?/, " at ");
+ }
+
+ return callStr;
+ }
+};
+Object.defineProperty(callProto, "stack", {
+ enumerable: true,
+ configurable: true,
+ get: function () {
+ return this.errorWithCallStack && this.errorWithCallStack.stack || "";
+ }
+});
+
+callProto.invokeCallback = callProto.yield;
+
+function createSpyCall(spy, thisValue, args, returnValue, exception, id, errorWithCallStack) {
+ if (typeof id !== "number") {
+ throw new TypeError("Call id is not a number");
+ }
+ var proxyCall = Object.create(callProto);
+ proxyCall.proxy = spy;
+ proxyCall.thisValue = thisValue;
+ proxyCall.args = args;
+ proxyCall.returnValue = returnValue;
+ proxyCall.exception = exception;
+ proxyCall.callId = id;
+ proxyCall.errorWithCallStack = errorWithCallStack;
+
+ return proxyCall;
+}
+createSpyCall.toString = callProto.toString; // used by mocks
+
+module.exports = createSpyCall;
+
+},{"./match":10,"./util/core/deep-equal":22,"./util/core/format":27,"./util/core/function-name":28,"./util/core/value-to-string":39}],6:[function(require,module,exports){
+"use strict";
+
+var walk = require("./util/core/walk");
+var getPropertyDescriptor = require("./util/core/get-property-descriptor");
+
+function collectMethod(methods, object, prop, propOwner) {
+ if (
+ typeof getPropertyDescriptor(propOwner, prop).value === "function" &&
+ object.hasOwnProperty(prop)
+ ) {
+ methods.push(object[prop]);
+ }
+}
+
+// This function returns an array of all the own methods on the passed object
+function collectOwnMethods(object) {
+ var methods = [];
+
+ walk(object, collectMethod.bind(null, methods, object));
+
+ return methods;
+}
+
+module.exports = collectOwnMethods;
+
+},{"./util/core/get-property-descriptor":31,"./util/core/walk":40}],7:[function(require,module,exports){
+"use strict";
+
+var sinonSpy = require("./spy");
+var sinonStub = require("./stub");
+var sinonMock = require("./mock");
+var throwOnFalsyObject = require("./throw-on-falsy-object");
+var collectOwnMethods = require("./collect-own-methods");
+var stubNonFunctionProperty = require("./stub-non-function-property");
+
+var push = [].push;
+
+function getFakes(fakeCollection) {
+ if (!fakeCollection.fakes) {
+ fakeCollection.fakes = [];
+ }
+
+ return fakeCollection.fakes;
+}
+
+function each(fakeCollection, method) {
+ var fakes = getFakes(fakeCollection);
+ var matchingFakes = fakes.filter(function (fake) {
+ return typeof fake[method] === "function";
+ });
+
+ matchingFakes.forEach(function (fake) {
+ fake[method]();
+ });
+}
+
+var collection = {
+ verify: function verify() {
+ each(this, "verify");
+ },
+
+ restore: function restore() {
+ each(this, "restore");
+ this.fakes = [];
+ },
+
+ reset: function reset() {
+ each(this, "reset");
+ },
+
+ resetBehavior: function resetBehavior() {
+ each(this, "resetBehavior");
+ },
+
+ resetHistory: function resetHistory() {
+ each(this, "resetHistory");
+ },
+
+ verifyAndRestore: function verifyAndRestore() {
+ var exception;
+
+ try {
+ this.verify();
+ } catch (e) {
+ exception = e;
+ }
+
+ this.restore();
+
+ if (exception) {
+ throw exception;
+ }
+ },
+
+ add: function add(fake) {
+ push.call(getFakes(this), fake);
+ return fake;
+ },
+
+ spy: function spy() {
+ return this.add(sinonSpy.apply(sinonSpy, arguments));
+ },
+
+ stub: function stub(object, property/*, value*/) {
+ throwOnFalsyObject.apply(null, arguments);
+
+ var isStubbingEntireObject = typeof property === "undefined" && typeof object === "object";
+ var isStubbingNonFunctionProperty = property && typeof object[property] !== "function";
+ var stubbed = isStubbingNonFunctionProperty ?
+ stubNonFunctionProperty.apply(null, arguments) :
+ sinonStub.apply(null, arguments);
+
+ if (isStubbingEntireObject) {
+ collectOwnMethods(stubbed).forEach(this.add.bind(this));
+ } else {
+ this.add(stubbed);
+ }
+
+ return stubbed;
+ },
+
+ mock: function mock() {
+ return this.add(sinonMock.apply(null, arguments));
+ },
+
+ inject: function inject(obj) {
+ var col = this;
+
+ obj.spy = function () {
+ return col.spy.apply(col, arguments);
+ };
+
+ obj.stub = function () {
+ return col.stub.apply(col, arguments);
+ };
+
+ obj.mock = function () {
+ return col.mock.apply(col, arguments);
+ };
+
+ return obj;
+ }
+};
+
+module.exports = collection;
+
+},{"./collect-own-methods":6,"./mock":12,"./spy":15,"./stub":19,"./stub-non-function-property":18,"./throw-on-falsy-object":20}],8:[function(require,module,exports){
+(function (process){
+"use strict";
+
+var canColor = typeof process !== "undefined";
+
+function colorize(str, color) {
+ if (!canColor) {
+ return str;
+ }
+
+ return "\x1b[" + color + "m" + str + "\x1b[0m";
+}
+
+exports.red = function (str) {
+ return colorize(str, 31);
+};
+
+exports.green = function (str) {
+ return colorize(str, 32);
+};
+
+}).call(this,require('_process'))
+
+},{"_process":67}],9:[function(require,module,exports){
+"use strict";
+
+var slice = [].slice;
+var useLeftMostCallback = -1;
+var useRightMostCallback = -2;
+
+function throwsException(fake, error, message) {
+ if (typeof error === "string") {
+ fake.exception = new Error(message || "");
+ fake.exception.name = error;
+ } else if (!error) {
+ fake.exception = new Error("Error");
+ } else {
+ fake.exception = error;
+ }
+}
+
+module.exports = {
+ callsFake: function callsFake(fake, fn) {
+ fake.fakeFn = fn;
+ },
+
+ callsArg: function callsArg(fake, pos) {
+ if (typeof pos !== "number") {
+ throw new TypeError("argument index is not number");
+ }
+
+ fake.callArgAt = pos;
+ fake.callbackArguments = [];
+ fake.callbackContext = undefined;
+ fake.callArgProp = undefined;
+ fake.callbackAsync = false;
+ },
+
+ callsArgOn: function callsArgOn(fake, pos, context) {
+ if (typeof pos !== "number") {
+ throw new TypeError("argument index is not number");
+ }
+
+ fake.callArgAt = pos;
+ fake.callbackArguments = [];
+ fake.callbackContext = context;
+ fake.callArgProp = undefined;
+ fake.callbackAsync = false;
+ },
+
+ callsArgWith: function callsArgWith(fake, pos) {
+ if (typeof pos !== "number") {
+ throw new TypeError("argument index is not number");
+ }
+
+ fake.callArgAt = pos;
+ fake.callbackArguments = slice.call(arguments, 2);
+ fake.callbackContext = undefined;
+ fake.callArgProp = undefined;
+ fake.callbackAsync = false;
+ },
+
+ callsArgOnWith: function callsArgWith(fake, pos, context) {
+ if (typeof pos !== "number") {
+ throw new TypeError("argument index is not number");
+ }
+
+ fake.callArgAt = pos;
+ fake.callbackArguments = slice.call(arguments, 3);
+ fake.callbackContext = context;
+ fake.callArgProp = undefined;
+ fake.callbackAsync = false;
+ },
+
+ yields: function (fake) {
+ fake.callArgAt = useLeftMostCallback;
+ fake.callbackArguments = slice.call(arguments, 1);
+ fake.callbackContext = undefined;
+ fake.callArgProp = undefined;
+ fake.callbackAsync = false;
+ },
+
+ yieldsRight: function (fake) {
+ fake.callArgAt = useRightMostCallback;
+ fake.callbackArguments = slice.call(arguments, 1);
+ fake.callbackContext = undefined;
+ fake.callArgProp = undefined;
+ fake.callbackAsync = false;
+ },
+
+ yieldsOn: function (fake, context) {
+ fake.callArgAt = useLeftMostCallback;
+ fake.callbackArguments = slice.call(arguments, 2);
+ fake.callbackContext = context;
+ fake.callArgProp = undefined;
+ fake.callbackAsync = false;
+ },
+
+ yieldsTo: function (fake, prop) {
+ fake.callArgAt = useLeftMostCallback;
+ fake.callbackArguments = slice.call(arguments, 2);
+ fake.callbackContext = undefined;
+ fake.callArgProp = prop;
+ fake.callbackAsync = false;
+ },
+
+ yieldsToOn: function (fake, prop, context) {
+ fake.callArgAt = useLeftMostCallback;
+ fake.callbackArguments = slice.call(arguments, 3);
+ fake.callbackContext = context;
+ fake.callArgProp = prop;
+ fake.callbackAsync = false;
+ },
+
+ throws: throwsException,
+ throwsException: throwsException,
+
+ returns: function returns(fake, value) {
+ fake.returnValue = value;
+ fake.resolve = false;
+ fake.reject = false;
+ fake.returnValueDefined = true;
+ fake.exception = undefined;
+ fake.fakeFn = undefined;
+ },
+
+ returnsArg: function returnsArg(fake, pos) {
+ if (typeof pos !== "number") {
+ throw new TypeError("argument index is not number");
+ }
+
+ fake.returnArgAt = pos;
+ },
+
+ returnsThis: function returnsThis(fake) {
+ fake.returnThis = true;
+ },
+
+ resolves: function resolves(fake, value) {
+ fake.returnValue = value;
+ fake.resolve = true;
+ fake.reject = false;
+ fake.returnValueDefined = true;
+ fake.exception = undefined;
+ fake.fakeFn = undefined;
+ },
+
+ rejects: function rejects(fake, error, message) {
+ var reason;
+ if (typeof error === "string") {
+ reason = new Error(message || "");
+ reason.name = error;
+ } else if (!error) {
+ reason = new Error("Error");
+ } else {
+ reason = error;
+ }
+ fake.returnValue = reason;
+ fake.resolve = false;
+ fake.reject = true;
+ fake.returnValueDefined = true;
+ fake.exception = undefined;
+ fake.fakeFn = undefined;
+
+ return fake;
+ },
+
+ callThrough: function callThrough(fake) {
+ fake.callsThrough = true;
+ },
+
+ get: function get(fake, getterFunction) {
+ var rootStub = fake.stub || fake;
+
+ Object.defineProperty(rootStub.rootObj, rootStub.propName, {
+ get: getterFunction
+ });
+
+ return fake;
+ },
+
+ set: function set(fake, setterFunction) {
+ var rootStub = fake.stub || fake;
+
+ Object.defineProperty(rootStub.rootObj, rootStub.propName, { // eslint-disable-line accessor-pairs
+ set: setterFunction
+ });
+
+ return fake;
+ }
+};
+
+function createAsyncVersion(syncFnName) {
+ return function () {
+ var result = module.exports[syncFnName].apply(this, arguments);
+ this.callbackAsync = true;
+ return result;
+ };
+}
+
+// create asynchronous versions of callsArg* and yields* methods
+Object.keys(module.exports).forEach(function (method) {
+ // need to avoid creating anotherasync versions of the newly added async methods
+ if (method.match(/^(callsArg|yields)/) && !method.match(/Async/)) {
+ module.exports[method + "Async"] = createAsyncVersion(method);
+ }
+});
+
+},{}],10:[function(require,module,exports){
+"use strict";
+
+var deepEqual = require("./util/core/deep-equal").use(match); // eslint-disable-line no-use-before-define
+var every = require("./util/core/every");
+var functionName = require("./util/core/function-name");
+var iterableToString = require("./util/core/iterable-to-string");
+var typeOf = require("./util/core/typeOf");
+var valueToString = require("./util/core/value-to-string");
+
+var indexOf = Array.prototype.indexOf;
+
+function assertType(value, type, name) {
+ var actual = typeOf(value);
+ if (actual !== type) {
+ throw new TypeError("Expected type of " + name + " to be " +
+ type + ", but was " + actual);
+ }
+}
+
+var matcher = {
+ toString: function () {
+ return this.message;
+ }
+};
+
+function isMatcher(object) {
+ return matcher.isPrototypeOf(object);
+}
+
+function matchObject(expectation, actual) {
+ if (actual === null || actual === undefined) {
+ return false;
+ }
+
+ return Object.keys(expectation).every(function (key) {
+ var exp = expectation[key];
+ var act = actual[key];
+
+ if (isMatcher(exp)) {
+ if (!exp.test(act)) {
+ return false;
+ }
+ } else if (typeOf(exp) === "object") {
+ if (!matchObject(exp, act)) {
+ return false;
+ }
+ } else if (!deepEqual(exp, act)) {
+ return false;
+ }
+
+ return true;
+ });
+}
+
+var TYPE_MAP = {
+ "function": function (m, expectation, message) {
+ m.test = expectation;
+ m.message = message || "match(" + functionName(expectation) + ")";
+ },
+ number: function (m, expectation) {
+ m.test = function (actual) {
+ // we need type coercion here
+ return expectation == actual; // eslint-disable-line eqeqeq
+ };
+ },
+ object: function (m, expectation) {
+ var array = [];
+
+ if (typeof expectation.test === "function") {
+ m.test = function (actual) {
+ return expectation.test(actual) === true;
+ };
+ m.message = "match(" + functionName(expectation.test) + ")";
+ return m;
+ }
+
+ array = Object.keys(expectation).map(function (key) {
+ return key + ": " + valueToString(expectation[key]);
+ });
+
+ m.test = function (actual) {
+ return matchObject(expectation, actual);
+ };
+ m.message = "match(" + array.join(", ") + ")";
+
+ return m;
+ },
+ regexp: function (m, expectation) {
+ m.test = function (actual) {
+ return typeof actual === "string" && expectation.test(actual);
+ };
+ },
+ string: function (m, expectation) {
+ m.test = function (actual) {
+ return typeof actual === "string" && actual.indexOf(expectation) !== -1;
+ };
+ m.message = "match(\"" + expectation + "\")";
+ }
+};
+
+function match(expectation, message) {
+ var m = Object.create(matcher);
+ var type = typeOf(expectation);
+
+ if (type in TYPE_MAP) {
+ TYPE_MAP[type](m, expectation, message);
+ } else {
+ m.test = function (actual) {
+ return deepEqual(expectation, actual);
+ };
+ }
+
+ if (!m.message) {
+ m.message = "match(" + valueToString(expectation) + ")";
+ }
+
+ return m;
+}
+
+matcher.or = function (m2) {
+ if (!arguments.length) {
+ throw new TypeError("Matcher expected");
+ } else if (!isMatcher(m2)) {
+ m2 = match(m2);
+ }
+ var m1 = this;
+ var or = Object.create(matcher);
+ or.test = function (actual) {
+ return m1.test(actual) || m2.test(actual);
+ };
+ or.message = m1.message + ".or(" + m2.message + ")";
+ return or;
+};
+
+matcher.and = function (m2) {
+ if (!arguments.length) {
+ throw new TypeError("Matcher expected");
+ } else if (!isMatcher(m2)) {
+ m2 = match(m2);
+ }
+ var m1 = this;
+ var and = Object.create(matcher);
+ and.test = function (actual) {
+ return m1.test(actual) && m2.test(actual);
+ };
+ and.message = m1.message + ".and(" + m2.message + ")";
+ return and;
+};
+
+match.isMatcher = isMatcher;
+
+match.any = match(function () {
+ return true;
+}, "any");
+
+match.defined = match(function (actual) {
+ return actual !== null && actual !== undefined;
+}, "defined");
+
+match.truthy = match(function (actual) {
+ return !!actual;
+}, "truthy");
+
+match.falsy = match(function (actual) {
+ return !actual;
+}, "falsy");
+
+match.same = function (expectation) {
+ return match(function (actual) {
+ return expectation === actual;
+ }, "same(" + valueToString(expectation) + ")");
+};
+
+match.typeOf = function (type) {
+ assertType(type, "string", "type");
+ return match(function (actual) {
+ return typeOf(actual) === type;
+ }, "typeOf(\"" + type + "\")");
+};
+
+match.instanceOf = function (type) {
+ assertType(type, "function", "type");
+ return match(function (actual) {
+ return actual instanceof type;
+ }, "instanceOf(" + functionName(type) + ")");
+};
+
+function createPropertyMatcher(propertyTest, messagePrefix) {
+ return function (property, value) {
+ assertType(property, "string", "property");
+ var onlyProperty = arguments.length === 1;
+ var message = messagePrefix + "(\"" + property + "\"";
+ if (!onlyProperty) {
+ message += ", " + valueToString(value);
+ }
+ message += ")";
+ return match(function (actual) {
+ if (actual === undefined || actual === null ||
+ !propertyTest(actual, property)) {
+ return false;
+ }
+ return onlyProperty || deepEqual(value, actual[property]);
+ }, message);
+ };
+}
+
+match.has = createPropertyMatcher(function (actual, property) {
+ if (typeof actual === "object") {
+ return property in actual;
+ }
+ return actual[property] !== undefined;
+}, "has");
+
+match.hasOwn = createPropertyMatcher(function (actual, property) {
+ return actual.hasOwnProperty(property);
+}, "hasOwn");
+
+match.array = match.typeOf("array");
+
+match.array.deepEquals = function (expectation) {
+ return match(function (actual) {
+ // Comparing lengths is the fastest way to spot a difference before iterating through every item
+ var sameLength = actual.length === expectation.length;
+ return typeOf(actual) === "array" && sameLength && every(actual, function (element, index) {
+ return expectation[index] === element;
+ });
+ }, "deepEquals([" + iterableToString(expectation) + "])");
+};
+
+match.array.startsWith = function (expectation) {
+ return match(function (actual) {
+ return typeOf(actual) === "array" && every(expectation, function (expectedElement, index) {
+ return actual[index] === expectedElement;
+ });
+ }, "startsWith([" + iterableToString(expectation) + "])");
+};
+
+match.array.endsWith = function (expectation) {
+ return match(function (actual) {
+ // This indicates the index in which we should start matching
+ var offset = actual.length - expectation.length;
+
+ return typeOf(actual) === "array" && every(expectation, function (expectedElement, index) {
+ return actual[offset + index] === expectedElement;
+ });
+ }, "endsWith([" + iterableToString(expectation) + "])");
+};
+
+match.array.contains = function (expectation) {
+ return match(function (actual) {
+ return typeOf(actual) === "array" && every(expectation, function (expectedElement) {
+ return indexOf.call(actual, expectedElement) !== -1;
+ });
+ }, "contains([" + iterableToString(expectation) + "])");
+};
+
+match.map = match.typeOf("map");
+
+match.map.deepEquals = function mapDeepEquals(expectation) {
+ return match(function (actual) {
+ // Comparing lengths is the fastest way to spot a difference before iterating through every item
+ var sameLength = actual.size === expectation.size;
+ return typeOf(actual) === "map" && sameLength && every(actual, function (element, key) {
+ return expectation.has(key) && expectation.get(key) === element;
+ });
+ }, "deepEquals(Map[" + iterableToString(expectation) + "])");
+};
+
+match.map.contains = function mapContains(expectation) {
+ return match(function (actual) {
+ return typeOf(actual) === "map" && every(expectation, function (element, key) {
+ return actual.has(key) && actual.get(key) === element;
+ });
+ }, "contains(Map[" + iterableToString(expectation) + "])");
+};
+
+match.set = match.typeOf("set");
+
+match.set.deepEquals = function setDeepEquals(expectation) {
+ return match(function (actual) {
+ // Comparing lengths is the fastest way to spot a difference before iterating through every item
+ var sameLength = actual.size === expectation.size;
+ return typeOf(actual) === "set" && sameLength && every(actual, function (element) {
+ return expectation.has(element);
+ });
+ }, "deepEquals(Set[" + iterableToString(expectation) + "])");
+};
+
+match.set.contains = function setContains(expectation) {
+ return match(function (actual) {
+ return typeOf(actual) === "set" && every(expectation, function (element) {
+ return actual.has(element);
+ });
+ }, "contains(Set[" + iterableToString(expectation) + "])");
+};
+
+match.bool = match.typeOf("boolean");
+match.number = match.typeOf("number");
+match.string = match.typeOf("string");
+match.object = match.typeOf("object");
+match.func = match.typeOf("function");
+match.regexp = match.typeOf("regexp");
+match.date = match.typeOf("date");
+match.symbol = match.typeOf("symbol");
+
+module.exports = match;
+
+},{"./util/core/deep-equal":22,"./util/core/every":25,"./util/core/function-name":28,"./util/core/iterable-to-string":33,"./util/core/typeOf":38,"./util/core/value-to-string":39}],11:[function(require,module,exports){
+"use strict";
+
+var spyInvoke = require("./spy").invoke;
+var spyCallToString = require("./call").toString;
+var timesInWords = require("./util/core/times-in-words");
+var extend = require("./util/core/extend");
+var match = require("./match");
+var stub = require("./stub");
+var assert = require("./assert");
+var deepEqual = require("./util/core/deep-equal").use(match);
+var format = require("./util/core/format");
+var valueToString = require("./util/core/value-to-string");
+
+var slice = Array.prototype.slice;
+var push = Array.prototype.push;
+
+function callCountInWords(callCount) {
+ if (callCount === 0) {
+ return "never called";
+ }
+
+ return "called " + timesInWords(callCount);
+}
+
+function expectedCallCountInWords(expectation) {
+ var min = expectation.minCalls;
+ var max = expectation.maxCalls;
+
+ if (typeof min === "number" && typeof max === "number") {
+ var str = timesInWords(min);
+
+ if (min !== max) {
+ str = "at least " + str + " and at most " + timesInWords(max);
+ }
+
+ return str;
+ }
+
+ if (typeof min === "number") {
+ return "at least " + timesInWords(min);
+ }
+
+ return "at most " + timesInWords(max);
+}
+
+function receivedMinCalls(expectation) {
+ var hasMinLimit = typeof expectation.minCalls === "number";
+ return !hasMinLimit || expectation.callCount >= expectation.minCalls;
+}
+
+function receivedMaxCalls(expectation) {
+ if (typeof expectation.maxCalls !== "number") {
+ return false;
+ }
+
+ return expectation.callCount === expectation.maxCalls;
+}
+
+function verifyMatcher(possibleMatcher, arg) {
+ var isMatcher = match && match.isMatcher(possibleMatcher);
+
+ return isMatcher && possibleMatcher.test(arg) || true;
+}
+
+var mockExpectation = {
+ minCalls: 1,
+ maxCalls: 1,
+
+ create: function create(methodName) {
+ var expectation = extend(stub.create(), mockExpectation);
+ delete expectation.create;
+ expectation.method = methodName;
+
+ return expectation;
+ },
+
+ invoke: function invoke(func, thisValue, args) {
+ this.verifyCallAllowed(thisValue, args);
+
+ return spyInvoke.apply(this, arguments);
+ },
+
+ atLeast: function atLeast(num) {
+ if (typeof num !== "number") {
+ throw new TypeError("'" + valueToString(num) + "' is not number");
+ }
+
+ if (!this.limitsSet) {
+ this.maxCalls = null;
+ this.limitsSet = true;
+ }
+
+ this.minCalls = num;
+
+ return this;
+ },
+
+ atMost: function atMost(num) {
+ if (typeof num !== "number") {
+ throw new TypeError("'" + valueToString(num) + "' is not number");
+ }
+
+ if (!this.limitsSet) {
+ this.minCalls = null;
+ this.limitsSet = true;
+ }
+
+ this.maxCalls = num;
+
+ return this;
+ },
+
+ never: function never() {
+ return this.exactly(0);
+ },
+
+ once: function once() {
+ return this.exactly(1);
+ },
+
+ twice: function twice() {
+ return this.exactly(2);
+ },
+
+ thrice: function thrice() {
+ return this.exactly(3);
+ },
+
+ exactly: function exactly(num) {
+ if (typeof num !== "number") {
+ throw new TypeError("'" + valueToString(num) + "' is not a number");
+ }
+
+ this.atLeast(num);
+ return this.atMost(num);
+ },
+
+ met: function met() {
+ return !this.failed && receivedMinCalls(this);
+ },
+
+ verifyCallAllowed: function verifyCallAllowed(thisValue, args) {
+ var expectedArguments = this.expectedArguments;
+
+ if (receivedMaxCalls(this)) {
+ this.failed = true;
+ mockExpectation.fail(this.method + " already called " + timesInWords(this.maxCalls));
+ }
+
+ if ("expectedThis" in this && this.expectedThis !== thisValue) {
+ mockExpectation.fail(this.method + " called with " + valueToString(thisValue) +
+ " as thisValue, expected " + valueToString(this.expectedThis));
+ }
+
+ if (!("expectedArguments" in this)) {
+ return;
+ }
+
+ if (!args) {
+ mockExpectation.fail(this.method + " received no arguments, expected " +
+ format(expectedArguments));
+ }
+
+ if (args.length < expectedArguments.length) {
+ mockExpectation.fail(this.method + " received too few arguments (" + format(args) +
+ "), expected " + format(expectedArguments));
+ }
+
+ if (this.expectsExactArgCount &&
+ args.length !== expectedArguments.length) {
+ mockExpectation.fail(this.method + " received too many arguments (" + format(args) +
+ "), expected " + format(expectedArguments));
+ }
+
+ expectedArguments.forEach(function (expectedArgument, i) {
+ if (!verifyMatcher(expectedArgument, args[i])) {
+ mockExpectation.fail(this.method + " received wrong arguments " + format(args) +
+ ", didn't match " + expectedArguments.toString());
+ }
+
+ if (!deepEqual(expectedArgument, args[i])) {
+ mockExpectation.fail(this.method + " received wrong arguments " + format(args) +
+ ", expected " + format(expectedArguments));
+ }
+ });
+ },
+
+ allowsCall: function allowsCall(thisValue, args) {
+ var expectedArguments = this.expectedArguments;
+
+ if (this.met() && receivedMaxCalls(this)) {
+ return false;
+ }
+
+ if ("expectedThis" in this && this.expectedThis !== thisValue) {
+ return false;
+ }
+
+ if (!("expectedArguments" in this)) {
+ return true;
+ }
+
+ args = args || [];
+
+ if (args.length < expectedArguments.length) {
+ return false;
+ }
+
+ if (this.expectsExactArgCount &&
+ args.length !== expectedArguments.length) {
+ return false;
+ }
+
+ return expectedArguments.every(function (expectedArgument, i) {
+ if (!verifyMatcher(expectedArgument, args[i])) {
+ return false;
+ }
+
+ if (!deepEqual(expectedArgument, args[i])) {
+ return false;
+ }
+
+ return true;
+ });
+ },
+
+ withArgs: function withArgs() {
+ this.expectedArguments = slice.call(arguments);
+ return this;
+ },
+
+ withExactArgs: function withExactArgs() {
+ this.withArgs.apply(this, arguments);
+ this.expectsExactArgCount = true;
+ return this;
+ },
+
+ on: function on(thisValue) {
+ this.expectedThis = thisValue;
+ return this;
+ },
+
+ toString: function () {
+ var args = (this.expectedArguments || []).slice();
+
+ if (!this.expectsExactArgCount) {
+ push.call(args, "[...]");
+ }
+
+ var callStr = spyCallToString.call({
+ proxy: this.method || "anonymous mock expectation",
+ args: args
+ });
+
+ var message = callStr.replace(", [...", "[, ...") + " " +
+ expectedCallCountInWords(this);
+
+ if (this.met()) {
+ return "Expectation met: " + message;
+ }
+
+ return "Expected " + message + " (" +
+ callCountInWords(this.callCount) + ")";
+ },
+
+ verify: function verify() {
+ if (!this.met()) {
+ mockExpectation.fail(this.toString());
+ } else {
+ mockExpectation.pass(this.toString());
+ }
+
+ return true;
+ },
+
+ pass: function pass(message) {
+ assert.pass(message);
+ },
+
+ fail: function fail(message) {
+ var exception = new Error(message);
+ exception.name = "ExpectationError";
+
+ throw exception;
+ }
+};
+
+module.exports = mockExpectation;
+
+},{"./assert":2,"./call":5,"./match":10,"./spy":15,"./stub":19,"./util/core/deep-equal":22,"./util/core/extend":26,"./util/core/format":27,"./util/core/times-in-words":37,"./util/core/value-to-string":39}],12:[function(require,module,exports){
+"use strict";
+
+var mockExpectation = require("./mock-expectation");
+var spyCallToString = require("./call").toString;
+var extend = require("./util/core/extend");
+var match = require("./match");
+var deepEqual = require("./util/core/deep-equal").use(match);
+var wrapMethod = require("./util/core/wrap-method");
+
+var push = Array.prototype.push;
+
+function mock(object) {
+ if (!object) {
+ return mockExpectation.create("Anonymous mock");
+ }
+
+ return mock.create(object);
+}
+
+function each(collection, callback) {
+ var col = collection || [];
+
+ col.forEach(callback);
+}
+
+function arrayEquals(arr1, arr2, compareLength) {
+ if (compareLength && (arr1.length !== arr2.length)) {
+ return false;
+ }
+
+ return arr1.every(function (element, i) {
+ return deepEqual(element, arr2[i]);
+
+ });
+}
+
+extend(mock, {
+ create: function create(object) {
+ if (!object) {
+ throw new TypeError("object is null");
+ }
+
+ var mockObject = extend({}, mock);
+ mockObject.object = object;
+ delete mockObject.create;
+
+ return mockObject;
+ },
+
+ expects: function expects(method) {
+ if (!method) {
+ throw new TypeError("method is falsy");
+ }
+
+ if (!this.expectations) {
+ this.expectations = {};
+ this.proxies = [];
+ this.failures = [];
+ }
+
+ if (!this.expectations[method]) {
+ this.expectations[method] = [];
+ var mockObject = this;
+
+ wrapMethod(this.object, method, function () {
+ return mockObject.invokeMethod(method, this, arguments);
+ });
+
+ push.call(this.proxies, method);
+ }
+
+ var expectation = mockExpectation.create(method);
+ push.call(this.expectations[method], expectation);
+
+ return expectation;
+ },
+
+ restore: function restore() {
+ var object = this.object;
+
+ each(this.proxies, function (proxy) {
+ if (typeof object[proxy].restore === "function") {
+ object[proxy].restore();
+ }
+ });
+ },
+
+ verify: function verify() {
+ var expectations = this.expectations || {};
+ var messages = this.failures ? this.failures.slice() : [];
+ var met = [];
+
+ each(this.proxies, function (proxy) {
+ each(expectations[proxy], function (expectation) {
+ if (!expectation.met()) {
+ push.call(messages, expectation.toString());
+ } else {
+ push.call(met, expectation.toString());
+ }
+ });
+ });
+
+ this.restore();
+
+ if (messages.length > 0) {
+ mockExpectation.fail(messages.concat(met).join("\n"));
+ } else if (met.length > 0) {
+ mockExpectation.pass(messages.concat(met).join("\n"));
+ }
+
+ return true;
+ },
+
+ invokeMethod: function invokeMethod(method, thisValue, args) {
+ /* if we cannot find any matching files we will explicitly call mockExpection#fail with error messages */
+ /* eslint consistent-return: "off" */
+ var expectations = this.expectations && this.expectations[method] ? this.expectations[method] : [];
+ var currentArgs = args || [];
+ var available;
+
+ var expectationsWithMatchingArgs = expectations.filter(function (expectation) {
+ var expectedArgs = expectation.expectedArguments || [];
+
+ return arrayEquals(expectedArgs, currentArgs, expectation.expectsExactArgCount);
+ });
+
+ var expectationsToApply = expectationsWithMatchingArgs.filter(function (expectation) {
+ return !expectation.met() && expectation.allowsCall(thisValue, args);
+ });
+
+ if (expectationsToApply.length > 0) {
+ return expectationsToApply[0].apply(thisValue, args);
+ }
+
+ var messages = [];
+ var exhausted = 0;
+
+ expectationsWithMatchingArgs.forEach(function (expectation) {
+ if (expectation.allowsCall(thisValue, args)) {
+ available = available || expectation;
+ } else {
+ exhausted += 1;
+ }
+ });
+
+ if (available && exhausted === 0) {
+ return available.apply(thisValue, args);
+ }
+
+ expectations.forEach(function (expectation) {
+ push.call(messages, " " + expectation.toString());
+ });
+
+ messages.unshift("Unexpected call: " + spyCallToString.call({
+ proxy: method,
+ args: args
+ }));
+
+ var err = new Error();
+ if (!err.stack) {
+ // PhantomJS does not serialize the stack trace until the error has been thrown
+ try {
+ throw err;
+ } catch (e) {/* empty */}
+ }
+ this.failures.push("Unexpected call: " + spyCallToString.call({
+ proxy: method,
+ args: args,
+ stack: err.stack
+ }));
+
+ mockExpectation.fail(messages.join("\n"));
+ }
+});
+
+module.exports = mock;
+
+},{"./call":5,"./match":10,"./mock-expectation":11,"./util/core/deep-equal":22,"./util/core/extend":26,"./util/core/wrap-method":41}],13:[function(require,module,exports){
+"use strict";
+
+var extend = require("./util/core/extend");
+var sinonCollection = require("./collection");
+var sinonMatch = require("./match");
+var sinonAssert = require("./assert");
+var sinonClock = require("./util/fake_timers");
+var fakeServer = require("./util/fake_server");
+var fakeXhr = require("./util/fake_xml_http_request");
+var fakeServerWithClock = require("./util/fake_server_with_clock");
+
+var push = [].push;
+
+var sinonSandbox = Object.create(sinonCollection);
+
+function exposeValue(sandbox, config, key, value) {
+ if (!value) {
+ return;
+ }
+
+ if (config.injectInto && !(key in config.injectInto)) {
+ config.injectInto[key] = value;
+ sandbox.injectedKeys.push(key);
+ } else {
+ push.call(sandbox.args, value);
+ }
+}
+
+function prepareSandboxFromConfig(config) {
+ var sandbox = Object.create(sinonSandbox);
+
+ if (config.useFakeServer) {
+ if (typeof config.useFakeServer === "object") {
+ sandbox.serverPrototype = config.useFakeServer;
+ }
+
+ sandbox.useFakeServer();
+ }
+
+ if (config.useFakeTimers) {
+ if (typeof config.useFakeTimers === "object") {
+ sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers);
+ } else {
+ sandbox.useFakeTimers();
+ }
+ }
+
+ return sandbox;
+}
+
+extend(sinonSandbox, {
+ useFakeTimers: function useFakeTimers() {
+ this.clock = sinonClock.useFakeTimers.apply(null, arguments);
+
+ return this.add(this.clock);
+ },
+
+ serverPrototype: fakeServerWithClock,
+
+ useFakeServer: function useFakeServer() {
+ var proto = this.serverPrototype || fakeServer;
+
+ if (!proto || !proto.create) {
+ return null;
+ }
+
+ this.server = proto.create();
+ return this.add(this.server);
+ },
+
+ useFakeXMLHttpRequest: function useFakeXMLHttpRequest() {
+ var xhr = fakeXhr.useFakeXMLHttpRequest();
+ return this.add(xhr);
+ },
+
+ inject: function (obj) {
+ sinonCollection.inject.call(this, obj);
+
+ if (this.clock) {
+ obj.clock = this.clock;
+ }
+
+ if (this.server) {
+ obj.server = this.server;
+ obj.requests = this.server.requests;
+ }
+
+ obj.match = sinonMatch;
+
+ return obj;
+ },
+
+ restore: function () {
+ if (arguments.length) {
+ throw new Error("sandbox.restore() does not take any parameters. Perhaps you meant stub.restore()");
+ }
+
+ sinonCollection.restore.apply(this, arguments);
+ this.restoreContext();
+ },
+
+ restoreContext: function () {
+ var injectedKeys = this.injectedKeys;
+ var injectInto = this.injectInto;
+
+ if (!injectedKeys) {
+ return;
+ }
+
+ injectedKeys.forEach(function (injectedKey) {
+ delete injectInto[injectedKey];
+ });
+
+ injectedKeys = [];
+ },
+
+ create: function (config) {
+ if (!config) {
+ return Object.create(sinonSandbox);
+ }
+
+ var sandbox = prepareSandboxFromConfig(config);
+ sandbox.args = sandbox.args || [];
+ sandbox.injectedKeys = [];
+ sandbox.injectInto = config.injectInto;
+ var exposed = sandbox.inject({});
+
+ if (config.properties) {
+ config.properties.forEach(function (prop) {
+ var value = exposed[prop] || prop === "sandbox" && sandbox;
+ exposeValue(sandbox, config, prop, value);
+ });
+ } else {
+ exposeValue(sandbox, config, "sandbox");
+ }
+
+ return sandbox;
+ },
+
+ match: sinonMatch,
+
+ assert: sinonAssert
+});
+
+module.exports = sinonSandbox;
+
+},{"./assert":2,"./collection":7,"./match":10,"./util/core/extend":26,"./util/fake_server":43,"./util/fake_server_with_clock":44,"./util/fake_timers":45,"./util/fake_xml_http_request":46}],14:[function(require,module,exports){
+"use strict";
+
+var color = require("./color");
+var timesInWords = require("./util/core/times-in-words");
+var sinonFormat = require("./util/core/format");
+var sinonMatch = require("./match");
+var jsDiff = require("diff");
+var push = Array.prototype.push;
+
+function colorSinonMatchText(matcher, calledArg, calledArgMessage) {
+ if (!matcher.test(calledArg)) {
+ matcher.message = color.red(matcher.message);
+ if (calledArgMessage) {
+ calledArgMessage = color.green(calledArgMessage);
+ }
+ }
+ return calledArgMessage + " " + matcher.message;
+}
+
+function colorDiffText(diff) {
+ var objects = diff.map(function (part) {
+ var text = part.value;
+ if (part.added) {
+ text = color.green(text);
+ } else if (part.removed) {
+ text = color.red(text);
+ }
+ if (diff.length === 2) {
+ text += " "; // format simple diffs
+ }
+ return text;
+ });
+ return objects.join("");
+}
+
+module.exports = {
+ c: function (spyInstance) {
+ return timesInWords(spyInstance.callCount);
+ },
+
+ n: function (spyInstance) {
+ return spyInstance.toString();
+ },
+
+ D: function (spyInstance, args) {
+ var message = "";
+
+ for (var i = 0, l = spyInstance.callCount; i < l; ++i) {
+ // describe multiple calls
+ if (l > 1) {
+ if (i > 0) {
+ message += "\n";
+ }
+ message += "Call " + (i + 1) + ":";
+ }
+ var calledArgs = spyInstance.getCall(i).args;
+ for (var j = 0; j < calledArgs.length || j < args.length; ++j) {
+ message += "\n";
+ var calledArgMessage = j < calledArgs.length ? sinonFormat(calledArgs[j]) : "";
+ if (sinonMatch.isMatcher(args[j])) {
+ message += colorSinonMatchText(args[j], calledArgs[j], calledArgMessage);
+ } else {
+ var expectedArgMessage = j < args.length ? sinonFormat(args[j]) : "";
+ var diff = jsDiff.diffJson(calledArgMessage, expectedArgMessage);
+ message += colorDiffText(diff);
+ }
+ }
+ }
+
+ return message;
+ },
+
+ C: function (spyInstance) {
+ var calls = [];
+
+ for (var i = 0, l = spyInstance.callCount; i < l; ++i) {
+ var stringifiedCall = " " + spyInstance.getCall(i).toString();
+ if (/\n/.test(calls[i - 1])) {
+ stringifiedCall = "\n" + stringifiedCall;
+ }
+ push.call(calls, stringifiedCall);
+ }
+
+ return calls.length > 0 ? "\n" + calls.join("\n") : "";
+ },
+
+ t: function (spyInstance) {
+ var objects = [];
+
+ for (var i = 0, l = spyInstance.callCount; i < l; ++i) {
+ push.call(objects, sinonFormat(spyInstance.thisValues[i]));
+ }
+
+ return objects.join(", ");
+ },
+
+ "*": function (spyInstance, args) {
+ return args.map(sinonFormat).join(", ");
+ }
+};
+
+},{"./color":8,"./match":10,"./util/core/format":27,"./util/core/times-in-words":37,"diff":57}],15:[function(require,module,exports){
+"use strict";
+
+var extend = require("./util/core/extend");
+var functionName = require("./util/core/function-name");
+var functionToString = require("./util/core/function-to-string");
+var getPropertyDescriptor = require("./util/core/get-property-descriptor");
+var sinonMatch = require("./match");
+var deepEqual = require("./util/core/deep-equal").use(sinonMatch);
+var spyCall = require("./call");
+var wrapMethod = require("./util/core/wrap-method");
+var sinonFormat = require("./util/core/format");
+var valueToString = require("./util/core/value-to-string");
+
+var push = Array.prototype.push;
+var slice = Array.prototype.slice;
+var callId = 0;
+var ErrorConstructor = Error.prototype.constructor;
+
+function spy(object, property, types) {
+ var descriptor, methodDesc;
+
+ if (!property && typeof object === "function") {
+ return spy.create(object);
+ }
+
+ if (!object && !property) {
+ return spy.create(function () { });
+ }
+
+ if (!types) {
+ return wrapMethod(object, property, spy.create(object[property]));
+ }
+
+ descriptor = {};
+ methodDesc = getPropertyDescriptor(object, property);
+
+ types.forEach(function (type) {
+ descriptor[type] = spy.create(methodDesc[type]);
+ });
+
+ return wrapMethod(object, property, descriptor);
+}
+
+function matchingFake(fakes, args, strict) {
+ if (!fakes) {
+ return undefined;
+ }
+
+ var matchingFakes = fakes.filter(function (fake) {
+ return fake.matches(args, strict);
+ });
+
+ return matchingFakes.pop();
+}
+
+function incrementCallCount() {
+ this.called = true;
+ this.callCount += 1;
+ this.notCalled = false;
+ this.calledOnce = this.callCount === 1;
+ this.calledTwice = this.callCount === 2;
+ this.calledThrice = this.callCount === 3;
+}
+
+function createCallProperties() {
+ this.firstCall = this.getCall(0);
+ this.secondCall = this.getCall(1);
+ this.thirdCall = this.getCall(2);
+ this.lastCall = this.getCall(this.callCount - 1);
+}
+
+function createProxy(func, proxyLength) {
+ // Retain the function length:
+ var p;
+ if (proxyLength) {
+ // Do not change this to use an eval. Projects that depend on sinon block the use of eval.
+ // ref: https://github.com/sinonjs/sinon/issues/710
+ switch (proxyLength) {
+ /*eslint-disable no-unused-vars, max-len*/
+ case 1: p = function proxy(a) { return p.invoke(func, this, slice.call(arguments)); }; break;
+ case 2: p = function proxy(a, b) { return p.invoke(func, this, slice.call(arguments)); }; break;
+ case 3: p = function proxy(a, b, c) { return p.invoke(func, this, slice.call(arguments)); }; break;
+ case 4: p = function proxy(a, b, c, d) { return p.invoke(func, this, slice.call(arguments)); }; break;
+ case 5: p = function proxy(a, b, c, d, e) { return p.invoke(func, this, slice.call(arguments)); }; break;
+ case 6: p = function proxy(a, b, c, d, e, f) { return p.invoke(func, this, slice.call(arguments)); }; break;
+ case 7: p = function proxy(a, b, c, d, e, f, g) { return p.invoke(func, this, slice.call(arguments)); }; break;
+ case 8: p = function proxy(a, b, c, d, e, f, g, h) { return p.invoke(func, this, slice.call(arguments)); }; break;
+ case 9: p = function proxy(a, b, c, d, e, f, g, h, i) { return p.invoke(func, this, slice.call(arguments)); }; break;
+ case 10: p = function proxy(a, b, c, d, e, f, g, h, i, j) { return p.invoke(func, this, slice.call(arguments)); }; break;
+ case 11: p = function proxy(a, b, c, d, e, f, g, h, i, j, k) { return p.invoke(func, this, slice.call(arguments)); }; break;
+ case 12: p = function proxy(a, b, c, d, e, f, g, h, i, j, k, l) { return p.invoke(func, this, slice.call(arguments)); }; break;
+ default: p = function proxy() { return p.invoke(func, this, slice.call(arguments)); }; break;
+ /*eslint-enable*/
+ }
+ } else {
+ p = function proxy() {
+ return p.invoke(func, this, slice.call(arguments));
+ };
+ }
+ p.isSinonProxy = true;
+ return p;
+}
+
+var uuid = 0;
+
+// Public API
+var spyApi = {
+ formatters: require("./spy-formatters"),
+
+ reset: function () {
+ if (this.invoking) {
+ var err = new Error("Cannot reset Sinon function while invoking it. " +
+ "Move the call to .reset outside of the callback.");
+ err.name = "InvalidResetException";
+ throw err;
+ }
+
+ this.called = false;
+ this.notCalled = true;
+ this.calledOnce = false;
+ this.calledTwice = false;
+ this.calledThrice = false;
+ this.callCount = 0;
+ this.firstCall = null;
+ this.secondCall = null;
+ this.thirdCall = null;
+ this.lastCall = null;
+ this.args = [];
+ this.returnValues = [];
+ this.thisValues = [];
+ this.exceptions = [];
+ this.callIds = [];
+ this.errorsWithCallStack = [];
+ if (this.fakes) {
+ this.fakes.forEach(function (fake) {
+ fake.reset();
+ });
+ }
+
+ return this;
+ },
+
+ create: function create(func, spyLength) {
+ var name;
+
+ if (typeof func !== "function") {
+ func = function () { };
+ } else {
+ name = functionName(func);
+ }
+
+ if (!spyLength) {
+ spyLength = func.length;
+ }
+
+ var proxy = createProxy(func, spyLength);
+
+ extend(proxy, spy);
+ delete proxy.create;
+ extend(proxy, func);
+
+ proxy.reset();
+ proxy.prototype = func.prototype;
+ proxy.displayName = name || "spy";
+ proxy.toString = functionToString;
+ proxy.instantiateFake = spy.create;
+ proxy.id = "spy#" + uuid++;
+
+ return proxy;
+ },
+
+ invoke: function invoke(func, thisValue, args) {
+ var matching = matchingFake(this.fakes, args);
+ var exception, returnValue;
+
+ incrementCallCount.call(this);
+ push.call(this.thisValues, thisValue);
+ push.call(this.args, args);
+ push.call(this.callIds, callId++);
+
+ // Make call properties available from within the spied function:
+ createCallProperties.call(this);
+
+ try {
+ this.invoking = true;
+
+ if (matching) {
+ returnValue = matching.invoke(func, thisValue, args);
+ } else {
+ returnValue = (this.func || func).apply(thisValue, args);
+ }
+
+ var thisCall = this.getCall(this.callCount - 1);
+ if (thisCall.calledWithNew() && typeof returnValue !== "object") {
+ returnValue = thisValue;
+ }
+ } catch (e) {
+ exception = e;
+ } finally {
+ delete this.invoking;
+ }
+
+ push.call(this.exceptions, exception);
+ push.call(this.returnValues, returnValue);
+ var err = new ErrorConstructor();
+ // 1. Please do not get stack at this point. It's may be so very slow, and not actually used
+ // 2. PhantomJS does not serialize the stack trace until the error has been thrown:
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error/Stack
+ try {
+ throw err;
+ } catch (e) {/* empty */}
+ push.call(this.errorsWithCallStack, err);
+
+ // Make return value and exception available in the calls:
+ createCallProperties.call(this);
+
+ if (exception !== undefined) {
+ throw exception;
+ }
+
+ return returnValue;
+ },
+
+ named: function named(name) {
+ this.displayName = name;
+ return this;
+ },
+
+ getCall: function getCall(i) {
+ if (i < 0 || i >= this.callCount) {
+ return null;
+ }
+
+ return spyCall(this, this.thisValues[i], this.args[i],
+ this.returnValues[i], this.exceptions[i],
+ this.callIds[i], this.errorsWithCallStack[i]);
+ },
+
+ getCalls: function () {
+ var calls = [];
+ var i;
+
+ for (i = 0; i < this.callCount; i++) {
+ calls.push(this.getCall(i));
+ }
+
+ return calls;
+ },
+
+ calledBefore: function calledBefore(spyFn) {
+ if (!this.called) {
+ return false;
+ }
+
+ if (!spyFn.called) {
+ return true;
+ }
+
+ return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1];
+ },
+
+ calledAfter: function calledAfter(spyFn) {
+ if (!this.called || !spyFn.called) {
+ return false;
+ }
+
+ return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1];
+ },
+
+ withArgs: function () {
+ var args = slice.call(arguments);
+
+ if (this.fakes) {
+ var match = matchingFake(this.fakes, args, true);
+
+ if (match) {
+ return match;
+ }
+ } else {
+ this.fakes = [];
+ }
+
+ var original = this;
+ var fake = this.instantiateFake();
+ fake.matchingArguments = args;
+ fake.parent = this;
+ push.call(this.fakes, fake);
+
+ fake.withArgs = function () {
+ return original.withArgs.apply(original, arguments);
+ };
+
+ original.args.forEach(function (arg, i) {
+ if (!fake.matches(arg)) {
+ return;
+ }
+
+ incrementCallCount.call(fake);
+ push.call(fake.thisValues, original.thisValues[i]);
+ push.call(fake.args, arg);
+ push.call(fake.returnValues, original.returnValues[i]);
+ push.call(fake.exceptions, original.exceptions[i]);
+ push.call(fake.callIds, original.callIds[i]);
+ });
+
+ createCallProperties.call(fake);
+
+ return fake;
+ },
+
+ matches: function (args, strict) {
+ var margs = this.matchingArguments;
+
+ if (margs.length <= args.length &&
+ deepEqual(margs, args.slice(0, margs.length))) {
+ return !strict || margs.length === args.length;
+ }
+
+ return undefined;
+ },
+
+ printf: function (format) {
+ var spyInstance = this;
+ var args = slice.call(arguments, 1);
+ var formatter;
+
+ return (format || "").replace(/%(.)/g, function (match, specifyer) {
+ formatter = spyApi.formatters[specifyer];
+
+ if (typeof formatter === "function") {
+ return formatter.call(null, spyInstance, args);
+ } else if (!isNaN(parseInt(specifyer, 10))) {
+ return sinonFormat(args[specifyer - 1]);
+ }
+
+ return "%" + specifyer;
+ });
+ }
+};
+
+function delegateToCalls(method, matchAny, actual, notCalled) {
+ spyApi[method] = function () {
+ if (!this.called) {
+ if (notCalled) {
+ return notCalled.apply(this, arguments);
+ }
+ return false;
+ }
+
+ var currentCall;
+ var matches = 0;
+
+ for (var i = 0, l = this.callCount; i < l; i += 1) {
+ currentCall = this.getCall(i);
+
+ if (currentCall[actual || method].apply(currentCall, arguments)) {
+ matches += 1;
+
+ if (matchAny) {
+ return true;
+ }
+ }
+ }
+
+ return matches === this.callCount;
+ };
+}
+
+delegateToCalls("calledOn", true);
+delegateToCalls("alwaysCalledOn", false, "calledOn");
+delegateToCalls("calledWith", true);
+delegateToCalls("calledWithMatch", true);
+delegateToCalls("alwaysCalledWith", false, "calledWith");
+delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch");
+delegateToCalls("calledWithExactly", true);
+delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly");
+delegateToCalls("neverCalledWith", false, "notCalledWith", function () {
+ return true;
+});
+delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch", function () {
+ return true;
+});
+delegateToCalls("threw", true);
+delegateToCalls("alwaysThrew", false, "threw");
+delegateToCalls("returned", true);
+delegateToCalls("alwaysReturned", false, "returned");
+delegateToCalls("calledWithNew", true);
+delegateToCalls("alwaysCalledWithNew", false, "calledWithNew");
+delegateToCalls("callArg", false, "callArgWith", function () {
+ throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
+});
+spyApi.callArgWith = spyApi.callArg;
+delegateToCalls("callArgOn", false, "callArgOnWith", function () {
+ throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
+});
+spyApi.callArgOnWith = spyApi.callArgOn;
+delegateToCalls("yield", false, "yield", function () {
+ throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
+});
+// "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode.
+spyApi.invokeCallback = spyApi.yield;
+delegateToCalls("yieldOn", false, "yieldOn", function () {
+ throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
+});
+delegateToCalls("yieldTo", false, "yieldTo", function (property) {
+ throw new Error(this.toString() + " cannot yield to '" + valueToString(property) +
+ "' since it was not yet invoked.");
+});
+delegateToCalls("yieldToOn", false, "yieldToOn", function (property) {
+ throw new Error(this.toString() + " cannot yield to '" + valueToString(property) +
+ "' since it was not yet invoked.");
+});
+
+extend(spy, spyApi);
+spy.spyCall = spyCall;
+module.exports = spy;
+
+},{"./call":5,"./match":10,"./spy-formatters":14,"./util/core/deep-equal":22,"./util/core/extend":26,"./util/core/format":27,"./util/core/function-name":28,"./util/core/function-to-string":29,"./util/core/get-property-descriptor":31,"./util/core/value-to-string":39,"./util/core/wrap-method":41}],16:[function(require,module,exports){
+"use strict";
+
+var deprecated = require("./util/core/deprecated");
+var spy = require("./spy");
+var wrapMethod = require("./util/core/wrap-method");
+
+// This is deprecated and will be removed in a future version of sinon.
+// We will only consider pull requests that fix serious bugs in the implementation
+function stubDescriptor(object, property, descriptor) {
+ var wrapper;
+
+ deprecated.printWarning(
+ "sinon.stub(obj, 'meth', fn) is deprecated and will be removed from" +
+ "the public API in a future version of sinon." +
+ "\n Use stub(obj, 'meth').callsFake(fn)." +
+ "\n Codemod available at https://github.com/hurrymaplelad/sinon-codemod"
+ );
+
+ if (!!descriptor && typeof descriptor !== "function" && typeof descriptor !== "object") {
+ throw new TypeError("Custom stub should be a property descriptor");
+ }
+
+ if (typeof descriptor === "object" && Object.keys(descriptor).length === 0) {
+ throw new TypeError("Expected property descriptor to have at least one key");
+ }
+
+ if (typeof descriptor === "function") {
+ wrapper = spy && spy.create ? spy.create(descriptor) : descriptor;
+ } else {
+ wrapper = descriptor;
+ if (spy && spy.create) {
+ Object.keys(wrapper).forEach(function (type) {
+ wrapper[type] = spy.create(wrapper[type]);
+ });
+ }
+ }
+
+ return wrapMethod(object, property, wrapper);
+}
+
+module.exports = stubDescriptor;
+
+},{"./spy":15,"./util/core/deprecated":24,"./util/core/wrap-method":41}],17:[function(require,module,exports){
+"use strict";
+
+var getPropertyDescriptor = require("./util/core/get-property-descriptor");
+var walk = require("./util/core/walk");
+
+function stubEntireObject(stub, object) {
+ walk(object || {}, function (prop, propOwner) {
+ // we don't want to stub things like toString(), valueOf(), etc. so we only stub if the object
+ // is not Object.prototype
+ if (
+ propOwner !== Object.prototype &&
+ prop !== "constructor" &&
+ typeof getPropertyDescriptor(propOwner, prop).value === "function"
+ ) {
+ stub(object, prop);
+ }
+ });
+
+ return object;
+}
+
+module.exports = stubEntireObject;
+
+},{"./util/core/get-property-descriptor":31,"./util/core/walk":40}],18:[function(require,module,exports){
+"use strict";
+
+var valueToString = require("./util/core/value-to-string");
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+function stubNonFunctionProperty(object, property, value) {
+ var original = object[property];
+
+ if (!hasOwnProperty.call(object, property)) {
+ throw new TypeError("Cannot stub non-existent own property " + valueToString(property));
+ }
+
+ object[property] = value;
+
+ return {
+ restore: function () {
+ object[property] = original;
+ }
+ };
+}
+
+module.exports = stubNonFunctionProperty;
+
+},{"./util/core/value-to-string":39}],19:[function(require,module,exports){
+"use strict";
+
+var behavior = require("./behavior");
+var behaviors = require("./default-behaviors");
+var spy = require("./spy");
+var extend = require("./util/core/extend");
+var functionToString = require("./util/core/function-to-string");
+var getPropertyDescriptor = require("./util/core/get-property-descriptor");
+var wrapMethod = require("./util/core/wrap-method");
+var stubEntireObject = require("./stub-entire-object");
+var stubDescriptor = require("./stub-descriptor");
+var throwOnFalsyObject = require("./throw-on-falsy-object");
+
+function stub(object, property, descriptor) {
+ throwOnFalsyObject.apply(null, arguments);
+
+ var actualDescriptor = getPropertyDescriptor(object, property);
+ var isStubbingEntireObject = typeof property === "undefined" && typeof object === "object";
+ var isCreatingNewStub = !object && typeof property === "undefined";
+ var isStubbingDescriptor = object && property && Boolean(descriptor);
+ var isStubbingNonFuncProperty = typeof object === "object"
+ && typeof property !== "undefined"
+ && (typeof actualDescriptor === "undefined"
+ || typeof actualDescriptor.value !== "function")
+ && typeof descriptor === "undefined";
+ var isStubbingExistingMethod = !isStubbingDescriptor
+ && typeof object === "object"
+ && typeof actualDescriptor !== "undefined"
+ && typeof actualDescriptor.value === "function";
+ var arity = isStubbingExistingMethod ? object[property].length : 0;
+
+ if (isStubbingEntireObject) {
+ return stubEntireObject(stub, object);
+ }
+
+ if (isStubbingDescriptor) {
+ return stubDescriptor.apply(null, arguments);
+ }
+
+ if (isCreatingNewStub) {
+ return stub.create();
+ }
+
+ var s = stub.create(arity);
+ s.rootObj = object;
+ s.propName = property;
+ s.restore = function restore() {
+ Object.defineProperty(object, property, actualDescriptor);
+ };
+
+ return isStubbingNonFuncProperty ? s : wrapMethod(object, property, s);
+}
+
+stub.createStubInstance = function (constructor) {
+ if (typeof constructor !== "function") {
+ throw new TypeError("The constructor should be a function.");
+ }
+ return stub(Object.create(constructor.prototype));
+};
+
+/*eslint-disable no-use-before-define*/
+function getParentBehaviour(stubInstance) {
+ return (stubInstance.parent && getCurrentBehavior(stubInstance.parent));
+}
+
+function getDefaultBehavior(stubInstance) {
+ return stubInstance.defaultBehavior ||
+ getParentBehaviour(stubInstance) ||
+ behavior.create(stubInstance);
+}
+
+function getCurrentBehavior(stubInstance) {
+ var currentBehavior = stubInstance.behaviors[stubInstance.callCount - 1];
+ return currentBehavior && currentBehavior.isPresent() ? currentBehavior : getDefaultBehavior(stubInstance);
+}
+/*eslint-enable no-use-before-define*/
+
+var uuid = 0;
+
+var proto = {
+ create: function create(stubLength) {
+ var functionStub = function () {
+ return getCurrentBehavior(functionStub).invoke(this, arguments);
+ };
+
+ functionStub.id = "stub#" + uuid++;
+ var orig = functionStub;
+ functionStub = spy.create(functionStub, stubLength);
+ functionStub.func = orig;
+
+ extend(functionStub, stub);
+ functionStub.instantiateFake = stub.create;
+ functionStub.displayName = "stub";
+ functionStub.toString = functionToString;
+
+ functionStub.defaultBehavior = null;
+ functionStub.behaviors = [];
+
+ return functionStub;
+ },
+
+ resetBehavior: function () {
+ var fakes = this.fakes || [];
+
+ this.defaultBehavior = null;
+ this.behaviors = [];
+
+ delete this.returnValue;
+ delete this.returnArgAt;
+ delete this.fakeFn;
+ this.returnThis = false;
+
+ fakes.forEach(function (fake) {
+ fake.resetBehavior();
+ });
+ },
+
+ resetHistory: spy.reset,
+
+ reset: function () {
+ this.resetHistory();
+ this.resetBehavior();
+ },
+
+ onCall: function onCall(index) {
+ if (!this.behaviors[index]) {
+ this.behaviors[index] = behavior.create(this);
+ }
+
+ return this.behaviors[index];
+ },
+
+ onFirstCall: function onFirstCall() {
+ return this.onCall(0);
+ },
+
+ onSecondCall: function onSecondCall() {
+ return this.onCall(1);
+ },
+
+ onThirdCall: function onThirdCall() {
+ return this.onCall(2);
+ }
+};
+
+Object.keys(behavior).forEach(function (method) {
+ if (behavior.hasOwnProperty(method) &&
+ !proto.hasOwnProperty(method) &&
+ method !== "create" &&
+ method !== "withArgs" &&
+ method !== "invoke") {
+ proto[method] = behavior.createBehavior(method);
+ }
+});
+
+Object.keys(behaviors).forEach(function (method) {
+ if (behaviors.hasOwnProperty(method) && !proto.hasOwnProperty(method)) {
+ behavior.addBehavior(stub, method, behaviors[method]);
+ }
+});
+
+extend(stub, proto);
+module.exports = stub;
+
+},{"./behavior":3,"./default-behaviors":9,"./spy":15,"./stub-descriptor":16,"./stub-entire-object":17,"./throw-on-falsy-object":20,"./util/core/extend":26,"./util/core/function-to-string":29,"./util/core/get-property-descriptor":31,"./util/core/wrap-method":41}],20:[function(require,module,exports){
+"use strict";
+var valueToString = require("./util/core/value-to-string");
+
+function throwOnFalsyObject(object, property) {
+ if (property && !object) {
+ var type = object === null ? "null" : "undefined";
+ throw new Error("Trying to stub property '" + valueToString(property) + "' of " + type);
+ }
+}
+
+module.exports = throwOnFalsyObject;
+
+},{"./util/core/value-to-string":39}],21:[function(require,module,exports){
+"use strict";
+
+module.exports = function calledInOrder(spies) {
+ if (arguments.length > 1) {
+ spies = arguments;
+ }
+
+ for (var i = 1, l = spies.length; i < l; i++) {
+ if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) {
+ return false;
+ }
+ }
+
+ return true;
+};
+
+},{}],22:[function(require,module,exports){
+"use strict";
+
+var div = typeof document !== "undefined" && document.createElement("div");
+
+function isReallyNaN(val) {
+ return val !== val;
+}
+
+function isDOMNode(obj) {
+ var success = false;
+
+ try {
+ obj.appendChild(div);
+ success = div.parentNode === obj;
+ } catch (e) {
+ return false;
+ } finally {
+ try {
+ obj.removeChild(div);
+ } catch (e) {
+ // Remove failed, not much we can do about that
+ }
+ }
+
+ return success;
+}
+
+function isElement(obj) {
+ return div && obj && obj.nodeType === 1 && isDOMNode(obj);
+}
+
+var deepEqual = module.exports = function deepEqual(a, b) {
+ if (typeof a !== "object" || typeof b !== "object") {
+ return isReallyNaN(a) && isReallyNaN(b) || a === b;
+ }
+
+ if (isElement(a) || isElement(b)) {
+ return a === b;
+ }
+
+ if (a === b) {
+ return true;
+ }
+
+ if ((a === null && b !== null) || (a !== null && b === null)) {
+ return false;
+ }
+
+ if (a instanceof RegExp && b instanceof RegExp) {
+ return (a.source === b.source) && (a.global === b.global) &&
+ (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline);
+ }
+
+ if (a instanceof Error && b instanceof Error) {
+ return a === b;
+ }
+
+ var aString = Object.prototype.toString.call(a);
+ if (aString !== Object.prototype.toString.call(b)) {
+ return false;
+ }
+
+ if (aString === "[object Date]") {
+ return a.valueOf() === b.valueOf();
+ }
+
+ var prop;
+ var aLength = 0;
+ var bLength = 0;
+
+ if (aString === "[object Array]" && a.length !== b.length) {
+ return false;
+ }
+
+ for (prop in a) {
+ if (Object.prototype.hasOwnProperty.call(a, prop)) {
+ aLength += 1;
+
+ if (!(prop in b)) {
+ return false;
+ }
+
+ // allow alternative function for recursion
+ if (!(arguments[2] || deepEqual)(a[prop], b[prop])) {
+ return false;
+ }
+ }
+ }
+
+ for (prop in b) {
+ if (Object.prototype.hasOwnProperty.call(b, prop)) {
+ bLength += 1;
+ }
+ }
+
+ return aLength === bLength;
+};
+
+deepEqual.use = function (match) {
+ return function deepEqual$matcher(a, b) {
+ // If both are matchers they must be the same instance in order to be considered equal
+ // If we didn't do that we would end up running one matcher against the other
+ if (match.isMatcher(a)) {
+ if (match.isMatcher(b)) {
+ return a === b;
+ }
+
+ return a.test(b);
+ }
+
+ return deepEqual(a, b, deepEqual$matcher);
+ };
+};
+
+},{}],23:[function(require,module,exports){
+"use strict";
+
+module.exports = {
+ injectIntoThis: true,
+ injectInto: null,
+ properties: ["spy", "stub", "mock", "clock", "server", "requests"],
+ useFakeTimers: true,
+ useFakeServer: true
+};
+
+},{}],24:[function(require,module,exports){
+/*eslint no-console: 0 */
+"use strict";
+
+// wrap returns a function that will invoke the supplied function and print a deprecation warning to the console each
+// time it is called.
+exports.wrap = function (func, msg) {
+ var wrapped = function () {
+ exports.printWarning(msg);
+ return func.apply(this, arguments);
+ };
+ if (func.prototype) {
+ wrapped.prototype = func.prototype;
+ }
+ return wrapped;
+};
+
+// defaultMsg returns a string which can be supplied to `wrap()` to notify the user that a particular part of the
+// sinon API has been deprecated.
+exports.defaultMsg = function (funcName) {
+ return "sinon." + funcName + " is deprecated and will be removed from the public API in a future version of sinon.";
+};
+
+exports.printWarning = function (msg) {
+ // Watch out for IE7 and below! :(
+ if (typeof console !== "undefined") {
+ if (console.info) {
+ console.info(msg);
+ } else {
+ console.log(msg);
+ }
+ }
+};
+
+},{}],25:[function(require,module,exports){
+"use strict";
+
+// This is an `every` implementation that works for all iterables
+module.exports = function every(obj, fn) {
+ var pass = true;
+
+ try {
+ obj.forEach(function () {
+ if (!fn.apply(this, arguments)) {
+ // Throwing an error is the only way to break `forEach`
+ throw new Error();
+ }
+ });
+ } catch (e) {
+ pass = false;
+ }
+
+ return pass;
+};
+
+},{}],26:[function(require,module,exports){
+"use strict";
+
+// Adapted from https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug
+var hasDontEnumBug = (function () {
+ var obj = {
+ constructor: function () {
+ return "0";
+ },
+ toString: function () {
+ return "1";
+ },
+ valueOf: function () {
+ return "2";
+ },
+ toLocaleString: function () {
+ return "3";
+ },
+ prototype: function () {
+ return "4";
+ },
+ isPrototypeOf: function () {
+ return "5";
+ },
+ propertyIsEnumerable: function () {
+ return "6";
+ },
+ hasOwnProperty: function () {
+ return "7";
+ },
+ length: function () {
+ return "8";
+ },
+ unique: function () {
+ return "9";
+ }
+ };
+
+ var result = [];
+ for (var prop in obj) {
+ if (obj.hasOwnProperty(prop)) {
+ result.push(obj[prop]());
+ }
+ }
+ return result.join("") !== "0123456789";
+})();
+
+/* Public: Extend target in place with all (own) properties from sources in-order. Thus, last source will
+ * override properties in previous sources.
+ *
+ * target - The Object to extend
+ * sources - Objects to copy properties from.
+ *
+ * Returns the extended target
+ */
+module.exports = function extend(target /*, sources */) {
+ var sources = Array.prototype.slice.call(arguments, 1);
+ var source, i, prop;
+
+ for (i = 0; i < sources.length; i++) {
+ source = sources[i];
+
+ for (prop in source) {
+ if (source.hasOwnProperty(prop)) {
+ target[prop] = source[prop];
+ }
+ }
+
+ // Make sure we copy (own) toString method even when in JScript with DontEnum bug
+ // See https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug
+ if (hasDontEnumBug && source.hasOwnProperty("toString") && source.toString !== target.toString) {
+ target.toString = source.toString;
+ }
+ }
+
+ return target;
+};
+
+},{}],27:[function(require,module,exports){
+"use strict";
+
+var formatio = require("formatio");
+
+var formatter = formatio.configure({
+ quoteStrings: false,
+ limitChildrenCount: 250
+});
+
+module.exports = function format() {
+ return formatter.ascii.apply(formatter, arguments);
+};
+
+},{"formatio":63}],28:[function(require,module,exports){
+"use strict";
+
+module.exports = function functionName(func) {
+ var name = func.displayName || func.name;
+ var matches;
+
+ // Use function decomposition as a last resort to get function
+ // name. Does not rely on function decomposition to work - if it
+ // doesn't debugging will be slightly less informative
+ // (i.e. toString will say 'spy' rather than 'myFunc').
+ if (!name && (matches = func.toString().match(/function ([^\s\(]+)/))) {
+ name = matches[1];
+ }
+
+ return name;
+};
+
+
+},{}],29:[function(require,module,exports){
+"use strict";
+
+module.exports = function toString() {
+ var i, prop, thisValue;
+ if (this.getCall && this.callCount) {
+ i = this.callCount;
+
+ while (i--) {
+ thisValue = this.getCall(i).thisValue;
+
+ for (prop in thisValue) {
+ if (thisValue[prop] === this) {
+ return prop;
+ }
+ }
+ }
+ }
+
+ return this.displayName || "sinon fake";
+};
+
+},{}],30:[function(require,module,exports){
+"use strict";
+
+var defaultConfig = require("./default-config");
+
+module.exports = function getConfig(custom) {
+ var config = {};
+ var prop;
+
+ custom = custom || {};
+
+ for (prop in defaultConfig) {
+ if (defaultConfig.hasOwnProperty(prop)) {
+ config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaultConfig[prop];
+ }
+ }
+
+ return config;
+};
+
+},{"./default-config":23}],31:[function(require,module,exports){
+"use strict";
+
+module.exports = function getPropertyDescriptor(object, property) {
+ var proto = object;
+ var descriptor;
+
+ while (proto && !(descriptor = Object.getOwnPropertyDescriptor(proto, property))) {
+ proto = Object.getPrototypeOf(proto);
+ }
+ return descriptor;
+};
+
+},{}],32:[function(require,module,exports){
+"use strict";
+
+module.exports = {
+ calledInOrder: require("./called-in-order"),
+ configureLogError: require("./log_error"),
+ defaultConfig: require("./default-config"),
+ deepEqual: require("./deep-equal"),
+ every: require("./every"),
+ extend: require("./extend"),
+ format: require("./format"),
+ functionName: require("./function-name"),
+ functionToString: require("./function-to-string"),
+ getConfig: require("./get-config"),
+ getPropertyDescriptor: require("./get-property-descriptor"),
+ iterableToString: require("./iterable-to-string"),
+ orderByFirstCall: require("./order-by-first-call"),
+ restore: require("./restore"),
+ timesInWords: require("./times-in-words"),
+ typeOf: require("./typeOf"),
+ walk: require("./walk"),
+ wrapMethod: require("./wrap-method")
+};
+
+},{"./called-in-order":21,"./deep-equal":22,"./default-config":23,"./every":25,"./extend":26,"./format":27,"./function-name":28,"./function-to-string":29,"./get-config":30,"./get-property-descriptor":31,"./iterable-to-string":33,"./log_error":34,"./order-by-first-call":35,"./restore":36,"./times-in-words":37,"./typeOf":38,"./walk":40,"./wrap-method":41}],33:[function(require,module,exports){
+"use strict";
+var typeOf = require("./typeOf");
+
+module.exports = function iterableToString(obj) {
+ var representation = "";
+
+ function stringify(item) {
+ return typeof item === "string" ? "'" + item + "'" : String(item);
+ }
+
+ function mapToString(map) {
+ map.forEach(function (value, key) {
+ representation += "[" + stringify(key) + "," + stringify(value) + "],";
+ });
+
+ representation = representation.slice(0, -1);
+ return representation;
+ }
+
+ function genericIterableToString(iterable) {
+ iterable.forEach(function (value) {
+ representation += stringify(value) + ",";
+ });
+
+ representation = representation.slice(0, -1);
+ return representation;
+ }
+
+ if (typeOf(obj) === "map") {
+ return mapToString(obj);
+ }
+
+ return genericIterableToString(obj);
+};
+
+},{"./typeOf":38}],34:[function(require,module,exports){
+"use strict";
+
+// cache a reference to setTimeout, so that our reference won't be stubbed out
+// when using fake timers and errors will still get logged
+// https://github.com/cjohansen/Sinon.JS/issues/381
+var realSetTimeout = setTimeout;
+
+function configure(config) {
+ config = config || {};
+ // Function which prints errors.
+ if (!config.hasOwnProperty("logger")) {
+ config.logger = function () { };
+ }
+ // When set to true, any errors logged will be thrown immediately;
+ // If set to false, the errors will be thrown in separate execution frame.
+ if (!config.hasOwnProperty("useImmediateExceptions")) {
+ config.useImmediateExceptions = true;
+ }
+ // wrap realSetTimeout with something we can stub in tests
+ if (!config.hasOwnProperty("setTimeout")) {
+ config.setTimeout = realSetTimeout;
+ }
+
+ return function logError(label, e) {
+ var msg = label + " threw exception: ";
+ var err = { name: e.name || label, message: e.message || e.toString(), stack: e.stack };
+
+ function throwLoggedError() {
+ err.message = msg + err.message;
+ throw err;
+ }
+
+ config.logger(msg + "[" + err.name + "] " + err.message);
+
+ if (err.stack) {
+ config.logger(err.stack);
+ }
+
+ if (config.useImmediateExceptions) {
+ throwLoggedError();
+ } else {
+ config.setTimeout(throwLoggedError, 0);
+ }
+ };
+}
+
+module.exports = configure;
+
+},{}],35:[function(require,module,exports){
+"use strict";
+
+module.exports = function orderByFirstCall(spies) {
+ return spies.sort(function (a, b) {
+ // uuid, won't ever be equal
+ var aCall = a.getCall(0);
+ var bCall = b.getCall(0);
+ var aId = aCall && aCall.callId || -1;
+ var bId = bCall && bCall.callId || -1;
+
+ return aId < bId ? -1 : 1;
+ });
+};
+
+},{}],36:[function(require,module,exports){
+"use strict";
+
+var walk = require("./walk");
+
+function isRestorable(obj) {
+ return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon;
+}
+
+module.exports = function restore(object) {
+ if (object !== null && typeof object === "object") {
+ walk(object, function (prop) {
+ if (isRestorable(object[prop])) {
+ object[prop].restore();
+ }
+ });
+ } else if (isRestorable(object)) {
+ object.restore();
+ }
+};
+
+},{"./walk":40}],37:[function(require,module,exports){
+"use strict";
+
+var array = [null, "once", "twice", "thrice"];
+
+module.exports = function timesInWords(count) {
+ return array[count] || (count || 0) + " times";
+};
+
+},{}],38:[function(require,module,exports){
+"use strict";
+
+var type = require("type-detect");
+
+module.exports = function typeOf(value) {
+ return type(value).toLowerCase();
+};
+
+},{"type-detect":72}],39:[function(require,module,exports){
+"use strict";
+
+module.exports = function (value) {
+ if (value && value.toString) {
+ return value.toString();
+ }
+ return String(value);
+};
+
+},{}],40:[function(require,module,exports){
+"use strict";
+
+function walkInternal(obj, iterator, context, originalObj, seen) {
+ var proto, prop;
+
+ if (typeof Object.getOwnPropertyNames !== "function") {
+ // We explicitly want to enumerate through all of the prototype's properties
+ // in this case, therefore we deliberately leave out an own property check.
+ /* eslint-disable guard-for-in */
+ for (prop in obj) {
+ iterator.call(context, obj[prop], prop, obj);
+ }
+ /* eslint-enable guard-for-in */
+
+ return;
+ }
+
+ Object.getOwnPropertyNames(obj).forEach(function (k) {
+ if (seen[k] !== true) {
+ seen[k] = true;
+ var target = typeof Object.getOwnPropertyDescriptor(obj, k).get === "function" ?
+ originalObj : obj;
+ iterator.call(context, k, target);
+ }
+ });
+
+ proto = Object.getPrototypeOf(obj);
+ if (proto) {
+ walkInternal(proto, iterator, context, originalObj, seen);
+ }
+}
+
+/* Walks the prototype chain of an object and iterates over every own property
+ * name encountered. The iterator is called in the same fashion that Array.prototype.forEach
+ * works, where it is passed the value, key, and own object as the 1st, 2nd, and 3rd positional
+ * argument, respectively. In cases where Object.getOwnPropertyNames is not available, walk will
+ * default to using a simple for..in loop.
+ *
+ * obj - The object to walk the prototype chain for.
+ * iterator - The function to be called on each pass of the walk.
+ * context - (Optional) When given, the iterator will be called with this object as the receiver.
+ */
+module.exports = function walk(obj, iterator, context) {
+ return walkInternal(obj, iterator, context, obj, {});
+};
+
+},{}],41:[function(require,module,exports){
+"use strict";
+
+var getPropertyDescriptor = require("./get-property-descriptor");
+var valueToString = require("./value-to-string");
+
+var hasOwn = Object.prototype.hasOwnProperty;
+
+function isFunction(obj) {
+ return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply);
+}
+
+function mirrorProperties(target, source) {
+ for (var prop in source) {
+ if (!hasOwn.call(target, prop)) {
+ target[prop] = source[prop];
+ }
+ }
+}
+
+// Cheap way to detect if we have ES5 support.
+var hasES5Support = "keys" in Object;
+
+module.exports = function wrapMethod(object, property, method) {
+ if (!object) {
+ throw new TypeError("Should wrap property of object");
+ }
+
+ if (typeof method !== "function" && typeof method !== "object") {
+ throw new TypeError("Method wrapper should be a function or a property descriptor");
+ }
+
+ function checkWrappedMethod(wrappedMethod) {
+ var error;
+
+ if (!isFunction(wrappedMethod)) {
+ error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
+ valueToString(property) + " as function");
+ } else if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
+ error = new TypeError("Attempted to wrap " + valueToString(property) + " which is already wrapped");
+ } else if (wrappedMethod.calledBefore) {
+ var verb = wrappedMethod.returns ? "stubbed" : "spied on";
+ error = new TypeError("Attempted to wrap " + valueToString(property) + " which is already " + verb);
+ }
+
+ if (error) {
+ if (wrappedMethod && wrappedMethod.stackTrace) {
+ error.stack += "\n--------------\n" + wrappedMethod.stackTrace;
+ }
+ throw error;
+ }
+ }
+
+ var error, wrappedMethod, i;
+
+ function simplePropertyAssignment() {
+ wrappedMethod = object[property];
+ checkWrappedMethod(wrappedMethod);
+ object[property] = method;
+ method.displayName = property;
+ }
+
+ // Firefox has a problem when using hasOwn.call on objects from other frames.
+ var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property);
+
+ if (hasES5Support) {
+ var methodDesc = (typeof method === "function") ? {value: method} : method;
+ var wrappedMethodDesc = getPropertyDescriptor(object, property);
+
+ if (!wrappedMethodDesc) {
+ error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
+ property + " as function");
+ } else if (wrappedMethodDesc.restore && wrappedMethodDesc.restore.sinon) {
+ error = new TypeError("Attempted to wrap " + property + " which is already wrapped");
+ }
+ if (error) {
+ if (wrappedMethodDesc && wrappedMethodDesc.stackTrace) {
+ error.stack += "\n--------------\n" + wrappedMethodDesc.stackTrace;
+ }
+ throw error;
+ }
+
+ var types = Object.keys(methodDesc);
+ for (i = 0; i < types.length; i++) {
+ wrappedMethod = wrappedMethodDesc[types[i]];
+ checkWrappedMethod(wrappedMethod);
+ }
+
+ mirrorProperties(methodDesc, wrappedMethodDesc);
+ for (i = 0; i < types.length; i++) {
+ mirrorProperties(methodDesc[types[i]], wrappedMethodDesc[types[i]]);
+ }
+ Object.defineProperty(object, property, methodDesc);
+
+ // catch failing assignment
+ // this is the converse of the check in `.restore` below
+ if ( typeof method === "function" && object[property] !== method ) {
+ // correct any wrongdoings caused by the defineProperty call above,
+ // such as adding new items (if object was a Storage object)
+ delete object[property];
+ simplePropertyAssignment();
+ }
+ } else {
+ simplePropertyAssignment();
+ }
+
+ method.displayName = property;
+
+ // Set up a stack trace which can be used later to find what line of
+ // code the original method was created on.
+ method.stackTrace = (new Error("Stack Trace for original")).stack;
+
+ method.restore = function () {
+ // For prototype properties try to reset by delete first.
+ // If this fails (ex: localStorage on mobile safari) then force a reset
+ // via direct assignment.
+ if (!owned) {
+ // In some cases `delete` may throw an error
+ try {
+ delete object[property];
+ } catch (e) {} // eslint-disable-line no-empty
+ // For native code functions `delete` fails without throwing an error
+ // on Chrome < 43, PhantomJS, etc.
+ } else if (hasES5Support) {
+ Object.defineProperty(object, property, wrappedMethodDesc);
+ }
+
+ if (hasES5Support) {
+ var descriptor = getPropertyDescriptor(object, property);
+ if (descriptor && descriptor.value === method) {
+ object[property] = wrappedMethod;
+ }
+ }
+ else {
+ // Use strict equality comparison to check failures then force a reset
+ // via direct assignment.
+ if (object[property] === method) {
+ object[property] = wrappedMethod;
+ }
+ }
+ };
+
+ method.wrappedMethod = wrappedMethod;
+
+ method.restore.sinon = true;
+
+ if (!hasES5Support) {
+ mirrorProperties(method, wrappedMethod);
+ }
+
+ return method;
+};
+
+},{"./get-property-descriptor":31,"./value-to-string":39}],42:[function(require,module,exports){
+"use strict";
+
+var push = [].push;
+
+function Event(type, bubbles, cancelable, target) {
+ this.initEvent(type, bubbles, cancelable, target);
+}
+
+Event.prototype = {
+ initEvent: function (type, bubbles, cancelable, target) {
+ this.type = type;
+ this.bubbles = bubbles;
+ this.cancelable = cancelable;
+ this.target = target;
+ },
+
+ stopPropagation: function () {},
+
+ preventDefault: function () {
+ this.defaultPrevented = true;
+ }
+};
+
+function ProgressEvent(type, progressEventRaw, target) {
+ this.initEvent(type, false, false, target);
+ this.loaded = typeof progressEventRaw.loaded === "number" ? progressEventRaw.loaded : null;
+ this.total = typeof progressEventRaw.total === "number" ? progressEventRaw.total : null;
+ this.lengthComputable = !!progressEventRaw.total;
+}
+
+ProgressEvent.prototype = new Event();
+
+ProgressEvent.prototype.constructor = ProgressEvent;
+
+function CustomEvent(type, customData, target) {
+ this.initEvent(type, false, false, target);
+ this.detail = customData.detail || null;
+}
+
+CustomEvent.prototype = new Event();
+
+CustomEvent.prototype.constructor = CustomEvent;
+
+var EventTarget = {
+ addEventListener: function addEventListener(event, listener) {
+ this.eventListeners = this.eventListeners || {};
+ this.eventListeners[event] = this.eventListeners[event] || [];
+ push.call(this.eventListeners[event], listener);
+ },
+
+ removeEventListener: function removeEventListener(event, listener) {
+ var listeners = this.eventListeners && this.eventListeners[event] || [];
+ var index = listeners.indexOf(listener);
+
+ if (index === -1) {
+ return;
+ }
+
+ listeners.splice(index, 1);
+ },
+
+ dispatchEvent: function dispatchEvent(event) {
+ var self = this;
+ var type = event.type;
+ var listeners = self.eventListeners && self.eventListeners[type] || [];
+
+ listeners.forEach(function (listener) {
+ if (typeof listener === "function") {
+ listener.call(self, event);
+ } else {
+ listener.handleEvent(event);
+ }
+ });
+
+ return !!event.defaultPrevented;
+ }
+};
+
+module.exports = {
+ Event: Event,
+ ProgressEvent: ProgressEvent,
+ CustomEvent: CustomEvent,
+ EventTarget: EventTarget
+};
+
+},{}],43:[function(require,module,exports){
+"use strict";
+
+var fakeXhr = require("./fake_xml_http_request");
+var push = [].push;
+var format = require("./core/format");
+var configureLogError = require("./core/log_error");
+var pathToRegexp = require("path-to-regexp");
+
+function responseArray(handler) {
+ var response = handler;
+
+ if (Object.prototype.toString.call(handler) !== "[object Array]") {
+ response = [200, {}, handler];
+ }
+
+ if (typeof response[2] !== "string") {
+ throw new TypeError("Fake server response body should be string, but was " +
+ typeof response[2]);
+ }
+
+ return response;
+}
+
+var wloc = typeof window !== "undefined" ? window.location : { "host": "localhost", "protocol": "http"};
+var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);
+
+function matchOne(response, reqMethod, reqUrl) {
+ var rmeth = response.method;
+ var matchMethod = !rmeth || rmeth.toLowerCase() === reqMethod.toLowerCase();
+ var url = response.url;
+ var matchUrl = !url || url === reqUrl || (typeof url.test === "function" && url.test(reqUrl));
+
+ return matchMethod && matchUrl;
+}
+
+function match(response, request) {
+ var requestUrl = request.url;
+
+ if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
+ requestUrl = requestUrl.replace(rCurrLoc, "");
+ }
+
+ if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
+ if (typeof response.response === "function") {
+ var ru = response.url;
+ var args = [request].concat(ru && typeof ru.exec === "function" ? ru.exec(requestUrl).slice(1) : []);
+ return response.response.apply(response, args);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+function incrementRequestCount() {
+ var count = ++this.requestCount;
+
+ this.requested = true;
+
+ this.requestedOnce = count === 1;
+ this.requestedTwice = count === 2;
+ this.requestedThrice = count === 3;
+
+ this.firstRequest = this.getRequest(0);
+ this.secondRequest = this.getRequest(1);
+ this.thirdRequest = this.getRequest(2);
+
+ this.lastRequest = this.getRequest(count - 1);
+}
+
+var fakeServer = {
+ create: function (config) {
+ var server = Object.create(this);
+ server.configure(config);
+ this.xhr = fakeXhr.useFakeXMLHttpRequest();
+ server.requests = [];
+ server.requestCount = 0;
+
+ this.xhr.onCreate = function (xhrObj) {
+ xhrObj.unsafeHeadersEnabled = function () {
+ return !(server.unsafeHeadersEnabled === false);
+ };
+ server.addRequest(xhrObj);
+ };
+
+ return server;
+ },
+
+ configure: function (config) {
+ var self = this;
+ var whitelist = {
+ "autoRespond": true,
+ "autoRespondAfter": true,
+ "respondImmediately": true,
+ "fakeHTTPMethods": true,
+ "logger": true,
+ "unsafeHeadersEnabled": true
+ };
+
+ config = config || {};
+
+ Object.keys(config).forEach(function (setting) {
+ if (setting in whitelist) {
+ self[setting] = config[setting];
+ }
+ });
+
+ self.logError = configureLogError(config);
+ },
+
+ addRequest: function addRequest(xhrObj) {
+ var server = this;
+ push.call(this.requests, xhrObj);
+
+ incrementRequestCount.call(this);
+
+ xhrObj.onSend = function () {
+ server.handleRequest(this);
+
+ if (server.respondImmediately) {
+ server.respond();
+ } else if (server.autoRespond && !server.responding) {
+ setTimeout(function () {
+ server.responding = false;
+ server.respond();
+ }, server.autoRespondAfter || 10);
+
+ server.responding = true;
+ }
+ };
+ },
+
+ getHTTPMethod: function getHTTPMethod(request) {
+ if (this.fakeHTTPMethods && /post/i.test(request.method)) {
+ var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);
+ return matches ? matches[1] : request.method;
+ }
+
+ return request.method;
+ },
+
+ handleRequest: function handleRequest(xhr) {
+ if (xhr.async) {
+ if (!this.queue) {
+ this.queue = [];
+ }
+
+ push.call(this.queue, xhr);
+ } else {
+ this.processRequest(xhr);
+ }
+ },
+
+ logger: function () {
+ // no-op; override via configure()
+ },
+
+ logError: configureLogError({}),
+
+ log: function log(response, request) {
+ var str;
+
+ str = "Request:\n" + format(request) + "\n\n";
+ str += "Response:\n" + format(response) + "\n\n";
+
+ if (typeof this.logger === "function") {
+ this.logger(str);
+ }
+ },
+
+ respondWith: function respondWith(method, url, body) {
+ if (arguments.length === 1 && typeof method !== "function") {
+ this.response = responseArray(method);
+ return;
+ }
+
+ if (!this.responses) {
+ this.responses = [];
+ }
+
+ if (arguments.length === 1) {
+ body = method;
+ url = method = null;
+ }
+
+ if (arguments.length === 2) {
+ body = url;
+ url = method;
+ method = null;
+ }
+
+ push.call(this.responses, {
+ method: method,
+ url: typeof url === "string" && url !== "" ? pathToRegexp(url) : url,
+ response: typeof body === "function" ? body : responseArray(body)
+ });
+ },
+
+ respond: function respond() {
+ if (arguments.length > 0) {
+ this.respondWith.apply(this, arguments);
+ }
+
+ var queue = this.queue || [];
+ var requests = queue.splice(0, queue.length);
+ var self = this;
+
+ requests.forEach(function (request) {
+ self.processRequest(request);
+ });
+ },
+
+ processRequest: function processRequest(request) {
+ try {
+ if (request.aborted) {
+ return;
+ }
+
+ var response = this.response || [404, {}, ""];
+
+ if (this.responses) {
+ for (var l = this.responses.length, i = l - 1; i >= 0; i--) {
+ if (match.call(this, this.responses[i], request)) {
+ response = this.responses[i].response;
+ break;
+ }
+ }
+ }
+
+ if (request.readyState !== 4) {
+ this.log(response, request);
+
+ request.respond(response[0], response[1], response[2]);
+ }
+ } catch (e) {
+ this.logError("Fake server request processing", e);
+ }
+ },
+
+ restore: function restore() {
+ return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
+ },
+
+ getRequest: function getRequest(index) {
+ return this.requests[index] || null;
+ },
+
+ reset: function reset() {
+ this.resetBehavior();
+ this.resetHistory();
+ },
+
+ resetBehavior: function resetBehavior() {
+ this.responses.length = this.queue.length = 0;
+ },
+
+ resetHistory: function resetHistory() {
+ this.requests.length = this.requestCount = 0;
+
+ this.requestedOnce = this.requestedTwice = this.requestedThrice = this.requested = false;
+
+ this.firstRequest = this.secondRequest = this.thirdRequest = this.lastRequest = null;
+ }
+};
+
+module.exports = fakeServer;
+
+},{"./core/format":27,"./core/log_error":34,"./fake_xml_http_request":46,"path-to-regexp":66}],44:[function(require,module,exports){
+"use strict";
+
+var fakeServer = require("./fake_server");
+var fakeTimers = require("./fake_timers");
+
+function Server() {}
+Server.prototype = fakeServer;
+
+var fakeServerWithClock = new Server();
+
+fakeServerWithClock.addRequest = function addRequest(xhr) {
+ if (xhr.async) {
+ if (typeof setTimeout.clock === "object") {
+ this.clock = setTimeout.clock;
+ } else {
+ this.clock = fakeTimers.useFakeTimers();
+ this.resetClock = true;
+ }
+
+ if (!this.longestTimeout) {
+ var clockSetTimeout = this.clock.setTimeout;
+ var clockSetInterval = this.clock.setInterval;
+ var server = this;
+
+ this.clock.setTimeout = function (fn, timeout) {
+ server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
+
+ return clockSetTimeout.apply(this, arguments);
+ };
+
+ this.clock.setInterval = function (fn, timeout) {
+ server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
+
+ return clockSetInterval.apply(this, arguments);
+ };
+ }
+ }
+
+ return fakeServer.addRequest.call(this, xhr);
+};
+
+fakeServerWithClock.respond = function respond() {
+ var returnVal = fakeServer.respond.apply(this, arguments);
+
+ if (this.clock) {
+ this.clock.tick(this.longestTimeout || 0);
+ this.longestTimeout = 0;
+
+ if (this.resetClock) {
+ this.clock.restore();
+ this.resetClock = false;
+ }
+ }
+
+ return returnVal;
+};
+
+fakeServerWithClock.restore = function restore() {
+ if (this.clock) {
+ this.clock.restore();
+ }
+
+ return fakeServer.restore.apply(this, arguments);
+};
+
+module.exports = fakeServerWithClock;
+
+},{"./fake_server":43,"./fake_timers":45}],45:[function(require,module,exports){
+"use strict";
+
+var llx = require("lolex");
+
+exports.useFakeTimers = function () {
+ var now;
+ var methods = Array.prototype.slice.call(arguments);
+
+ if (typeof methods[0] === "string") {
+ now = 0;
+ } else {
+ now = methods.shift();
+ }
+
+ var clock = llx.install(now || 0, methods);
+ clock.restore = clock.uninstall;
+ return clock;
+};
+
+exports.clock = {
+ create: function (now) {
+ return llx.createClock(now);
+ }
+};
+
+exports.timers = {
+ setTimeout: setTimeout,
+ clearTimeout: clearTimeout,
+ setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
+ clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate : undefined),
+ setInterval: setInterval,
+ clearInterval: clearInterval,
+ Date: Date
+};
+
+},{"lolex":65}],46:[function(require,module,exports){
+(function (global){
+"use strict";
+
+var TextEncoder = require("text-encoding").TextEncoder;
+
+var configureLogError = require("./core/log_error");
+var sinonEvent = require("./event");
+var extend = require("./core/extend");
+
+function getWorkingXHR(globalScope) {
+ var supportsXHR = typeof globalScope.XMLHttpRequest !== "undefined";
+ if (supportsXHR) {
+ return globalScope.XMLHttpRequest;
+ }
+
+ var supportsActiveX = typeof globalScope.ActiveXObject !== "undefined";
+ if (supportsActiveX) {
+ return function () {
+ return new globalScope.ActiveXObject("MSXML2.XMLHTTP.3.0");
+ };
+ }
+
+ return false;
+}
+
+var supportsProgress = typeof ProgressEvent !== "undefined";
+var supportsCustomEvent = typeof CustomEvent !== "undefined";
+var supportsFormData = typeof FormData !== "undefined";
+var supportsArrayBuffer = typeof ArrayBuffer !== "undefined";
+var supportsBlob = require("../blob").isSupported;
+var isReactNative = global.navigator && global.navigator.product === "ReactNative";
+var sinonXhr = { XMLHttpRequest: global.XMLHttpRequest };
+sinonXhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
+sinonXhr.GlobalActiveXObject = global.ActiveXObject;
+sinonXhr.supportsActiveX = typeof sinonXhr.GlobalActiveXObject !== "undefined";
+sinonXhr.supportsXHR = typeof sinonXhr.GlobalXMLHttpRequest !== "undefined";
+sinonXhr.workingXHR = getWorkingXHR(global);
+sinonXhr.supportsCORS = isReactNative ||
+ (sinonXhr.supportsXHR && "withCredentials" in (new sinonXhr.GlobalXMLHttpRequest()));
+
+var unsafeHeaders = {
+ "Accept-Charset": true,
+ "Accept-Encoding": true,
+ "Connection": true,
+ "Content-Length": true,
+ "Cookie": true,
+ "Cookie2": true,
+ "Content-Transfer-Encoding": true,
+ "Date": true,
+ "Expect": true,
+ "Host": true,
+ "Keep-Alive": true,
+ "Referer": true,
+ "TE": true,
+ "Trailer": true,
+ "Transfer-Encoding": true,
+ "Upgrade": true,
+ "User-Agent": true,
+ "Via": true
+};
+
+
+function EventTargetHandler() {
+ var self = this;
+ var events = ["loadstart", "progress", "abort", "error", "load", "timeout", "loadend"];
+
+ function addEventListener(eventName) {
+ self.addEventListener(eventName, function (event) {
+ var listener = self["on" + eventName];
+
+ if (listener && typeof listener === "function") {
+ listener.call(this, event);
+ }
+ });
+ }
+
+ events.forEach(addEventListener);
+}
+
+EventTargetHandler.prototype = sinonEvent.EventTarget;
+
+// Note that for FakeXMLHttpRequest to work pre ES5
+// we lose some of the alignment with the spec.
+// To ensure as close a match as possible,
+// set responseType before calling open, send or respond;
+function FakeXMLHttpRequest(config) {
+ EventTargetHandler.call(this);
+ this.readyState = FakeXMLHttpRequest.UNSENT;
+ this.requestHeaders = {};
+ this.requestBody = null;
+ this.status = 0;
+ this.statusText = "";
+ this.upload = new EventTargetHandler();
+ this.responseType = "";
+ this.response = "";
+ this.logError = configureLogError(config);
+ if (sinonXhr.supportsCORS) {
+ this.withCredentials = false;
+ }
+
+ if (typeof FakeXMLHttpRequest.onCreate === "function") {
+ FakeXMLHttpRequest.onCreate(this);
+ }
+}
+
+function verifyState(xhr) {
+ if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
+ throw new Error("INVALID_STATE_ERR");
+ }
+
+ if (xhr.sendFlag) {
+ throw new Error("INVALID_STATE_ERR");
+ }
+}
+
+function getHeader(headers, header) {
+ var foundHeader = Object.keys(headers).filter(function (h) {
+ return h.toLowerCase() === header.toLowerCase();
+ });
+
+ return foundHeader[0] || null;
+}
+
+function excludeSetCookie2Header(header) {
+ return !/^Set-Cookie2?$/i.test(header);
+}
+
+// largest arity in XHR is 5 - XHR#open
+var apply = function (obj, method, args) {
+ switch (args.length) {
+ case 0: return obj[method]();
+ case 1: return obj[method](args[0]);
+ case 2: return obj[method](args[0], args[1]);
+ case 3: return obj[method](args[0], args[1], args[2]);
+ case 4: return obj[method](args[0], args[1], args[2], args[3]);
+ case 5: return obj[method](args[0], args[1], args[2], args[3], args[4]);
+ default: throw new Error("Unhandled case");
+ }
+};
+
+FakeXMLHttpRequest.filters = [];
+FakeXMLHttpRequest.addFilter = function addFilter(fn) {
+ this.filters.push(fn);
+};
+FakeXMLHttpRequest.defake = function defake(fakeXhr, xhrArgs) {
+ var xhr = new sinonXhr.workingXHR(); // eslint-disable-line new-cap
+
+ [
+ "open",
+ "setRequestHeader",
+ "send",
+ "abort",
+ "getResponseHeader",
+ "getAllResponseHeaders",
+ "addEventListener",
+ "overrideMimeType",
+ "removeEventListener"
+ ].forEach(function (method) {
+ fakeXhr[method] = function () {
+ return apply(xhr, method, arguments);
+ };
+ });
+
+ var copyAttrs = function (args) {
+ args.forEach(function (attr) {
+ fakeXhr[attr] = xhr[attr];
+ });
+ };
+
+ var stateChange = function stateChange() {
+ fakeXhr.readyState = xhr.readyState;
+ if (xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ copyAttrs(["status", "statusText"]);
+ }
+ if (xhr.readyState >= FakeXMLHttpRequest.LOADING) {
+ copyAttrs(["responseText", "response"]);
+ }
+ if (xhr.readyState === FakeXMLHttpRequest.DONE) {
+ copyAttrs(["responseXML"]);
+ }
+ if (fakeXhr.onreadystatechange) {
+ fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr });
+ }
+ };
+
+ if (xhr.addEventListener) {
+ Object.keys(fakeXhr.eventListeners).forEach(function (event) {
+ /*eslint-disable no-loop-func*/
+ fakeXhr.eventListeners[event].forEach(function (handler) {
+ xhr.addEventListener(event, handler);
+ });
+ /*eslint-enable no-loop-func*/
+ });
+
+ xhr.addEventListener("readystatechange", stateChange);
+ } else {
+ xhr.onreadystatechange = stateChange;
+ }
+ apply(xhr, "open", xhrArgs);
+};
+FakeXMLHttpRequest.useFilters = false;
+
+function verifyRequestOpened(xhr) {
+ if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
+ throw new Error("INVALID_STATE_ERR - " + xhr.readyState);
+ }
+}
+
+function verifyRequestSent(xhr) {
+ if (xhr.readyState === FakeXMLHttpRequest.DONE) {
+ throw new Error("Request done");
+ }
+}
+
+function verifyHeadersReceived(xhr) {
+ if (xhr.async && xhr.readyState !== FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ throw new Error("No headers received");
+ }
+}
+
+function verifyResponseBodyType(body) {
+ if (typeof body !== "string") {
+ var error = new Error("Attempted to respond to fake XMLHttpRequest with " +
+ body + ", which is not a string.");
+ error.name = "InvalidBodyException";
+ throw error;
+ }
+}
+
+function convertToArrayBuffer(body, encoding) {
+ return new TextEncoder(encoding || "utf-8").encode(body).buffer;
+}
+
+function isXmlContentType(contentType) {
+ return !contentType || /(text\/xml)|(application\/xml)|(\+xml)/.test(contentType);
+}
+
+function convertResponseBody(responseType, contentType, body) {
+ if (responseType === "" || responseType === "text") {
+ return body;
+ } else if (supportsArrayBuffer && responseType === "arraybuffer") {
+ return convertToArrayBuffer(body);
+ } else if (responseType === "json") {
+ try {
+ return JSON.parse(body);
+ } catch (e) {
+ // Return parsing failure as null
+ return null;
+ }
+ } else if (supportsBlob && responseType === "blob") {
+ var blobOptions = {};
+ if (contentType) {
+ blobOptions.type = contentType;
+ }
+ return new Blob([convertToArrayBuffer(body)], blobOptions);
+ } else if (responseType === "document") {
+ if (isXmlContentType(contentType)) {
+ return FakeXMLHttpRequest.parseXML(body);
+ }
+ return null;
+ }
+ throw new Error("Invalid responseType " + responseType);
+}
+
+function clearResponse(xhr) {
+ if (xhr.responseType === "" || xhr.responseType === "text") {
+ xhr.response = xhr.responseText = "";
+ } else {
+ xhr.response = xhr.responseText = null;
+ }
+ xhr.responseXML = null;
+}
+
+FakeXMLHttpRequest.parseXML = function parseXML(text) {
+ // Treat empty string as parsing failure
+ if (text !== "") {
+ try {
+ if (typeof DOMParser !== "undefined") {
+ var parser = new DOMParser();
+ return parser.parseFromString(text, "text/xml");
+ }
+ var xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM");
+ xmlDoc.async = "false";
+ xmlDoc.loadXML(text);
+ return xmlDoc;
+ } catch (e) {
+ // Unable to parse XML - no biggie
+ }
+ }
+
+ return null;
+};
+
+FakeXMLHttpRequest.statusCodes = {
+ 100: "Continue",
+ 101: "Switching Protocols",
+ 200: "OK",
+ 201: "Created",
+ 202: "Accepted",
+ 203: "Non-Authoritative Information",
+ 204: "No Content",
+ 205: "Reset Content",
+ 206: "Partial Content",
+ 207: "Multi-Status",
+ 300: "Multiple Choice",
+ 301: "Moved Permanently",
+ 302: "Found",
+ 303: "See Other",
+ 304: "Not Modified",
+ 305: "Use Proxy",
+ 307: "Temporary Redirect",
+ 400: "Bad Request",
+ 401: "Unauthorized",
+ 402: "Payment Required",
+ 403: "Forbidden",
+ 404: "Not Found",
+ 405: "Method Not Allowed",
+ 406: "Not Acceptable",
+ 407: "Proxy Authentication Required",
+ 408: "Request Timeout",
+ 409: "Conflict",
+ 410: "Gone",
+ 411: "Length Required",
+ 412: "Precondition Failed",
+ 413: "Request Entity Too Large",
+ 414: "Request-URI Too Long",
+ 415: "Unsupported Media Type",
+ 416: "Requested Range Not Satisfiable",
+ 417: "Expectation Failed",
+ 422: "Unprocessable Entity",
+ 500: "Internal Server Error",
+ 501: "Not Implemented",
+ 502: "Bad Gateway",
+ 503: "Service Unavailable",
+ 504: "Gateway Timeout",
+ 505: "HTTP Version Not Supported"
+};
+
+extend(FakeXMLHttpRequest.prototype, sinonEvent.EventTarget, {
+ async: true,
+
+ open: function open(method, url, async, username, password) {
+ this.method = method;
+ this.url = url;
+ this.async = typeof async === "boolean" ? async : true;
+ this.username = username;
+ this.password = password;
+ clearResponse(this);
+ this.requestHeaders = {};
+ this.sendFlag = false;
+
+ if (FakeXMLHttpRequest.useFilters === true) {
+ var xhrArgs = arguments;
+ var defake = FakeXMLHttpRequest.filters.some(function (filter) {
+ return filter.apply(this, xhrArgs);
+ });
+ if (defake) {
+ FakeXMLHttpRequest.defake(this, arguments);
+ return;
+ }
+ }
+ this.readyStateChange(FakeXMLHttpRequest.OPENED);
+ },
+
+ readyStateChange: function readyStateChange(state) {
+ this.readyState = state;
+
+ var readyStateChangeEvent = new sinonEvent.Event("readystatechange", false, false, this);
+ var event, progress;
+
+ if (typeof this.onreadystatechange === "function") {
+ try {
+ this.onreadystatechange(readyStateChangeEvent);
+ } catch (e) {
+ this.logError("Fake XHR onreadystatechange handler", e);
+ }
+ }
+
+ if (this.readyState === FakeXMLHttpRequest.DONE) {
+ if (this.aborted || this.status === 0) {
+ progress = {loaded: 0, total: 0};
+ event = this.aborted ? "abort" : "error";
+ } else {
+ progress = {loaded: 100, total: 100};
+ event = "load";
+ }
+
+ if (supportsProgress) {
+ this.upload.dispatchEvent(new sinonEvent.ProgressEvent("progress", progress, this));
+ this.upload.dispatchEvent(new sinonEvent.ProgressEvent(event, progress, this));
+ this.upload.dispatchEvent(new sinonEvent.ProgressEvent("loadend", progress, this));
+ }
+
+ this.dispatchEvent(new sinonEvent.ProgressEvent("progress", progress, this));
+ this.dispatchEvent(new sinonEvent.ProgressEvent(event, progress, this));
+ this.dispatchEvent(new sinonEvent.ProgressEvent("loadend", progress, this));
+ }
+
+ this.dispatchEvent(readyStateChangeEvent);
+ },
+
+ setRequestHeader: function setRequestHeader(header, value) {
+ verifyState(this);
+
+ var checkUnsafeHeaders = true;
+ if (typeof this.unsafeHeadersEnabled === "function") {
+ checkUnsafeHeaders = this.unsafeHeadersEnabled();
+ }
+
+ if (checkUnsafeHeaders && (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header))) {
+ throw new Error("Refused to set unsafe header \"" + header + "\"");
+ }
+
+ if (this.requestHeaders[header]) {
+ this.requestHeaders[header] += "," + value;
+ } else {
+ this.requestHeaders[header] = value;
+ }
+ },
+
+ setStatus: function setStatus(status) {
+ var sanitizedStatus = typeof status === "number" ? status : 200;
+
+ verifyRequestOpened(this);
+ this.status = sanitizedStatus;
+ this.statusText = FakeXMLHttpRequest.statusCodes[sanitizedStatus];
+ },
+
+ // Helps testing
+ setResponseHeaders: function setResponseHeaders(headers) {
+ verifyRequestOpened(this);
+
+ var responseHeaders = this.responseHeaders = {};
+
+ Object.keys(headers).forEach(function (header) {
+ responseHeaders[header] = headers[header];
+ });
+
+ if (this.async) {
+ this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);
+ } else {
+ this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED;
+ }
+ },
+
+ // Currently treats ALL data as a DOMString (i.e. no Document)
+ send: function send(data) {
+ verifyState(this);
+
+ if (!/^(head)$/i.test(this.method)) {
+ var contentType = getHeader(this.requestHeaders, "Content-Type");
+ if (this.requestHeaders[contentType]) {
+ var value = this.requestHeaders[contentType].split(";");
+ this.requestHeaders[contentType] = value[0] + ";charset=utf-8";
+ } else if (supportsFormData && !(data instanceof FormData)) {
+ this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
+ }
+
+ this.requestBody = data;
+ }
+
+ this.errorFlag = false;
+ this.sendFlag = this.async;
+ clearResponse(this);
+ this.readyStateChange(FakeXMLHttpRequest.OPENED);
+
+ if (typeof this.onSend === "function") {
+ this.onSend(this);
+ }
+
+ this.dispatchEvent(new sinonEvent.Event("loadstart", false, false, this));
+ },
+
+ abort: function abort() {
+ this.aborted = true;
+ clearResponse(this);
+ this.errorFlag = true;
+ this.requestHeaders = {};
+ this.responseHeaders = {};
+
+ if (this.readyState !== FakeXMLHttpRequest.UNSENT && this.sendFlag
+ && this.readyState !== FakeXMLHttpRequest.DONE) {
+ this.readyStateChange(FakeXMLHttpRequest.DONE);
+ this.sendFlag = false;
+ }
+
+ this.readyState = FakeXMLHttpRequest.UNSENT;
+ },
+
+ error: function () {
+ clearResponse(this);
+ this.errorFlag = true;
+ this.requestHeaders = {};
+ this.responseHeaders = {};
+
+ this.readyStateChange(FakeXMLHttpRequest.DONE);
+ },
+
+ getResponseHeader: function getResponseHeader(header) {
+ if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ return null;
+ }
+
+ if (/^Set-Cookie2?$/i.test(header)) {
+ return null;
+ }
+
+ header = getHeader(this.responseHeaders, header);
+
+ return this.responseHeaders[header] || null;
+ },
+
+ getAllResponseHeaders: function getAllResponseHeaders() {
+ if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ return "";
+ }
+
+ var responseHeaders = this.responseHeaders;
+ var headers = Object.keys(responseHeaders)
+ .filter(excludeSetCookie2Header)
+ .reduce(function (prev, header) {
+ var value = responseHeaders[header];
+
+ return prev + (header + ": " + value + "\r\n");
+ }, "");
+
+ return headers;
+ },
+
+ setResponseBody: function setResponseBody(body) {
+ verifyRequestSent(this);
+ verifyHeadersReceived(this);
+ verifyResponseBodyType(body);
+ var contentType = this.overriddenMimeType || this.getResponseHeader("Content-Type");
+
+ var isTextResponse = this.responseType === "" || this.responseType === "text";
+ clearResponse(this);
+ if (this.async) {
+ var chunkSize = this.chunkSize || 10;
+ var index = 0;
+
+ do {
+ this.readyStateChange(FakeXMLHttpRequest.LOADING);
+
+ if (isTextResponse) {
+ this.responseText = this.response += body.substring(index, index + chunkSize);
+ }
+ index += chunkSize;
+ } while (index < body.length);
+ }
+
+ this.response = convertResponseBody(this.responseType, contentType, body);
+ if (isTextResponse) {
+ this.responseText = this.response;
+ }
+
+ if (this.responseType === "document") {
+ this.responseXML = this.response;
+ } else if (this.responseType === "" && isXmlContentType(contentType)) {
+ this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);
+ }
+ this.readyStateChange(FakeXMLHttpRequest.DONE);
+ },
+
+ respond: function respond(status, headers, body) {
+ this.setStatus(status);
+ this.setResponseHeaders(headers || {});
+ this.setResponseBody(body || "");
+ },
+
+ uploadProgress: function uploadProgress(progressEventRaw) {
+ if (supportsProgress) {
+ this.upload.dispatchEvent(new sinonEvent.ProgressEvent("progress", progressEventRaw));
+ }
+ },
+
+ downloadProgress: function downloadProgress(progressEventRaw) {
+ if (supportsProgress) {
+ this.dispatchEvent(new sinonEvent.ProgressEvent("progress", progressEventRaw));
+ }
+ },
+
+ uploadError: function uploadError(error) {
+ if (supportsCustomEvent) {
+ this.upload.dispatchEvent(new sinonEvent.CustomEvent("error", {detail: error}));
+ }
+ },
+
+ overrideMimeType: function overrideMimeType(type) {
+ if (this.readyState >= FakeXMLHttpRequest.LOADING) {
+ throw new Error("INVALID_STATE_ERR");
+ }
+ this.overriddenMimeType = type;
+ }
+});
+
+var states = {
+ UNSENT: 0,
+ OPENED: 1,
+ HEADERS_RECEIVED: 2,
+ LOADING: 3,
+ DONE: 4
+};
+
+extend(FakeXMLHttpRequest, states);
+extend(FakeXMLHttpRequest.prototype, states);
+
+function useFakeXMLHttpRequest() {
+ FakeXMLHttpRequest.restore = function restore(keepOnCreate) {
+ if (sinonXhr.supportsXHR) {
+ global.XMLHttpRequest = sinonXhr.GlobalXMLHttpRequest;
+ }
+
+ if (sinonXhr.supportsActiveX) {
+ global.ActiveXObject = sinonXhr.GlobalActiveXObject;
+ }
+
+ delete FakeXMLHttpRequest.restore;
+
+ if (keepOnCreate !== true) {
+ delete FakeXMLHttpRequest.onCreate;
+ }
+ };
+ if (sinonXhr.supportsXHR) {
+ global.XMLHttpRequest = FakeXMLHttpRequest;
+ }
+
+ if (sinonXhr.supportsActiveX) {
+ global.ActiveXObject = function ActiveXObject(objId) {
+ if (objId === "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) {
+
+ return new FakeXMLHttpRequest();
+ }
+
+ return new sinonXhr.GlobalActiveXObject(objId);
+ };
+ }
+
+ return FakeXMLHttpRequest;
+}
+
+module.exports = {
+ xhr: sinonXhr,
+ FakeXMLHttpRequest: FakeXMLHttpRequest,
+ useFakeXMLHttpRequest: useFakeXMLHttpRequest
+};
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+
+},{"../blob":4,"./core/extend":26,"./core/log_error":34,"./event":42,"text-encoding":69}],47:[function(require,module,exports){
+/*istanbul ignore start*/"use strict";
+
+exports.__esModule = true;
+exports. /*istanbul ignore end*/convertChangesToDMP = convertChangesToDMP;
+// See: http://code.google.com/p/google-diff-match-patch/wiki/API
+function convertChangesToDMP(changes) {
+ var ret = [],
+ change = /*istanbul ignore start*/void 0 /*istanbul ignore end*/,
+ operation = /*istanbul ignore start*/void 0 /*istanbul ignore end*/;
+ for (var i = 0; i < changes.length; i++) {
+ change = changes[i];
+ if (change.added) {
+ operation = 1;
+ } else if (change.removed) {
+ operation = -1;
+ } else {
+ operation = 0;
+ }
+
+ ret.push([operation, change.value]);
+ }
+ return ret;
+}
+
+
+},{}],48:[function(require,module,exports){
+/*istanbul ignore start*/'use strict';
+
+exports.__esModule = true;
+exports. /*istanbul ignore end*/convertChangesToXML = convertChangesToXML;
+function convertChangesToXML(changes) {
+ var ret = [];
+ for (var i = 0; i < changes.length; i++) {
+ var change = changes[i];
+ if (change.added) {
+ ret.push('<ins>');
+ } else if (change.removed) {
+ ret.push('<del>');
+ }
+
+ ret.push(escapeHTML(change.value));
+
+ if (change.added) {
+ ret.push('</ins>');
+ } else if (change.removed) {
+ ret.push('</del>');
+ }
+ }
+ return ret.join('');
+}
+
+function escapeHTML(s) {
+ var n = s;
+ n = n.replace(/&/g, '&amp;');
+ n = n.replace(/</g, '&lt;');
+ n = n.replace(/>/g, '&gt;');
+ n = n.replace(/"/g, '&quot;');
+
+ return n;
+}
+
+
+},{}],49:[function(require,module,exports){
+/*istanbul ignore start*/'use strict';
+
+exports.__esModule = true;
+exports.arrayDiff = undefined;
+exports. /*istanbul ignore end*/diffArrays = diffArrays;
+
+var /*istanbul ignore start*/_base = require('./base') /*istanbul ignore end*/;
+
+/*istanbul ignore start*/
+var _base2 = _interopRequireDefault(_base);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+/*istanbul ignore end*/var arrayDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/arrayDiff = new /*istanbul ignore start*/_base2['default']() /*istanbul ignore end*/;
+arrayDiff.tokenize = arrayDiff.join = function (value) {
+ return value.slice();
+};
+
+function diffArrays(oldArr, newArr, callback) {
+ return arrayDiff.diff(oldArr, newArr, callback);
+}
+
+
+},{"./base":50}],50:[function(require,module,exports){
+/*istanbul ignore start*/'use strict';
+
+exports.__esModule = true;
+exports['default'] = /*istanbul ignore end*/Diff;
+function Diff() {}
+
+Diff.prototype = { /*istanbul ignore start*/
+ /*istanbul ignore end*/diff: function diff(oldString, newString) {
+ /*istanbul ignore start*/var /*istanbul ignore end*/options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
+
+ var callback = options.callback;
+ if (typeof options === 'function') {
+ callback = options;
+ options = {};
+ }
+ this.options = options;
+
+ var self = this;
+
+ function done(value) {
+ if (callback) {
+ setTimeout(function () {
+ callback(undefined, value);
+ }, 0);
+ return true;
+ } else {
+ return value;
+ }
+ }
+
+ // Allow subclasses to massage the input prior to running
+ oldString = this.castInput(oldString);
+ newString = this.castInput(newString);
+
+ oldString = this.removeEmpty(this.tokenize(oldString));
+ newString = this.removeEmpty(this.tokenize(newString));
+
+ var newLen = newString.length,
+ oldLen = oldString.length;
+ var editLength = 1;
+ var maxEditLength = newLen + oldLen;
+ var bestPath = [{ newPos: -1, components: [] }];
+
+ // Seed editLength = 0, i.e. the content starts with the same values
+ var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0);
+ if (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen) {
+ // Identity per the equality and tokenizer
+ return done([{ value: this.join(newString), count: newString.length }]);
+ }
+
+ // Main worker method. checks all permutations of a given edit length for acceptance.
+ function execEditLength() {
+ for (var diagonalPath = -1 * editLength; diagonalPath <= editLength; diagonalPath += 2) {
+ var basePath = /*istanbul ignore start*/void 0 /*istanbul ignore end*/;
+ var addPath = bestPath[diagonalPath - 1],
+ removePath = bestPath[diagonalPath + 1],
+ _oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;
+ if (addPath) {
+ // No one else is going to attempt to use this value, clear it
+ bestPath[diagonalPath - 1] = undefined;
+ }
+
+ var canAdd = addPath && addPath.newPos + 1 < newLen,
+ canRemove = removePath && 0 <= _oldPos && _oldPos < oldLen;
+ if (!canAdd && !canRemove) {
+ // If this path is a terminal then prune
+ bestPath[diagonalPath] = undefined;
+ continue;
+ }
+
+ // Select the diagonal that we want to branch from. We select the prior
+ // path whose position in the new string is the farthest from the origin
+ // and does not pass the bounds of the diff graph
+ if (!canAdd || canRemove && addPath.newPos < removePath.newPos) {
+ basePath = clonePath(removePath);
+ self.pushComponent(basePath.components, undefined, true);
+ } else {
+ basePath = addPath; // No need to clone, we've pulled it from the list
+ basePath.newPos++;
+ self.pushComponent(basePath.components, true, undefined);
+ }
+
+ _oldPos = self.extractCommon(basePath, newString, oldString, diagonalPath);
+
+ // If we have hit the end of both strings, then we are done
+ if (basePath.newPos + 1 >= newLen && _oldPos + 1 >= oldLen) {
+ return done(buildValues(self, basePath.components, newString, oldString, self.useLongestToken));
+ } else {
+ // Otherwise track this path as a potential candidate and continue.
+ bestPath[diagonalPath] = basePath;
+ }
+ }
+
+ editLength++;
+ }
+
+ // Performs the length of edit iteration. Is a bit fugly as this has to support the
+ // sync and async mode which is never fun. Loops over execEditLength until a value
+ // is produced.
+ if (callback) {
+ (function exec() {
+ setTimeout(function () {
+ // This should not happen, but we want to be safe.
+ /* istanbul ignore next */
+ if (editLength > maxEditLength) {
+ return callback();
+ }
+
+ if (!execEditLength()) {
+ exec();
+ }
+ }, 0);
+ })();
+ } else {
+ while (editLength <= maxEditLength) {
+ var ret = execEditLength();
+ if (ret) {
+ return ret;
+ }
+ }
+ }
+ },
+ /*istanbul ignore start*/ /*istanbul ignore end*/pushComponent: function pushComponent(components, added, removed) {
+ var last = components[components.length - 1];
+ if (last && last.added === added && last.removed === removed) {
+ // We need to clone here as the component clone operation is just
+ // as shallow array clone
+ components[components.length - 1] = { count: last.count + 1, added: added, removed: removed };
+ } else {
+ components.push({ count: 1, added: added, removed: removed });
+ }
+ },
+ /*istanbul ignore start*/ /*istanbul ignore end*/extractCommon: function extractCommon(basePath, newString, oldString, diagonalPath) {
+ var newLen = newString.length,
+ oldLen = oldString.length,
+ newPos = basePath.newPos,
+ oldPos = newPos - diagonalPath,
+ commonCount = 0;
+ while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newString[newPos + 1], oldString[oldPos + 1])) {
+ newPos++;
+ oldPos++;
+ commonCount++;
+ }
+
+ if (commonCount) {
+ basePath.components.push({ count: commonCount });
+ }
+
+ basePath.newPos = newPos;
+ return oldPos;
+ },
+ /*istanbul ignore start*/ /*istanbul ignore end*/equals: function equals(left, right) {
+ return left === right;
+ },
+ /*istanbul ignore start*/ /*istanbul ignore end*/removeEmpty: function removeEmpty(array) {
+ var ret = [];
+ for (var i = 0; i < array.length; i++) {
+ if (array[i]) {
+ ret.push(array[i]);
+ }
+ }
+ return ret;
+ },
+ /*istanbul ignore start*/ /*istanbul ignore end*/castInput: function castInput(value) {
+ return value;
+ },
+ /*istanbul ignore start*/ /*istanbul ignore end*/tokenize: function tokenize(value) {
+ return value.split('');
+ },
+ /*istanbul ignore start*/ /*istanbul ignore end*/join: function join(chars) {
+ return chars.join('');
+ }
+};
+
+function buildValues(diff, components, newString, oldString, useLongestToken) {
+ var componentPos = 0,
+ componentLen = components.length,
+ newPos = 0,
+ oldPos = 0;
+
+ for (; componentPos < componentLen; componentPos++) {
+ var component = components[componentPos];
+ if (!component.removed) {
+ if (!component.added && useLongestToken) {
+ var value = newString.slice(newPos, newPos + component.count);
+ value = value.map(function (value, i) {
+ var oldValue = oldString[oldPos + i];
+ return oldValue.length > value.length ? oldValue : value;
+ });
+
+ component.value = diff.join(value);
+ } else {
+ component.value = diff.join(newString.slice(newPos, newPos + component.count));
+ }
+ newPos += component.count;
+
+ // Common case
+ if (!component.added) {
+ oldPos += component.count;
+ }
+ } else {
+ component.value = diff.join(oldString.slice(oldPos, oldPos + component.count));
+ oldPos += component.count;
+
+ // Reverse add and remove so removes are output first to match common convention
+ // The diffing algorithm is tied to add then remove output and this is the simplest
+ // route to get the desired output with minimal overhead.
+ if (componentPos && components[componentPos - 1].added) {
+ var tmp = components[componentPos - 1];
+ components[componentPos - 1] = components[componentPos];
+ components[componentPos] = tmp;
+ }
+ }
+ }
+
+ // Special case handle for when one terminal is ignored. For this case we merge the
+ // terminal into the prior string and drop the change.
+ var lastComponent = components[componentLen - 1];
+ if (componentLen > 1 && (lastComponent.added || lastComponent.removed) && diff.equals('', lastComponent.value)) {
+ components[componentLen - 2].value += lastComponent.value;
+ components.pop();
+ }
+
+ return components;
+}
+
+function clonePath(path) {
+ return { newPos: path.newPos, components: path.components.slice(0) };
+}
+
+
+},{}],51:[function(require,module,exports){
+/*istanbul ignore start*/'use strict';
+
+exports.__esModule = true;
+exports.characterDiff = undefined;
+exports. /*istanbul ignore end*/diffChars = diffChars;
+
+var /*istanbul ignore start*/_base = require('./base') /*istanbul ignore end*/;
+
+/*istanbul ignore start*/
+var _base2 = _interopRequireDefault(_base);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+/*istanbul ignore end*/var characterDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/characterDiff = new /*istanbul ignore start*/_base2['default']() /*istanbul ignore end*/;
+function diffChars(oldStr, newStr, callback) {
+ return characterDiff.diff(oldStr, newStr, callback);
+}
+
+
+},{"./base":50}],52:[function(require,module,exports){
+/*istanbul ignore start*/'use strict';
+
+exports.__esModule = true;
+exports.cssDiff = undefined;
+exports. /*istanbul ignore end*/diffCss = diffCss;
+
+var /*istanbul ignore start*/_base = require('./base') /*istanbul ignore end*/;
+
+/*istanbul ignore start*/
+var _base2 = _interopRequireDefault(_base);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+/*istanbul ignore end*/var cssDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/cssDiff = new /*istanbul ignore start*/_base2['default']() /*istanbul ignore end*/;
+cssDiff.tokenize = function (value) {
+ return value.split(/([{}:;,]|\s+)/);
+};
+
+function diffCss(oldStr, newStr, callback) {
+ return cssDiff.diff(oldStr, newStr, callback);
+}
+
+
+},{"./base":50}],53:[function(require,module,exports){
+/*istanbul ignore start*/'use strict';
+
+exports.__esModule = true;
+exports.jsonDiff = undefined;
+
+var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
+
+exports. /*istanbul ignore end*/diffJson = diffJson;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/canonicalize = canonicalize;
+
+var /*istanbul ignore start*/_base = require('./base') /*istanbul ignore end*/;
+
+/*istanbul ignore start*/
+var _base2 = _interopRequireDefault(_base);
+
+/*istanbul ignore end*/
+var /*istanbul ignore start*/_line = require('./line') /*istanbul ignore end*/;
+
+/*istanbul ignore start*/
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+/*istanbul ignore end*/
+
+var objectPrototypeToString = Object.prototype.toString;
+
+var jsonDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/jsonDiff = new /*istanbul ignore start*/_base2['default']() /*istanbul ignore end*/;
+// Discriminate between two lines of pretty-printed, serialized JSON where one of them has a
+// dangling comma and the other doesn't. Turns out including the dangling comma yields the nicest output:
+jsonDiff.useLongestToken = true;
+
+jsonDiff.tokenize = /*istanbul ignore start*/_line.lineDiff. /*istanbul ignore end*/tokenize;
+jsonDiff.castInput = function (value) {
+ /*istanbul ignore start*/var /*istanbul ignore end*/undefinedReplacement = this.options.undefinedReplacement;
+
+
+ return typeof value === 'string' ? value : JSON.stringify(canonicalize(value), function (k, v) {
+ if (typeof v === 'undefined') {
+ return undefinedReplacement;
+ }
+
+ return v;
+ }, ' ');
+};
+jsonDiff.equals = function (left, right) {
+ return (/*istanbul ignore start*/_base2['default']. /*istanbul ignore end*/prototype.equals(left.replace(/,([\r\n])/g, '$1'), right.replace(/,([\r\n])/g, '$1'))
+ );
+};
+
+function diffJson(oldObj, newObj, options) {
+ return jsonDiff.diff(oldObj, newObj, options);
+}
+
+// This function handles the presence of circular references by bailing out when encountering an
+// object that is already on the "stack" of items being processed.
+function canonicalize(obj, stack, replacementStack) {
+ stack = stack || [];
+ replacementStack = replacementStack || [];
+
+ var i = /*istanbul ignore start*/void 0 /*istanbul ignore end*/;
+
+ for (i = 0; i < stack.length; i += 1) {
+ if (stack[i] === obj) {
+ return replacementStack[i];
+ }
+ }
+
+ var canonicalizedObj = /*istanbul ignore start*/void 0 /*istanbul ignore end*/;
+
+ if ('[object Array]' === objectPrototypeToString.call(obj)) {
+ stack.push(obj);
+ canonicalizedObj = new Array(obj.length);
+ replacementStack.push(canonicalizedObj);
+ for (i = 0; i < obj.length; i += 1) {
+ canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack);
+ }
+ stack.pop();
+ replacementStack.pop();
+ return canonicalizedObj;
+ }
+
+ if (obj && obj.toJSON) {
+ obj = obj.toJSON();
+ }
+
+ if ( /*istanbul ignore start*/(typeof /*istanbul ignore end*/obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object' && obj !== null) {
+ stack.push(obj);
+ canonicalizedObj = {};
+ replacementStack.push(canonicalizedObj);
+ var sortedKeys = [],
+ key = /*istanbul ignore start*/void 0 /*istanbul ignore end*/;
+ for (key in obj) {
+ /* istanbul ignore else */
+ if (obj.hasOwnProperty(key)) {
+ sortedKeys.push(key);
+ }
+ }
+ sortedKeys.sort();
+ for (i = 0; i < sortedKeys.length; i += 1) {
+ key = sortedKeys[i];
+ canonicalizedObj[key] = canonicalize(obj[key], stack, replacementStack);
+ }
+ stack.pop();
+ replacementStack.pop();
+ } else {
+ canonicalizedObj = obj;
+ }
+ return canonicalizedObj;
+}
+
+
+},{"./base":50,"./line":54}],54:[function(require,module,exports){
+/*istanbul ignore start*/'use strict';
+
+exports.__esModule = true;
+exports.lineDiff = undefined;
+exports. /*istanbul ignore end*/diffLines = diffLines;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/diffTrimmedLines = diffTrimmedLines;
+
+var /*istanbul ignore start*/_base = require('./base') /*istanbul ignore end*/;
+
+/*istanbul ignore start*/
+var _base2 = _interopRequireDefault(_base);
+
+/*istanbul ignore end*/
+var /*istanbul ignore start*/_params = require('../util/params') /*istanbul ignore end*/;
+
+/*istanbul ignore start*/
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+/*istanbul ignore end*/var lineDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/lineDiff = new /*istanbul ignore start*/_base2['default']() /*istanbul ignore end*/;
+lineDiff.tokenize = function (value) {
+ var retLines = [],
+ linesAndNewlines = value.split(/(\n|\r\n)/);
+
+ // Ignore the final empty token that occurs if the string ends with a new line
+ if (!linesAndNewlines[linesAndNewlines.length - 1]) {
+ linesAndNewlines.pop();
+ }
+
+ // Merge the content and line separators into single tokens
+ for (var i = 0; i < linesAndNewlines.length; i++) {
+ var line = linesAndNewlines[i];
+
+ if (i % 2 && !this.options.newlineIsToken) {
+ retLines[retLines.length - 1] += line;
+ } else {
+ if (this.options.ignoreWhitespace) {
+ line = line.trim();
+ }
+ retLines.push(line);
+ }
+ }
+
+ return retLines;
+};
+
+function diffLines(oldStr, newStr, callback) {
+ return lineDiff.diff(oldStr, newStr, callback);
+}
+function diffTrimmedLines(oldStr, newStr, callback) {
+ var options = /*istanbul ignore start*/(0, _params.generateOptions) /*istanbul ignore end*/(callback, { ignoreWhitespace: true });
+ return lineDiff.diff(oldStr, newStr, options);
+}
+
+
+},{"../util/params":62,"./base":50}],55:[function(require,module,exports){
+/*istanbul ignore start*/'use strict';
+
+exports.__esModule = true;
+exports.sentenceDiff = undefined;
+exports. /*istanbul ignore end*/diffSentences = diffSentences;
+
+var /*istanbul ignore start*/_base = require('./base') /*istanbul ignore end*/;
+
+/*istanbul ignore start*/
+var _base2 = _interopRequireDefault(_base);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+/*istanbul ignore end*/var sentenceDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/sentenceDiff = new /*istanbul ignore start*/_base2['default']() /*istanbul ignore end*/;
+sentenceDiff.tokenize = function (value) {
+ return value.split(/(\S.+?[.!?])(?=\s+|$)/);
+};
+
+function diffSentences(oldStr, newStr, callback) {
+ return sentenceDiff.diff(oldStr, newStr, callback);
+}
+
+
+},{"./base":50}],56:[function(require,module,exports){
+/*istanbul ignore start*/'use strict';
+
+exports.__esModule = true;
+exports.wordDiff = undefined;
+exports. /*istanbul ignore end*/diffWords = diffWords;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/diffWordsWithSpace = diffWordsWithSpace;
+
+var /*istanbul ignore start*/_base = require('./base') /*istanbul ignore end*/;
+
+/*istanbul ignore start*/
+var _base2 = _interopRequireDefault(_base);
+
+/*istanbul ignore end*/
+var /*istanbul ignore start*/_params = require('../util/params') /*istanbul ignore end*/;
+
+/*istanbul ignore start*/
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+/*istanbul ignore end*/
+
+// Based on https://en.wikipedia.org/wiki/Latin_script_in_Unicode
+//
+// Ranges and exceptions:
+// Latin-1 Supplement, 0080–00FF
+// - U+00D7 × Multiplication sign
+// - U+00F7 ÷ Division sign
+// Latin Extended-A, 0100–017F
+// Latin Extended-B, 0180–024F
+// IPA Extensions, 0250–02AF
+// Spacing Modifier Letters, 02B0–02FF
+// - U+02C7 ˇ &#711; Caron
+// - U+02D8 ˘ &#728; Breve
+// - U+02D9 ˙ &#729; Dot Above
+// - U+02DA ˚ &#730; Ring Above
+// - U+02DB ˛ &#731; Ogonek
+// - U+02DC ˜ &#732; Small Tilde
+// - U+02DD ˝ &#733; Double Acute Accent
+// Latin Extended Additional, 1E00–1EFF
+var extendedWordChars = /^[A-Za-z\xC0-\u02C6\u02C8-\u02D7\u02DE-\u02FF\u1E00-\u1EFF]+$/;
+
+var reWhitespace = /\S/;
+
+var wordDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/wordDiff = new /*istanbul ignore start*/_base2['default']() /*istanbul ignore end*/;
+wordDiff.equals = function (left, right) {
+ return left === right || this.options.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right);
+};
+wordDiff.tokenize = function (value) {
+ var tokens = value.split(/(\s+|\b)/);
+
+ // Join the boundary splits that we do not consider to be boundaries. This is primarily the extended Latin character set.
+ for (var i = 0; i < tokens.length - 1; i++) {
+ // If we have an empty string in the next field and we have only word chars before and after, merge
+ if (!tokens[i + 1] && tokens[i + 2] && extendedWordChars.test(tokens[i]) && extendedWordChars.test(tokens[i + 2])) {
+ tokens[i] += tokens[i + 2];
+ tokens.splice(i + 1, 2);
+ i--;
+ }
+ }
+
+ return tokens;
+};
+
+function diffWords(oldStr, newStr, callback) {
+ var options = /*istanbul ignore start*/(0, _params.generateOptions) /*istanbul ignore end*/(callback, { ignoreWhitespace: true });
+ return wordDiff.diff(oldStr, newStr, options);
+}
+function diffWordsWithSpace(oldStr, newStr, callback) {
+ return wordDiff.diff(oldStr, newStr, callback);
+}
+
+
+},{"../util/params":62,"./base":50}],57:[function(require,module,exports){
+/*istanbul ignore start*/'use strict';
+
+exports.__esModule = true;
+exports.canonicalize = exports.convertChangesToXML = exports.convertChangesToDMP = exports.parsePatch = exports.applyPatches = exports.applyPatch = exports.createPatch = exports.createTwoFilesPatch = exports.structuredPatch = exports.diffArrays = exports.diffJson = exports.diffCss = exports.diffSentences = exports.diffTrimmedLines = exports.diffLines = exports.diffWordsWithSpace = exports.diffWords = exports.diffChars = exports.Diff = undefined;
+/*istanbul ignore end*/
+var /*istanbul ignore start*/_base = require('./diff/base') /*istanbul ignore end*/;
+
+/*istanbul ignore start*/
+var _base2 = _interopRequireDefault(_base);
+
+/*istanbul ignore end*/
+var /*istanbul ignore start*/_character = require('./diff/character') /*istanbul ignore end*/;
+
+var /*istanbul ignore start*/_word = require('./diff/word') /*istanbul ignore end*/;
+
+var /*istanbul ignore start*/_line = require('./diff/line') /*istanbul ignore end*/;
+
+var /*istanbul ignore start*/_sentence = require('./diff/sentence') /*istanbul ignore end*/;
+
+var /*istanbul ignore start*/_css = require('./diff/css') /*istanbul ignore end*/;
+
+var /*istanbul ignore start*/_json = require('./diff/json') /*istanbul ignore end*/;
+
+var /*istanbul ignore start*/_array = require('./diff/array') /*istanbul ignore end*/;
+
+var /*istanbul ignore start*/_apply = require('./patch/apply') /*istanbul ignore end*/;
+
+var /*istanbul ignore start*/_parse = require('./patch/parse') /*istanbul ignore end*/;
+
+var /*istanbul ignore start*/_create = require('./patch/create') /*istanbul ignore end*/;
+
+var /*istanbul ignore start*/_dmp = require('./convert/dmp') /*istanbul ignore end*/;
+
+var /*istanbul ignore start*/_xml = require('./convert/xml') /*istanbul ignore end*/;
+
+/*istanbul ignore start*/
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+exports. /*istanbul ignore end*/Diff = _base2['default'];
+/*istanbul ignore start*/exports. /*istanbul ignore end*/diffChars = _character.diffChars;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/diffWords = _word.diffWords;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/diffWordsWithSpace = _word.diffWordsWithSpace;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/diffLines = _line.diffLines;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/diffTrimmedLines = _line.diffTrimmedLines;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/diffSentences = _sentence.diffSentences;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/diffCss = _css.diffCss;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/diffJson = _json.diffJson;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/diffArrays = _array.diffArrays;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/structuredPatch = _create.structuredPatch;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/createTwoFilesPatch = _create.createTwoFilesPatch;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/createPatch = _create.createPatch;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/applyPatch = _apply.applyPatch;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/applyPatches = _apply.applyPatches;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/parsePatch = _parse.parsePatch;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/convertChangesToDMP = _dmp.convertChangesToDMP;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/convertChangesToXML = _xml.convertChangesToXML;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/canonicalize = _json.canonicalize; /* See LICENSE file for terms of use */
+
+/*
+ * Text diff implementation.
+ *
+ * This library supports the following APIS:
+ * JsDiff.diffChars: Character by character diff
+ * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace
+ * JsDiff.diffLines: Line based diff
+ *
+ * JsDiff.diffCss: Diff targeted at CSS content
+ *
+ * These methods are based on the implementation proposed in
+ * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986).
+ * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927
+ */
+
+
+},{"./convert/dmp":47,"./convert/xml":48,"./diff/array":49,"./diff/base":50,"./diff/character":51,"./diff/css":52,"./diff/json":53,"./diff/line":54,"./diff/sentence":55,"./diff/word":56,"./patch/apply":58,"./patch/create":59,"./patch/parse":60}],58:[function(require,module,exports){
+/*istanbul ignore start*/'use strict';
+
+exports.__esModule = true;
+exports. /*istanbul ignore end*/applyPatch = applyPatch;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/applyPatches = applyPatches;
+
+var /*istanbul ignore start*/_parse = require('./parse') /*istanbul ignore end*/;
+
+var /*istanbul ignore start*/_distanceIterator = require('../util/distance-iterator') /*istanbul ignore end*/;
+
+/*istanbul ignore start*/
+var _distanceIterator2 = _interopRequireDefault(_distanceIterator);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
+
+/*istanbul ignore end*/function applyPatch(source, uniDiff) {
+ /*istanbul ignore start*/var /*istanbul ignore end*/options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
+
+ if (typeof uniDiff === 'string') {
+ uniDiff = /*istanbul ignore start*/(0, _parse.parsePatch) /*istanbul ignore end*/(uniDiff);
+ }
+
+ if (Array.isArray(uniDiff)) {
+ if (uniDiff.length > 1) {
+ throw new Error('applyPatch only works with a single input.');
+ }
+
+ uniDiff = uniDiff[0];
+ }
+
+ // Apply the diff to the input
+ var lines = source.split(/\r\n|[\n\v\f\r\x85]/),
+ delimiters = source.match(/\r\n|[\n\v\f\r\x85]/g) || [],
+ hunks = uniDiff.hunks,
+ compareLine = options.compareLine || function (lineNumber, line, operation, patchContent) /*istanbul ignore start*/{
+ return (/*istanbul ignore end*/line === patchContent
+ );
+ },
+ errorCount = 0,
+ fuzzFactor = options.fuzzFactor || 0,
+ minLine = 0,
+ offset = 0,
+ removeEOFNL = /*istanbul ignore start*/void 0 /*istanbul ignore end*/,
+ addEOFNL = /*istanbul ignore start*/void 0 /*istanbul ignore end*/;
+
+ /**
+ * Checks if the hunk exactly fits on the provided location
+ */
+ function hunkFits(hunk, toPos) {
+ for (var j = 0; j < hunk.lines.length; j++) {
+ var line = hunk.lines[j],
+ operation = line[0],
+ content = line.substr(1);
+
+ if (operation === ' ' || operation === '-') {
+ // Context sanity check
+ if (!compareLine(toPos + 1, lines[toPos], operation, content)) {
+ errorCount++;
+
+ if (errorCount > fuzzFactor) {
+ return false;
+ }
+ }
+ toPos++;
+ }
+ }
+
+ return true;
+ }
+
+ // Search best fit offsets for each hunk based on the previous ones
+ for (var i = 0; i < hunks.length; i++) {
+ var hunk = hunks[i],
+ maxLine = lines.length - hunk.oldLines,
+ localOffset = 0,
+ toPos = offset + hunk.oldStart - 1;
+
+ var iterator = /*istanbul ignore start*/(0, _distanceIterator2['default']) /*istanbul ignore end*/(toPos, minLine, maxLine);
+
+ for (; localOffset !== undefined; localOffset = iterator()) {
+ if (hunkFits(hunk, toPos + localOffset)) {
+ hunk.offset = offset += localOffset;
+ break;
+ }
+ }
+
+ if (localOffset === undefined) {
+ return false;
+ }
+
+ // Set lower text limit to end of the current hunk, so next ones don't try
+ // to fit over already patched text
+ minLine = hunk.offset + hunk.oldStart + hunk.oldLines;
+ }
+
+ // Apply patch hunks
+ for (var _i = 0; _i < hunks.length; _i++) {
+ var _hunk = hunks[_i],
+ _toPos = _hunk.offset + _hunk.newStart - 1;
+ if (_hunk.newLines == 0) {
+ _toPos++;
+ }
+
+ for (var j = 0; j < _hunk.lines.length; j++) {
+ var line = _hunk.lines[j],
+ operation = line[0],
+ content = line.substr(1),
+ delimiter = _hunk.linedelimiters[j];
+
+ if (operation === ' ') {
+ _toPos++;
+ } else if (operation === '-') {
+ lines.splice(_toPos, 1);
+ delimiters.splice(_toPos, 1);
+ /* istanbul ignore else */
+ } else if (operation === '+') {
+ lines.splice(_toPos, 0, content);
+ delimiters.splice(_toPos, 0, delimiter);
+ _toPos++;
+ } else if (operation === '\\') {
+ var previousOperation = _hunk.lines[j - 1] ? _hunk.lines[j - 1][0] : null;
+ if (previousOperation === '+') {
+ removeEOFNL = true;
+ } else if (previousOperation === '-') {
+ addEOFNL = true;
+ }
+ }
+ }
+ }
+
+ // Handle EOFNL insertion/removal
+ if (removeEOFNL) {
+ while (!lines[lines.length - 1]) {
+ lines.pop();
+ delimiters.pop();
+ }
+ } else if (addEOFNL) {
+ lines.push('');
+ delimiters.push('\n');
+ }
+ for (var _k = 0; _k < lines.length - 1; _k++) {
+ lines[_k] = lines[_k] + delimiters[_k];
+ }
+ return lines.join('');
+}
+
+// Wrapper that supports multiple file patches via callbacks.
+function applyPatches(uniDiff, options) {
+ if (typeof uniDiff === 'string') {
+ uniDiff = /*istanbul ignore start*/(0, _parse.parsePatch) /*istanbul ignore end*/(uniDiff);
+ }
+
+ var currentIndex = 0;
+ function processIndex() {
+ var index = uniDiff[currentIndex++];
+ if (!index) {
+ return options.complete();
+ }
+
+ options.loadFile(index, function (err, data) {
+ if (err) {
+ return options.complete(err);
+ }
+
+ var updatedContent = applyPatch(data, index, options);
+ options.patched(index, updatedContent, function (err) {
+ if (err) {
+ return options.complete(err);
+ }
+
+ processIndex();
+ });
+ });
+ }
+ processIndex();
+}
+
+
+},{"../util/distance-iterator":61,"./parse":60}],59:[function(require,module,exports){
+/*istanbul ignore start*/'use strict';
+
+exports.__esModule = true;
+exports. /*istanbul ignore end*/structuredPatch = structuredPatch;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/createTwoFilesPatch = createTwoFilesPatch;
+/*istanbul ignore start*/exports. /*istanbul ignore end*/createPatch = createPatch;
+
+var /*istanbul ignore start*/_line = require('../diff/line') /*istanbul ignore end*/;
+
+/*istanbul ignore start*/
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
+/*istanbul ignore end*/function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
+ if (!options) {
+ options = {};
+ }
+ if (typeof options.context === 'undefined') {
+ options.context = 4;
+ }
+
+ var diff = /*istanbul ignore start*/(0, _line.diffLines) /*istanbul ignore end*/(oldStr, newStr, options);
+ diff.push({ value: '', lines: [] }); // Append an empty value to make cleanup easier
+
+ function contextLines(lines) {
+ return lines.map(function (entry) {
+ return ' ' + entry;
+ });
+ }
+
+ var hunks = [];
+ var oldRangeStart = 0,
+ newRangeStart = 0,
+ curRange = [],
+ oldLine = 1,
+ newLine = 1;
+ /*istanbul ignore start*/
+ var _loop = function _loop( /*istanbul ignore end*/i) {
+ var current = diff[i],
+ lines = current.lines || current.value.replace(/\n$/, '').split('\n');
+ current.lines = lines;
+
+ if (current.added || current.removed) {
+ /*istanbul ignore start*/
+ var _curRange;
+
+ /*istanbul ignore end*/
+ // If we have previous context, start with that
+ if (!oldRangeStart) {
+ var prev = diff[i - 1];
+ oldRangeStart = oldLine;
+ newRangeStart = newLine;
+
+ if (prev) {
+ curRange = options.context > 0 ? contextLines(prev.lines.slice(-options.context)) : [];
+ oldRangeStart -= curRange.length;
+ newRangeStart -= curRange.length;
+ }
+ }
+
+ // Output our changes
+ /*istanbul ignore start*/(_curRange = /*istanbul ignore end*/curRange).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_curRange /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/lines.map(function (entry) {
+ return (current.added ? '+' : '-') + entry;
+ })));
+
+ // Track the updated file position
+ if (current.added) {
+ newLine += lines.length;
+ } else {
+ oldLine += lines.length;
+ }
+ } else {
+ // Identical context lines. Track line changes
+ if (oldRangeStart) {
+ // Close out any changes that have been output (or join overlapping)
+ if (lines.length <= options.context * 2 && i < diff.length - 2) {
+ /*istanbul ignore start*/
+ var _curRange2;
+
+ /*istanbul ignore end*/
+ // Overlapping
+ /*istanbul ignore start*/(_curRange2 = /*istanbul ignore end*/curRange).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_curRange2 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/contextLines(lines)));
+ } else {
+ /*istanbul ignore start*/
+ var _curRange3;
+
+ /*istanbul ignore end*/
+ // end the range and output
+ var contextSize = Math.min(lines.length, options.context);
+ /*istanbul ignore start*/(_curRange3 = /*istanbul ignore end*/curRange).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_curRange3 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/contextLines(lines.slice(0, contextSize))));
+
+ var hunk = {
+ oldStart: oldRangeStart,
+ oldLines: oldLine - oldRangeStart + contextSize,
+ newStart: newRangeStart,
+ newLines: newLine - newRangeStart + contextSize,
+ lines: curRange
+ };
+ if (i >= diff.length - 2 && lines.length <= options.context) {
+ // EOF is inside this hunk
+ var oldEOFNewline = /\n$/.test(oldStr);
+ var newEOFNewline = /\n$/.test(newStr);
+ if (lines.length == 0 && !oldEOFNewline) {
+ // special case: old has no eol and no trailing context; no-nl can end up before adds
+ curRange.splice(hunk.oldLines, 0, '\\ No newline at end of file');
+ } else if (!oldEOFNewline || !newEOFNewline) {
+ curRange.push('\\ No newline at end of file');
+ }
+ }
+ hunks.push(hunk);
+
+ oldRangeStart = 0;
+ newRangeStart = 0;
+ curRange = [];
+ }
+ }
+ oldLine += lines.length;
+ newLine += lines.length;
+ }
+ };
+
+ for (var i = 0; i < diff.length; i++) {
+ /*istanbul ignore start*/
+ _loop( /*istanbul ignore end*/i);
+ }
+
+ return {
+ oldFileName: oldFileName, newFileName: newFileName,
+ oldHeader: oldHeader, newHeader: newHeader,
+ hunks: hunks
+ };
+}
+
+function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
+ var diff = structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options);
+
+ var ret = [];
+ if (oldFileName == newFileName) {
+ ret.push('Index: ' + oldFileName);
+ }
+ ret.push('===================================================================');
+ ret.push('--- ' + diff.oldFileName + (typeof diff.oldHeader === 'undefined' ? '' : '\t' + diff.oldHeader));
+ ret.push('+++ ' + diff.newFileName + (typeof diff.newHeader === 'undefined' ? '' : '\t' + diff.newHeader));
+
+ for (var i = 0; i < diff.hunks.length; i++) {
+ var hunk = diff.hunks[i];
+ ret.push('@@ -' + hunk.oldStart + ',' + hunk.oldLines + ' +' + hunk.newStart + ',' + hunk.newLines + ' @@');
+ ret.push.apply(ret, hunk.lines);
+ }
+
+ return ret.join('\n') + '\n';
+}
+
+function createPatch(fileName, oldStr, newStr, oldHeader, newHeader, options) {
+ return createTwoFilesPatch(fileName, fileName, oldStr, newStr, oldHeader, newHeader, options);
+}
+
+
+},{"../diff/line":54}],60:[function(require,module,exports){
+/*istanbul ignore start*/'use strict';
+
+exports.__esModule = true;
+exports. /*istanbul ignore end*/parsePatch = parsePatch;
+function parsePatch(uniDiff) {
+ /*istanbul ignore start*/var /*istanbul ignore end*/options = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
+
+ var diffstr = uniDiff.split(/\r\n|[\n\v\f\r\x85]/),
+ delimiters = uniDiff.match(/\r\n|[\n\v\f\r\x85]/g) || [],
+ list = [],
+ i = 0;
+
+ function parseIndex() {
+ var index = {};
+ list.push(index);
+
+ // Parse diff metadata
+ while (i < diffstr.length) {
+ var line = diffstr[i];
+
+ // File header found, end parsing diff metadata
+ if (/^(\-\-\-|\+\+\+|@@)\s/.test(line)) {
+ break;
+ }
+
+ // Diff index
+ var header = /^(?:Index:|diff(?: -r \w+)+)\s+(.+?)\s*$/.exec(line);
+ if (header) {
+ index.index = header[1];
+ }
+
+ i++;
+ }
+
+ // Parse file headers if they are defined. Unified diff requires them, but
+ // there's no technical issues to have an isolated hunk without file header
+ parseFileHeader(index);
+ parseFileHeader(index);
+
+ // Parse hunks
+ index.hunks = [];
+
+ while (i < diffstr.length) {
+ var _line = diffstr[i];
+
+ if (/^(Index:|diff|\-\-\-|\+\+\+)\s/.test(_line)) {
+ break;
+ } else if (/^@@/.test(_line)) {
+ index.hunks.push(parseHunk());
+ } else if (_line && options.strict) {
+ // Ignore unexpected content unless in strict mode
+ throw new Error('Unknown line ' + (i + 1) + ' ' + JSON.stringify(_line));
+ } else {
+ i++;
+ }
+ }
+ }
+
+ // Parses the --- and +++ headers, if none are found, no lines
+ // are consumed.
+ function parseFileHeader(index) {
+ var headerPattern = /^(---|\+\+\+)\s+([\S ]*)(?:\t(.*?)\s*)?$/;
+ var fileHeader = headerPattern.exec(diffstr[i]);
+ if (fileHeader) {
+ var keyPrefix = fileHeader[1] === '---' ? 'old' : 'new';
+ index[keyPrefix + 'FileName'] = fileHeader[2];
+ index[keyPrefix + 'Header'] = fileHeader[3];
+
+ i++;
+ }
+ }
+
+ // Parses a hunk
+ // This assumes that we are at the start of a hunk.
+ function parseHunk() {
+ var chunkHeaderIndex = i,
+ chunkHeaderLine = diffstr[i++],
+ chunkHeader = chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
+
+ var hunk = {
+ oldStart: +chunkHeader[1],
+ oldLines: +chunkHeader[2] || 1,
+ newStart: +chunkHeader[3],
+ newLines: +chunkHeader[4] || 1,
+ lines: [],
+ linedelimiters: []
+ };
+
+ var addCount = 0,
+ removeCount = 0;
+ for (; i < diffstr.length; i++) {
+ // Lines starting with '---' could be mistaken for the "remove line" operation
+ // But they could be the header for the next file. Therefore prune such cases out.
+ if (diffstr[i].indexOf('--- ') === 0 && i + 2 < diffstr.length && diffstr[i + 1].indexOf('+++ ') === 0 && diffstr[i + 2].indexOf('@@') === 0) {
+ break;
+ }
+ var operation = diffstr[i][0];
+
+ if (operation === '+' || operation === '-' || operation === ' ' || operation === '\\') {
+ hunk.lines.push(diffstr[i]);
+ hunk.linedelimiters.push(delimiters[i] || '\n');
+
+ if (operation === '+') {
+ addCount++;
+ } else if (operation === '-') {
+ removeCount++;
+ } else if (operation === ' ') {
+ addCount++;
+ removeCount++;
+ }
+ } else {
+ break;
+ }
+ }
+
+ // Handle the empty block count case
+ if (!addCount && hunk.newLines === 1) {
+ hunk.newLines = 0;
+ }
+ if (!removeCount && hunk.oldLines === 1) {
+ hunk.oldLines = 0;
+ }
+
+ // Perform optional sanity checking
+ if (options.strict) {
+ if (addCount !== hunk.newLines) {
+ throw new Error('Added line count did not match for hunk at line ' + (chunkHeaderIndex + 1));
+ }
+ if (removeCount !== hunk.oldLines) {
+ throw new Error('Removed line count did not match for hunk at line ' + (chunkHeaderIndex + 1));
+ }
+ }
+
+ return hunk;
+ }
+
+ while (i < diffstr.length) {
+ parseIndex();
+ }
+
+ return list;
+}
+
+
+},{}],61:[function(require,module,exports){
+/*istanbul ignore start*/"use strict";
+
+exports.__esModule = true;
+
+exports["default"] = /*istanbul ignore end*/function (start, minLine, maxLine) {
+ var wantForward = true,
+ backwardExhausted = false,
+ forwardExhausted = false,
+ localOffset = 1;
+
+ return function iterator() {
+ if (wantForward && !forwardExhausted) {
+ if (backwardExhausted) {
+ localOffset++;
+ } else {
+ wantForward = false;
+ }
+
+ // Check if trying to fit beyond text length, and if not, check it fits
+ // after offset location (or desired location on first iteration)
+ if (start + localOffset <= maxLine) {
+ return localOffset;
+ }
+
+ forwardExhausted = true;
+ }
+
+ if (!backwardExhausted) {
+ if (!forwardExhausted) {
+ wantForward = true;
+ }
+
+ // Check if trying to fit before text beginning, and if not, check it fits
+ // before offset location
+ if (minLine <= start - localOffset) {
+ return -localOffset++;
+ }
+
+ backwardExhausted = true;
+ return iterator();
+ }
+
+ // We tried to fit hunk before text beginning and beyond text lenght, then
+ // hunk can't fit on the text. Return undefined
+ };
+};
+
+
+},{}],62:[function(require,module,exports){
+/*istanbul ignore start*/'use strict';
+
+exports.__esModule = true;
+exports. /*istanbul ignore end*/generateOptions = generateOptions;
+function generateOptions(options, defaults) {
+ if (typeof options === 'function') {
+ defaults.callback = options;
+ } else if (options) {
+ for (var name in options) {
+ /* istanbul ignore else */
+ if (options.hasOwnProperty(name)) {
+ defaults[name] = options[name];
+ }
+ }
+ }
+ return defaults;
+}
+
+
+},{}],63:[function(require,module,exports){
+(function (global){
+((typeof define === "function" && define.amd && function (m) {
+ define("formatio", ["samsam"], m);
+}) || (typeof module === "object" && function (m) {
+ module.exports = m(require("samsam"));
+}) || function (m) { this.formatio = m(this.samsam); }
+)(function (samsam) {
+ "use strict";
+
+ var formatio = {
+ excludeConstructors: ["Object", /^.$/],
+ quoteStrings: true,
+ limitChildrenCount: 0
+ };
+
+ var hasOwn = Object.prototype.hasOwnProperty;
+
+ var specialObjects = [];
+ if (typeof global !== "undefined") {
+ specialObjects.push({ object: global, value: "[object global]" });
+ }
+ if (typeof document !== "undefined") {
+ specialObjects.push({
+ object: document,
+ value: "[object HTMLDocument]"
+ });
+ }
+ if (typeof window !== "undefined") {
+ specialObjects.push({ object: window, value: "[object Window]" });
+ }
+
+ function functionName(func) {
+ if (!func) { return ""; }
+ if (func.displayName) { return func.displayName; }
+ if (func.name) { return func.name; }
+ var matches = func.toString().match(/function\s+([^\(]+)/m);
+ return (matches && matches[1]) || "";
+ }
+
+ function constructorName(f, object) {
+ var name = functionName(object && object.constructor);
+ var excludes = f.excludeConstructors ||
+ formatio.excludeConstructors || [];
+
+ var i, l;
+ for (i = 0, l = excludes.length; i < l; ++i) {
+ if (typeof excludes[i] === "string" && excludes[i] === name) {
+ return "";
+ } else if (excludes[i].test && excludes[i].test(name)) {
+ return "";
+ }
+ }
+
+ return name;
+ }
+
+ function isCircular(object, objects) {
+ if (typeof object !== "object") { return false; }
+ var i, l;
+ for (i = 0, l = objects.length; i < l; ++i) {
+ if (objects[i] === object) { return true; }
+ }
+ return false;
+ }
+
+ function ascii(f, object, processed, indent) {
+ if (typeof object === "string") {
+ if (object.length === 0) { return "(empty string)"; }
+ var qs = f.quoteStrings;
+ var quote = typeof qs !== "boolean" || qs;
+ return processed || quote ? '"' + object + '"' : object;
+ }
+
+ if (typeof object === "function" && !(object instanceof RegExp)) {
+ return ascii.func(object);
+ }
+
+ processed = processed || [];
+
+ if (isCircular(object, processed)) { return "[Circular]"; }
+
+ if (Object.prototype.toString.call(object) === "[object Array]") {
+ return ascii.array.call(f, object, processed);
+ }
+
+ if (!object) { return String((1/object) === -Infinity ? "-0" : object); }
+ if (samsam.isElement(object)) { return ascii.element(object); }
+
+ if (typeof object.toString === "function" &&
+ object.toString !== Object.prototype.toString) {
+ return object.toString();
+ }
+
+ var i, l;
+ for (i = 0, l = specialObjects.length; i < l; i++) {
+ if (object === specialObjects[i].object) {
+ return specialObjects[i].value;
+ }
+ }
+
+ if (typeof Set !== 'undefined' && object instanceof Set) {
+ return ascii.set.call(f, object, processed);
+ }
+
+ return ascii.object.call(f, object, processed, indent);
+ }
+
+ ascii.func = function (func) {
+ return "function " + functionName(func) + "() {}";
+ };
+
+ function delimit(str, delimiters) {
+ delimiters = delimiters || ["[", "]"];
+ return delimiters[0] + str + delimiters[1];
+ }
+
+ ascii.array = function (array, processed, delimiters) {
+ processed = processed || [];
+ processed.push(array);
+ var pieces = [];
+ var i, l;
+ l = (this.limitChildrenCount > 0) ?
+ Math.min(this.limitChildrenCount, array.length) : array.length;
+
+ for (i = 0; i < l; ++i) {
+ pieces.push(ascii(this, array[i], processed));
+ }
+
+ if (l < array.length) {
+ pieces.push("[... " + (array.length - l) + " more elements]");
+ }
+
+ return delimit(pieces.join(", "), delimiters);
+ };
+
+ ascii.set = function (set, processed) {
+ return ascii.array.call(this, Array.from(set), processed, ['Set {', '}']);
+ };
+
+ ascii.object = function (object, processed, indent) {
+ processed = processed || [];
+ processed.push(object);
+ indent = indent || 0;
+ var pieces = [], properties = samsam.keys(object).sort();
+ var length = 3;
+ var prop, str, obj, i, k, l;
+ l = (this.limitChildrenCount > 0) ?
+ Math.min(this.limitChildrenCount, properties.length) : properties.length;
+
+ for (i = 0; i < l; ++i) {
+ prop = properties[i];
+ obj = object[prop];
+
+ if (isCircular(obj, processed)) {
+ str = "[Circular]";
+ } else {
+ str = ascii(this, obj, processed, indent + 2);
+ }
+
+ str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str;
+ length += str.length;
+ pieces.push(str);
+ }
+
+ var cons = constructorName(this, object);
+ var prefix = cons ? "[" + cons + "] " : "";
+ var is = "";
+ for (i = 0, k = indent; i < k; ++i) { is += " "; }
+
+ if(l < properties.length)
+ pieces.push("[... " + (properties.length - l) + " more elements]");
+
+ if (length + indent > 80) {
+ return prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" +
+ is + "}";
+ }
+ return prefix + "{ " + pieces.join(", ") + " }";
+ };
+
+ ascii.element = function (element) {
+ var tagName = element.tagName.toLowerCase();
+ var attrs = element.attributes, attr, pairs = [], attrName, i, l, val;
+
+ for (i = 0, l = attrs.length; i < l; ++i) {
+ attr = attrs.item(i);
+ attrName = attr.nodeName.toLowerCase().replace("html:", "");
+ val = attr.nodeValue;
+ if (attrName !== "contenteditable" || val !== "inherit") {
+ if (!!val) { pairs.push(attrName + "=\"" + val + "\""); }
+ }
+ }
+
+ var formatted = "<" + tagName + (pairs.length > 0 ? " " : "");
+ // SVG elements have undefined innerHTML
+ var content = element.innerHTML || '';
+
+ if (content.length > 20) {
+ content = content.substr(0, 20) + "[...]";
+ }
+
+ var res = formatted + pairs.join(" ") + ">" + content +
+ "</" + tagName + ">";
+
+ return res.replace(/ contentEditable="inherit"/, "");
+ };
+
+ function Formatio(options) {
+ for (var opt in options) {
+ this[opt] = options[opt];
+ }
+ }
+
+ Formatio.prototype = {
+ functionName: functionName,
+
+ configure: function (options) {
+ return new Formatio(options);
+ },
+
+ constructorName: function (object) {
+ return constructorName(this, object);
+ },
+
+ ascii: function (object, processed, indent) {
+ return ascii(this, object, processed, indent);
+ }
+ };
+
+ return Formatio.prototype;
+});
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+
+},{"samsam":68}],64:[function(require,module,exports){
+module.exports = Array.isArray || function (arr) {
+ return Object.prototype.toString.call(arr) == '[object Array]';
+};
+
+},{}],65:[function(require,module,exports){
+(function (global){
+"use strict";
+
+var userAgent = global.navigator && global.navigator.userAgent;
+var isRunningInIE = userAgent && userAgent.indexOf("MSIE ") > -1;
+
+// Make properties writable in IE, as per
+// http://www.adequatelygood.com/Replacing-setTimeout-Globally.html
+if (isRunningInIE) {
+ global.setTimeout = global.setTimeout;
+ global.clearTimeout = global.clearTimeout;
+ global.setInterval = global.setInterval;
+ global.clearInterval = global.clearInterval;
+ global.Date = global.Date;
+}
+
+// setImmediate is not a standard function
+// avoid adding the prop to the window object if not present
+if (global.setImmediate !== undefined) {
+ global.setImmediate = global.setImmediate;
+ global.clearImmediate = global.clearImmediate;
+}
+
+// node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref()
+// browsers, a number.
+// see https://github.com/cjohansen/Sinon.JS/pull/436
+
+var NOOP = function () { return undefined; };
+var timeoutResult = setTimeout(NOOP, 0);
+var addTimerReturnsObject = typeof timeoutResult === "object";
+var hrtimePresent = (global.process && typeof global.process.hrtime === "function");
+clearTimeout(timeoutResult);
+
+var NativeDate = Date;
+var uniqueTimerId = 1;
+
+/**
+ * Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into
+ * number of milliseconds. This is used to support human-readable strings passed
+ * to clock.tick()
+ */
+function parseTime(str) {
+ if (!str) {
+ return 0;
+ }
+
+ var strings = str.split(":");
+ var l = strings.length;
+ var i = l;
+ var ms = 0;
+ var parsed;
+
+ if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
+ throw new Error("tick only understands numbers, 'm:s' and 'h:m:s'. Each part must be two digits");
+ }
+
+ while (i--) {
+ parsed = parseInt(strings[i], 10);
+
+ if (parsed >= 60) {
+ throw new Error("Invalid time " + str);
+ }
+
+ ms += parsed * Math.pow(60, (l - i - 1));
+ }
+
+ return ms * 1000;
+}
+
+/**
+ * Floor function that also works for negative numbers
+ */
+function fixedFloor(n) {
+ return (n >= 0 ? Math.floor(n) : Math.ceil(n));
+}
+
+/**
+ * % operator that also works for negative numbers
+ */
+function fixedModulo(n, m) {
+ return ((n % m) + m) % m;
+}
+
+/**
+ * Used to grok the `now` parameter to createClock.
+ */
+function getEpoch(epoch) {
+ if (!epoch) { return 0; }
+ if (typeof epoch.getTime === "function") { return epoch.getTime(); }
+ if (typeof epoch === "number") { return epoch; }
+ throw new TypeError("now should be milliseconds since UNIX epoch");
+}
+
+function inRange(from, to, timer) {
+ return timer && timer.callAt >= from && timer.callAt <= to;
+}
+
+function mirrorDateProperties(target, source) {
+ var prop;
+ for (prop in source) {
+ if (source.hasOwnProperty(prop)) {
+ target[prop] = source[prop];
+ }
+ }
+
+ // set special now implementation
+ if (source.now) {
+ target.now = function now() {
+ return target.clock.now;
+ };
+ } else {
+ delete target.now;
+ }
+
+ // set special toSource implementation
+ if (source.toSource) {
+ target.toSource = function toSource() {
+ return source.toSource();
+ };
+ } else {
+ delete target.toSource;
+ }
+
+ // set special toString implementation
+ target.toString = function toString() {
+ return source.toString();
+ };
+
+ target.prototype = source.prototype;
+ target.parse = source.parse;
+ target.UTC = source.UTC;
+ target.prototype.toUTCString = source.prototype.toUTCString;
+
+ return target;
+}
+
+function createDate() {
+ function ClockDate(year, month, date, hour, minute, second, ms) {
+ // Defensive and verbose to avoid potential harm in passing
+ // explicit undefined when user does not pass argument
+ switch (arguments.length) {
+ case 0:
+ return new NativeDate(ClockDate.clock.now);
+ case 1:
+ return new NativeDate(year);
+ case 2:
+ return new NativeDate(year, month);
+ case 3:
+ return new NativeDate(year, month, date);
+ case 4:
+ return new NativeDate(year, month, date, hour);
+ case 5:
+ return new NativeDate(year, month, date, hour, minute);
+ case 6:
+ return new NativeDate(year, month, date, hour, minute, second);
+ default:
+ return new NativeDate(year, month, date, hour, minute, second, ms);
+ }
+ }
+
+ return mirrorDateProperties(ClockDate, NativeDate);
+}
+
+function addTimer(clock, timer) {
+ if (timer.func === undefined) {
+ throw new Error("Callback must be provided to timer calls");
+ }
+
+ if (!clock.timers) {
+ clock.timers = {};
+ }
+
+ timer.id = uniqueTimerId++;
+ timer.createdAt = clock.now;
+ timer.callAt = clock.now + (parseInt(timer.delay) || (clock.duringTick ? 1 : 0));
+
+ clock.timers[timer.id] = timer;
+
+ if (addTimerReturnsObject) {
+ return {
+ id: timer.id,
+ ref: NOOP,
+ unref: NOOP
+ };
+ }
+
+ return timer.id;
+}
+
+
+/* eslint consistent-return: "off" */
+function compareTimers(a, b) {
+ // Sort first by absolute timing
+ if (a.callAt < b.callAt) {
+ return -1;
+ }
+ if (a.callAt > b.callAt) {
+ return 1;
+ }
+
+ // Sort next by immediate, immediate timers take precedence
+ if (a.immediate && !b.immediate) {
+ return -1;
+ }
+ if (!a.immediate && b.immediate) {
+ return 1;
+ }
+
+ // Sort next by creation time, earlier-created timers take precedence
+ if (a.createdAt < b.createdAt) {
+ return -1;
+ }
+ if (a.createdAt > b.createdAt) {
+ return 1;
+ }
+
+ // Sort next by id, lower-id timers take precedence
+ if (a.id < b.id) {
+ return -1;
+ }
+ if (a.id > b.id) {
+ return 1;
+ }
+
+ // As timer ids are unique, no fallback `0` is necessary
+}
+
+function firstTimerInRange(clock, from, to) {
+ var timers = clock.timers;
+ var timer = null;
+ var id, isInRange;
+
+ for (id in timers) {
+ if (timers.hasOwnProperty(id)) {
+ isInRange = inRange(from, to, timers[id]);
+
+ if (isInRange && (!timer || compareTimers(timer, timers[id]) === 1)) {
+ timer = timers[id];
+ }
+ }
+ }
+
+ return timer;
+}
+
+function firstTimer(clock) {
+ var timers = clock.timers;
+ var timer = null;
+ var id;
+
+ for (id in timers) {
+ if (timers.hasOwnProperty(id)) {
+ if (!timer || compareTimers(timer, timers[id]) === 1) {
+ timer = timers[id];
+ }
+ }
+ }
+
+ return timer;
+}
+
+function lastTimer(clock) {
+ var timers = clock.timers;
+ var timer = null;
+ var id;
+
+ for (id in timers) {
+ if (timers.hasOwnProperty(id)) {
+ if (!timer || compareTimers(timer, timers[id]) === -1) {
+ timer = timers[id];
+ }
+ }
+ }
+
+ return timer;
+}
+
+function callTimer(clock, timer) {
+ var exception;
+
+ if (typeof timer.interval === "number") {
+ clock.timers[timer.id].callAt += timer.interval;
+ } else {
+ delete clock.timers[timer.id];
+ }
+
+ try {
+ if (typeof timer.func === "function") {
+ timer.func.apply(null, timer.args);
+ } else {
+ /* eslint no-eval: "off" */
+ eval(timer.func);
+ }
+ } catch (e) {
+ exception = e;
+ }
+
+ if (!clock.timers[timer.id]) {
+ if (exception) {
+ throw exception;
+ }
+ return;
+ }
+
+ if (exception) {
+ throw exception;
+ }
+}
+
+function timerType(timer) {
+ if (timer.immediate) {
+ return "Immediate";
+ }
+ if (timer.interval !== undefined) {
+ return "Interval";
+ }
+ return "Timeout";
+}
+
+function clearTimer(clock, timerId, ttype) {
+ if (!timerId) {
+ // null appears to be allowed in most browsers, and appears to be
+ // relied upon by some libraries, like Bootstrap carousel
+ return;
+ }
+
+ if (!clock.timers) {
+ clock.timers = [];
+ }
+
+ // in Node, timerId is an object with .ref()/.unref(), and
+ // its .id field is the actual timer id.
+ if (typeof timerId === "object") {
+ timerId = timerId.id;
+ }
+
+ if (clock.timers.hasOwnProperty(timerId)) {
+ // check that the ID matches a timer of the correct type
+ var timer = clock.timers[timerId];
+ if (timerType(timer) === ttype) {
+ delete clock.timers[timerId];
+ } else {
+ throw new Error("Cannot clear timer: timer created with set" + timerType(timer)
+ + "() but cleared with clear" + ttype + "()");
+ }
+ }
+}
+
+function uninstall(clock, target) {
+ var method,
+ i,
+ l;
+ var installedHrTime = "_hrtime";
+
+ for (i = 0, l = clock.methods.length; i < l; i++) {
+ method = clock.methods[i];
+ if (method === "hrtime" && target.process) {
+ target.process.hrtime = clock[installedHrTime];
+ } else {
+ if (target[method] && target[method].hadOwnProperty) {
+ target[method] = clock["_" + method];
+ } else {
+ try {
+ delete target[method];
+ } catch (ignore) { /* eslint empty-block: "off" */ }
+ }
+ }
+ }
+
+ // Prevent multiple executions which will completely remove these props
+ clock.methods = [];
+}
+
+function hijackMethod(target, method, clock) {
+ var prop;
+
+ clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(target, method);
+ clock["_" + method] = target[method];
+
+ if (method === "Date") {
+ var date = mirrorDateProperties(clock[method], target[method]);
+ target[method] = date;
+ } else {
+ target[method] = function () {
+ return clock[method].apply(clock, arguments);
+ };
+
+ for (prop in clock[method]) {
+ if (clock[method].hasOwnProperty(prop)) {
+ target[method][prop] = clock[method][prop];
+ }
+ }
+ }
+
+ target[method].clock = clock;
+}
+
+var timers = {
+ setTimeout: setTimeout,
+ clearTimeout: clearTimeout,
+ setImmediate: global.setImmediate,
+ clearImmediate: global.clearImmediate,
+ setInterval: setInterval,
+ clearInterval: clearInterval,
+ Date: Date
+};
+
+if (hrtimePresent) {
+ timers.hrtime = global.process.hrtime;
+}
+
+var keys = Object.keys || function (obj) {
+ var ks = [];
+ var key;
+
+ for (key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ ks.push(key);
+ }
+ }
+
+ return ks;
+};
+
+exports.timers = timers;
+
+function createClock(now, loopLimit) {
+ loopLimit = loopLimit || 1000;
+
+ var clock = {
+ now: getEpoch(now),
+ hrNow: 0,
+ timeouts: {},
+ Date: createDate(),
+ loopLimit: loopLimit
+ };
+
+ clock.Date.clock = clock;
+
+ clock.setTimeout = function setTimeout(func, timeout) {
+ return addTimer(clock, {
+ func: func,
+ args: Array.prototype.slice.call(arguments, 2),
+ delay: timeout
+ });
+ };
+
+ clock.clearTimeout = function clearTimeout(timerId) {
+ return clearTimer(clock, timerId, "Timeout");
+ };
+
+ clock.setInterval = function setInterval(func, timeout) {
+ return addTimer(clock, {
+ func: func,
+ args: Array.prototype.slice.call(arguments, 2),
+ delay: timeout,
+ interval: timeout
+ });
+ };
+
+ clock.clearInterval = function clearInterval(timerId) {
+ return clearTimer(clock, timerId, "Interval");
+ };
+
+ clock.setImmediate = function setImmediate(func) {
+ return addTimer(clock, {
+ func: func,
+ args: Array.prototype.slice.call(arguments, 1),
+ immediate: true
+ });
+ };
+
+ clock.clearImmediate = function clearImmediate(timerId) {
+ return clearTimer(clock, timerId, "Immediate");
+ };
+
+ clock.tick = function tick(ms) {
+ ms = typeof ms === "number" ? ms : parseTime(ms);
+ var tickFrom = clock.now;
+ var tickTo = clock.now + ms;
+ var previous = clock.now;
+ var timer = firstTimerInRange(clock, tickFrom, tickTo);
+ var oldNow, firstException;
+
+ clock.duringTick = true;
+
+ function updateHrTime(newNow) {
+ clock.hrNow += (newNow - clock.now);
+ }
+
+ while (timer && tickFrom <= tickTo) {
+ if (clock.timers[timer.id]) {
+ updateHrTime(timer.callAt);
+ tickFrom = timer.callAt;
+ clock.now = timer.callAt;
+ try {
+ oldNow = clock.now;
+ callTimer(clock, timer);
+ // compensate for any setSystemTime() call during timer callback
+ if (oldNow !== clock.now) {
+ tickFrom += clock.now - oldNow;
+ tickTo += clock.now - oldNow;
+ previous += clock.now - oldNow;
+ }
+ } catch (e) {
+ firstException = firstException || e;
+ }
+ }
+
+ timer = firstTimerInRange(clock, previous, tickTo);
+ previous = tickFrom;
+ }
+
+ clock.duringTick = false;
+ updateHrTime(tickTo);
+ clock.now = tickTo;
+
+ if (firstException) {
+ throw firstException;
+ }
+
+ return clock.now;
+ };
+
+ clock.next = function next() {
+ var timer = firstTimer(clock);
+ if (!timer) {
+ return clock.now;
+ }
+
+ clock.duringTick = true;
+ try {
+ clock.now = timer.callAt;
+ callTimer(clock, timer);
+ return clock.now;
+ } finally {
+ clock.duringTick = false;
+ }
+ };
+
+ clock.runAll = function runAll() {
+ var numTimers, i;
+ for (i = 0; i < clock.loopLimit; i++) {
+ if (!clock.timers) {
+ return clock.now;
+ }
+
+ numTimers = Object.keys(clock.timers).length;
+ if (numTimers === 0) {
+ return clock.now;
+ }
+
+ clock.next();
+ }
+
+ throw new Error("Aborting after running " + clock.loopLimit + " timers, assuming an infinite loop!");
+ };
+
+ clock.runToLast = function runToLast() {
+ var timer = lastTimer(clock);
+ if (!timer) {
+ return clock.now;
+ }
+
+ return clock.tick(timer.callAt);
+ };
+
+ clock.reset = function reset() {
+ clock.timers = {};
+ };
+
+ clock.setSystemTime = function setSystemTime(systemTime) {
+ // determine time difference
+ var newNow = getEpoch(systemTime);
+ var difference = newNow - clock.now;
+ var id, timer;
+
+ // update 'system clock'
+ clock.now = newNow;
+
+ // update timers and intervals to keep them stable
+ for (id in clock.timers) {
+ if (clock.timers.hasOwnProperty(id)) {
+ timer = clock.timers[id];
+ timer.createdAt += difference;
+ timer.callAt += difference;
+ }
+ }
+ };
+
+ if (hrtimePresent) {
+ clock.hrtime = function (prev) {
+ if (Array.isArray(prev)) {
+ var oldSecs = (prev[0] + prev[1] / 1e9);
+ var newSecs = (clock.hrNow / 1000);
+ var difference = (newSecs - oldSecs);
+ var secs = fixedFloor(difference);
+ var nanosecs = fixedModulo(difference * 1e9, 1e9);
+ return [
+ secs,
+ nanosecs
+ ];
+ }
+ return [
+ fixedFloor(clock.hrNow / 1000),
+ fixedModulo(clock.hrNow * 1e6, 1e9)
+ ];
+ };
+ }
+
+ return clock;
+}
+exports.createClock = createClock;
+
+exports.install = function install(target, now, toFake, loopLimit) {
+ var i, l;
+
+ if (target instanceof Date) {
+ toFake = now;
+ now = target.getTime();
+ target = null;
+ }
+
+ if (typeof target === "number") {
+ toFake = now;
+ now = target;
+ target = null;
+ }
+
+ if (!target) {
+ target = global;
+ }
+
+ var clock = createClock(now, loopLimit);
+
+ clock.uninstall = function () {
+ uninstall(clock, target);
+ };
+
+ clock.methods = toFake || [];
+
+ if (clock.methods.length === 0) {
+ clock.methods = keys(timers);
+ }
+
+ for (i = 0, l = clock.methods.length; i < l; i++) {
+ if (clock.methods[i] === "hrtime") {
+ if (target.process && typeof target.process.hrtime === "function") {
+ hijackMethod(target.process, clock.methods[i], clock);
+ }
+ } else {
+ hijackMethod(target, clock.methods[i], clock);
+ }
+ }
+
+ return clock;
+};
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+
+},{}],66:[function(require,module,exports){
+var isarray = require('isarray')
+
+/**
+ * Expose `pathToRegexp`.
+ */
+module.exports = pathToRegexp
+module.exports.parse = parse
+module.exports.compile = compile
+module.exports.tokensToFunction = tokensToFunction
+module.exports.tokensToRegExp = tokensToRegExp
+
+/**
+ * The main path matching regexp utility.
+ *
+ * @type {RegExp}
+ */
+var PATH_REGEXP = new RegExp([
+ // Match escaped characters that would otherwise appear in future matches.
+ // This allows the user to escape special characters that won't transform.
+ '(\\\\.)',
+ // Match Express-style parameters and un-named parameters with a prefix
+ // and optional suffixes. Matches appear as:
+ //
+ // "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined]
+ // "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined, undefined]
+ // "/*" => ["/", undefined, undefined, undefined, undefined, "*"]
+ '([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))'
+].join('|'), 'g')
+
+/**
+ * Parse a string for the raw tokens.
+ *
+ * @param {string} str
+ * @param {Object=} options
+ * @return {!Array}
+ */
+function parse (str, options) {
+ var tokens = []
+ var key = 0
+ var index = 0
+ var path = ''
+ var defaultDelimiter = options && options.delimiter || '/'
+ var res
+
+ while ((res = PATH_REGEXP.exec(str)) != null) {
+ var m = res[0]
+ var escaped = res[1]
+ var offset = res.index
+ path += str.slice(index, offset)
+ index = offset + m.length
+
+ // Ignore already escaped sequences.
+ if (escaped) {
+ path += escaped[1]
+ continue
+ }
+
+ var next = str[index]
+ var prefix = res[2]
+ var name = res[3]
+ var capture = res[4]
+ var group = res[5]
+ var modifier = res[6]
+ var asterisk = res[7]
+
+ // Push the current path onto the tokens.
+ if (path) {
+ tokens.push(path)
+ path = ''
+ }
+
+ var partial = prefix != null && next != null && next !== prefix
+ var repeat = modifier === '+' || modifier === '*'
+ var optional = modifier === '?' || modifier === '*'
+ var delimiter = res[2] || defaultDelimiter
+ var pattern = capture || group
+
+ tokens.push({
+ name: name || key++,
+ prefix: prefix || '',
+ delimiter: delimiter,
+ optional: optional,
+ repeat: repeat,
+ partial: partial,
+ asterisk: !!asterisk,
+ pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')
+ })
+ }
+
+ // Match any characters still remaining.
+ if (index < str.length) {
+ path += str.substr(index)
+ }
+
+ // If the path exists, push it onto the end.
+ if (path) {
+ tokens.push(path)
+ }
+
+ return tokens
+}
+
+/**
+ * Compile a string to a template function for the path.
+ *
+ * @param {string} str
+ * @param {Object=} options
+ * @return {!function(Object=, Object=)}
+ */
+function compile (str, options) {
+ return tokensToFunction(parse(str, options))
+}
+
+/**
+ * Prettier encoding of URI path segments.
+ *
+ * @param {string}
+ * @return {string}
+ */
+function encodeURIComponentPretty (str) {
+ return encodeURI(str).replace(/[\/?#]/g, function (c) {
+ return '%' + c.charCodeAt(0).toString(16).toUpperCase()
+ })
+}
+
+/**
+ * Encode the asterisk parameter. Similar to `pretty`, but allows slashes.
+ *
+ * @param {string}
+ * @return {string}
+ */
+function encodeAsterisk (str) {
+ return encodeURI(str).replace(/[?#]/g, function (c) {
+ return '%' + c.charCodeAt(0).toString(16).toUpperCase()
+ })
+}
+
+/**
+ * Expose a method for transforming tokens into the path function.
+ */
+function tokensToFunction (tokens) {
+ // Compile all the tokens into regexps.
+ var matches = new Array(tokens.length)
+
+ // Compile all the patterns before compilation.
+ for (var i = 0; i < tokens.length; i++) {
+ if (typeof tokens[i] === 'object') {
+ matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$')
+ }
+ }
+
+ return function (obj, opts) {
+ var path = ''
+ var data = obj || {}
+ var options = opts || {}
+ var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent
+
+ for (var i = 0; i < tokens.length; i++) {
+ var token = tokens[i]
+
+ if (typeof token === 'string') {
+ path += token
+
+ continue
+ }
+
+ var value = data[token.name]
+ var segment
+
+ if (value == null) {
+ if (token.optional) {
+ // Prepend partial segment prefixes.
+ if (token.partial) {
+ path += token.prefix
+ }
+
+ continue
+ } else {
+ throw new TypeError('Expected "' + token.name + '" to be defined')
+ }
+ }
+
+ if (isarray(value)) {
+ if (!token.repeat) {
+ throw new TypeError('Expected "' + token.name + '" to not repeat, but received `' + JSON.stringify(value) + '`')
+ }
+
+ if (value.length === 0) {
+ if (token.optional) {
+ continue
+ } else {
+ throw new TypeError('Expected "' + token.name + '" to not be empty')
+ }
+ }
+
+ for (var j = 0; j < value.length; j++) {
+ segment = encode(value[j])
+
+ if (!matches[i].test(segment)) {
+ throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received `' + JSON.stringify(segment) + '`')
+ }
+
+ path += (j === 0 ? token.prefix : token.delimiter) + segment
+ }
+
+ continue
+ }
+
+ segment = token.asterisk ? encodeAsterisk(value) : encode(value)
+
+ if (!matches[i].test(segment)) {
+ throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"')
+ }
+
+ path += token.prefix + segment
+ }
+
+ return path
+ }
+}
+
+/**
+ * Escape a regular expression string.
+ *
+ * @param {string} str
+ * @return {string}
+ */
+function escapeString (str) {
+ return str.replace(/([.+*?=^!:${}()[\]|\/\\])/g, '\\$1')
+}
+
+/**
+ * Escape the capturing group by escaping special characters and meaning.
+ *
+ * @param {string} group
+ * @return {string}
+ */
+function escapeGroup (group) {
+ return group.replace(/([=!:$\/()])/g, '\\$1')
+}
+
+/**
+ * Attach the keys as a property of the regexp.
+ *
+ * @param {!RegExp} re
+ * @param {Array} keys
+ * @return {!RegExp}
+ */
+function attachKeys (re, keys) {
+ re.keys = keys
+ return re
+}
+
+/**
+ * Get the flags for a regexp from the options.
+ *
+ * @param {Object} options
+ * @return {string}
+ */
+function flags (options) {
+ return options.sensitive ? '' : 'i'
+}
+
+/**
+ * Pull out keys from a regexp.
+ *
+ * @param {!RegExp} path
+ * @param {!Array} keys
+ * @return {!RegExp}
+ */
+function regexpToRegexp (path, keys) {
+ // Use a negative lookahead to match only capturing groups.
+ var groups = path.source.match(/\((?!\?)/g)
+
+ if (groups) {
+ for (var i = 0; i < groups.length; i++) {
+ keys.push({
+ name: i,
+ prefix: null,
+ delimiter: null,
+ optional: false,
+ repeat: false,
+ partial: false,
+ asterisk: false,
+ pattern: null
+ })
+ }
+ }
+
+ return attachKeys(path, keys)
+}
+
+/**
+ * Transform an array into a regexp.
+ *
+ * @param {!Array} path
+ * @param {Array} keys
+ * @param {!Object} options
+ * @return {!RegExp}
+ */
+function arrayToRegexp (path, keys, options) {
+ var parts = []
+
+ for (var i = 0; i < path.length; i++) {
+ parts.push(pathToRegexp(path[i], keys, options).source)
+ }
+
+ var regexp = new RegExp('(?:' + parts.join('|') + ')', flags(options))
+
+ return attachKeys(regexp, keys)
+}
+
+/**
+ * Create a path regexp from string input.
+ *
+ * @param {string} path
+ * @param {!Array} keys
+ * @param {!Object} options
+ * @return {!RegExp}
+ */
+function stringToRegexp (path, keys, options) {
+ return tokensToRegExp(parse(path, options), keys, options)
+}
+
+/**
+ * Expose a function for taking tokens and returning a RegExp.
+ *
+ * @param {!Array} tokens
+ * @param {(Array|Object)=} keys
+ * @param {Object=} options
+ * @return {!RegExp}
+ */
+function tokensToRegExp (tokens, keys, options) {
+ if (!isarray(keys)) {
+ options = /** @type {!Object} */ (keys || options)
+ keys = []
+ }
+
+ options = options || {}
+
+ var strict = options.strict
+ var end = options.end !== false
+ var route = ''
+
+ // Iterate over the tokens and create our regexp string.
+ for (var i = 0; i < tokens.length; i++) {
+ var token = tokens[i]
+
+ if (typeof token === 'string') {
+ route += escapeString(token)
+ } else {
+ var prefix = escapeString(token.prefix)
+ var capture = '(?:' + token.pattern + ')'
+
+ keys.push(token)
+
+ if (token.repeat) {
+ capture += '(?:' + prefix + capture + ')*'
+ }
+
+ if (token.optional) {
+ if (!token.partial) {
+ capture = '(?:' + prefix + '(' + capture + '))?'
+ } else {
+ capture = prefix + '(' + capture + ')?'
+ }
+ } else {
+ capture = prefix + '(' + capture + ')'
+ }
+
+ route += capture
+ }
+ }
+
+ var delimiter = escapeString(options.delimiter || '/')
+ var endsWithDelimiter = route.slice(-delimiter.length) === delimiter
+
+ // In non-strict mode we allow a slash at the end of match. If the path to
+ // match already ends with a slash, we remove it for consistency. The slash
+ // is valid at the end of a path match, not in the middle. This is important
+ // in non-ending mode, where "/test/" shouldn't match "/test//route".
+ if (!strict) {
+ route = (endsWithDelimiter ? route.slice(0, -delimiter.length) : route) + '(?:' + delimiter + '(?=$))?'
+ }
+
+ if (end) {
+ route += '$'
+ } else {
+ // In non-ending mode, we need the capturing groups to match as much as
+ // possible by using a positive lookahead to the end or next path segment.
+ route += strict && endsWithDelimiter ? '' : '(?=' + delimiter + '|$)'
+ }
+
+ return attachKeys(new RegExp('^' + route, flags(options)), keys)
+}
+
+/**
+ * Normalize the given path string, returning a regular expression.
+ *
+ * An empty array can be passed in for the keys, which will hold the
+ * placeholder key descriptions. For example, using `/user/:id`, `keys` will
+ * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
+ *
+ * @param {(string|RegExp|Array)} path
+ * @param {(Array|Object)=} keys
+ * @param {Object=} options
+ * @return {!RegExp}
+ */
+function pathToRegexp (path, keys, options) {
+ if (!isarray(keys)) {
+ options = /** @type {!Object} */ (keys || options)
+ keys = []
+ }
+
+ options = options || {}
+
+ if (path instanceof RegExp) {
+ return regexpToRegexp(path, /** @type {!Array} */ (keys))
+ }
+
+ if (isarray(path)) {
+ return arrayToRegexp(/** @type {!Array} */ (path), /** @type {!Array} */ (keys), options)
+ }
+
+ return stringToRegexp(/** @type {string} */ (path), /** @type {!Array} */ (keys), options)
+}
+
+},{"isarray":64}],67:[function(require,module,exports){
+// shim for using process in browser
+var process = module.exports = {};
+
+// cached from whatever global is present so that test runners that stub it
+// don't break things. But we need to wrap it in a try catch in case it is
+// wrapped in strict mode code which doesn't define any globals. It's inside a
+// function because try/catches deoptimize in certain engines.
+
+var cachedSetTimeout;
+var cachedClearTimeout;
+
+function defaultSetTimout() {
+ throw new Error('setTimeout has not been defined');
+}
+function defaultClearTimeout () {
+ throw new Error('clearTimeout has not been defined');
+}
+(function () {
+ try {
+ if (typeof setTimeout === 'function') {
+ cachedSetTimeout = setTimeout;
+ } else {
+ cachedSetTimeout = defaultSetTimout;
+ }
+ } catch (e) {
+ cachedSetTimeout = defaultSetTimout;
+ }
+ try {
+ if (typeof clearTimeout === 'function') {
+ cachedClearTimeout = clearTimeout;
+ } else {
+ cachedClearTimeout = defaultClearTimeout;
+ }
+ } catch (e) {
+ cachedClearTimeout = defaultClearTimeout;
+ }
+} ())
+function runTimeout(fun) {
+ if (cachedSetTimeout === setTimeout) {
+ //normal enviroments in sane situations
+ return setTimeout(fun, 0);
+ }
+ // if setTimeout wasn't available but was latter defined
+ if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
+ cachedSetTimeout = setTimeout;
+ return setTimeout(fun, 0);
+ }
+ try {
+ // when when somebody has screwed with setTimeout but no I.E. maddness
+ return cachedSetTimeout(fun, 0);
+ } catch(e){
+ try {
+ // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
+ return cachedSetTimeout.call(null, fun, 0);
+ } catch(e){
+ // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
+ return cachedSetTimeout.call(this, fun, 0);
+ }
+ }
+
+
+}
+function runClearTimeout(marker) {
+ if (cachedClearTimeout === clearTimeout) {
+ //normal enviroments in sane situations
+ return clearTimeout(marker);
+ }
+ // if clearTimeout wasn't available but was latter defined
+ if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
+ cachedClearTimeout = clearTimeout;
+ return clearTimeout(marker);
+ }
+ try {
+ // when when somebody has screwed with setTimeout but no I.E. maddness
+ return cachedClearTimeout(marker);
+ } catch (e){
+ try {
+ // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
+ return cachedClearTimeout.call(null, marker);
+ } catch (e){
+ // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
+ // Some versions of I.E. have different rules for clearTimeout vs setTimeout
+ return cachedClearTimeout.call(this, marker);
+ }
+ }
+
+
+
+}
+var queue = [];
+var draining = false;
+var currentQueue;
+var queueIndex = -1;
+
+function cleanUpNextTick() {
+ if (!draining || !currentQueue) {
+ return;
+ }
+ draining = false;
+ if (currentQueue.length) {
+ queue = currentQueue.concat(queue);
+ } else {
+ queueIndex = -1;
+ }
+ if (queue.length) {
+ drainQueue();
+ }
+}
+
+function drainQueue() {
+ if (draining) {
+ return;
+ }
+ var timeout = runTimeout(cleanUpNextTick);
+ draining = true;
+
+ var len = queue.length;
+ while(len) {
+ currentQueue = queue;
+ queue = [];
+ while (++queueIndex < len) {
+ if (currentQueue) {
+ currentQueue[queueIndex].run();
+ }
+ }
+ queueIndex = -1;
+ len = queue.length;
+ }
+ currentQueue = null;
+ draining = false;
+ runClearTimeout(timeout);
+}
+
+process.nextTick = function (fun) {
+ var args = new Array(arguments.length - 1);
+ if (arguments.length > 1) {
+ for (var i = 1; i < arguments.length; i++) {
+ args[i - 1] = arguments[i];
+ }
+ }
+ queue.push(new Item(fun, args));
+ if (queue.length === 1 && !draining) {
+ runTimeout(drainQueue);
+ }
+};
+
+// v8 likes predictible objects
+function Item(fun, array) {
+ this.fun = fun;
+ this.array = array;
+}
+Item.prototype.run = function () {
+ this.fun.apply(null, this.array);
+};
+process.title = 'browser';
+process.browser = true;
+process.env = {};
+process.argv = [];
+process.version = ''; // empty string to avoid regexp issues
+process.versions = {};
+
+function noop() {}
+
+process.on = noop;
+process.addListener = noop;
+process.once = noop;
+process.off = noop;
+process.removeListener = noop;
+process.removeAllListeners = noop;
+process.emit = noop;
+
+process.binding = function (name) {
+ throw new Error('process.binding is not supported');
+};
+
+process.cwd = function () { return '/' };
+process.chdir = function (dir) {
+ throw new Error('process.chdir is not supported');
+};
+process.umask = function() { return 0; };
+
+},{}],68:[function(require,module,exports){
+((typeof define === "function" && define.amd && function (m) { define("samsam", m); }) ||
+ (typeof module === "object" &&
+ function (m) { module.exports = m(); }) || // Node
+ function (m) { this.samsam = m(); } // Browser globals
+)(function () {
+ var o = Object.prototype;
+ var div = typeof document !== "undefined" && document.createElement("div");
+
+ function isNaN(value) {
+ // Unlike global isNaN, this avoids type coercion
+ // typeof check avoids IE host object issues, hat tip to
+ // lodash
+ var val = value; // JsLint thinks value !== value is "weird"
+ return typeof value === "number" && value !== val;
+ }
+
+ function getClass(value) {
+ // Returns the internal [[Class]] by calling Object.prototype.toString
+ // with the provided value as this. Return value is a string, naming the
+ // internal class, e.g. "Array"
+ return o.toString.call(value).split(/[ \]]/)[1];
+ }
+
+ /**
+ * @name samsam.isArguments
+ * @param Object object
+ *
+ * Returns ``true`` if ``object`` is an ``arguments`` object,
+ * ``false`` otherwise.
+ */
+ function isArguments(object) {
+ if (getClass(object) === 'Arguments') { return true; }
+ if (typeof object !== "object" || typeof object.length !== "number" ||
+ getClass(object) === "Array") {
+ return false;
+ }
+ if (typeof object.callee == "function") { return true; }
+ try {
+ object[object.length] = 6;
+ delete object[object.length];
+ } catch (e) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @name samsam.isElement
+ * @param Object object
+ *
+ * Returns ``true`` if ``object`` is a DOM element node. Unlike
+ * Underscore.js/lodash, this function will return ``false`` if ``object``
+ * is an *element-like* object, i.e. a regular object with a ``nodeType``
+ * property that holds the value ``1``.
+ */
+ function isElement(object) {
+ if (!object || object.nodeType !== 1 || !div) { return false; }
+ try {
+ object.appendChild(div);
+ object.removeChild(div);
+ } catch (e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @name samsam.keys
+ * @param Object object
+ *
+ * Return an array of own property names.
+ */
+ function keys(object) {
+ var ks = [], prop;
+ for (prop in object) {
+ if (o.hasOwnProperty.call(object, prop)) { ks.push(prop); }
+ }
+ return ks;
+ }
+
+ /**
+ * @name samsam.isDate
+ * @param Object value
+ *
+ * Returns true if the object is a ``Date``, or *date-like*. Duck typing
+ * of date objects work by checking that the object has a ``getTime``
+ * function whose return value equals the return value from the object's
+ * ``valueOf``.
+ */
+ function isDate(value) {
+ return typeof value.getTime == "function" &&
+ value.getTime() == value.valueOf();
+ }
+
+ /**
+ * @name samsam.isNegZero
+ * @param Object value
+ *
+ * Returns ``true`` if ``value`` is ``-0``.
+ */
+ function isNegZero(value) {
+ return value === 0 && 1 / value === -Infinity;
+ }
+
+ /**
+ * @name samsam.equal
+ * @param Object obj1
+ * @param Object obj2
+ *
+ * Returns ``true`` if two objects are strictly equal. Compared to
+ * ``===`` there are two exceptions:
+ *
+ * - NaN is considered equal to NaN
+ * - -0 and +0 are not considered equal
+ */
+ function identical(obj1, obj2) {
+ if (obj1 === obj2 || (isNaN(obj1) && isNaN(obj2))) {
+ return obj1 !== 0 || isNegZero(obj1) === isNegZero(obj2);
+ }
+ }
+
+ function isSet(val) {
+ if (typeof Set !== 'undefined' && val instanceof Set) {
+ return true;
+ }
+ }
+
+ function isSubset(s1, s2, compare) {
+ var values1 = Array.from(s1);
+ var values2 = Array.from(s2);
+
+ for (var i = 0; i < values1.length; i++) {
+ var includes = false;
+
+ for (var j = 0; j < values2.length; j++) {
+ if (compare(values2[j], values1[i])) {
+ includes = true;
+ break;
+ }
+ }
+
+ if (!includes) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * @name samsam.deepEqual
+ * @param Object obj1
+ * @param Object obj2
+ *
+ * Deep equal comparison. Two values are "deep equal" if:
+ *
+ * - They are equal, according to samsam.identical
+ * - They are both date objects representing the same time
+ * - They are both arrays containing elements that are all deepEqual
+ * - They are objects with the same set of properties, and each property
+ * in ``obj1`` is deepEqual to the corresponding property in ``obj2``
+ *
+ * Supports cyclic objects.
+ */
+ function deepEqualCyclic(obj1, obj2) {
+
+ // used for cyclic comparison
+ // contain already visited objects
+ var objects1 = [],
+ objects2 = [],
+ // contain pathes (position in the object structure)
+ // of the already visited objects
+ // indexes same as in objects arrays
+ paths1 = [],
+ paths2 = [],
+ // contains combinations of already compared objects
+ // in the manner: { "$1['ref']$2['ref']": true }
+ compared = {};
+
+ /**
+ * used to check, if the value of a property is an object
+ * (cyclic logic is only needed for objects)
+ * only needed for cyclic logic
+ */
+ function isObject(value) {
+
+ if (typeof value === 'object' && value !== null &&
+ !(value instanceof Boolean) &&
+ !(value instanceof Date) &&
+ !(value instanceof Number) &&
+ !(value instanceof RegExp) &&
+ !(value instanceof String)) {
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * returns the index of the given object in the
+ * given objects array, -1 if not contained
+ * only needed for cyclic logic
+ */
+ function getIndex(objects, obj) {
+
+ var i;
+ for (i = 0; i < objects.length; i++) {
+ if (objects[i] === obj) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ // does the recursion for the deep equal check
+ return (function deepEqual(obj1, obj2, path1, path2) {
+ var type1 = typeof obj1;
+ var type2 = typeof obj2;
+
+ // == null also matches undefined
+ if (obj1 === obj2 ||
+ isNaN(obj1) || isNaN(obj2) ||
+ obj1 == null || obj2 == null ||
+ type1 !== "object" || type2 !== "object") {
+
+ return identical(obj1, obj2);
+ }
+
+ // Elements are only equal if identical(expected, actual)
+ if (isElement(obj1) || isElement(obj2)) { return false; }
+
+ var isDate1 = isDate(obj1), isDate2 = isDate(obj2);
+ if (isDate1 || isDate2) {
+ if (!isDate1 || !isDate2 || obj1.getTime() !== obj2.getTime()) {
+ return false;
+ }
+ }
+
+ if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
+ if (obj1.toString() !== obj2.toString()) { return false; }
+ }
+
+ var class1 = getClass(obj1);
+ var class2 = getClass(obj2);
+ var keys1 = keys(obj1);
+ var keys2 = keys(obj2);
+
+ if (isArguments(obj1) || isArguments(obj2)) {
+ if (obj1.length !== obj2.length) { return false; }
+ } else {
+ if (type1 !== type2 || class1 !== class2 ||
+ keys1.length !== keys2.length) {
+ return false;
+ }
+ }
+
+ if (isSet(obj1) || isSet(obj2)) {
+ if (!isSet(obj1) || !isSet(obj2) || obj1.size !== obj2.size) {
+ return false;
+ }
+
+ return isSubset(obj1, obj2, deepEqual);
+ }
+
+ var key, i, l,
+ // following vars are used for the cyclic logic
+ value1, value2,
+ isObject1, isObject2,
+ index1, index2,
+ newPath1, newPath2;
+
+ for (i = 0, l = keys1.length; i < l; i++) {
+ key = keys1[i];
+ if (!o.hasOwnProperty.call(obj2, key)) {
+ return false;
+ }
+
+ // Start of the cyclic logic
+
+ value1 = obj1[key];
+ value2 = obj2[key];
+
+ isObject1 = isObject(value1);
+ isObject2 = isObject(value2);
+
+ // determine, if the objects were already visited
+ // (it's faster to check for isObject first, than to
+ // get -1 from getIndex for non objects)
+ index1 = isObject1 ? getIndex(objects1, value1) : -1;
+ index2 = isObject2 ? getIndex(objects2, value2) : -1;
+
+ // determine the new pathes of the objects
+ // - for non cyclic objects the current path will be extended
+ // by current property name
+ // - for cyclic objects the stored path is taken
+ newPath1 = index1 !== -1
+ ? paths1[index1]
+ : path1 + '[' + JSON.stringify(key) + ']';
+ newPath2 = index2 !== -1
+ ? paths2[index2]
+ : path2 + '[' + JSON.stringify(key) + ']';
+
+ // stop recursion if current objects are already compared
+ if (compared[newPath1 + newPath2]) {
+ return true;
+ }
+
+ // remember the current objects and their pathes
+ if (index1 === -1 && isObject1) {
+ objects1.push(value1);
+ paths1.push(newPath1);
+ }
+ if (index2 === -1 && isObject2) {
+ objects2.push(value2);
+ paths2.push(newPath2);
+ }
+
+ // remember that the current objects are already compared
+ if (isObject1 && isObject2) {
+ compared[newPath1 + newPath2] = true;
+ }
+
+ // End of cyclic logic
+
+ // neither value1 nor value2 is a cycle
+ // continue with next level
+ if (!deepEqual(value1, value2, newPath1, newPath2)) {
+ return false;
+ }
+ }
+
+ return true;
+
+ }(obj1, obj2, '$1', '$2'));
+ }
+
+ function arrayContains(array, subset, compare) {
+ if (subset.length === 0) { return true; }
+ var i, l, j, k;
+ for (i = 0, l = array.length; i < l; ++i) {
+ if (compare(array[i], subset[0])) {
+ for (j = 0, k = subset.length; j < k; ++j) {
+ if ((i + j) >= l) { return false; }
+ if (!compare(array[i + j], subset[j])) { return false; }
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @name samsam.match
+ * @param Object object
+ * @param Object matcher
+ *
+ * Compare arbitrary value ``object`` with matcher.
+ */
+ function match(object, matcher) {
+ if (matcher && typeof matcher.test === "function") {
+ return matcher.test(object);
+ }
+
+ if (typeof matcher === "function") {
+ return matcher(object) === true;
+ }
+
+ if (typeof matcher === "string") {
+ matcher = matcher.toLowerCase();
+ var notNull = typeof object === "string" || !!object;
+ return notNull &&
+ (String(object)).toLowerCase().indexOf(matcher) >= 0;
+ }
+
+ if (typeof matcher === "number") {
+ return matcher === object;
+ }
+
+ if (typeof matcher === "boolean") {
+ return matcher === object;
+ }
+
+ if (typeof(matcher) === "undefined") {
+ return typeof(object) === "undefined";
+ }
+
+ if (matcher === null) {
+ return object === null;
+ }
+
+ if (isSet(object)) {
+ return isSubset(matcher, object, match);
+ }
+
+ if (getClass(object) === "Array" && getClass(matcher) === "Array") {
+ return arrayContains(object, matcher, match);
+ }
+
+ if (matcher && typeof matcher === "object") {
+ if (matcher === object) {
+ return true;
+ }
+ var prop;
+ for (prop in matcher) {
+ var value = object[prop];
+ if (typeof value === "undefined" &&
+ typeof object.getAttribute === "function") {
+ value = object.getAttribute(prop);
+ }
+ if (matcher[prop] === null || typeof matcher[prop] === 'undefined') {
+ if (value !== matcher[prop]) {
+ return false;
+ }
+ } else if (typeof value === "undefined" || !match(value, matcher[prop])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ throw new Error("Matcher was not a string, a number, a " +
+ "function, a boolean or an object");
+ }
+
+ return {
+ isArguments: isArguments,
+ isElement: isElement,
+ isDate: isDate,
+ isNegZero: isNegZero,
+ identical: identical,
+ deepEqual: deepEqualCyclic,
+ match: match,
+ keys: keys
+ };
+});
+
+},{}],69:[function(require,module,exports){
+// This is free and unencumbered software released into the public domain.
+// See LICENSE.md for more information.
+
+var encoding = require("./lib/encoding.js");
+
+module.exports = {
+ TextEncoder: encoding.TextEncoder,
+ TextDecoder: encoding.TextDecoder,
+};
+
+},{"./lib/encoding.js":71}],70:[function(require,module,exports){
+(function(global) {
+ 'use strict';
+
+ if (typeof module !== "undefined" && module.exports) {
+ module.exports = global;
+ }
+
+ global["encoding-indexes"] =
+{
+ "big5":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,17392,19506,17923,17830,17784,160359,19831,17843,162993,19682,163013,15253,18230,18244,19527,19520,148159,144919,160594,159371,159954,19543,172881,18255,17882,19589,162924,19719,19108,18081,158499,29221,154196,137827,146950,147297,26189,22267,null,32149,22813,166841,15860,38708,162799,23515,138590,23204,13861,171696,23249,23479,23804,26478,34195,170309,29793,29853,14453,138579,145054,155681,16108,153822,15093,31484,40855,147809,166157,143850,133770,143966,17162,33924,40854,37935,18736,34323,22678,38730,37400,31184,31282,26208,27177,34973,29772,31685,26498,31276,21071,36934,13542,29636,155065,29894,40903,22451,18735,21580,16689,145038,22552,31346,162661,35727,18094,159368,16769,155033,31662,140476,40904,140481,140489,140492,40905,34052,144827,16564,40906,17633,175615,25281,28782,40907,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,12736,12737,12738,12739,12740,131340,12741,131281,131277,12742,12743,131275,139240,12744,131274,12745,12746,12747,12748,131342,12749,12750,256,193,461,192,274,201,282,200,332,211,465,210,null,7870,null,7872,202,257,225,462,224,593,275,233,283,232,299,237,464,236,333,243,466,242,363,250,468,249,470,472,474,476,252,null,7871,null,7873,234,609,9178,9179,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,172969,135493,null,25866,null,null,20029,28381,40270,37343,null,null,161589,25745,20250,20264,20392,20822,20852,20892,20964,21153,21160,21307,21326,21457,21464,22242,22768,22788,22791,22834,22836,23398,23454,23455,23706,24198,24635,25993,26622,26628,26725,27982,28860,30005,32420,32428,32442,32455,32463,32479,32518,32567,33402,33487,33647,35270,35774,35810,36710,36711,36718,29713,31996,32205,26950,31433,21031,null,null,null,null,37260,30904,37214,32956,null,36107,33014,133607,null,null,32927,40647,19661,40393,40460,19518,171510,159758,40458,172339,13761,null,28314,33342,29977,null,18705,39532,39567,40857,31111,164972,138698,132560,142054,20004,20097,20096,20103,20159,20203,20279,13388,20413,15944,20483,20616,13437,13459,13477,20870,22789,20955,20988,20997,20105,21113,21136,21287,13767,21417,13649,21424,13651,21442,21539,13677,13682,13953,21651,21667,21684,21689,21712,21743,21784,21795,21800,13720,21823,13733,13759,21975,13765,163204,21797,null,134210,134421,151851,21904,142534,14828,131905,36422,150968,169189,16467,164030,30586,142392,14900,18389,164189,158194,151018,25821,134524,135092,134357,135412,25741,36478,134806,134155,135012,142505,164438,148691,null,134470,170573,164073,18420,151207,142530,39602,14951,169460,16365,13574,152263,169940,161992,142660,40302,38933,null,17369,155813,25780,21731,142668,142282,135287,14843,135279,157402,157462,162208,25834,151634,134211,36456,139681,166732,132913,null,18443,131497,16378,22643,142733,null,148936,132348,155799,134988,134550,21881,16571,17338,null,19124,141926,135325,33194,39157,134556,25465,14846,141173,36288,22177,25724,15939,null,173569,134665,142031,142537,null,135368,145858,14738,14854,164507,13688,155209,139463,22098,134961,142514,169760,13500,27709,151099,null,null,161140,142987,139784,173659,167117,134778,134196,157724,32659,135375,141315,141625,13819,152035,134796,135053,134826,16275,134960,134471,135503,134732,null,134827,134057,134472,135360,135485,16377,140950,25650,135085,144372,161337,142286,134526,134527,142417,142421,14872,134808,135367,134958,173618,158544,167122,167321,167114,38314,21708,33476,21945,null,171715,39974,39606,161630,142830,28992,33133,33004,23580,157042,33076,14231,21343,164029,37302,134906,134671,134775,134907,13789,151019,13833,134358,22191,141237,135369,134672,134776,135288,135496,164359,136277,134777,151120,142756,23124,135197,135198,135413,135414,22428,134673,161428,164557,135093,134779,151934,14083,135094,135552,152280,172733,149978,137274,147831,164476,22681,21096,13850,153405,31666,23400,18432,19244,40743,18919,39967,39821,154484,143677,22011,13810,22153,20008,22786,138177,194680,38737,131206,20059,20155,13630,23587,24401,24516,14586,25164,25909,27514,27701,27706,28780,29227,20012,29357,149737,32594,31035,31993,32595,156266,13505,null,156491,32770,32896,157202,158033,21341,34916,35265,161970,35744,36125,38021,38264,38271,38376,167439,38886,39029,39118,39134,39267,170000,40060,40479,40644,27503,63751,20023,131207,38429,25143,38050,null,20539,28158,171123,40870,15817,34959,147790,28791,23797,19232,152013,13657,154928,24866,166450,36775,37366,29073,26393,29626,144001,172295,15499,137600,19216,30948,29698,20910,165647,16393,27235,172730,16931,34319,133743,31274,170311,166634,38741,28749,21284,139390,37876,30425,166371,40871,30685,20131,20464,20668,20015,20247,40872,21556,32139,22674,22736,138678,24210,24217,24514,141074,25995,144377,26905,27203,146531,27903,null,29184,148741,29580,16091,150035,23317,29881,35715,154788,153237,31379,31724,31939,32364,33528,34199,40873,34960,40874,36537,40875,36815,34143,39392,37409,40876,167353,136255,16497,17058,23066,null,null,null,39016,26475,17014,22333,null,34262,149883,33471,160013,19585,159092,23931,158485,159678,40877,40878,23446,40879,26343,32347,28247,31178,15752,17603,143958,141206,17306,17718,null,23765,146202,35577,23672,15634,144721,23928,40882,29015,17752,147692,138787,19575,14712,13386,131492,158785,35532,20404,131641,22975,33132,38998,170234,24379,134047,null,139713,166253,16642,18107,168057,16135,40883,172469,16632,14294,18167,158790,16764,165554,160767,17773,14548,152730,17761,17691,19849,19579,19830,17898,16328,150287,13921,17630,17597,16877,23870,23880,23894,15868,14351,23972,23993,14368,14392,24130,24253,24357,24451,14600,14612,14655,14669,24791,24893,23781,14729,25015,25017,25039,14776,25132,25232,25317,25368,14840,22193,14851,25570,25595,25607,25690,14923,25792,23829,22049,40863,14999,25990,15037,26111,26195,15090,26258,15138,26390,15170,26532,26624,15192,26698,26756,15218,15217,15227,26889,26947,29276,26980,27039,27013,15292,27094,15325,27237,27252,27249,27266,15340,27289,15346,27307,27317,27348,27382,27521,27585,27626,27765,27818,15563,27906,27910,27942,28033,15599,28068,28081,28181,28184,28201,28294,166336,28347,28386,28378,40831,28392,28393,28452,28468,15686,147265,28545,28606,15722,15733,29111,23705,15754,28716,15761,28752,28756,28783,28799,28809,131877,17345,13809,134872,147159,22462,159443,28990,153568,13902,27042,166889,23412,31305,153825,169177,31333,31357,154028,31419,31408,31426,31427,29137,156813,16842,31450,31453,31466,16879,21682,154625,31499,31573,31529,152334,154878,31650,31599,33692,154548,158847,31696,33825,31634,31672,154912,15789,154725,33938,31738,31750,31797,154817,31812,31875,149634,31910,26237,148856,31945,31943,31974,31860,31987,31989,31950,32359,17693,159300,32093,159446,29837,32137,32171,28981,32179,32210,147543,155689,32228,15635,32245,137209,32229,164717,32285,155937,155994,32366,32402,17195,37996,32295,32576,32577,32583,31030,156368,39393,32663,156497,32675,136801,131176,17756,145254,17667,164666,32762,156809,32773,32776,32797,32808,32815,172167,158915,32827,32828,32865,141076,18825,157222,146915,157416,26405,32935,166472,33031,33050,22704,141046,27775,156824,151480,25831,136330,33304,137310,27219,150117,150165,17530,33321,133901,158290,146814,20473,136445,34018,33634,158474,149927,144688,137075,146936,33450,26907,194964,16859,34123,33488,33562,134678,137140,14017,143741,144730,33403,33506,33560,147083,159139,158469,158615,144846,15807,33565,21996,33669,17675,159141,33708,33729,33747,13438,159444,27223,34138,13462,159298,143087,33880,154596,33905,15827,17636,27303,33866,146613,31064,33960,158614,159351,159299,34014,33807,33681,17568,33939,34020,154769,16960,154816,17731,34100,23282,159385,17703,34163,17686,26559,34326,165413,165435,34241,159880,34306,136578,159949,194994,17770,34344,13896,137378,21495,160666,34430,34673,172280,34798,142375,34737,34778,34831,22113,34412,26710,17935,34885,34886,161248,146873,161252,34910,34972,18011,34996,34997,25537,35013,30583,161551,35207,35210,35238,35241,35239,35260,166437,35303,162084,162493,35484,30611,37374,35472,162393,31465,162618,147343,18195,162616,29052,35596,35615,152624,152933,35647,35660,35661,35497,150138,35728,35739,35503,136927,17941,34895,35995,163156,163215,195028,14117,163155,36054,163224,163261,36114,36099,137488,36059,28764,36113,150729,16080,36215,36265,163842,135188,149898,15228,164284,160012,31463,36525,36534,36547,37588,36633,36653,164709,164882,36773,37635,172703,133712,36787,18730,166366,165181,146875,24312,143970,36857,172052,165564,165121,140069,14720,159447,36919,165180,162494,36961,165228,165387,37032,165651,37060,165606,37038,37117,37223,15088,37289,37316,31916,166195,138889,37390,27807,37441,37474,153017,37561,166598,146587,166668,153051,134449,37676,37739,166625,166891,28815,23235,166626,166629,18789,37444,166892,166969,166911,37747,37979,36540,38277,38310,37926,38304,28662,17081,140922,165592,135804,146990,18911,27676,38523,38550,16748,38563,159445,25050,38582,30965,166624,38589,21452,18849,158904,131700,156688,168111,168165,150225,137493,144138,38705,34370,38710,18959,17725,17797,150249,28789,23361,38683,38748,168405,38743,23370,168427,38751,37925,20688,143543,143548,38793,38815,38833,38846,38848,38866,38880,152684,38894,29724,169011,38911,38901,168989,162170,19153,38964,38963,38987,39014,15118,160117,15697,132656,147804,153350,39114,39095,39112,39111,19199,159015,136915,21936,39137,39142,39148,37752,39225,150057,19314,170071,170245,39413,39436,39483,39440,39512,153381,14020,168113,170965,39648,39650,170757,39668,19470,39700,39725,165376,20532,39732,158120,14531,143485,39760,39744,171326,23109,137315,39822,148043,39938,39935,39948,171624,40404,171959,172434,172459,172257,172323,172511,40318,40323,172340,40462,26760,40388,139611,172435,172576,137531,172595,40249,172217,172724,40592,40597,40606,40610,19764,40618,40623,148324,40641,15200,14821,15645,20274,14270,166955,40706,40712,19350,37924,159138,40727,40726,40761,22175,22154,40773,39352,168075,38898,33919,40802,40809,31452,40846,29206,19390,149877,149947,29047,150008,148296,150097,29598,166874,137466,31135,166270,167478,37737,37875,166468,37612,37761,37835,166252,148665,29207,16107,30578,31299,28880,148595,148472,29054,137199,28835,137406,144793,16071,137349,152623,137208,14114,136955,137273,14049,137076,137425,155467,14115,136896,22363,150053,136190,135848,136134,136374,34051,145062,34051,33877,149908,160101,146993,152924,147195,159826,17652,145134,170397,159526,26617,14131,15381,15847,22636,137506,26640,16471,145215,147681,147595,147727,158753,21707,22174,157361,22162,135135,134056,134669,37830,166675,37788,20216,20779,14361,148534,20156,132197,131967,20299,20362,153169,23144,131499,132043,14745,131850,132116,13365,20265,131776,167603,131701,35546,131596,20120,20685,20749,20386,20227,150030,147082,20290,20526,20588,20609,20428,20453,20568,20732,20825,20827,20829,20830,28278,144789,147001,147135,28018,137348,147081,20904,20931,132576,17629,132259,132242,132241,36218,166556,132878,21081,21156,133235,21217,37742,18042,29068,148364,134176,149932,135396,27089,134685,29817,16094,29849,29716,29782,29592,19342,150204,147597,21456,13700,29199,147657,21940,131909,21709,134086,22301,37469,38644,37734,22493,22413,22399,13886,22731,23193,166470,136954,137071,136976,23084,22968,37519,23166,23247,23058,153926,137715,137313,148117,14069,27909,29763,23073,155267,23169,166871,132115,37856,29836,135939,28933,18802,37896,166395,37821,14240,23582,23710,24158,24136,137622,137596,146158,24269,23375,137475,137476,14081,137376,14045,136958,14035,33066,166471,138682,144498,166312,24332,24334,137511,137131,23147,137019,23364,34324,161277,34912,24702,141408,140843,24539,16056,140719,140734,168072,159603,25024,131134,131142,140827,24985,24984,24693,142491,142599,149204,168269,25713,149093,142186,14889,142114,144464,170218,142968,25399,173147,25782,25393,25553,149987,142695,25252,142497,25659,25963,26994,15348,143502,144045,149897,144043,21773,144096,137433,169023,26318,144009,143795,15072,16784,152964,166690,152975,136956,152923,152613,30958,143619,137258,143924,13412,143887,143746,148169,26254,159012,26219,19347,26160,161904,138731,26211,144082,144097,26142,153714,14545,145466,145340,15257,145314,144382,29904,15254,26511,149034,26806,26654,15300,27326,14435,145365,148615,27187,27218,27337,27397,137490,25873,26776,27212,15319,27258,27479,147392,146586,37792,37618,166890,166603,37513,163870,166364,37991,28069,28427,149996,28007,147327,15759,28164,147516,23101,28170,22599,27940,30786,28987,148250,148086,28913,29264,29319,29332,149391,149285,20857,150180,132587,29818,147192,144991,150090,149783,155617,16134,16049,150239,166947,147253,24743,16115,29900,29756,37767,29751,17567,159210,17745,30083,16227,150745,150790,16216,30037,30323,173510,15129,29800,166604,149931,149902,15099,15821,150094,16127,149957,149747,37370,22322,37698,166627,137316,20703,152097,152039,30584,143922,30478,30479,30587,149143,145281,14942,149744,29752,29851,16063,150202,150215,16584,150166,156078,37639,152961,30750,30861,30856,30930,29648,31065,161601,153315,16654,31131,33942,31141,27181,147194,31290,31220,16750,136934,16690,37429,31217,134476,149900,131737,146874,137070,13719,21867,13680,13994,131540,134157,31458,23129,141045,154287,154268,23053,131675,30960,23082,154566,31486,16889,31837,31853,16913,154547,155324,155302,31949,150009,137136,31886,31868,31918,27314,32220,32263,32211,32590,156257,155996,162632,32151,155266,17002,158581,133398,26582,131150,144847,22468,156690,156664,149858,32733,31527,133164,154345,154947,31500,155150,39398,34373,39523,27164,144447,14818,150007,157101,39455,157088,33920,160039,158929,17642,33079,17410,32966,33033,33090,157620,39107,158274,33378,33381,158289,33875,159143,34320,160283,23174,16767,137280,23339,137377,23268,137432,34464,195004,146831,34861,160802,23042,34926,20293,34951,35007,35046,35173,35149,153219,35156,161669,161668,166901,166873,166812,166393,16045,33955,18165,18127,14322,35389,35356,169032,24397,37419,148100,26068,28969,28868,137285,40301,35999,36073,163292,22938,30659,23024,17262,14036,36394,36519,150537,36656,36682,17140,27736,28603,140065,18587,28537,28299,137178,39913,14005,149807,37051,37015,21873,18694,37307,37892,166475,16482,166652,37927,166941,166971,34021,35371,38297,38311,38295,38294,167220,29765,16066,149759,150082,148458,16103,143909,38543,167655,167526,167525,16076,149997,150136,147438,29714,29803,16124,38721,168112,26695,18973,168083,153567,38749,37736,166281,166950,166703,156606,37562,23313,35689,18748,29689,147995,38811,38769,39224,134950,24001,166853,150194,38943,169178,37622,169431,37349,17600,166736,150119,166756,39132,166469,16128,37418,18725,33812,39227,39245,162566,15869,39323,19311,39338,39516,166757,153800,27279,39457,23294,39471,170225,19344,170312,39356,19389,19351,37757,22642,135938,22562,149944,136424,30788,141087,146872,26821,15741,37976,14631,24912,141185,141675,24839,40015,40019,40059,39989,39952,39807,39887,171565,39839,172533,172286,40225,19630,147716,40472,19632,40204,172468,172269,172275,170287,40357,33981,159250,159711,158594,34300,17715,159140,159364,159216,33824,34286,159232,145367,155748,31202,144796,144960,18733,149982,15714,37851,37566,37704,131775,30905,37495,37965,20452,13376,36964,152925,30781,30804,30902,30795,137047,143817,149825,13978,20338,28634,28633,28702,28702,21524,147893,22459,22771,22410,40214,22487,28980,13487,147884,29163,158784,151447,23336,137141,166473,24844,23246,23051,17084,148616,14124,19323,166396,37819,37816,137430,134941,33906,158912,136211,148218,142374,148417,22932,146871,157505,32168,155995,155812,149945,149899,166394,37605,29666,16105,29876,166755,137375,16097,150195,27352,29683,29691,16086,150078,150164,137177,150118,132007,136228,149989,29768,149782,28837,149878,37508,29670,37727,132350,37681,166606,166422,37766,166887,153045,18741,166530,29035,149827,134399,22180,132634,134123,134328,21762,31172,137210,32254,136898,150096,137298,17710,37889,14090,166592,149933,22960,137407,137347,160900,23201,14050,146779,14000,37471,23161,166529,137314,37748,15565,133812,19094,14730,20724,15721,15692,136092,29045,17147,164376,28175,168164,17643,27991,163407,28775,27823,15574,147437,146989,28162,28428,15727,132085,30033,14012,13512,18048,16090,18545,22980,37486,18750,36673,166940,158656,22546,22472,14038,136274,28926,148322,150129,143331,135856,140221,26809,26983,136088,144613,162804,145119,166531,145366,144378,150687,27162,145069,158903,33854,17631,17614,159014,159057,158850,159710,28439,160009,33597,137018,33773,158848,159827,137179,22921,23170,137139,23137,23153,137477,147964,14125,23023,137020,14023,29070,37776,26266,148133,23150,23083,148115,27179,147193,161590,148571,148170,28957,148057,166369,20400,159016,23746,148686,163405,148413,27148,148054,135940,28838,28979,148457,15781,27871,194597,150095,32357,23019,23855,15859,24412,150109,137183,32164,33830,21637,146170,144128,131604,22398,133333,132633,16357,139166,172726,28675,168283,23920,29583,31955,166489,168992,20424,32743,29389,29456,162548,29496,29497,153334,29505,29512,16041,162584,36972,29173,149746,29665,33270,16074,30476,16081,27810,22269,29721,29726,29727,16098,16112,16116,16122,29907,16142,16211,30018,30061,30066,30093,16252,30152,30172,16320,30285,16343,30324,16348,30330,151388,29064,22051,35200,22633,16413,30531,16441,26465,16453,13787,30616,16490,16495,23646,30654,30667,22770,30744,28857,30748,16552,30777,30791,30801,30822,33864,152885,31027,26627,31026,16643,16649,31121,31129,36795,31238,36796,16743,31377,16818,31420,33401,16836,31439,31451,16847,20001,31586,31596,31611,31762,31771,16992,17018,31867,31900,17036,31928,17044,31981,36755,28864,134351,32207,32212,32208,32253,32686,32692,29343,17303,32800,32805,31545,32814,32817,32852,15820,22452,28832,32951,33001,17389,33036,29482,33038,33042,30048,33044,17409,15161,33110,33113,33114,17427,22586,33148,33156,17445,33171,17453,33189,22511,33217,33252,33364,17551,33446,33398,33482,33496,33535,17584,33623,38505,27018,33797,28917,33892,24803,33928,17668,33982,34017,34040,34064,34104,34130,17723,34159,34160,34272,17783,34418,34450,34482,34543,38469,34699,17926,17943,34990,35071,35108,35143,35217,162151,35369,35384,35476,35508,35921,36052,36082,36124,18328,22623,36291,18413,20206,36410,21976,22356,36465,22005,36528,18487,36558,36578,36580,36589,36594,36791,36801,36810,36812,36915,39364,18605,39136,37395,18718,37416,37464,37483,37553,37550,37567,37603,37611,37619,37620,37629,37699,37764,37805,18757,18769,40639,37911,21249,37917,37933,37950,18794,37972,38009,38189,38306,18855,38388,38451,18917,26528,18980,38720,18997,38834,38850,22100,19172,24808,39097,19225,39153,22596,39182,39193,20916,39196,39223,39234,39261,39266,19312,39365,19357,39484,39695,31363,39785,39809,39901,39921,39924,19565,39968,14191,138178,40265,39994,40702,22096,40339,40381,40384,40444,38134,36790,40571,40620,40625,40637,40646,38108,40674,40689,40696,31432,40772,131220,131767,132000,26906,38083,22956,132311,22592,38081,14265,132565,132629,132726,136890,22359,29043,133826,133837,134079,21610,194619,134091,21662,134139,134203,134227,134245,134268,24807,134285,22138,134325,134365,134381,134511,134578,134600,26965,39983,34725,134660,134670,134871,135056,134957,134771,23584,135100,24075,135260,135247,135286,26398,135291,135304,135318,13895,135359,135379,135471,135483,21348,33965,135907,136053,135990,35713,136567,136729,137155,137159,20088,28859,137261,137578,137773,137797,138282,138352,138412,138952,25283,138965,139029,29080,26709,139333,27113,14024,139900,140247,140282,141098,141425,141647,33533,141671,141715,142037,35237,142056,36768,142094,38840,142143,38983,39613,142412,null,142472,142519,154600,142600,142610,142775,142741,142914,143220,143308,143411,143462,144159,144350,24497,26184,26303,162425,144743,144883,29185,149946,30679,144922,145174,32391,131910,22709,26382,26904,146087,161367,155618,146961,147129,161278,139418,18640,19128,147737,166554,148206,148237,147515,148276,148374,150085,132554,20946,132625,22943,138920,15294,146687,148484,148694,22408,149108,14747,149295,165352,170441,14178,139715,35678,166734,39382,149522,149755,150037,29193,150208,134264,22885,151205,151430,132985,36570,151596,21135,22335,29041,152217,152601,147274,150183,21948,152646,152686,158546,37332,13427,152895,161330,152926,18200,152930,152934,153543,149823,153693,20582,13563,144332,24798,153859,18300,166216,154286,154505,154630,138640,22433,29009,28598,155906,162834,36950,156082,151450,35682,156674,156746,23899,158711,36662,156804,137500,35562,150006,156808,147439,156946,19392,157119,157365,141083,37989,153569,24981,23079,194765,20411,22201,148769,157436,20074,149812,38486,28047,158909,13848,35191,157593,157806,156689,157790,29151,157895,31554,168128,133649,157990,37124,158009,31301,40432,158202,39462,158253,13919,156777,131105,31107,158260,158555,23852,144665,33743,158621,18128,158884,30011,34917,159150,22710,14108,140685,159819,160205,15444,160384,160389,37505,139642,160395,37680,160486,149968,27705,38047,160848,134904,34855,35061,141606,164979,137137,28344,150058,137248,14756,14009,23568,31203,17727,26294,171181,170148,35139,161740,161880,22230,16607,136714,14753,145199,164072,136133,29101,33638,162269,168360,23143,19639,159919,166315,162301,162314,162571,163174,147834,31555,31102,163849,28597,172767,27139,164632,21410,159239,37823,26678,38749,164207,163875,158133,136173,143919,163912,23941,166960,163971,22293,38947,166217,23979,149896,26046,27093,21458,150181,147329,15377,26422,163984,164084,164142,139169,164175,164233,164271,164378,164614,164655,164746,13770,164968,165546,18682,25574,166230,30728,37461,166328,17394,166375,17375,166376,166726,166868,23032,166921,36619,167877,168172,31569,168208,168252,15863,168286,150218,36816,29327,22155,169191,169449,169392,169400,169778,170193,170313,170346,170435,170536,170766,171354,171419,32415,171768,171811,19620,38215,172691,29090,172799,19857,36882,173515,19868,134300,36798,21953,36794,140464,36793,150163,17673,32383,28502,27313,20202,13540,166700,161949,14138,36480,137205,163876,166764,166809,162366,157359,15851,161365,146615,153141,153942,20122,155265,156248,22207,134765,36366,23405,147080,150686,25566,25296,137206,137339,25904,22061,154698,21530,152337,15814,171416,19581,22050,22046,32585,155352,22901,146752,34672,19996,135146,134473,145082,33047,40286,36120,30267,40005,30286,30649,37701,21554,33096,33527,22053,33074,33816,32957,21994,31074,22083,21526,134813,13774,22021,22001,26353,164578,13869,30004,22000,21946,21655,21874,134209,134294,24272,151880,134774,142434,134818,40619,32090,21982,135285,25245,38765,21652,36045,29174,37238,25596,25529,25598,21865,142147,40050,143027,20890,13535,134567,20903,21581,21790,21779,30310,36397,157834,30129,32950,34820,34694,35015,33206,33820,135361,17644,29444,149254,23440,33547,157843,22139,141044,163119,147875,163187,159440,160438,37232,135641,37384,146684,173737,134828,134905,29286,138402,18254,151490,163833,135147,16634,40029,25887,142752,18675,149472,171388,135148,134666,24674,161187,135149,null,155720,135559,29091,32398,40272,19994,19972,13687,23309,27826,21351,13996,14812,21373,13989,149016,22682,150382,33325,21579,22442,154261,133497,null,14930,140389,29556,171692,19721,39917,146686,171824,19547,151465,169374,171998,33884,146870,160434,157619,145184,25390,32037,147191,146988,14890,36872,21196,15988,13946,17897,132238,30272,23280,134838,30842,163630,22695,16575,22140,39819,23924,30292,173108,40581,19681,30201,14331,24857,143578,148466,null,22109,135849,22439,149859,171526,21044,159918,13741,27722,40316,31830,39737,22494,137068,23635,25811,169168,156469,160100,34477,134440,159010,150242,134513,null,20990,139023,23950,38659,138705,40577,36940,31519,39682,23761,31651,25192,25397,39679,31695,39722,31870,39726,31810,31878,39957,31740,39689,40727,39963,149822,40794,21875,23491,20477,40600,20466,21088,15878,21201,22375,20566,22967,24082,38856,40363,36700,21609,38836,39232,38842,21292,24880,26924,21466,39946,40194,19515,38465,27008,20646,30022,137069,39386,21107,null,37209,38529,37212,null,37201,167575,25471,159011,27338,22033,37262,30074,25221,132092,29519,31856,154657,146685,null,149785,30422,39837,20010,134356,33726,34882,null,23626,27072,20717,22394,21023,24053,20174,27697,131570,20281,21660,21722,21146,36226,13822,24332,13811,null,27474,37244,40869,39831,38958,39092,39610,40616,40580,29050,31508,null,27642,34840,32632,null,22048,173642,36471,40787,null,36308,36431,40476,36353,25218,164733,36392,36469,31443,150135,31294,30936,27882,35431,30215,166490,40742,27854,34774,30147,172722,30803,194624,36108,29410,29553,35629,29442,29937,36075,150203,34351,24506,34976,17591,null,137275,159237,null,35454,140571,null,24829,30311,39639,40260,37742,39823,34805,null,34831,36087,29484,38689,39856,13782,29362,19463,31825,39242,155993,24921,19460,40598,24957,null,22367,24943,25254,25145,25294,14940,25058,21418,144373,25444,26626,13778,23895,166850,36826,167481,null,20697,138566,30982,21298,38456,134971,16485,null,30718,null,31938,155418,31962,31277,32870,32867,32077,29957,29938,35220,33306,26380,32866,160902,32859,29936,33027,30500,35209,157644,30035,159441,34729,34766,33224,34700,35401,36013,35651,30507,29944,34010,13877,27058,36262,null,35241,29800,28089,34753,147473,29927,15835,29046,24740,24988,15569,29026,24695,null,32625,166701,29264,24809,19326,21024,15384,146631,155351,161366,152881,137540,135934,170243,159196,159917,23745,156077,166415,145015,131310,157766,151310,17762,23327,156492,40784,40614,156267,12288,65292,12289,12290,65294,8231,65307,65306,65311,65281,65072,8230,8229,65104,65105,65106,183,65108,65109,65110,65111,65372,8211,65073,8212,65075,9588,65076,65103,65288,65289,65077,65078,65371,65373,65079,65080,12308,12309,65081,65082,12304,12305,65083,65084,12298,12299,65085,65086,12296,12297,65087,65088,12300,12301,65089,65090,12302,12303,65091,65092,65113,65114,65115,65116,65117,65118,8216,8217,8220,8221,12317,12318,8245,8242,65283,65286,65290,8251,167,12291,9675,9679,9651,9650,9678,9734,9733,9671,9670,9633,9632,9661,9660,12963,8453,175,65507,65343,717,65097,65098,65101,65102,65099,65100,65119,65120,65121,65291,65293,215,247,177,8730,65308,65310,65309,8806,8807,8800,8734,8786,8801,65122,65123,65124,65125,65126,65374,8745,8746,8869,8736,8735,8895,13266,13265,8747,8750,8757,8756,9792,9794,8853,8857,8593,8595,8592,8594,8598,8599,8601,8600,8741,8739,65295,65340,8725,65128,65284,65509,12306,65504,65505,65285,65312,8451,8457,65129,65130,65131,13269,13212,13213,13214,13262,13217,13198,13199,13252,176,20825,20827,20830,20829,20833,20835,21991,29929,31950,9601,9602,9603,9604,9605,9606,9607,9608,9615,9614,9613,9612,9611,9610,9609,9532,9524,9516,9508,9500,9620,9472,9474,9621,9484,9488,9492,9496,9581,9582,9584,9583,9552,9566,9578,9569,9698,9699,9701,9700,9585,9586,9587,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,12321,12322,12323,12324,12325,12326,12327,12328,12329,21313,21316,21317,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,964,965,966,967,968,969,12549,12550,12551,12552,12553,12554,12555,12556,12557,12558,12559,12560,12561,12562,12563,12564,12565,12566,12567,12568,12569,12570,12571,12572,12573,12574,12575,12576,12577,12578,12579,12580,12581,12582,12583,12584,12585,729,713,714,711,715,9216,9217,9218,9219,9220,9221,9222,9223,9224,9225,9226,9227,9228,9229,9230,9231,9232,9233,9234,9235,9236,9237,9238,9239,9240,9241,9242,9243,9244,9245,9246,9247,9249,8364,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,19968,20057,19969,19971,20035,20061,20102,20108,20154,20799,20837,20843,20960,20992,20993,21147,21269,21313,21340,21448,19977,19979,19976,19978,20011,20024,20961,20037,20040,20063,20062,20110,20129,20800,20995,21242,21315,21449,21475,22303,22763,22805,22823,22899,23376,23377,23379,23544,23567,23586,23608,23665,24029,24037,24049,24050,24051,24062,24178,24318,24331,24339,25165,19985,19984,19981,20013,20016,20025,20043,23609,20104,20113,20117,20114,20116,20130,20161,20160,20163,20166,20167,20173,20170,20171,20164,20803,20801,20839,20845,20846,20844,20887,20982,20998,20999,21000,21243,21246,21247,21270,21305,21320,21319,21317,21342,21380,21451,21450,21453,22764,22825,22827,22826,22829,23380,23569,23588,23610,23663,24052,24187,24319,24340,24341,24515,25096,25142,25163,25166,25903,25991,26007,26020,26041,26085,26352,26376,26408,27424,27490,27513,27595,27604,27611,27663,27700,28779,29226,29238,29243,29255,29273,29275,29356,29579,19993,19990,19989,19988,19992,20027,20045,20047,20046,20197,20184,20180,20181,20182,20183,20195,20196,20185,20190,20805,20804,20873,20874,20908,20985,20986,20984,21002,21152,21151,21253,21254,21271,21277,20191,21322,21321,21345,21344,21359,21358,21435,21487,21476,21491,21484,21486,21481,21480,21500,21496,21493,21483,21478,21482,21490,21489,21488,21477,21485,21499,22235,22234,22806,22830,22833,22900,22902,23381,23427,23612,24040,24039,24038,24066,24067,24179,24188,24321,24344,24343,24517,25098,25171,25172,25170,25169,26021,26086,26414,26412,26410,26411,26413,27491,27597,27665,27664,27704,27713,27712,27710,29359,29572,29577,29916,29926,29976,29983,29992,29993,30000,30001,30002,30003,30091,30333,30382,30399,30446,30683,30690,30707,31034,31166,31348,31435,19998,19999,20050,20051,20073,20121,20132,20134,20133,20223,20233,20249,20234,20245,20237,20240,20241,20239,20210,20214,20219,20208,20211,20221,20225,20235,20809,20807,20806,20808,20840,20849,20877,20912,21015,21009,21010,21006,21014,21155,21256,21281,21280,21360,21361,21513,21519,21516,21514,21520,21505,21515,21508,21521,21517,21512,21507,21518,21510,21522,22240,22238,22237,22323,22320,22312,22317,22316,22319,22313,22809,22810,22839,22840,22916,22904,22915,22909,22905,22914,22913,23383,23384,23431,23432,23429,23433,23546,23574,23673,24030,24070,24182,24180,24335,24347,24537,24534,25102,25100,25101,25104,25187,25179,25176,25910,26089,26088,26092,26093,26354,26355,26377,26429,26420,26417,26421,27425,27492,27515,27670,27741,27735,27737,27743,27744,27728,27733,27745,27739,27725,27726,28784,29279,29277,30334,31481,31859,31992,32566,32650,32701,32769,32771,32780,32786,32819,32895,32905,32907,32908,33251,33258,33267,33276,33292,33307,33311,33390,33394,33406,34411,34880,34892,34915,35199,38433,20018,20136,20301,20303,20295,20311,20318,20276,20315,20309,20272,20304,20305,20285,20282,20280,20291,20308,20284,20294,20323,20316,20320,20271,20302,20278,20313,20317,20296,20314,20812,20811,20813,20853,20918,20919,21029,21028,21033,21034,21032,21163,21161,21162,21164,21283,21363,21365,21533,21549,21534,21566,21542,21582,21543,21574,21571,21555,21576,21570,21531,21545,21578,21561,21563,21560,21550,21557,21558,21536,21564,21568,21553,21547,21535,21548,22250,22256,22244,22251,22346,22353,22336,22349,22343,22350,22334,22352,22351,22331,22767,22846,22941,22930,22952,22942,22947,22937,22934,22925,22948,22931,22922,22949,23389,23388,23386,23387,23436,23435,23439,23596,23616,23617,23615,23614,23696,23697,23700,23692,24043,24076,24207,24199,24202,24311,24324,24351,24420,24418,24439,24441,24536,24524,24535,24525,24561,24555,24568,24554,25106,25105,25220,25239,25238,25216,25206,25225,25197,25226,25212,25214,25209,25203,25234,25199,25240,25198,25237,25235,25233,25222,25913,25915,25912,26097,26356,26463,26446,26447,26448,26449,26460,26454,26462,26441,26438,26464,26451,26455,27493,27599,27714,27742,27801,27777,27784,27785,27781,27803,27754,27770,27792,27760,27788,27752,27798,27794,27773,27779,27762,27774,27764,27782,27766,27789,27796,27800,27778,28790,28796,28797,28792,29282,29281,29280,29380,29378,29590,29996,29995,30007,30008,30338,30447,30691,31169,31168,31167,31350,31995,32597,32918,32915,32925,32920,32923,32922,32946,33391,33426,33419,33421,35211,35282,35328,35895,35910,35925,35997,36196,36208,36275,36523,36554,36763,36784,36802,36806,36805,36804,24033,37009,37026,37034,37030,37027,37193,37318,37324,38450,38446,38449,38442,38444,20006,20054,20083,20107,20123,20126,20139,20140,20335,20381,20365,20339,20351,20332,20379,20363,20358,20355,20336,20341,20360,20329,20347,20374,20350,20367,20369,20346,20820,20818,20821,20841,20855,20854,20856,20925,20989,21051,21048,21047,21050,21040,21038,21046,21057,21182,21179,21330,21332,21331,21329,21350,21367,21368,21369,21462,21460,21463,21619,21621,21654,21624,21653,21632,21627,21623,21636,21650,21638,21628,21648,21617,21622,21644,21658,21602,21608,21643,21629,21646,22266,22403,22391,22378,22377,22369,22374,22372,22396,22812,22857,22855,22856,22852,22868,22974,22971,22996,22969,22958,22993,22982,22992,22989,22987,22995,22986,22959,22963,22994,22981,23391,23396,23395,23447,23450,23448,23452,23449,23451,23578,23624,23621,23622,23735,23713,23736,23721,23723,23729,23731,24088,24090,24086,24085,24091,24081,24184,24218,24215,24220,24213,24214,24310,24358,24359,24361,24448,24449,24447,24444,24541,24544,24573,24565,24575,24591,24596,24623,24629,24598,24618,24597,24609,24615,24617,24619,24603,25110,25109,25151,25150,25152,25215,25289,25292,25284,25279,25282,25273,25298,25307,25259,25299,25300,25291,25288,25256,25277,25276,25296,25305,25287,25293,25269,25306,25265,25304,25302,25303,25286,25260,25294,25918,26023,26044,26106,26132,26131,26124,26118,26114,26126,26112,26127,26133,26122,26119,26381,26379,26477,26507,26517,26481,26524,26483,26487,26503,26525,26519,26479,26480,26495,26505,26494,26512,26485,26522,26515,26492,26474,26482,27427,27494,27495,27519,27667,27675,27875,27880,27891,27825,27852,27877,27827,27837,27838,27836,27874,27819,27861,27859,27832,27844,27833,27841,27822,27863,27845,27889,27839,27835,27873,27867,27850,27820,27887,27868,27862,27872,28821,28814,28818,28810,28825,29228,29229,29240,29256,29287,29289,29376,29390,29401,29399,29392,29609,29608,29599,29611,29605,30013,30109,30105,30106,30340,30402,30450,30452,30693,30717,31038,31040,31041,31177,31176,31354,31353,31482,31998,32596,32652,32651,32773,32954,32933,32930,32945,32929,32939,32937,32948,32938,32943,33253,33278,33293,33459,33437,33433,33453,33469,33439,33465,33457,33452,33445,33455,33464,33443,33456,33470,33463,34382,34417,21021,34920,36555,36814,36820,36817,37045,37048,37041,37046,37319,37329,38263,38272,38428,38464,38463,38459,38468,38466,38585,38632,38738,38750,20127,20141,20142,20449,20405,20399,20415,20448,20433,20431,20445,20419,20406,20440,20447,20426,20439,20398,20432,20420,20418,20442,20430,20446,20407,20823,20882,20881,20896,21070,21059,21066,21069,21068,21067,21063,21191,21193,21187,21185,21261,21335,21371,21402,21467,21676,21696,21672,21710,21705,21688,21670,21683,21703,21698,21693,21674,21697,21700,21704,21679,21675,21681,21691,21673,21671,21695,22271,22402,22411,22432,22435,22434,22478,22446,22419,22869,22865,22863,22862,22864,23004,23000,23039,23011,23016,23043,23013,23018,23002,23014,23041,23035,23401,23459,23462,23460,23458,23461,23553,23630,23631,23629,23627,23769,23762,24055,24093,24101,24095,24189,24224,24230,24314,24328,24365,24421,24456,24453,24458,24459,24455,24460,24457,24594,24605,24608,24613,24590,24616,24653,24688,24680,24674,24646,24643,24684,24683,24682,24676,25153,25308,25366,25353,25340,25325,25345,25326,25341,25351,25329,25335,25327,25324,25342,25332,25361,25346,25919,25925,26027,26045,26082,26149,26157,26144,26151,26159,26143,26152,26161,26148,26359,26623,26579,26609,26580,26576,26604,26550,26543,26613,26601,26607,26564,26577,26548,26586,26597,26552,26575,26590,26611,26544,26585,26594,26589,26578,27498,27523,27526,27573,27602,27607,27679,27849,27915,27954,27946,27969,27941,27916,27953,27934,27927,27963,27965,27966,27958,27931,27893,27961,27943,27960,27945,27950,27957,27918,27947,28843,28858,28851,28844,28847,28845,28856,28846,28836,29232,29298,29295,29300,29417,29408,29409,29623,29642,29627,29618,29645,29632,29619,29978,29997,30031,30028,30030,30027,30123,30116,30117,30114,30115,30328,30342,30343,30344,30408,30406,30403,30405,30465,30457,30456,30473,30475,30462,30460,30471,30684,30722,30740,30732,30733,31046,31049,31048,31047,31161,31162,31185,31186,31179,31359,31361,31487,31485,31869,32002,32005,32000,32009,32007,32004,32006,32568,32654,32703,32772,32784,32781,32785,32822,32982,32997,32986,32963,32964,32972,32993,32987,32974,32990,32996,32989,33268,33314,33511,33539,33541,33507,33499,33510,33540,33509,33538,33545,33490,33495,33521,33537,33500,33492,33489,33502,33491,33503,33519,33542,34384,34425,34427,34426,34893,34923,35201,35284,35336,35330,35331,35998,36000,36212,36211,36276,36557,36556,36848,36838,36834,36842,36837,36845,36843,36836,36840,37066,37070,37057,37059,37195,37194,37325,38274,38480,38475,38476,38477,38754,38761,38859,38893,38899,38913,39080,39131,39135,39318,39321,20056,20147,20492,20493,20515,20463,20518,20517,20472,20521,20502,20486,20540,20511,20506,20498,20497,20474,20480,20500,20520,20465,20513,20491,20505,20504,20467,20462,20525,20522,20478,20523,20489,20860,20900,20901,20898,20941,20940,20934,20939,21078,21084,21076,21083,21085,21290,21375,21407,21405,21471,21736,21776,21761,21815,21756,21733,21746,21766,21754,21780,21737,21741,21729,21769,21742,21738,21734,21799,21767,21757,21775,22275,22276,22466,22484,22475,22467,22537,22799,22871,22872,22874,23057,23064,23068,23071,23067,23059,23020,23072,23075,23081,23077,23052,23049,23403,23640,23472,23475,23478,23476,23470,23477,23481,23480,23556,23633,23637,23632,23789,23805,23803,23786,23784,23792,23798,23809,23796,24046,24109,24107,24235,24237,24231,24369,24466,24465,24464,24665,24675,24677,24656,24661,24685,24681,24687,24708,24735,24730,24717,24724,24716,24709,24726,25159,25331,25352,25343,25422,25406,25391,25429,25410,25414,25423,25417,25402,25424,25405,25386,25387,25384,25421,25420,25928,25929,26009,26049,26053,26178,26185,26191,26179,26194,26188,26181,26177,26360,26388,26389,26391,26657,26680,26696,26694,26707,26681,26690,26708,26665,26803,26647,26700,26705,26685,26612,26704,26688,26684,26691,26666,26693,26643,26648,26689,27530,27529,27575,27683,27687,27688,27686,27684,27888,28010,28053,28040,28039,28006,28024,28023,27993,28051,28012,28041,28014,27994,28020,28009,28044,28042,28025,28037,28005,28052,28874,28888,28900,28889,28872,28879,29241,29305,29436,29433,29437,29432,29431,29574,29677,29705,29678,29664,29674,29662,30036,30045,30044,30042,30041,30142,30149,30151,30130,30131,30141,30140,30137,30146,30136,30347,30384,30410,30413,30414,30505,30495,30496,30504,30697,30768,30759,30776,30749,30772,30775,30757,30765,30752,30751,30770,31061,31056,31072,31071,31062,31070,31069,31063,31066,31204,31203,31207,31199,31206,31209,31192,31364,31368,31449,31494,31505,31881,32033,32023,32011,32010,32032,32034,32020,32016,32021,32026,32028,32013,32025,32027,32570,32607,32660,32709,32705,32774,32792,32789,32793,32791,32829,32831,33009,33026,33008,33029,33005,33012,33030,33016,33011,33032,33021,33034,33020,33007,33261,33260,33280,33296,33322,33323,33320,33324,33467,33579,33618,33620,33610,33592,33616,33609,33589,33588,33615,33586,33593,33590,33559,33600,33585,33576,33603,34388,34442,34474,34451,34468,34473,34444,34467,34460,34928,34935,34945,34946,34941,34937,35352,35344,35342,35340,35349,35338,35351,35347,35350,35343,35345,35912,35962,35961,36001,36002,36215,36524,36562,36564,36559,36785,36865,36870,36855,36864,36858,36852,36867,36861,36869,36856,37013,37089,37085,37090,37202,37197,37196,37336,37341,37335,37340,37337,38275,38498,38499,38497,38491,38493,38500,38488,38494,38587,39138,39340,39592,39640,39717,39730,39740,20094,20602,20605,20572,20551,20547,20556,20570,20553,20581,20598,20558,20565,20597,20596,20599,20559,20495,20591,20589,20828,20885,20976,21098,21103,21202,21209,21208,21205,21264,21263,21273,21311,21312,21310,21443,26364,21830,21866,21862,21828,21854,21857,21827,21834,21809,21846,21839,21845,21807,21860,21816,21806,21852,21804,21859,21811,21825,21847,22280,22283,22281,22495,22533,22538,22534,22496,22500,22522,22530,22581,22519,22521,22816,22882,23094,23105,23113,23142,23146,23104,23100,23138,23130,23110,23114,23408,23495,23493,23492,23490,23487,23494,23561,23560,23559,23648,23644,23645,23815,23814,23822,23835,23830,23842,23825,23849,23828,23833,23844,23847,23831,24034,24120,24118,24115,24119,24247,24248,24246,24245,24254,24373,24375,24407,24428,24425,24427,24471,24473,24478,24472,24481,24480,24476,24703,24739,24713,24736,24744,24779,24756,24806,24765,24773,24763,24757,24796,24764,24792,24789,24774,24799,24760,24794,24775,25114,25115,25160,25504,25511,25458,25494,25506,25509,25463,25447,25496,25514,25457,25513,25481,25475,25499,25451,25512,25476,25480,25497,25505,25516,25490,25487,25472,25467,25449,25448,25466,25949,25942,25937,25945,25943,21855,25935,25944,25941,25940,26012,26011,26028,26063,26059,26060,26062,26205,26202,26212,26216,26214,26206,26361,21207,26395,26753,26799,26786,26771,26805,26751,26742,26801,26791,26775,26800,26755,26820,26797,26758,26757,26772,26781,26792,26783,26785,26754,27442,27578,27627,27628,27691,28046,28092,28147,28121,28082,28129,28108,28132,28155,28154,28165,28103,28107,28079,28113,28078,28126,28153,28088,28151,28149,28101,28114,28186,28085,28122,28139,28120,28138,28145,28142,28136,28102,28100,28074,28140,28095,28134,28921,28937,28938,28925,28911,29245,29309,29313,29468,29467,29462,29459,29465,29575,29701,29706,29699,29702,29694,29709,29920,29942,29943,29980,29986,30053,30054,30050,30064,30095,30164,30165,30133,30154,30157,30350,30420,30418,30427,30519,30526,30524,30518,30520,30522,30827,30787,30798,31077,31080,31085,31227,31378,31381,31520,31528,31515,31532,31526,31513,31518,31534,31890,31895,31893,32070,32067,32113,32046,32057,32060,32064,32048,32051,32068,32047,32066,32050,32049,32573,32670,32666,32716,32718,32722,32796,32842,32838,33071,33046,33059,33067,33065,33072,33060,33282,33333,33335,33334,33337,33678,33694,33688,33656,33698,33686,33725,33707,33682,33674,33683,33673,33696,33655,33659,33660,33670,33703,34389,24426,34503,34496,34486,34500,34485,34502,34507,34481,34479,34505,34899,34974,34952,34987,34962,34966,34957,34955,35219,35215,35370,35357,35363,35365,35377,35373,35359,35355,35362,35913,35930,36009,36012,36011,36008,36010,36007,36199,36198,36286,36282,36571,36575,36889,36877,36890,36887,36899,36895,36893,36880,36885,36894,36896,36879,36898,36886,36891,36884,37096,37101,37117,37207,37326,37365,37350,37347,37351,37357,37353,38281,38506,38517,38515,38520,38512,38516,38518,38519,38508,38592,38634,38633,31456,31455,38914,38915,39770,40165,40565,40575,40613,40635,20642,20621,20613,20633,20625,20608,20630,20632,20634,26368,20977,21106,21108,21109,21097,21214,21213,21211,21338,21413,21883,21888,21927,21884,21898,21917,21912,21890,21916,21930,21908,21895,21899,21891,21939,21934,21919,21822,21938,21914,21947,21932,21937,21886,21897,21931,21913,22285,22575,22570,22580,22564,22576,22577,22561,22557,22560,22777,22778,22880,23159,23194,23167,23186,23195,23207,23411,23409,23506,23500,23507,23504,23562,23563,23601,23884,23888,23860,23879,24061,24133,24125,24128,24131,24190,24266,24257,24258,24260,24380,24429,24489,24490,24488,24785,24801,24754,24758,24800,24860,24867,24826,24853,24816,24827,24820,24936,24817,24846,24822,24841,24832,24850,25119,25161,25507,25484,25551,25536,25577,25545,25542,25549,25554,25571,25552,25569,25558,25581,25582,25462,25588,25578,25563,25682,25562,25593,25950,25958,25954,25955,26001,26000,26031,26222,26224,26228,26230,26223,26257,26234,26238,26231,26366,26367,26399,26397,26874,26837,26848,26840,26839,26885,26847,26869,26862,26855,26873,26834,26866,26851,26827,26829,26893,26898,26894,26825,26842,26990,26875,27454,27450,27453,27544,27542,27580,27631,27694,27695,27692,28207,28216,28244,28193,28210,28263,28234,28192,28197,28195,28187,28251,28248,28196,28246,28270,28205,28198,28271,28212,28237,28218,28204,28227,28189,28222,28363,28297,28185,28238,28259,28228,28274,28265,28255,28953,28954,28966,28976,28961,28982,29038,28956,29260,29316,29312,29494,29477,29492,29481,29754,29738,29747,29730,29733,29749,29750,29748,29743,29723,29734,29736,29989,29990,30059,30058,30178,30171,30179,30169,30168,30174,30176,30331,30332,30358,30355,30388,30428,30543,30701,30813,30828,30831,31245,31240,31243,31237,31232,31384,31383,31382,31461,31459,31561,31574,31558,31568,31570,31572,31565,31563,31567,31569,31903,31909,32094,32080,32104,32085,32043,32110,32114,32097,32102,32098,32112,32115,21892,32724,32725,32779,32850,32901,33109,33108,33099,33105,33102,33081,33094,33086,33100,33107,33140,33298,33308,33769,33795,33784,33805,33760,33733,33803,33729,33775,33777,33780,33879,33802,33776,33804,33740,33789,33778,33738,33848,33806,33796,33756,33799,33748,33759,34395,34527,34521,34541,34516,34523,34532,34512,34526,34903,35009,35010,34993,35203,35222,35387,35424,35413,35422,35388,35393,35412,35419,35408,35398,35380,35386,35382,35414,35937,35970,36015,36028,36019,36029,36033,36027,36032,36020,36023,36022,36031,36024,36234,36229,36225,36302,36317,36299,36314,36305,36300,36315,36294,36603,36600,36604,36764,36910,36917,36913,36920,36914,36918,37122,37109,37129,37118,37219,37221,37327,37396,37397,37411,37385,37406,37389,37392,37383,37393,38292,38287,38283,38289,38291,38290,38286,38538,38542,38539,38525,38533,38534,38541,38514,38532,38593,38597,38596,38598,38599,38639,38642,38860,38917,38918,38920,39143,39146,39151,39145,39154,39149,39342,39341,40643,40653,40657,20098,20653,20661,20658,20659,20677,20670,20652,20663,20667,20655,20679,21119,21111,21117,21215,21222,21220,21218,21219,21295,21983,21992,21971,21990,21966,21980,21959,21969,21987,21988,21999,21978,21985,21957,21958,21989,21961,22290,22291,22622,22609,22616,22615,22618,22612,22635,22604,22637,22602,22626,22610,22603,22887,23233,23241,23244,23230,23229,23228,23219,23234,23218,23913,23919,24140,24185,24265,24264,24338,24409,24492,24494,24858,24847,24904,24863,24819,24859,24825,24833,24840,24910,24908,24900,24909,24894,24884,24871,24845,24838,24887,25121,25122,25619,25662,25630,25642,25645,25661,25644,25615,25628,25620,25613,25654,25622,25623,25606,25964,26015,26032,26263,26249,26247,26248,26262,26244,26264,26253,26371,27028,26989,26970,26999,26976,26964,26997,26928,27010,26954,26984,26987,26974,26963,27001,27014,26973,26979,26971,27463,27506,27584,27583,27603,27645,28322,28335,28371,28342,28354,28304,28317,28359,28357,28325,28312,28348,28346,28331,28369,28310,28316,28356,28372,28330,28327,28340,29006,29017,29033,29028,29001,29031,29020,29036,29030,29004,29029,29022,28998,29032,29014,29242,29266,29495,29509,29503,29502,29807,29786,29781,29791,29790,29761,29759,29785,29787,29788,30070,30072,30208,30192,30209,30194,30193,30202,30207,30196,30195,30430,30431,30555,30571,30566,30558,30563,30585,30570,30572,30556,30565,30568,30562,30702,30862,30896,30871,30872,30860,30857,30844,30865,30867,30847,31098,31103,31105,33836,31165,31260,31258,31264,31252,31263,31262,31391,31392,31607,31680,31584,31598,31591,31921,31923,31925,32147,32121,32145,32129,32143,32091,32622,32617,32618,32626,32681,32680,32676,32854,32856,32902,32900,33137,33136,33144,33125,33134,33139,33131,33145,33146,33126,33285,33351,33922,33911,33853,33841,33909,33894,33899,33865,33900,33883,33852,33845,33889,33891,33897,33901,33862,34398,34396,34399,34553,34579,34568,34567,34560,34558,34555,34562,34563,34566,34570,34905,35039,35028,35033,35036,35032,35037,35041,35018,35029,35026,35228,35299,35435,35442,35443,35430,35433,35440,35463,35452,35427,35488,35441,35461,35437,35426,35438,35436,35449,35451,35390,35432,35938,35978,35977,36042,36039,36040,36036,36018,36035,36034,36037,36321,36319,36328,36335,36339,36346,36330,36324,36326,36530,36611,36617,36606,36618,36767,36786,36939,36938,36947,36930,36948,36924,36949,36944,36935,36943,36942,36941,36945,36926,36929,37138,37143,37228,37226,37225,37321,37431,37463,37432,37437,37440,37438,37467,37451,37476,37457,37428,37449,37453,37445,37433,37439,37466,38296,38552,38548,38549,38605,38603,38601,38602,38647,38651,38649,38646,38742,38772,38774,38928,38929,38931,38922,38930,38924,39164,39156,39165,39166,39347,39345,39348,39649,40169,40578,40718,40723,40736,20711,20718,20709,20694,20717,20698,20693,20687,20689,20721,20686,20713,20834,20979,21123,21122,21297,21421,22014,22016,22043,22039,22013,22036,22022,22025,22029,22030,22007,22038,22047,22024,22032,22006,22296,22294,22645,22654,22659,22675,22666,22649,22661,22653,22781,22821,22818,22820,22890,22889,23265,23270,23273,23255,23254,23256,23267,23413,23518,23527,23521,23525,23526,23528,23522,23524,23519,23565,23650,23940,23943,24155,24163,24149,24151,24148,24275,24278,24330,24390,24432,24505,24903,24895,24907,24951,24930,24931,24927,24922,24920,24949,25130,25735,25688,25684,25764,25720,25695,25722,25681,25703,25652,25709,25723,25970,26017,26071,26070,26274,26280,26269,27036,27048,27029,27073,27054,27091,27083,27035,27063,27067,27051,27060,27088,27085,27053,27084,27046,27075,27043,27465,27468,27699,28467,28436,28414,28435,28404,28457,28478,28448,28460,28431,28418,28450,28415,28399,28422,28465,28472,28466,28451,28437,28459,28463,28552,28458,28396,28417,28402,28364,28407,29076,29081,29053,29066,29060,29074,29246,29330,29334,29508,29520,29796,29795,29802,29808,29805,29956,30097,30247,30221,30219,30217,30227,30433,30435,30596,30589,30591,30561,30913,30879,30887,30899,30889,30883,31118,31119,31117,31278,31281,31402,31401,31469,31471,31649,31637,31627,31605,31639,31645,31636,31631,31672,31623,31620,31929,31933,31934,32187,32176,32156,32189,32190,32160,32202,32180,32178,32177,32186,32162,32191,32181,32184,32173,32210,32199,32172,32624,32736,32737,32735,32862,32858,32903,33104,33152,33167,33160,33162,33151,33154,33255,33274,33287,33300,33310,33355,33993,33983,33990,33988,33945,33950,33970,33948,33995,33976,33984,34003,33936,33980,34001,33994,34623,34588,34619,34594,34597,34612,34584,34645,34615,34601,35059,35074,35060,35065,35064,35069,35048,35098,35055,35494,35468,35486,35491,35469,35489,35475,35492,35498,35493,35496,35480,35473,35482,35495,35946,35981,35980,36051,36049,36050,36203,36249,36245,36348,36628,36626,36629,36627,36771,36960,36952,36956,36963,36953,36958,36962,36957,36955,37145,37144,37150,37237,37240,37239,37236,37496,37504,37509,37528,37526,37499,37523,37532,37544,37500,37521,38305,38312,38313,38307,38309,38308,38553,38556,38555,38604,38610,38656,38780,38789,38902,38935,38936,39087,39089,39171,39173,39180,39177,39361,39599,39600,39654,39745,39746,40180,40182,40179,40636,40763,40778,20740,20736,20731,20725,20729,20738,20744,20745,20741,20956,21127,21128,21129,21133,21130,21232,21426,22062,22075,22073,22066,22079,22068,22057,22099,22094,22103,22132,22070,22063,22064,22656,22687,22686,22707,22684,22702,22697,22694,22893,23305,23291,23307,23285,23308,23304,23534,23532,23529,23531,23652,23653,23965,23956,24162,24159,24161,24290,24282,24287,24285,24291,24288,24392,24433,24503,24501,24950,24935,24942,24925,24917,24962,24956,24944,24939,24958,24999,24976,25003,24974,25004,24986,24996,24980,25006,25134,25705,25711,25721,25758,25778,25736,25744,25776,25765,25747,25749,25769,25746,25774,25773,25771,25754,25772,25753,25762,25779,25973,25975,25976,26286,26283,26292,26289,27171,27167,27112,27137,27166,27161,27133,27169,27155,27146,27123,27138,27141,27117,27153,27472,27470,27556,27589,27590,28479,28540,28548,28497,28518,28500,28550,28525,28507,28536,28526,28558,28538,28528,28516,28567,28504,28373,28527,28512,28511,29087,29100,29105,29096,29270,29339,29518,29527,29801,29835,29827,29822,29824,30079,30240,30249,30239,30244,30246,30241,30242,30362,30394,30436,30606,30599,30604,30609,30603,30923,30917,30906,30922,30910,30933,30908,30928,31295,31292,31296,31293,31287,31291,31407,31406,31661,31665,31684,31668,31686,31687,31681,31648,31692,31946,32224,32244,32239,32251,32216,32236,32221,32232,32227,32218,32222,32233,32158,32217,32242,32249,32629,32631,32687,32745,32806,33179,33180,33181,33184,33178,33176,34071,34109,34074,34030,34092,34093,34067,34065,34083,34081,34068,34028,34085,34047,34054,34690,34676,34678,34656,34662,34680,34664,34649,34647,34636,34643,34907,34909,35088,35079,35090,35091,35093,35082,35516,35538,35527,35524,35477,35531,35576,35506,35529,35522,35519,35504,35542,35533,35510,35513,35547,35916,35918,35948,36064,36062,36070,36068,36076,36077,36066,36067,36060,36074,36065,36205,36255,36259,36395,36368,36381,36386,36367,36393,36383,36385,36382,36538,36637,36635,36639,36649,36646,36650,36636,36638,36645,36969,36974,36968,36973,36983,37168,37165,37159,37169,37255,37257,37259,37251,37573,37563,37559,37610,37548,37604,37569,37555,37564,37586,37575,37616,37554,38317,38321,38660,38662,38663,38665,38752,38797,38795,38799,38945,38955,38940,39091,39178,39187,39186,39192,39389,39376,39391,39387,39377,39381,39378,39385,39607,39662,39663,39719,39749,39748,39799,39791,40198,40201,40195,40617,40638,40654,22696,40786,20754,20760,20756,20752,20757,20864,20906,20957,21137,21139,21235,22105,22123,22137,22121,22116,22136,22122,22120,22117,22129,22127,22124,22114,22134,22721,22718,22727,22725,22894,23325,23348,23416,23536,23566,24394,25010,24977,25001,24970,25037,25014,25022,25034,25032,25136,25797,25793,25803,25787,25788,25818,25796,25799,25794,25805,25791,25810,25812,25790,25972,26310,26313,26297,26308,26311,26296,27197,27192,27194,27225,27243,27224,27193,27204,27234,27233,27211,27207,27189,27231,27208,27481,27511,27653,28610,28593,28577,28611,28580,28609,28583,28595,28608,28601,28598,28582,28576,28596,29118,29129,29136,29138,29128,29141,29113,29134,29145,29148,29123,29124,29544,29852,29859,29848,29855,29854,29922,29964,29965,30260,30264,30266,30439,30437,30624,30622,30623,30629,30952,30938,30956,30951,31142,31309,31310,31302,31308,31307,31418,31705,31761,31689,31716,31707,31713,31721,31718,31957,31958,32266,32273,32264,32283,32291,32286,32285,32265,32272,32633,32690,32752,32753,32750,32808,33203,33193,33192,33275,33288,33368,33369,34122,34137,34120,34152,34153,34115,34121,34157,34154,34142,34691,34719,34718,34722,34701,34913,35114,35122,35109,35115,35105,35242,35238,35558,35578,35563,35569,35584,35548,35559,35566,35582,35585,35586,35575,35565,35571,35574,35580,35947,35949,35987,36084,36420,36401,36404,36418,36409,36405,36667,36655,36664,36659,36776,36774,36981,36980,36984,36978,36988,36986,37172,37266,37664,37686,37624,37683,37679,37666,37628,37675,37636,37658,37648,37670,37665,37653,37678,37657,38331,38567,38568,38570,38613,38670,38673,38678,38669,38675,38671,38747,38748,38758,38808,38960,38968,38971,38967,38957,38969,38948,39184,39208,39198,39195,39201,39194,39405,39394,39409,39608,39612,39675,39661,39720,39825,40213,40227,40230,40232,40210,40219,40664,40660,40845,40860,20778,20767,20769,20786,21237,22158,22144,22160,22149,22151,22159,22741,22739,22737,22734,23344,23338,23332,23418,23607,23656,23996,23994,23997,23992,24171,24396,24509,25033,25026,25031,25062,25035,25138,25140,25806,25802,25816,25824,25840,25830,25836,25841,25826,25837,25986,25987,26329,26326,27264,27284,27268,27298,27292,27355,27299,27262,27287,27280,27296,27484,27566,27610,27656,28632,28657,28639,28640,28635,28644,28651,28655,28544,28652,28641,28649,28629,28654,28656,29159,29151,29166,29158,29157,29165,29164,29172,29152,29237,29254,29552,29554,29865,29872,29862,29864,30278,30274,30284,30442,30643,30634,30640,30636,30631,30637,30703,30967,30970,30964,30959,30977,31143,31146,31319,31423,31751,31757,31742,31735,31756,31712,31968,31964,31966,31970,31967,31961,31965,32302,32318,32326,32311,32306,32323,32299,32317,32305,32325,32321,32308,32313,32328,32309,32319,32303,32580,32755,32764,32881,32882,32880,32879,32883,33222,33219,33210,33218,33216,33215,33213,33225,33214,33256,33289,33393,34218,34180,34174,34204,34193,34196,34223,34203,34183,34216,34186,34407,34752,34769,34739,34770,34758,34731,34747,34746,34760,34763,35131,35126,35140,35128,35133,35244,35598,35607,35609,35611,35594,35616,35613,35588,35600,35905,35903,35955,36090,36093,36092,36088,36091,36264,36425,36427,36424,36426,36676,36670,36674,36677,36671,36991,36989,36996,36993,36994,36992,37177,37283,37278,37276,37709,37762,37672,37749,37706,37733,37707,37656,37758,37740,37723,37744,37722,37716,38346,38347,38348,38344,38342,38577,38584,38614,38684,38686,38816,38867,38982,39094,39221,39425,39423,39854,39851,39850,39853,40251,40255,40587,40655,40670,40668,40669,40667,40766,40779,21474,22165,22190,22745,22744,23352,24413,25059,25139,25844,25842,25854,25862,25850,25851,25847,26039,26332,26406,27315,27308,27331,27323,27320,27330,27310,27311,27487,27512,27567,28681,28683,28670,28678,28666,28689,28687,29179,29180,29182,29176,29559,29557,29863,29887,29973,30294,30296,30290,30653,30655,30651,30652,30990,31150,31329,31330,31328,31428,31429,31787,31783,31786,31774,31779,31777,31975,32340,32341,32350,32346,32353,32338,32345,32584,32761,32763,32887,32886,33229,33231,33290,34255,34217,34253,34256,34249,34224,34234,34233,34214,34799,34796,34802,34784,35206,35250,35316,35624,35641,35628,35627,35920,36101,36441,36451,36454,36452,36447,36437,36544,36681,36685,36999,36995,37000,37291,37292,37328,37780,37770,37782,37794,37811,37806,37804,37808,37784,37786,37783,38356,38358,38352,38357,38626,38620,38617,38619,38622,38692,38819,38822,38829,38905,38989,38991,38988,38990,38995,39098,39230,39231,39229,39214,39333,39438,39617,39683,39686,39759,39758,39757,39882,39881,39933,39880,39872,40273,40285,40288,40672,40725,40748,20787,22181,22750,22751,22754,23541,40848,24300,25074,25079,25078,25077,25856,25871,26336,26333,27365,27357,27354,27347,28699,28703,28712,28698,28701,28693,28696,29190,29197,29272,29346,29560,29562,29885,29898,29923,30087,30086,30303,30305,30663,31001,31153,31339,31337,31806,31807,31800,31805,31799,31808,32363,32365,32377,32361,32362,32645,32371,32694,32697,32696,33240,34281,34269,34282,34261,34276,34277,34295,34811,34821,34829,34809,34814,35168,35167,35158,35166,35649,35676,35672,35657,35674,35662,35663,35654,35673,36104,36106,36476,36466,36487,36470,36460,36474,36468,36692,36686,36781,37002,37003,37297,37294,37857,37841,37855,37827,37832,37852,37853,37846,37858,37837,37848,37860,37847,37864,38364,38580,38627,38698,38695,38753,38876,38907,39006,39000,39003,39100,39237,39241,39446,39449,39693,39912,39911,39894,39899,40329,40289,40306,40298,40300,40594,40599,40595,40628,21240,22184,22199,22198,22196,22204,22756,23360,23363,23421,23542,24009,25080,25082,25880,25876,25881,26342,26407,27372,28734,28720,28722,29200,29563,29903,30306,30309,31014,31018,31020,31019,31431,31478,31820,31811,31821,31983,31984,36782,32381,32380,32386,32588,32768,33242,33382,34299,34297,34321,34298,34310,34315,34311,34314,34836,34837,35172,35258,35320,35696,35692,35686,35695,35679,35691,36111,36109,36489,36481,36485,36482,37300,37323,37912,37891,37885,38369,38704,39108,39250,39249,39336,39467,39472,39479,39477,39955,39949,40569,40629,40680,40751,40799,40803,40801,20791,20792,22209,22208,22210,22804,23660,24013,25084,25086,25885,25884,26005,26345,27387,27396,27386,27570,28748,29211,29351,29910,29908,30313,30675,31824,32399,32396,32700,34327,34349,34330,34851,34850,34849,34847,35178,35180,35261,35700,35703,35709,36115,36490,36493,36491,36703,36783,37306,37934,37939,37941,37946,37944,37938,37931,38370,38712,38713,38706,38911,39015,39013,39255,39493,39491,39488,39486,39631,39764,39761,39981,39973,40367,40372,40386,40376,40605,40687,40729,40796,40806,40807,20796,20795,22216,22218,22217,23423,24020,24018,24398,25087,25892,27402,27489,28753,28760,29568,29924,30090,30318,30316,31155,31840,31839,32894,32893,33247,35186,35183,35324,35712,36118,36119,36497,36499,36705,37192,37956,37969,37970,38717,38718,38851,38849,39019,39253,39509,39501,39634,39706,40009,39985,39998,39995,40403,40407,40756,40812,40810,40852,22220,24022,25088,25891,25899,25898,26348,27408,29914,31434,31844,31843,31845,32403,32406,32404,33250,34360,34367,34865,35722,37008,37007,37987,37984,37988,38760,39023,39260,39514,39515,39511,39635,39636,39633,40020,40023,40022,40421,40607,40692,22225,22761,25900,28766,30321,30322,30679,32592,32648,34870,34873,34914,35731,35730,35734,33399,36123,37312,37994,38722,38728,38724,38854,39024,39519,39714,39768,40031,40441,40442,40572,40573,40711,40823,40818,24307,27414,28771,31852,31854,34875,35264,36513,37313,38002,38000,39025,39262,39638,39715,40652,28772,30682,35738,38007,38857,39522,39525,32412,35740,36522,37317,38013,38014,38012,40055,40056,40695,35924,38015,40474,29224,39530,39729,40475,40478,31858,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,20022,20031,20101,20128,20866,20886,20907,21241,21304,21353,21430,22794,23424,24027,12083,24191,24308,24400,24417,25908,26080,30098,30326,36789,38582,168,710,12541,12542,12445,12446,12291,20189,12293,12294,12295,12540,65339,65341,10045,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,8679,8632,8633,12751,131276,20058,131210,20994,17553,40880,20872,40881,161287,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,65506,65508,65287,65282,12849,8470,8481,12443,12444,11904,11908,11910,11911,11912,11914,11916,11917,11925,11932,11933,11941,11943,11946,11948,11950,11958,11964,11966,11974,11978,11980,11981,11983,11990,11991,11998,12003,null,null,null,643,592,603,596,629,339,248,331,650,618,20034,20060,20981,21274,21378,19975,19980,20039,20109,22231,64012,23662,24435,19983,20871,19982,20014,20115,20162,20169,20168,20888,21244,21356,21433,22304,22787,22828,23568,24063,26081,27571,27596,27668,29247,20017,20028,20200,20188,20201,20193,20189,20186,21004,21276,21324,22306,22307,22807,22831,23425,23428,23570,23611,23668,23667,24068,24192,24194,24521,25097,25168,27669,27702,27715,27711,27707,29358,29360,29578,31160,32906,38430,20238,20248,20268,20213,20244,20209,20224,20215,20232,20253,20226,20229,20258,20243,20228,20212,20242,20913,21011,21001,21008,21158,21282,21279,21325,21386,21511,22241,22239,22318,22314,22324,22844,22912,22908,22917,22907,22910,22903,22911,23382,23573,23589,23676,23674,23675,23678,24031,24181,24196,24322,24346,24436,24533,24532,24527,25180,25182,25188,25185,25190,25186,25177,25184,25178,25189,26095,26094,26430,26425,26424,26427,26426,26431,26428,26419,27672,27718,27730,27740,27727,27722,27732,27723,27724,28785,29278,29364,29365,29582,29994,30335,31349,32593,33400,33404,33408,33405,33407,34381,35198,37017,37015,37016,37019,37012,38434,38436,38432,38435,20310,20283,20322,20297,20307,20324,20286,20327,20306,20319,20289,20312,20269,20275,20287,20321,20879,20921,21020,21022,21025,21165,21166,21257,21347,21362,21390,21391,21552,21559,21546,21588,21573,21529,21532,21541,21528,21565,21583,21569,21544,21540,21575,22254,22247,22245,22337,22341,22348,22345,22347,22354,22790,22848,22950,22936,22944,22935,22926,22946,22928,22927,22951,22945,23438,23442,23592,23594,23693,23695,23688,23691,23689,23698,23690,23686,23699,23701,24032,24074,24078,24203,24201,24204,24200,24205,24325,24349,24440,24438,24530,24529,24528,24557,24552,24558,24563,24545,24548,24547,24570,24559,24567,24571,24576,24564,25146,25219,25228,25230,25231,25236,25223,25201,25211,25210,25200,25217,25224,25207,25213,25202,25204,25911,26096,26100,26099,26098,26101,26437,26439,26457,26453,26444,26440,26461,26445,26458,26443,27600,27673,27674,27768,27751,27755,27780,27787,27791,27761,27759,27753,27802,27757,27783,27797,27804,27750,27763,27749,27771,27790,28788,28794,29283,29375,29373,29379,29382,29377,29370,29381,29589,29591,29587,29588,29586,30010,30009,30100,30101,30337,31037,32820,32917,32921,32912,32914,32924,33424,33423,33413,33422,33425,33427,33418,33411,33412,35960,36809,36799,37023,37025,37029,37022,37031,37024,38448,38440,38447,38445,20019,20376,20348,20357,20349,20352,20359,20342,20340,20361,20356,20343,20300,20375,20330,20378,20345,20353,20344,20368,20380,20372,20382,20370,20354,20373,20331,20334,20894,20924,20926,21045,21042,21043,21062,21041,21180,21258,21259,21308,21394,21396,21639,21631,21633,21649,21634,21640,21611,21626,21630,21605,21612,21620,21606,21645,21615,21601,21600,21656,21603,21607,21604,22263,22265,22383,22386,22381,22379,22385,22384,22390,22400,22389,22395,22387,22388,22370,22376,22397,22796,22853,22965,22970,22991,22990,22962,22988,22977,22966,22972,22979,22998,22961,22973,22976,22984,22964,22983,23394,23397,23443,23445,23620,23623,23726,23716,23712,23733,23727,23720,23724,23711,23715,23725,23714,23722,23719,23709,23717,23734,23728,23718,24087,24084,24089,24360,24354,24355,24356,24404,24450,24446,24445,24542,24549,24621,24614,24601,24626,24587,24628,24586,24599,24627,24602,24606,24620,24610,24589,24592,24622,24595,24593,24588,24585,24604,25108,25149,25261,25268,25297,25278,25258,25270,25290,25262,25267,25263,25275,25257,25264,25272,25917,26024,26043,26121,26108,26116,26130,26120,26107,26115,26123,26125,26117,26109,26129,26128,26358,26378,26501,26476,26510,26514,26486,26491,26520,26502,26500,26484,26509,26508,26490,26527,26513,26521,26499,26493,26497,26488,26489,26516,27429,27520,27518,27614,27677,27795,27884,27883,27886,27865,27830,27860,27821,27879,27831,27856,27842,27834,27843,27846,27885,27890,27858,27869,27828,27786,27805,27776,27870,27840,27952,27853,27847,27824,27897,27855,27881,27857,28820,28824,28805,28819,28806,28804,28817,28822,28802,28826,28803,29290,29398,29387,29400,29385,29404,29394,29396,29402,29388,29393,29604,29601,29613,29606,29602,29600,29612,29597,29917,29928,30015,30016,30014,30092,30104,30383,30451,30449,30448,30453,30712,30716,30713,30715,30714,30711,31042,31039,31173,31352,31355,31483,31861,31997,32821,32911,32942,32931,32952,32949,32941,33312,33440,33472,33451,33434,33432,33435,33461,33447,33454,33468,33438,33466,33460,33448,33441,33449,33474,33444,33475,33462,33442,34416,34415,34413,34414,35926,36818,36811,36819,36813,36822,36821,36823,37042,37044,37039,37043,37040,38457,38461,38460,38458,38467,20429,20421,20435,20402,20425,20427,20417,20436,20444,20441,20411,20403,20443,20423,20438,20410,20416,20409,20460,21060,21065,21184,21186,21309,21372,21399,21398,21401,21400,21690,21665,21677,21669,21711,21699,33549,21687,21678,21718,21686,21701,21702,21664,21616,21692,21666,21694,21618,21726,21680,22453,22430,22431,22436,22412,22423,22429,22427,22420,22424,22415,22425,22437,22426,22421,22772,22797,22867,23009,23006,23022,23040,23025,23005,23034,23037,23036,23030,23012,23026,23031,23003,23017,23027,23029,23008,23038,23028,23021,23464,23628,23760,23768,23756,23767,23755,23771,23774,23770,23753,23751,23754,23766,23763,23764,23759,23752,23750,23758,23775,23800,24057,24097,24098,24099,24096,24100,24240,24228,24226,24219,24227,24229,24327,24366,24406,24454,24631,24633,24660,24690,24670,24645,24659,24647,24649,24667,24652,24640,24642,24671,24612,24644,24664,24678,24686,25154,25155,25295,25357,25355,25333,25358,25347,25323,25337,25359,25356,25336,25334,25344,25363,25364,25338,25365,25339,25328,25921,25923,26026,26047,26166,26145,26162,26165,26140,26150,26146,26163,26155,26170,26141,26164,26169,26158,26383,26384,26561,26610,26568,26554,26588,26555,26616,26584,26560,26551,26565,26603,26596,26591,26549,26573,26547,26615,26614,26606,26595,26562,26553,26574,26599,26608,26546,26620,26566,26605,26572,26542,26598,26587,26618,26569,26570,26563,26602,26571,27432,27522,27524,27574,27606,27608,27616,27680,27681,27944,27956,27949,27935,27964,27967,27922,27914,27866,27955,27908,27929,27962,27930,27921,27904,27933,27970,27905,27928,27959,27907,27919,27968,27911,27936,27948,27912,27938,27913,27920,28855,28831,28862,28849,28848,28833,28852,28853,28841,29249,29257,29258,29292,29296,29299,29294,29386,29412,29416,29419,29407,29418,29414,29411,29573,29644,29634,29640,29637,29625,29622,29621,29620,29675,29631,29639,29630,29635,29638,29624,29643,29932,29934,29998,30023,30024,30119,30122,30329,30404,30472,30467,30468,30469,30474,30455,30459,30458,30695,30696,30726,30737,30738,30725,30736,30735,30734,30729,30723,30739,31050,31052,31051,31045,31044,31189,31181,31183,31190,31182,31360,31358,31441,31488,31489,31866,31864,31865,31871,31872,31873,32003,32008,32001,32600,32657,32653,32702,32775,32782,32783,32788,32823,32984,32967,32992,32977,32968,32962,32976,32965,32995,32985,32988,32970,32981,32969,32975,32983,32998,32973,33279,33313,33428,33497,33534,33529,33543,33512,33536,33493,33594,33515,33494,33524,33516,33505,33522,33525,33548,33531,33526,33520,33514,33508,33504,33530,33523,33517,34423,34420,34428,34419,34881,34894,34919,34922,34921,35283,35332,35335,36210,36835,36833,36846,36832,37105,37053,37055,37077,37061,37054,37063,37067,37064,37332,37331,38484,38479,38481,38483,38474,38478,20510,20485,20487,20499,20514,20528,20507,20469,20468,20531,20535,20524,20470,20471,20503,20508,20512,20519,20533,20527,20529,20494,20826,20884,20883,20938,20932,20933,20936,20942,21089,21082,21074,21086,21087,21077,21090,21197,21262,21406,21798,21730,21783,21778,21735,21747,21732,21786,21759,21764,21768,21739,21777,21765,21745,21770,21755,21751,21752,21728,21774,21763,21771,22273,22274,22476,22578,22485,22482,22458,22470,22461,22460,22456,22454,22463,22471,22480,22457,22465,22798,22858,23065,23062,23085,23086,23061,23055,23063,23050,23070,23091,23404,23463,23469,23468,23555,23638,23636,23788,23807,23790,23793,23799,23808,23801,24105,24104,24232,24238,24234,24236,24371,24368,24423,24669,24666,24679,24641,24738,24712,24704,24722,24705,24733,24707,24725,24731,24727,24711,24732,24718,25113,25158,25330,25360,25430,25388,25412,25413,25398,25411,25572,25401,25419,25418,25404,25385,25409,25396,25432,25428,25433,25389,25415,25395,25434,25425,25400,25431,25408,25416,25930,25926,26054,26051,26052,26050,26186,26207,26183,26193,26386,26387,26655,26650,26697,26674,26675,26683,26699,26703,26646,26673,26652,26677,26667,26669,26671,26702,26692,26676,26653,26642,26644,26662,26664,26670,26701,26682,26661,26656,27436,27439,27437,27441,27444,27501,32898,27528,27622,27620,27624,27619,27618,27623,27685,28026,28003,28004,28022,27917,28001,28050,27992,28002,28013,28015,28049,28045,28143,28031,28038,27998,28007,28000,28055,28016,28028,27999,28034,28056,27951,28008,28043,28030,28032,28036,27926,28035,28027,28029,28021,28048,28892,28883,28881,28893,28875,32569,28898,28887,28882,28894,28896,28884,28877,28869,28870,28871,28890,28878,28897,29250,29304,29303,29302,29440,29434,29428,29438,29430,29427,29435,29441,29651,29657,29669,29654,29628,29671,29667,29673,29660,29650,29659,29652,29661,29658,29655,29656,29672,29918,29919,29940,29941,29985,30043,30047,30128,30145,30139,30148,30144,30143,30134,30138,30346,30409,30493,30491,30480,30483,30482,30499,30481,30485,30489,30490,30498,30503,30755,30764,30754,30773,30767,30760,30766,30763,30753,30761,30771,30762,30769,31060,31067,31055,31068,31059,31058,31057,31211,31212,31200,31214,31213,31210,31196,31198,31197,31366,31369,31365,31371,31372,31370,31367,31448,31504,31492,31507,31493,31503,31496,31498,31502,31497,31506,31876,31889,31882,31884,31880,31885,31877,32030,32029,32017,32014,32024,32022,32019,32031,32018,32015,32012,32604,32609,32606,32608,32605,32603,32662,32658,32707,32706,32704,32790,32830,32825,33018,33010,33017,33013,33025,33019,33024,33281,33327,33317,33587,33581,33604,33561,33617,33573,33622,33599,33601,33574,33564,33570,33602,33614,33563,33578,33544,33596,33613,33558,33572,33568,33591,33583,33577,33607,33605,33612,33619,33566,33580,33611,33575,33608,34387,34386,34466,34472,34454,34445,34449,34462,34439,34455,34438,34443,34458,34437,34469,34457,34465,34471,34453,34456,34446,34461,34448,34452,34883,34884,34925,34933,34934,34930,34944,34929,34943,34927,34947,34942,34932,34940,35346,35911,35927,35963,36004,36003,36214,36216,36277,36279,36278,36561,36563,36862,36853,36866,36863,36859,36868,36860,36854,37078,37088,37081,37082,37091,37087,37093,37080,37083,37079,37084,37092,37200,37198,37199,37333,37346,37338,38492,38495,38588,39139,39647,39727,20095,20592,20586,20577,20574,20576,20563,20555,20573,20594,20552,20557,20545,20571,20554,20578,20501,20549,20575,20585,20587,20579,20580,20550,20544,20590,20595,20567,20561,20944,21099,21101,21100,21102,21206,21203,21293,21404,21877,21878,21820,21837,21840,21812,21802,21841,21858,21814,21813,21808,21842,21829,21772,21810,21861,21838,21817,21832,21805,21819,21824,21835,22282,22279,22523,22548,22498,22518,22492,22516,22528,22509,22525,22536,22520,22539,22515,22479,22535,22510,22499,22514,22501,22508,22497,22542,22524,22544,22503,22529,22540,22513,22505,22512,22541,22532,22876,23136,23128,23125,23143,23134,23096,23093,23149,23120,23135,23141,23148,23123,23140,23127,23107,23133,23122,23108,23131,23112,23182,23102,23117,23097,23116,23152,23145,23111,23121,23126,23106,23132,23410,23406,23489,23488,23641,23838,23819,23837,23834,23840,23820,23848,23821,23846,23845,23823,23856,23826,23843,23839,23854,24126,24116,24241,24244,24249,24242,24243,24374,24376,24475,24470,24479,24714,24720,24710,24766,24752,24762,24787,24788,24783,24804,24793,24797,24776,24753,24795,24759,24778,24767,24771,24781,24768,25394,25445,25482,25474,25469,25533,25502,25517,25501,25495,25515,25486,25455,25479,25488,25454,25519,25461,25500,25453,25518,25468,25508,25403,25503,25464,25477,25473,25489,25485,25456,25939,26061,26213,26209,26203,26201,26204,26210,26392,26745,26759,26768,26780,26733,26734,26798,26795,26966,26735,26787,26796,26793,26741,26740,26802,26767,26743,26770,26748,26731,26738,26794,26752,26737,26750,26779,26774,26763,26784,26761,26788,26744,26747,26769,26764,26762,26749,27446,27443,27447,27448,27537,27535,27533,27534,27532,27690,28096,28075,28084,28083,28276,28076,28137,28130,28087,28150,28116,28160,28104,28128,28127,28118,28094,28133,28124,28125,28123,28148,28106,28093,28141,28144,28090,28117,28098,28111,28105,28112,28146,28115,28157,28119,28109,28131,28091,28922,28941,28919,28951,28916,28940,28912,28932,28915,28944,28924,28927,28934,28947,28928,28920,28918,28939,28930,28942,29310,29307,29308,29311,29469,29463,29447,29457,29464,29450,29448,29439,29455,29470,29576,29686,29688,29685,29700,29697,29693,29703,29696,29690,29692,29695,29708,29707,29684,29704,30052,30051,30158,30162,30159,30155,30156,30161,30160,30351,30345,30419,30521,30511,30509,30513,30514,30516,30515,30525,30501,30523,30517,30792,30802,30793,30797,30794,30796,30758,30789,30800,31076,31079,31081,31082,31075,31083,31073,31163,31226,31224,31222,31223,31375,31380,31376,31541,31559,31540,31525,31536,31522,31524,31539,31512,31530,31517,31537,31531,31533,31535,31538,31544,31514,31523,31892,31896,31894,31907,32053,32061,32056,32054,32058,32069,32044,32041,32065,32071,32062,32063,32074,32059,32040,32611,32661,32668,32669,32667,32714,32715,32717,32720,32721,32711,32719,32713,32799,32798,32795,32839,32835,32840,33048,33061,33049,33051,33069,33055,33068,33054,33057,33045,33063,33053,33058,33297,33336,33331,33338,33332,33330,33396,33680,33699,33704,33677,33658,33651,33700,33652,33679,33665,33685,33689,33653,33684,33705,33661,33667,33676,33693,33691,33706,33675,33662,33701,33711,33672,33687,33712,33663,33702,33671,33710,33654,33690,34393,34390,34495,34487,34498,34497,34501,34490,34480,34504,34489,34483,34488,34508,34484,34491,34492,34499,34493,34494,34898,34953,34965,34984,34978,34986,34970,34961,34977,34975,34968,34983,34969,34971,34967,34980,34988,34956,34963,34958,35202,35286,35289,35285,35376,35367,35372,35358,35897,35899,35932,35933,35965,36005,36221,36219,36217,36284,36290,36281,36287,36289,36568,36574,36573,36572,36567,36576,36577,36900,36875,36881,36892,36876,36897,37103,37098,37104,37108,37106,37107,37076,37099,37100,37097,37206,37208,37210,37203,37205,37356,37364,37361,37363,37368,37348,37369,37354,37355,37367,37352,37358,38266,38278,38280,38524,38509,38507,38513,38511,38591,38762,38916,39141,39319,20635,20629,20628,20638,20619,20643,20611,20620,20622,20637,20584,20636,20626,20610,20615,20831,20948,21266,21265,21412,21415,21905,21928,21925,21933,21879,22085,21922,21907,21896,21903,21941,21889,21923,21906,21924,21885,21900,21926,21887,21909,21921,21902,22284,22569,22583,22553,22558,22567,22563,22568,22517,22600,22565,22556,22555,22579,22591,22582,22574,22585,22584,22573,22572,22587,22881,23215,23188,23199,23162,23202,23198,23160,23206,23164,23205,23212,23189,23214,23095,23172,23178,23191,23171,23179,23209,23163,23165,23180,23196,23183,23187,23197,23530,23501,23499,23508,23505,23498,23502,23564,23600,23863,23875,23915,23873,23883,23871,23861,23889,23886,23893,23859,23866,23890,23869,23857,23897,23874,23865,23881,23864,23868,23858,23862,23872,23877,24132,24129,24408,24486,24485,24491,24777,24761,24780,24802,24782,24772,24852,24818,24842,24854,24837,24821,24851,24824,24828,24830,24769,24835,24856,24861,24848,24831,24836,24843,25162,25492,25521,25520,25550,25573,25576,25583,25539,25757,25587,25546,25568,25590,25557,25586,25589,25697,25567,25534,25565,25564,25540,25560,25555,25538,25543,25548,25547,25544,25584,25559,25561,25906,25959,25962,25956,25948,25960,25957,25996,26013,26014,26030,26064,26066,26236,26220,26235,26240,26225,26233,26218,26226,26369,26892,26835,26884,26844,26922,26860,26858,26865,26895,26838,26871,26859,26852,26870,26899,26896,26867,26849,26887,26828,26888,26992,26804,26897,26863,26822,26900,26872,26832,26877,26876,26856,26891,26890,26903,26830,26824,26845,26846,26854,26868,26833,26886,26836,26857,26901,26917,26823,27449,27451,27455,27452,27540,27543,27545,27541,27581,27632,27634,27635,27696,28156,28230,28231,28191,28233,28296,28220,28221,28229,28258,28203,28223,28225,28253,28275,28188,28211,28235,28224,28241,28219,28163,28206,28254,28264,28252,28257,28209,28200,28256,28273,28267,28217,28194,28208,28243,28261,28199,28280,28260,28279,28245,28281,28242,28262,28213,28214,28250,28960,28958,28975,28923,28974,28977,28963,28965,28962,28978,28959,28968,28986,28955,29259,29274,29320,29321,29318,29317,29323,29458,29451,29488,29474,29489,29491,29479,29490,29485,29478,29475,29493,29452,29742,29740,29744,29739,29718,29722,29729,29741,29745,29732,29731,29725,29737,29728,29746,29947,29999,30063,30060,30183,30170,30177,30182,30173,30175,30180,30167,30357,30354,30426,30534,30535,30532,30541,30533,30538,30542,30539,30540,30686,30700,30816,30820,30821,30812,30829,30833,30826,30830,30832,30825,30824,30814,30818,31092,31091,31090,31088,31234,31242,31235,31244,31236,31385,31462,31460,31562,31547,31556,31560,31564,31566,31552,31576,31557,31906,31902,31912,31905,32088,32111,32099,32083,32086,32103,32106,32079,32109,32092,32107,32082,32084,32105,32081,32095,32078,32574,32575,32613,32614,32674,32672,32673,32727,32849,32847,32848,33022,32980,33091,33098,33106,33103,33095,33085,33101,33082,33254,33262,33271,33272,33273,33284,33340,33341,33343,33397,33595,33743,33785,33827,33728,33768,33810,33767,33764,33788,33782,33808,33734,33736,33771,33763,33727,33793,33757,33765,33752,33791,33761,33739,33742,33750,33781,33737,33801,33807,33758,33809,33798,33730,33779,33749,33786,33735,33745,33770,33811,33731,33772,33774,33732,33787,33751,33762,33819,33755,33790,34520,34530,34534,34515,34531,34522,34538,34525,34539,34524,34540,34537,34519,34536,34513,34888,34902,34901,35002,35031,35001,35000,35008,35006,34998,35004,34999,35005,34994,35073,35017,35221,35224,35223,35293,35290,35291,35406,35405,35385,35417,35392,35415,35416,35396,35397,35410,35400,35409,35402,35404,35407,35935,35969,35968,36026,36030,36016,36025,36021,36228,36224,36233,36312,36307,36301,36295,36310,36316,36303,36309,36313,36296,36311,36293,36591,36599,36602,36601,36582,36590,36581,36597,36583,36584,36598,36587,36593,36588,36596,36585,36909,36916,36911,37126,37164,37124,37119,37116,37128,37113,37115,37121,37120,37127,37125,37123,37217,37220,37215,37218,37216,37377,37386,37413,37379,37402,37414,37391,37388,37376,37394,37375,37373,37382,37380,37415,37378,37404,37412,37401,37399,37381,37398,38267,38285,38284,38288,38535,38526,38536,38537,38531,38528,38594,38600,38595,38641,38640,38764,38768,38766,38919,39081,39147,40166,40697,20099,20100,20150,20669,20671,20678,20654,20676,20682,20660,20680,20674,20656,20673,20666,20657,20683,20681,20662,20664,20951,21114,21112,21115,21116,21955,21979,21964,21968,21963,21962,21981,21952,21972,21956,21993,21951,21970,21901,21967,21973,21986,21974,21960,22002,21965,21977,21954,22292,22611,22632,22628,22607,22605,22601,22639,22613,22606,22621,22617,22629,22619,22589,22627,22641,22780,23239,23236,23243,23226,23224,23217,23221,23216,23231,23240,23227,23238,23223,23232,23242,23220,23222,23245,23225,23184,23510,23512,23513,23583,23603,23921,23907,23882,23909,23922,23916,23902,23912,23911,23906,24048,24143,24142,24138,24141,24139,24261,24268,24262,24267,24263,24384,24495,24493,24823,24905,24906,24875,24901,24886,24882,24878,24902,24879,24911,24873,24896,25120,37224,25123,25125,25124,25541,25585,25579,25616,25618,25609,25632,25636,25651,25667,25631,25621,25624,25657,25655,25634,25635,25612,25638,25648,25640,25665,25653,25647,25610,25626,25664,25637,25639,25611,25575,25627,25646,25633,25614,25967,26002,26067,26246,26252,26261,26256,26251,26250,26265,26260,26232,26400,26982,26975,26936,26958,26978,26993,26943,26949,26986,26937,26946,26967,26969,27002,26952,26953,26933,26988,26931,26941,26981,26864,27000,26932,26985,26944,26991,26948,26998,26968,26945,26996,26956,26939,26955,26935,26972,26959,26961,26930,26962,26927,27003,26940,27462,27461,27459,27458,27464,27457,27547,64013,27643,27644,27641,27639,27640,28315,28374,28360,28303,28352,28319,28307,28308,28320,28337,28345,28358,28370,28349,28353,28318,28361,28343,28336,28365,28326,28367,28338,28350,28355,28380,28376,28313,28306,28302,28301,28324,28321,28351,28339,28368,28362,28311,28334,28323,28999,29012,29010,29027,29024,28993,29021,29026,29042,29048,29034,29025,28994,29016,28995,29003,29040,29023,29008,29011,28996,29005,29018,29263,29325,29324,29329,29328,29326,29500,29506,29499,29498,29504,29514,29513,29764,29770,29771,29778,29777,29783,29760,29775,29776,29774,29762,29766,29773,29780,29921,29951,29950,29949,29981,30073,30071,27011,30191,30223,30211,30199,30206,30204,30201,30200,30224,30203,30198,30189,30197,30205,30361,30389,30429,30549,30559,30560,30546,30550,30554,30569,30567,30548,30553,30573,30688,30855,30874,30868,30863,30852,30869,30853,30854,30881,30851,30841,30873,30848,30870,30843,31100,31106,31101,31097,31249,31256,31257,31250,31255,31253,31266,31251,31259,31248,31395,31394,31390,31467,31590,31588,31597,31604,31593,31602,31589,31603,31601,31600,31585,31608,31606,31587,31922,31924,31919,32136,32134,32128,32141,32127,32133,32122,32142,32123,32131,32124,32140,32148,32132,32125,32146,32621,32619,32615,32616,32620,32678,32677,32679,32731,32732,32801,33124,33120,33143,33116,33129,33115,33122,33138,26401,33118,33142,33127,33135,33092,33121,33309,33353,33348,33344,33346,33349,34033,33855,33878,33910,33913,33935,33933,33893,33873,33856,33926,33895,33840,33869,33917,33882,33881,33908,33907,33885,34055,33886,33847,33850,33844,33914,33859,33912,33842,33861,33833,33753,33867,33839,33858,33837,33887,33904,33849,33870,33868,33874,33903,33989,33934,33851,33863,33846,33843,33896,33918,33860,33835,33888,33876,33902,33872,34571,34564,34551,34572,34554,34518,34549,34637,34552,34574,34569,34561,34550,34573,34565,35030,35019,35021,35022,35038,35035,35034,35020,35024,35205,35227,35295,35301,35300,35297,35296,35298,35292,35302,35446,35462,35455,35425,35391,35447,35458,35460,35445,35459,35457,35444,35450,35900,35915,35914,35941,35940,35942,35974,35972,35973,36044,36200,36201,36241,36236,36238,36239,36237,36243,36244,36240,36242,36336,36320,36332,36337,36334,36304,36329,36323,36322,36327,36338,36331,36340,36614,36607,36609,36608,36613,36615,36616,36610,36619,36946,36927,36932,36937,36925,37136,37133,37135,37137,37142,37140,37131,37134,37230,37231,37448,37458,37424,37434,37478,37427,37477,37470,37507,37422,37450,37446,37485,37484,37455,37472,37479,37487,37430,37473,37488,37425,37460,37475,37456,37490,37454,37459,37452,37462,37426,38303,38300,38302,38299,38546,38547,38545,38551,38606,38650,38653,38648,38645,38771,38775,38776,38770,38927,38925,38926,39084,39158,39161,39343,39346,39344,39349,39597,39595,39771,40170,40173,40167,40576,40701,20710,20692,20695,20712,20723,20699,20714,20701,20708,20691,20716,20720,20719,20707,20704,20952,21120,21121,21225,21227,21296,21420,22055,22037,22028,22034,22012,22031,22044,22017,22035,22018,22010,22045,22020,22015,22009,22665,22652,22672,22680,22662,22657,22655,22644,22667,22650,22663,22673,22670,22646,22658,22664,22651,22676,22671,22782,22891,23260,23278,23269,23253,23274,23258,23277,23275,23283,23266,23264,23259,23276,23262,23261,23257,23272,23263,23415,23520,23523,23651,23938,23936,23933,23942,23930,23937,23927,23946,23945,23944,23934,23932,23949,23929,23935,24152,24153,24147,24280,24273,24279,24270,24284,24277,24281,24274,24276,24388,24387,24431,24502,24876,24872,24897,24926,24945,24947,24914,24915,24946,24940,24960,24948,24916,24954,24923,24933,24891,24938,24929,24918,25129,25127,25131,25643,25677,25691,25693,25716,25718,25714,25715,25725,25717,25702,25766,25678,25730,25694,25692,25675,25683,25696,25680,25727,25663,25708,25707,25689,25701,25719,25971,26016,26273,26272,26271,26373,26372,26402,27057,27062,27081,27040,27086,27030,27056,27052,27068,27025,27033,27022,27047,27021,27049,27070,27055,27071,27076,27069,27044,27092,27065,27082,27034,27087,27059,27027,27050,27041,27038,27097,27031,27024,27074,27061,27045,27078,27466,27469,27467,27550,27551,27552,27587,27588,27646,28366,28405,28401,28419,28453,28408,28471,28411,28462,28425,28494,28441,28442,28455,28440,28475,28434,28397,28426,28470,28531,28409,28398,28461,28480,28464,28476,28469,28395,28423,28430,28483,28421,28413,28406,28473,28444,28412,28474,28447,28429,28446,28424,28449,29063,29072,29065,29056,29061,29058,29071,29051,29062,29057,29079,29252,29267,29335,29333,29331,29507,29517,29521,29516,29794,29811,29809,29813,29810,29799,29806,29952,29954,29955,30077,30096,30230,30216,30220,30229,30225,30218,30228,30392,30593,30588,30597,30594,30574,30592,30575,30590,30595,30898,30890,30900,30893,30888,30846,30891,30878,30885,30880,30892,30882,30884,31128,31114,31115,31126,31125,31124,31123,31127,31112,31122,31120,31275,31306,31280,31279,31272,31270,31400,31403,31404,31470,31624,31644,31626,31633,31632,31638,31629,31628,31643,31630,31621,31640,21124,31641,31652,31618,31931,31935,31932,31930,32167,32183,32194,32163,32170,32193,32192,32197,32157,32206,32196,32198,32203,32204,32175,32185,32150,32188,32159,32166,32174,32169,32161,32201,32627,32738,32739,32741,32734,32804,32861,32860,33161,33158,33155,33159,33165,33164,33163,33301,33943,33956,33953,33951,33978,33998,33986,33964,33966,33963,33977,33972,33985,33997,33962,33946,33969,34000,33949,33959,33979,33954,33940,33991,33996,33947,33961,33967,33960,34006,33944,33974,33999,33952,34007,34004,34002,34011,33968,33937,34401,34611,34595,34600,34667,34624,34606,34590,34593,34585,34587,34627,34604,34625,34622,34630,34592,34610,34602,34605,34620,34578,34618,34609,34613,34626,34598,34599,34616,34596,34586,34608,34577,35063,35047,35057,35058,35066,35070,35054,35068,35062,35067,35056,35052,35051,35229,35233,35231,35230,35305,35307,35304,35499,35481,35467,35474,35471,35478,35901,35944,35945,36053,36047,36055,36246,36361,36354,36351,36365,36349,36362,36355,36359,36358,36357,36350,36352,36356,36624,36625,36622,36621,37155,37148,37152,37154,37151,37149,37146,37156,37153,37147,37242,37234,37241,37235,37541,37540,37494,37531,37498,37536,37524,37546,37517,37542,37530,37547,37497,37527,37503,37539,37614,37518,37506,37525,37538,37501,37512,37537,37514,37510,37516,37529,37543,37502,37511,37545,37533,37515,37421,38558,38561,38655,38744,38781,38778,38782,38787,38784,38786,38779,38788,38785,38783,38862,38861,38934,39085,39086,39170,39168,39175,39325,39324,39363,39353,39355,39354,39362,39357,39367,39601,39651,39655,39742,39743,39776,39777,39775,40177,40178,40181,40615,20735,20739,20784,20728,20742,20743,20726,20734,20747,20748,20733,20746,21131,21132,21233,21231,22088,22082,22092,22069,22081,22090,22089,22086,22104,22106,22080,22067,22077,22060,22078,22072,22058,22074,22298,22699,22685,22705,22688,22691,22703,22700,22693,22689,22783,23295,23284,23293,23287,23286,23299,23288,23298,23289,23297,23303,23301,23311,23655,23961,23959,23967,23954,23970,23955,23957,23968,23964,23969,23962,23966,24169,24157,24160,24156,32243,24283,24286,24289,24393,24498,24971,24963,24953,25009,25008,24994,24969,24987,24979,25007,25005,24991,24978,25002,24993,24973,24934,25011,25133,25710,25712,25750,25760,25733,25751,25756,25743,25739,25738,25740,25763,25759,25704,25777,25752,25974,25978,25977,25979,26034,26035,26293,26288,26281,26290,26295,26282,26287,27136,27142,27159,27109,27128,27157,27121,27108,27168,27135,27116,27106,27163,27165,27134,27175,27122,27118,27156,27127,27111,27200,27144,27110,27131,27149,27132,27115,27145,27140,27160,27173,27151,27126,27174,27143,27124,27158,27473,27557,27555,27554,27558,27649,27648,27647,27650,28481,28454,28542,28551,28614,28562,28557,28553,28556,28514,28495,28549,28506,28566,28534,28524,28546,28501,28530,28498,28496,28503,28564,28563,28509,28416,28513,28523,28541,28519,28560,28499,28555,28521,28543,28565,28515,28535,28522,28539,29106,29103,29083,29104,29088,29082,29097,29109,29085,29093,29086,29092,29089,29098,29084,29095,29107,29336,29338,29528,29522,29534,29535,29536,29533,29531,29537,29530,29529,29538,29831,29833,29834,29830,29825,29821,29829,29832,29820,29817,29960,29959,30078,30245,30238,30233,30237,30236,30243,30234,30248,30235,30364,30365,30366,30363,30605,30607,30601,30600,30925,30907,30927,30924,30929,30926,30932,30920,30915,30916,30921,31130,31137,31136,31132,31138,31131,27510,31289,31410,31412,31411,31671,31691,31678,31660,31694,31663,31673,31690,31669,31941,31944,31948,31947,32247,32219,32234,32231,32215,32225,32259,32250,32230,32246,32241,32240,32238,32223,32630,32684,32688,32685,32749,32747,32746,32748,32742,32744,32868,32871,33187,33183,33182,33173,33186,33177,33175,33302,33359,33363,33362,33360,33358,33361,34084,34107,34063,34048,34089,34062,34057,34061,34079,34058,34087,34076,34043,34091,34042,34056,34060,34036,34090,34034,34069,34039,34027,34035,34044,34066,34026,34025,34070,34046,34088,34077,34094,34050,34045,34078,34038,34097,34086,34023,34024,34032,34031,34041,34072,34080,34096,34059,34073,34095,34402,34646,34659,34660,34679,34785,34675,34648,34644,34651,34642,34657,34650,34641,34654,34669,34666,34640,34638,34655,34653,34671,34668,34682,34670,34652,34661,34639,34683,34677,34658,34663,34665,34906,35077,35084,35092,35083,35095,35096,35097,35078,35094,35089,35086,35081,35234,35236,35235,35309,35312,35308,35535,35526,35512,35539,35537,35540,35541,35515,35543,35518,35520,35525,35544,35523,35514,35517,35545,35902,35917,35983,36069,36063,36057,36072,36058,36061,36071,36256,36252,36257,36251,36384,36387,36389,36388,36398,36373,36379,36374,36369,36377,36390,36391,36372,36370,36376,36371,36380,36375,36378,36652,36644,36632,36634,36640,36643,36630,36631,36979,36976,36975,36967,36971,37167,37163,37161,37162,37170,37158,37166,37253,37254,37258,37249,37250,37252,37248,37584,37571,37572,37568,37593,37558,37583,37617,37599,37592,37609,37591,37597,37580,37615,37570,37608,37578,37576,37582,37606,37581,37589,37577,37600,37598,37607,37585,37587,37557,37601,37574,37556,38268,38316,38315,38318,38320,38564,38562,38611,38661,38664,38658,38746,38794,38798,38792,38864,38863,38942,38941,38950,38953,38952,38944,38939,38951,39090,39176,39162,39185,39188,39190,39191,39189,39388,39373,39375,39379,39380,39374,39369,39382,39384,39371,39383,39372,39603,39660,39659,39667,39666,39665,39750,39747,39783,39796,39793,39782,39798,39797,39792,39784,39780,39788,40188,40186,40189,40191,40183,40199,40192,40185,40187,40200,40197,40196,40579,40659,40719,40720,20764,20755,20759,20762,20753,20958,21300,21473,22128,22112,22126,22131,22118,22115,22125,22130,22110,22135,22300,22299,22728,22717,22729,22719,22714,22722,22716,22726,23319,23321,23323,23329,23316,23315,23312,23318,23336,23322,23328,23326,23535,23980,23985,23977,23975,23989,23984,23982,23978,23976,23986,23981,23983,23988,24167,24168,24166,24175,24297,24295,24294,24296,24293,24395,24508,24989,25000,24982,25029,25012,25030,25025,25036,25018,25023,25016,24972,25815,25814,25808,25807,25801,25789,25737,25795,25819,25843,25817,25907,25983,25980,26018,26312,26302,26304,26314,26315,26319,26301,26299,26298,26316,26403,27188,27238,27209,27239,27186,27240,27198,27229,27245,27254,27227,27217,27176,27226,27195,27199,27201,27242,27236,27216,27215,27220,27247,27241,27232,27196,27230,27222,27221,27213,27214,27206,27477,27476,27478,27559,27562,27563,27592,27591,27652,27651,27654,28589,28619,28579,28615,28604,28622,28616,28510,28612,28605,28574,28618,28584,28676,28581,28590,28602,28588,28586,28623,28607,28600,28578,28617,28587,28621,28591,28594,28592,29125,29122,29119,29112,29142,29120,29121,29131,29140,29130,29127,29135,29117,29144,29116,29126,29146,29147,29341,29342,29545,29542,29543,29548,29541,29547,29546,29823,29850,29856,29844,29842,29845,29857,29963,30080,30255,30253,30257,30269,30259,30268,30261,30258,30256,30395,30438,30618,30621,30625,30620,30619,30626,30627,30613,30617,30615,30941,30953,30949,30954,30942,30947,30939,30945,30946,30957,30943,30944,31140,31300,31304,31303,31414,31416,31413,31409,31415,31710,31715,31719,31709,31701,31717,31706,31720,31737,31700,31722,31714,31708,31723,31704,31711,31954,31956,31959,31952,31953,32274,32289,32279,32268,32287,32288,32275,32270,32284,32277,32282,32290,32267,32271,32278,32269,32276,32293,32292,32579,32635,32636,32634,32689,32751,32810,32809,32876,33201,33190,33198,33209,33205,33195,33200,33196,33204,33202,33207,33191,33266,33365,33366,33367,34134,34117,34155,34125,34131,34145,34136,34112,34118,34148,34113,34146,34116,34129,34119,34147,34110,34139,34161,34126,34158,34165,34133,34151,34144,34188,34150,34141,34132,34149,34156,34403,34405,34404,34715,34703,34711,34707,34706,34696,34689,34710,34712,34681,34695,34723,34693,34704,34705,34717,34692,34708,34716,34714,34697,35102,35110,35120,35117,35118,35111,35121,35106,35113,35107,35119,35116,35103,35313,35552,35554,35570,35572,35573,35549,35604,35556,35551,35568,35528,35550,35553,35560,35583,35567,35579,35985,35986,35984,36085,36078,36081,36080,36083,36204,36206,36261,36263,36403,36414,36408,36416,36421,36406,36412,36413,36417,36400,36415,36541,36662,36654,36661,36658,36665,36663,36660,36982,36985,36987,36998,37114,37171,37173,37174,37267,37264,37265,37261,37263,37671,37662,37640,37663,37638,37647,37754,37688,37692,37659,37667,37650,37633,37702,37677,37646,37645,37579,37661,37626,37669,37651,37625,37623,37684,37634,37668,37631,37673,37689,37685,37674,37652,37644,37643,37630,37641,37632,37627,37654,38332,38349,38334,38329,38330,38326,38335,38325,38333,38569,38612,38667,38674,38672,38809,38807,38804,38896,38904,38965,38959,38962,39204,39199,39207,39209,39326,39406,39404,39397,39396,39408,39395,39402,39401,39399,39609,39615,39604,39611,39670,39674,39673,39671,39731,39808,39813,39815,39804,39806,39803,39810,39827,39826,39824,39802,39829,39805,39816,40229,40215,40224,40222,40212,40233,40221,40216,40226,40208,40217,40223,40584,40582,40583,40622,40621,40661,40662,40698,40722,40765,20774,20773,20770,20772,20768,20777,21236,22163,22156,22157,22150,22148,22147,22142,22146,22143,22145,22742,22740,22735,22738,23341,23333,23346,23331,23340,23335,23334,23343,23342,23419,23537,23538,23991,24172,24170,24510,24507,25027,25013,25020,25063,25056,25061,25060,25064,25054,25839,25833,25827,25835,25828,25832,25985,25984,26038,26074,26322,27277,27286,27265,27301,27273,27295,27291,27297,27294,27271,27283,27278,27285,27267,27304,27300,27281,27263,27302,27290,27269,27276,27282,27483,27565,27657,28620,28585,28660,28628,28643,28636,28653,28647,28646,28638,28658,28637,28642,28648,29153,29169,29160,29170,29156,29168,29154,29555,29550,29551,29847,29874,29867,29840,29866,29869,29873,29861,29871,29968,29969,29970,29967,30084,30275,30280,30281,30279,30372,30441,30645,30635,30642,30647,30646,30644,30641,30632,30704,30963,30973,30978,30971,30972,30962,30981,30969,30974,30980,31147,31144,31324,31323,31318,31320,31316,31322,31422,31424,31425,31749,31759,31730,31744,31743,31739,31758,31732,31755,31731,31746,31753,31747,31745,31736,31741,31750,31728,31729,31760,31754,31976,32301,32316,32322,32307,38984,32312,32298,32329,32320,32327,32297,32332,32304,32315,32310,32324,32314,32581,32639,32638,32637,32756,32754,32812,33211,33220,33228,33226,33221,33223,33212,33257,33371,33370,33372,34179,34176,34191,34215,34197,34208,34187,34211,34171,34212,34202,34206,34167,34172,34185,34209,34170,34168,34135,34190,34198,34182,34189,34201,34205,34177,34210,34178,34184,34181,34169,34166,34200,34192,34207,34408,34750,34730,34733,34757,34736,34732,34745,34741,34748,34734,34761,34755,34754,34764,34743,34735,34756,34762,34740,34742,34751,34744,34749,34782,34738,35125,35123,35132,35134,35137,35154,35127,35138,35245,35247,35246,35314,35315,35614,35608,35606,35601,35589,35595,35618,35599,35602,35605,35591,35597,35592,35590,35612,35603,35610,35919,35952,35954,35953,35951,35989,35988,36089,36207,36430,36429,36435,36432,36428,36423,36675,36672,36997,36990,37176,37274,37282,37275,37273,37279,37281,37277,37280,37793,37763,37807,37732,37718,37703,37756,37720,37724,37750,37705,37712,37713,37728,37741,37775,37708,37738,37753,37719,37717,37714,37711,37745,37751,37755,37729,37726,37731,37735,37760,37710,37721,38343,38336,38345,38339,38341,38327,38574,38576,38572,38688,38687,38680,38685,38681,38810,38817,38812,38814,38813,38869,38868,38897,38977,38980,38986,38985,38981,38979,39205,39211,39212,39210,39219,39218,39215,39213,39217,39216,39320,39331,39329,39426,39418,39412,39415,39417,39416,39414,39419,39421,39422,39420,39427,39614,39678,39677,39681,39676,39752,39834,39848,39838,39835,39846,39841,39845,39844,39814,39842,39840,39855,40243,40257,40295,40246,40238,40239,40241,40248,40240,40261,40258,40259,40254,40247,40256,40253,32757,40237,40586,40585,40589,40624,40648,40666,40699,40703,40740,40739,40738,40788,40864,20785,20781,20782,22168,22172,22167,22170,22173,22169,22896,23356,23657,23658,24000,24173,24174,25048,25055,25069,25070,25073,25066,25072,25067,25046,25065,25855,25860,25853,25848,25857,25859,25852,26004,26075,26330,26331,26328,27333,27321,27325,27361,27334,27322,27318,27319,27335,27316,27309,27486,27593,27659,28679,28684,28685,28673,28677,28692,28686,28671,28672,28667,28710,28668,28663,28682,29185,29183,29177,29187,29181,29558,29880,29888,29877,29889,29886,29878,29883,29890,29972,29971,30300,30308,30297,30288,30291,30295,30298,30374,30397,30444,30658,30650,30975,30988,30995,30996,30985,30992,30994,30993,31149,31148,31327,31772,31785,31769,31776,31775,31789,31773,31782,31784,31778,31781,31792,32348,32336,32342,32355,32344,32354,32351,32337,32352,32343,32339,32693,32691,32759,32760,32885,33233,33234,33232,33375,33374,34228,34246,34240,34243,34242,34227,34229,34237,34247,34244,34239,34251,34254,34248,34245,34225,34230,34258,34340,34232,34231,34238,34409,34791,34790,34786,34779,34795,34794,34789,34783,34803,34788,34772,34780,34771,34797,34776,34787,34724,34775,34777,34817,34804,34792,34781,35155,35147,35151,35148,35142,35152,35153,35145,35626,35623,35619,35635,35632,35637,35655,35631,35644,35646,35633,35621,35639,35622,35638,35630,35620,35643,35645,35642,35906,35957,35993,35992,35991,36094,36100,36098,36096,36444,36450,36448,36439,36438,36446,36453,36455,36443,36442,36449,36445,36457,36436,36678,36679,36680,36683,37160,37178,37179,37182,37288,37285,37287,37295,37290,37813,37772,37778,37815,37787,37789,37769,37799,37774,37802,37790,37798,37781,37768,37785,37791,37773,37809,37777,37810,37796,37800,37812,37795,37797,38354,38355,38353,38579,38615,38618,24002,38623,38616,38621,38691,38690,38693,38828,38830,38824,38827,38820,38826,38818,38821,38871,38873,38870,38872,38906,38992,38993,38994,39096,39233,39228,39226,39439,39435,39433,39437,39428,39441,39434,39429,39431,39430,39616,39644,39688,39684,39685,39721,39733,39754,39756,39755,39879,39878,39875,39871,39873,39861,39864,39891,39862,39876,39865,39869,40284,40275,40271,40266,40283,40267,40281,40278,40268,40279,40274,40276,40287,40280,40282,40590,40588,40671,40705,40704,40726,40741,40747,40746,40745,40744,40780,40789,20788,20789,21142,21239,21428,22187,22189,22182,22183,22186,22188,22746,22749,22747,22802,23357,23358,23359,24003,24176,24511,25083,25863,25872,25869,25865,25868,25870,25988,26078,26077,26334,27367,27360,27340,27345,27353,27339,27359,27356,27344,27371,27343,27341,27358,27488,27568,27660,28697,28711,28704,28694,28715,28705,28706,28707,28713,28695,28708,28700,28714,29196,29194,29191,29186,29189,29349,29350,29348,29347,29345,29899,29893,29879,29891,29974,30304,30665,30666,30660,30705,31005,31003,31009,31004,30999,31006,31152,31335,31336,31795,31804,31801,31788,31803,31980,31978,32374,32373,32376,32368,32375,32367,32378,32370,32372,32360,32587,32586,32643,32646,32695,32765,32766,32888,33239,33237,33380,33377,33379,34283,34289,34285,34265,34273,34280,34266,34263,34284,34290,34296,34264,34271,34275,34268,34257,34288,34278,34287,34270,34274,34816,34810,34819,34806,34807,34825,34828,34827,34822,34812,34824,34815,34826,34818,35170,35162,35163,35159,35169,35164,35160,35165,35161,35208,35255,35254,35318,35664,35656,35658,35648,35667,35670,35668,35659,35669,35665,35650,35666,35671,35907,35959,35958,35994,36102,36103,36105,36268,36266,36269,36267,36461,36472,36467,36458,36463,36475,36546,36690,36689,36687,36688,36691,36788,37184,37183,37296,37293,37854,37831,37839,37826,37850,37840,37881,37868,37836,37849,37801,37862,37834,37844,37870,37859,37845,37828,37838,37824,37842,37863,38269,38362,38363,38625,38697,38699,38700,38696,38694,38835,38839,38838,38877,38878,38879,39004,39001,39005,38999,39103,39101,39099,39102,39240,39239,39235,39334,39335,39450,39445,39461,39453,39460,39451,39458,39456,39463,39459,39454,39452,39444,39618,39691,39690,39694,39692,39735,39914,39915,39904,39902,39908,39910,39906,39920,39892,39895,39916,39900,39897,39909,39893,39905,39898,40311,40321,40330,40324,40328,40305,40320,40312,40326,40331,40332,40317,40299,40308,40309,40304,40297,40325,40307,40315,40322,40303,40313,40319,40327,40296,40596,40593,40640,40700,40749,40768,40769,40781,40790,40791,40792,21303,22194,22197,22195,22755,23365,24006,24007,24302,24303,24512,24513,25081,25879,25878,25877,25875,26079,26344,26339,26340,27379,27376,27370,27368,27385,27377,27374,27375,28732,28725,28719,28727,28724,28721,28738,28728,28735,28730,28729,28736,28731,28723,28737,29203,29204,29352,29565,29564,29882,30379,30378,30398,30445,30668,30670,30671,30669,30706,31013,31011,31015,31016,31012,31017,31154,31342,31340,31341,31479,31817,31816,31818,31815,31813,31982,32379,32382,32385,32384,32698,32767,32889,33243,33241,33291,33384,33385,34338,34303,34305,34302,34331,34304,34294,34308,34313,34309,34316,34301,34841,34832,34833,34839,34835,34838,35171,35174,35257,35319,35680,35690,35677,35688,35683,35685,35687,35693,36270,36486,36488,36484,36697,36694,36695,36693,36696,36698,37005,37187,37185,37303,37301,37298,37299,37899,37907,37883,37920,37903,37908,37886,37909,37904,37928,37913,37901,37877,37888,37879,37895,37902,37910,37906,37882,37897,37880,37898,37887,37884,37900,37878,37905,37894,38366,38368,38367,38702,38703,38841,38843,38909,38910,39008,39010,39011,39007,39105,39106,39248,39246,39257,39244,39243,39251,39474,39476,39473,39468,39466,39478,39465,39470,39480,39469,39623,39626,39622,39696,39698,39697,39947,39944,39927,39941,39954,39928,40000,39943,39950,39942,39959,39956,39945,40351,40345,40356,40349,40338,40344,40336,40347,40352,40340,40348,40362,40343,40353,40346,40354,40360,40350,40355,40383,40361,40342,40358,40359,40601,40603,40602,40677,40676,40679,40678,40752,40750,40795,40800,40798,40797,40793,40849,20794,20793,21144,21143,22211,22205,22206,23368,23367,24011,24015,24305,25085,25883,27394,27388,27395,27384,27392,28739,28740,28746,28744,28745,28741,28742,29213,29210,29209,29566,29975,30314,30672,31021,31025,31023,31828,31827,31986,32394,32391,32392,32395,32390,32397,32589,32699,32816,33245,34328,34346,34342,34335,34339,34332,34329,34343,34350,34337,34336,34345,34334,34341,34857,34845,34843,34848,34852,34844,34859,34890,35181,35177,35182,35179,35322,35705,35704,35653,35706,35707,36112,36116,36271,36494,36492,36702,36699,36701,37190,37188,37189,37305,37951,37947,37942,37929,37949,37948,37936,37945,37930,37943,37932,37952,37937,38373,38372,38371,38709,38714,38847,38881,39012,39113,39110,39104,39256,39254,39481,39485,39494,39492,39490,39489,39482,39487,39629,39701,39703,39704,39702,39738,39762,39979,39965,39964,39980,39971,39976,39977,39972,39969,40375,40374,40380,40385,40391,40394,40399,40382,40389,40387,40379,40373,40398,40377,40378,40364,40392,40369,40365,40396,40371,40397,40370,40570,40604,40683,40686,40685,40731,40728,40730,40753,40782,40805,40804,40850,20153,22214,22213,22219,22897,23371,23372,24021,24017,24306,25889,25888,25894,25890,27403,27400,27401,27661,28757,28758,28759,28754,29214,29215,29353,29567,29912,29909,29913,29911,30317,30381,31029,31156,31344,31345,31831,31836,31833,31835,31834,31988,31985,32401,32591,32647,33246,33387,34356,34357,34355,34348,34354,34358,34860,34856,34854,34858,34853,35185,35263,35262,35323,35710,35716,35714,35718,35717,35711,36117,36501,36500,36506,36498,36496,36502,36503,36704,36706,37191,37964,37968,37962,37963,37967,37959,37957,37960,37961,37958,38719,38883,39018,39017,39115,39252,39259,39502,39507,39508,39500,39503,39496,39498,39497,39506,39504,39632,39705,39723,39739,39766,39765,40006,40008,39999,40004,39993,39987,40001,39996,39991,39988,39986,39997,39990,40411,40402,40414,40410,40395,40400,40412,40401,40415,40425,40409,40408,40406,40437,40405,40413,40630,40688,40757,40755,40754,40770,40811,40853,40866,20797,21145,22760,22759,22898,23373,24024,34863,24399,25089,25091,25092,25897,25893,26006,26347,27409,27410,27407,27594,28763,28762,29218,29570,29569,29571,30320,30676,31847,31846,32405,33388,34362,34368,34361,34364,34353,34363,34366,34864,34866,34862,34867,35190,35188,35187,35326,35724,35726,35723,35720,35909,36121,36504,36708,36707,37308,37986,37973,37981,37975,37982,38852,38853,38912,39510,39513,39710,39711,39712,40018,40024,40016,40010,40013,40011,40021,40025,40012,40014,40443,40439,40431,40419,40427,40440,40420,40438,40417,40430,40422,40434,40432,40418,40428,40436,40435,40424,40429,40642,40656,40690,40691,40710,40732,40760,40759,40758,40771,40783,40817,40816,40814,40815,22227,22221,23374,23661,25901,26349,26350,27411,28767,28769,28765,28768,29219,29915,29925,30677,31032,31159,31158,31850,32407,32649,33389,34371,34872,34871,34869,34891,35732,35733,36510,36511,36512,36509,37310,37309,37314,37995,37992,37993,38629,38726,38723,38727,38855,38885,39518,39637,39769,40035,40039,40038,40034,40030,40032,40450,40446,40455,40451,40454,40453,40448,40449,40457,40447,40445,40452,40608,40734,40774,40820,40821,40822,22228,25902,26040,27416,27417,27415,27418,28770,29222,29354,30680,30681,31033,31849,31851,31990,32410,32408,32411,32409,33248,33249,34374,34375,34376,35193,35194,35196,35195,35327,35736,35737,36517,36516,36515,37998,37997,37999,38001,38003,38729,39026,39263,40040,40046,40045,40459,40461,40464,40463,40466,40465,40609,40693,40713,40775,40824,40827,40826,40825,22302,28774,31855,34876,36274,36518,37315,38004,38008,38006,38005,39520,40052,40051,40049,40053,40468,40467,40694,40714,40868,28776,28773,31991,34410,34878,34877,34879,35742,35996,36521,36553,38731,39027,39028,39116,39265,39339,39524,39526,39527,39716,40469,40471,40776,25095,27422,29223,34380,36520,38018,38016,38017,39529,39528,39726,40473,29225,34379,35743,38019,40057,40631,30325,39531,40058,40477,28777,28778,40612,40830,40777,40856,30849,37561,35023,22715,24658,31911,23290,9556,9574,9559,9568,9580,9571,9562,9577,9565,9554,9572,9557,9566,9578,9569,9560,9575,9563,9555,9573,9558,9567,9579,9570,9561,9576,9564,9553,9552,9581,9582,9584,9583,65517,132423,37595,132575,147397,34124,17077,29679,20917,13897,149826,166372,37700,137691,33518,146632,30780,26436,25311,149811,166314,131744,158643,135941,20395,140525,20488,159017,162436,144896,150193,140563,20521,131966,24484,131968,131911,28379,132127,20605,20737,13434,20750,39020,14147,33814,149924,132231,20832,144308,20842,134143,139516,131813,140592,132494,143923,137603,23426,34685,132531,146585,20914,20920,40244,20937,20943,20945,15580,20947,150182,20915,20962,21314,20973,33741,26942,145197,24443,21003,21030,21052,21173,21079,21140,21177,21189,31765,34114,21216,34317,158483,21253,166622,21833,28377,147328,133460,147436,21299,21316,134114,27851,136998,26651,29653,24650,16042,14540,136936,29149,17570,21357,21364,165547,21374,21375,136598,136723,30694,21395,166555,21408,21419,21422,29607,153458,16217,29596,21441,21445,27721,20041,22526,21465,15019,134031,21472,147435,142755,21494,134263,21523,28793,21803,26199,27995,21613,158547,134516,21853,21647,21668,18342,136973,134877,15796,134477,166332,140952,21831,19693,21551,29719,21894,21929,22021,137431,147514,17746,148533,26291,135348,22071,26317,144010,26276,26285,22093,22095,30961,22257,38791,21502,22272,22255,22253,166758,13859,135759,22342,147877,27758,28811,22338,14001,158846,22502,136214,22531,136276,148323,22566,150517,22620,22698,13665,22752,22748,135740,22779,23551,22339,172368,148088,37843,13729,22815,26790,14019,28249,136766,23076,21843,136850,34053,22985,134478,158849,159018,137180,23001,137211,137138,159142,28017,137256,136917,23033,159301,23211,23139,14054,149929,23159,14088,23190,29797,23251,159649,140628,15749,137489,14130,136888,24195,21200,23414,25992,23420,162318,16388,18525,131588,23509,24928,137780,154060,132517,23539,23453,19728,23557,138052,23571,29646,23572,138405,158504,23625,18653,23685,23785,23791,23947,138745,138807,23824,23832,23878,138916,23738,24023,33532,14381,149761,139337,139635,33415,14390,15298,24110,27274,24181,24186,148668,134355,21414,20151,24272,21416,137073,24073,24308,164994,24313,24315,14496,24316,26686,37915,24333,131521,194708,15070,18606,135994,24378,157832,140240,24408,140401,24419,38845,159342,24434,37696,166454,24487,23990,15711,152144,139114,159992,140904,37334,131742,166441,24625,26245,137335,14691,15815,13881,22416,141236,31089,15936,24734,24740,24755,149890,149903,162387,29860,20705,23200,24932,33828,24898,194726,159442,24961,20980,132694,24967,23466,147383,141407,25043,166813,170333,25040,14642,141696,141505,24611,24924,25886,25483,131352,25285,137072,25301,142861,25452,149983,14871,25656,25592,136078,137212,25744,28554,142902,38932,147596,153373,25825,25829,38011,14950,25658,14935,25933,28438,150056,150051,25989,25965,25951,143486,26037,149824,19255,26065,16600,137257,26080,26083,24543,144384,26136,143863,143864,26180,143780,143781,26187,134773,26215,152038,26227,26228,138813,143921,165364,143816,152339,30661,141559,39332,26370,148380,150049,15147,27130,145346,26462,26471,26466,147917,168173,26583,17641,26658,28240,37436,26625,144358,159136,26717,144495,27105,27147,166623,26995,26819,144845,26881,26880,15666,14849,144956,15232,26540,26977,166474,17148,26934,27032,15265,132041,33635,20624,27129,144985,139562,27205,145155,27293,15347,26545,27336,168348,15373,27421,133411,24798,27445,27508,141261,28341,146139,132021,137560,14144,21537,146266,27617,147196,27612,27703,140427,149745,158545,27738,33318,27769,146876,17605,146877,147876,149772,149760,146633,14053,15595,134450,39811,143865,140433,32655,26679,159013,159137,159211,28054,27996,28284,28420,149887,147589,159346,34099,159604,20935,27804,28189,33838,166689,28207,146991,29779,147330,31180,28239,23185,143435,28664,14093,28573,146992,28410,136343,147517,17749,37872,28484,28508,15694,28532,168304,15675,28575,147780,28627,147601,147797,147513,147440,147380,147775,20959,147798,147799,147776,156125,28747,28798,28839,28801,28876,28885,28886,28895,16644,15848,29108,29078,148087,28971,28997,23176,29002,29038,23708,148325,29007,37730,148161,28972,148570,150055,150050,29114,166888,28861,29198,37954,29205,22801,37955,29220,37697,153093,29230,29248,149876,26813,29269,29271,15957,143428,26637,28477,29314,29482,29483,149539,165931,18669,165892,29480,29486,29647,29610,134202,158254,29641,29769,147938,136935,150052,26147,14021,149943,149901,150011,29687,29717,26883,150054,29753,132547,16087,29788,141485,29792,167602,29767,29668,29814,33721,29804,14128,29812,37873,27180,29826,18771,150156,147807,150137,166799,23366,166915,137374,29896,137608,29966,29929,29982,167641,137803,23511,167596,37765,30029,30026,30055,30062,151426,16132,150803,30094,29789,30110,30132,30210,30252,30289,30287,30319,30326,156661,30352,33263,14328,157969,157966,30369,30373,30391,30412,159647,33890,151709,151933,138780,30494,30502,30528,25775,152096,30552,144044,30639,166244,166248,136897,30708,30729,136054,150034,26826,30895,30919,30931,38565,31022,153056,30935,31028,30897,161292,36792,34948,166699,155779,140828,31110,35072,26882,31104,153687,31133,162617,31036,31145,28202,160038,16040,31174,168205,31188],
+ "euc-kr":[44034,44035,44037,44038,44043,44044,44045,44046,44047,44056,44062,44063,44065,44066,44067,44069,44070,44071,44072,44073,44074,44075,44078,44082,44083,44084,null,null,null,null,null,null,44085,44086,44087,44090,44091,44093,44094,44095,44097,44098,44099,44100,44101,44102,44103,44104,44105,44106,44108,44110,44111,44112,44113,44114,44115,44117,null,null,null,null,null,null,44118,44119,44121,44122,44123,44125,44126,44127,44128,44129,44130,44131,44132,44133,44134,44135,44136,44137,44138,44139,44140,44141,44142,44143,44146,44147,44149,44150,44153,44155,44156,44157,44158,44159,44162,44167,44168,44173,44174,44175,44177,44178,44179,44181,44182,44183,44184,44185,44186,44187,44190,44194,44195,44196,44197,44198,44199,44203,44205,44206,44209,44210,44211,44212,44213,44214,44215,44218,44222,44223,44224,44226,44227,44229,44230,44231,44233,44234,44235,44237,44238,44239,44240,44241,44242,44243,44244,44246,44248,44249,44250,44251,44252,44253,44254,44255,44258,44259,44261,44262,44265,44267,44269,44270,44274,44276,44279,44280,44281,44282,44283,44286,44287,44289,44290,44291,44293,44295,44296,44297,44298,44299,44302,44304,44306,44307,44308,44309,44310,44311,44313,44314,44315,44317,44318,44319,44321,44322,44323,44324,44325,44326,44327,44328,44330,44331,44334,44335,44336,44337,44338,44339,null,null,null,null,null,null,44342,44343,44345,44346,44347,44349,44350,44351,44352,44353,44354,44355,44358,44360,44362,44363,44364,44365,44366,44367,44369,44370,44371,44373,44374,44375,null,null,null,null,null,null,44377,44378,44379,44380,44381,44382,44383,44384,44386,44388,44389,44390,44391,44392,44393,44394,44395,44398,44399,44401,44402,44407,44408,44409,44410,44414,44416,44419,44420,44421,44422,44423,44426,44427,44429,44430,44431,44433,44434,44435,44436,44437,44438,44439,44440,44441,44442,44443,44446,44447,44448,44449,44450,44451,44453,44454,44455,44456,44457,44458,44459,44460,44461,44462,44463,44464,44465,44466,44467,44468,44469,44470,44472,44473,44474,44475,44476,44477,44478,44479,44482,44483,44485,44486,44487,44489,44490,44491,44492,44493,44494,44495,44498,44500,44501,44502,44503,44504,44505,44506,44507,44509,44510,44511,44513,44514,44515,44517,44518,44519,44520,44521,44522,44523,44524,44525,44526,44527,44528,44529,44530,44531,44532,44533,44534,44535,44538,44539,44541,44542,44546,44547,44548,44549,44550,44551,44554,44556,44558,44559,44560,44561,44562,44563,44565,44566,44567,44568,44569,44570,44571,44572,null,null,null,null,null,null,44573,44574,44575,44576,44577,44578,44579,44580,44581,44582,44583,44584,44585,44586,44587,44588,44589,44590,44591,44594,44595,44597,44598,44601,44603,44604,null,null,null,null,null,null,44605,44606,44607,44610,44612,44615,44616,44617,44619,44623,44625,44626,44627,44629,44631,44632,44633,44634,44635,44638,44642,44643,44644,44646,44647,44650,44651,44653,44654,44655,44657,44658,44659,44660,44661,44662,44663,44666,44670,44671,44672,44673,44674,44675,44678,44679,44680,44681,44682,44683,44685,44686,44687,44688,44689,44690,44691,44692,44693,44694,44695,44696,44697,44698,44699,44700,44701,44702,44703,44704,44705,44706,44707,44708,44709,44710,44711,44712,44713,44714,44715,44716,44717,44718,44719,44720,44721,44722,44723,44724,44725,44726,44727,44728,44729,44730,44731,44735,44737,44738,44739,44741,44742,44743,44744,44745,44746,44747,44750,44754,44755,44756,44757,44758,44759,44762,44763,44765,44766,44767,44768,44769,44770,44771,44772,44773,44774,44775,44777,44778,44780,44782,44783,44784,44785,44786,44787,44789,44790,44791,44793,44794,44795,44797,44798,44799,44800,44801,44802,44803,44804,44805,null,null,null,null,null,null,44806,44809,44810,44811,44812,44814,44815,44817,44818,44819,44820,44821,44822,44823,44824,44825,44826,44827,44828,44829,44830,44831,44832,44833,44834,44835,null,null,null,null,null,null,44836,44837,44838,44839,44840,44841,44842,44843,44846,44847,44849,44851,44853,44854,44855,44856,44857,44858,44859,44862,44864,44868,44869,44870,44871,44874,44875,44876,44877,44878,44879,44881,44882,44883,44884,44885,44886,44887,44888,44889,44890,44891,44894,44895,44896,44897,44898,44899,44902,44903,44904,44905,44906,44907,44908,44909,44910,44911,44912,44913,44914,44915,44916,44917,44918,44919,44920,44922,44923,44924,44925,44926,44927,44929,44930,44931,44933,44934,44935,44937,44938,44939,44940,44941,44942,44943,44946,44947,44948,44950,44951,44952,44953,44954,44955,44957,44958,44959,44960,44961,44962,44963,44964,44965,44966,44967,44968,44969,44970,44971,44972,44973,44974,44975,44976,44977,44978,44979,44980,44981,44982,44983,44986,44987,44989,44990,44991,44993,44994,44995,44996,44997,44998,45002,45004,45007,45008,45009,45010,45011,45013,45014,45015,45016,45017,45018,45019,45021,45022,45023,45024,45025,null,null,null,null,null,null,45026,45027,45028,45029,45030,45031,45034,45035,45036,45037,45038,45039,45042,45043,45045,45046,45047,45049,45050,45051,45052,45053,45054,45055,45058,45059,null,null,null,null,null,null,45061,45062,45063,45064,45065,45066,45067,45069,45070,45071,45073,45074,45075,45077,45078,45079,45080,45081,45082,45083,45086,45087,45088,45089,45090,45091,45092,45093,45094,45095,45097,45098,45099,45100,45101,45102,45103,45104,45105,45106,45107,45108,45109,45110,45111,45112,45113,45114,45115,45116,45117,45118,45119,45120,45121,45122,45123,45126,45127,45129,45131,45133,45135,45136,45137,45138,45142,45144,45146,45147,45148,45150,45151,45152,45153,45154,45155,45156,45157,45158,45159,45160,45161,45162,45163,45164,45165,45166,45167,45168,45169,45170,45171,45172,45173,45174,45175,45176,45177,45178,45179,45182,45183,45185,45186,45187,45189,45190,45191,45192,45193,45194,45195,45198,45200,45202,45203,45204,45205,45206,45207,45211,45213,45214,45219,45220,45221,45222,45223,45226,45232,45234,45238,45239,45241,45242,45243,45245,45246,45247,45248,45249,45250,45251,45254,45258,45259,45260,45261,45262,45263,45266,null,null,null,null,null,null,45267,45269,45270,45271,45273,45274,45275,45276,45277,45278,45279,45281,45282,45283,45284,45286,45287,45288,45289,45290,45291,45292,45293,45294,45295,45296,null,null,null,null,null,null,45297,45298,45299,45300,45301,45302,45303,45304,45305,45306,45307,45308,45309,45310,45311,45312,45313,45314,45315,45316,45317,45318,45319,45322,45325,45326,45327,45329,45332,45333,45334,45335,45338,45342,45343,45344,45345,45346,45350,45351,45353,45354,45355,45357,45358,45359,45360,45361,45362,45363,45366,45370,45371,45372,45373,45374,45375,45378,45379,45381,45382,45383,45385,45386,45387,45388,45389,45390,45391,45394,45395,45398,45399,45401,45402,45403,45405,45406,45407,45409,45410,45411,45412,45413,45414,45415,45416,45417,45418,45419,45420,45421,45422,45423,45424,45425,45426,45427,45428,45429,45430,45431,45434,45435,45437,45438,45439,45441,45443,45444,45445,45446,45447,45450,45452,45454,45455,45456,45457,45461,45462,45463,45465,45466,45467,45469,45470,45471,45472,45473,45474,45475,45476,45477,45478,45479,45481,45482,45483,45484,45485,45486,45487,45488,45489,45490,45491,45492,45493,45494,45495,45496,null,null,null,null,null,null,45497,45498,45499,45500,45501,45502,45503,45504,45505,45506,45507,45508,45509,45510,45511,45512,45513,45514,45515,45517,45518,45519,45521,45522,45523,45525,null,null,null,null,null,null,45526,45527,45528,45529,45530,45531,45534,45536,45537,45538,45539,45540,45541,45542,45543,45546,45547,45549,45550,45551,45553,45554,45555,45556,45557,45558,45559,45560,45562,45564,45566,45567,45568,45569,45570,45571,45574,45575,45577,45578,45581,45582,45583,45584,45585,45586,45587,45590,45592,45594,45595,45596,45597,45598,45599,45601,45602,45603,45604,45605,45606,45607,45608,45609,45610,45611,45612,45613,45614,45615,45616,45617,45618,45619,45621,45622,45623,45624,45625,45626,45627,45629,45630,45631,45632,45633,45634,45635,45636,45637,45638,45639,45640,45641,45642,45643,45644,45645,45646,45647,45648,45649,45650,45651,45652,45653,45654,45655,45657,45658,45659,45661,45662,45663,45665,45666,45667,45668,45669,45670,45671,45674,45675,45676,45677,45678,45679,45680,45681,45682,45683,45686,45687,45688,45689,45690,45691,45693,45694,45695,45696,45697,45698,45699,45702,45703,45704,45706,45707,45708,45709,45710,null,null,null,null,null,null,45711,45714,45715,45717,45718,45719,45723,45724,45725,45726,45727,45730,45732,45735,45736,45737,45739,45741,45742,45743,45745,45746,45747,45749,45750,45751,null,null,null,null,null,null,45752,45753,45754,45755,45756,45757,45758,45759,45760,45761,45762,45763,45764,45765,45766,45767,45770,45771,45773,45774,45775,45777,45779,45780,45781,45782,45783,45786,45788,45790,45791,45792,45793,45795,45799,45801,45802,45808,45809,45810,45814,45820,45821,45822,45826,45827,45829,45830,45831,45833,45834,45835,45836,45837,45838,45839,45842,45846,45847,45848,45849,45850,45851,45853,45854,45855,45856,45857,45858,45859,45860,45861,45862,45863,45864,45865,45866,45867,45868,45869,45870,45871,45872,45873,45874,45875,45876,45877,45878,45879,45880,45881,45882,45883,45884,45885,45886,45887,45888,45889,45890,45891,45892,45893,45894,45895,45896,45897,45898,45899,45900,45901,45902,45903,45904,45905,45906,45907,45911,45913,45914,45917,45920,45921,45922,45923,45926,45928,45930,45932,45933,45935,45938,45939,45941,45942,45943,45945,45946,45947,45948,45949,45950,45951,45954,45958,45959,45960,45961,45962,45963,45965,null,null,null,null,null,null,45966,45967,45969,45970,45971,45973,45974,45975,45976,45977,45978,45979,45980,45981,45982,45983,45986,45987,45988,45989,45990,45991,45993,45994,45995,45997,null,null,null,null,null,null,45998,45999,46000,46001,46002,46003,46004,46005,46006,46007,46008,46009,46010,46011,46012,46013,46014,46015,46016,46017,46018,46019,46022,46023,46025,46026,46029,46031,46033,46034,46035,46038,46040,46042,46044,46046,46047,46049,46050,46051,46053,46054,46055,46057,46058,46059,46060,46061,46062,46063,46064,46065,46066,46067,46068,46069,46070,46071,46072,46073,46074,46075,46077,46078,46079,46080,46081,46082,46083,46084,46085,46086,46087,46088,46089,46090,46091,46092,46093,46094,46095,46097,46098,46099,46100,46101,46102,46103,46105,46106,46107,46109,46110,46111,46113,46114,46115,46116,46117,46118,46119,46122,46124,46125,46126,46127,46128,46129,46130,46131,46133,46134,46135,46136,46137,46138,46139,46140,46141,46142,46143,46144,46145,46146,46147,46148,46149,46150,46151,46152,46153,46154,46155,46156,46157,46158,46159,46162,46163,46165,46166,46167,46169,46170,46171,46172,46173,46174,46175,46178,46180,46182,null,null,null,null,null,null,46183,46184,46185,46186,46187,46189,46190,46191,46192,46193,46194,46195,46196,46197,46198,46199,46200,46201,46202,46203,46204,46205,46206,46207,46209,46210,null,null,null,null,null,null,46211,46212,46213,46214,46215,46217,46218,46219,46220,46221,46222,46223,46224,46225,46226,46227,46228,46229,46230,46231,46232,46233,46234,46235,46236,46238,46239,46240,46241,46242,46243,46245,46246,46247,46249,46250,46251,46253,46254,46255,46256,46257,46258,46259,46260,46262,46264,46266,46267,46268,46269,46270,46271,46273,46274,46275,46277,46278,46279,46281,46282,46283,46284,46285,46286,46287,46289,46290,46291,46292,46294,46295,46296,46297,46298,46299,46302,46303,46305,46306,46309,46311,46312,46313,46314,46315,46318,46320,46322,46323,46324,46325,46326,46327,46329,46330,46331,46332,46333,46334,46335,46336,46337,46338,46339,46340,46341,46342,46343,46344,46345,46346,46347,46348,46349,46350,46351,46352,46353,46354,46355,46358,46359,46361,46362,46365,46366,46367,46368,46369,46370,46371,46374,46379,46380,46381,46382,46383,46386,46387,46389,46390,46391,46393,46394,46395,46396,46397,46398,46399,46402,46406,null,null,null,null,null,null,46407,46408,46409,46410,46414,46415,46417,46418,46419,46421,46422,46423,46424,46425,46426,46427,46430,46434,46435,46436,46437,46438,46439,46440,46441,46442,null,null,null,null,null,null,46443,46444,46445,46446,46447,46448,46449,46450,46451,46452,46453,46454,46455,46456,46457,46458,46459,46460,46461,46462,46463,46464,46465,46466,46467,46468,46469,46470,46471,46472,46473,46474,46475,46476,46477,46478,46479,46480,46481,46482,46483,46484,46485,46486,46487,46488,46489,46490,46491,46492,46493,46494,46495,46498,46499,46501,46502,46503,46505,46508,46509,46510,46511,46514,46518,46519,46520,46521,46522,46526,46527,46529,46530,46531,46533,46534,46535,46536,46537,46538,46539,46542,46546,46547,46548,46549,46550,46551,46553,46554,46555,46556,46557,46558,46559,46560,46561,46562,46563,46564,46565,46566,46567,46568,46569,46570,46571,46573,46574,46575,46576,46577,46578,46579,46580,46581,46582,46583,46584,46585,46586,46587,46588,46589,46590,46591,46592,46593,46594,46595,46596,46597,46598,46599,46600,46601,46602,46603,46604,46605,46606,46607,46610,46611,46613,46614,46615,46617,46618,46619,46620,46621,null,null,null,null,null,null,46622,46623,46624,46625,46626,46627,46628,46630,46631,46632,46633,46634,46635,46637,46638,46639,46640,46641,46642,46643,46645,46646,46647,46648,46649,46650,null,null,null,null,null,null,46651,46652,46653,46654,46655,46656,46657,46658,46659,46660,46661,46662,46663,46665,46666,46667,46668,46669,46670,46671,46672,46673,46674,46675,46676,46677,46678,46679,46680,46681,46682,46683,46684,46685,46686,46687,46688,46689,46690,46691,46693,46694,46695,46697,46698,46699,46700,46701,46702,46703,46704,46705,46706,46707,46708,46709,46710,46711,46712,46713,46714,46715,46716,46717,46718,46719,46720,46721,46722,46723,46724,46725,46726,46727,46728,46729,46730,46731,46732,46733,46734,46735,46736,46737,46738,46739,46740,46741,46742,46743,46744,46745,46746,46747,46750,46751,46753,46754,46755,46757,46758,46759,46760,46761,46762,46765,46766,46767,46768,46770,46771,46772,46773,46774,46775,46776,46777,46778,46779,46780,46781,46782,46783,46784,46785,46786,46787,46788,46789,46790,46791,46792,46793,46794,46795,46796,46797,46798,46799,46800,46801,46802,46803,46805,46806,46807,46808,46809,46810,46811,46812,46813,null,null,null,null,null,null,46814,46815,46816,46817,46818,46819,46820,46821,46822,46823,46824,46825,46826,46827,46828,46829,46830,46831,46833,46834,46835,46837,46838,46839,46841,46842,null,null,null,null,null,null,46843,46844,46845,46846,46847,46850,46851,46852,46854,46855,46856,46857,46858,46859,46860,46861,46862,46863,46864,46865,46866,46867,46868,46869,46870,46871,46872,46873,46874,46875,46876,46877,46878,46879,46880,46881,46882,46883,46884,46885,46886,46887,46890,46891,46893,46894,46897,46898,46899,46900,46901,46902,46903,46906,46908,46909,46910,46911,46912,46913,46914,46915,46917,46918,46919,46921,46922,46923,46925,46926,46927,46928,46929,46930,46931,46934,46935,46936,46937,46938,46939,46940,46941,46942,46943,46945,46946,46947,46949,46950,46951,46953,46954,46955,46956,46957,46958,46959,46962,46964,46966,46967,46968,46969,46970,46971,46974,46975,46977,46978,46979,46981,46982,46983,46984,46985,46986,46987,46990,46995,46996,46997,47002,47003,47005,47006,47007,47009,47010,47011,47012,47013,47014,47015,47018,47022,47023,47024,47025,47026,47027,47030,47031,47033,47034,47035,47036,47037,47038,47039,47040,47041,null,null,null,null,null,null,47042,47043,47044,47045,47046,47048,47050,47051,47052,47053,47054,47055,47056,47057,47058,47059,47060,47061,47062,47063,47064,47065,47066,47067,47068,47069,null,null,null,null,null,null,47070,47071,47072,47073,47074,47075,47076,47077,47078,47079,47080,47081,47082,47083,47086,47087,47089,47090,47091,47093,47094,47095,47096,47097,47098,47099,47102,47106,47107,47108,47109,47110,47114,47115,47117,47118,47119,47121,47122,47123,47124,47125,47126,47127,47130,47132,47134,47135,47136,47137,47138,47139,47142,47143,47145,47146,47147,47149,47150,47151,47152,47153,47154,47155,47158,47162,47163,47164,47165,47166,47167,47169,47170,47171,47173,47174,47175,47176,47177,47178,47179,47180,47181,47182,47183,47184,47186,47188,47189,47190,47191,47192,47193,47194,47195,47198,47199,47201,47202,47203,47205,47206,47207,47208,47209,47210,47211,47214,47216,47218,47219,47220,47221,47222,47223,47225,47226,47227,47229,47230,47231,47232,47233,47234,47235,47236,47237,47238,47239,47240,47241,47242,47243,47244,47246,47247,47248,47249,47250,47251,47252,47253,47254,47255,47256,47257,47258,47259,47260,47261,47262,47263,null,null,null,null,null,null,47264,47265,47266,47267,47268,47269,47270,47271,47273,47274,47275,47276,47277,47278,47279,47281,47282,47283,47285,47286,47287,47289,47290,47291,47292,47293,null,null,null,null,null,null,47294,47295,47298,47300,47302,47303,47304,47305,47306,47307,47309,47310,47311,47313,47314,47315,47317,47318,47319,47320,47321,47322,47323,47324,47326,47328,47330,47331,47332,47333,47334,47335,47338,47339,47341,47342,47343,47345,47346,47347,47348,47349,47350,47351,47354,47356,47358,47359,47360,47361,47362,47363,47365,47366,47367,47368,47369,47370,47371,47372,47373,47374,47375,47376,47377,47378,47379,47380,47381,47382,47383,47385,47386,47387,47388,47389,47390,47391,47393,47394,47395,47396,47397,47398,47399,47400,47401,47402,47403,47404,47405,47406,47407,47408,47409,47410,47411,47412,47413,47414,47415,47416,47417,47418,47419,47422,47423,47425,47426,47427,47429,47430,47431,47432,47433,47434,47435,47437,47438,47440,47442,47443,47444,47445,47446,47447,47450,47451,47453,47454,47455,47457,47458,47459,47460,47461,47462,47463,47466,47468,47470,47471,47472,47473,47474,47475,47478,47479,47481,47482,47483,47485,null,null,null,null,null,null,47486,47487,47488,47489,47490,47491,47494,47496,47499,47500,47503,47504,47505,47506,47507,47508,47509,47510,47511,47512,47513,47514,47515,47516,47517,47518,null,null,null,null,null,null,47519,47520,47521,47522,47523,47524,47525,47526,47527,47528,47529,47530,47531,47534,47535,47537,47538,47539,47541,47542,47543,47544,47545,47546,47547,47550,47552,47554,47555,47556,47557,47558,47559,47562,47563,47565,47571,47572,47573,47574,47575,47578,47580,47583,47584,47586,47590,47591,47593,47594,47595,47597,47598,47599,47600,47601,47602,47603,47606,47611,47612,47613,47614,47615,47618,47619,47620,47621,47622,47623,47625,47626,47627,47628,47629,47630,47631,47632,47633,47634,47635,47636,47638,47639,47640,47641,47642,47643,47644,47645,47646,47647,47648,47649,47650,47651,47652,47653,47654,47655,47656,47657,47658,47659,47660,47661,47662,47663,47664,47665,47666,47667,47668,47669,47670,47671,47674,47675,47677,47678,47679,47681,47683,47684,47685,47686,47687,47690,47692,47695,47696,47697,47698,47702,47703,47705,47706,47707,47709,47710,47711,47712,47713,47714,47715,47718,47722,47723,47724,47725,47726,47727,null,null,null,null,null,null,47730,47731,47733,47734,47735,47737,47738,47739,47740,47741,47742,47743,47744,47745,47746,47750,47752,47753,47754,47755,47757,47758,47759,47760,47761,47762,null,null,null,null,null,null,47763,47764,47765,47766,47767,47768,47769,47770,47771,47772,47773,47774,47775,47776,47777,47778,47779,47780,47781,47782,47783,47786,47789,47790,47791,47793,47795,47796,47797,47798,47799,47802,47804,47806,47807,47808,47809,47810,47811,47813,47814,47815,47817,47818,47819,47820,47821,47822,47823,47824,47825,47826,47827,47828,47829,47830,47831,47834,47835,47836,47837,47838,47839,47840,47841,47842,47843,47844,47845,47846,47847,47848,47849,47850,47851,47852,47853,47854,47855,47856,47857,47858,47859,47860,47861,47862,47863,47864,47865,47866,47867,47869,47870,47871,47873,47874,47875,47877,47878,47879,47880,47881,47882,47883,47884,47886,47888,47890,47891,47892,47893,47894,47895,47897,47898,47899,47901,47902,47903,47905,47906,47907,47908,47909,47910,47911,47912,47914,47916,47917,47918,47919,47920,47921,47922,47923,47927,47929,47930,47935,47936,47937,47938,47939,47942,47944,47946,47947,47948,47950,47953,47954,null,null,null,null,null,null,47955,47957,47958,47959,47961,47962,47963,47964,47965,47966,47967,47968,47970,47972,47973,47974,47975,47976,47977,47978,47979,47981,47982,47983,47984,47985,null,null,null,null,null,null,47986,47987,47988,47989,47990,47991,47992,47993,47994,47995,47996,47997,47998,47999,48000,48001,48002,48003,48004,48005,48006,48007,48009,48010,48011,48013,48014,48015,48017,48018,48019,48020,48021,48022,48023,48024,48025,48026,48027,48028,48029,48030,48031,48032,48033,48034,48035,48037,48038,48039,48041,48042,48043,48045,48046,48047,48048,48049,48050,48051,48053,48054,48056,48057,48058,48059,48060,48061,48062,48063,48065,48066,48067,48069,48070,48071,48073,48074,48075,48076,48077,48078,48079,48081,48082,48084,48085,48086,48087,48088,48089,48090,48091,48092,48093,48094,48095,48096,48097,48098,48099,48100,48101,48102,48103,48104,48105,48106,48107,48108,48109,48110,48111,48112,48113,48114,48115,48116,48117,48118,48119,48122,48123,48125,48126,48129,48131,48132,48133,48134,48135,48138,48142,48144,48146,48147,48153,48154,48160,48161,48162,48163,48166,48168,48170,48171,48172,48174,48175,48178,48179,48181,null,null,null,null,null,null,48182,48183,48185,48186,48187,48188,48189,48190,48191,48194,48198,48199,48200,48202,48203,48206,48207,48209,48210,48211,48212,48213,48214,48215,48216,48217,null,null,null,null,null,null,48218,48219,48220,48222,48223,48224,48225,48226,48227,48228,48229,48230,48231,48232,48233,48234,48235,48236,48237,48238,48239,48240,48241,48242,48243,48244,48245,48246,48247,48248,48249,48250,48251,48252,48253,48254,48255,48256,48257,48258,48259,48262,48263,48265,48266,48269,48271,48272,48273,48274,48275,48278,48280,48283,48284,48285,48286,48287,48290,48291,48293,48294,48297,48298,48299,48300,48301,48302,48303,48306,48310,48311,48312,48313,48314,48315,48318,48319,48321,48322,48323,48325,48326,48327,48328,48329,48330,48331,48332,48334,48338,48339,48340,48342,48343,48345,48346,48347,48349,48350,48351,48352,48353,48354,48355,48356,48357,48358,48359,48360,48361,48362,48363,48364,48365,48366,48367,48368,48369,48370,48371,48375,48377,48378,48379,48381,48382,48383,48384,48385,48386,48387,48390,48392,48394,48395,48396,48397,48398,48399,48401,48402,48403,48405,48406,48407,48408,48409,48410,48411,48412,48413,null,null,null,null,null,null,48414,48415,48416,48417,48418,48419,48421,48422,48423,48424,48425,48426,48427,48429,48430,48431,48432,48433,48434,48435,48436,48437,48438,48439,48440,48441,null,null,null,null,null,null,48442,48443,48444,48445,48446,48447,48449,48450,48451,48452,48453,48454,48455,48458,48459,48461,48462,48463,48465,48466,48467,48468,48469,48470,48471,48474,48475,48476,48477,48478,48479,48480,48481,48482,48483,48485,48486,48487,48489,48490,48491,48492,48493,48494,48495,48496,48497,48498,48499,48500,48501,48502,48503,48504,48505,48506,48507,48508,48509,48510,48511,48514,48515,48517,48518,48523,48524,48525,48526,48527,48530,48532,48534,48535,48536,48539,48541,48542,48543,48544,48545,48546,48547,48549,48550,48551,48552,48553,48554,48555,48556,48557,48558,48559,48561,48562,48563,48564,48565,48566,48567,48569,48570,48571,48572,48573,48574,48575,48576,48577,48578,48579,48580,48581,48582,48583,48584,48585,48586,48587,48588,48589,48590,48591,48592,48593,48594,48595,48598,48599,48601,48602,48603,48605,48606,48607,48608,48609,48610,48611,48612,48613,48614,48615,48616,48618,48619,48620,48621,48622,48623,48625,null,null,null,null,null,null,48626,48627,48629,48630,48631,48633,48634,48635,48636,48637,48638,48639,48641,48642,48644,48646,48647,48648,48649,48650,48651,48654,48655,48657,48658,48659,null,null,null,null,null,null,48661,48662,48663,48664,48665,48666,48667,48670,48672,48673,48674,48675,48676,48677,48678,48679,48680,48681,48682,48683,48684,48685,48686,48687,48688,48689,48690,48691,48692,48693,48694,48695,48696,48697,48698,48699,48700,48701,48702,48703,48704,48705,48706,48707,48710,48711,48713,48714,48715,48717,48719,48720,48721,48722,48723,48726,48728,48732,48733,48734,48735,48738,48739,48741,48742,48743,48745,48747,48748,48749,48750,48751,48754,48758,48759,48760,48761,48762,48766,48767,48769,48770,48771,48773,48774,48775,48776,48777,48778,48779,48782,48786,48787,48788,48789,48790,48791,48794,48795,48796,48797,48798,48799,48800,48801,48802,48803,48804,48805,48806,48807,48809,48810,48811,48812,48813,48814,48815,48816,48817,48818,48819,48820,48821,48822,48823,48824,48825,48826,48827,48828,48829,48830,48831,48832,48833,48834,48835,48836,48837,48838,48839,48840,48841,48842,48843,48844,48845,48846,48847,48850,48851,null,null,null,null,null,null,48853,48854,48857,48858,48859,48860,48861,48862,48863,48865,48866,48870,48871,48872,48873,48874,48875,48877,48878,48879,48880,48881,48882,48883,48884,48885,null,null,null,null,null,null,48886,48887,48888,48889,48890,48891,48892,48893,48894,48895,48896,48898,48899,48900,48901,48902,48903,48906,48907,48908,48909,48910,48911,48912,48913,48914,48915,48916,48917,48918,48919,48922,48926,48927,48928,48929,48930,48931,48932,48933,48934,48935,48936,48937,48938,48939,48940,48941,48942,48943,48944,48945,48946,48947,48948,48949,48950,48951,48952,48953,48954,48955,48956,48957,48958,48959,48962,48963,48965,48966,48967,48969,48970,48971,48972,48973,48974,48975,48978,48979,48980,48982,48983,48984,48985,48986,48987,48988,48989,48990,48991,48992,48993,48994,48995,48996,48997,48998,48999,49000,49001,49002,49003,49004,49005,49006,49007,49008,49009,49010,49011,49012,49013,49014,49015,49016,49017,49018,49019,49020,49021,49022,49023,49024,49025,49026,49027,49028,49029,49030,49031,49032,49033,49034,49035,49036,49037,49038,49039,49040,49041,49042,49043,49045,49046,49047,49048,49049,49050,49051,49052,49053,null,null,null,null,null,null,49054,49055,49056,49057,49058,49059,49060,49061,49062,49063,49064,49065,49066,49067,49068,49069,49070,49071,49073,49074,49075,49076,49077,49078,49079,49080,null,null,null,null,null,null,49081,49082,49083,49084,49085,49086,49087,49088,49089,49090,49091,49092,49094,49095,49096,49097,49098,49099,49102,49103,49105,49106,49107,49109,49110,49111,49112,49113,49114,49115,49117,49118,49120,49122,49123,49124,49125,49126,49127,49128,49129,49130,49131,49132,49133,49134,49135,49136,49137,49138,49139,49140,49141,49142,49143,49144,49145,49146,49147,49148,49149,49150,49151,49152,49153,49154,49155,49156,49157,49158,49159,49160,49161,49162,49163,49164,49165,49166,49167,49168,49169,49170,49171,49172,49173,49174,49175,49176,49177,49178,49179,49180,49181,49182,49183,49184,49185,49186,49187,49188,49189,49190,49191,49192,49193,49194,49195,49196,49197,49198,49199,49200,49201,49202,49203,49204,49205,49206,49207,49208,49209,49210,49211,49213,49214,49215,49216,49217,49218,49219,49220,49221,49222,49223,49224,49225,49226,49227,49228,49229,49230,49231,49232,49234,49235,49236,49237,49238,49239,49241,49242,49243,null,null,null,null,null,null,49245,49246,49247,49249,49250,49251,49252,49253,49254,49255,49258,49259,49260,49261,49262,49263,49264,49265,49266,49267,49268,49269,49270,49271,49272,49273,null,null,null,null,null,null,49274,49275,49276,49277,49278,49279,49280,49281,49282,49283,49284,49285,49286,49287,49288,49289,49290,49291,49292,49293,49294,49295,49298,49299,49301,49302,49303,49305,49306,49307,49308,49309,49310,49311,49314,49316,49318,49319,49320,49321,49322,49323,49326,49329,49330,49335,49336,49337,49338,49339,49342,49346,49347,49348,49350,49351,49354,49355,49357,49358,49359,49361,49362,49363,49364,49365,49366,49367,49370,49374,49375,49376,49377,49378,49379,49382,49383,49385,49386,49387,49389,49390,49391,49392,49393,49394,49395,49398,49400,49402,49403,49404,49405,49406,49407,49409,49410,49411,49413,49414,49415,49417,49418,49419,49420,49421,49422,49423,49425,49426,49427,49428,49430,49431,49432,49433,49434,49435,49441,49442,49445,49448,49449,49450,49451,49454,49458,49459,49460,49461,49463,49466,49467,49469,49470,49471,49473,49474,49475,49476,49477,49478,49479,49482,49486,49487,49488,49489,49490,49491,49494,49495,null,null,null,null,null,null,49497,49498,49499,49501,49502,49503,49504,49505,49506,49507,49510,49514,49515,49516,49517,49518,49519,49521,49522,49523,49525,49526,49527,49529,49530,49531,null,null,null,null,null,null,49532,49533,49534,49535,49536,49537,49538,49539,49540,49542,49543,49544,49545,49546,49547,49551,49553,49554,49555,49557,49559,49560,49561,49562,49563,49566,49568,49570,49571,49572,49574,49575,49578,49579,49581,49582,49583,49585,49586,49587,49588,49589,49590,49591,49592,49593,49594,49595,49596,49598,49599,49600,49601,49602,49603,49605,49606,49607,49609,49610,49611,49613,49614,49615,49616,49617,49618,49619,49621,49622,49625,49626,49627,49628,49629,49630,49631,49633,49634,49635,49637,49638,49639,49641,49642,49643,49644,49645,49646,49647,49650,49652,49653,49654,49655,49656,49657,49658,49659,49662,49663,49665,49666,49667,49669,49670,49671,49672,49673,49674,49675,49678,49680,49682,49683,49684,49685,49686,49687,49690,49691,49693,49694,49697,49698,49699,49700,49701,49702,49703,49706,49708,49710,49712,49715,49717,49718,49719,49720,49721,49722,49723,49724,49725,49726,49727,49728,49729,49730,49731,49732,49733,null,null,null,null,null,null,49734,49735,49737,49738,49739,49740,49741,49742,49743,49746,49747,49749,49750,49751,49753,49754,49755,49756,49757,49758,49759,49761,49762,49763,49764,49766,null,null,null,null,null,null,49767,49768,49769,49770,49771,49774,49775,49777,49778,49779,49781,49782,49783,49784,49785,49786,49787,49790,49792,49794,49795,49796,49797,49798,49799,49802,49803,49804,49805,49806,49807,49809,49810,49811,49812,49813,49814,49815,49817,49818,49820,49822,49823,49824,49825,49826,49827,49830,49831,49833,49834,49835,49838,49839,49840,49841,49842,49843,49846,49848,49850,49851,49852,49853,49854,49855,49856,49857,49858,49859,49860,49861,49862,49863,49864,49865,49866,49867,49868,49869,49870,49871,49872,49873,49874,49875,49876,49877,49878,49879,49880,49881,49882,49883,49886,49887,49889,49890,49893,49894,49895,49896,49897,49898,49902,49904,49906,49907,49908,49909,49911,49914,49917,49918,49919,49921,49922,49923,49924,49925,49926,49927,49930,49931,49934,49935,49936,49937,49938,49942,49943,49945,49946,49947,49949,49950,49951,49952,49953,49954,49955,49958,49959,49962,49963,49964,49965,49966,49967,49968,49969,49970,null,null,null,null,null,null,49971,49972,49973,49974,49975,49976,49977,49978,49979,49980,49981,49982,49983,49984,49985,49986,49987,49988,49990,49991,49992,49993,49994,49995,49996,49997,null,null,null,null,null,null,49998,49999,50000,50001,50002,50003,50004,50005,50006,50007,50008,50009,50010,50011,50012,50013,50014,50015,50016,50017,50018,50019,50020,50021,50022,50023,50026,50027,50029,50030,50031,50033,50035,50036,50037,50038,50039,50042,50043,50046,50047,50048,50049,50050,50051,50053,50054,50055,50057,50058,50059,50061,50062,50063,50064,50065,50066,50067,50068,50069,50070,50071,50072,50073,50074,50075,50076,50077,50078,50079,50080,50081,50082,50083,50084,50085,50086,50087,50088,50089,50090,50091,50092,50093,50094,50095,50096,50097,50098,50099,50100,50101,50102,50103,50104,50105,50106,50107,50108,50109,50110,50111,50113,50114,50115,50116,50117,50118,50119,50120,50121,50122,50123,50124,50125,50126,50127,50128,50129,50130,50131,50132,50133,50134,50135,50138,50139,50141,50142,50145,50147,50148,50149,50150,50151,50154,50155,50156,50158,50159,50160,50161,50162,50163,50166,50167,50169,50170,50171,50172,50173,50174,null,null,null,null,null,null,50175,50176,50177,50178,50179,50180,50181,50182,50183,50185,50186,50187,50188,50189,50190,50191,50193,50194,50195,50196,50197,50198,50199,50200,50201,50202,null,null,null,null,null,null,50203,50204,50205,50206,50207,50208,50209,50210,50211,50213,50214,50215,50216,50217,50218,50219,50221,50222,50223,50225,50226,50227,50229,50230,50231,50232,50233,50234,50235,50238,50239,50240,50241,50242,50243,50244,50245,50246,50247,50249,50250,50251,50252,50253,50254,50255,50256,50257,50258,50259,50260,50261,50262,50263,50264,50265,50266,50267,50268,50269,50270,50271,50272,50273,50274,50275,50278,50279,50281,50282,50283,50285,50286,50287,50288,50289,50290,50291,50294,50295,50296,50298,50299,50300,50301,50302,50303,50305,50306,50307,50308,50309,50310,50311,50312,50313,50314,50315,50316,50317,50318,50319,50320,50321,50322,50323,50325,50326,50327,50328,50329,50330,50331,50333,50334,50335,50336,50337,50338,50339,50340,50341,50342,50343,50344,50345,50346,50347,50348,50349,50350,50351,50352,50353,50354,50355,50356,50357,50358,50359,50361,50362,50363,50365,50366,50367,50368,50369,50370,50371,50372,50373,null,null,null,null,null,null,50374,50375,50376,50377,50378,50379,50380,50381,50382,50383,50384,50385,50386,50387,50388,50389,50390,50391,50392,50393,50394,50395,50396,50397,50398,50399,null,null,null,null,null,null,50400,50401,50402,50403,50404,50405,50406,50407,50408,50410,50411,50412,50413,50414,50415,50418,50419,50421,50422,50423,50425,50427,50428,50429,50430,50434,50435,50436,50437,50438,50439,50440,50441,50442,50443,50445,50446,50447,50449,50450,50451,50453,50454,50455,50456,50457,50458,50459,50461,50462,50463,50464,50465,50466,50467,50468,50469,50470,50471,50474,50475,50477,50478,50479,50481,50482,50483,50484,50485,50486,50487,50490,50492,50494,50495,50496,50497,50498,50499,50502,50503,50507,50511,50512,50513,50514,50518,50522,50523,50524,50527,50530,50531,50533,50534,50535,50537,50538,50539,50540,50541,50542,50543,50546,50550,50551,50552,50553,50554,50555,50558,50559,50561,50562,50563,50565,50566,50568,50569,50570,50571,50574,50576,50578,50579,50580,50582,50585,50586,50587,50589,50590,50591,50593,50594,50595,50596,50597,50598,50599,50600,50602,50603,50604,50605,50606,50607,50608,50609,50610,50611,50614,null,null,null,null,null,null,50615,50618,50623,50624,50625,50626,50627,50635,50637,50639,50642,50643,50645,50646,50647,50649,50650,50651,50652,50653,50654,50655,50658,50660,50662,50663,null,null,null,null,null,null,50664,50665,50666,50667,50671,50673,50674,50675,50677,50680,50681,50682,50683,50690,50691,50692,50697,50698,50699,50701,50702,50703,50705,50706,50707,50708,50709,50710,50711,50714,50717,50718,50719,50720,50721,50722,50723,50726,50727,50729,50730,50731,50735,50737,50738,50742,50744,50746,50748,50749,50750,50751,50754,50755,50757,50758,50759,50761,50762,50763,50764,50765,50766,50767,50770,50774,50775,50776,50777,50778,50779,50782,50783,50785,50786,50787,50788,50789,50790,50791,50792,50793,50794,50795,50797,50798,50800,50802,50803,50804,50805,50806,50807,50810,50811,50813,50814,50815,50817,50818,50819,50820,50821,50822,50823,50826,50828,50830,50831,50832,50833,50834,50835,50838,50839,50841,50842,50843,50845,50846,50847,50848,50849,50850,50851,50854,50856,50858,50859,50860,50861,50862,50863,50866,50867,50869,50870,50871,50875,50876,50877,50878,50879,50882,50884,50886,50887,50888,50889,50890,50891,50894,null,null,null,null,null,null,50895,50897,50898,50899,50901,50902,50903,50904,50905,50906,50907,50910,50911,50914,50915,50916,50917,50918,50919,50922,50923,50925,50926,50927,50929,50930,null,null,null,null,null,null,50931,50932,50933,50934,50935,50938,50939,50940,50942,50943,50944,50945,50946,50947,50950,50951,50953,50954,50955,50957,50958,50959,50960,50961,50962,50963,50966,50968,50970,50971,50972,50973,50974,50975,50978,50979,50981,50982,50983,50985,50986,50987,50988,50989,50990,50991,50994,50996,50998,51000,51001,51002,51003,51006,51007,51009,51010,51011,51013,51014,51015,51016,51017,51019,51022,51024,51033,51034,51035,51037,51038,51039,51041,51042,51043,51044,51045,51046,51047,51049,51050,51052,51053,51054,51055,51056,51057,51058,51059,51062,51063,51065,51066,51067,51071,51072,51073,51074,51078,51083,51084,51085,51087,51090,51091,51093,51097,51099,51100,51101,51102,51103,51106,51111,51112,51113,51114,51115,51118,51119,51121,51122,51123,51125,51126,51127,51128,51129,51130,51131,51134,51138,51139,51140,51141,51142,51143,51146,51147,51149,51151,51153,51154,51155,51156,51157,51158,51159,51161,51162,51163,51164,null,null,null,null,null,null,51166,51167,51168,51169,51170,51171,51173,51174,51175,51177,51178,51179,51181,51182,51183,51184,51185,51186,51187,51188,51189,51190,51191,51192,51193,51194,null,null,null,null,null,null,51195,51196,51197,51198,51199,51202,51203,51205,51206,51207,51209,51211,51212,51213,51214,51215,51218,51220,51223,51224,51225,51226,51227,51230,51231,51233,51234,51235,51237,51238,51239,51240,51241,51242,51243,51246,51248,51250,51251,51252,51253,51254,51255,51257,51258,51259,51261,51262,51263,51265,51266,51267,51268,51269,51270,51271,51274,51275,51278,51279,51280,51281,51282,51283,51285,51286,51287,51288,51289,51290,51291,51292,51293,51294,51295,51296,51297,51298,51299,51300,51301,51302,51303,51304,51305,51306,51307,51308,51309,51310,51311,51314,51315,51317,51318,51319,51321,51323,51324,51325,51326,51327,51330,51332,51336,51337,51338,51342,51343,51344,51345,51346,51347,51349,51350,51351,51352,51353,51354,51355,51356,51358,51360,51362,51363,51364,51365,51366,51367,51369,51370,51371,51372,51373,51374,51375,51376,51377,51378,51379,51380,51381,51382,51383,51384,51385,51386,51387,51390,51391,51392,51393,null,null,null,null,null,null,51394,51395,51397,51398,51399,51401,51402,51403,51405,51406,51407,51408,51409,51410,51411,51414,51416,51418,51419,51420,51421,51422,51423,51426,51427,51429,null,null,null,null,null,null,51430,51431,51432,51433,51434,51435,51436,51437,51438,51439,51440,51441,51442,51443,51444,51446,51447,51448,51449,51450,51451,51454,51455,51457,51458,51459,51463,51464,51465,51466,51467,51470,12288,12289,12290,183,8229,8230,168,12291,173,8213,8741,65340,8764,8216,8217,8220,8221,12308,12309,12296,12297,12298,12299,12300,12301,12302,12303,12304,12305,177,215,247,8800,8804,8805,8734,8756,176,8242,8243,8451,8491,65504,65505,65509,9794,9792,8736,8869,8978,8706,8711,8801,8786,167,8251,9734,9733,9675,9679,9678,9671,9670,9633,9632,9651,9650,9661,9660,8594,8592,8593,8595,8596,12307,8810,8811,8730,8765,8733,8757,8747,8748,8712,8715,8838,8839,8834,8835,8746,8745,8743,8744,65506,51472,51474,51475,51476,51477,51478,51479,51481,51482,51483,51484,51485,51486,51487,51488,51489,51490,51491,51492,51493,51494,51495,51496,51497,51498,51499,null,null,null,null,null,null,51501,51502,51503,51504,51505,51506,51507,51509,51510,51511,51512,51513,51514,51515,51516,51517,51518,51519,51520,51521,51522,51523,51524,51525,51526,51527,null,null,null,null,null,null,51528,51529,51530,51531,51532,51533,51534,51535,51538,51539,51541,51542,51543,51545,51546,51547,51548,51549,51550,51551,51554,51556,51557,51558,51559,51560,51561,51562,51563,51565,51566,51567,8658,8660,8704,8707,180,65374,711,728,733,730,729,184,731,161,191,720,8750,8721,8719,164,8457,8240,9665,9664,9655,9654,9828,9824,9825,9829,9831,9827,8857,9672,9635,9680,9681,9618,9636,9637,9640,9639,9638,9641,9832,9743,9742,9756,9758,182,8224,8225,8597,8599,8601,8598,8600,9837,9833,9834,9836,12927,12828,8470,13255,8482,13250,13272,8481,8364,174,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,51569,51570,51571,51573,51574,51575,51576,51577,51578,51579,51581,51582,51583,51584,51585,51586,51587,51588,51589,51590,51591,51594,51595,51597,51598,51599,null,null,null,null,null,null,51601,51602,51603,51604,51605,51606,51607,51610,51612,51614,51615,51616,51617,51618,51619,51620,51621,51622,51623,51624,51625,51626,51627,51628,51629,51630,null,null,null,null,null,null,51631,51632,51633,51634,51635,51636,51637,51638,51639,51640,51641,51642,51643,51644,51645,51646,51647,51650,51651,51653,51654,51657,51659,51660,51661,51662,51663,51666,51668,51671,51672,51675,65281,65282,65283,65284,65285,65286,65287,65288,65289,65290,65291,65292,65293,65294,65295,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,65306,65307,65308,65309,65310,65311,65312,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,65339,65510,65341,65342,65343,65344,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,65371,65372,65373,65507,51678,51679,51681,51683,51685,51686,51688,51689,51690,51691,51694,51698,51699,51700,51701,51702,51703,51706,51707,51709,51710,51711,51713,51714,51715,51716,null,null,null,null,null,null,51717,51718,51719,51722,51726,51727,51728,51729,51730,51731,51733,51734,51735,51737,51738,51739,51740,51741,51742,51743,51744,51745,51746,51747,51748,51749,null,null,null,null,null,null,51750,51751,51752,51754,51755,51756,51757,51758,51759,51760,51761,51762,51763,51764,51765,51766,51767,51768,51769,51770,51771,51772,51773,51774,51775,51776,51777,51778,51779,51780,51781,51782,12593,12594,12595,12596,12597,12598,12599,12600,12601,12602,12603,12604,12605,12606,12607,12608,12609,12610,12611,12612,12613,12614,12615,12616,12617,12618,12619,12620,12621,12622,12623,12624,12625,12626,12627,12628,12629,12630,12631,12632,12633,12634,12635,12636,12637,12638,12639,12640,12641,12642,12643,12644,12645,12646,12647,12648,12649,12650,12651,12652,12653,12654,12655,12656,12657,12658,12659,12660,12661,12662,12663,12664,12665,12666,12667,12668,12669,12670,12671,12672,12673,12674,12675,12676,12677,12678,12679,12680,12681,12682,12683,12684,12685,12686,51783,51784,51785,51786,51787,51790,51791,51793,51794,51795,51797,51798,51799,51800,51801,51802,51803,51806,51810,51811,51812,51813,51814,51815,51817,51818,null,null,null,null,null,null,51819,51820,51821,51822,51823,51824,51825,51826,51827,51828,51829,51830,51831,51832,51833,51834,51835,51836,51838,51839,51840,51841,51842,51843,51845,51846,null,null,null,null,null,null,51847,51848,51849,51850,51851,51852,51853,51854,51855,51856,51857,51858,51859,51860,51861,51862,51863,51865,51866,51867,51868,51869,51870,51871,51872,51873,51874,51875,51876,51877,51878,51879,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,null,null,null,null,null,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,null,null,null,null,null,null,null,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,null,null,null,null,null,null,null,null,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,964,965,966,967,968,969,null,null,null,null,null,null,51880,51881,51882,51883,51884,51885,51886,51887,51888,51889,51890,51891,51892,51893,51894,51895,51896,51897,51898,51899,51902,51903,51905,51906,51907,51909,null,null,null,null,null,null,51910,51911,51912,51913,51914,51915,51918,51920,51922,51924,51925,51926,51927,51930,51931,51932,51933,51934,51935,51937,51938,51939,51940,51941,51942,51943,null,null,null,null,null,null,51944,51945,51946,51947,51949,51950,51951,51952,51953,51954,51955,51957,51958,51959,51960,51961,51962,51963,51964,51965,51966,51967,51968,51969,51970,51971,51972,51973,51974,51975,51977,51978,9472,9474,9484,9488,9496,9492,9500,9516,9508,9524,9532,9473,9475,9487,9491,9499,9495,9507,9523,9515,9531,9547,9504,9519,9512,9527,9535,9501,9520,9509,9528,9538,9490,9489,9498,9497,9494,9493,9486,9485,9502,9503,9505,9506,9510,9511,9513,9514,9517,9518,9521,9522,9525,9526,9529,9530,9533,9534,9536,9537,9539,9540,9541,9542,9543,9544,9545,9546,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,51979,51980,51981,51982,51983,51985,51986,51987,51989,51990,51991,51993,51994,51995,51996,51997,51998,51999,52002,52003,52004,52005,52006,52007,52008,52009,null,null,null,null,null,null,52010,52011,52012,52013,52014,52015,52016,52017,52018,52019,52020,52021,52022,52023,52024,52025,52026,52027,52028,52029,52030,52031,52032,52034,52035,52036,null,null,null,null,null,null,52037,52038,52039,52042,52043,52045,52046,52047,52049,52050,52051,52052,52053,52054,52055,52058,52059,52060,52062,52063,52064,52065,52066,52067,52069,52070,52071,52072,52073,52074,52075,52076,13205,13206,13207,8467,13208,13252,13219,13220,13221,13222,13209,13210,13211,13212,13213,13214,13215,13216,13217,13218,13258,13197,13198,13199,13263,13192,13193,13256,13223,13224,13232,13233,13234,13235,13236,13237,13238,13239,13240,13241,13184,13185,13186,13187,13188,13242,13243,13244,13245,13246,13247,13200,13201,13202,13203,13204,8486,13248,13249,13194,13195,13196,13270,13253,13229,13230,13231,13275,13225,13226,13227,13228,13277,13264,13267,13251,13257,13276,13254,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,52077,52078,52079,52080,52081,52082,52083,52084,52085,52086,52087,52090,52091,52092,52093,52094,52095,52096,52097,52098,52099,52100,52101,52102,52103,52104,null,null,null,null,null,null,52105,52106,52107,52108,52109,52110,52111,52112,52113,52114,52115,52116,52117,52118,52119,52120,52121,52122,52123,52125,52126,52127,52128,52129,52130,52131,null,null,null,null,null,null,52132,52133,52134,52135,52136,52137,52138,52139,52140,52141,52142,52143,52144,52145,52146,52147,52148,52149,52150,52151,52153,52154,52155,52156,52157,52158,52159,52160,52161,52162,52163,52164,198,208,170,294,null,306,null,319,321,216,338,186,222,358,330,null,12896,12897,12898,12899,12900,12901,12902,12903,12904,12905,12906,12907,12908,12909,12910,12911,12912,12913,12914,12915,12916,12917,12918,12919,12920,12921,12922,12923,9424,9425,9426,9427,9428,9429,9430,9431,9432,9433,9434,9435,9436,9437,9438,9439,9440,9441,9442,9443,9444,9445,9446,9447,9448,9449,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9322,9323,9324,9325,9326,189,8531,8532,188,190,8539,8540,8541,8542,52165,52166,52167,52168,52169,52170,52171,52172,52173,52174,52175,52176,52177,52178,52179,52181,52182,52183,52184,52185,52186,52187,52188,52189,52190,52191,null,null,null,null,null,null,52192,52193,52194,52195,52197,52198,52200,52202,52203,52204,52205,52206,52207,52208,52209,52210,52211,52212,52213,52214,52215,52216,52217,52218,52219,52220,null,null,null,null,null,null,52221,52222,52223,52224,52225,52226,52227,52228,52229,52230,52231,52232,52233,52234,52235,52238,52239,52241,52242,52243,52245,52246,52247,52248,52249,52250,52251,52254,52255,52256,52259,52260,230,273,240,295,305,307,312,320,322,248,339,223,254,359,331,329,12800,12801,12802,12803,12804,12805,12806,12807,12808,12809,12810,12811,12812,12813,12814,12815,12816,12817,12818,12819,12820,12821,12822,12823,12824,12825,12826,12827,9372,9373,9374,9375,9376,9377,9378,9379,9380,9381,9382,9383,9384,9385,9386,9387,9388,9389,9390,9391,9392,9393,9394,9395,9396,9397,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,9342,9343,9344,9345,9346,185,178,179,8308,8319,8321,8322,8323,8324,52261,52262,52266,52267,52269,52271,52273,52274,52275,52276,52277,52278,52279,52282,52287,52288,52289,52290,52291,52294,52295,52297,52298,52299,52301,52302,null,null,null,null,null,null,52303,52304,52305,52306,52307,52310,52314,52315,52316,52317,52318,52319,52321,52322,52323,52325,52327,52329,52330,52331,52332,52333,52334,52335,52337,52338,null,null,null,null,null,null,52339,52340,52342,52343,52344,52345,52346,52347,52348,52349,52350,52351,52352,52353,52354,52355,52356,52357,52358,52359,52360,52361,52362,52363,52364,52365,52366,52367,52368,52369,52370,52371,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,null,null,null,null,null,null,null,null,null,null,null,52372,52373,52374,52375,52378,52379,52381,52382,52383,52385,52386,52387,52388,52389,52390,52391,52394,52398,52399,52400,52401,52402,52403,52406,52407,52409,null,null,null,null,null,null,52410,52411,52413,52414,52415,52416,52417,52418,52419,52422,52424,52426,52427,52428,52429,52430,52431,52433,52434,52435,52437,52438,52439,52440,52441,52442,null,null,null,null,null,null,52443,52444,52445,52446,52447,52448,52449,52450,52451,52453,52454,52455,52456,52457,52458,52459,52461,52462,52463,52465,52466,52467,52468,52469,52470,52471,52472,52473,52474,52475,52476,52477,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,null,null,null,null,null,null,null,null,52478,52479,52480,52482,52483,52484,52485,52486,52487,52490,52491,52493,52494,52495,52497,52498,52499,52500,52501,52502,52503,52506,52508,52510,52511,52512,null,null,null,null,null,null,52513,52514,52515,52517,52518,52519,52521,52522,52523,52525,52526,52527,52528,52529,52530,52531,52532,52533,52534,52535,52536,52538,52539,52540,52541,52542,null,null,null,null,null,null,52543,52544,52545,52546,52547,52548,52549,52550,52551,52552,52553,52554,52555,52556,52557,52558,52559,52560,52561,52562,52563,52564,52565,52566,52567,52568,52569,52570,52571,52573,52574,52575,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,null,null,null,null,null,null,null,null,null,null,null,null,null,52577,52578,52579,52581,52582,52583,52584,52585,52586,52587,52590,52592,52594,52595,52596,52597,52598,52599,52601,52602,52603,52604,52605,52606,52607,52608,null,null,null,null,null,null,52609,52610,52611,52612,52613,52614,52615,52617,52618,52619,52620,52621,52622,52623,52624,52625,52626,52627,52630,52631,52633,52634,52635,52637,52638,52639,null,null,null,null,null,null,52640,52641,52642,52643,52646,52648,52650,52651,52652,52653,52654,52655,52657,52658,52659,52660,52661,52662,52663,52664,52665,52666,52667,52668,52669,52670,52671,52672,52673,52674,52675,52677,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,52678,52679,52680,52681,52682,52683,52685,52686,52687,52689,52690,52691,52692,52693,52694,52695,52696,52697,52698,52699,52700,52701,52702,52703,52704,52705,null,null,null,null,null,null,52706,52707,52708,52709,52710,52711,52713,52714,52715,52717,52718,52719,52721,52722,52723,52724,52725,52726,52727,52730,52732,52734,52735,52736,52737,52738,null,null,null,null,null,null,52739,52741,52742,52743,52745,52746,52747,52749,52750,52751,52752,52753,52754,52755,52757,52758,52759,52760,52762,52763,52764,52765,52766,52767,52770,52771,52773,52774,52775,52777,52778,52779,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,52780,52781,52782,52783,52786,52788,52790,52791,52792,52793,52794,52795,52796,52797,52798,52799,52800,52801,52802,52803,52804,52805,52806,52807,52808,52809,null,null,null,null,null,null,52810,52811,52812,52813,52814,52815,52816,52817,52818,52819,52820,52821,52822,52823,52826,52827,52829,52830,52834,52835,52836,52837,52838,52839,52842,52844,null,null,null,null,null,null,52846,52847,52848,52849,52850,52851,52854,52855,52857,52858,52859,52861,52862,52863,52864,52865,52866,52867,52870,52872,52874,52875,52876,52877,52878,52879,52882,52883,52885,52886,52887,52889,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,52890,52891,52892,52893,52894,52895,52898,52902,52903,52904,52905,52906,52907,52910,52911,52912,52913,52914,52915,52916,52917,52918,52919,52920,52921,52922,null,null,null,null,null,null,52923,52924,52925,52926,52927,52928,52930,52931,52932,52933,52934,52935,52936,52937,52938,52939,52940,52941,52942,52943,52944,52945,52946,52947,52948,52949,null,null,null,null,null,null,52950,52951,52952,52953,52954,52955,52956,52957,52958,52959,52960,52961,52962,52963,52966,52967,52969,52970,52973,52974,52975,52976,52977,52978,52979,52982,52986,52987,52988,52989,52990,52991,44032,44033,44036,44039,44040,44041,44042,44048,44049,44050,44051,44052,44053,44054,44055,44057,44058,44059,44060,44061,44064,44068,44076,44077,44079,44080,44081,44088,44089,44092,44096,44107,44109,44116,44120,44124,44144,44145,44148,44151,44152,44154,44160,44161,44163,44164,44165,44166,44169,44170,44171,44172,44176,44180,44188,44189,44191,44192,44193,44200,44201,44202,44204,44207,44208,44216,44217,44219,44220,44221,44225,44228,44232,44236,44245,44247,44256,44257,44260,44263,44264,44266,44268,44271,44272,44273,44275,44277,44278,44284,44285,44288,44292,44294,52994,52995,52997,52998,52999,53001,53002,53003,53004,53005,53006,53007,53010,53012,53014,53015,53016,53017,53018,53019,53021,53022,53023,53025,53026,53027,null,null,null,null,null,null,53029,53030,53031,53032,53033,53034,53035,53038,53042,53043,53044,53045,53046,53047,53049,53050,53051,53052,53053,53054,53055,53056,53057,53058,53059,53060,null,null,null,null,null,null,53061,53062,53063,53064,53065,53066,53067,53068,53069,53070,53071,53072,53073,53074,53075,53078,53079,53081,53082,53083,53085,53086,53087,53088,53089,53090,53091,53094,53096,53098,53099,53100,44300,44301,44303,44305,44312,44316,44320,44329,44332,44333,44340,44341,44344,44348,44356,44357,44359,44361,44368,44372,44376,44385,44387,44396,44397,44400,44403,44404,44405,44406,44411,44412,44413,44415,44417,44418,44424,44425,44428,44432,44444,44445,44452,44471,44480,44481,44484,44488,44496,44497,44499,44508,44512,44516,44536,44537,44540,44543,44544,44545,44552,44553,44555,44557,44564,44592,44593,44596,44599,44600,44602,44608,44609,44611,44613,44614,44618,44620,44621,44622,44624,44628,44630,44636,44637,44639,44640,44641,44645,44648,44649,44652,44656,44664,53101,53102,53103,53106,53107,53109,53110,53111,53113,53114,53115,53116,53117,53118,53119,53121,53122,53123,53124,53126,53127,53128,53129,53130,53131,53133,null,null,null,null,null,null,53134,53135,53136,53137,53138,53139,53140,53141,53142,53143,53144,53145,53146,53147,53148,53149,53150,53151,53152,53154,53155,53156,53157,53158,53159,53161,null,null,null,null,null,null,53162,53163,53164,53165,53166,53167,53169,53170,53171,53172,53173,53174,53175,53176,53177,53178,53179,53180,53181,53182,53183,53184,53185,53186,53187,53189,53190,53191,53192,53193,53194,53195,44665,44667,44668,44669,44676,44677,44684,44732,44733,44734,44736,44740,44748,44749,44751,44752,44753,44760,44761,44764,44776,44779,44781,44788,44792,44796,44807,44808,44813,44816,44844,44845,44848,44850,44852,44860,44861,44863,44865,44866,44867,44872,44873,44880,44892,44893,44900,44901,44921,44928,44932,44936,44944,44945,44949,44956,44984,44985,44988,44992,44999,45000,45001,45003,45005,45006,45012,45020,45032,45033,45040,45041,45044,45048,45056,45057,45060,45068,45072,45076,45084,45085,45096,45124,45125,45128,45130,45132,45134,45139,45140,45141,45143,45145,53196,53197,53198,53199,53200,53201,53202,53203,53204,53205,53206,53207,53208,53209,53210,53211,53212,53213,53214,53215,53218,53219,53221,53222,53223,53225,null,null,null,null,null,null,53226,53227,53228,53229,53230,53231,53234,53236,53238,53239,53240,53241,53242,53243,53245,53246,53247,53249,53250,53251,53253,53254,53255,53256,53257,53258,null,null,null,null,null,null,53259,53260,53261,53262,53263,53264,53266,53267,53268,53269,53270,53271,53273,53274,53275,53276,53277,53278,53279,53280,53281,53282,53283,53284,53285,53286,53287,53288,53289,53290,53291,53292,45149,45180,45181,45184,45188,45196,45197,45199,45201,45208,45209,45210,45212,45215,45216,45217,45218,45224,45225,45227,45228,45229,45230,45231,45233,45235,45236,45237,45240,45244,45252,45253,45255,45256,45257,45264,45265,45268,45272,45280,45285,45320,45321,45323,45324,45328,45330,45331,45336,45337,45339,45340,45341,45347,45348,45349,45352,45356,45364,45365,45367,45368,45369,45376,45377,45380,45384,45392,45393,45396,45397,45400,45404,45408,45432,45433,45436,45440,45442,45448,45449,45451,45453,45458,45459,45460,45464,45468,45480,45516,45520,45524,45532,45533,53294,53295,53296,53297,53298,53299,53302,53303,53305,53306,53307,53309,53310,53311,53312,53313,53314,53315,53318,53320,53322,53323,53324,53325,53326,53327,null,null,null,null,null,null,53329,53330,53331,53333,53334,53335,53337,53338,53339,53340,53341,53342,53343,53345,53346,53347,53348,53349,53350,53351,53352,53353,53354,53355,53358,53359,null,null,null,null,null,null,53361,53362,53363,53365,53366,53367,53368,53369,53370,53371,53374,53375,53376,53378,53379,53380,53381,53382,53383,53384,53385,53386,53387,53388,53389,53390,53391,53392,53393,53394,53395,53396,45535,45544,45545,45548,45552,45561,45563,45565,45572,45573,45576,45579,45580,45588,45589,45591,45593,45600,45620,45628,45656,45660,45664,45672,45673,45684,45685,45692,45700,45701,45705,45712,45713,45716,45720,45721,45722,45728,45729,45731,45733,45734,45738,45740,45744,45748,45768,45769,45772,45776,45778,45784,45785,45787,45789,45794,45796,45797,45798,45800,45803,45804,45805,45806,45807,45811,45812,45813,45815,45816,45817,45818,45819,45823,45824,45825,45828,45832,45840,45841,45843,45844,45845,45852,45908,45909,45910,45912,45915,45916,45918,45919,45924,45925,53397,53398,53399,53400,53401,53402,53403,53404,53405,53406,53407,53408,53409,53410,53411,53414,53415,53417,53418,53419,53421,53422,53423,53424,53425,53426,null,null,null,null,null,null,53427,53430,53432,53434,53435,53436,53437,53438,53439,53442,53443,53445,53446,53447,53450,53451,53452,53453,53454,53455,53458,53462,53463,53464,53465,53466,null,null,null,null,null,null,53467,53470,53471,53473,53474,53475,53477,53478,53479,53480,53481,53482,53483,53486,53490,53491,53492,53493,53494,53495,53497,53498,53499,53500,53501,53502,53503,53504,53505,53506,53507,53508,45927,45929,45931,45934,45936,45937,45940,45944,45952,45953,45955,45956,45957,45964,45968,45972,45984,45985,45992,45996,46020,46021,46024,46027,46028,46030,46032,46036,46037,46039,46041,46043,46045,46048,46052,46056,46076,46096,46104,46108,46112,46120,46121,46123,46132,46160,46161,46164,46168,46176,46177,46179,46181,46188,46208,46216,46237,46244,46248,46252,46261,46263,46265,46272,46276,46280,46288,46293,46300,46301,46304,46307,46308,46310,46316,46317,46319,46321,46328,46356,46357,46360,46363,46364,46372,46373,46375,46376,46377,46378,46384,46385,46388,46392,53509,53510,53511,53512,53513,53514,53515,53516,53518,53519,53520,53521,53522,53523,53524,53525,53526,53527,53528,53529,53530,53531,53532,53533,53534,53535,null,null,null,null,null,null,53536,53537,53538,53539,53540,53541,53542,53543,53544,53545,53546,53547,53548,53549,53550,53551,53554,53555,53557,53558,53559,53561,53563,53564,53565,53566,null,null,null,null,null,null,53567,53570,53574,53575,53576,53577,53578,53579,53582,53583,53585,53586,53587,53589,53590,53591,53592,53593,53594,53595,53598,53600,53602,53603,53604,53605,53606,53607,53609,53610,53611,53613,46400,46401,46403,46404,46405,46411,46412,46413,46416,46420,46428,46429,46431,46432,46433,46496,46497,46500,46504,46506,46507,46512,46513,46515,46516,46517,46523,46524,46525,46528,46532,46540,46541,46543,46544,46545,46552,46572,46608,46609,46612,46616,46629,46636,46644,46664,46692,46696,46748,46749,46752,46756,46763,46764,46769,46804,46832,46836,46840,46848,46849,46853,46888,46889,46892,46895,46896,46904,46905,46907,46916,46920,46924,46932,46933,46944,46948,46952,46960,46961,46963,46965,46972,46973,46976,46980,46988,46989,46991,46992,46993,46994,46998,46999,53614,53615,53616,53617,53618,53619,53620,53621,53622,53623,53624,53625,53626,53627,53629,53630,53631,53632,53633,53634,53635,53637,53638,53639,53641,53642,null,null,null,null,null,null,53643,53644,53645,53646,53647,53648,53649,53650,53651,53652,53653,53654,53655,53656,53657,53658,53659,53660,53661,53662,53663,53666,53667,53669,53670,53671,null,null,null,null,null,null,53673,53674,53675,53676,53677,53678,53679,53682,53684,53686,53687,53688,53689,53691,53693,53694,53695,53697,53698,53699,53700,53701,53702,53703,53704,53705,53706,53707,53708,53709,53710,53711,47000,47001,47004,47008,47016,47017,47019,47020,47021,47028,47029,47032,47047,47049,47084,47085,47088,47092,47100,47101,47103,47104,47105,47111,47112,47113,47116,47120,47128,47129,47131,47133,47140,47141,47144,47148,47156,47157,47159,47160,47161,47168,47172,47185,47187,47196,47197,47200,47204,47212,47213,47215,47217,47224,47228,47245,47272,47280,47284,47288,47296,47297,47299,47301,47308,47312,47316,47325,47327,47329,47336,47337,47340,47344,47352,47353,47355,47357,47364,47384,47392,47420,47421,47424,47428,47436,47439,47441,47448,47449,47452,47456,47464,47465,53712,53713,53714,53715,53716,53717,53718,53719,53721,53722,53723,53724,53725,53726,53727,53728,53729,53730,53731,53732,53733,53734,53735,53736,53737,53738,null,null,null,null,null,null,53739,53740,53741,53742,53743,53744,53745,53746,53747,53749,53750,53751,53753,53754,53755,53756,53757,53758,53759,53760,53761,53762,53763,53764,53765,53766,null,null,null,null,null,null,53768,53770,53771,53772,53773,53774,53775,53777,53778,53779,53780,53781,53782,53783,53784,53785,53786,53787,53788,53789,53790,53791,53792,53793,53794,53795,53796,53797,53798,53799,53800,53801,47467,47469,47476,47477,47480,47484,47492,47493,47495,47497,47498,47501,47502,47532,47533,47536,47540,47548,47549,47551,47553,47560,47561,47564,47566,47567,47568,47569,47570,47576,47577,47579,47581,47582,47585,47587,47588,47589,47592,47596,47604,47605,47607,47608,47609,47610,47616,47617,47624,47637,47672,47673,47676,47680,47682,47688,47689,47691,47693,47694,47699,47700,47701,47704,47708,47716,47717,47719,47720,47721,47728,47729,47732,47736,47747,47748,47749,47751,47756,47784,47785,47787,47788,47792,47794,47800,47801,47803,47805,47812,47816,47832,47833,47868,53802,53803,53806,53807,53809,53810,53811,53813,53814,53815,53816,53817,53818,53819,53822,53824,53826,53827,53828,53829,53830,53831,53833,53834,53835,53836,null,null,null,null,null,null,53837,53838,53839,53840,53841,53842,53843,53844,53845,53846,53847,53848,53849,53850,53851,53853,53854,53855,53856,53857,53858,53859,53861,53862,53863,53864,null,null,null,null,null,null,53865,53866,53867,53868,53869,53870,53871,53872,53873,53874,53875,53876,53877,53878,53879,53880,53881,53882,53883,53884,53885,53886,53887,53890,53891,53893,53894,53895,53897,53898,53899,53900,47872,47876,47885,47887,47889,47896,47900,47904,47913,47915,47924,47925,47926,47928,47931,47932,47933,47934,47940,47941,47943,47945,47949,47951,47952,47956,47960,47969,47971,47980,48008,48012,48016,48036,48040,48044,48052,48055,48064,48068,48072,48080,48083,48120,48121,48124,48127,48128,48130,48136,48137,48139,48140,48141,48143,48145,48148,48149,48150,48151,48152,48155,48156,48157,48158,48159,48164,48165,48167,48169,48173,48176,48177,48180,48184,48192,48193,48195,48196,48197,48201,48204,48205,48208,48221,48260,48261,48264,48267,48268,48270,48276,48277,48279,53901,53902,53903,53906,53907,53908,53910,53911,53912,53913,53914,53915,53917,53918,53919,53921,53922,53923,53925,53926,53927,53928,53929,53930,53931,53933,null,null,null,null,null,null,53934,53935,53936,53938,53939,53940,53941,53942,53943,53946,53947,53949,53950,53953,53955,53956,53957,53958,53959,53962,53964,53965,53966,53967,53968,53969,null,null,null,null,null,null,53970,53971,53973,53974,53975,53977,53978,53979,53981,53982,53983,53984,53985,53986,53987,53990,53991,53992,53993,53994,53995,53996,53997,53998,53999,54002,54003,54005,54006,54007,54009,54010,48281,48282,48288,48289,48292,48295,48296,48304,48305,48307,48308,48309,48316,48317,48320,48324,48333,48335,48336,48337,48341,48344,48348,48372,48373,48374,48376,48380,48388,48389,48391,48393,48400,48404,48420,48428,48448,48456,48457,48460,48464,48472,48473,48484,48488,48512,48513,48516,48519,48520,48521,48522,48528,48529,48531,48533,48537,48538,48540,48548,48560,48568,48596,48597,48600,48604,48617,48624,48628,48632,48640,48643,48645,48652,48653,48656,48660,48668,48669,48671,48708,48709,48712,48716,48718,48724,48725,48727,48729,48730,48731,48736,48737,48740,54011,54012,54013,54014,54015,54018,54020,54022,54023,54024,54025,54026,54027,54031,54033,54034,54035,54037,54039,54040,54041,54042,54043,54046,54050,54051,null,null,null,null,null,null,54052,54054,54055,54058,54059,54061,54062,54063,54065,54066,54067,54068,54069,54070,54071,54074,54078,54079,54080,54081,54082,54083,54086,54087,54088,54089,null,null,null,null,null,null,54090,54091,54092,54093,54094,54095,54096,54097,54098,54099,54100,54101,54102,54103,54104,54105,54106,54107,54108,54109,54110,54111,54112,54113,54114,54115,54116,54117,54118,54119,54120,54121,48744,48746,48752,48753,48755,48756,48757,48763,48764,48765,48768,48772,48780,48781,48783,48784,48785,48792,48793,48808,48848,48849,48852,48855,48856,48864,48867,48868,48869,48876,48897,48904,48905,48920,48921,48923,48924,48925,48960,48961,48964,48968,48976,48977,48981,49044,49072,49093,49100,49101,49104,49108,49116,49119,49121,49212,49233,49240,49244,49248,49256,49257,49296,49297,49300,49304,49312,49313,49315,49317,49324,49325,49327,49328,49331,49332,49333,49334,49340,49341,49343,49344,49345,49349,49352,49353,49356,49360,49368,49369,49371,49372,49373,49380,54122,54123,54124,54125,54126,54127,54128,54129,54130,54131,54132,54133,54134,54135,54136,54137,54138,54139,54142,54143,54145,54146,54147,54149,54150,54151,null,null,null,null,null,null,54152,54153,54154,54155,54158,54162,54163,54164,54165,54166,54167,54170,54171,54173,54174,54175,54177,54178,54179,54180,54181,54182,54183,54186,54188,54190,null,null,null,null,null,null,54191,54192,54193,54194,54195,54197,54198,54199,54201,54202,54203,54205,54206,54207,54208,54209,54210,54211,54214,54215,54218,54219,54220,54221,54222,54223,54225,54226,54227,54228,54229,54230,49381,49384,49388,49396,49397,49399,49401,49408,49412,49416,49424,49429,49436,49437,49438,49439,49440,49443,49444,49446,49447,49452,49453,49455,49456,49457,49462,49464,49465,49468,49472,49480,49481,49483,49484,49485,49492,49493,49496,49500,49508,49509,49511,49512,49513,49520,49524,49528,49541,49548,49549,49550,49552,49556,49558,49564,49565,49567,49569,49573,49576,49577,49580,49584,49597,49604,49608,49612,49620,49623,49624,49632,49636,49640,49648,49649,49651,49660,49661,49664,49668,49676,49677,49679,49681,49688,49689,49692,49695,49696,49704,49705,49707,49709,54231,54233,54234,54235,54236,54237,54238,54239,54240,54242,54244,54245,54246,54247,54248,54249,54250,54251,54254,54255,54257,54258,54259,54261,54262,54263,null,null,null,null,null,null,54264,54265,54266,54267,54270,54272,54274,54275,54276,54277,54278,54279,54281,54282,54283,54284,54285,54286,54287,54288,54289,54290,54291,54292,54293,54294,null,null,null,null,null,null,54295,54296,54297,54298,54299,54300,54302,54303,54304,54305,54306,54307,54308,54309,54310,54311,54312,54313,54314,54315,54316,54317,54318,54319,54320,54321,54322,54323,54324,54325,54326,54327,49711,49713,49714,49716,49736,49744,49745,49748,49752,49760,49765,49772,49773,49776,49780,49788,49789,49791,49793,49800,49801,49808,49816,49819,49821,49828,49829,49832,49836,49837,49844,49845,49847,49849,49884,49885,49888,49891,49892,49899,49900,49901,49903,49905,49910,49912,49913,49915,49916,49920,49928,49929,49932,49933,49939,49940,49941,49944,49948,49956,49957,49960,49961,49989,50024,50025,50028,50032,50034,50040,50041,50044,50045,50052,50056,50060,50112,50136,50137,50140,50143,50144,50146,50152,50153,50157,50164,50165,50168,50184,50192,50212,50220,50224,54328,54329,54330,54331,54332,54333,54334,54335,54337,54338,54339,54341,54342,54343,54344,54345,54346,54347,54348,54349,54350,54351,54352,54353,54354,54355,null,null,null,null,null,null,54356,54357,54358,54359,54360,54361,54362,54363,54365,54366,54367,54369,54370,54371,54373,54374,54375,54376,54377,54378,54379,54380,54382,54384,54385,54386,null,null,null,null,null,null,54387,54388,54389,54390,54391,54394,54395,54397,54398,54401,54403,54404,54405,54406,54407,54410,54412,54414,54415,54416,54417,54418,54419,54421,54422,54423,54424,54425,54426,54427,54428,54429,50228,50236,50237,50248,50276,50277,50280,50284,50292,50293,50297,50304,50324,50332,50360,50364,50409,50416,50417,50420,50424,50426,50431,50432,50433,50444,50448,50452,50460,50472,50473,50476,50480,50488,50489,50491,50493,50500,50501,50504,50505,50506,50508,50509,50510,50515,50516,50517,50519,50520,50521,50525,50526,50528,50529,50532,50536,50544,50545,50547,50548,50549,50556,50557,50560,50564,50567,50572,50573,50575,50577,50581,50583,50584,50588,50592,50601,50612,50613,50616,50617,50619,50620,50621,50622,50628,50629,50630,50631,50632,50633,50634,50636,50638,54430,54431,54432,54433,54434,54435,54436,54437,54438,54439,54440,54442,54443,54444,54445,54446,54447,54448,54449,54450,54451,54452,54453,54454,54455,54456,null,null,null,null,null,null,54457,54458,54459,54460,54461,54462,54463,54464,54465,54466,54467,54468,54469,54470,54471,54472,54473,54474,54475,54477,54478,54479,54481,54482,54483,54485,null,null,null,null,null,null,54486,54487,54488,54489,54490,54491,54493,54494,54496,54497,54498,54499,54500,54501,54502,54503,54505,54506,54507,54509,54510,54511,54513,54514,54515,54516,54517,54518,54519,54521,54522,54524,50640,50641,50644,50648,50656,50657,50659,50661,50668,50669,50670,50672,50676,50678,50679,50684,50685,50686,50687,50688,50689,50693,50694,50695,50696,50700,50704,50712,50713,50715,50716,50724,50725,50728,50732,50733,50734,50736,50739,50740,50741,50743,50745,50747,50752,50753,50756,50760,50768,50769,50771,50772,50773,50780,50781,50784,50796,50799,50801,50808,50809,50812,50816,50824,50825,50827,50829,50836,50837,50840,50844,50852,50853,50855,50857,50864,50865,50868,50872,50873,50874,50880,50881,50883,50885,50892,50893,50896,50900,50908,50909,50912,50913,50920,54526,54527,54528,54529,54530,54531,54533,54534,54535,54537,54538,54539,54541,54542,54543,54544,54545,54546,54547,54550,54552,54553,54554,54555,54556,54557,null,null,null,null,null,null,54558,54559,54560,54561,54562,54563,54564,54565,54566,54567,54568,54569,54570,54571,54572,54573,54574,54575,54576,54577,54578,54579,54580,54581,54582,54583,null,null,null,null,null,null,54584,54585,54586,54587,54590,54591,54593,54594,54595,54597,54598,54599,54600,54601,54602,54603,54606,54608,54610,54611,54612,54613,54614,54615,54618,54619,54621,54622,54623,54625,54626,54627,50921,50924,50928,50936,50937,50941,50948,50949,50952,50956,50964,50965,50967,50969,50976,50977,50980,50984,50992,50993,50995,50997,50999,51004,51005,51008,51012,51018,51020,51021,51023,51025,51026,51027,51028,51029,51030,51031,51032,51036,51040,51048,51051,51060,51061,51064,51068,51069,51070,51075,51076,51077,51079,51080,51081,51082,51086,51088,51089,51092,51094,51095,51096,51098,51104,51105,51107,51108,51109,51110,51116,51117,51120,51124,51132,51133,51135,51136,51137,51144,51145,51148,51150,51152,51160,51165,51172,51176,51180,51200,51201,51204,51208,51210,54628,54630,54631,54634,54636,54638,54639,54640,54641,54642,54643,54646,54647,54649,54650,54651,54653,54654,54655,54656,54657,54658,54659,54662,54666,54667,null,null,null,null,null,null,54668,54669,54670,54671,54673,54674,54675,54676,54677,54678,54679,54680,54681,54682,54683,54684,54685,54686,54687,54688,54689,54690,54691,54692,54694,54695,null,null,null,null,null,null,54696,54697,54698,54699,54700,54701,54702,54703,54704,54705,54706,54707,54708,54709,54710,54711,54712,54713,54714,54715,54716,54717,54718,54719,54720,54721,54722,54723,54724,54725,54726,54727,51216,51217,51219,51221,51222,51228,51229,51232,51236,51244,51245,51247,51249,51256,51260,51264,51272,51273,51276,51277,51284,51312,51313,51316,51320,51322,51328,51329,51331,51333,51334,51335,51339,51340,51341,51348,51357,51359,51361,51368,51388,51389,51396,51400,51404,51412,51413,51415,51417,51424,51425,51428,51445,51452,51453,51456,51460,51461,51462,51468,51469,51471,51473,51480,51500,51508,51536,51537,51540,51544,51552,51553,51555,51564,51568,51572,51580,51592,51593,51596,51600,51608,51609,51611,51613,51648,51649,51652,51655,51656,51658,51664,51665,51667,54730,54731,54733,54734,54735,54737,54739,54740,54741,54742,54743,54746,54748,54750,54751,54752,54753,54754,54755,54758,54759,54761,54762,54763,54765,54766,null,null,null,null,null,null,54767,54768,54769,54770,54771,54774,54776,54778,54779,54780,54781,54782,54783,54786,54787,54789,54790,54791,54793,54794,54795,54796,54797,54798,54799,54802,null,null,null,null,null,null,54806,54807,54808,54809,54810,54811,54813,54814,54815,54817,54818,54819,54821,54822,54823,54824,54825,54826,54827,54828,54830,54831,54832,54833,54834,54835,54836,54837,54838,54839,54842,54843,51669,51670,51673,51674,51676,51677,51680,51682,51684,51687,51692,51693,51695,51696,51697,51704,51705,51708,51712,51720,51721,51723,51724,51725,51732,51736,51753,51788,51789,51792,51796,51804,51805,51807,51808,51809,51816,51837,51844,51864,51900,51901,51904,51908,51916,51917,51919,51921,51923,51928,51929,51936,51948,51956,51976,51984,51988,51992,52000,52001,52033,52040,52041,52044,52048,52056,52057,52061,52068,52088,52089,52124,52152,52180,52196,52199,52201,52236,52237,52240,52244,52252,52253,52257,52258,52263,52264,52265,52268,52270,52272,52280,52281,52283,54845,54846,54847,54849,54850,54851,54852,54854,54855,54858,54860,54862,54863,54864,54866,54867,54870,54871,54873,54874,54875,54877,54878,54879,54880,54881,null,null,null,null,null,null,54882,54883,54884,54885,54886,54888,54890,54891,54892,54893,54894,54895,54898,54899,54901,54902,54903,54904,54905,54906,54907,54908,54909,54910,54911,54912,null,null,null,null,null,null,54913,54914,54916,54918,54919,54920,54921,54922,54923,54926,54927,54929,54930,54931,54933,54934,54935,54936,54937,54938,54939,54940,54942,54944,54946,54947,54948,54949,54950,54951,54953,54954,52284,52285,52286,52292,52293,52296,52300,52308,52309,52311,52312,52313,52320,52324,52326,52328,52336,52341,52376,52377,52380,52384,52392,52393,52395,52396,52397,52404,52405,52408,52412,52420,52421,52423,52425,52432,52436,52452,52460,52464,52481,52488,52489,52492,52496,52504,52505,52507,52509,52516,52520,52524,52537,52572,52576,52580,52588,52589,52591,52593,52600,52616,52628,52629,52632,52636,52644,52645,52647,52649,52656,52676,52684,52688,52712,52716,52720,52728,52729,52731,52733,52740,52744,52748,52756,52761,52768,52769,52772,52776,52784,52785,52787,52789,54955,54957,54958,54959,54961,54962,54963,54964,54965,54966,54967,54968,54970,54972,54973,54974,54975,54976,54977,54978,54979,54982,54983,54985,54986,54987,null,null,null,null,null,null,54989,54990,54991,54992,54994,54995,54997,54998,55000,55002,55003,55004,55005,55006,55007,55009,55010,55011,55013,55014,55015,55017,55018,55019,55020,55021,null,null,null,null,null,null,55022,55023,55025,55026,55027,55028,55030,55031,55032,55033,55034,55035,55038,55039,55041,55042,55043,55045,55046,55047,55048,55049,55050,55051,55052,55053,55054,55055,55056,55058,55059,55060,52824,52825,52828,52831,52832,52833,52840,52841,52843,52845,52852,52853,52856,52860,52868,52869,52871,52873,52880,52881,52884,52888,52896,52897,52899,52900,52901,52908,52909,52929,52964,52965,52968,52971,52972,52980,52981,52983,52984,52985,52992,52993,52996,53000,53008,53009,53011,53013,53020,53024,53028,53036,53037,53039,53040,53041,53048,53076,53077,53080,53084,53092,53093,53095,53097,53104,53105,53108,53112,53120,53125,53132,53153,53160,53168,53188,53216,53217,53220,53224,53232,53233,53235,53237,53244,53248,53252,53265,53272,53293,53300,53301,53304,53308,55061,55062,55063,55066,55067,55069,55070,55071,55073,55074,55075,55076,55077,55078,55079,55082,55084,55086,55087,55088,55089,55090,55091,55094,55095,55097,null,null,null,null,null,null,55098,55099,55101,55102,55103,55104,55105,55106,55107,55109,55110,55112,55114,55115,55116,55117,55118,55119,55122,55123,55125,55130,55131,55132,55133,55134,null,null,null,null,null,null,55135,55138,55140,55142,55143,55144,55146,55147,55149,55150,55151,55153,55154,55155,55157,55158,55159,55160,55161,55162,55163,55166,55167,55168,55170,55171,55172,55173,55174,55175,55178,55179,53316,53317,53319,53321,53328,53332,53336,53344,53356,53357,53360,53364,53372,53373,53377,53412,53413,53416,53420,53428,53429,53431,53433,53440,53441,53444,53448,53449,53456,53457,53459,53460,53461,53468,53469,53472,53476,53484,53485,53487,53488,53489,53496,53517,53552,53553,53556,53560,53562,53568,53569,53571,53572,53573,53580,53581,53584,53588,53596,53597,53599,53601,53608,53612,53628,53636,53640,53664,53665,53668,53672,53680,53681,53683,53685,53690,53692,53696,53720,53748,53752,53767,53769,53776,53804,53805,53808,53812,53820,53821,53823,53825,53832,53852,55181,55182,55183,55185,55186,55187,55188,55189,55190,55191,55194,55196,55198,55199,55200,55201,55202,55203,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,53860,53888,53889,53892,53896,53904,53905,53909,53916,53920,53924,53932,53937,53944,53945,53948,53951,53952,53954,53960,53961,53963,53972,53976,53980,53988,53989,54000,54001,54004,54008,54016,54017,54019,54021,54028,54029,54030,54032,54036,54038,54044,54045,54047,54048,54049,54053,54056,54057,54060,54064,54072,54073,54075,54076,54077,54084,54085,54140,54141,54144,54148,54156,54157,54159,54160,54161,54168,54169,54172,54176,54184,54185,54187,54189,54196,54200,54204,54212,54213,54216,54217,54224,54232,54241,54243,54252,54253,54256,54260,54268,54269,54271,54273,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,54280,54301,54336,54340,54364,54368,54372,54381,54383,54392,54393,54396,54399,54400,54402,54408,54409,54411,54413,54420,54441,54476,54480,54484,54492,54495,54504,54508,54512,54520,54523,54525,54532,54536,54540,54548,54549,54551,54588,54589,54592,54596,54604,54605,54607,54609,54616,54617,54620,54624,54629,54632,54633,54635,54637,54644,54645,54648,54652,54660,54661,54663,54664,54665,54672,54693,54728,54729,54732,54736,54738,54744,54745,54747,54749,54756,54757,54760,54764,54772,54773,54775,54777,54784,54785,54788,54792,54800,54801,54803,54804,54805,54812,54816,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,54820,54829,54840,54841,54844,54848,54853,54856,54857,54859,54861,54865,54868,54869,54872,54876,54887,54889,54896,54897,54900,54915,54917,54924,54925,54928,54932,54941,54943,54945,54952,54956,54960,54969,54971,54980,54981,54984,54988,54993,54996,54999,55001,55008,55012,55016,55024,55029,55036,55037,55040,55044,55057,55064,55065,55068,55072,55080,55081,55083,55085,55092,55093,55096,55100,55108,55111,55113,55120,55121,55124,55126,55127,55128,55129,55136,55137,55139,55141,55145,55148,55152,55156,55164,55165,55169,55176,55177,55180,55184,55192,55193,55195,55197,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,20285,20339,20551,20729,21152,21487,21621,21733,22025,23233,23478,26247,26550,26551,26607,27468,29634,30146,31292,33499,33540,34903,34952,35382,36040,36303,36603,36838,39381,21051,21364,21508,24682,24932,27580,29647,33050,35258,35282,38307,20355,21002,22718,22904,23014,24178,24185,25031,25536,26438,26604,26751,28567,30286,30475,30965,31240,31487,31777,32925,33390,33393,35563,38291,20075,21917,26359,28212,30883,31469,33883,35088,34638,38824,21208,22350,22570,23884,24863,25022,25121,25954,26577,27204,28187,29976,30131,30435,30640,32058,37039,37969,37970,40853,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,21283,23724,30002,32987,37440,38296,21083,22536,23004,23713,23831,24247,24378,24394,24951,27743,30074,30086,31968,32115,32177,32652,33108,33313,34193,35137,35611,37628,38477,40007,20171,20215,20491,20977,22607,24887,24894,24936,25913,27114,28433,30117,30342,30422,31623,33445,33995,63744,37799,38283,21888,23458,22353,63745,31923,32697,37301,20520,21435,23621,24040,25298,25454,25818,25831,28192,28844,31067,36317,36382,63746,36989,37445,37624,20094,20214,20581,24062,24314,24838,26967,33137,34388,36423,37749,39467,20062,20625,26480,26688,20745,21133,21138,27298,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,30652,37392,40660,21163,24623,36850,20552,25001,25581,25802,26684,27268,28608,33160,35233,38548,22533,29309,29356,29956,32121,32365,32937,35211,35700,36963,40273,25225,27770,28500,32080,32570,35363,20860,24906,31645,35609,37463,37772,20140,20435,20510,20670,20742,21185,21197,21375,22384,22659,24218,24465,24950,25004,25806,25964,26223,26299,26356,26775,28039,28805,28913,29855,29861,29898,30169,30828,30956,31455,31478,32069,32147,32789,32831,33051,33686,35686,36629,36885,37857,38915,38968,39514,39912,20418,21843,22586,22865,23395,23622,24760,25106,26690,26800,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,26856,28330,30028,30328,30926,31293,31995,32363,32380,35336,35489,35903,38542,40388,21476,21481,21578,21617,22266,22993,23396,23611,24235,25335,25911,25925,25970,26272,26543,27073,27837,30204,30352,30590,31295,32660,32771,32929,33167,33510,33533,33776,34241,34865,34996,35493,63747,36764,37678,38599,39015,39640,40723,21741,26011,26354,26767,31296,35895,40288,22256,22372,23825,26118,26801,26829,28414,29736,34974,39908,27752,63748,39592,20379,20844,20849,21151,23380,24037,24656,24685,25329,25511,25915,29657,31354,34467,36002,38799,20018,23521,25096,26524,29916,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,31185,33747,35463,35506,36328,36942,37707,38982,24275,27112,34303,37101,63749,20896,23448,23532,24931,26874,27454,28748,29743,29912,31649,32592,33733,35264,36011,38364,39208,21038,24669,25324,36866,20362,20809,21281,22745,24291,26336,27960,28826,29378,29654,31568,33009,37979,21350,25499,32619,20054,20608,22602,22750,24618,24871,25296,27088,39745,23439,32024,32945,36703,20132,20689,21676,21932,23308,23968,24039,25898,25934,26657,27211,29409,30350,30703,32094,32761,33184,34126,34527,36611,36686,37066,39171,39509,39851,19992,20037,20061,20167,20465,20855,21246,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,21312,21475,21477,21646,22036,22389,22434,23495,23943,24272,25084,25304,25937,26552,26601,27083,27472,27590,27628,27714,28317,28792,29399,29590,29699,30655,30697,31350,32127,32777,33276,33285,33290,33503,34914,35635,36092,36544,36881,37041,37476,37558,39378,39493,40169,40407,40860,22283,23616,33738,38816,38827,40628,21531,31384,32676,35033,36557,37089,22528,23624,25496,31391,23470,24339,31353,31406,33422,36524,20518,21048,21240,21367,22280,25331,25458,27402,28099,30519,21413,29527,34152,36470,38357,26426,27331,28528,35437,36556,39243,63750,26231,27512,36020,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,39740,63751,21483,22317,22862,25542,27131,29674,30789,31418,31429,31998,33909,35215,36211,36917,38312,21243,22343,30023,31584,33740,37406,63752,27224,20811,21067,21127,25119,26840,26997,38553,20677,21156,21220,25027,26020,26681,27135,29822,31563,33465,33771,35250,35641,36817,39241,63753,20170,22935,25810,26129,27278,29748,31105,31165,33449,34942,34943,35167,63754,37670,20235,21450,24613,25201,27762,32026,32102,20120,20834,30684,32943,20225,20238,20854,20864,21980,22120,22331,22522,22524,22804,22855,22931,23492,23696,23822,24049,24190,24524,25216,26071,26083,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,26398,26399,26462,26827,26820,27231,27450,27683,27773,27778,28103,29592,29734,29738,29826,29859,30072,30079,30849,30959,31041,31047,31048,31098,31637,32000,32186,32648,32774,32813,32908,35352,35663,35912,36215,37665,37668,39138,39249,39438,39439,39525,40594,32202,20342,21513,25326,26708,37329,21931,20794,63755,63756,23068,25062,63757,25295,25343,63758,63759,63760,63761,63762,63763,37027,63764,63765,63766,63767,63768,35582,63769,63770,63771,63772,26262,63773,29014,63774,63775,38627,63776,25423,25466,21335,63777,26511,26976,28275,63778,30007,63779,63780,63781,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,32013,63782,63783,34930,22218,23064,63784,63785,63786,63787,63788,20035,63789,20839,22856,26608,32784,63790,22899,24180,25754,31178,24565,24684,25288,25467,23527,23511,21162,63791,22900,24361,24594,63792,63793,63794,29785,63795,63796,63797,63798,63799,63800,39377,63801,63802,63803,63804,63805,63806,63807,63808,63809,63810,63811,28611,63812,63813,33215,36786,24817,63814,63815,33126,63816,63817,23615,63818,63819,63820,63821,63822,63823,63824,63825,23273,35365,26491,32016,63826,63827,63828,63829,63830,63831,33021,63832,63833,23612,27877,21311,28346,22810,33590,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,20025,20150,20294,21934,22296,22727,24406,26039,26086,27264,27573,28237,30701,31471,31774,32222,34507,34962,37170,37723,25787,28606,29562,30136,36948,21846,22349,25018,25812,26311,28129,28251,28525,28601,30192,32835,33213,34113,35203,35527,35674,37663,27795,30035,31572,36367,36957,21776,22530,22616,24162,25095,25758,26848,30070,31958,34739,40680,20195,22408,22382,22823,23565,23729,24118,24453,25140,25825,29619,33274,34955,36024,38538,40667,23429,24503,24755,20498,20992,21040,22294,22581,22615,23566,23648,23798,23947,24230,24466,24764,25361,25481,25623,26691,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,26873,27330,28120,28193,28372,28644,29182,30428,30585,31153,31291,33796,35241,36077,36339,36424,36867,36884,36947,37117,37709,38518,38876,27602,28678,29272,29346,29544,30563,31167,31716,32411,35712,22697,24775,25958,26109,26302,27788,28958,29129,35930,38931,20077,31361,20189,20908,20941,21205,21516,24999,26481,26704,26847,27934,28540,30140,30643,31461,33012,33891,37509,20828,26007,26460,26515,30168,31431,33651,63834,35910,36887,38957,23663,33216,33434,36929,36975,37389,24471,23965,27225,29128,30331,31561,34276,35588,37159,39472,21895,25078,63835,30313,32645,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,34367,34746,35064,37007,63836,27931,28889,29662,32097,33853,63837,37226,39409,63838,20098,21365,27396,27410,28734,29211,34349,40478,21068,36771,23888,25829,25900,27414,28651,31811,32412,34253,35172,35261,25289,33240,34847,24266,26391,28010,29436,29701,29807,34690,37086,20358,23821,24480,33802,20919,25504,30053,20142,20486,20841,20937,26753,27153,31918,31921,31975,33391,35538,36635,37327,20406,20791,21237,21570,24300,24942,25150,26053,27354,28670,31018,34268,34851,38317,39522,39530,40599,40654,21147,26310,27511,28701,31019,36706,38722,24976,25088,25891,28451,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,29001,29833,32244,32879,34030,36646,36899,37706,20925,21015,21155,27916,28872,35010,24265,25986,27566,28610,31806,29557,20196,20278,22265,63839,23738,23994,24604,29618,31533,32666,32718,32838,36894,37428,38646,38728,38936,40801,20363,28583,31150,37300,38583,21214,63840,25736,25796,27347,28510,28696,29200,30439,32769,34310,34396,36335,36613,38706,39791,40442,40565,30860,31103,32160,33737,37636,40575,40595,35542,22751,24324,26407,28711,29903,31840,32894,20769,28712,29282,30922,36034,36058,36084,38647,20102,20698,23534,24278,26009,29134,30274,30637,32842,34044,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36988,39719,40845,22744,23105,23650,27155,28122,28431,30267,32047,32311,34078,35128,37860,38475,21129,26066,26611,27060,27969,28316,28687,29705,29792,30041,30244,30827,35628,39006,20845,25134,38520,20374,20523,23833,28138,32184,36650,24459,24900,26647,63841,38534,21202,32907,20956,20940,26974,31260,32190,33777,38517,20442,21033,21400,21519,21774,23653,24743,26446,26792,28012,29313,29432,29702,29827,63842,30178,31852,32633,32696,33673,35023,35041,37324,37328,38626,39881,21533,28542,29136,29848,34298,36522,38563,40023,40607,26519,28107,29747,33256,38678,30764,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,31435,31520,31890,25705,29802,30194,30908,30952,39340,39764,40635,23518,24149,28448,33180,33707,37000,19975,21325,23081,24018,24398,24930,25405,26217,26364,28415,28459,28771,30622,33836,34067,34875,36627,39237,39995,21788,25273,26411,27819,33545,35178,38778,20129,22916,24536,24537,26395,32178,32596,33426,33579,33725,36638,37017,22475,22969,23186,23504,26151,26522,26757,27599,29028,32629,36023,36067,36993,39749,33032,35978,38476,39488,40613,23391,27667,29467,30450,30431,33804,20906,35219,20813,20885,21193,26825,27796,30468,30496,32191,32236,38754,40629,28357,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,34065,20901,21517,21629,26126,26269,26919,28319,30399,30609,33559,33986,34719,37225,37528,40180,34946,20398,20882,21215,22982,24125,24917,25720,25721,26286,26576,27169,27597,27611,29279,29281,29761,30520,30683,32791,33468,33541,35584,35624,35980,26408,27792,29287,30446,30566,31302,40361,27519,27794,22818,26406,33945,21359,22675,22937,24287,25551,26164,26483,28218,29483,31447,33495,37672,21209,24043,25006,25035,25098,25287,25771,26080,26969,27494,27595,28961,29687,30045,32326,33310,33538,34154,35491,36031,38695,40289,22696,40664,20497,21006,21563,21839,25991,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,27766,32010,32011,32862,34442,38272,38639,21247,27797,29289,21619,23194,23614,23883,24396,24494,26410,26806,26979,28220,28228,30473,31859,32654,34183,35598,36855,38753,40692,23735,24758,24845,25003,25935,26107,26108,27665,27887,29599,29641,32225,38292,23494,34588,35600,21085,21338,25293,25615,25778,26420,27192,27850,29632,29854,31636,31893,32283,33162,33334,34180,36843,38649,39361,20276,21322,21453,21467,25292,25644,25856,26001,27075,27886,28504,29677,30036,30242,30436,30460,30928,30971,31020,32070,33324,34784,36820,38930,39151,21187,25300,25765,28196,28497,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,30332,36299,37297,37474,39662,39747,20515,20621,22346,22952,23592,24135,24439,25151,25918,26041,26049,26121,26507,27036,28354,30917,32033,32938,33152,33323,33459,33953,34444,35370,35607,37030,38450,40848,20493,20467,63843,22521,24472,25308,25490,26479,28227,28953,30403,32972,32986,35060,35061,35097,36064,36649,37197,38506,20271,20336,24091,26575,26658,30333,30334,39748,24161,27146,29033,29140,30058,63844,32321,34115,34281,39132,20240,31567,32624,38309,20961,24070,26805,27710,27726,27867,29359,31684,33539,27861,29754,20731,21128,22721,25816,27287,29863,30294,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,30887,34327,38370,38713,63845,21342,24321,35722,36776,36783,37002,21029,30629,40009,40712,19993,20482,20853,23643,24183,26142,26170,26564,26821,28851,29953,30149,31177,31453,36647,39200,39432,20445,22561,22577,23542,26222,27493,27921,28282,28541,29668,29995,33769,35036,35091,35676,36628,20239,20693,21264,21340,23443,24489,26381,31119,33145,33583,34068,35079,35206,36665,36667,39333,39954,26412,20086,20472,22857,23553,23791,23792,25447,26834,28925,29090,29739,32299,34028,34562,36898,37586,40179,19981,20184,20463,20613,21078,21103,21542,21648,22496,22827,23142,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,23386,23413,23500,24220,63846,25206,25975,26023,28014,28325,29238,31526,31807,32566,33104,33105,33178,33344,33433,33705,35331,36000,36070,36091,36212,36282,37096,37340,38428,38468,39385,40167,21271,20998,21545,22132,22707,22868,22894,24575,24996,25198,26128,27774,28954,30406,31881,31966,32027,33452,36033,38640,63847,20315,24343,24447,25282,23849,26379,26842,30844,32323,40300,19989,20633,21269,21290,21329,22915,23138,24199,24754,24970,25161,25209,26000,26503,27047,27604,27606,27607,27608,27832,63848,29749,30202,30738,30865,31189,31192,31875,32203,32737,32933,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,33086,33218,33778,34586,35048,35513,35692,36027,37145,38750,39131,40763,22188,23338,24428,25996,27315,27567,27996,28657,28693,29277,29613,36007,36051,38971,24977,27703,32856,39425,20045,20107,20123,20181,20282,20284,20351,20447,20735,21490,21496,21766,21987,22235,22763,22882,23057,23531,23546,23556,24051,24107,24473,24605,25448,26012,26031,26614,26619,26797,27515,27801,27863,28195,28681,29509,30722,31038,31040,31072,31169,31721,32023,32114,32902,33293,33678,34001,34503,35039,35408,35422,35613,36060,36198,36781,37034,39164,39391,40605,21066,63849,26388,63850,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,20632,21034,23665,25955,27733,29642,29987,30109,31639,33948,37240,38704,20087,25746,27578,29022,34217,19977,63851,26441,26862,28183,33439,34072,34923,25591,28545,37394,39087,19978,20663,20687,20767,21830,21930,22039,23360,23577,23776,24120,24202,24224,24258,24819,26705,27233,28248,29245,29248,29376,30456,31077,31665,32724,35059,35316,35443,35937,36062,38684,22622,29885,36093,21959,63852,31329,32034,33394,29298,29983,29989,63853,31513,22661,22779,23996,24207,24246,24464,24661,25234,25471,25933,26257,26329,26360,26646,26866,29312,29790,31598,32110,32214,32626,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,32997,33298,34223,35199,35475,36893,37604,40653,40736,22805,22893,24109,24796,26132,26227,26512,27728,28101,28511,30707,30889,33990,37323,37675,20185,20682,20808,21892,23307,23459,25159,25982,26059,28210,29053,29697,29764,29831,29887,30316,31146,32218,32341,32680,33146,33203,33337,34330,34796,35445,36323,36984,37521,37925,39245,39854,21352,23633,26964,27844,27945,28203,33292,34203,35131,35373,35498,38634,40807,21089,26297,27570,32406,34814,36109,38275,38493,25885,28041,29166,63854,22478,22995,23468,24615,24826,25104,26143,26207,29481,29689,30427,30465,31596,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,32854,32882,33125,35488,37266,19990,21218,27506,27927,31237,31545,32048,63855,36016,21484,22063,22609,23477,23567,23569,24034,25152,25475,25620,26157,26803,27836,28040,28335,28703,28836,29138,29990,30095,30094,30233,31505,31712,31787,32032,32057,34092,34157,34311,35380,36877,36961,37045,37559,38902,39479,20439,23660,26463,28049,31903,32396,35606,36118,36895,23403,24061,25613,33984,36956,39137,29575,23435,24730,26494,28126,35359,35494,36865,38924,21047,63856,28753,30862,37782,34928,37335,20462,21463,22013,22234,22402,22781,23234,23432,23723,23744,24101,24833,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,25101,25163,25480,25628,25910,25976,27193,27530,27700,27929,28465,29159,29417,29560,29703,29874,30246,30561,31168,31319,31466,31929,32143,32172,32353,32670,33065,33585,33936,34010,34282,34966,35504,35728,36664,36930,36995,37228,37526,37561,38539,38567,38568,38614,38656,38920,39318,39635,39706,21460,22654,22809,23408,23487,28113,28506,29087,29729,29881,32901,33789,24033,24455,24490,24642,26092,26642,26991,27219,27529,27957,28147,29667,30462,30636,31565,32020,33059,33308,33600,34036,34147,35426,35524,37255,37662,38918,39348,25100,34899,36848,37477,23815,23847,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,23913,29791,33181,34664,28629,25342,32722,35126,35186,19998,20056,20711,21213,21319,25215,26119,32361,34821,38494,20365,21273,22070,22987,23204,23608,23630,23629,24066,24337,24643,26045,26159,26178,26558,26612,29468,30690,31034,32709,33940,33997,35222,35430,35433,35553,35925,35962,22516,23508,24335,24687,25325,26893,27542,28252,29060,31698,34645,35672,36606,39135,39166,20280,20353,20449,21627,23072,23480,24892,26032,26216,29180,30003,31070,32051,33102,33251,33688,34218,34254,34563,35338,36523,36763,63857,36805,22833,23460,23526,24713,23529,23563,24515,27777,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,63858,28145,28683,29978,33455,35574,20160,21313,63859,38617,27663,20126,20420,20818,21854,23077,23784,25105,29273,33469,33706,34558,34905,35357,38463,38597,39187,40201,40285,22538,23731,23997,24132,24801,24853,25569,27138,28197,37122,37716,38990,39952,40823,23433,23736,25353,26191,26696,30524,38593,38797,38996,39839,26017,35585,36555,38332,21813,23721,24022,24245,26263,30284,33780,38343,22739,25276,29390,40232,20208,22830,24591,26171,27523,31207,40230,21395,21696,22467,23830,24859,26326,28079,30861,33406,38552,38724,21380,25212,25494,28082,32266,33099,38989,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,27387,32588,40367,40474,20063,20539,20918,22812,24825,25590,26928,29242,32822,63860,37326,24369,63861,63862,32004,33509,33903,33979,34277,36493,63863,20335,63864,63865,22756,23363,24665,25562,25880,25965,26264,63866,26954,27171,27915,28673,29036,30162,30221,31155,31344,63867,32650,63868,35140,63869,35731,37312,38525,63870,39178,22276,24481,26044,28417,30208,31142,35486,39341,39770,40812,20740,25014,25233,27277,33222,20547,22576,24422,28937,35328,35578,23420,34326,20474,20796,22196,22852,25513,28153,23978,26989,20870,20104,20313,63871,63872,63873,22914,63874,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,63875,27487,27741,63876,29877,30998,63877,33287,33349,33593,36671,36701,63878,39192,63879,63880,63881,20134,63882,22495,24441,26131,63883,63884,30123,32377,35695,63885,36870,39515,22181,22567,23032,23071,23476,63886,24310,63887,63888,25424,25403,63889,26941,27783,27839,28046,28051,28149,28436,63890,28895,28982,29017,63891,29123,29141,63892,30799,30831,63893,31605,32227,63894,32303,63895,34893,36575,63896,63897,63898,37467,63899,40182,63900,63901,63902,24709,28037,63903,29105,63904,63905,38321,21421,63906,63907,63908,26579,63909,28814,28976,29744,33398,33490,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,63910,38331,39653,40573,26308,63911,29121,33865,63912,63913,22603,63914,63915,23992,24433,63916,26144,26254,27001,27054,27704,27891,28214,28481,28634,28699,28719,29008,29151,29552,63917,29787,63918,29908,30408,31310,32403,63919,63920,33521,35424,36814,63921,37704,63922,38681,63923,63924,20034,20522,63925,21000,21473,26355,27757,28618,29450,30591,31330,33454,34269,34306,63926,35028,35427,35709,35947,63927,37555,63928,38675,38928,20116,20237,20425,20658,21320,21566,21555,21978,22626,22714,22887,23067,23524,24735,63929,25034,25942,26111,26212,26791,27738,28595,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,28879,29100,29522,31613,34568,35492,39986,40711,23627,27779,29508,29577,37434,28331,29797,30239,31337,32277,34314,20800,22725,25793,29934,29973,30320,32705,37013,38605,39252,28198,29926,31401,31402,33253,34521,34680,35355,23113,23436,23451,26785,26880,28003,29609,29715,29740,30871,32233,32747,33048,33109,33694,35916,38446,38929,26352,24448,26106,26505,27754,29579,20525,23043,27498,30702,22806,23916,24013,29477,30031,63930,63931,20709,20985,22575,22829,22934,23002,23525,63932,63933,23970,25303,25622,25747,25854,63934,26332,63935,27208,63936,29183,29796,63937,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,31368,31407,32327,32350,32768,33136,63938,34799,35201,35616,36953,63939,36992,39250,24958,27442,28020,32287,35109,36785,20433,20653,20887,21191,22471,22665,23481,24248,24898,27029,28044,28263,28342,29076,29794,29992,29996,32883,33592,33993,36362,37780,37854,63940,20110,20305,20598,20778,21448,21451,21491,23431,23507,23588,24858,24962,26100,29275,29591,29760,30402,31056,31121,31161,32006,32701,33419,34261,34398,36802,36935,37109,37354,38533,38632,38633,21206,24423,26093,26161,26671,29020,31286,37057,38922,20113,63941,27218,27550,28560,29065,32792,33464,34131,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36939,38549,38642,38907,34074,39729,20112,29066,38596,20803,21407,21729,22291,22290,22435,23195,23236,23491,24616,24895,25588,27781,27961,28274,28304,29232,29503,29783,33489,34945,36677,36960,63942,38498,39000,40219,26376,36234,37470,20301,20553,20702,21361,22285,22996,23041,23561,24944,26256,28205,29234,29771,32239,32963,33806,33894,34111,34655,34907,35096,35586,36949,38859,39759,20083,20369,20754,20842,63943,21807,21929,23418,23461,24188,24189,24254,24736,24799,24840,24841,25540,25912,26377,63944,26580,26586,63945,26977,26978,27833,27943,63946,28216,63947,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,28641,29494,29495,63948,29788,30001,63949,30290,63950,63951,32173,33278,33848,35029,35480,35547,35565,36400,36418,36938,36926,36986,37193,37321,37742,63952,63953,22537,63954,27603,32905,32946,63955,63956,20801,22891,23609,63957,63958,28516,29607,32996,36103,63959,37399,38287,63960,63961,63962,63963,32895,25102,28700,32104,34701,63964,22432,24681,24903,27575,35518,37504,38577,20057,21535,28139,34093,38512,38899,39150,25558,27875,37009,20957,25033,33210,40441,20381,20506,20736,23452,24847,25087,25836,26885,27589,30097,30691,32681,33380,34191,34811,34915,35516,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,35696,37291,20108,20197,20234,63965,63966,22839,23016,63967,24050,24347,24411,24609,63968,63969,63970,63971,29246,29669,63972,30064,30157,63973,31227,63974,32780,32819,32900,33505,33617,63975,63976,36029,36019,36999,63977,63978,39156,39180,63979,63980,28727,30410,32714,32716,32764,35610,20154,20161,20995,21360,63981,21693,22240,23035,23493,24341,24525,28270,63982,63983,32106,33589,63984,34451,35469,63985,38765,38775,63986,63987,19968,20314,20350,22777,26085,28322,36920,37808,39353,20219,22764,22922,23001,24641,63988,63989,31252,63990,33615,36035,20837,21316,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,63991,63992,63993,20173,21097,23381,33471,20180,21050,21672,22985,23039,23376,23383,23388,24675,24904,28363,28825,29038,29574,29943,30133,30913,32043,32773,33258,33576,34071,34249,35566,36039,38604,20316,21242,22204,26027,26152,28796,28856,29237,32189,33421,37196,38592,40306,23409,26855,27544,28538,30430,23697,26283,28507,31668,31786,34870,38620,19976,20183,21280,22580,22715,22767,22892,23559,24115,24196,24373,25484,26290,26454,27167,27299,27404,28479,29254,63994,29520,29835,31456,31911,33144,33247,33255,33674,33900,34083,34196,34255,35037,36115,37292,38263,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,38556,20877,21705,22312,23472,25165,26448,26685,26771,28221,28371,28797,32289,35009,36001,36617,40779,40782,29229,31631,35533,37658,20295,20302,20786,21632,22992,24213,25269,26485,26990,27159,27822,28186,29401,29482,30141,31672,32053,33511,33785,33879,34295,35419,36015,36487,36889,37048,38606,40799,21219,21514,23265,23490,25688,25973,28404,29380,63995,30340,31309,31515,31821,32318,32735,33659,35627,36042,36196,36321,36447,36842,36857,36969,37841,20291,20346,20659,20840,20856,21069,21098,22625,22652,22880,23560,23637,24283,24731,25136,26643,27583,27656,28593,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,29006,29728,30000,30008,30033,30322,31564,31627,31661,31686,32399,35438,36670,36681,37439,37523,37666,37931,38651,39002,39019,39198,20999,25130,25240,27993,30308,31434,31680,32118,21344,23742,24215,28472,28857,31896,38673,39822,40670,25509,25722,34678,19969,20117,20141,20572,20597,21576,22979,23450,24128,24237,24311,24449,24773,25402,25919,25972,26060,26230,26232,26622,26984,27273,27491,27712,28096,28136,28191,28254,28702,28833,29582,29693,30010,30555,30855,31118,31243,31357,31934,32142,33351,35330,35562,35998,37165,37194,37336,37478,37580,37664,38662,38742,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,38748,38914,40718,21046,21137,21884,22564,24093,24351,24716,25552,26799,28639,31085,31532,33229,34234,35069,35576,36420,37261,38500,38555,38717,38988,40778,20430,20806,20939,21161,22066,24340,24427,25514,25805,26089,26177,26362,26361,26397,26781,26839,27133,28437,28526,29031,29157,29226,29866,30522,31062,31066,31199,31264,31381,31895,31967,32068,32368,32903,34299,34468,35412,35519,36249,36481,36896,36973,37347,38459,38613,40165,26063,31751,36275,37827,23384,23562,21330,25305,29469,20519,23447,24478,24752,24939,26837,28121,29742,31278,32066,32156,32305,33131,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36394,36405,37758,37912,20304,22352,24038,24231,25387,32618,20027,20303,20367,20570,23005,32964,21610,21608,22014,22863,23449,24030,24282,26205,26417,26609,26666,27880,27954,28234,28557,28855,29664,30087,31820,32002,32044,32162,33311,34523,35387,35461,36208,36490,36659,36913,37198,37202,37956,39376,31481,31909,20426,20737,20934,22472,23535,23803,26201,27197,27994,28310,28652,28940,30063,31459,34850,36897,36981,38603,39423,33537,20013,20210,34886,37325,21373,27355,26987,27713,33914,22686,24974,26366,25327,28893,29969,30151,32338,33976,35657,36104,20043,21482,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,21675,22320,22336,24535,25345,25351,25711,25903,26088,26234,26525,26547,27490,27744,27802,28460,30693,30757,31049,31063,32025,32930,33026,33267,33437,33463,34584,35468,63996,36100,36286,36978,30452,31257,31287,32340,32887,21767,21972,22645,25391,25634,26185,26187,26733,27035,27524,27941,28337,29645,29800,29857,30043,30137,30433,30494,30603,31206,32265,32285,33275,34095,34967,35386,36049,36587,36784,36914,37805,38499,38515,38663,20356,21489,23018,23241,24089,26702,29894,30142,31209,31378,33187,34541,36074,36300,36845,26015,26389,63997,22519,28503,32221,36655,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,37878,38598,24501,25074,28548,19988,20376,20511,21449,21983,23919,24046,27425,27492,30923,31642,63998,36425,36554,36974,25417,25662,30528,31364,37679,38015,40810,25776,28591,29158,29864,29914,31428,31762,32386,31922,32408,35738,36106,38013,39184,39244,21049,23519,25830,26413,32046,20717,21443,22649,24920,24921,25082,26028,31449,35730,35734,20489,20513,21109,21809,23100,24288,24432,24884,25950,26124,26166,26274,27085,28356,28466,29462,30241,31379,33081,33369,33750,33980,20661,22512,23488,23528,24425,25505,30758,32181,33756,34081,37319,37365,20874,26613,31574,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36012,20932,22971,24765,34389,20508,63999,21076,23610,24957,25114,25299,25842,26021,28364,30240,33034,36448,38495,38587,20191,21315,21912,22825,24029,25797,27849,28154,29588,31359,33307,34214,36068,36368,36983,37351,38369,38433,38854,20984,21746,21894,24505,25764,28552,32180,36639,36685,37941,20681,23574,27838,28155,29979,30651,31805,31844,35449,35522,22558,22974,24086,25463,29266,30090,30571,35548,36028,36626,24307,26228,28152,32893,33729,35531,38737,39894,64000,21059,26367,28053,28399,32224,35558,36910,36958,39636,21021,21119,21736,24980,25220,25307,26786,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,26898,26970,27189,28818,28966,30813,30977,30990,31186,31245,32918,33400,33493,33609,34121,35970,36229,37218,37259,37294,20419,22225,29165,30679,34560,35320,23544,24534,26449,37032,21474,22618,23541,24740,24961,25696,32317,32880,34085,37507,25774,20652,23828,26368,22684,25277,25512,26894,27000,27166,28267,30394,31179,33467,33833,35535,36264,36861,37138,37195,37276,37648,37656,37786,38619,39478,39949,19985,30044,31069,31482,31569,31689,32302,33988,36441,36468,36600,36880,26149,26943,29763,20986,26414,40668,20805,24544,27798,34802,34909,34935,24756,33205,33795,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,36101,21462,21561,22068,23094,23601,28810,32736,32858,33030,33261,36259,37257,39519,40434,20596,20164,21408,24827,28204,23652,20360,20516,21988,23769,24159,24677,26772,27835,28100,29118,30164,30196,30305,31258,31305,32199,32251,32622,33268,34473,36636,38601,39347,40786,21063,21189,39149,35242,19971,26578,28422,20405,23522,26517,27784,28024,29723,30759,37341,37756,34756,31204,31281,24555,20182,21668,21822,22702,22949,24816,25171,25302,26422,26965,33333,38464,39345,39389,20524,21331,21828,22396,64001,25176,64002,25826,26219,26589,28609,28655,29730,29752,35351,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,37944,21585,22022,22374,24392,24986,27470,28760,28845,32187,35477,22890,33067,25506,30472,32829,36010,22612,25645,27067,23445,24081,28271,64003,34153,20812,21488,22826,24608,24907,27526,27760,27888,31518,32974,33492,36294,37040,39089,64004,25799,28580,25745,25860,20814,21520,22303,35342,24927,26742,64005,30171,31570,32113,36890,22534,27084,33151,35114,36864,38969,20600,22871,22956,25237,36879,39722,24925,29305,38358,22369,23110,24052,25226,25773,25850,26487,27874,27966,29228,29750,30772,32631,33453,36315,38935,21028,22338,26495,29256,29923,36009,36774,37393,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,38442,20843,21485,25420,20329,21764,24726,25943,27803,28031,29260,29437,31255,35207,35997,24429,28558,28921,33192,24846,20415,20559,25153,29255,31687,32232,32745,36941,38829,39449,36022,22378,24179,26544,33805,35413,21536,23318,24163,24290,24330,25987,32954,34109,38281,38491,20296,21253,21261,21263,21638,21754,22275,24067,24598,25243,25265,25429,64006,27873,28006,30129,30770,32990,33071,33502,33889,33970,34957,35090,36875,37610,39165,39825,24133,26292,26333,28689,29190,64007,20469,21117,24426,24915,26451,27161,28418,29922,31080,34920,35961,39111,39108,39491,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,21697,31263,26963,35575,35914,39080,39342,24444,25259,30130,30382,34987,36991,38466,21305,24380,24517,27852,29644,30050,30091,31558,33534,39325,20047,36924,19979,20309,21414,22799,24264,26160,27827,29781,33655,34662,36032,36944,38686,39957,22737,23416,34384,35604,40372,23506,24680,24717,26097,27735,28450,28579,28698,32597,32752,38289,38290,38480,38867,21106,36676,20989,21547,21688,21859,21898,27323,28085,32216,33382,37532,38519,40569,21512,21704,30418,34532,38308,38356,38492,20130,20233,23022,23270,24055,24658,25239,26477,26689,27782,28207,32568,32923,33322,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,64008,64009,38917,20133,20565,21683,22419,22874,23401,23475,25032,26999,28023,28707,34809,35299,35442,35559,36994,39405,39608,21182,26680,20502,24184,26447,33607,34892,20139,21521,22190,29670,37141,38911,39177,39255,39321,22099,22687,34395,35377,25010,27382,29563,36562,27463,38570,39511,22869,29184,36203,38761,20436,23796,24358,25080,26203,27883,28843,29572,29625,29694,30505,30541,32067,32098,32291,33335,34898,64010,36066,37449,39023,23377,31348,34880,38913,23244,20448,21332,22846,23805,25406,28025,29433,33029,33031,33698,37583,38960,20136,20804,21009,22411,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,24418,27842,28366,28677,28752,28847,29074,29673,29801,33610,34722,34913,36872,37026,37795,39336,20846,24407,24800,24935,26291,34137,36426,37295,38795,20046,20114,21628,22741,22778,22909,23733,24359,25142,25160,26122,26215,27627,28009,28111,28246,28408,28564,28640,28649,28765,29392,29733,29786,29920,30355,31068,31946,32286,32993,33446,33899,33983,34382,34399,34676,35703,35946,37804,38912,39013,24785,25110,37239,23130,26127,28151,28222,29759,39746,24573,24794,31503,21700,24344,27742,27859,27946,28888,32005,34425,35340,40251,21270,21644,23301,27194,28779,30069,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,31117,31166,33457,33775,35441,35649,36008,38772,64011,25844,25899,30906,30907,31339,20024,21914,22864,23462,24187,24739,25563,27489,26213,26707,28185,29029,29872,32008,36996,39529,39973,27963,28369,29502,35905,38346,20976,24140,24488,24653,24822,24880,24908,26179,26180,27045,27841,28255,28361,28514,29004,29852,30343,31681,31783,33618,34647,36945,38541,40643,21295,22238,24315,24458,24674,24724,25079,26214,26371,27292,28142,28590,28784,29546,32362,33214,33588,34516,35496,36036,21123,29554,23446,27243,37892,21742,22150,23389,25928,25989,26313,26783,28045,28102,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,29243,32948,37237,39501,20399,20505,21402,21518,21564,21897,21957,24127,24460,26429,29030,29661,36869,21211,21235,22628,22734,28932,29071,29179,34224,35347,26248,34216,21927,26244,29002,33841,21321,21913,27585,24409,24509,25582,26249,28999,35569,36637,40638,20241,25658,28875,30054,34407,24676,35662,40440,20807,20982,21256,27958,33016,40657,26133,27427,28824,30165,21507,23673,32007,35350,27424,27453,27462,21560,24688,27965,32725,33288,20694,20958,21916,22123,22221,23020,23305,24076,24985,24984,25137,26206,26342,29081,29113,29114,29351,31143,31232,32690,35440,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],
+ "gb18030":[19970,19972,19973,19974,19983,19986,19991,19999,20000,20001,20003,20006,20009,20014,20015,20017,20019,20021,20023,20028,20032,20033,20034,20036,20038,20042,20049,20053,20055,20058,20059,20066,20067,20068,20069,20071,20072,20074,20075,20076,20077,20078,20079,20082,20084,20085,20086,20087,20088,20089,20090,20091,20092,20093,20095,20096,20097,20098,20099,20100,20101,20103,20106,20112,20118,20119,20121,20124,20125,20126,20131,20138,20143,20144,20145,20148,20150,20151,20152,20153,20156,20157,20158,20168,20172,20175,20176,20178,20186,20187,20188,20192,20194,20198,20199,20201,20205,20206,20207,20209,20212,20216,20217,20218,20220,20222,20224,20226,20227,20228,20229,20230,20231,20232,20235,20236,20242,20243,20244,20245,20246,20252,20253,20257,20259,20264,20265,20268,20269,20270,20273,20275,20277,20279,20281,20283,20286,20287,20288,20289,20290,20292,20293,20295,20296,20297,20298,20299,20300,20306,20308,20310,20321,20322,20326,20328,20330,20331,20333,20334,20337,20338,20341,20343,20344,20345,20346,20349,20352,20353,20354,20357,20358,20359,20362,20364,20366,20368,20370,20371,20373,20374,20376,20377,20378,20380,20382,20383,20385,20386,20388,20395,20397,20400,20401,20402,20403,20404,20406,20407,20408,20409,20410,20411,20412,20413,20414,20416,20417,20418,20422,20423,20424,20425,20427,20428,20429,20434,20435,20436,20437,20438,20441,20443,20448,20450,20452,20453,20455,20459,20460,20464,20466,20468,20469,20470,20471,20473,20475,20476,20477,20479,20480,20481,20482,20483,20484,20485,20486,20487,20488,20489,20490,20491,20494,20496,20497,20499,20501,20502,20503,20507,20509,20510,20512,20514,20515,20516,20519,20523,20527,20528,20529,20530,20531,20532,20533,20534,20535,20536,20537,20539,20541,20543,20544,20545,20546,20548,20549,20550,20553,20554,20555,20557,20560,20561,20562,20563,20564,20566,20567,20568,20569,20571,20573,20574,20575,20576,20577,20578,20579,20580,20582,20583,20584,20585,20586,20587,20589,20590,20591,20592,20593,20594,20595,20596,20597,20600,20601,20602,20604,20605,20609,20610,20611,20612,20614,20615,20617,20618,20619,20620,20622,20623,20624,20625,20626,20627,20628,20629,20630,20631,20632,20633,20634,20635,20636,20637,20638,20639,20640,20641,20642,20644,20646,20650,20651,20653,20654,20655,20656,20657,20659,20660,20661,20662,20663,20664,20665,20668,20669,20670,20671,20672,20673,20674,20675,20676,20677,20678,20679,20680,20681,20682,20683,20684,20685,20686,20688,20689,20690,20691,20692,20693,20695,20696,20697,20699,20700,20701,20702,20703,20704,20705,20706,20707,20708,20709,20712,20713,20714,20715,20719,20720,20721,20722,20724,20726,20727,20728,20729,20730,20732,20733,20734,20735,20736,20737,20738,20739,20740,20741,20744,20745,20746,20748,20749,20750,20751,20752,20753,20755,20756,20757,20758,20759,20760,20761,20762,20763,20764,20765,20766,20767,20768,20770,20771,20772,20773,20774,20775,20776,20777,20778,20779,20780,20781,20782,20783,20784,20785,20786,20787,20788,20789,20790,20791,20792,20793,20794,20795,20796,20797,20798,20802,20807,20810,20812,20814,20815,20816,20818,20819,20823,20824,20825,20827,20829,20830,20831,20832,20833,20835,20836,20838,20839,20841,20842,20847,20850,20858,20862,20863,20867,20868,20870,20871,20874,20875,20878,20879,20880,20881,20883,20884,20888,20890,20893,20894,20895,20897,20899,20902,20903,20904,20905,20906,20909,20910,20916,20920,20921,20922,20926,20927,20929,20930,20931,20933,20936,20938,20941,20942,20944,20946,20947,20948,20949,20950,20951,20952,20953,20954,20956,20958,20959,20962,20963,20965,20966,20967,20968,20969,20970,20972,20974,20977,20978,20980,20983,20990,20996,20997,21001,21003,21004,21007,21008,21011,21012,21013,21020,21022,21023,21025,21026,21027,21029,21030,21031,21034,21036,21039,21041,21042,21044,21045,21052,21054,21060,21061,21062,21063,21064,21065,21067,21070,21071,21074,21075,21077,21079,21080,21081,21082,21083,21085,21087,21088,21090,21091,21092,21094,21096,21099,21100,21101,21102,21104,21105,21107,21108,21109,21110,21111,21112,21113,21114,21115,21116,21118,21120,21123,21124,21125,21126,21127,21129,21130,21131,21132,21133,21134,21135,21137,21138,21140,21141,21142,21143,21144,21145,21146,21148,21156,21157,21158,21159,21166,21167,21168,21172,21173,21174,21175,21176,21177,21178,21179,21180,21181,21184,21185,21186,21188,21189,21190,21192,21194,21196,21197,21198,21199,21201,21203,21204,21205,21207,21209,21210,21211,21212,21213,21214,21216,21217,21218,21219,21221,21222,21223,21224,21225,21226,21227,21228,21229,21230,21231,21233,21234,21235,21236,21237,21238,21239,21240,21243,21244,21245,21249,21250,21251,21252,21255,21257,21258,21259,21260,21262,21265,21266,21267,21268,21272,21275,21276,21278,21279,21282,21284,21285,21287,21288,21289,21291,21292,21293,21295,21296,21297,21298,21299,21300,21301,21302,21303,21304,21308,21309,21312,21314,21316,21318,21323,21324,21325,21328,21332,21336,21337,21339,21341,21349,21352,21354,21356,21357,21362,21366,21369,21371,21372,21373,21374,21376,21377,21379,21383,21384,21386,21390,21391,21392,21393,21394,21395,21396,21398,21399,21401,21403,21404,21406,21408,21409,21412,21415,21418,21419,21420,21421,21423,21424,21425,21426,21427,21428,21429,21431,21432,21433,21434,21436,21437,21438,21440,21443,21444,21445,21446,21447,21454,21455,21456,21458,21459,21461,21466,21468,21469,21470,21473,21474,21479,21492,21498,21502,21503,21504,21506,21509,21511,21515,21524,21528,21529,21530,21532,21538,21540,21541,21546,21552,21555,21558,21559,21562,21565,21567,21569,21570,21572,21573,21575,21577,21580,21581,21582,21583,21585,21594,21597,21598,21599,21600,21601,21603,21605,21607,21609,21610,21611,21612,21613,21614,21615,21616,21620,21625,21626,21630,21631,21633,21635,21637,21639,21640,21641,21642,21645,21649,21651,21655,21656,21660,21662,21663,21664,21665,21666,21669,21678,21680,21682,21685,21686,21687,21689,21690,21692,21694,21699,21701,21706,21707,21718,21720,21723,21728,21729,21730,21731,21732,21739,21740,21743,21744,21745,21748,21749,21750,21751,21752,21753,21755,21758,21760,21762,21763,21764,21765,21768,21770,21771,21772,21773,21774,21778,21779,21781,21782,21783,21784,21785,21786,21788,21789,21790,21791,21793,21797,21798,21800,21801,21803,21805,21810,21812,21813,21814,21816,21817,21818,21819,21821,21824,21826,21829,21831,21832,21835,21836,21837,21838,21839,21841,21842,21843,21844,21847,21848,21849,21850,21851,21853,21854,21855,21856,21858,21859,21864,21865,21867,21871,21872,21873,21874,21875,21876,21881,21882,21885,21887,21893,21894,21900,21901,21902,21904,21906,21907,21909,21910,21911,21914,21915,21918,21920,21921,21922,21923,21924,21925,21926,21928,21929,21930,21931,21932,21933,21934,21935,21936,21938,21940,21942,21944,21946,21948,21951,21952,21953,21954,21955,21958,21959,21960,21962,21963,21966,21967,21968,21973,21975,21976,21977,21978,21979,21982,21984,21986,21991,21993,21997,21998,22000,22001,22004,22006,22008,22009,22010,22011,22012,22015,22018,22019,22020,22021,22022,22023,22026,22027,22029,22032,22033,22034,22035,22036,22037,22038,22039,22041,22042,22044,22045,22048,22049,22050,22053,22054,22056,22057,22058,22059,22062,22063,22064,22067,22069,22071,22072,22074,22076,22077,22078,22080,22081,22082,22083,22084,22085,22086,22087,22088,22089,22090,22091,22095,22096,22097,22098,22099,22101,22102,22106,22107,22109,22110,22111,22112,22113,22115,22117,22118,22119,22125,22126,22127,22128,22130,22131,22132,22133,22135,22136,22137,22138,22141,22142,22143,22144,22145,22146,22147,22148,22151,22152,22153,22154,22155,22156,22157,22160,22161,22162,22164,22165,22166,22167,22168,22169,22170,22171,22172,22173,22174,22175,22176,22177,22178,22180,22181,22182,22183,22184,22185,22186,22187,22188,22189,22190,22192,22193,22194,22195,22196,22197,22198,22200,22201,22202,22203,22205,22206,22207,22208,22209,22210,22211,22212,22213,22214,22215,22216,22217,22219,22220,22221,22222,22223,22224,22225,22226,22227,22229,22230,22232,22233,22236,22243,22245,22246,22247,22248,22249,22250,22252,22254,22255,22258,22259,22262,22263,22264,22267,22268,22272,22273,22274,22277,22279,22283,22284,22285,22286,22287,22288,22289,22290,22291,22292,22293,22294,22295,22296,22297,22298,22299,22301,22302,22304,22305,22306,22308,22309,22310,22311,22315,22321,22322,22324,22325,22326,22327,22328,22332,22333,22335,22337,22339,22340,22341,22342,22344,22345,22347,22354,22355,22356,22357,22358,22360,22361,22370,22371,22373,22375,22380,22382,22384,22385,22386,22388,22389,22392,22393,22394,22397,22398,22399,22400,22401,22407,22408,22409,22410,22413,22414,22415,22416,22417,22420,22421,22422,22423,22424,22425,22426,22428,22429,22430,22431,22437,22440,22442,22444,22447,22448,22449,22451,22453,22454,22455,22457,22458,22459,22460,22461,22462,22463,22464,22465,22468,22469,22470,22471,22472,22473,22474,22476,22477,22480,22481,22483,22486,22487,22491,22492,22494,22497,22498,22499,22501,22502,22503,22504,22505,22506,22507,22508,22510,22512,22513,22514,22515,22517,22518,22519,22523,22524,22526,22527,22529,22531,22532,22533,22536,22537,22538,22540,22542,22543,22544,22546,22547,22548,22550,22551,22552,22554,22555,22556,22557,22559,22562,22563,22565,22566,22567,22568,22569,22571,22572,22573,22574,22575,22577,22578,22579,22580,22582,22583,22584,22585,22586,22587,22588,22589,22590,22591,22592,22593,22594,22595,22597,22598,22599,22600,22601,22602,22603,22606,22607,22608,22610,22611,22613,22614,22615,22617,22618,22619,22620,22621,22623,22624,22625,22626,22627,22628,22630,22631,22632,22633,22634,22637,22638,22639,22640,22641,22642,22643,22644,22645,22646,22647,22648,22649,22650,22651,22652,22653,22655,22658,22660,22662,22663,22664,22666,22667,22668,22669,22670,22671,22672,22673,22676,22677,22678,22679,22680,22683,22684,22685,22688,22689,22690,22691,22692,22693,22694,22695,22698,22699,22700,22701,22702,22703,22704,22705,22706,22707,22708,22709,22710,22711,22712,22713,22714,22715,22717,22718,22719,22720,22722,22723,22724,22726,22727,22728,22729,22730,22731,22732,22733,22734,22735,22736,22738,22739,22740,22742,22743,22744,22745,22746,22747,22748,22749,22750,22751,22752,22753,22754,22755,22757,22758,22759,22760,22761,22762,22765,22767,22769,22770,22772,22773,22775,22776,22778,22779,22780,22781,22782,22783,22784,22785,22787,22789,22790,22792,22793,22794,22795,22796,22798,22800,22801,22802,22803,22807,22808,22811,22813,22814,22816,22817,22818,22819,22822,22824,22828,22832,22834,22835,22837,22838,22843,22845,22846,22847,22848,22851,22853,22854,22858,22860,22861,22864,22866,22867,22873,22875,22876,22877,22878,22879,22881,22883,22884,22886,22887,22888,22889,22890,22891,22892,22893,22894,22895,22896,22897,22898,22901,22903,22906,22907,22908,22910,22911,22912,22917,22921,22923,22924,22926,22927,22928,22929,22932,22933,22936,22938,22939,22940,22941,22943,22944,22945,22946,22950,22951,22956,22957,22960,22961,22963,22964,22965,22966,22967,22968,22970,22972,22973,22975,22976,22977,22978,22979,22980,22981,22983,22984,22985,22988,22989,22990,22991,22997,22998,23001,23003,23006,23007,23008,23009,23010,23012,23014,23015,23017,23018,23019,23021,23022,23023,23024,23025,23026,23027,23028,23029,23030,23031,23032,23034,23036,23037,23038,23040,23042,23050,23051,23053,23054,23055,23056,23058,23060,23061,23062,23063,23065,23066,23067,23069,23070,23073,23074,23076,23078,23079,23080,23082,23083,23084,23085,23086,23087,23088,23091,23093,23095,23096,23097,23098,23099,23101,23102,23103,23105,23106,23107,23108,23109,23111,23112,23115,23116,23117,23118,23119,23120,23121,23122,23123,23124,23126,23127,23128,23129,23131,23132,23133,23134,23135,23136,23137,23139,23140,23141,23142,23144,23145,23147,23148,23149,23150,23151,23152,23153,23154,23155,23160,23161,23163,23164,23165,23166,23168,23169,23170,23171,23172,23173,23174,23175,23176,23177,23178,23179,23180,23181,23182,23183,23184,23185,23187,23188,23189,23190,23191,23192,23193,23196,23197,23198,23199,23200,23201,23202,23203,23204,23205,23206,23207,23208,23209,23211,23212,23213,23214,23215,23216,23217,23220,23222,23223,23225,23226,23227,23228,23229,23231,23232,23235,23236,23237,23238,23239,23240,23242,23243,23245,23246,23247,23248,23249,23251,23253,23255,23257,23258,23259,23261,23262,23263,23266,23268,23269,23271,23272,23274,23276,23277,23278,23279,23280,23282,23283,23284,23285,23286,23287,23288,23289,23290,23291,23292,23293,23294,23295,23296,23297,23298,23299,23300,23301,23302,23303,23304,23306,23307,23308,23309,23310,23311,23312,23313,23314,23315,23316,23317,23320,23321,23322,23323,23324,23325,23326,23327,23328,23329,23330,23331,23332,23333,23334,23335,23336,23337,23338,23339,23340,23341,23342,23343,23344,23345,23347,23349,23350,23352,23353,23354,23355,23356,23357,23358,23359,23361,23362,23363,23364,23365,23366,23367,23368,23369,23370,23371,23372,23373,23374,23375,23378,23382,23390,23392,23393,23399,23400,23403,23405,23406,23407,23410,23412,23414,23415,23416,23417,23419,23420,23422,23423,23426,23430,23434,23437,23438,23440,23441,23442,23444,23446,23455,23463,23464,23465,23468,23469,23470,23471,23473,23474,23479,23482,23483,23484,23488,23489,23491,23496,23497,23498,23499,23501,23502,23503,23505,23508,23509,23510,23511,23512,23513,23514,23515,23516,23520,23522,23523,23526,23527,23529,23530,23531,23532,23533,23535,23537,23538,23539,23540,23541,23542,23543,23549,23550,23552,23554,23555,23557,23559,23560,23563,23564,23565,23566,23568,23570,23571,23575,23577,23579,23582,23583,23584,23585,23587,23590,23592,23593,23594,23595,23597,23598,23599,23600,23602,23603,23605,23606,23607,23619,23620,23622,23623,23628,23629,23634,23635,23636,23638,23639,23640,23642,23643,23644,23645,23647,23650,23652,23655,23656,23657,23658,23659,23660,23661,23664,23666,23667,23668,23669,23670,23671,23672,23675,23676,23677,23678,23680,23683,23684,23685,23686,23687,23689,23690,23691,23694,23695,23698,23699,23701,23709,23710,23711,23712,23713,23716,23717,23718,23719,23720,23722,23726,23727,23728,23730,23732,23734,23737,23738,23739,23740,23742,23744,23746,23747,23749,23750,23751,23752,23753,23754,23756,23757,23758,23759,23760,23761,23763,23764,23765,23766,23767,23768,23770,23771,23772,23773,23774,23775,23776,23778,23779,23783,23785,23787,23788,23790,23791,23793,23794,23795,23796,23797,23798,23799,23800,23801,23802,23804,23805,23806,23807,23808,23809,23812,23813,23816,23817,23818,23819,23820,23821,23823,23824,23825,23826,23827,23829,23831,23832,23833,23834,23836,23837,23839,23840,23841,23842,23843,23845,23848,23850,23851,23852,23855,23856,23857,23858,23859,23861,23862,23863,23864,23865,23866,23867,23868,23871,23872,23873,23874,23875,23876,23877,23878,23880,23881,23885,23886,23887,23888,23889,23890,23891,23892,23893,23894,23895,23897,23898,23900,23902,23903,23904,23905,23906,23907,23908,23909,23910,23911,23912,23914,23917,23918,23920,23921,23922,23923,23925,23926,23927,23928,23929,23930,23931,23932,23933,23934,23935,23936,23937,23939,23940,23941,23942,23943,23944,23945,23946,23947,23948,23949,23950,23951,23952,23953,23954,23955,23956,23957,23958,23959,23960,23962,23963,23964,23966,23967,23968,23969,23970,23971,23972,23973,23974,23975,23976,23977,23978,23979,23980,23981,23982,23983,23984,23985,23986,23987,23988,23989,23990,23992,23993,23994,23995,23996,23997,23998,23999,24000,24001,24002,24003,24004,24006,24007,24008,24009,24010,24011,24012,24014,24015,24016,24017,24018,24019,24020,24021,24022,24023,24024,24025,24026,24028,24031,24032,24035,24036,24042,24044,24045,24048,24053,24054,24056,24057,24058,24059,24060,24063,24064,24068,24071,24073,24074,24075,24077,24078,24082,24083,24087,24094,24095,24096,24097,24098,24099,24100,24101,24104,24105,24106,24107,24108,24111,24112,24114,24115,24116,24117,24118,24121,24122,24126,24127,24128,24129,24131,24134,24135,24136,24137,24138,24139,24141,24142,24143,24144,24145,24146,24147,24150,24151,24152,24153,24154,24156,24157,24159,24160,24163,24164,24165,24166,24167,24168,24169,24170,24171,24172,24173,24174,24175,24176,24177,24181,24183,24185,24190,24193,24194,24195,24197,24200,24201,24204,24205,24206,24210,24216,24219,24221,24225,24226,24227,24228,24232,24233,24234,24235,24236,24238,24239,24240,24241,24242,24244,24250,24251,24252,24253,24255,24256,24257,24258,24259,24260,24261,24262,24263,24264,24267,24268,24269,24270,24271,24272,24276,24277,24279,24280,24281,24282,24284,24285,24286,24287,24288,24289,24290,24291,24292,24293,24294,24295,24297,24299,24300,24301,24302,24303,24304,24305,24306,24307,24309,24312,24313,24315,24316,24317,24325,24326,24327,24329,24332,24333,24334,24336,24338,24340,24342,24345,24346,24348,24349,24350,24353,24354,24355,24356,24360,24363,24364,24366,24368,24370,24371,24372,24373,24374,24375,24376,24379,24381,24382,24383,24385,24386,24387,24388,24389,24390,24391,24392,24393,24394,24395,24396,24397,24398,24399,24401,24404,24409,24410,24411,24412,24414,24415,24416,24419,24421,24423,24424,24427,24430,24431,24434,24436,24437,24438,24440,24442,24445,24446,24447,24451,24454,24461,24462,24463,24465,24467,24468,24470,24474,24475,24477,24478,24479,24480,24482,24483,24484,24485,24486,24487,24489,24491,24492,24495,24496,24497,24498,24499,24500,24502,24504,24505,24506,24507,24510,24511,24512,24513,24514,24519,24520,24522,24523,24526,24531,24532,24533,24538,24539,24540,24542,24543,24546,24547,24549,24550,24552,24553,24556,24559,24560,24562,24563,24564,24566,24567,24569,24570,24572,24583,24584,24585,24587,24588,24592,24593,24595,24599,24600,24602,24606,24607,24610,24611,24612,24620,24621,24622,24624,24625,24626,24627,24628,24630,24631,24632,24633,24634,24637,24638,24640,24644,24645,24646,24647,24648,24649,24650,24652,24654,24655,24657,24659,24660,24662,24663,24664,24667,24668,24670,24671,24672,24673,24677,24678,24686,24689,24690,24692,24693,24695,24702,24704,24705,24706,24709,24710,24711,24712,24714,24715,24718,24719,24720,24721,24723,24725,24727,24728,24729,24732,24734,24737,24738,24740,24741,24743,24745,24746,24750,24752,24755,24757,24758,24759,24761,24762,24765,24766,24767,24768,24769,24770,24771,24772,24775,24776,24777,24780,24781,24782,24783,24784,24786,24787,24788,24790,24791,24793,24795,24798,24801,24802,24803,24804,24805,24810,24817,24818,24821,24823,24824,24827,24828,24829,24830,24831,24834,24835,24836,24837,24839,24842,24843,24844,24848,24849,24850,24851,24852,24854,24855,24856,24857,24859,24860,24861,24862,24865,24866,24869,24872,24873,24874,24876,24877,24878,24879,24880,24881,24882,24883,24884,24885,24886,24887,24888,24889,24890,24891,24892,24893,24894,24896,24897,24898,24899,24900,24901,24902,24903,24905,24907,24909,24911,24912,24914,24915,24916,24918,24919,24920,24921,24922,24923,24924,24926,24927,24928,24929,24931,24932,24933,24934,24937,24938,24939,24940,24941,24942,24943,24945,24946,24947,24948,24950,24952,24953,24954,24955,24956,24957,24958,24959,24960,24961,24962,24963,24964,24965,24966,24967,24968,24969,24970,24972,24973,24975,24976,24977,24978,24979,24981,24982,24983,24984,24985,24986,24987,24988,24990,24991,24992,24993,24994,24995,24996,24997,24998,25002,25003,25005,25006,25007,25008,25009,25010,25011,25012,25013,25014,25016,25017,25018,25019,25020,25021,25023,25024,25025,25027,25028,25029,25030,25031,25033,25036,25037,25038,25039,25040,25043,25045,25046,25047,25048,25049,25050,25051,25052,25053,25054,25055,25056,25057,25058,25059,25060,25061,25063,25064,25065,25066,25067,25068,25069,25070,25071,25072,25073,25074,25075,25076,25078,25079,25080,25081,25082,25083,25084,25085,25086,25088,25089,25090,25091,25092,25093,25095,25097,25107,25108,25113,25116,25117,25118,25120,25123,25126,25127,25128,25129,25131,25133,25135,25136,25137,25138,25141,25142,25144,25145,25146,25147,25148,25154,25156,25157,25158,25162,25167,25168,25173,25174,25175,25177,25178,25180,25181,25182,25183,25184,25185,25186,25188,25189,25192,25201,25202,25204,25205,25207,25208,25210,25211,25213,25217,25218,25219,25221,25222,25223,25224,25227,25228,25229,25230,25231,25232,25236,25241,25244,25245,25246,25251,25254,25255,25257,25258,25261,25262,25263,25264,25266,25267,25268,25270,25271,25272,25274,25278,25280,25281,25283,25291,25295,25297,25301,25309,25310,25312,25313,25316,25322,25323,25328,25330,25333,25336,25337,25338,25339,25344,25347,25348,25349,25350,25354,25355,25356,25357,25359,25360,25362,25363,25364,25365,25367,25368,25369,25372,25382,25383,25385,25388,25389,25390,25392,25393,25395,25396,25397,25398,25399,25400,25403,25404,25406,25407,25408,25409,25412,25415,25416,25418,25425,25426,25427,25428,25430,25431,25432,25433,25434,25435,25436,25437,25440,25444,25445,25446,25448,25450,25451,25452,25455,25456,25458,25459,25460,25461,25464,25465,25468,25469,25470,25471,25473,25475,25476,25477,25478,25483,25485,25489,25491,25492,25493,25495,25497,25498,25499,25500,25501,25502,25503,25505,25508,25510,25515,25519,25521,25522,25525,25526,25529,25531,25533,25535,25536,25537,25538,25539,25541,25543,25544,25546,25547,25548,25553,25555,25556,25557,25559,25560,25561,25562,25563,25564,25565,25567,25570,25572,25573,25574,25575,25576,25579,25580,25582,25583,25584,25585,25587,25589,25591,25593,25594,25595,25596,25598,25603,25604,25606,25607,25608,25609,25610,25613,25614,25617,25618,25621,25622,25623,25624,25625,25626,25629,25631,25634,25635,25636,25637,25639,25640,25641,25643,25646,25647,25648,25649,25650,25651,25653,25654,25655,25656,25657,25659,25660,25662,25664,25666,25667,25673,25675,25676,25677,25678,25679,25680,25681,25683,25685,25686,25687,25689,25690,25691,25692,25693,25695,25696,25697,25698,25699,25700,25701,25702,25704,25706,25707,25708,25710,25711,25712,25713,25714,25715,25716,25717,25718,25719,25723,25724,25725,25726,25727,25728,25729,25731,25734,25736,25737,25738,25739,25740,25741,25742,25743,25744,25747,25748,25751,25752,25754,25755,25756,25757,25759,25760,25761,25762,25763,25765,25766,25767,25768,25770,25771,25775,25777,25778,25779,25780,25782,25785,25787,25789,25790,25791,25793,25795,25796,25798,25799,25800,25801,25802,25803,25804,25807,25809,25811,25812,25813,25814,25817,25818,25819,25820,25821,25823,25824,25825,25827,25829,25831,25832,25833,25834,25835,25836,25837,25838,25839,25840,25841,25842,25843,25844,25845,25846,25847,25848,25849,25850,25851,25852,25853,25854,25855,25857,25858,25859,25860,25861,25862,25863,25864,25866,25867,25868,25869,25870,25871,25872,25873,25875,25876,25877,25878,25879,25881,25882,25883,25884,25885,25886,25887,25888,25889,25890,25891,25892,25894,25895,25896,25897,25898,25900,25901,25904,25905,25906,25907,25911,25914,25916,25917,25920,25921,25922,25923,25924,25926,25927,25930,25931,25933,25934,25936,25938,25939,25940,25943,25944,25946,25948,25951,25952,25953,25956,25957,25959,25960,25961,25962,25965,25966,25967,25969,25971,25973,25974,25976,25977,25978,25979,25980,25981,25982,25983,25984,25985,25986,25987,25988,25989,25990,25992,25993,25994,25997,25998,25999,26002,26004,26005,26006,26008,26010,26013,26014,26016,26018,26019,26022,26024,26026,26028,26030,26033,26034,26035,26036,26037,26038,26039,26040,26042,26043,26046,26047,26048,26050,26055,26056,26057,26058,26061,26064,26065,26067,26068,26069,26072,26073,26074,26075,26076,26077,26078,26079,26081,26083,26084,26090,26091,26098,26099,26100,26101,26104,26105,26107,26108,26109,26110,26111,26113,26116,26117,26119,26120,26121,26123,26125,26128,26129,26130,26134,26135,26136,26138,26139,26140,26142,26145,26146,26147,26148,26150,26153,26154,26155,26156,26158,26160,26162,26163,26167,26168,26169,26170,26171,26173,26175,26176,26178,26180,26181,26182,26183,26184,26185,26186,26189,26190,26192,26193,26200,26201,26203,26204,26205,26206,26208,26210,26211,26213,26215,26217,26218,26219,26220,26221,26225,26226,26227,26229,26232,26233,26235,26236,26237,26239,26240,26241,26243,26245,26246,26248,26249,26250,26251,26253,26254,26255,26256,26258,26259,26260,26261,26264,26265,26266,26267,26268,26270,26271,26272,26273,26274,26275,26276,26277,26278,26281,26282,26283,26284,26285,26287,26288,26289,26290,26291,26293,26294,26295,26296,26298,26299,26300,26301,26303,26304,26305,26306,26307,26308,26309,26310,26311,26312,26313,26314,26315,26316,26317,26318,26319,26320,26321,26322,26323,26324,26325,26326,26327,26328,26330,26334,26335,26336,26337,26338,26339,26340,26341,26343,26344,26346,26347,26348,26349,26350,26351,26353,26357,26358,26360,26362,26363,26365,26369,26370,26371,26372,26373,26374,26375,26380,26382,26383,26385,26386,26387,26390,26392,26393,26394,26396,26398,26400,26401,26402,26403,26404,26405,26407,26409,26414,26416,26418,26419,26422,26423,26424,26425,26427,26428,26430,26431,26433,26436,26437,26439,26442,26443,26445,26450,26452,26453,26455,26456,26457,26458,26459,26461,26466,26467,26468,26470,26471,26475,26476,26478,26481,26484,26486,26488,26489,26490,26491,26493,26496,26498,26499,26501,26502,26504,26506,26508,26509,26510,26511,26513,26514,26515,26516,26518,26521,26523,26527,26528,26529,26532,26534,26537,26540,26542,26545,26546,26548,26553,26554,26555,26556,26557,26558,26559,26560,26562,26565,26566,26567,26568,26569,26570,26571,26572,26573,26574,26581,26582,26583,26587,26591,26593,26595,26596,26598,26599,26600,26602,26603,26605,26606,26610,26613,26614,26615,26616,26617,26618,26619,26620,26622,26625,26626,26627,26628,26630,26637,26640,26642,26644,26645,26648,26649,26650,26651,26652,26654,26655,26656,26658,26659,26660,26661,26662,26663,26664,26667,26668,26669,26670,26671,26672,26673,26676,26677,26678,26682,26683,26687,26695,26699,26701,26703,26706,26710,26711,26712,26713,26714,26715,26716,26717,26718,26719,26730,26732,26733,26734,26735,26736,26737,26738,26739,26741,26744,26745,26746,26747,26748,26749,26750,26751,26752,26754,26756,26759,26760,26761,26762,26763,26764,26765,26766,26768,26769,26770,26772,26773,26774,26776,26777,26778,26779,26780,26781,26782,26783,26784,26785,26787,26788,26789,26793,26794,26795,26796,26798,26801,26802,26804,26806,26807,26808,26809,26810,26811,26812,26813,26814,26815,26817,26819,26820,26821,26822,26823,26824,26826,26828,26830,26831,26832,26833,26835,26836,26838,26839,26841,26843,26844,26845,26846,26847,26849,26850,26852,26853,26854,26855,26856,26857,26858,26859,26860,26861,26863,26866,26867,26868,26870,26871,26872,26875,26877,26878,26879,26880,26882,26883,26884,26886,26887,26888,26889,26890,26892,26895,26897,26899,26900,26901,26902,26903,26904,26905,26906,26907,26908,26909,26910,26913,26914,26915,26917,26918,26919,26920,26921,26922,26923,26924,26926,26927,26929,26930,26931,26933,26934,26935,26936,26938,26939,26940,26942,26944,26945,26947,26948,26949,26950,26951,26952,26953,26954,26955,26956,26957,26958,26959,26960,26961,26962,26963,26965,26966,26968,26969,26971,26972,26975,26977,26978,26980,26981,26983,26984,26985,26986,26988,26989,26991,26992,26994,26995,26996,26997,26998,27002,27003,27005,27006,27007,27009,27011,27013,27018,27019,27020,27022,27023,27024,27025,27026,27027,27030,27031,27033,27034,27037,27038,27039,27040,27041,27042,27043,27044,27045,27046,27049,27050,27052,27054,27055,27056,27058,27059,27061,27062,27064,27065,27066,27068,27069,27070,27071,27072,27074,27075,27076,27077,27078,27079,27080,27081,27083,27085,27087,27089,27090,27091,27093,27094,27095,27096,27097,27098,27100,27101,27102,27105,27106,27107,27108,27109,27110,27111,27112,27113,27114,27115,27116,27118,27119,27120,27121,27123,27124,27125,27126,27127,27128,27129,27130,27131,27132,27134,27136,27137,27138,27139,27140,27141,27142,27143,27144,27145,27147,27148,27149,27150,27151,27152,27153,27154,27155,27156,27157,27158,27161,27162,27163,27164,27165,27166,27168,27170,27171,27172,27173,27174,27175,27177,27179,27180,27181,27182,27184,27186,27187,27188,27190,27191,27192,27193,27194,27195,27196,27199,27200,27201,27202,27203,27205,27206,27208,27209,27210,27211,27212,27213,27214,27215,27217,27218,27219,27220,27221,27222,27223,27226,27228,27229,27230,27231,27232,27234,27235,27236,27238,27239,27240,27241,27242,27243,27244,27245,27246,27247,27248,27250,27251,27252,27253,27254,27255,27256,27258,27259,27261,27262,27263,27265,27266,27267,27269,27270,27271,27272,27273,27274,27275,27276,27277,27279,27282,27283,27284,27285,27286,27288,27289,27290,27291,27292,27293,27294,27295,27297,27298,27299,27300,27301,27302,27303,27304,27306,27309,27310,27311,27312,27313,27314,27315,27316,27317,27318,27319,27320,27321,27322,27323,27324,27325,27326,27327,27328,27329,27330,27331,27332,27333,27334,27335,27336,27337,27338,27339,27340,27341,27342,27343,27344,27345,27346,27347,27348,27349,27350,27351,27352,27353,27354,27355,27356,27357,27358,27359,27360,27361,27362,27363,27364,27365,27366,27367,27368,27369,27370,27371,27372,27373,27374,27375,27376,27377,27378,27379,27380,27381,27382,27383,27384,27385,27386,27387,27388,27389,27390,27391,27392,27393,27394,27395,27396,27397,27398,27399,27400,27401,27402,27403,27404,27405,27406,27407,27408,27409,27410,27411,27412,27413,27414,27415,27416,27417,27418,27419,27420,27421,27422,27423,27429,27430,27432,27433,27434,27435,27436,27437,27438,27439,27440,27441,27443,27444,27445,27446,27448,27451,27452,27453,27455,27456,27457,27458,27460,27461,27464,27466,27467,27469,27470,27471,27472,27473,27474,27475,27476,27477,27478,27479,27480,27482,27483,27484,27485,27486,27487,27488,27489,27496,27497,27499,27500,27501,27502,27503,27504,27505,27506,27507,27508,27509,27510,27511,27512,27514,27517,27518,27519,27520,27525,27528,27532,27534,27535,27536,27537,27540,27541,27543,27544,27545,27548,27549,27550,27551,27552,27554,27555,27556,27557,27558,27559,27560,27561,27563,27564,27565,27566,27567,27568,27569,27570,27574,27576,27577,27578,27579,27580,27581,27582,27584,27587,27588,27590,27591,27592,27593,27594,27596,27598,27600,27601,27608,27610,27612,27613,27614,27615,27616,27618,27619,27620,27621,27622,27623,27624,27625,27628,27629,27630,27632,27633,27634,27636,27638,27639,27640,27642,27643,27644,27646,27647,27648,27649,27650,27651,27652,27656,27657,27658,27659,27660,27662,27666,27671,27676,27677,27678,27680,27683,27685,27691,27692,27693,27697,27699,27702,27703,27705,27706,27707,27708,27710,27711,27715,27716,27717,27720,27723,27724,27725,27726,27727,27729,27730,27731,27734,27736,27737,27738,27746,27747,27749,27750,27751,27755,27756,27757,27758,27759,27761,27763,27765,27767,27768,27770,27771,27772,27775,27776,27780,27783,27786,27787,27789,27790,27793,27794,27797,27798,27799,27800,27802,27804,27805,27806,27808,27810,27816,27820,27823,27824,27828,27829,27830,27831,27834,27840,27841,27842,27843,27846,27847,27848,27851,27853,27854,27855,27857,27858,27864,27865,27866,27868,27869,27871,27876,27878,27879,27881,27884,27885,27890,27892,27897,27903,27904,27906,27907,27909,27910,27912,27913,27914,27917,27919,27920,27921,27923,27924,27925,27926,27928,27932,27933,27935,27936,27937,27938,27939,27940,27942,27944,27945,27948,27949,27951,27952,27956,27958,27959,27960,27962,27967,27968,27970,27972,27977,27980,27984,27989,27990,27991,27992,27995,27997,27999,28001,28002,28004,28005,28007,28008,28011,28012,28013,28016,28017,28018,28019,28021,28022,28025,28026,28027,28029,28030,28031,28032,28033,28035,28036,28038,28039,28042,28043,28045,28047,28048,28050,28054,28055,28056,28057,28058,28060,28066,28069,28076,28077,28080,28081,28083,28084,28086,28087,28089,28090,28091,28092,28093,28094,28097,28098,28099,28104,28105,28106,28109,28110,28111,28112,28114,28115,28116,28117,28119,28122,28123,28124,28127,28130,28131,28133,28135,28136,28137,28138,28141,28143,28144,28146,28148,28149,28150,28152,28154,28157,28158,28159,28160,28161,28162,28163,28164,28166,28167,28168,28169,28171,28175,28178,28179,28181,28184,28185,28187,28188,28190,28191,28194,28198,28199,28200,28202,28204,28206,28208,28209,28211,28213,28214,28215,28217,28219,28220,28221,28222,28223,28224,28225,28226,28229,28230,28231,28232,28233,28234,28235,28236,28239,28240,28241,28242,28245,28247,28249,28250,28252,28253,28254,28256,28257,28258,28259,28260,28261,28262,28263,28264,28265,28266,28268,28269,28271,28272,28273,28274,28275,28276,28277,28278,28279,28280,28281,28282,28283,28284,28285,28288,28289,28290,28292,28295,28296,28298,28299,28300,28301,28302,28305,28306,28307,28308,28309,28310,28311,28313,28314,28315,28317,28318,28320,28321,28323,28324,28326,28328,28329,28331,28332,28333,28334,28336,28339,28341,28344,28345,28348,28350,28351,28352,28355,28356,28357,28358,28360,28361,28362,28364,28365,28366,28368,28370,28374,28376,28377,28379,28380,28381,28387,28391,28394,28395,28396,28397,28398,28399,28400,28401,28402,28403,28405,28406,28407,28408,28410,28411,28412,28413,28414,28415,28416,28417,28419,28420,28421,28423,28424,28426,28427,28428,28429,28430,28432,28433,28434,28438,28439,28440,28441,28442,28443,28444,28445,28446,28447,28449,28450,28451,28453,28454,28455,28456,28460,28462,28464,28466,28468,28469,28471,28472,28473,28474,28475,28476,28477,28479,28480,28481,28482,28483,28484,28485,28488,28489,28490,28492,28494,28495,28496,28497,28498,28499,28500,28501,28502,28503,28505,28506,28507,28509,28511,28512,28513,28515,28516,28517,28519,28520,28521,28522,28523,28524,28527,28528,28529,28531,28533,28534,28535,28537,28539,28541,28542,28543,28544,28545,28546,28547,28549,28550,28551,28554,28555,28559,28560,28561,28562,28563,28564,28565,28566,28567,28568,28569,28570,28571,28573,28574,28575,28576,28578,28579,28580,28581,28582,28584,28585,28586,28587,28588,28589,28590,28591,28592,28593,28594,28596,28597,28599,28600,28602,28603,28604,28605,28606,28607,28609,28611,28612,28613,28614,28615,28616,28618,28619,28620,28621,28622,28623,28624,28627,28628,28629,28630,28631,28632,28633,28634,28635,28636,28637,28639,28642,28643,28644,28645,28646,28647,28648,28649,28650,28651,28652,28653,28656,28657,28658,28659,28660,28661,28662,28663,28664,28665,28666,28667,28668,28669,28670,28671,28672,28673,28674,28675,28676,28677,28678,28679,28680,28681,28682,28683,28684,28685,28686,28687,28688,28690,28691,28692,28693,28694,28695,28696,28697,28700,28701,28702,28703,28704,28705,28706,28708,28709,28710,28711,28712,28713,28714,28715,28716,28717,28718,28719,28720,28721,28722,28723,28724,28726,28727,28728,28730,28731,28732,28733,28734,28735,28736,28737,28738,28739,28740,28741,28742,28743,28744,28745,28746,28747,28749,28750,28752,28753,28754,28755,28756,28757,28758,28759,28760,28761,28762,28763,28764,28765,28767,28768,28769,28770,28771,28772,28773,28774,28775,28776,28777,28778,28782,28785,28786,28787,28788,28791,28793,28794,28795,28797,28801,28802,28803,28804,28806,28807,28808,28811,28812,28813,28815,28816,28817,28819,28823,28824,28826,28827,28830,28831,28832,28833,28834,28835,28836,28837,28838,28839,28840,28841,28842,28848,28850,28852,28853,28854,28858,28862,28863,28868,28869,28870,28871,28873,28875,28876,28877,28878,28879,28880,28881,28882,28883,28884,28885,28886,28887,28890,28892,28893,28894,28896,28897,28898,28899,28901,28906,28910,28912,28913,28914,28915,28916,28917,28918,28920,28922,28923,28924,28926,28927,28928,28929,28930,28931,28932,28933,28934,28935,28936,28939,28940,28941,28942,28943,28945,28946,28948,28951,28955,28956,28957,28958,28959,28960,28961,28962,28963,28964,28965,28967,28968,28969,28970,28971,28972,28973,28974,28978,28979,28980,28981,28983,28984,28985,28986,28987,28988,28989,28990,28991,28992,28993,28994,28995,28996,28998,28999,29000,29001,29003,29005,29007,29008,29009,29010,29011,29012,29013,29014,29015,29016,29017,29018,29019,29021,29023,29024,29025,29026,29027,29029,29033,29034,29035,29036,29037,29039,29040,29041,29044,29045,29046,29047,29049,29051,29052,29054,29055,29056,29057,29058,29059,29061,29062,29063,29064,29065,29067,29068,29069,29070,29072,29073,29074,29075,29077,29078,29079,29082,29083,29084,29085,29086,29089,29090,29091,29092,29093,29094,29095,29097,29098,29099,29101,29102,29103,29104,29105,29106,29108,29110,29111,29112,29114,29115,29116,29117,29118,29119,29120,29121,29122,29124,29125,29126,29127,29128,29129,29130,29131,29132,29133,29135,29136,29137,29138,29139,29142,29143,29144,29145,29146,29147,29148,29149,29150,29151,29153,29154,29155,29156,29158,29160,29161,29162,29163,29164,29165,29167,29168,29169,29170,29171,29172,29173,29174,29175,29176,29178,29179,29180,29181,29182,29183,29184,29185,29186,29187,29188,29189,29191,29192,29193,29194,29195,29196,29197,29198,29199,29200,29201,29202,29203,29204,29205,29206,29207,29208,29209,29210,29211,29212,29214,29215,29216,29217,29218,29219,29220,29221,29222,29223,29225,29227,29229,29230,29231,29234,29235,29236,29242,29244,29246,29248,29249,29250,29251,29252,29253,29254,29257,29258,29259,29262,29263,29264,29265,29267,29268,29269,29271,29272,29274,29276,29278,29280,29283,29284,29285,29288,29290,29291,29292,29293,29296,29297,29299,29300,29302,29303,29304,29307,29308,29309,29314,29315,29317,29318,29319,29320,29321,29324,29326,29328,29329,29331,29332,29333,29334,29335,29336,29337,29338,29339,29340,29341,29342,29344,29345,29346,29347,29348,29349,29350,29351,29352,29353,29354,29355,29358,29361,29362,29363,29365,29370,29371,29372,29373,29374,29375,29376,29381,29382,29383,29385,29386,29387,29388,29391,29393,29395,29396,29397,29398,29400,29402,29403,58566,58567,58568,58569,58570,58571,58572,58573,58574,58575,58576,58577,58578,58579,58580,58581,58582,58583,58584,58585,58586,58587,58588,58589,58590,58591,58592,58593,58594,58595,58596,58597,58598,58599,58600,58601,58602,58603,58604,58605,58606,58607,58608,58609,58610,58611,58612,58613,58614,58615,58616,58617,58618,58619,58620,58621,58622,58623,58624,58625,58626,58627,58628,58629,58630,58631,58632,58633,58634,58635,58636,58637,58638,58639,58640,58641,58642,58643,58644,58645,58646,58647,58648,58649,58650,58651,58652,58653,58654,58655,58656,58657,58658,58659,58660,58661,12288,12289,12290,183,713,711,168,12291,12293,8212,65374,8214,8230,8216,8217,8220,8221,12308,12309,12296,12297,12298,12299,12300,12301,12302,12303,12310,12311,12304,12305,177,215,247,8758,8743,8744,8721,8719,8746,8745,8712,8759,8730,8869,8741,8736,8978,8857,8747,8750,8801,8780,8776,8765,8733,8800,8814,8815,8804,8805,8734,8757,8756,9794,9792,176,8242,8243,8451,65284,164,65504,65505,8240,167,8470,9734,9733,9675,9679,9678,9671,9670,9633,9632,9651,9650,8251,8594,8592,8593,8595,12307,58662,58663,58664,58665,58666,58667,58668,58669,58670,58671,58672,58673,58674,58675,58676,58677,58678,58679,58680,58681,58682,58683,58684,58685,58686,58687,58688,58689,58690,58691,58692,58693,58694,58695,58696,58697,58698,58699,58700,58701,58702,58703,58704,58705,58706,58707,58708,58709,58710,58711,58712,58713,58714,58715,58716,58717,58718,58719,58720,58721,58722,58723,58724,58725,58726,58727,58728,58729,58730,58731,58732,58733,58734,58735,58736,58737,58738,58739,58740,58741,58742,58743,58744,58745,58746,58747,58748,58749,58750,58751,58752,58753,58754,58755,58756,58757,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,59238,59239,59240,59241,59242,59243,9352,9353,9354,9355,9356,9357,9358,9359,9360,9361,9362,9363,9364,9365,9366,9367,9368,9369,9370,9371,9332,9333,9334,9335,9336,9337,9338,9339,9340,9341,9342,9343,9344,9345,9346,9347,9348,9349,9350,9351,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,8364,59245,12832,12833,12834,12835,12836,12837,12838,12839,12840,12841,59246,59247,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,59248,59249,58758,58759,58760,58761,58762,58763,58764,58765,58766,58767,58768,58769,58770,58771,58772,58773,58774,58775,58776,58777,58778,58779,58780,58781,58782,58783,58784,58785,58786,58787,58788,58789,58790,58791,58792,58793,58794,58795,58796,58797,58798,58799,58800,58801,58802,58803,58804,58805,58806,58807,58808,58809,58810,58811,58812,58813,58814,58815,58816,58817,58818,58819,58820,58821,58822,58823,58824,58825,58826,58827,58828,58829,58830,58831,58832,58833,58834,58835,58836,58837,58838,58839,58840,58841,58842,58843,58844,58845,58846,58847,58848,58849,58850,58851,58852,12288,65281,65282,65283,65509,65285,65286,65287,65288,65289,65290,65291,65292,65293,65294,65295,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,65306,65307,65308,65309,65310,65311,65312,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,65339,65340,65341,65342,65343,65344,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,65371,65372,65373,65507,58854,58855,58856,58857,58858,58859,58860,58861,58862,58863,58864,58865,58866,58867,58868,58869,58870,58871,58872,58873,58874,58875,58876,58877,58878,58879,58880,58881,58882,58883,58884,58885,58886,58887,58888,58889,58890,58891,58892,58893,58894,58895,58896,58897,58898,58899,58900,58901,58902,58903,58904,58905,58906,58907,58908,58909,58910,58911,58912,58913,58914,58915,58916,58917,58918,58919,58920,58921,58922,58923,58924,58925,58926,58927,58928,58929,58930,58931,58932,58933,58934,58935,58936,58937,58938,58939,58940,58941,58942,58943,58944,58945,58946,58947,58948,58949,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,59250,59251,59252,59253,59254,59255,59256,59257,59258,59259,59260,58950,58951,58952,58953,58954,58955,58956,58957,58958,58959,58960,58961,58962,58963,58964,58965,58966,58967,58968,58969,58970,58971,58972,58973,58974,58975,58976,58977,58978,58979,58980,58981,58982,58983,58984,58985,58986,58987,58988,58989,58990,58991,58992,58993,58994,58995,58996,58997,58998,58999,59000,59001,59002,59003,59004,59005,59006,59007,59008,59009,59010,59011,59012,59013,59014,59015,59016,59017,59018,59019,59020,59021,59022,59023,59024,59025,59026,59027,59028,59029,59030,59031,59032,59033,59034,59035,59036,59037,59038,59039,59040,59041,59042,59043,59044,59045,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,59261,59262,59263,59264,59265,59266,59267,59268,59046,59047,59048,59049,59050,59051,59052,59053,59054,59055,59056,59057,59058,59059,59060,59061,59062,59063,59064,59065,59066,59067,59068,59069,59070,59071,59072,59073,59074,59075,59076,59077,59078,59079,59080,59081,59082,59083,59084,59085,59086,59087,59088,59089,59090,59091,59092,59093,59094,59095,59096,59097,59098,59099,59100,59101,59102,59103,59104,59105,59106,59107,59108,59109,59110,59111,59112,59113,59114,59115,59116,59117,59118,59119,59120,59121,59122,59123,59124,59125,59126,59127,59128,59129,59130,59131,59132,59133,59134,59135,59136,59137,59138,59139,59140,59141,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,59269,59270,59271,59272,59273,59274,59275,59276,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,964,965,966,967,968,969,59277,59278,59279,59280,59281,59282,59283,65077,65078,65081,65082,65087,65088,65085,65086,65089,65090,65091,65092,59284,59285,65083,65084,65079,65080,65073,59286,65075,65076,59287,59288,59289,59290,59291,59292,59293,59294,59295,59142,59143,59144,59145,59146,59147,59148,59149,59150,59151,59152,59153,59154,59155,59156,59157,59158,59159,59160,59161,59162,59163,59164,59165,59166,59167,59168,59169,59170,59171,59172,59173,59174,59175,59176,59177,59178,59179,59180,59181,59182,59183,59184,59185,59186,59187,59188,59189,59190,59191,59192,59193,59194,59195,59196,59197,59198,59199,59200,59201,59202,59203,59204,59205,59206,59207,59208,59209,59210,59211,59212,59213,59214,59215,59216,59217,59218,59219,59220,59221,59222,59223,59224,59225,59226,59227,59228,59229,59230,59231,59232,59233,59234,59235,59236,59237,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,59296,59297,59298,59299,59300,59301,59302,59303,59304,59305,59306,59307,59308,59309,59310,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,59311,59312,59313,59314,59315,59316,59317,59318,59319,59320,59321,59322,59323,714,715,729,8211,8213,8229,8245,8453,8457,8598,8599,8600,8601,8725,8735,8739,8786,8806,8807,8895,9552,9553,9554,9555,9556,9557,9558,9559,9560,9561,9562,9563,9564,9565,9566,9567,9568,9569,9570,9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,9581,9582,9583,9584,9585,9586,9587,9601,9602,9603,9604,9605,9606,9607,9608,9609,9610,9611,9612,9613,9614,9615,9619,9620,9621,9660,9661,9698,9699,9700,9701,9737,8853,12306,12317,12318,59324,59325,59326,59327,59328,59329,59330,59331,59332,59333,59334,257,225,462,224,275,233,283,232,299,237,464,236,333,243,466,242,363,250,468,249,470,472,474,476,252,234,593,7743,324,328,505,609,59337,59338,59339,59340,12549,12550,12551,12552,12553,12554,12555,12556,12557,12558,12559,12560,12561,12562,12563,12564,12565,12566,12567,12568,12569,12570,12571,12572,12573,12574,12575,12576,12577,12578,12579,12580,12581,12582,12583,12584,12585,59341,59342,59343,59344,59345,59346,59347,59348,59349,59350,59351,59352,59353,59354,59355,59356,59357,59358,59359,59360,59361,12321,12322,12323,12324,12325,12326,12327,12328,12329,12963,13198,13199,13212,13213,13214,13217,13252,13262,13265,13266,13269,65072,65506,65508,59362,8481,12849,59363,8208,59364,59365,59366,12540,12443,12444,12541,12542,12294,12445,12446,65097,65098,65099,65100,65101,65102,65103,65104,65105,65106,65108,65109,65110,65111,65113,65114,65115,65116,65117,65118,65119,65120,65121,65122,65123,65124,65125,65126,65128,65129,65130,65131,12350,12272,12273,12274,12275,12276,12277,12278,12279,12280,12281,12282,12283,12295,59380,59381,59382,59383,59384,59385,59386,59387,59388,59389,59390,59391,59392,9472,9473,9474,9475,9476,9477,9478,9479,9480,9481,9482,9483,9484,9485,9486,9487,9488,9489,9490,9491,9492,9493,9494,9495,9496,9497,9498,9499,9500,9501,9502,9503,9504,9505,9506,9507,9508,9509,9510,9511,9512,9513,9514,9515,9516,9517,9518,9519,9520,9521,9522,9523,9524,9525,9526,9527,9528,9529,9530,9531,9532,9533,9534,9535,9536,9537,9538,9539,9540,9541,9542,9543,9544,9545,9546,9547,59393,59394,59395,59396,59397,59398,59399,59400,59401,59402,59403,59404,59405,59406,59407,29404,29405,29407,29410,29411,29412,29413,29414,29415,29418,29419,29429,29430,29433,29437,29438,29439,29440,29442,29444,29445,29446,29447,29448,29449,29451,29452,29453,29455,29456,29457,29458,29460,29464,29465,29466,29471,29472,29475,29476,29478,29479,29480,29485,29487,29488,29490,29491,29493,29494,29498,29499,29500,29501,29504,29505,29506,29507,29508,29509,29510,29511,29512,29513,29514,29515,29516,29518,29519,29521,29523,29524,29525,29526,29528,29529,29530,29531,29532,29533,29534,29535,29537,29538,29539,29540,29541,29542,29543,29544,29545,29546,29547,29550,29552,29553,57344,57345,57346,57347,57348,57349,57350,57351,57352,57353,57354,57355,57356,57357,57358,57359,57360,57361,57362,57363,57364,57365,57366,57367,57368,57369,57370,57371,57372,57373,57374,57375,57376,57377,57378,57379,57380,57381,57382,57383,57384,57385,57386,57387,57388,57389,57390,57391,57392,57393,57394,57395,57396,57397,57398,57399,57400,57401,57402,57403,57404,57405,57406,57407,57408,57409,57410,57411,57412,57413,57414,57415,57416,57417,57418,57419,57420,57421,57422,57423,57424,57425,57426,57427,57428,57429,57430,57431,57432,57433,57434,57435,57436,57437,29554,29555,29556,29557,29558,29559,29560,29561,29562,29563,29564,29565,29567,29568,29569,29570,29571,29573,29574,29576,29578,29580,29581,29583,29584,29586,29587,29588,29589,29591,29592,29593,29594,29596,29597,29598,29600,29601,29603,29604,29605,29606,29607,29608,29610,29612,29613,29617,29620,29621,29622,29624,29625,29628,29629,29630,29631,29633,29635,29636,29637,29638,29639,29643,29644,29646,29650,29651,29652,29653,29654,29655,29656,29658,29659,29660,29661,29663,29665,29666,29667,29668,29670,29672,29674,29675,29676,29678,29679,29680,29681,29683,29684,29685,29686,29687,57438,57439,57440,57441,57442,57443,57444,57445,57446,57447,57448,57449,57450,57451,57452,57453,57454,57455,57456,57457,57458,57459,57460,57461,57462,57463,57464,57465,57466,57467,57468,57469,57470,57471,57472,57473,57474,57475,57476,57477,57478,57479,57480,57481,57482,57483,57484,57485,57486,57487,57488,57489,57490,57491,57492,57493,57494,57495,57496,57497,57498,57499,57500,57501,57502,57503,57504,57505,57506,57507,57508,57509,57510,57511,57512,57513,57514,57515,57516,57517,57518,57519,57520,57521,57522,57523,57524,57525,57526,57527,57528,57529,57530,57531,29688,29689,29690,29691,29692,29693,29694,29695,29696,29697,29698,29700,29703,29704,29707,29708,29709,29710,29713,29714,29715,29716,29717,29718,29719,29720,29721,29724,29725,29726,29727,29728,29729,29731,29732,29735,29737,29739,29741,29743,29745,29746,29751,29752,29753,29754,29755,29757,29758,29759,29760,29762,29763,29764,29765,29766,29767,29768,29769,29770,29771,29772,29773,29774,29775,29776,29777,29778,29779,29780,29782,29784,29789,29792,29793,29794,29795,29796,29797,29798,29799,29800,29801,29802,29803,29804,29806,29807,29809,29810,29811,29812,29813,29816,29817,29818,57532,57533,57534,57535,57536,57537,57538,57539,57540,57541,57542,57543,57544,57545,57546,57547,57548,57549,57550,57551,57552,57553,57554,57555,57556,57557,57558,57559,57560,57561,57562,57563,57564,57565,57566,57567,57568,57569,57570,57571,57572,57573,57574,57575,57576,57577,57578,57579,57580,57581,57582,57583,57584,57585,57586,57587,57588,57589,57590,57591,57592,57593,57594,57595,57596,57597,57598,57599,57600,57601,57602,57603,57604,57605,57606,57607,57608,57609,57610,57611,57612,57613,57614,57615,57616,57617,57618,57619,57620,57621,57622,57623,57624,57625,29819,29820,29821,29823,29826,29828,29829,29830,29832,29833,29834,29836,29837,29839,29841,29842,29843,29844,29845,29846,29847,29848,29849,29850,29851,29853,29855,29856,29857,29858,29859,29860,29861,29862,29866,29867,29868,29869,29870,29871,29872,29873,29874,29875,29876,29877,29878,29879,29880,29881,29883,29884,29885,29886,29887,29888,29889,29890,29891,29892,29893,29894,29895,29896,29897,29898,29899,29900,29901,29902,29903,29904,29905,29907,29908,29909,29910,29911,29912,29913,29914,29915,29917,29919,29921,29925,29927,29928,29929,29930,29931,29932,29933,29936,29937,29938,57626,57627,57628,57629,57630,57631,57632,57633,57634,57635,57636,57637,57638,57639,57640,57641,57642,57643,57644,57645,57646,57647,57648,57649,57650,57651,57652,57653,57654,57655,57656,57657,57658,57659,57660,57661,57662,57663,57664,57665,57666,57667,57668,57669,57670,57671,57672,57673,57674,57675,57676,57677,57678,57679,57680,57681,57682,57683,57684,57685,57686,57687,57688,57689,57690,57691,57692,57693,57694,57695,57696,57697,57698,57699,57700,57701,57702,57703,57704,57705,57706,57707,57708,57709,57710,57711,57712,57713,57714,57715,57716,57717,57718,57719,29939,29941,29944,29945,29946,29947,29948,29949,29950,29952,29953,29954,29955,29957,29958,29959,29960,29961,29962,29963,29964,29966,29968,29970,29972,29973,29974,29975,29979,29981,29982,29984,29985,29986,29987,29988,29990,29991,29994,29998,30004,30006,30009,30012,30013,30015,30017,30018,30019,30020,30022,30023,30025,30026,30029,30032,30033,30034,30035,30037,30038,30039,30040,30045,30046,30047,30048,30049,30050,30051,30052,30055,30056,30057,30059,30060,30061,30062,30063,30064,30065,30067,30069,30070,30071,30074,30075,30076,30077,30078,30080,30081,30082,30084,30085,30087,57720,57721,57722,57723,57724,57725,57726,57727,57728,57729,57730,57731,57732,57733,57734,57735,57736,57737,57738,57739,57740,57741,57742,57743,57744,57745,57746,57747,57748,57749,57750,57751,57752,57753,57754,57755,57756,57757,57758,57759,57760,57761,57762,57763,57764,57765,57766,57767,57768,57769,57770,57771,57772,57773,57774,57775,57776,57777,57778,57779,57780,57781,57782,57783,57784,57785,57786,57787,57788,57789,57790,57791,57792,57793,57794,57795,57796,57797,57798,57799,57800,57801,57802,57803,57804,57805,57806,57807,57808,57809,57810,57811,57812,57813,30088,30089,30090,30092,30093,30094,30096,30099,30101,30104,30107,30108,30110,30114,30118,30119,30120,30121,30122,30125,30134,30135,30138,30139,30143,30144,30145,30150,30155,30156,30158,30159,30160,30161,30163,30167,30169,30170,30172,30173,30175,30176,30177,30181,30185,30188,30189,30190,30191,30194,30195,30197,30198,30199,30200,30202,30203,30205,30206,30210,30212,30214,30215,30216,30217,30219,30221,30222,30223,30225,30226,30227,30228,30230,30234,30236,30237,30238,30241,30243,30247,30248,30252,30254,30255,30257,30258,30262,30263,30265,30266,30267,30269,30273,30274,30276,57814,57815,57816,57817,57818,57819,57820,57821,57822,57823,57824,57825,57826,57827,57828,57829,57830,57831,57832,57833,57834,57835,57836,57837,57838,57839,57840,57841,57842,57843,57844,57845,57846,57847,57848,57849,57850,57851,57852,57853,57854,57855,57856,57857,57858,57859,57860,57861,57862,57863,57864,57865,57866,57867,57868,57869,57870,57871,57872,57873,57874,57875,57876,57877,57878,57879,57880,57881,57882,57883,57884,57885,57886,57887,57888,57889,57890,57891,57892,57893,57894,57895,57896,57897,57898,57899,57900,57901,57902,57903,57904,57905,57906,57907,30277,30278,30279,30280,30281,30282,30283,30286,30287,30288,30289,30290,30291,30293,30295,30296,30297,30298,30299,30301,30303,30304,30305,30306,30308,30309,30310,30311,30312,30313,30314,30316,30317,30318,30320,30321,30322,30323,30324,30325,30326,30327,30329,30330,30332,30335,30336,30337,30339,30341,30345,30346,30348,30349,30351,30352,30354,30356,30357,30359,30360,30362,30363,30364,30365,30366,30367,30368,30369,30370,30371,30373,30374,30375,30376,30377,30378,30379,30380,30381,30383,30384,30387,30389,30390,30391,30392,30393,30394,30395,30396,30397,30398,30400,30401,30403,21834,38463,22467,25384,21710,21769,21696,30353,30284,34108,30702,33406,30861,29233,38552,38797,27688,23433,20474,25353,26263,23736,33018,26696,32942,26114,30414,20985,25942,29100,32753,34948,20658,22885,25034,28595,33453,25420,25170,21485,21543,31494,20843,30116,24052,25300,36299,38774,25226,32793,22365,38712,32610,29240,30333,26575,30334,25670,20336,36133,25308,31255,26001,29677,25644,25203,33324,39041,26495,29256,25198,25292,20276,29923,21322,21150,32458,37030,24110,26758,27036,33152,32465,26834,30917,34444,38225,20621,35876,33502,32990,21253,35090,21093,30404,30407,30409,30411,30412,30419,30421,30425,30426,30428,30429,30430,30432,30433,30434,30435,30436,30438,30439,30440,30441,30442,30443,30444,30445,30448,30451,30453,30454,30455,30458,30459,30461,30463,30464,30466,30467,30469,30470,30474,30476,30478,30479,30480,30481,30482,30483,30484,30485,30486,30487,30488,30491,30492,30493,30494,30497,30499,30500,30501,30503,30506,30507,30508,30510,30512,30513,30514,30515,30516,30521,30523,30525,30526,30527,30530,30532,30533,30534,30536,30537,30538,30539,30540,30541,30542,30543,30546,30547,30548,30549,30550,30551,30552,30553,30556,34180,38649,20445,22561,39281,23453,25265,25253,26292,35961,40077,29190,26479,30865,24754,21329,21271,36744,32972,36125,38049,20493,29384,22791,24811,28953,34987,22868,33519,26412,31528,23849,32503,29997,27893,36454,36856,36924,40763,27604,37145,31508,24444,30887,34006,34109,27605,27609,27606,24065,24199,30201,38381,25949,24330,24517,36767,22721,33218,36991,38491,38829,36793,32534,36140,25153,20415,21464,21342,36776,36777,36779,36941,26631,24426,33176,34920,40150,24971,21035,30250,24428,25996,28626,28392,23486,25672,20853,20912,26564,19993,31177,39292,28851,30557,30558,30559,30560,30564,30567,30569,30570,30573,30574,30575,30576,30577,30578,30579,30580,30581,30582,30583,30584,30586,30587,30588,30593,30594,30595,30598,30599,30600,30601,30602,30603,30607,30608,30611,30612,30613,30614,30615,30616,30617,30618,30619,30620,30621,30622,30625,30627,30628,30630,30632,30635,30637,30638,30639,30641,30642,30644,30646,30647,30648,30649,30650,30652,30654,30656,30657,30658,30659,30660,30661,30662,30663,30664,30665,30666,30667,30668,30670,30671,30672,30673,30674,30675,30676,30677,30678,30680,30681,30682,30685,30686,30687,30688,30689,30692,30149,24182,29627,33760,25773,25320,38069,27874,21338,21187,25615,38082,31636,20271,24091,33334,33046,33162,28196,27850,39539,25429,21340,21754,34917,22496,19981,24067,27493,31807,37096,24598,25830,29468,35009,26448,25165,36130,30572,36393,37319,24425,33756,34081,39184,21442,34453,27531,24813,24808,28799,33485,33329,20179,27815,34255,25805,31961,27133,26361,33609,21397,31574,20391,20876,27979,23618,36461,25554,21449,33580,33590,26597,30900,25661,23519,23700,24046,35815,25286,26612,35962,25600,25530,34633,39307,35863,32544,38130,20135,38416,39076,26124,29462,30694,30696,30698,30703,30704,30705,30706,30708,30709,30711,30713,30714,30715,30716,30723,30724,30725,30726,30727,30728,30730,30731,30734,30735,30736,30739,30741,30745,30747,30750,30752,30753,30754,30756,30760,30762,30763,30766,30767,30769,30770,30771,30773,30774,30781,30783,30785,30786,30787,30788,30790,30792,30793,30794,30795,30797,30799,30801,30803,30804,30808,30809,30810,30811,30812,30814,30815,30816,30817,30818,30819,30820,30821,30822,30823,30824,30825,30831,30832,30833,30834,30835,30836,30837,30838,30840,30841,30842,30843,30845,30846,30847,30848,30849,30850,30851,22330,23581,24120,38271,20607,32928,21378,25950,30021,21809,20513,36229,25220,38046,26397,22066,28526,24034,21557,28818,36710,25199,25764,25507,24443,28552,37108,33251,36784,23576,26216,24561,27785,38472,36225,34924,25745,31216,22478,27225,25104,21576,20056,31243,24809,28548,35802,25215,36894,39563,31204,21507,30196,25345,21273,27744,36831,24347,39536,32827,40831,20360,23610,36196,32709,26021,28861,20805,20914,34411,23815,23456,25277,37228,30068,36364,31264,24833,31609,20167,32504,30597,19985,33261,21021,20986,27249,21416,36487,38148,38607,28353,38500,26970,30852,30853,30854,30856,30858,30859,30863,30864,30866,30868,30869,30870,30873,30877,30878,30880,30882,30884,30886,30888,30889,30890,30891,30892,30893,30894,30895,30901,30902,30903,30904,30906,30907,30908,30909,30911,30912,30914,30915,30916,30918,30919,30920,30924,30925,30926,30927,30929,30930,30931,30934,30935,30936,30938,30939,30940,30941,30942,30943,30944,30945,30946,30947,30948,30949,30950,30951,30953,30954,30955,30957,30958,30959,30960,30961,30963,30965,30966,30968,30969,30971,30972,30973,30974,30975,30976,30978,30979,30980,30982,30983,30984,30985,30986,30987,30988,30784,20648,30679,25616,35302,22788,25571,24029,31359,26941,20256,33337,21912,20018,30126,31383,24162,24202,38383,21019,21561,28810,25462,38180,22402,26149,26943,37255,21767,28147,32431,34850,25139,32496,30133,33576,30913,38604,36766,24904,29943,35789,27492,21050,36176,27425,32874,33905,22257,21254,20174,19995,20945,31895,37259,31751,20419,36479,31713,31388,25703,23828,20652,33030,30209,31929,28140,32736,26449,23384,23544,30923,25774,25619,25514,25387,38169,25645,36798,31572,30249,25171,22823,21574,27513,20643,25140,24102,27526,20195,36151,34955,24453,36910,30989,30990,30991,30992,30993,30994,30996,30997,30998,30999,31000,31001,31002,31003,31004,31005,31007,31008,31009,31010,31011,31013,31014,31015,31016,31017,31018,31019,31020,31021,31022,31023,31024,31025,31026,31027,31029,31030,31031,31032,31033,31037,31039,31042,31043,31044,31045,31047,31050,31051,31052,31053,31054,31055,31056,31057,31058,31060,31061,31064,31065,31073,31075,31076,31078,31081,31082,31083,31084,31086,31088,31089,31090,31091,31092,31093,31094,31097,31099,31100,31101,31102,31103,31106,31107,31110,31111,31112,31113,31115,31116,31117,31118,31120,31121,31122,24608,32829,25285,20025,21333,37112,25528,32966,26086,27694,20294,24814,28129,35806,24377,34507,24403,25377,20826,33633,26723,20992,25443,36424,20498,23707,31095,23548,21040,31291,24764,36947,30423,24503,24471,30340,36460,28783,30331,31561,30634,20979,37011,22564,20302,28404,36842,25932,31515,29380,28068,32735,23265,25269,24213,22320,33922,31532,24093,24351,36882,32532,39072,25474,28359,30872,28857,20856,38747,22443,30005,20291,30008,24215,24806,22880,28096,27583,30857,21500,38613,20939,20993,25481,21514,38035,35843,36300,29241,30879,34678,36845,35853,21472,31123,31124,31125,31126,31127,31128,31129,31131,31132,31133,31134,31135,31136,31137,31138,31139,31140,31141,31142,31144,31145,31146,31147,31148,31149,31150,31151,31152,31153,31154,31156,31157,31158,31159,31160,31164,31167,31170,31172,31173,31175,31176,31178,31180,31182,31183,31184,31187,31188,31190,31191,31193,31194,31195,31196,31197,31198,31200,31201,31202,31205,31208,31210,31212,31214,31217,31218,31219,31220,31221,31222,31223,31225,31226,31228,31230,31231,31233,31236,31237,31239,31240,31241,31242,31244,31247,31248,31249,31250,31251,31253,31254,31256,31257,31259,31260,19969,30447,21486,38025,39030,40718,38189,23450,35746,20002,19996,20908,33891,25026,21160,26635,20375,24683,20923,27934,20828,25238,26007,38497,35910,36887,30168,37117,30563,27602,29322,29420,35835,22581,30585,36172,26460,38208,32922,24230,28193,22930,31471,30701,38203,27573,26029,32526,22534,20817,38431,23545,22697,21544,36466,25958,39039,22244,38045,30462,36929,25479,21702,22810,22842,22427,36530,26421,36346,33333,21057,24816,22549,34558,23784,40517,20420,39069,35769,23077,24694,21380,25212,36943,37122,39295,24681,32780,20799,32819,23572,39285,27953,20108,31261,31263,31265,31266,31268,31269,31270,31271,31272,31273,31274,31275,31276,31277,31278,31279,31280,31281,31282,31284,31285,31286,31288,31290,31294,31296,31297,31298,31299,31300,31301,31303,31304,31305,31306,31307,31308,31309,31310,31311,31312,31314,31315,31316,31317,31318,31320,31321,31322,31323,31324,31325,31326,31327,31328,31329,31330,31331,31332,31333,31334,31335,31336,31337,31338,31339,31340,31341,31342,31343,31345,31346,31347,31349,31355,31356,31357,31358,31362,31365,31367,31369,31370,31371,31372,31374,31375,31376,31379,31380,31385,31386,31387,31390,31393,31394,36144,21457,32602,31567,20240,20047,38400,27861,29648,34281,24070,30058,32763,27146,30718,38034,32321,20961,28902,21453,36820,33539,36137,29359,39277,27867,22346,33459,26041,32938,25151,38450,22952,20223,35775,32442,25918,33778,38750,21857,39134,32933,21290,35837,21536,32954,24223,27832,36153,33452,37210,21545,27675,20998,32439,22367,28954,27774,31881,22859,20221,24575,24868,31914,20016,23553,26539,34562,23792,38155,39118,30127,28925,36898,20911,32541,35773,22857,20964,20315,21542,22827,25975,32932,23413,25206,25282,36752,24133,27679,31526,20239,20440,26381,31395,31396,31399,31401,31402,31403,31406,31407,31408,31409,31410,31412,31413,31414,31415,31416,31417,31418,31419,31420,31421,31422,31424,31425,31426,31427,31428,31429,31430,31431,31432,31433,31434,31436,31437,31438,31439,31440,31441,31442,31443,31444,31445,31447,31448,31450,31451,31452,31453,31457,31458,31460,31463,31464,31465,31466,31467,31468,31470,31472,31473,31474,31475,31476,31477,31478,31479,31480,31483,31484,31486,31488,31489,31490,31493,31495,31497,31500,31501,31502,31504,31506,31507,31510,31511,31512,31514,31516,31517,31519,31521,31522,31523,31527,31529,31533,28014,28074,31119,34993,24343,29995,25242,36741,20463,37340,26023,33071,33105,24220,33104,36212,21103,35206,36171,22797,20613,20184,38428,29238,33145,36127,23500,35747,38468,22919,32538,21648,22134,22030,35813,25913,27010,38041,30422,28297,24178,29976,26438,26577,31487,32925,36214,24863,31174,25954,36195,20872,21018,38050,32568,32923,32434,23703,28207,26464,31705,30347,39640,33167,32660,31957,25630,38224,31295,21578,21733,27468,25601,25096,40509,33011,30105,21106,38761,33883,26684,34532,38401,38548,38124,20010,21508,32473,26681,36319,32789,26356,24218,32697,31535,31536,31538,31540,31541,31542,31543,31545,31547,31549,31551,31552,31553,31554,31555,31556,31558,31560,31562,31565,31566,31571,31573,31575,31577,31580,31582,31583,31585,31587,31588,31589,31590,31591,31592,31593,31594,31595,31596,31597,31599,31600,31603,31604,31606,31608,31610,31612,31613,31615,31617,31618,31619,31620,31622,31623,31624,31625,31626,31627,31628,31630,31631,31633,31634,31635,31638,31640,31641,31642,31643,31646,31647,31648,31651,31652,31653,31662,31663,31664,31666,31667,31669,31670,31671,31673,31674,31675,31676,31677,31678,31679,31680,31682,31683,31684,22466,32831,26775,24037,25915,21151,24685,40858,20379,36524,20844,23467,24339,24041,27742,25329,36129,20849,38057,21246,27807,33503,29399,22434,26500,36141,22815,36764,33735,21653,31629,20272,27837,23396,22993,40723,21476,34506,39592,35895,32929,25925,39038,22266,38599,21038,29916,21072,23521,25346,35074,20054,25296,24618,26874,20851,23448,20896,35266,31649,39302,32592,24815,28748,36143,20809,24191,36891,29808,35268,22317,30789,24402,40863,38394,36712,39740,35809,30328,26690,26588,36330,36149,21053,36746,28378,26829,38149,37101,22269,26524,35065,36807,21704,31685,31688,31689,31690,31691,31693,31694,31695,31696,31698,31700,31701,31702,31703,31704,31707,31708,31710,31711,31712,31714,31715,31716,31719,31720,31721,31723,31724,31725,31727,31728,31730,31731,31732,31733,31734,31736,31737,31738,31739,31741,31743,31744,31745,31746,31747,31748,31749,31750,31752,31753,31754,31757,31758,31760,31761,31762,31763,31764,31765,31767,31768,31769,31770,31771,31772,31773,31774,31776,31777,31778,31779,31780,31781,31784,31785,31787,31788,31789,31790,31791,31792,31793,31794,31795,31796,31797,31798,31799,31801,31802,31803,31804,31805,31806,31810,39608,23401,28023,27686,20133,23475,39559,37219,25000,37039,38889,21547,28085,23506,20989,21898,32597,32752,25788,25421,26097,25022,24717,28938,27735,27721,22831,26477,33322,22741,22158,35946,27627,37085,22909,32791,21495,28009,21621,21917,33655,33743,26680,31166,21644,20309,21512,30418,35977,38402,27827,28088,36203,35088,40548,36154,22079,40657,30165,24456,29408,24680,21756,20136,27178,34913,24658,36720,21700,28888,34425,40511,27946,23439,24344,32418,21897,20399,29492,21564,21402,20505,21518,21628,20046,24573,29786,22774,33899,32993,34676,29392,31946,28246,31811,31812,31813,31814,31815,31816,31817,31818,31819,31820,31822,31823,31824,31825,31826,31827,31828,31829,31830,31831,31832,31833,31834,31835,31836,31837,31838,31839,31840,31841,31842,31843,31844,31845,31846,31847,31848,31849,31850,31851,31852,31853,31854,31855,31856,31857,31858,31861,31862,31863,31864,31865,31866,31870,31871,31872,31873,31874,31875,31876,31877,31878,31879,31880,31882,31883,31884,31885,31886,31887,31888,31891,31892,31894,31897,31898,31899,31904,31905,31907,31910,31911,31912,31913,31915,31916,31917,31919,31920,31924,31925,31926,31927,31928,31930,31931,24359,34382,21804,25252,20114,27818,25143,33457,21719,21326,29502,28369,30011,21010,21270,35805,27088,24458,24576,28142,22351,27426,29615,26707,36824,32531,25442,24739,21796,30186,35938,28949,28067,23462,24187,33618,24908,40644,30970,34647,31783,30343,20976,24822,29004,26179,24140,24653,35854,28784,25381,36745,24509,24674,34516,22238,27585,24724,24935,21321,24800,26214,36159,31229,20250,28905,27719,35763,35826,32472,33636,26127,23130,39746,27985,28151,35905,27963,20249,28779,33719,25110,24785,38669,36135,31096,20987,22334,22522,26426,30072,31293,31215,31637,31935,31936,31938,31939,31940,31942,31945,31947,31950,31951,31952,31953,31954,31955,31956,31960,31962,31963,31965,31966,31969,31970,31971,31972,31973,31974,31975,31977,31978,31979,31980,31981,31982,31984,31985,31986,31987,31988,31989,31990,31991,31993,31994,31996,31997,31998,31999,32000,32001,32002,32003,32004,32005,32006,32007,32008,32009,32011,32012,32013,32014,32015,32016,32017,32018,32019,32020,32021,32022,32023,32024,32025,32026,32027,32028,32029,32030,32031,32033,32035,32036,32037,32038,32040,32041,32042,32044,32045,32046,32048,32049,32050,32051,32052,32053,32054,32908,39269,36857,28608,35749,40481,23020,32489,32521,21513,26497,26840,36753,31821,38598,21450,24613,30142,27762,21363,23241,32423,25380,20960,33034,24049,34015,25216,20864,23395,20238,31085,21058,24760,27982,23492,23490,35745,35760,26082,24524,38469,22931,32487,32426,22025,26551,22841,20339,23478,21152,33626,39050,36158,30002,38078,20551,31292,20215,26550,39550,23233,27516,30417,22362,23574,31546,38388,29006,20860,32937,33392,22904,32516,33575,26816,26604,30897,30839,25315,25441,31616,20461,21098,20943,33616,27099,37492,36341,36145,35265,38190,31661,20214,32055,32056,32057,32058,32059,32060,32061,32062,32063,32064,32065,32066,32067,32068,32069,32070,32071,32072,32073,32074,32075,32076,32077,32078,32079,32080,32081,32082,32083,32084,32085,32086,32087,32088,32089,32090,32091,32092,32093,32094,32095,32096,32097,32098,32099,32100,32101,32102,32103,32104,32105,32106,32107,32108,32109,32111,32112,32113,32114,32115,32116,32117,32118,32120,32121,32122,32123,32124,32125,32126,32127,32128,32129,32130,32131,32132,32133,32134,32135,32136,32137,32138,32139,32140,32141,32142,32143,32144,32145,32146,32147,32148,32149,32150,32151,32152,20581,33328,21073,39279,28176,28293,28071,24314,20725,23004,23558,27974,27743,30086,33931,26728,22870,35762,21280,37233,38477,34121,26898,30977,28966,33014,20132,37066,27975,39556,23047,22204,25605,38128,30699,20389,33050,29409,35282,39290,32564,32478,21119,25945,37237,36735,36739,21483,31382,25581,25509,30342,31224,34903,38454,25130,21163,33410,26708,26480,25463,30571,31469,27905,32467,35299,22992,25106,34249,33445,30028,20511,20171,30117,35819,23626,24062,31563,26020,37329,20170,27941,35167,32039,38182,20165,35880,36827,38771,26187,31105,36817,28908,28024,32153,32154,32155,32156,32157,32158,32159,32160,32161,32162,32163,32164,32165,32167,32168,32169,32170,32171,32172,32173,32175,32176,32177,32178,32179,32180,32181,32182,32183,32184,32185,32186,32187,32188,32189,32190,32191,32192,32193,32194,32195,32196,32197,32198,32199,32200,32201,32202,32203,32204,32205,32206,32207,32208,32209,32210,32211,32212,32213,32214,32215,32216,32217,32218,32219,32220,32221,32222,32223,32224,32225,32226,32227,32228,32229,32230,32231,32232,32233,32234,32235,32236,32237,32238,32239,32240,32241,32242,32243,32244,32245,32246,32247,32248,32249,32250,23613,21170,33606,20834,33550,30555,26230,40120,20140,24778,31934,31923,32463,20117,35686,26223,39048,38745,22659,25964,38236,24452,30153,38742,31455,31454,20928,28847,31384,25578,31350,32416,29590,38893,20037,28792,20061,37202,21417,25937,26087,33276,33285,21646,23601,30106,38816,25304,29401,30141,23621,39545,33738,23616,21632,30697,20030,27822,32858,25298,25454,24040,20855,36317,36382,38191,20465,21477,24807,28844,21095,25424,40515,23071,20518,30519,21367,32482,25733,25899,25225,25496,20500,29237,35273,20915,35776,32477,22343,33740,38055,20891,21531,23803,32251,32252,32253,32254,32255,32256,32257,32258,32259,32260,32261,32262,32263,32264,32265,32266,32267,32268,32269,32270,32271,32272,32273,32274,32275,32276,32277,32278,32279,32280,32281,32282,32283,32284,32285,32286,32287,32288,32289,32290,32291,32292,32293,32294,32295,32296,32297,32298,32299,32300,32301,32302,32303,32304,32305,32306,32307,32308,32309,32310,32311,32312,32313,32314,32316,32317,32318,32319,32320,32322,32323,32324,32325,32326,32328,32329,32330,32331,32332,32333,32334,32335,32336,32337,32338,32339,32340,32341,32342,32343,32344,32345,32346,32347,32348,32349,20426,31459,27994,37089,39567,21888,21654,21345,21679,24320,25577,26999,20975,24936,21002,22570,21208,22350,30733,30475,24247,24951,31968,25179,25239,20130,28821,32771,25335,28900,38752,22391,33499,26607,26869,30933,39063,31185,22771,21683,21487,28212,20811,21051,23458,35838,32943,21827,22438,24691,22353,21549,31354,24656,23380,25511,25248,21475,25187,23495,26543,21741,31391,33510,37239,24211,35044,22840,22446,25358,36328,33007,22359,31607,20393,24555,23485,27454,21281,31568,29378,26694,30719,30518,26103,20917,20111,30420,23743,31397,33909,22862,39745,20608,32350,32351,32352,32353,32354,32355,32356,32357,32358,32359,32360,32361,32362,32363,32364,32365,32366,32367,32368,32369,32370,32371,32372,32373,32374,32375,32376,32377,32378,32379,32380,32381,32382,32383,32384,32385,32387,32388,32389,32390,32391,32392,32393,32394,32395,32396,32397,32398,32399,32400,32401,32402,32403,32404,32405,32406,32407,32408,32409,32410,32412,32413,32414,32430,32436,32443,32444,32470,32484,32492,32505,32522,32528,32542,32567,32569,32571,32572,32573,32574,32575,32576,32577,32579,32582,32583,32584,32585,32586,32587,32588,32589,32590,32591,32594,32595,39304,24871,28291,22372,26118,25414,22256,25324,25193,24275,38420,22403,25289,21895,34593,33098,36771,21862,33713,26469,36182,34013,23146,26639,25318,31726,38417,20848,28572,35888,25597,35272,25042,32518,28866,28389,29701,27028,29436,24266,37070,26391,28010,25438,21171,29282,32769,20332,23013,37226,28889,28061,21202,20048,38647,38253,34174,30922,32047,20769,22418,25794,32907,31867,27882,26865,26974,20919,21400,26792,29313,40654,31729,29432,31163,28435,29702,26446,37324,40100,31036,33673,33620,21519,26647,20029,21385,21169,30782,21382,21033,20616,20363,20432,32598,32601,32603,32604,32605,32606,32608,32611,32612,32613,32614,32615,32619,32620,32621,32623,32624,32627,32629,32630,32631,32632,32634,32635,32636,32637,32639,32640,32642,32643,32644,32645,32646,32647,32648,32649,32651,32653,32655,32656,32657,32658,32659,32661,32662,32663,32664,32665,32667,32668,32672,32674,32675,32677,32678,32680,32681,32682,32683,32684,32685,32686,32689,32691,32692,32693,32694,32695,32698,32699,32702,32704,32706,32707,32708,32710,32711,32712,32713,32715,32717,32719,32720,32721,32722,32723,32726,32727,32729,32730,32731,32732,32733,32734,32738,32739,30178,31435,31890,27813,38582,21147,29827,21737,20457,32852,33714,36830,38256,24265,24604,28063,24088,25947,33080,38142,24651,28860,32451,31918,20937,26753,31921,33391,20004,36742,37327,26238,20142,35845,25769,32842,20698,30103,29134,23525,36797,28518,20102,25730,38243,24278,26009,21015,35010,28872,21155,29454,29747,26519,30967,38678,20020,37051,40158,28107,20955,36161,21533,25294,29618,33777,38646,40836,38083,20278,32666,20940,28789,38517,23725,39046,21478,20196,28316,29705,27060,30827,39311,30041,21016,30244,27969,26611,20845,40857,32843,21657,31548,31423,32740,32743,32744,32746,32747,32748,32749,32751,32754,32756,32757,32758,32759,32760,32761,32762,32765,32766,32767,32770,32775,32776,32777,32778,32782,32783,32785,32787,32794,32795,32797,32798,32799,32801,32803,32804,32811,32812,32813,32814,32815,32816,32818,32820,32825,32826,32828,32830,32832,32833,32836,32837,32839,32840,32841,32846,32847,32848,32849,32851,32853,32854,32855,32857,32859,32860,32861,32862,32863,32864,32865,32866,32867,32868,32869,32870,32871,32872,32875,32876,32877,32878,32879,32880,32882,32883,32884,32885,32886,32887,32888,32889,32890,32891,32892,32893,38534,22404,25314,38471,27004,23044,25602,31699,28431,38475,33446,21346,39045,24208,28809,25523,21348,34383,40065,40595,30860,38706,36335,36162,40575,28510,31108,24405,38470,25134,39540,21525,38109,20387,26053,23653,23649,32533,34385,27695,24459,29575,28388,32511,23782,25371,23402,28390,21365,20081,25504,30053,25249,36718,20262,20177,27814,32438,35770,33821,34746,32599,36923,38179,31657,39585,35064,33853,27931,39558,32476,22920,40635,29595,30721,34434,39532,39554,22043,21527,22475,20080,40614,21334,36808,33033,30610,39314,34542,28385,34067,26364,24930,28459,32894,32897,32898,32901,32904,32906,32909,32910,32911,32912,32913,32914,32916,32917,32919,32921,32926,32931,32934,32935,32936,32940,32944,32947,32949,32950,32952,32953,32955,32965,32967,32968,32969,32970,32971,32975,32976,32977,32978,32979,32980,32981,32984,32991,32992,32994,32995,32998,33006,33013,33015,33017,33019,33022,33023,33024,33025,33027,33028,33029,33031,33032,33035,33036,33045,33047,33049,33051,33052,33053,33055,33056,33057,33058,33059,33060,33061,33062,33063,33064,33065,33066,33067,33069,33070,33072,33075,33076,33077,33079,33081,33082,33083,33084,33085,33087,35881,33426,33579,30450,27667,24537,33725,29483,33541,38170,27611,30683,38086,21359,33538,20882,24125,35980,36152,20040,29611,26522,26757,37238,38665,29028,27809,30473,23186,38209,27599,32654,26151,23504,22969,23194,38376,38391,20204,33804,33945,27308,30431,38192,29467,26790,23391,30511,37274,38753,31964,36855,35868,24357,31859,31192,35269,27852,34588,23494,24130,26825,30496,32501,20885,20813,21193,23081,32517,38754,33495,25551,30596,34256,31186,28218,24217,22937,34065,28781,27665,25279,30399,25935,24751,38397,26126,34719,40483,38125,21517,21629,35884,25720,33088,33089,33090,33091,33092,33093,33095,33097,33101,33102,33103,33106,33110,33111,33112,33115,33116,33117,33118,33119,33121,33122,33123,33124,33126,33128,33130,33131,33132,33135,33138,33139,33141,33142,33143,33144,33153,33155,33156,33157,33158,33159,33161,33163,33164,33165,33166,33168,33170,33171,33172,33173,33174,33175,33177,33178,33182,33183,33184,33185,33186,33188,33189,33191,33193,33195,33196,33197,33198,33199,33200,33201,33202,33204,33205,33206,33207,33208,33209,33212,33213,33214,33215,33220,33221,33223,33224,33225,33227,33229,33230,33231,33232,33233,33234,33235,25721,34321,27169,33180,30952,25705,39764,25273,26411,33707,22696,40664,27819,28448,23518,38476,35851,29279,26576,25287,29281,20137,22982,27597,22675,26286,24149,21215,24917,26408,30446,30566,29287,31302,25343,21738,21584,38048,37027,23068,32435,27670,20035,22902,32784,22856,21335,30007,38590,22218,25376,33041,24700,38393,28118,21602,39297,20869,23273,33021,22958,38675,20522,27877,23612,25311,20320,21311,33147,36870,28346,34091,25288,24180,30910,25781,25467,24565,23064,37247,40479,23615,25423,32834,23421,21870,38218,38221,28037,24744,26592,29406,20957,23425,33236,33237,33238,33239,33240,33241,33242,33243,33244,33245,33246,33247,33248,33249,33250,33252,33253,33254,33256,33257,33259,33262,33263,33264,33265,33266,33269,33270,33271,33272,33273,33274,33277,33279,33283,33287,33288,33289,33290,33291,33294,33295,33297,33299,33301,33302,33303,33304,33305,33306,33309,33312,33316,33317,33318,33319,33321,33326,33330,33338,33340,33341,33343,33344,33345,33346,33347,33349,33350,33352,33354,33356,33357,33358,33360,33361,33362,33363,33364,33365,33366,33367,33369,33371,33372,33373,33374,33376,33377,33378,33379,33380,33381,33382,33383,33385,25319,27870,29275,25197,38062,32445,33043,27987,20892,24324,22900,21162,24594,22899,26262,34384,30111,25386,25062,31983,35834,21734,27431,40485,27572,34261,21589,20598,27812,21866,36276,29228,24085,24597,29750,25293,25490,29260,24472,28227,27966,25856,28504,30424,30928,30460,30036,21028,21467,20051,24222,26049,32810,32982,25243,21638,21032,28846,34957,36305,27873,21624,32986,22521,35060,36180,38506,37197,20329,27803,21943,30406,30768,25256,28921,28558,24429,34028,26842,30844,31735,33192,26379,40527,25447,30896,22383,30738,38713,25209,25259,21128,29749,27607,33386,33387,33388,33389,33393,33397,33398,33399,33400,33403,33404,33408,33409,33411,33413,33414,33415,33417,33420,33424,33427,33428,33429,33430,33434,33435,33438,33440,33442,33443,33447,33458,33461,33462,33466,33467,33468,33471,33472,33474,33475,33477,33478,33481,33488,33494,33497,33498,33501,33506,33511,33512,33513,33514,33516,33517,33518,33520,33522,33523,33525,33526,33528,33530,33532,33533,33534,33535,33536,33546,33547,33549,33552,33554,33555,33558,33560,33561,33565,33566,33567,33568,33569,33570,33571,33572,33573,33574,33577,33578,33582,33584,33586,33591,33595,33597,21860,33086,30130,30382,21305,30174,20731,23617,35692,31687,20559,29255,39575,39128,28418,29922,31080,25735,30629,25340,39057,36139,21697,32856,20050,22378,33529,33805,24179,20973,29942,35780,23631,22369,27900,39047,23110,30772,39748,36843,31893,21078,25169,38138,20166,33670,33889,33769,33970,22484,26420,22275,26222,28006,35889,26333,28689,26399,27450,26646,25114,22971,19971,20932,28422,26578,27791,20854,26827,22855,27495,30054,23822,33040,40784,26071,31048,31041,39569,36215,23682,20062,20225,21551,22865,30732,22120,27668,36804,24323,27773,27875,35755,25488,33598,33599,33601,33602,33604,33605,33608,33610,33611,33612,33613,33614,33619,33621,33622,33623,33624,33625,33629,33634,33648,33649,33650,33651,33652,33653,33654,33657,33658,33662,33663,33664,33665,33666,33667,33668,33671,33672,33674,33675,33676,33677,33679,33680,33681,33684,33685,33686,33687,33689,33690,33693,33695,33697,33698,33699,33700,33701,33702,33703,33708,33709,33710,33711,33717,33723,33726,33727,33730,33731,33732,33734,33736,33737,33739,33741,33742,33744,33745,33746,33747,33749,33751,33753,33754,33755,33758,33762,33763,33764,33766,33767,33768,33771,33772,33773,24688,27965,29301,25190,38030,38085,21315,36801,31614,20191,35878,20094,40660,38065,38067,21069,28508,36963,27973,35892,22545,23884,27424,27465,26538,21595,33108,32652,22681,34103,24378,25250,27207,38201,25970,24708,26725,30631,20052,20392,24039,38808,25772,32728,23789,20431,31373,20999,33540,19988,24623,31363,38054,20405,20146,31206,29748,21220,33465,25810,31165,23517,27777,38738,36731,27682,20542,21375,28165,25806,26228,27696,24773,39031,35831,24198,29756,31351,31179,19992,37041,29699,27714,22234,37195,27845,36235,21306,34502,26354,36527,23624,39537,28192,33774,33775,33779,33780,33781,33782,33783,33786,33787,33788,33790,33791,33792,33794,33797,33799,33800,33801,33802,33808,33810,33811,33812,33813,33814,33815,33817,33818,33819,33822,33823,33824,33825,33826,33827,33833,33834,33835,33836,33837,33838,33839,33840,33842,33843,33844,33845,33846,33847,33849,33850,33851,33854,33855,33856,33857,33858,33859,33860,33861,33863,33864,33865,33866,33867,33868,33869,33870,33871,33872,33874,33875,33876,33877,33878,33880,33885,33886,33887,33888,33890,33892,33893,33894,33895,33896,33898,33902,33903,33904,33906,33908,33911,33913,33915,33916,21462,23094,40843,36259,21435,22280,39079,26435,37275,27849,20840,30154,25331,29356,21048,21149,32570,28820,30264,21364,40522,27063,30830,38592,35033,32676,28982,29123,20873,26579,29924,22756,25880,22199,35753,39286,25200,32469,24825,28909,22764,20161,20154,24525,38887,20219,35748,20995,22922,32427,25172,20173,26085,25102,33592,33993,33635,34701,29076,28342,23481,32466,20887,25545,26580,32905,33593,34837,20754,23418,22914,36785,20083,27741,20837,35109,36719,38446,34122,29790,38160,38384,28070,33509,24369,25746,27922,33832,33134,40131,22622,36187,19977,21441,33917,33918,33919,33920,33921,33923,33924,33925,33926,33930,33933,33935,33936,33937,33938,33939,33940,33941,33942,33944,33946,33947,33949,33950,33951,33952,33954,33955,33956,33957,33958,33959,33960,33961,33962,33963,33964,33965,33966,33968,33969,33971,33973,33974,33975,33979,33980,33982,33984,33986,33987,33989,33990,33991,33992,33995,33996,33998,33999,34002,34004,34005,34007,34008,34009,34010,34011,34012,34014,34017,34018,34020,34023,34024,34025,34026,34027,34029,34030,34031,34033,34034,34035,34036,34037,34038,34039,34040,34041,34042,34043,34045,34046,34048,34049,34050,20254,25955,26705,21971,20007,25620,39578,25195,23234,29791,33394,28073,26862,20711,33678,30722,26432,21049,27801,32433,20667,21861,29022,31579,26194,29642,33515,26441,23665,21024,29053,34923,38378,38485,25797,36193,33203,21892,27733,25159,32558,22674,20260,21830,36175,26188,19978,23578,35059,26786,25422,31245,28903,33421,21242,38902,23569,21736,37045,32461,22882,36170,34503,33292,33293,36198,25668,23556,24913,28041,31038,35774,30775,30003,21627,20280,36523,28145,23072,32453,31070,27784,23457,23158,29978,32958,24910,28183,22768,29983,29989,29298,21319,32499,34051,34052,34053,34054,34055,34056,34057,34058,34059,34061,34062,34063,34064,34066,34068,34069,34070,34072,34073,34075,34076,34077,34078,34080,34082,34083,34084,34085,34086,34087,34088,34089,34090,34093,34094,34095,34096,34097,34098,34099,34100,34101,34102,34110,34111,34112,34113,34114,34116,34117,34118,34119,34123,34124,34125,34126,34127,34128,34129,34130,34131,34132,34133,34135,34136,34138,34139,34140,34141,34143,34144,34145,34146,34147,34149,34150,34151,34153,34154,34155,34156,34157,34158,34159,34160,34161,34163,34165,34166,34167,34168,34172,34173,34175,34176,34177,30465,30427,21097,32988,22307,24072,22833,29422,26045,28287,35799,23608,34417,21313,30707,25342,26102,20160,39135,34432,23454,35782,21490,30690,20351,23630,39542,22987,24335,31034,22763,19990,26623,20107,25325,35475,36893,21183,26159,21980,22124,36866,20181,20365,37322,39280,27663,24066,24643,23460,35270,35797,25910,25163,39318,23432,23551,25480,21806,21463,30246,20861,34092,26530,26803,27530,25234,36755,21460,33298,28113,30095,20070,36174,23408,29087,34223,26257,26329,32626,34560,40653,40736,23646,26415,36848,26641,26463,25101,31446,22661,24246,25968,28465,34178,34179,34182,34184,34185,34186,34187,34188,34189,34190,34192,34193,34194,34195,34196,34197,34198,34199,34200,34201,34202,34205,34206,34207,34208,34209,34210,34211,34213,34214,34215,34217,34219,34220,34221,34225,34226,34227,34228,34229,34230,34232,34234,34235,34236,34237,34238,34239,34240,34242,34243,34244,34245,34246,34247,34248,34250,34251,34252,34253,34254,34257,34258,34260,34262,34263,34264,34265,34266,34267,34269,34270,34271,34272,34273,34274,34275,34277,34278,34279,34280,34282,34283,34284,34285,34286,34287,34288,34289,34290,34291,34292,34293,34294,34295,34296,24661,21047,32781,25684,34928,29993,24069,26643,25332,38684,21452,29245,35841,27700,30561,31246,21550,30636,39034,33308,35828,30805,26388,28865,26031,25749,22070,24605,31169,21496,19997,27515,32902,23546,21987,22235,20282,20284,39282,24051,26494,32824,24578,39042,36865,23435,35772,35829,25628,33368,25822,22013,33487,37221,20439,32032,36895,31903,20723,22609,28335,23487,35785,32899,37240,33948,31639,34429,38539,38543,32485,39635,30862,23681,31319,36930,38567,31071,23385,25439,31499,34001,26797,21766,32553,29712,32034,38145,25152,22604,20182,23427,22905,22612,34297,34298,34300,34301,34302,34304,34305,34306,34307,34308,34310,34311,34312,34313,34314,34315,34316,34317,34318,34319,34320,34322,34323,34324,34325,34327,34328,34329,34330,34331,34332,34333,34334,34335,34336,34337,34338,34339,34340,34341,34342,34344,34346,34347,34348,34349,34350,34351,34352,34353,34354,34355,34356,34357,34358,34359,34361,34362,34363,34365,34366,34367,34368,34369,34370,34371,34372,34373,34374,34375,34376,34377,34378,34379,34380,34386,34387,34389,34390,34391,34392,34393,34395,34396,34397,34399,34400,34401,34403,34404,34405,34406,34407,34408,34409,34410,29549,25374,36427,36367,32974,33492,25260,21488,27888,37214,22826,24577,27760,22349,25674,36138,30251,28393,22363,27264,30192,28525,35885,35848,22374,27631,34962,30899,25506,21497,28845,27748,22616,25642,22530,26848,33179,21776,31958,20504,36538,28108,36255,28907,25487,28059,28372,32486,33796,26691,36867,28120,38518,35752,22871,29305,34276,33150,30140,35466,26799,21076,36386,38161,25552,39064,36420,21884,20307,26367,22159,24789,28053,21059,23625,22825,28155,22635,30000,29980,24684,33300,33094,25361,26465,36834,30522,36339,36148,38081,24086,21381,21548,28867,34413,34415,34416,34418,34419,34420,34421,34422,34423,34424,34435,34436,34437,34438,34439,34440,34441,34446,34447,34448,34449,34450,34452,34454,34455,34456,34457,34458,34459,34462,34463,34464,34465,34466,34469,34470,34475,34477,34478,34482,34483,34487,34488,34489,34491,34492,34493,34494,34495,34497,34498,34499,34501,34504,34508,34509,34514,34515,34517,34518,34519,34522,34524,34525,34528,34529,34530,34531,34533,34534,34535,34536,34538,34539,34540,34543,34549,34550,34551,34554,34555,34556,34557,34559,34561,34564,34565,34566,34571,34572,34574,34575,34576,34577,34580,34582,27712,24311,20572,20141,24237,25402,33351,36890,26704,37230,30643,21516,38108,24420,31461,26742,25413,31570,32479,30171,20599,25237,22836,36879,20984,31171,31361,22270,24466,36884,28034,23648,22303,21520,20820,28237,22242,25512,39059,33151,34581,35114,36864,21534,23663,33216,25302,25176,33073,40501,38464,39534,39548,26925,22949,25299,21822,25366,21703,34521,27964,23043,29926,34972,27498,22806,35916,24367,28286,29609,39037,20024,28919,23436,30871,25405,26202,30358,24779,23451,23113,19975,33109,27754,29579,20129,26505,32593,24448,26106,26395,24536,22916,23041,34585,34587,34589,34591,34592,34596,34598,34599,34600,34602,34603,34604,34605,34607,34608,34610,34611,34613,34614,34616,34617,34618,34620,34621,34624,34625,34626,34627,34628,34629,34630,34634,34635,34637,34639,34640,34641,34642,34644,34645,34646,34648,34650,34651,34652,34653,34654,34655,34657,34658,34662,34663,34664,34665,34666,34667,34668,34669,34671,34673,34674,34675,34677,34679,34680,34681,34682,34687,34688,34689,34692,34694,34695,34697,34698,34700,34702,34703,34704,34705,34706,34708,34709,34710,34712,34713,34714,34715,34716,34717,34718,34720,34721,34722,34723,34724,24013,24494,21361,38886,36829,26693,22260,21807,24799,20026,28493,32500,33479,33806,22996,20255,20266,23614,32428,26410,34074,21619,30031,32963,21890,39759,20301,28205,35859,23561,24944,21355,30239,28201,34442,25991,38395,32441,21563,31283,32010,38382,21985,32705,29934,25373,34583,28065,31389,25105,26017,21351,25569,27779,24043,21596,38056,20044,27745,35820,23627,26080,33436,26791,21566,21556,27595,27494,20116,25410,21320,33310,20237,20398,22366,25098,38654,26212,29289,21247,21153,24735,35823,26132,29081,26512,35199,30802,30717,26224,22075,21560,38177,29306,34725,34726,34727,34729,34730,34734,34736,34737,34738,34740,34742,34743,34744,34745,34747,34748,34750,34751,34753,34754,34755,34756,34757,34759,34760,34761,34764,34765,34766,34767,34768,34772,34773,34774,34775,34776,34777,34778,34780,34781,34782,34783,34785,34786,34787,34788,34790,34791,34792,34793,34795,34796,34797,34799,34800,34801,34802,34803,34804,34805,34806,34807,34808,34810,34811,34812,34813,34815,34816,34817,34818,34820,34821,34822,34823,34824,34825,34827,34828,34829,34830,34831,34832,34833,34834,34836,34839,34840,34841,34842,34844,34845,34846,34847,34848,34851,31232,24687,24076,24713,33181,22805,24796,29060,28911,28330,27728,29312,27268,34989,24109,20064,23219,21916,38115,27927,31995,38553,25103,32454,30606,34430,21283,38686,36758,26247,23777,20384,29421,19979,21414,22799,21523,25472,38184,20808,20185,40092,32420,21688,36132,34900,33335,38386,28046,24358,23244,26174,38505,29616,29486,21439,33146,39301,32673,23466,38519,38480,32447,30456,21410,38262,39321,31665,35140,28248,20065,32724,31077,35814,24819,21709,20139,39033,24055,27233,20687,21521,35937,33831,30813,38660,21066,21742,22179,38144,28040,23477,28102,26195,34852,34853,34854,34855,34856,34857,34858,34859,34860,34861,34862,34863,34864,34865,34867,34868,34869,34870,34871,34872,34874,34875,34877,34878,34879,34881,34882,34883,34886,34887,34888,34889,34890,34891,34894,34895,34896,34897,34898,34899,34901,34902,34904,34906,34907,34908,34909,34910,34911,34912,34918,34919,34922,34925,34927,34929,34931,34932,34933,34934,34936,34937,34938,34939,34940,34944,34947,34950,34951,34953,34954,34956,34958,34959,34960,34961,34963,34964,34965,34967,34968,34969,34970,34971,34973,34974,34975,34976,34977,34979,34981,34982,34983,34984,34985,34986,23567,23389,26657,32918,21880,31505,25928,26964,20123,27463,34638,38795,21327,25375,25658,37034,26012,32961,35856,20889,26800,21368,34809,25032,27844,27899,35874,23633,34218,33455,38156,27427,36763,26032,24571,24515,20449,34885,26143,33125,29481,24826,20852,21009,22411,24418,37026,34892,37266,24184,26447,24615,22995,20804,20982,33016,21256,27769,38596,29066,20241,20462,32670,26429,21957,38152,31168,34966,32483,22687,25100,38656,34394,22040,39035,24464,35768,33988,37207,21465,26093,24207,30044,24676,32110,23167,32490,32493,36713,21927,23459,24748,26059,29572,34988,34990,34991,34992,34994,34995,34996,34997,34998,35000,35001,35002,35003,35005,35006,35007,35008,35011,35012,35015,35016,35018,35019,35020,35021,35023,35024,35025,35027,35030,35031,35034,35035,35036,35037,35038,35040,35041,35046,35047,35049,35050,35051,35052,35053,35054,35055,35058,35061,35062,35063,35066,35067,35069,35071,35072,35073,35075,35076,35077,35078,35079,35080,35081,35083,35084,35085,35086,35087,35089,35092,35093,35094,35095,35096,35100,35101,35102,35103,35104,35106,35107,35108,35110,35111,35112,35113,35116,35117,35118,35119,35121,35122,35123,35125,35127,36873,30307,30505,32474,38772,34203,23398,31348,38634,34880,21195,29071,24490,26092,35810,23547,39535,24033,27529,27739,35757,35759,36874,36805,21387,25276,40486,40493,21568,20011,33469,29273,34460,23830,34905,28079,38597,21713,20122,35766,28937,21693,38409,28895,28153,30416,20005,30740,34578,23721,24310,35328,39068,38414,28814,27839,22852,25513,30524,34893,28436,33395,22576,29141,21388,30746,38593,21761,24422,28976,23476,35866,39564,27523,22830,40495,31207,26472,25196,20335,30113,32650,27915,38451,27687,20208,30162,20859,26679,28478,36992,33136,22934,29814,35128,35129,35130,35131,35132,35133,35134,35135,35136,35138,35139,35141,35142,35143,35144,35145,35146,35147,35148,35149,35150,35151,35152,35153,35154,35155,35156,35157,35158,35159,35160,35161,35162,35163,35164,35165,35168,35169,35170,35171,35172,35173,35175,35176,35177,35178,35179,35180,35181,35182,35183,35184,35185,35186,35187,35188,35189,35190,35191,35192,35193,35194,35196,35197,35198,35200,35202,35204,35205,35207,35208,35209,35210,35211,35212,35213,35214,35215,35216,35217,35218,35219,35220,35221,35222,35223,35224,35225,35226,35227,35228,35229,35230,35231,35232,35233,25671,23591,36965,31377,35875,23002,21676,33280,33647,35201,32768,26928,22094,32822,29239,37326,20918,20063,39029,25494,19994,21494,26355,33099,22812,28082,19968,22777,21307,25558,38129,20381,20234,34915,39056,22839,36951,31227,20202,33008,30097,27778,23452,23016,24413,26885,34433,20506,24050,20057,30691,20197,33402,25233,26131,37009,23673,20159,24441,33222,36920,32900,30123,20134,35028,24847,27589,24518,20041,30410,28322,35811,35758,35850,35793,24322,32764,32716,32462,33589,33643,22240,27575,38899,38452,23035,21535,38134,28139,23493,39278,23609,24341,38544,35234,35235,35236,35237,35238,35239,35240,35241,35242,35243,35244,35245,35246,35247,35248,35249,35250,35251,35252,35253,35254,35255,35256,35257,35258,35259,35260,35261,35262,35263,35264,35267,35277,35283,35284,35285,35287,35288,35289,35291,35293,35295,35296,35297,35298,35300,35303,35304,35305,35306,35308,35309,35310,35312,35313,35314,35316,35317,35318,35319,35320,35321,35322,35323,35324,35325,35326,35327,35329,35330,35331,35332,35333,35334,35336,35337,35338,35339,35340,35341,35342,35343,35344,35345,35346,35347,35348,35349,35350,35351,35352,35353,35354,35355,35356,35357,21360,33521,27185,23156,40560,24212,32552,33721,33828,33829,33639,34631,36814,36194,30408,24433,39062,30828,26144,21727,25317,20323,33219,30152,24248,38605,36362,34553,21647,27891,28044,27704,24703,21191,29992,24189,20248,24736,24551,23588,30001,37038,38080,29369,27833,28216,37193,26377,21451,21491,20305,37321,35825,21448,24188,36802,28132,20110,30402,27014,34398,24858,33286,20313,20446,36926,40060,24841,28189,28180,38533,20104,23089,38632,19982,23679,31161,23431,35821,32701,29577,22495,33419,37057,21505,36935,21947,23786,24481,24840,27442,29425,32946,35465,35358,35359,35360,35361,35362,35363,35364,35365,35366,35367,35368,35369,35370,35371,35372,35373,35374,35375,35376,35377,35378,35379,35380,35381,35382,35383,35384,35385,35386,35387,35388,35389,35391,35392,35393,35394,35395,35396,35397,35398,35399,35401,35402,35403,35404,35405,35406,35407,35408,35409,35410,35411,35412,35413,35414,35415,35416,35417,35418,35419,35420,35421,35422,35423,35424,35425,35426,35427,35428,35429,35430,35431,35432,35433,35434,35435,35436,35437,35438,35439,35440,35441,35442,35443,35444,35445,35446,35447,35448,35450,35451,35452,35453,35454,35455,35456,28020,23507,35029,39044,35947,39533,40499,28170,20900,20803,22435,34945,21407,25588,36757,22253,21592,22278,29503,28304,32536,36828,33489,24895,24616,38498,26352,32422,36234,36291,38053,23731,31908,26376,24742,38405,32792,20113,37095,21248,38504,20801,36816,34164,37213,26197,38901,23381,21277,30776,26434,26685,21705,28798,23472,36733,20877,22312,21681,25874,26242,36190,36163,33039,33900,36973,31967,20991,34299,26531,26089,28577,34468,36481,22122,36896,30338,28790,29157,36131,25321,21017,27901,36156,24590,22686,24974,26366,36192,25166,21939,28195,26413,36711,35457,35458,35459,35460,35461,35462,35463,35464,35467,35468,35469,35470,35471,35472,35473,35474,35476,35477,35478,35479,35480,35481,35482,35483,35484,35485,35486,35487,35488,35489,35490,35491,35492,35493,35494,35495,35496,35497,35498,35499,35500,35501,35502,35503,35504,35505,35506,35507,35508,35509,35510,35511,35512,35513,35514,35515,35516,35517,35518,35519,35520,35521,35522,35523,35524,35525,35526,35527,35528,35529,35530,35531,35532,35533,35534,35535,35536,35537,35538,35539,35540,35541,35542,35543,35544,35545,35546,35547,35548,35549,35550,35551,35552,35553,35554,35555,38113,38392,30504,26629,27048,21643,20045,28856,35784,25688,25995,23429,31364,20538,23528,30651,27617,35449,31896,27838,30415,26025,36759,23853,23637,34360,26632,21344,25112,31449,28251,32509,27167,31456,24432,28467,24352,25484,28072,26454,19976,24080,36134,20183,32960,30260,38556,25307,26157,25214,27836,36213,29031,32617,20806,32903,21484,36974,25240,21746,34544,36761,32773,38167,34071,36825,27993,29645,26015,30495,29956,30759,33275,36126,38024,20390,26517,30137,35786,38663,25391,38215,38453,33976,25379,30529,24449,29424,20105,24596,25972,25327,27491,25919,35556,35557,35558,35559,35560,35561,35562,35563,35564,35565,35566,35567,35568,35569,35570,35571,35572,35573,35574,35575,35576,35577,35578,35579,35580,35581,35582,35583,35584,35585,35586,35587,35588,35589,35590,35592,35593,35594,35595,35596,35597,35598,35599,35600,35601,35602,35603,35604,35605,35606,35607,35608,35609,35610,35611,35612,35613,35614,35615,35616,35617,35618,35619,35620,35621,35623,35624,35625,35626,35627,35628,35629,35630,35631,35632,35633,35634,35635,35636,35637,35638,35639,35640,35641,35642,35643,35644,35645,35646,35647,35648,35649,35650,35651,35652,35653,24103,30151,37073,35777,33437,26525,25903,21553,34584,30693,32930,33026,27713,20043,32455,32844,30452,26893,27542,25191,20540,20356,22336,25351,27490,36286,21482,26088,32440,24535,25370,25527,33267,33268,32622,24092,23769,21046,26234,31209,31258,36136,28825,30164,28382,27835,31378,20013,30405,24544,38047,34935,32456,31181,32959,37325,20210,20247,33311,21608,24030,27954,35788,31909,36724,32920,24090,21650,30385,23449,26172,39588,29664,26666,34523,26417,29482,35832,35803,36880,31481,28891,29038,25284,30633,22065,20027,33879,26609,21161,34496,36142,38136,31569,35654,35655,35656,35657,35658,35659,35660,35661,35662,35663,35664,35665,35666,35667,35668,35669,35670,35671,35672,35673,35674,35675,35676,35677,35678,35679,35680,35681,35682,35683,35684,35685,35687,35688,35689,35690,35691,35693,35694,35695,35696,35697,35698,35699,35700,35701,35702,35703,35704,35705,35706,35707,35708,35709,35710,35711,35712,35713,35714,35715,35716,35717,35718,35719,35720,35721,35722,35723,35724,35725,35726,35727,35728,35729,35730,35731,35732,35733,35734,35735,35736,35737,35738,35739,35740,35741,35742,35743,35756,35761,35771,35783,35792,35818,35849,35870,20303,27880,31069,39547,25235,29226,25341,19987,30742,36716,25776,36186,31686,26729,24196,35013,22918,25758,22766,29366,26894,38181,36861,36184,22368,32512,35846,20934,25417,25305,21331,26700,29730,33537,37196,21828,30528,28796,27978,20857,21672,36164,23039,28363,28100,23388,32043,20180,31869,28371,23376,33258,28173,23383,39683,26837,36394,23447,32508,24635,32437,37049,36208,22863,25549,31199,36275,21330,26063,31062,35781,38459,32452,38075,32386,22068,37257,26368,32618,23562,36981,26152,24038,20304,26590,20570,20316,22352,24231,59408,59409,59410,59411,59412,35896,35897,35898,35899,35900,35901,35902,35903,35904,35906,35907,35908,35909,35912,35914,35915,35917,35918,35919,35920,35921,35922,35923,35924,35926,35927,35928,35929,35931,35932,35933,35934,35935,35936,35939,35940,35941,35942,35943,35944,35945,35948,35949,35950,35951,35952,35953,35954,35956,35957,35958,35959,35963,35964,35965,35966,35967,35968,35969,35971,35972,35974,35975,35976,35979,35981,35982,35983,35984,35985,35986,35987,35989,35990,35991,35993,35994,35995,35996,35997,35998,35999,36000,36001,36002,36003,36004,36005,36006,36007,36008,36009,36010,36011,36012,36013,20109,19980,20800,19984,24319,21317,19989,20120,19998,39730,23404,22121,20008,31162,20031,21269,20039,22829,29243,21358,27664,22239,32996,39319,27603,30590,40727,20022,20127,40720,20060,20073,20115,33416,23387,21868,22031,20164,21389,21405,21411,21413,21422,38757,36189,21274,21493,21286,21294,21310,36188,21350,21347,20994,21000,21006,21037,21043,21055,21056,21068,21086,21089,21084,33967,21117,21122,21121,21136,21139,20866,32596,20155,20163,20169,20162,20200,20193,20203,20190,20251,20211,20258,20324,20213,20261,20263,20233,20267,20318,20327,25912,20314,20317,36014,36015,36016,36017,36018,36019,36020,36021,36022,36023,36024,36025,36026,36027,36028,36029,36030,36031,36032,36033,36034,36035,36036,36037,36038,36039,36040,36041,36042,36043,36044,36045,36046,36047,36048,36049,36050,36051,36052,36053,36054,36055,36056,36057,36058,36059,36060,36061,36062,36063,36064,36065,36066,36067,36068,36069,36070,36071,36072,36073,36074,36075,36076,36077,36078,36079,36080,36081,36082,36083,36084,36085,36086,36087,36088,36089,36090,36091,36092,36093,36094,36095,36096,36097,36098,36099,36100,36101,36102,36103,36104,36105,36106,36107,36108,36109,20319,20311,20274,20285,20342,20340,20369,20361,20355,20367,20350,20347,20394,20348,20396,20372,20454,20456,20458,20421,20442,20451,20444,20433,20447,20472,20521,20556,20467,20524,20495,20526,20525,20478,20508,20492,20517,20520,20606,20547,20565,20552,20558,20588,20603,20645,20647,20649,20666,20694,20742,20717,20716,20710,20718,20743,20747,20189,27709,20312,20325,20430,40864,27718,31860,20846,24061,40649,39320,20865,22804,21241,21261,35335,21264,20971,22809,20821,20128,20822,20147,34926,34980,20149,33044,35026,31104,23348,34819,32696,20907,20913,20925,20924,36110,36111,36112,36113,36114,36115,36116,36117,36118,36119,36120,36121,36122,36123,36124,36128,36177,36178,36183,36191,36197,36200,36201,36202,36204,36206,36207,36209,36210,36216,36217,36218,36219,36220,36221,36222,36223,36224,36226,36227,36230,36231,36232,36233,36236,36237,36238,36239,36240,36242,36243,36245,36246,36247,36248,36249,36250,36251,36252,36253,36254,36256,36257,36258,36260,36261,36262,36263,36264,36265,36266,36267,36268,36269,36270,36271,36272,36274,36278,36279,36281,36283,36285,36288,36289,36290,36293,36295,36296,36297,36298,36301,36304,36306,36307,36308,20935,20886,20898,20901,35744,35750,35751,35754,35764,35765,35767,35778,35779,35787,35791,35790,35794,35795,35796,35798,35800,35801,35804,35807,35808,35812,35816,35817,35822,35824,35827,35830,35833,35836,35839,35840,35842,35844,35847,35852,35855,35857,35858,35860,35861,35862,35865,35867,35864,35869,35871,35872,35873,35877,35879,35882,35883,35886,35887,35890,35891,35893,35894,21353,21370,38429,38434,38433,38449,38442,38461,38460,38466,38473,38484,38495,38503,38508,38514,38516,38536,38541,38551,38576,37015,37019,37021,37017,37036,37025,37044,37043,37046,37050,36309,36312,36313,36316,36320,36321,36322,36325,36326,36327,36329,36333,36334,36336,36337,36338,36340,36342,36348,36350,36351,36352,36353,36354,36355,36356,36358,36359,36360,36363,36365,36366,36368,36369,36370,36371,36373,36374,36375,36376,36377,36378,36379,36380,36384,36385,36388,36389,36390,36391,36392,36395,36397,36400,36402,36403,36404,36406,36407,36408,36411,36412,36414,36415,36419,36421,36422,36428,36429,36430,36431,36432,36435,36436,36437,36438,36439,36440,36442,36443,36444,36445,36446,36447,36448,36449,36450,36451,36452,36453,36455,36456,36458,36459,36462,36465,37048,37040,37071,37061,37054,37072,37060,37063,37075,37094,37090,37084,37079,37083,37099,37103,37118,37124,37154,37150,37155,37169,37167,37177,37187,37190,21005,22850,21154,21164,21165,21182,21759,21200,21206,21232,21471,29166,30669,24308,20981,20988,39727,21430,24321,30042,24047,22348,22441,22433,22654,22716,22725,22737,22313,22316,22314,22323,22329,22318,22319,22364,22331,22338,22377,22405,22379,22406,22396,22395,22376,22381,22390,22387,22445,22436,22412,22450,22479,22439,22452,22419,22432,22485,22488,22490,22489,22482,22456,22516,22511,22520,22500,22493,36467,36469,36471,36472,36473,36474,36475,36477,36478,36480,36482,36483,36484,36486,36488,36489,36490,36491,36492,36493,36494,36497,36498,36499,36501,36502,36503,36504,36505,36506,36507,36509,36511,36512,36513,36514,36515,36516,36517,36518,36519,36520,36521,36522,36525,36526,36528,36529,36531,36532,36533,36534,36535,36536,36537,36539,36540,36541,36542,36543,36544,36545,36546,36547,36548,36549,36550,36551,36552,36553,36554,36555,36556,36557,36559,36560,36561,36562,36563,36564,36565,36566,36567,36568,36569,36570,36571,36572,36573,36574,36575,36576,36577,36578,36579,36580,22539,22541,22525,22509,22528,22558,22553,22596,22560,22629,22636,22657,22665,22682,22656,39336,40729,25087,33401,33405,33407,33423,33418,33448,33412,33422,33425,33431,33433,33451,33464,33470,33456,33480,33482,33507,33432,33463,33454,33483,33484,33473,33449,33460,33441,33450,33439,33476,33486,33444,33505,33545,33527,33508,33551,33543,33500,33524,33490,33496,33548,33531,33491,33553,33562,33542,33556,33557,33504,33493,33564,33617,33627,33628,33544,33682,33596,33588,33585,33691,33630,33583,33615,33607,33603,33631,33600,33559,33632,33581,33594,33587,33638,33637,36581,36582,36583,36584,36585,36586,36587,36588,36589,36590,36591,36592,36593,36594,36595,36596,36597,36598,36599,36600,36601,36602,36603,36604,36605,36606,36607,36608,36609,36610,36611,36612,36613,36614,36615,36616,36617,36618,36619,36620,36621,36622,36623,36624,36625,36626,36627,36628,36629,36630,36631,36632,36633,36634,36635,36636,36637,36638,36639,36640,36641,36642,36643,36644,36645,36646,36647,36648,36649,36650,36651,36652,36653,36654,36655,36656,36657,36658,36659,36660,36661,36662,36663,36664,36665,36666,36667,36668,36669,36670,36671,36672,36673,36674,36675,36676,33640,33563,33641,33644,33642,33645,33646,33712,33656,33715,33716,33696,33706,33683,33692,33669,33660,33718,33705,33661,33720,33659,33688,33694,33704,33722,33724,33729,33793,33765,33752,22535,33816,33803,33757,33789,33750,33820,33848,33809,33798,33748,33759,33807,33795,33784,33785,33770,33733,33728,33830,33776,33761,33884,33873,33882,33881,33907,33927,33928,33914,33929,33912,33852,33862,33897,33910,33932,33934,33841,33901,33985,33997,34000,34022,33981,34003,33994,33983,33978,34016,33953,33977,33972,33943,34021,34019,34060,29965,34104,34032,34105,34079,34106,36677,36678,36679,36680,36681,36682,36683,36684,36685,36686,36687,36688,36689,36690,36691,36692,36693,36694,36695,36696,36697,36698,36699,36700,36701,36702,36703,36704,36705,36706,36707,36708,36709,36714,36736,36748,36754,36765,36768,36769,36770,36772,36773,36774,36775,36778,36780,36781,36782,36783,36786,36787,36788,36789,36791,36792,36794,36795,36796,36799,36800,36803,36806,36809,36810,36811,36812,36813,36815,36818,36822,36823,36826,36832,36833,36835,36839,36844,36847,36849,36850,36852,36853,36854,36858,36859,36860,36862,36863,36871,36872,36876,36878,36883,36885,36888,34134,34107,34047,34044,34137,34120,34152,34148,34142,34170,30626,34115,34162,34171,34212,34216,34183,34191,34169,34222,34204,34181,34233,34231,34224,34259,34241,34268,34303,34343,34309,34345,34326,34364,24318,24328,22844,22849,32823,22869,22874,22872,21263,23586,23589,23596,23604,25164,25194,25247,25275,25290,25306,25303,25326,25378,25334,25401,25419,25411,25517,25590,25457,25466,25486,25524,25453,25516,25482,25449,25518,25532,25586,25592,25568,25599,25540,25566,25550,25682,25542,25534,25669,25665,25611,25627,25632,25612,25638,25633,25694,25732,25709,25750,36889,36892,36899,36900,36901,36903,36904,36905,36906,36907,36908,36912,36913,36914,36915,36916,36919,36921,36922,36925,36927,36928,36931,36933,36934,36936,36937,36938,36939,36940,36942,36948,36949,36950,36953,36954,36956,36957,36958,36959,36960,36961,36964,36966,36967,36969,36970,36971,36972,36975,36976,36977,36978,36979,36982,36983,36984,36985,36986,36987,36988,36990,36993,36996,36997,36998,36999,37001,37002,37004,37005,37006,37007,37008,37010,37012,37014,37016,37018,37020,37022,37023,37024,37028,37029,37031,37032,37033,37035,37037,37042,37047,37052,37053,37055,37056,25722,25783,25784,25753,25786,25792,25808,25815,25828,25826,25865,25893,25902,24331,24530,29977,24337,21343,21489,21501,21481,21480,21499,21522,21526,21510,21579,21586,21587,21588,21590,21571,21537,21591,21593,21539,21554,21634,21652,21623,21617,21604,21658,21659,21636,21622,21606,21661,21712,21677,21698,21684,21714,21671,21670,21715,21716,21618,21667,21717,21691,21695,21708,21721,21722,21724,21673,21674,21668,21725,21711,21726,21787,21735,21792,21757,21780,21747,21794,21795,21775,21777,21799,21802,21863,21903,21941,21833,21869,21825,21845,21823,21840,21820,37058,37059,37062,37064,37065,37067,37068,37069,37074,37076,37077,37078,37080,37081,37082,37086,37087,37088,37091,37092,37093,37097,37098,37100,37102,37104,37105,37106,37107,37109,37110,37111,37113,37114,37115,37116,37119,37120,37121,37123,37125,37126,37127,37128,37129,37130,37131,37132,37133,37134,37135,37136,37137,37138,37139,37140,37141,37142,37143,37144,37146,37147,37148,37149,37151,37152,37153,37156,37157,37158,37159,37160,37161,37162,37163,37164,37165,37166,37168,37170,37171,37172,37173,37174,37175,37176,37178,37179,37180,37181,37182,37183,37184,37185,37186,37188,21815,21846,21877,21878,21879,21811,21808,21852,21899,21970,21891,21937,21945,21896,21889,21919,21886,21974,21905,21883,21983,21949,21950,21908,21913,21994,22007,21961,22047,21969,21995,21996,21972,21990,21981,21956,21999,21989,22002,22003,21964,21965,21992,22005,21988,36756,22046,22024,22028,22017,22052,22051,22014,22016,22055,22061,22104,22073,22103,22060,22093,22114,22105,22108,22092,22100,22150,22116,22129,22123,22139,22140,22149,22163,22191,22228,22231,22237,22241,22261,22251,22265,22271,22276,22282,22281,22300,24079,24089,24084,24081,24113,24123,24124,37189,37191,37192,37201,37203,37204,37205,37206,37208,37209,37211,37212,37215,37216,37222,37223,37224,37227,37229,37235,37242,37243,37244,37248,37249,37250,37251,37252,37254,37256,37258,37262,37263,37267,37268,37269,37270,37271,37272,37273,37276,37277,37278,37279,37280,37281,37284,37285,37286,37287,37288,37289,37291,37292,37296,37297,37298,37299,37302,37303,37304,37305,37307,37308,37309,37310,37311,37312,37313,37314,37315,37316,37317,37318,37320,37323,37328,37330,37331,37332,37333,37334,37335,37336,37337,37338,37339,37341,37342,37343,37344,37345,37346,37347,37348,37349,24119,24132,24148,24155,24158,24161,23692,23674,23693,23696,23702,23688,23704,23705,23697,23706,23708,23733,23714,23741,23724,23723,23729,23715,23745,23735,23748,23762,23780,23755,23781,23810,23811,23847,23846,23854,23844,23838,23814,23835,23896,23870,23860,23869,23916,23899,23919,23901,23915,23883,23882,23913,23924,23938,23961,23965,35955,23991,24005,24435,24439,24450,24455,24457,24460,24469,24473,24476,24488,24493,24501,24508,34914,24417,29357,29360,29364,29367,29368,29379,29377,29390,29389,29394,29416,29423,29417,29426,29428,29431,29441,29427,29443,29434,37350,37351,37352,37353,37354,37355,37356,37357,37358,37359,37360,37361,37362,37363,37364,37365,37366,37367,37368,37369,37370,37371,37372,37373,37374,37375,37376,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37387,37388,37389,37390,37391,37392,37393,37394,37395,37396,37397,37398,37399,37400,37401,37402,37403,37404,37405,37406,37407,37408,37409,37410,37411,37412,37413,37414,37415,37416,37417,37418,37419,37420,37421,37422,37423,37424,37425,37426,37427,37428,37429,37430,37431,37432,37433,37434,37435,37436,37437,37438,37439,37440,37441,37442,37443,37444,37445,29435,29463,29459,29473,29450,29470,29469,29461,29474,29497,29477,29484,29496,29489,29520,29517,29527,29536,29548,29551,29566,33307,22821,39143,22820,22786,39267,39271,39272,39273,39274,39275,39276,39284,39287,39293,39296,39300,39303,39306,39309,39312,39313,39315,39316,39317,24192,24209,24203,24214,24229,24224,24249,24245,24254,24243,36179,24274,24273,24283,24296,24298,33210,24516,24521,24534,24527,24579,24558,24580,24545,24548,24574,24581,24582,24554,24557,24568,24601,24629,24614,24603,24591,24589,24617,24619,24586,24639,24609,24696,24697,24699,24698,24642,37446,37447,37448,37449,37450,37451,37452,37453,37454,37455,37456,37457,37458,37459,37460,37461,37462,37463,37464,37465,37466,37467,37468,37469,37470,37471,37472,37473,37474,37475,37476,37477,37478,37479,37480,37481,37482,37483,37484,37485,37486,37487,37488,37489,37490,37491,37493,37494,37495,37496,37497,37498,37499,37500,37501,37502,37503,37504,37505,37506,37507,37508,37509,37510,37511,37512,37513,37514,37515,37516,37517,37519,37520,37521,37522,37523,37524,37525,37526,37527,37528,37529,37530,37531,37532,37533,37534,37535,37536,37537,37538,37539,37540,37541,37542,37543,24682,24701,24726,24730,24749,24733,24707,24722,24716,24731,24812,24763,24753,24797,24792,24774,24794,24756,24864,24870,24853,24867,24820,24832,24846,24875,24906,24949,25004,24980,24999,25015,25044,25077,24541,38579,38377,38379,38385,38387,38389,38390,38396,38398,38403,38404,38406,38408,38410,38411,38412,38413,38415,38418,38421,38422,38423,38425,38426,20012,29247,25109,27701,27732,27740,27722,27811,27781,27792,27796,27788,27752,27753,27764,27766,27782,27817,27856,27860,27821,27895,27896,27889,27863,27826,27872,27862,27898,27883,27886,27825,27859,27887,27902,37544,37545,37546,37547,37548,37549,37551,37552,37553,37554,37555,37556,37557,37558,37559,37560,37561,37562,37563,37564,37565,37566,37567,37568,37569,37570,37571,37572,37573,37574,37575,37577,37578,37579,37580,37581,37582,37583,37584,37585,37586,37587,37588,37589,37590,37591,37592,37593,37594,37595,37596,37597,37598,37599,37600,37601,37602,37603,37604,37605,37606,37607,37608,37609,37610,37611,37612,37613,37614,37615,37616,37617,37618,37619,37620,37621,37622,37623,37624,37625,37626,37627,37628,37629,37630,37631,37632,37633,37634,37635,37636,37637,37638,37639,37640,37641,27961,27943,27916,27971,27976,27911,27908,27929,27918,27947,27981,27950,27957,27930,27983,27986,27988,27955,28049,28015,28062,28064,27998,28051,28052,27996,28000,28028,28003,28186,28103,28101,28126,28174,28095,28128,28177,28134,28125,28121,28182,28075,28172,28078,28203,28270,28238,28267,28338,28255,28294,28243,28244,28210,28197,28228,28383,28337,28312,28384,28461,28386,28325,28327,28349,28347,28343,28375,28340,28367,28303,28354,28319,28514,28486,28487,28452,28437,28409,28463,28470,28491,28532,28458,28425,28457,28553,28557,28556,28536,28530,28540,28538,28625,37642,37643,37644,37645,37646,37647,37648,37649,37650,37651,37652,37653,37654,37655,37656,37657,37658,37659,37660,37661,37662,37663,37664,37665,37666,37667,37668,37669,37670,37671,37672,37673,37674,37675,37676,37677,37678,37679,37680,37681,37682,37683,37684,37685,37686,37687,37688,37689,37690,37691,37692,37693,37695,37696,37697,37698,37699,37700,37701,37702,37703,37704,37705,37706,37707,37708,37709,37710,37711,37712,37713,37714,37715,37716,37717,37718,37719,37720,37721,37722,37723,37724,37725,37726,37727,37728,37729,37730,37731,37732,37733,37734,37735,37736,37737,37739,28617,28583,28601,28598,28610,28641,28654,28638,28640,28655,28698,28707,28699,28729,28725,28751,28766,23424,23428,23445,23443,23461,23480,29999,39582,25652,23524,23534,35120,23536,36423,35591,36790,36819,36821,36837,36846,36836,36841,36838,36851,36840,36869,36868,36875,36902,36881,36877,36886,36897,36917,36918,36909,36911,36932,36945,36946,36944,36968,36952,36962,36955,26297,36980,36989,36994,37000,36995,37003,24400,24407,24406,24408,23611,21675,23632,23641,23409,23651,23654,32700,24362,24361,24365,33396,24380,39739,23662,22913,22915,22925,22953,22954,22947,37740,37741,37742,37743,37744,37745,37746,37747,37748,37749,37750,37751,37752,37753,37754,37755,37756,37757,37758,37759,37760,37761,37762,37763,37764,37765,37766,37767,37768,37769,37770,37771,37772,37773,37774,37776,37777,37778,37779,37780,37781,37782,37783,37784,37785,37786,37787,37788,37789,37790,37791,37792,37793,37794,37795,37796,37797,37798,37799,37800,37801,37802,37803,37804,37805,37806,37807,37808,37809,37810,37811,37812,37813,37814,37815,37816,37817,37818,37819,37820,37821,37822,37823,37824,37825,37826,37827,37828,37829,37830,37831,37832,37833,37835,37836,37837,22935,22986,22955,22942,22948,22994,22962,22959,22999,22974,23045,23046,23005,23048,23011,23000,23033,23052,23049,23090,23092,23057,23075,23059,23104,23143,23114,23125,23100,23138,23157,33004,23210,23195,23159,23162,23230,23275,23218,23250,23252,23224,23264,23267,23281,23254,23270,23256,23260,23305,23319,23318,23346,23351,23360,23573,23580,23386,23397,23411,23377,23379,23394,39541,39543,39544,39546,39551,39549,39552,39553,39557,39560,39562,39568,39570,39571,39574,39576,39579,39580,39581,39583,39584,39586,39587,39589,39591,32415,32417,32419,32421,32424,32425,37838,37839,37840,37841,37842,37843,37844,37845,37847,37848,37849,37850,37851,37852,37853,37854,37855,37856,37857,37858,37859,37860,37861,37862,37863,37864,37865,37866,37867,37868,37869,37870,37871,37872,37873,37874,37875,37876,37877,37878,37879,37880,37881,37882,37883,37884,37885,37886,37887,37888,37889,37890,37891,37892,37893,37894,37895,37896,37897,37898,37899,37900,37901,37902,37903,37904,37905,37906,37907,37908,37909,37910,37911,37912,37913,37914,37915,37916,37917,37918,37919,37920,37921,37922,37923,37924,37925,37926,37927,37928,37929,37930,37931,37932,37933,37934,32429,32432,32446,32448,32449,32450,32457,32459,32460,32464,32468,32471,32475,32480,32481,32488,32491,32494,32495,32497,32498,32525,32502,32506,32507,32510,32513,32514,32515,32519,32520,32523,32524,32527,32529,32530,32535,32537,32540,32539,32543,32545,32546,32547,32548,32549,32550,32551,32554,32555,32556,32557,32559,32560,32561,32562,32563,32565,24186,30079,24027,30014,37013,29582,29585,29614,29602,29599,29647,29634,29649,29623,29619,29632,29641,29640,29669,29657,39036,29706,29673,29671,29662,29626,29682,29711,29738,29787,29734,29733,29736,29744,29742,29740,37935,37936,37937,37938,37939,37940,37941,37942,37943,37944,37945,37946,37947,37948,37949,37951,37952,37953,37954,37955,37956,37957,37958,37959,37960,37961,37962,37963,37964,37965,37966,37967,37968,37969,37970,37971,37972,37973,37974,37975,37976,37977,37978,37979,37980,37981,37982,37983,37984,37985,37986,37987,37988,37989,37990,37991,37992,37993,37994,37996,37997,37998,37999,38000,38001,38002,38003,38004,38005,38006,38007,38008,38009,38010,38011,38012,38013,38014,38015,38016,38017,38018,38019,38020,38033,38038,38040,38087,38095,38099,38100,38106,38118,38139,38172,38176,29723,29722,29761,29788,29783,29781,29785,29815,29805,29822,29852,29838,29824,29825,29831,29835,29854,29864,29865,29840,29863,29906,29882,38890,38891,38892,26444,26451,26462,26440,26473,26533,26503,26474,26483,26520,26535,26485,26536,26526,26541,26507,26487,26492,26608,26633,26584,26634,26601,26544,26636,26585,26549,26586,26547,26589,26624,26563,26552,26594,26638,26561,26621,26674,26675,26720,26721,26702,26722,26692,26724,26755,26653,26709,26726,26689,26727,26688,26686,26698,26697,26665,26805,26767,26740,26743,26771,26731,26818,26990,26876,26911,26912,26873,38183,38195,38205,38211,38216,38219,38229,38234,38240,38254,38260,38261,38263,38264,38265,38266,38267,38268,38269,38270,38272,38273,38274,38275,38276,38277,38278,38279,38280,38281,38282,38283,38284,38285,38286,38287,38288,38289,38290,38291,38292,38293,38294,38295,38296,38297,38298,38299,38300,38301,38302,38303,38304,38305,38306,38307,38308,38309,38310,38311,38312,38313,38314,38315,38316,38317,38318,38319,38320,38321,38322,38323,38324,38325,38326,38327,38328,38329,38330,38331,38332,38333,38334,38335,38336,38337,38338,38339,38340,38341,38342,38343,38344,38345,38346,38347,26916,26864,26891,26881,26967,26851,26896,26993,26937,26976,26946,26973,27012,26987,27008,27032,27000,26932,27084,27015,27016,27086,27017,26982,26979,27001,27035,27047,27067,27051,27053,27092,27057,27073,27082,27103,27029,27104,27021,27135,27183,27117,27159,27160,27237,27122,27204,27198,27296,27216,27227,27189,27278,27257,27197,27176,27224,27260,27281,27280,27305,27287,27307,29495,29522,27521,27522,27527,27524,27538,27539,27533,27546,27547,27553,27562,36715,36717,36721,36722,36723,36725,36726,36728,36727,36729,36730,36732,36734,36737,36738,36740,36743,36747,38348,38349,38350,38351,38352,38353,38354,38355,38356,38357,38358,38359,38360,38361,38362,38363,38364,38365,38366,38367,38368,38369,38370,38371,38372,38373,38374,38375,38380,38399,38407,38419,38424,38427,38430,38432,38435,38436,38437,38438,38439,38440,38441,38443,38444,38445,38447,38448,38455,38456,38457,38458,38462,38465,38467,38474,38478,38479,38481,38482,38483,38486,38487,38488,38489,38490,38492,38493,38494,38496,38499,38501,38502,38507,38509,38510,38511,38512,38513,38515,38520,38521,38522,38523,38524,38525,38526,38527,38528,38529,38530,38531,38532,38535,38537,38538,36749,36750,36751,36760,36762,36558,25099,25111,25115,25119,25122,25121,25125,25124,25132,33255,29935,29940,29951,29967,29969,29971,25908,26094,26095,26096,26122,26137,26482,26115,26133,26112,28805,26359,26141,26164,26161,26166,26165,32774,26207,26196,26177,26191,26198,26209,26199,26231,26244,26252,26279,26269,26302,26331,26332,26342,26345,36146,36147,36150,36155,36157,36160,36165,36166,36168,36169,36167,36173,36181,36185,35271,35274,35275,35276,35278,35279,35280,35281,29294,29343,29277,29286,29295,29310,29311,29316,29323,29325,29327,29330,25352,25394,25520,38540,38542,38545,38546,38547,38549,38550,38554,38555,38557,38558,38559,38560,38561,38562,38563,38564,38565,38566,38568,38569,38570,38571,38572,38573,38574,38575,38577,38578,38580,38581,38583,38584,38586,38587,38591,38594,38595,38600,38602,38603,38608,38609,38611,38612,38614,38615,38616,38617,38618,38619,38620,38621,38622,38623,38625,38626,38627,38628,38629,38630,38631,38635,38636,38637,38638,38640,38641,38642,38644,38645,38648,38650,38651,38652,38653,38655,38658,38659,38661,38666,38667,38668,38672,38673,38674,38676,38677,38679,38680,38681,38682,38683,38685,38687,38688,25663,25816,32772,27626,27635,27645,27637,27641,27653,27655,27654,27661,27669,27672,27673,27674,27681,27689,27684,27690,27698,25909,25941,25963,29261,29266,29270,29232,34402,21014,32927,32924,32915,32956,26378,32957,32945,32939,32941,32948,32951,32999,33000,33001,33002,32987,32962,32964,32985,32973,32983,26384,32989,33003,33009,33012,33005,33037,33038,33010,33020,26389,33042,35930,33078,33054,33068,33048,33074,33096,33100,33107,33140,33113,33114,33137,33120,33129,33148,33149,33133,33127,22605,23221,33160,33154,33169,28373,33187,33194,33228,26406,33226,33211,38689,38690,38691,38692,38693,38694,38695,38696,38697,38699,38700,38702,38703,38705,38707,38708,38709,38710,38711,38714,38715,38716,38717,38719,38720,38721,38722,38723,38724,38725,38726,38727,38728,38729,38730,38731,38732,38733,38734,38735,38736,38737,38740,38741,38743,38744,38746,38748,38749,38751,38755,38756,38758,38759,38760,38762,38763,38764,38765,38766,38767,38768,38769,38770,38773,38775,38776,38777,38778,38779,38781,38782,38783,38784,38785,38786,38787,38788,38790,38791,38792,38793,38794,38796,38798,38799,38800,38803,38805,38806,38807,38809,38810,38811,38812,38813,33217,33190,27428,27447,27449,27459,27462,27481,39121,39122,39123,39125,39129,39130,27571,24384,27586,35315,26000,40785,26003,26044,26054,26052,26051,26060,26062,26066,26070,28800,28828,28822,28829,28859,28864,28855,28843,28849,28904,28874,28944,28947,28950,28975,28977,29043,29020,29032,28997,29042,29002,29048,29050,29080,29107,29109,29096,29088,29152,29140,29159,29177,29213,29224,28780,28952,29030,29113,25150,25149,25155,25160,25161,31035,31040,31046,31049,31067,31068,31059,31066,31074,31063,31072,31087,31079,31098,31109,31114,31130,31143,31155,24529,24528,38814,38815,38817,38818,38820,38821,38822,38823,38824,38825,38826,38828,38830,38832,38833,38835,38837,38838,38839,38840,38841,38842,38843,38844,38845,38846,38847,38848,38849,38850,38851,38852,38853,38854,38855,38856,38857,38858,38859,38860,38861,38862,38863,38864,38865,38866,38867,38868,38869,38870,38871,38872,38873,38874,38875,38876,38877,38878,38879,38880,38881,38882,38883,38884,38885,38888,38894,38895,38896,38897,38898,38900,38903,38904,38905,38906,38907,38908,38909,38910,38911,38912,38913,38914,38915,38916,38917,38918,38919,38920,38921,38922,38923,38924,38925,38926,24636,24669,24666,24679,24641,24665,24675,24747,24838,24845,24925,25001,24989,25035,25041,25094,32896,32895,27795,27894,28156,30710,30712,30720,30729,30743,30744,30737,26027,30765,30748,30749,30777,30778,30779,30751,30780,30757,30764,30755,30761,30798,30829,30806,30807,30758,30800,30791,30796,30826,30875,30867,30874,30855,30876,30881,30883,30898,30905,30885,30932,30937,30921,30956,30962,30981,30964,30995,31012,31006,31028,40859,40697,40699,40700,30449,30468,30477,30457,30471,30472,30490,30498,30489,30509,30502,30517,30520,30544,30545,30535,30531,30554,30568,38927,38928,38929,38930,38931,38932,38933,38934,38935,38936,38937,38938,38939,38940,38941,38942,38943,38944,38945,38946,38947,38948,38949,38950,38951,38952,38953,38954,38955,38956,38957,38958,38959,38960,38961,38962,38963,38964,38965,38966,38967,38968,38969,38970,38971,38972,38973,38974,38975,38976,38977,38978,38979,38980,38981,38982,38983,38984,38985,38986,38987,38988,38989,38990,38991,38992,38993,38994,38995,38996,38997,38998,38999,39000,39001,39002,39003,39004,39005,39006,39007,39008,39009,39010,39011,39012,39013,39014,39015,39016,39017,39018,39019,39020,39021,39022,30562,30565,30591,30605,30589,30592,30604,30609,30623,30624,30640,30645,30653,30010,30016,30030,30027,30024,30043,30066,30073,30083,32600,32609,32607,35400,32616,32628,32625,32633,32641,32638,30413,30437,34866,38021,38022,38023,38027,38026,38028,38029,38031,38032,38036,38039,38037,38042,38043,38044,38051,38052,38059,38058,38061,38060,38063,38064,38066,38068,38070,38071,38072,38073,38074,38076,38077,38079,38084,38088,38089,38090,38091,38092,38093,38094,38096,38097,38098,38101,38102,38103,38105,38104,38107,38110,38111,38112,38114,38116,38117,38119,38120,38122,39023,39024,39025,39026,39027,39028,39051,39054,39058,39061,39065,39075,39080,39081,39082,39083,39084,39085,39086,39087,39088,39089,39090,39091,39092,39093,39094,39095,39096,39097,39098,39099,39100,39101,39102,39103,39104,39105,39106,39107,39108,39109,39110,39111,39112,39113,39114,39115,39116,39117,39119,39120,39124,39126,39127,39131,39132,39133,39136,39137,39138,39139,39140,39141,39142,39145,39146,39147,39148,39149,39150,39151,39152,39153,39154,39155,39156,39157,39158,39159,39160,39161,39162,39163,39164,39165,39166,39167,39168,39169,39170,39171,39172,39173,39174,39175,38121,38123,38126,38127,38131,38132,38133,38135,38137,38140,38141,38143,38147,38146,38150,38151,38153,38154,38157,38158,38159,38162,38163,38164,38165,38166,38168,38171,38173,38174,38175,38178,38186,38187,38185,38188,38193,38194,38196,38198,38199,38200,38204,38206,38207,38210,38197,38212,38213,38214,38217,38220,38222,38223,38226,38227,38228,38230,38231,38232,38233,38235,38238,38239,38237,38241,38242,38244,38245,38246,38247,38248,38249,38250,38251,38252,38255,38257,38258,38259,38202,30695,30700,38601,31189,31213,31203,31211,31238,23879,31235,31234,31262,31252,39176,39177,39178,39179,39180,39182,39183,39185,39186,39187,39188,39189,39190,39191,39192,39193,39194,39195,39196,39197,39198,39199,39200,39201,39202,39203,39204,39205,39206,39207,39208,39209,39210,39211,39212,39213,39215,39216,39217,39218,39219,39220,39221,39222,39223,39224,39225,39226,39227,39228,39229,39230,39231,39232,39233,39234,39235,39236,39237,39238,39239,39240,39241,39242,39243,39244,39245,39246,39247,39248,39249,39250,39251,39254,39255,39256,39257,39258,39259,39260,39261,39262,39263,39264,39265,39266,39268,39270,39283,39288,39289,39291,39294,39298,39299,39305,31289,31287,31313,40655,39333,31344,30344,30350,30355,30361,30372,29918,29920,29996,40480,40482,40488,40489,40490,40491,40492,40498,40497,40502,40504,40503,40505,40506,40510,40513,40514,40516,40518,40519,40520,40521,40523,40524,40526,40529,40533,40535,40538,40539,40540,40542,40547,40550,40551,40552,40553,40554,40555,40556,40561,40557,40563,30098,30100,30102,30112,30109,30124,30115,30131,30132,30136,30148,30129,30128,30147,30146,30166,30157,30179,30184,30182,30180,30187,30183,30211,30193,30204,30207,30224,30208,30213,30220,30231,30218,30245,30232,30229,30233,39308,39310,39322,39323,39324,39325,39326,39327,39328,39329,39330,39331,39332,39334,39335,39337,39338,39339,39340,39341,39342,39343,39344,39345,39346,39347,39348,39349,39350,39351,39352,39353,39354,39355,39356,39357,39358,39359,39360,39361,39362,39363,39364,39365,39366,39367,39368,39369,39370,39371,39372,39373,39374,39375,39376,39377,39378,39379,39380,39381,39382,39383,39384,39385,39386,39387,39388,39389,39390,39391,39392,39393,39394,39395,39396,39397,39398,39399,39400,39401,39402,39403,39404,39405,39406,39407,39408,39409,39410,39411,39412,39413,39414,39415,39416,39417,30235,30268,30242,30240,30272,30253,30256,30271,30261,30275,30270,30259,30285,30302,30292,30300,30294,30315,30319,32714,31462,31352,31353,31360,31366,31368,31381,31398,31392,31404,31400,31405,31411,34916,34921,34930,34941,34943,34946,34978,35014,34999,35004,35017,35042,35022,35043,35045,35057,35098,35068,35048,35070,35056,35105,35097,35091,35099,35082,35124,35115,35126,35137,35174,35195,30091,32997,30386,30388,30684,32786,32788,32790,32796,32800,32802,32805,32806,32807,32809,32808,32817,32779,32821,32835,32838,32845,32850,32873,32881,35203,39032,39040,39043,39418,39419,39420,39421,39422,39423,39424,39425,39426,39427,39428,39429,39430,39431,39432,39433,39434,39435,39436,39437,39438,39439,39440,39441,39442,39443,39444,39445,39446,39447,39448,39449,39450,39451,39452,39453,39454,39455,39456,39457,39458,39459,39460,39461,39462,39463,39464,39465,39466,39467,39468,39469,39470,39471,39472,39473,39474,39475,39476,39477,39478,39479,39480,39481,39482,39483,39484,39485,39486,39487,39488,39489,39490,39491,39492,39493,39494,39495,39496,39497,39498,39499,39500,39501,39502,39503,39504,39505,39506,39507,39508,39509,39510,39511,39512,39513,39049,39052,39053,39055,39060,39066,39067,39070,39071,39073,39074,39077,39078,34381,34388,34412,34414,34431,34426,34428,34427,34472,34445,34443,34476,34461,34471,34467,34474,34451,34473,34486,34500,34485,34510,34480,34490,34481,34479,34505,34511,34484,34537,34545,34546,34541,34547,34512,34579,34526,34548,34527,34520,34513,34563,34567,34552,34568,34570,34573,34569,34595,34619,34590,34597,34606,34586,34622,34632,34612,34609,34601,34615,34623,34690,34594,34685,34686,34683,34656,34672,34636,34670,34699,34643,34659,34684,34660,34649,34661,34707,34735,34728,34770,39514,39515,39516,39517,39518,39519,39520,39521,39522,39523,39524,39525,39526,39527,39528,39529,39530,39531,39538,39555,39561,39565,39566,39572,39573,39577,39590,39593,39594,39595,39596,39597,39598,39599,39602,39603,39604,39605,39609,39611,39613,39614,39615,39619,39620,39622,39623,39624,39625,39626,39629,39630,39631,39632,39634,39636,39637,39638,39639,39641,39642,39643,39644,39645,39646,39648,39650,39651,39652,39653,39655,39656,39657,39658,39660,39662,39664,39665,39666,39667,39668,39669,39670,39671,39672,39674,39676,39677,39678,39679,39680,39681,39682,39684,39685,39686,34758,34696,34693,34733,34711,34691,34731,34789,34732,34741,34739,34763,34771,34749,34769,34752,34762,34779,34794,34784,34798,34838,34835,34814,34826,34843,34849,34873,34876,32566,32578,32580,32581,33296,31482,31485,31496,31491,31492,31509,31498,31531,31503,31559,31544,31530,31513,31534,31537,31520,31525,31524,31539,31550,31518,31576,31578,31557,31605,31564,31581,31584,31598,31611,31586,31602,31601,31632,31654,31655,31672,31660,31645,31656,31621,31658,31644,31650,31659,31668,31697,31681,31692,31709,31706,31717,31718,31722,31756,31742,31740,31759,31766,31755,39687,39689,39690,39691,39692,39693,39694,39696,39697,39698,39700,39701,39702,39703,39704,39705,39706,39707,39708,39709,39710,39712,39713,39714,39716,39717,39718,39719,39720,39721,39722,39723,39724,39725,39726,39728,39729,39731,39732,39733,39734,39735,39736,39737,39738,39741,39742,39743,39744,39750,39754,39755,39756,39758,39760,39762,39763,39765,39766,39767,39768,39769,39770,39771,39772,39773,39774,39775,39776,39777,39778,39779,39780,39781,39782,39783,39784,39785,39786,39787,39788,39789,39790,39791,39792,39793,39794,39795,39796,39797,39798,39799,39800,39801,39802,39803,31775,31786,31782,31800,31809,31808,33278,33281,33282,33284,33260,34884,33313,33314,33315,33325,33327,33320,33323,33336,33339,33331,33332,33342,33348,33353,33355,33359,33370,33375,33384,34942,34949,34952,35032,35039,35166,32669,32671,32679,32687,32688,32690,31868,25929,31889,31901,31900,31902,31906,31922,31932,31933,31937,31943,31948,31949,31944,31941,31959,31976,33390,26280,32703,32718,32725,32741,32737,32742,32745,32750,32755,31992,32119,32166,32174,32327,32411,40632,40628,36211,36228,36244,36241,36273,36199,36205,35911,35913,37194,37200,37198,37199,37220,39804,39805,39806,39807,39808,39809,39810,39811,39812,39813,39814,39815,39816,39817,39818,39819,39820,39821,39822,39823,39824,39825,39826,39827,39828,39829,39830,39831,39832,39833,39834,39835,39836,39837,39838,39839,39840,39841,39842,39843,39844,39845,39846,39847,39848,39849,39850,39851,39852,39853,39854,39855,39856,39857,39858,39859,39860,39861,39862,39863,39864,39865,39866,39867,39868,39869,39870,39871,39872,39873,39874,39875,39876,39877,39878,39879,39880,39881,39882,39883,39884,39885,39886,39887,39888,39889,39890,39891,39892,39893,39894,39895,39896,39897,39898,39899,37218,37217,37232,37225,37231,37245,37246,37234,37236,37241,37260,37253,37264,37261,37265,37282,37283,37290,37293,37294,37295,37301,37300,37306,35925,40574,36280,36331,36357,36441,36457,36277,36287,36284,36282,36292,36310,36311,36314,36318,36302,36303,36315,36294,36332,36343,36344,36323,36345,36347,36324,36361,36349,36372,36381,36383,36396,36398,36387,36399,36410,36416,36409,36405,36413,36401,36425,36417,36418,36433,36434,36426,36464,36470,36476,36463,36468,36485,36495,36500,36496,36508,36510,35960,35970,35978,35973,35992,35988,26011,35286,35294,35290,35292,39900,39901,39902,39903,39904,39905,39906,39907,39908,39909,39910,39911,39912,39913,39914,39915,39916,39917,39918,39919,39920,39921,39922,39923,39924,39925,39926,39927,39928,39929,39930,39931,39932,39933,39934,39935,39936,39937,39938,39939,39940,39941,39942,39943,39944,39945,39946,39947,39948,39949,39950,39951,39952,39953,39954,39955,39956,39957,39958,39959,39960,39961,39962,39963,39964,39965,39966,39967,39968,39969,39970,39971,39972,39973,39974,39975,39976,39977,39978,39979,39980,39981,39982,39983,39984,39985,39986,39987,39988,39989,39990,39991,39992,39993,39994,39995,35301,35307,35311,35390,35622,38739,38633,38643,38639,38662,38657,38664,38671,38670,38698,38701,38704,38718,40832,40835,40837,40838,40839,40840,40841,40842,40844,40702,40715,40717,38585,38588,38589,38606,38610,30655,38624,37518,37550,37576,37694,37738,37834,37775,37950,37995,40063,40066,40069,40070,40071,40072,31267,40075,40078,40080,40081,40082,40084,40085,40090,40091,40094,40095,40096,40097,40098,40099,40101,40102,40103,40104,40105,40107,40109,40110,40112,40113,40114,40115,40116,40117,40118,40119,40122,40123,40124,40125,40132,40133,40134,40135,40138,40139,39996,39997,39998,39999,40000,40001,40002,40003,40004,40005,40006,40007,40008,40009,40010,40011,40012,40013,40014,40015,40016,40017,40018,40019,40020,40021,40022,40023,40024,40025,40026,40027,40028,40029,40030,40031,40032,40033,40034,40035,40036,40037,40038,40039,40040,40041,40042,40043,40044,40045,40046,40047,40048,40049,40050,40051,40052,40053,40054,40055,40056,40057,40058,40059,40061,40062,40064,40067,40068,40073,40074,40076,40079,40083,40086,40087,40088,40089,40093,40106,40108,40111,40121,40126,40127,40128,40129,40130,40136,40137,40145,40146,40154,40155,40160,40161,40140,40141,40142,40143,40144,40147,40148,40149,40151,40152,40153,40156,40157,40159,40162,38780,38789,38801,38802,38804,38831,38827,38819,38834,38836,39601,39600,39607,40536,39606,39610,39612,39617,39616,39621,39618,39627,39628,39633,39749,39747,39751,39753,39752,39757,39761,39144,39181,39214,39253,39252,39647,39649,39654,39663,39659,39675,39661,39673,39688,39695,39699,39711,39715,40637,40638,32315,40578,40583,40584,40587,40594,37846,40605,40607,40667,40668,40669,40672,40671,40674,40681,40679,40677,40682,40687,40738,40748,40751,40761,40759,40765,40766,40772,40163,40164,40165,40166,40167,40168,40169,40170,40171,40172,40173,40174,40175,40176,40177,40178,40179,40180,40181,40182,40183,40184,40185,40186,40187,40188,40189,40190,40191,40192,40193,40194,40195,40196,40197,40198,40199,40200,40201,40202,40203,40204,40205,40206,40207,40208,40209,40210,40211,40212,40213,40214,40215,40216,40217,40218,40219,40220,40221,40222,40223,40224,40225,40226,40227,40228,40229,40230,40231,40232,40233,40234,40235,40236,40237,40238,40239,40240,40241,40242,40243,40244,40245,40246,40247,40248,40249,40250,40251,40252,40253,40254,40255,40256,40257,40258,57908,57909,57910,57911,57912,57913,57914,57915,57916,57917,57918,57919,57920,57921,57922,57923,57924,57925,57926,57927,57928,57929,57930,57931,57932,57933,57934,57935,57936,57937,57938,57939,57940,57941,57942,57943,57944,57945,57946,57947,57948,57949,57950,57951,57952,57953,57954,57955,57956,57957,57958,57959,57960,57961,57962,57963,57964,57965,57966,57967,57968,57969,57970,57971,57972,57973,57974,57975,57976,57977,57978,57979,57980,57981,57982,57983,57984,57985,57986,57987,57988,57989,57990,57991,57992,57993,57994,57995,57996,57997,57998,57999,58000,58001,40259,40260,40261,40262,40263,40264,40265,40266,40267,40268,40269,40270,40271,40272,40273,40274,40275,40276,40277,40278,40279,40280,40281,40282,40283,40284,40285,40286,40287,40288,40289,40290,40291,40292,40293,40294,40295,40296,40297,40298,40299,40300,40301,40302,40303,40304,40305,40306,40307,40308,40309,40310,40311,40312,40313,40314,40315,40316,40317,40318,40319,40320,40321,40322,40323,40324,40325,40326,40327,40328,40329,40330,40331,40332,40333,40334,40335,40336,40337,40338,40339,40340,40341,40342,40343,40344,40345,40346,40347,40348,40349,40350,40351,40352,40353,40354,58002,58003,58004,58005,58006,58007,58008,58009,58010,58011,58012,58013,58014,58015,58016,58017,58018,58019,58020,58021,58022,58023,58024,58025,58026,58027,58028,58029,58030,58031,58032,58033,58034,58035,58036,58037,58038,58039,58040,58041,58042,58043,58044,58045,58046,58047,58048,58049,58050,58051,58052,58053,58054,58055,58056,58057,58058,58059,58060,58061,58062,58063,58064,58065,58066,58067,58068,58069,58070,58071,58072,58073,58074,58075,58076,58077,58078,58079,58080,58081,58082,58083,58084,58085,58086,58087,58088,58089,58090,58091,58092,58093,58094,58095,40355,40356,40357,40358,40359,40360,40361,40362,40363,40364,40365,40366,40367,40368,40369,40370,40371,40372,40373,40374,40375,40376,40377,40378,40379,40380,40381,40382,40383,40384,40385,40386,40387,40388,40389,40390,40391,40392,40393,40394,40395,40396,40397,40398,40399,40400,40401,40402,40403,40404,40405,40406,40407,40408,40409,40410,40411,40412,40413,40414,40415,40416,40417,40418,40419,40420,40421,40422,40423,40424,40425,40426,40427,40428,40429,40430,40431,40432,40433,40434,40435,40436,40437,40438,40439,40440,40441,40442,40443,40444,40445,40446,40447,40448,40449,40450,58096,58097,58098,58099,58100,58101,58102,58103,58104,58105,58106,58107,58108,58109,58110,58111,58112,58113,58114,58115,58116,58117,58118,58119,58120,58121,58122,58123,58124,58125,58126,58127,58128,58129,58130,58131,58132,58133,58134,58135,58136,58137,58138,58139,58140,58141,58142,58143,58144,58145,58146,58147,58148,58149,58150,58151,58152,58153,58154,58155,58156,58157,58158,58159,58160,58161,58162,58163,58164,58165,58166,58167,58168,58169,58170,58171,58172,58173,58174,58175,58176,58177,58178,58179,58180,58181,58182,58183,58184,58185,58186,58187,58188,58189,40451,40452,40453,40454,40455,40456,40457,40458,40459,40460,40461,40462,40463,40464,40465,40466,40467,40468,40469,40470,40471,40472,40473,40474,40475,40476,40477,40478,40484,40487,40494,40496,40500,40507,40508,40512,40525,40528,40530,40531,40532,40534,40537,40541,40543,40544,40545,40546,40549,40558,40559,40562,40564,40565,40566,40567,40568,40569,40570,40571,40572,40573,40576,40577,40579,40580,40581,40582,40585,40586,40588,40589,40590,40591,40592,40593,40596,40597,40598,40599,40600,40601,40602,40603,40604,40606,40608,40609,40610,40611,40612,40613,40615,40616,40617,40618,58190,58191,58192,58193,58194,58195,58196,58197,58198,58199,58200,58201,58202,58203,58204,58205,58206,58207,58208,58209,58210,58211,58212,58213,58214,58215,58216,58217,58218,58219,58220,58221,58222,58223,58224,58225,58226,58227,58228,58229,58230,58231,58232,58233,58234,58235,58236,58237,58238,58239,58240,58241,58242,58243,58244,58245,58246,58247,58248,58249,58250,58251,58252,58253,58254,58255,58256,58257,58258,58259,58260,58261,58262,58263,58264,58265,58266,58267,58268,58269,58270,58271,58272,58273,58274,58275,58276,58277,58278,58279,58280,58281,58282,58283,40619,40620,40621,40622,40623,40624,40625,40626,40627,40629,40630,40631,40633,40634,40636,40639,40640,40641,40642,40643,40645,40646,40647,40648,40650,40651,40652,40656,40658,40659,40661,40662,40663,40665,40666,40670,40673,40675,40676,40678,40680,40683,40684,40685,40686,40688,40689,40690,40691,40692,40693,40694,40695,40696,40698,40701,40703,40704,40705,40706,40707,40708,40709,40710,40711,40712,40713,40714,40716,40719,40721,40722,40724,40725,40726,40728,40730,40731,40732,40733,40734,40735,40737,40739,40740,40741,40742,40743,40744,40745,40746,40747,40749,40750,40752,40753,58284,58285,58286,58287,58288,58289,58290,58291,58292,58293,58294,58295,58296,58297,58298,58299,58300,58301,58302,58303,58304,58305,58306,58307,58308,58309,58310,58311,58312,58313,58314,58315,58316,58317,58318,58319,58320,58321,58322,58323,58324,58325,58326,58327,58328,58329,58330,58331,58332,58333,58334,58335,58336,58337,58338,58339,58340,58341,58342,58343,58344,58345,58346,58347,58348,58349,58350,58351,58352,58353,58354,58355,58356,58357,58358,58359,58360,58361,58362,58363,58364,58365,58366,58367,58368,58369,58370,58371,58372,58373,58374,58375,58376,58377,40754,40755,40756,40757,40758,40760,40762,40764,40767,40768,40769,40770,40771,40773,40774,40775,40776,40777,40778,40779,40780,40781,40782,40783,40786,40787,40788,40789,40790,40791,40792,40793,40794,40795,40796,40797,40798,40799,40800,40801,40802,40803,40804,40805,40806,40807,40808,40809,40810,40811,40812,40813,40814,40815,40816,40817,40818,40819,40820,40821,40822,40823,40824,40825,40826,40827,40828,40829,40830,40833,40834,40845,40846,40847,40848,40849,40850,40851,40852,40853,40854,40855,40856,40860,40861,40862,40865,40866,40867,40868,40869,63788,63865,63893,63975,63985,58378,58379,58380,58381,58382,58383,58384,58385,58386,58387,58388,58389,58390,58391,58392,58393,58394,58395,58396,58397,58398,58399,58400,58401,58402,58403,58404,58405,58406,58407,58408,58409,58410,58411,58412,58413,58414,58415,58416,58417,58418,58419,58420,58421,58422,58423,58424,58425,58426,58427,58428,58429,58430,58431,58432,58433,58434,58435,58436,58437,58438,58439,58440,58441,58442,58443,58444,58445,58446,58447,58448,58449,58450,58451,58452,58453,58454,58455,58456,58457,58458,58459,58460,58461,58462,58463,58464,58465,58466,58467,58468,58469,58470,58471,64012,64013,64014,64015,64017,64019,64020,64024,64031,64032,64033,64035,64036,64039,64040,64041,11905,59414,59415,59416,11908,13427,13383,11912,11915,59422,13726,13850,13838,11916,11927,14702,14616,59430,14799,14815,14963,14800,59435,59436,15182,15470,15584,11943,59441,59442,11946,16470,16735,11950,17207,11955,11958,11959,59451,17329,17324,11963,17373,17622,18017,17996,59459,18211,18217,18300,18317,11978,18759,18810,18813,18818,18819,18821,18822,18847,18843,18871,18870,59476,59477,19619,19615,19616,19617,19575,19618,19731,19732,19733,19734,19735,19736,19737,19886,59492,58472,58473,58474,58475,58476,58477,58478,58479,58480,58481,58482,58483,58484,58485,58486,58487,58488,58489,58490,58491,58492,58493,58494,58495,58496,58497,58498,58499,58500,58501,58502,58503,58504,58505,58506,58507,58508,58509,58510,58511,58512,58513,58514,58515,58516,58517,58518,58519,58520,58521,58522,58523,58524,58525,58526,58527,58528,58529,58530,58531,58532,58533,58534,58535,58536,58537,58538,58539,58540,58541,58542,58543,58544,58545,58546,58547,58548,58549,58550,58551,58552,58553,58554,58555,58556,58557,58558,58559,58560,58561,58562,58563,58564,58565],
+ "gb18030-ranges":[[0,128],[36,165],[38,169],[45,178],[50,184],[81,216],[89,226],[95,235],[96,238],[100,244],[103,248],[104,251],[105,253],[109,258],[126,276],[133,284],[148,300],[172,325],[175,329],[179,334],[208,364],[306,463],[307,465],[308,467],[309,469],[310,471],[311,473],[312,475],[313,477],[341,506],[428,594],[443,610],[544,712],[545,716],[558,730],[741,930],[742,938],[749,962],[750,970],[805,1026],[819,1104],[820,1106],[7922,8209],[7924,8215],[7925,8218],[7927,8222],[7934,8231],[7943,8241],[7944,8244],[7945,8246],[7950,8252],[8062,8365],[8148,8452],[8149,8454],[8152,8458],[8164,8471],[8174,8482],[8236,8556],[8240,8570],[8262,8596],[8264,8602],[8374,8713],[8380,8720],[8381,8722],[8384,8726],[8388,8731],[8390,8737],[8392,8740],[8393,8742],[8394,8748],[8396,8751],[8401,8760],[8406,8766],[8416,8777],[8419,8781],[8424,8787],[8437,8802],[8439,8808],[8445,8816],[8482,8854],[8485,8858],[8496,8870],[8521,8896],[8603,8979],[8936,9322],[8946,9372],[9046,9548],[9050,9588],[9063,9616],[9066,9622],[9076,9634],[9092,9652],[9100,9662],[9108,9672],[9111,9676],[9113,9680],[9131,9702],[9162,9735],[9164,9738],[9218,9793],[9219,9795],[11329,11906],[11331,11909],[11334,11913],[11336,11917],[11346,11928],[11361,11944],[11363,11947],[11366,11951],[11370,11956],[11372,11960],[11375,11964],[11389,11979],[11682,12284],[11686,12292],[11687,12312],[11692,12319],[11694,12330],[11714,12351],[11716,12436],[11723,12447],[11725,12535],[11730,12543],[11736,12586],[11982,12842],[11989,12850],[12102,12964],[12336,13200],[12348,13215],[12350,13218],[12384,13253],[12393,13263],[12395,13267],[12397,13270],[12510,13384],[12553,13428],[12851,13727],[12962,13839],[12973,13851],[13738,14617],[13823,14703],[13919,14801],[13933,14816],[14080,14964],[14298,15183],[14585,15471],[14698,15585],[15583,16471],[15847,16736],[16318,17208],[16434,17325],[16438,17330],[16481,17374],[16729,17623],[17102,17997],[17122,18018],[17315,18212],[17320,18218],[17402,18301],[17418,18318],[17859,18760],[17909,18811],[17911,18814],[17915,18820],[17916,18823],[17936,18844],[17939,18848],[17961,18872],[18664,19576],[18703,19620],[18814,19738],[18962,19887],[19043,40870],[33469,59244],[33470,59336],[33471,59367],[33484,59413],[33485,59417],[33490,59423],[33497,59431],[33501,59437],[33505,59443],[33513,59452],[33520,59460],[33536,59478],[33550,59493],[37845,63789],[37921,63866],[37948,63894],[38029,63976],[38038,63986],[38064,64016],[38065,64018],[38066,64021],[38069,64025],[38075,64034],[38076,64037],[38078,64042],[39108,65074],[39109,65093],[39113,65107],[39114,65112],[39115,65127],[39116,65132],[39265,65375],[39394,65510],[189000,65536]],
+ "jis0208":[12288,12289,12290,65292,65294,12539,65306,65307,65311,65281,12443,12444,180,65344,168,65342,65507,65343,12541,12542,12445,12446,12291,20189,12293,12294,12295,12540,8213,8208,65295,65340,65374,8741,65372,8230,8229,8216,8217,8220,8221,65288,65289,12308,12309,65339,65341,65371,65373,12296,12297,12298,12299,12300,12301,12302,12303,12304,12305,65291,65293,177,215,247,65309,8800,65308,65310,8806,8807,8734,8756,9794,9792,176,8242,8243,8451,65509,65284,65504,65505,65285,65283,65286,65290,65312,167,9734,9733,9675,9679,9678,9671,9670,9633,9632,9651,9650,9661,9660,8251,12306,8594,8592,8593,8595,12307,null,null,null,null,null,null,null,null,null,null,null,8712,8715,8838,8839,8834,8835,8746,8745,null,null,null,null,null,null,null,null,8743,8744,65506,8658,8660,8704,8707,null,null,null,null,null,null,null,null,null,null,null,8736,8869,8978,8706,8711,8801,8786,8810,8811,8730,8765,8733,8757,8747,8748,null,null,null,null,null,null,null,8491,8240,9839,9837,9834,8224,8225,182,null,null,null,null,9711,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,65296,65297,65298,65299,65300,65301,65302,65303,65304,65305,null,null,null,null,null,null,null,65313,65314,65315,65316,65317,65318,65319,65320,65321,65322,65323,65324,65325,65326,65327,65328,65329,65330,65331,65332,65333,65334,65335,65336,65337,65338,null,null,null,null,null,null,65345,65346,65347,65348,65349,65350,65351,65352,65353,65354,65355,65356,65357,65358,65359,65360,65361,65362,65363,65364,65365,65366,65367,65368,65369,65370,null,null,null,null,12353,12354,12355,12356,12357,12358,12359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,12371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,12383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,12395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,12407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,12419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,12431,12432,12433,12434,12435,null,null,null,null,null,null,null,null,null,null,null,12449,12450,12451,12452,12453,12454,12455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,12467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,12479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,12491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,12503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,12515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,12527,12528,12529,12530,12531,12532,12533,12534,null,null,null,null,null,null,null,null,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,932,933,934,935,936,937,null,null,null,null,null,null,null,null,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,963,964,965,966,967,968,969,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1040,1041,1042,1043,1044,1045,1025,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1072,1073,1074,1075,1076,1077,1105,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,null,null,null,null,null,null,null,null,null,null,null,null,null,9472,9474,9484,9488,9496,9492,9500,9516,9508,9524,9532,9473,9475,9487,9491,9499,9495,9507,9523,9515,9531,9547,9504,9519,9512,9527,9535,9501,9520,9509,9528,9538,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9322,9323,9324,9325,9326,9327,9328,9329,9330,9331,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,null,13129,13076,13090,13133,13080,13095,13059,13110,13137,13143,13069,13094,13091,13099,13130,13115,13212,13213,13214,13198,13199,13252,13217,null,null,null,null,null,null,null,null,13179,12317,12319,8470,13261,8481,12964,12965,12966,12967,12968,12849,12850,12857,13182,13181,13180,8786,8801,8747,8750,8721,8730,8869,8736,8735,8895,8757,8745,8746,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,20124,21782,23043,38463,21696,24859,25384,23030,36898,33909,33564,31312,24746,25569,28197,26093,33894,33446,39925,26771,22311,26017,25201,23451,22992,34427,39156,32098,32190,39822,25110,31903,34999,23433,24245,25353,26263,26696,38343,38797,26447,20197,20234,20301,20381,20553,22258,22839,22996,23041,23561,24799,24847,24944,26131,26885,28858,30031,30064,31227,32173,32239,32963,33806,34915,35586,36949,36986,21307,20117,20133,22495,32946,37057,30959,19968,22769,28322,36920,31282,33576,33419,39983,20801,21360,21693,21729,22240,23035,24341,39154,28139,32996,34093,38498,38512,38560,38907,21515,21491,23431,28879,32701,36802,38632,21359,40284,31418,19985,30867,33276,28198,22040,21764,27421,34074,39995,23013,21417,28006,29916,38287,22082,20113,36939,38642,33615,39180,21473,21942,23344,24433,26144,26355,26628,27704,27891,27945,29787,30408,31310,38964,33521,34907,35424,37613,28082,30123,30410,39365,24742,35585,36234,38322,27022,21421,20870,22290,22576,22852,23476,24310,24616,25513,25588,27839,28436,28814,28948,29017,29141,29503,32257,33398,33489,34199,36960,37467,40219,22633,26044,27738,29989,20985,22830,22885,24448,24540,25276,26106,27178,27431,27572,29579,32705,35158,40236,40206,40644,23713,27798,33659,20740,23627,25014,33222,26742,29281,20057,20474,21368,24681,28201,31311,38899,19979,21270,20206,20309,20285,20385,20339,21152,21487,22025,22799,23233,23478,23521,31185,26247,26524,26550,27468,27827,28779,29634,31117,31166,31292,31623,33457,33499,33540,33655,33775,33747,34662,35506,22057,36008,36838,36942,38686,34442,20420,23784,25105,29273,30011,33253,33469,34558,36032,38597,39187,39381,20171,20250,35299,22238,22602,22730,24315,24555,24618,24724,24674,25040,25106,25296,25913,39745,26214,26800,28023,28784,30028,30342,32117,33445,34809,38283,38542,35997,20977,21182,22806,21683,23475,23830,24936,27010,28079,30861,33995,34903,35442,37799,39608,28012,39336,34521,22435,26623,34510,37390,21123,22151,21508,24275,25313,25785,26684,26680,27579,29554,30906,31339,35226,35282,36203,36611,37101,38307,38548,38761,23398,23731,27005,38989,38990,25499,31520,27179,27263,26806,39949,28511,21106,21917,24688,25324,27963,28167,28369,33883,35088,36676,19988,39993,21494,26907,27194,38788,26666,20828,31427,33970,37340,37772,22107,40232,26658,33541,33841,31909,21000,33477,29926,20094,20355,20896,23506,21002,21208,21223,24059,21914,22570,23014,23436,23448,23515,24178,24185,24739,24863,24931,25022,25563,25954,26577,26707,26874,27454,27475,27735,28450,28567,28485,29872,29976,30435,30475,31487,31649,31777,32233,32566,32752,32925,33382,33694,35251,35532,36011,36996,37969,38291,38289,38306,38501,38867,39208,33304,20024,21547,23736,24012,29609,30284,30524,23721,32747,36107,38593,38929,38996,39000,20225,20238,21361,21916,22120,22522,22855,23305,23492,23696,24076,24190,24524,25582,26426,26071,26082,26399,26827,26820,27231,24112,27589,27671,27773,30079,31048,23395,31232,32000,24509,35215,35352,36020,36215,36556,36637,39138,39438,39740,20096,20605,20736,22931,23452,25135,25216,25836,27450,29344,30097,31047,32681,34811,35516,35696,25516,33738,38816,21513,21507,21931,26708,27224,35440,30759,26485,40653,21364,23458,33050,34384,36870,19992,20037,20167,20241,21450,21560,23470,24339,24613,25937,26429,27714,27762,27875,28792,29699,31350,31406,31496,32026,31998,32102,26087,29275,21435,23621,24040,25298,25312,25369,28192,34394,35377,36317,37624,28417,31142,39770,20136,20139,20140,20379,20384,20689,20807,31478,20849,20982,21332,21281,21375,21483,21932,22659,23777,24375,24394,24623,24656,24685,25375,25945,27211,27841,29378,29421,30703,33016,33029,33288,34126,37111,37857,38911,39255,39514,20208,20957,23597,26241,26989,23616,26354,26997,29577,26704,31873,20677,21220,22343,24062,37670,26020,27427,27453,29748,31105,31165,31563,32202,33465,33740,34943,35167,35641,36817,37329,21535,37504,20061,20534,21477,21306,29399,29590,30697,33510,36527,39366,39368,39378,20855,24858,34398,21936,31354,20598,23507,36935,38533,20018,27355,37351,23633,23624,25496,31391,27795,38772,36705,31402,29066,38536,31874,26647,32368,26705,37740,21234,21531,34219,35347,32676,36557,37089,21350,34952,31041,20418,20670,21009,20804,21843,22317,29674,22411,22865,24418,24452,24693,24950,24935,25001,25522,25658,25964,26223,26690,28179,30054,31293,31995,32076,32153,32331,32619,33550,33610,34509,35336,35427,35686,36605,38938,40335,33464,36814,39912,21127,25119,25731,28608,38553,26689,20625,27424,27770,28500,31348,32080,34880,35363,26376,20214,20537,20518,20581,20860,21048,21091,21927,22287,22533,23244,24314,25010,25080,25331,25458,26908,27177,29309,29356,29486,30740,30831,32121,30476,32937,35211,35609,36066,36562,36963,37749,38522,38997,39443,40568,20803,21407,21427,24187,24358,28187,28304,29572,29694,32067,33335,35328,35578,38480,20046,20491,21476,21628,22266,22993,23396,24049,24235,24359,25144,25925,26543,28246,29392,31946,34996,32929,32993,33776,34382,35463,36328,37431,38599,39015,40723,20116,20114,20237,21320,21577,21566,23087,24460,24481,24735,26791,27278,29786,30849,35486,35492,35703,37264,20062,39881,20132,20348,20399,20505,20502,20809,20844,21151,21177,21246,21402,21475,21521,21518,21897,22353,22434,22909,23380,23389,23439,24037,24039,24055,24184,24195,24218,24247,24344,24658,24908,25239,25304,25511,25915,26114,26179,26356,26477,26657,26775,27083,27743,27946,28009,28207,28317,30002,30343,30828,31295,31968,32005,32024,32094,32177,32789,32771,32943,32945,33108,33167,33322,33618,34892,34913,35611,36002,36092,37066,37237,37489,30783,37628,38308,38477,38917,39321,39640,40251,21083,21163,21495,21512,22741,25335,28640,35946,36703,40633,20811,21051,21578,22269,31296,37239,40288,40658,29508,28425,33136,29969,24573,24794,39592,29403,36796,27492,38915,20170,22256,22372,22718,23130,24680,25031,26127,26118,26681,26801,28151,30165,32058,33390,39746,20123,20304,21449,21766,23919,24038,24046,26619,27801,29811,30722,35408,37782,35039,22352,24231,25387,20661,20652,20877,26368,21705,22622,22971,23472,24425,25165,25505,26685,27507,28168,28797,37319,29312,30741,30758,31085,25998,32048,33756,35009,36617,38555,21092,22312,26448,32618,36001,20916,22338,38442,22586,27018,32948,21682,23822,22524,30869,40442,20316,21066,21643,25662,26152,26388,26613,31364,31574,32034,37679,26716,39853,31545,21273,20874,21047,23519,25334,25774,25830,26413,27578,34217,38609,30352,39894,25420,37638,39851,30399,26194,19977,20632,21442,23665,24808,25746,25955,26719,29158,29642,29987,31639,32386,34453,35715,36059,37240,39184,26028,26283,27531,20181,20180,20282,20351,21050,21496,21490,21987,22235,22763,22987,22985,23039,23376,23629,24066,24107,24535,24605,25351,25903,23388,26031,26045,26088,26525,27490,27515,27663,29509,31049,31169,31992,32025,32043,32930,33026,33267,35222,35422,35433,35430,35468,35566,36039,36060,38604,39164,27503,20107,20284,20365,20816,23383,23546,24904,25345,26178,27425,28363,27835,29246,29885,30164,30913,31034,32780,32819,33258,33940,36766,27728,40575,24335,35672,40235,31482,36600,23437,38635,19971,21489,22519,22833,23241,23460,24713,28287,28422,30142,36074,23455,34048,31712,20594,26612,33437,23649,34122,32286,33294,20889,23556,25448,36198,26012,29038,31038,32023,32773,35613,36554,36974,34503,37034,20511,21242,23610,26451,28796,29237,37196,37320,37675,33509,23490,24369,24825,20027,21462,23432,25163,26417,27530,29417,29664,31278,33131,36259,37202,39318,20754,21463,21610,23551,25480,27193,32172,38656,22234,21454,21608,23447,23601,24030,20462,24833,25342,27954,31168,31179,32066,32333,32722,33261,33311,33936,34886,35186,35728,36468,36655,36913,37195,37228,38598,37276,20160,20303,20805,21313,24467,25102,26580,27713,28171,29539,32294,37325,37507,21460,22809,23487,28113,31069,32302,31899,22654,29087,20986,34899,36848,20426,23803,26149,30636,31459,33308,39423,20934,24490,26092,26991,27529,28147,28310,28516,30462,32020,24033,36981,37255,38918,20966,21021,25152,26257,26329,28186,24246,32210,32626,26360,34223,34295,35576,21161,21465,22899,24207,24464,24661,37604,38500,20663,20767,21213,21280,21319,21484,21736,21830,21809,22039,22888,22974,23100,23477,23558,23567,23569,23578,24196,24202,24288,24432,25215,25220,25307,25484,25463,26119,26124,26157,26230,26494,26786,27167,27189,27836,28040,28169,28248,28988,28966,29031,30151,30465,30813,30977,31077,31216,31456,31505,31911,32057,32918,33750,33931,34121,34909,35059,35359,35388,35412,35443,35937,36062,37284,37478,37758,37912,38556,38808,19978,19976,19998,20055,20887,21104,22478,22580,22732,23330,24120,24773,25854,26465,26454,27972,29366,30067,31331,33976,35698,37304,37664,22065,22516,39166,25325,26893,27542,29165,32340,32887,33394,35302,39135,34645,36785,23611,20280,20449,20405,21767,23072,23517,23529,24515,24910,25391,26032,26187,26862,27035,28024,28145,30003,30137,30495,31070,31206,32051,33251,33455,34218,35242,35386,36523,36763,36914,37341,38663,20154,20161,20995,22645,22764,23563,29978,23613,33102,35338,36805,38499,38765,31525,35535,38920,37218,22259,21416,36887,21561,22402,24101,25512,27700,28810,30561,31883,32736,34928,36930,37204,37648,37656,38543,29790,39620,23815,23913,25968,26530,36264,38619,25454,26441,26905,33733,38935,38592,35070,28548,25722,23544,19990,28716,30045,26159,20932,21046,21218,22995,24449,24615,25104,25919,25972,26143,26228,26866,26646,27491,28165,29298,29983,30427,31934,32854,22768,35069,35199,35488,35475,35531,36893,37266,38738,38745,25993,31246,33030,38587,24109,24796,25114,26021,26132,26512,30707,31309,31821,32318,33034,36012,36196,36321,36447,30889,20999,25305,25509,25666,25240,35373,31363,31680,35500,38634,32118,33292,34633,20185,20808,21315,21344,23459,23554,23574,24029,25126,25159,25776,26643,26676,27849,27973,27927,26579,28508,29006,29053,26059,31359,31661,32218,32330,32680,33146,33307,33337,34214,35438,36046,36341,36984,36983,37549,37521,38275,39854,21069,21892,28472,28982,20840,31109,32341,33203,31950,22092,22609,23720,25514,26366,26365,26970,29401,30095,30094,30990,31062,31199,31895,32032,32068,34311,35380,38459,36961,40736,20711,21109,21452,21474,20489,21930,22766,22863,29245,23435,23652,21277,24803,24819,25436,25475,25407,25531,25805,26089,26361,24035,27085,27133,28437,29157,20105,30185,30456,31379,31967,32207,32156,32865,33609,33624,33900,33980,34299,35013,36208,36865,36973,37783,38684,39442,20687,22679,24974,33235,34101,36104,36896,20419,20596,21063,21363,24687,25417,26463,28204,36275,36895,20439,23646,36042,26063,32154,21330,34966,20854,25539,23384,23403,23562,25613,26449,36956,20182,22810,22826,27760,35409,21822,22549,22949,24816,25171,26561,33333,26965,38464,39364,39464,20307,22534,23550,32784,23729,24111,24453,24608,24907,25140,26367,27888,28382,32974,33151,33492,34955,36024,36864,36910,38538,40667,39899,20195,21488,22823,31532,37261,38988,40441,28381,28711,21331,21828,23429,25176,25246,25299,27810,28655,29730,35351,37944,28609,35582,33592,20967,34552,21482,21481,20294,36948,36784,22890,33073,24061,31466,36799,26842,35895,29432,40008,27197,35504,20025,21336,22022,22374,25285,25506,26086,27470,28129,28251,28845,30701,31471,31658,32187,32829,32966,34507,35477,37723,22243,22727,24382,26029,26262,27264,27573,30007,35527,20516,30693,22320,24347,24677,26234,27744,30196,31258,32622,33268,34584,36933,39347,31689,30044,31481,31569,33988,36880,31209,31378,33590,23265,30528,20013,20210,23449,24544,25277,26172,26609,27880,34411,34935,35387,37198,37619,39376,27159,28710,29482,33511,33879,36015,19969,20806,20939,21899,23541,24086,24115,24193,24340,24373,24427,24500,25074,25361,26274,26397,28526,29266,30010,30522,32884,33081,33144,34678,35519,35548,36229,36339,37530,38263,38914,40165,21189,25431,30452,26389,27784,29645,36035,37806,38515,27941,22684,26894,27084,36861,37786,30171,36890,22618,26626,25524,27131,20291,28460,26584,36795,34086,32180,37716,26943,28528,22378,22775,23340,32044,29226,21514,37347,40372,20141,20302,20572,20597,21059,35998,21576,22564,23450,24093,24213,24237,24311,24351,24716,25269,25402,25552,26799,27712,30855,31118,31243,32224,33351,35330,35558,36420,36883,37048,37165,37336,40718,27877,25688,25826,25973,28404,30340,31515,36969,37841,28346,21746,24505,25764,36685,36845,37444,20856,22635,22825,23637,24215,28155,32399,29980,36028,36578,39003,28857,20253,27583,28593,30000,38651,20814,21520,22581,22615,22956,23648,24466,26007,26460,28193,30331,33759,36077,36884,37117,37709,30757,30778,21162,24230,22303,22900,24594,20498,20826,20908,20941,20992,21776,22612,22616,22871,23445,23798,23947,24764,25237,25645,26481,26691,26812,26847,30423,28120,28271,28059,28783,29128,24403,30168,31095,31561,31572,31570,31958,32113,21040,33891,34153,34276,35342,35588,35910,36367,36867,36879,37913,38518,38957,39472,38360,20685,21205,21516,22530,23566,24999,25758,27934,30643,31461,33012,33796,36947,37509,23776,40199,21311,24471,24499,28060,29305,30563,31167,31716,27602,29420,35501,26627,27233,20984,31361,26932,23626,40182,33515,23493,37193,28702,22136,23663,24775,25958,27788,35930,36929,38931,21585,26311,37389,22856,37027,20869,20045,20970,34201,35598,28760,25466,37707,26978,39348,32260,30071,21335,26976,36575,38627,27741,20108,23612,24336,36841,21250,36049,32905,34425,24319,26085,20083,20837,22914,23615,38894,20219,22922,24525,35469,28641,31152,31074,23527,33905,29483,29105,24180,24565,25467,25754,29123,31896,20035,24316,20043,22492,22178,24745,28611,32013,33021,33075,33215,36786,35223,34468,24052,25226,25773,35207,26487,27874,27966,29750,30772,23110,32629,33453,39340,20467,24259,25309,25490,25943,26479,30403,29260,32972,32954,36649,37197,20493,22521,23186,26757,26995,29028,29437,36023,22770,36064,38506,36889,34687,31204,30695,33833,20271,21093,21338,25293,26575,27850,30333,31636,31893,33334,34180,36843,26333,28448,29190,32283,33707,39361,40614,20989,31665,30834,31672,32903,31560,27368,24161,32908,30033,30048,20843,37474,28300,30330,37271,39658,20240,32624,25244,31567,38309,40169,22138,22617,34532,38588,20276,21028,21322,21453,21467,24070,25644,26001,26495,27710,27726,29256,29359,29677,30036,32321,33324,34281,36009,31684,37318,29033,38930,39151,25405,26217,30058,30436,30928,34115,34542,21290,21329,21542,22915,24199,24444,24754,25161,25209,25259,26000,27604,27852,30130,30382,30865,31192,32203,32631,32933,34987,35513,36027,36991,38750,39131,27147,31800,20633,23614,24494,26503,27608,29749,30473,32654,40763,26570,31255,21305,30091,39661,24422,33181,33777,32920,24380,24517,30050,31558,36924,26727,23019,23195,32016,30334,35628,20469,24426,27161,27703,28418,29922,31080,34920,35413,35961,24287,25551,30149,31186,33495,37672,37618,33948,34541,39981,21697,24428,25996,27996,28693,36007,36051,38971,25935,29942,19981,20184,22496,22827,23142,23500,20904,24067,24220,24598,25206,25975,26023,26222,28014,29238,31526,33104,33178,33433,35676,36000,36070,36212,38428,38468,20398,25771,27494,33310,33889,34154,37096,23553,26963,39080,33914,34135,20239,21103,24489,24133,26381,31119,33145,35079,35206,28149,24343,25173,27832,20175,29289,39826,20998,21563,22132,22707,24996,25198,28954,22894,31881,31966,32027,38640,25991,32862,19993,20341,20853,22592,24163,24179,24330,26564,20006,34109,38281,38491,31859,38913,20731,22721,30294,30887,21029,30629,34065,31622,20559,22793,29255,31687,32232,36794,36820,36941,20415,21193,23081,24321,38829,20445,33303,37610,22275,25429,27497,29995,35036,36628,31298,21215,22675,24917,25098,26286,27597,31807,33769,20515,20472,21253,21574,22577,22857,23453,23792,23791,23849,24214,25265,25447,25918,26041,26379,27861,27873,28921,30770,32299,32990,33459,33804,34028,34562,35090,35370,35914,37030,37586,39165,40179,40300,20047,20129,20621,21078,22346,22952,24125,24536,24537,25151,26292,26395,26576,26834,20882,32033,32938,33192,35584,35980,36031,37502,38450,21536,38956,21271,20693,21340,22696,25778,26420,29287,30566,31302,37350,21187,27809,27526,22528,24140,22868,26412,32763,20961,30406,25705,30952,39764,40635,22475,22969,26151,26522,27598,21737,27097,24149,33180,26517,39850,26622,40018,26717,20134,20451,21448,25273,26411,27819,36804,20397,32365,40639,19975,24930,28288,28459,34067,21619,26410,39749,24051,31637,23724,23494,34588,28234,34001,31252,33032,22937,31885,27665,30496,21209,22818,28961,29279,30683,38695,40289,26891,23167,23064,20901,21517,21629,26126,30431,36855,37528,40180,23018,29277,28357,20813,26825,32191,32236,38754,40634,25720,27169,33538,22916,23391,27611,29467,30450,32178,32791,33945,20786,26408,40665,30446,26466,21247,39173,23588,25147,31870,36016,21839,24758,32011,38272,21249,20063,20918,22812,29242,32822,37326,24357,30690,21380,24441,32004,34220,35379,36493,38742,26611,34222,37971,24841,24840,27833,30290,35565,36664,21807,20305,20778,21191,21451,23461,24189,24736,24962,25558,26377,26586,28263,28044,29494,29495,30001,31056,35029,35480,36938,37009,37109,38596,34701,22805,20104,20313,19982,35465,36671,38928,20653,24188,22934,23481,24248,25562,25594,25793,26332,26954,27096,27915,28342,29076,29992,31407,32650,32768,33865,33993,35201,35617,36362,36965,38525,39178,24958,25233,27442,27779,28020,32716,32764,28096,32645,34746,35064,26469,33713,38972,38647,27931,32097,33853,37226,20081,21365,23888,27396,28651,34253,34349,35239,21033,21519,23653,26446,26792,29702,29827,30178,35023,35041,37324,38626,38520,24459,29575,31435,33870,25504,30053,21129,27969,28316,29705,30041,30827,31890,38534,31452,40845,20406,24942,26053,34396,20102,20142,20698,20001,20940,23534,26009,26753,28092,29471,30274,30637,31260,31975,33391,35538,36988,37327,38517,38936,21147,32209,20523,21400,26519,28107,29136,29747,33256,36650,38563,40023,40607,29792,22593,28057,32047,39006,20196,20278,20363,20919,21169,23994,24604,29618,31036,33491,37428,38583,38646,38666,40599,40802,26278,27508,21015,21155,28872,35010,24265,24651,24976,28451,29001,31806,32244,32879,34030,36899,37676,21570,39791,27347,28809,36034,36335,38706,21172,23105,24266,24324,26391,27004,27028,28010,28431,29282,29436,31725,32769,32894,34635,37070,20845,40595,31108,32907,37682,35542,20525,21644,35441,27498,36036,33031,24785,26528,40434,20121,20120,39952,35435,34241,34152,26880,28286,30871,33109,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,24332,19984,19989,20010,20017,20022,20028,20031,20034,20054,20056,20098,20101,35947,20106,33298,24333,20110,20126,20127,20128,20130,20144,20147,20150,20174,20173,20164,20166,20162,20183,20190,20205,20191,20215,20233,20314,20272,20315,20317,20311,20295,20342,20360,20367,20376,20347,20329,20336,20369,20335,20358,20374,20760,20436,20447,20430,20440,20443,20433,20442,20432,20452,20453,20506,20520,20500,20522,20517,20485,20252,20470,20513,20521,20524,20478,20463,20497,20486,20547,20551,26371,20565,20560,20552,20570,20566,20588,20600,20608,20634,20613,20660,20658,20681,20682,20659,20674,20694,20702,20709,20717,20707,20718,20729,20725,20745,20737,20738,20758,20757,20756,20762,20769,20794,20791,20796,20795,20799,20800,20818,20812,20820,20834,31480,20841,20842,20846,20864,20866,22232,20876,20873,20879,20881,20883,20885,20886,20900,20902,20898,20905,20906,20907,20915,20913,20914,20912,20917,20925,20933,20937,20955,20960,34389,20969,20973,20976,20981,20990,20996,21003,21012,21006,21031,21034,21038,21043,21049,21071,21060,21067,21068,21086,21076,21098,21108,21097,21107,21119,21117,21133,21140,21138,21105,21128,21137,36776,36775,21164,21165,21180,21173,21185,21197,21207,21214,21219,21222,39149,21216,21235,21237,21240,21241,21254,21256,30008,21261,21264,21263,21269,21274,21283,21295,21297,21299,21304,21312,21318,21317,19991,21321,21325,20950,21342,21353,21358,22808,21371,21367,21378,21398,21408,21414,21413,21422,21424,21430,21443,31762,38617,21471,26364,29166,21486,21480,21485,21498,21505,21565,21568,21548,21549,21564,21550,21558,21545,21533,21582,21647,21621,21646,21599,21617,21623,21616,21650,21627,21632,21622,21636,21648,21638,21703,21666,21688,21669,21676,21700,21704,21672,21675,21698,21668,21694,21692,21720,21733,21734,21775,21780,21757,21742,21741,21754,21730,21817,21824,21859,21836,21806,21852,21829,21846,21847,21816,21811,21853,21913,21888,21679,21898,21919,21883,21886,21912,21918,21934,21884,21891,21929,21895,21928,21978,21957,21983,21956,21980,21988,21972,22036,22007,22038,22014,22013,22043,22009,22094,22096,29151,22068,22070,22066,22072,22123,22116,22063,22124,22122,22150,22144,22154,22176,22164,22159,22181,22190,22198,22196,22210,22204,22209,22211,22208,22216,22222,22225,22227,22231,22254,22265,22272,22271,22276,22281,22280,22283,22285,22291,22296,22294,21959,22300,22310,22327,22328,22350,22331,22336,22351,22377,22464,22408,22369,22399,22409,22419,22432,22451,22436,22442,22448,22467,22470,22484,22482,22483,22538,22486,22499,22539,22553,22557,22642,22561,22626,22603,22640,27584,22610,22589,22649,22661,22713,22687,22699,22714,22750,22715,22712,22702,22725,22739,22737,22743,22745,22744,22757,22748,22756,22751,22767,22778,22777,22779,22780,22781,22786,22794,22800,22811,26790,22821,22828,22829,22834,22840,22846,31442,22869,22864,22862,22874,22872,22882,22880,22887,22892,22889,22904,22913,22941,20318,20395,22947,22962,22982,23016,23004,22925,23001,23002,23077,23071,23057,23068,23049,23066,23104,23148,23113,23093,23094,23138,23146,23194,23228,23230,23243,23234,23229,23267,23255,23270,23273,23254,23290,23291,23308,23307,23318,23346,23248,23338,23350,23358,23363,23365,23360,23377,23381,23386,23387,23397,23401,23408,23411,23413,23416,25992,23418,23424,23427,23462,23480,23491,23495,23497,23508,23504,23524,23526,23522,23518,23525,23531,23536,23542,23539,23557,23559,23560,23565,23571,23584,23586,23592,23608,23609,23617,23622,23630,23635,23632,23631,23409,23660,23662,20066,23670,23673,23692,23697,23700,22939,23723,23739,23734,23740,23735,23749,23742,23751,23769,23785,23805,23802,23789,23948,23786,23819,23829,23831,23900,23839,23835,23825,23828,23842,23834,23833,23832,23884,23890,23886,23883,23916,23923,23926,23943,23940,23938,23970,23965,23980,23982,23997,23952,23991,23996,24009,24013,24019,24018,24022,24027,24043,24050,24053,24075,24090,24089,24081,24091,24118,24119,24132,24131,24128,24142,24151,24148,24159,24162,24164,24135,24181,24182,24186,40636,24191,24224,24257,24258,24264,24272,24271,24278,24291,24285,24282,24283,24290,24289,24296,24297,24300,24305,24307,24304,24308,24312,24318,24323,24329,24413,24412,24331,24337,24342,24361,24365,24376,24385,24392,24396,24398,24367,24401,24406,24407,24409,24417,24429,24435,24439,24451,24450,24447,24458,24456,24465,24455,24478,24473,24472,24480,24488,24493,24508,24534,24571,24548,24568,24561,24541,24755,24575,24609,24672,24601,24592,24617,24590,24625,24603,24597,24619,24614,24591,24634,24666,24641,24682,24695,24671,24650,24646,24653,24675,24643,24676,24642,24684,24683,24665,24705,24717,24807,24707,24730,24708,24731,24726,24727,24722,24743,24715,24801,24760,24800,24787,24756,24560,24765,24774,24757,24792,24909,24853,24838,24822,24823,24832,24820,24826,24835,24865,24827,24817,24845,24846,24903,24894,24872,24871,24906,24895,24892,24876,24884,24893,24898,24900,24947,24951,24920,24921,24922,24939,24948,24943,24933,24945,24927,24925,24915,24949,24985,24982,24967,25004,24980,24986,24970,24977,25003,25006,25036,25034,25033,25079,25032,25027,25030,25018,25035,32633,25037,25062,25059,25078,25082,25076,25087,25085,25084,25086,25088,25096,25097,25101,25100,25108,25115,25118,25121,25130,25134,25136,25138,25139,25153,25166,25182,25187,25179,25184,25192,25212,25218,25225,25214,25234,25235,25238,25300,25219,25236,25303,25297,25275,25295,25343,25286,25812,25288,25308,25292,25290,25282,25287,25243,25289,25356,25326,25329,25383,25346,25352,25327,25333,25424,25406,25421,25628,25423,25494,25486,25472,25515,25462,25507,25487,25481,25503,25525,25451,25449,25534,25577,25536,25542,25571,25545,25554,25590,25540,25622,25652,25606,25619,25638,25654,25885,25623,25640,25615,25703,25711,25718,25678,25898,25749,25747,25765,25769,25736,25788,25818,25810,25797,25799,25787,25816,25794,25841,25831,33289,25824,25825,25260,25827,25839,25900,25846,25844,25842,25850,25856,25853,25880,25884,25861,25892,25891,25899,25908,25909,25911,25910,25912,30027,25928,25942,25941,25933,25944,25950,25949,25970,25976,25986,25987,35722,26011,26015,26027,26039,26051,26054,26049,26052,26060,26066,26075,26073,26080,26081,26097,26482,26122,26115,26107,26483,26165,26166,26164,26140,26191,26180,26185,26177,26206,26205,26212,26215,26216,26207,26210,26224,26243,26248,26254,26249,26244,26264,26269,26305,26297,26313,26302,26300,26308,26296,26326,26330,26336,26175,26342,26345,26352,26357,26359,26383,26390,26398,26406,26407,38712,26414,26431,26422,26433,26424,26423,26438,26462,26464,26457,26467,26468,26505,26480,26537,26492,26474,26508,26507,26534,26529,26501,26551,26607,26548,26604,26547,26601,26552,26596,26590,26589,26594,26606,26553,26574,26566,26599,27292,26654,26694,26665,26688,26701,26674,26702,26803,26667,26713,26723,26743,26751,26783,26767,26797,26772,26781,26779,26755,27310,26809,26740,26805,26784,26810,26895,26765,26750,26881,26826,26888,26840,26914,26918,26849,26892,26829,26836,26855,26837,26934,26898,26884,26839,26851,26917,26873,26848,26863,26920,26922,26906,26915,26913,26822,27001,26999,26972,27000,26987,26964,27006,26990,26937,26996,26941,26969,26928,26977,26974,26973,27009,26986,27058,27054,27088,27071,27073,27091,27070,27086,23528,27082,27101,27067,27075,27047,27182,27025,27040,27036,27029,27060,27102,27112,27138,27163,27135,27402,27129,27122,27111,27141,27057,27166,27117,27156,27115,27146,27154,27329,27171,27155,27204,27148,27250,27190,27256,27207,27234,27225,27238,27208,27192,27170,27280,27277,27296,27268,27298,27299,27287,34327,27323,27331,27330,27320,27315,27308,27358,27345,27359,27306,27354,27370,27387,27397,34326,27386,27410,27414,39729,27423,27448,27447,30428,27449,39150,27463,27459,27465,27472,27481,27476,27483,27487,27489,27512,27513,27519,27520,27524,27523,27533,27544,27541,27550,27556,27562,27563,27567,27570,27569,27571,27575,27580,27590,27595,27603,27615,27628,27627,27635,27631,40638,27656,27667,27668,27675,27684,27683,27742,27733,27746,27754,27778,27789,27802,27777,27803,27774,27752,27763,27794,27792,27844,27889,27859,27837,27863,27845,27869,27822,27825,27838,27834,27867,27887,27865,27882,27935,34893,27958,27947,27965,27960,27929,27957,27955,27922,27916,28003,28051,28004,27994,28025,27993,28046,28053,28644,28037,28153,28181,28170,28085,28103,28134,28088,28102,28140,28126,28108,28136,28114,28101,28154,28121,28132,28117,28138,28142,28205,28270,28206,28185,28274,28255,28222,28195,28267,28203,28278,28237,28191,28227,28218,28238,28196,28415,28189,28216,28290,28330,28312,28361,28343,28371,28349,28335,28356,28338,28372,28373,28303,28325,28354,28319,28481,28433,28748,28396,28408,28414,28479,28402,28465,28399,28466,28364,28478,28435,28407,28550,28538,28536,28545,28544,28527,28507,28659,28525,28546,28540,28504,28558,28561,28610,28518,28595,28579,28577,28580,28601,28614,28586,28639,28629,28652,28628,28632,28657,28654,28635,28681,28683,28666,28689,28673,28687,28670,28699,28698,28532,28701,28696,28703,28720,28734,28722,28753,28771,28825,28818,28847,28913,28844,28856,28851,28846,28895,28875,28893,28889,28937,28925,28956,28953,29029,29013,29064,29030,29026,29004,29014,29036,29071,29179,29060,29077,29096,29100,29143,29113,29118,29138,29129,29140,29134,29152,29164,29159,29173,29180,29177,29183,29197,29200,29211,29224,29229,29228,29232,29234,29243,29244,29247,29248,29254,29259,29272,29300,29310,29314,29313,29319,29330,29334,29346,29351,29369,29362,29379,29382,29380,29390,29394,29410,29408,29409,29433,29431,20495,29463,29450,29468,29462,29469,29492,29487,29481,29477,29502,29518,29519,40664,29527,29546,29544,29552,29560,29557,29563,29562,29640,29619,29646,29627,29632,29669,29678,29662,29858,29701,29807,29733,29688,29746,29754,29781,29759,29791,29785,29761,29788,29801,29808,29795,29802,29814,29822,29835,29854,29863,29898,29903,29908,29681,29920,29923,29927,29929,29934,29938,29936,29937,29944,29943,29956,29955,29957,29964,29966,29965,29973,29971,29982,29990,29996,30012,30020,30029,30026,30025,30043,30022,30042,30057,30052,30055,30059,30061,30072,30070,30086,30087,30068,30090,30089,30082,30100,30106,30109,30117,30115,30146,30131,30147,30133,30141,30136,30140,30129,30157,30154,30162,30169,30179,30174,30206,30207,30204,30209,30192,30202,30194,30195,30219,30221,30217,30239,30247,30240,30241,30242,30244,30260,30256,30267,30279,30280,30278,30300,30296,30305,30306,30312,30313,30314,30311,30316,30320,30322,30326,30328,30332,30336,30339,30344,30347,30350,30358,30355,30361,30362,30384,30388,30392,30393,30394,30402,30413,30422,30418,30430,30433,30437,30439,30442,34351,30459,30472,30471,30468,30505,30500,30494,30501,30502,30491,30519,30520,30535,30554,30568,30571,30555,30565,30591,30590,30585,30606,30603,30609,30624,30622,30640,30646,30649,30655,30652,30653,30651,30663,30669,30679,30682,30684,30691,30702,30716,30732,30738,31014,30752,31018,30789,30862,30836,30854,30844,30874,30860,30883,30901,30890,30895,30929,30918,30923,30932,30910,30908,30917,30922,30956,30951,30938,30973,30964,30983,30994,30993,31001,31020,31019,31040,31072,31063,31071,31066,31061,31059,31098,31103,31114,31133,31143,40779,31146,31150,31155,31161,31162,31177,31189,31207,31212,31201,31203,31240,31245,31256,31257,31264,31263,31104,31281,31291,31294,31287,31299,31319,31305,31329,31330,31337,40861,31344,31353,31357,31368,31383,31381,31384,31382,31401,31432,31408,31414,31429,31428,31423,36995,31431,31434,31437,31439,31445,31443,31449,31450,31453,31457,31458,31462,31469,31472,31490,31503,31498,31494,31539,31512,31513,31518,31541,31528,31542,31568,31610,31492,31565,31499,31564,31557,31605,31589,31604,31591,31600,31601,31596,31598,31645,31640,31647,31629,31644,31642,31627,31634,31631,31581,31641,31691,31681,31692,31695,31668,31686,31709,31721,31761,31764,31718,31717,31840,31744,31751,31763,31731,31735,31767,31757,31734,31779,31783,31786,31775,31799,31787,31805,31820,31811,31828,31823,31808,31824,31832,31839,31844,31830,31845,31852,31861,31875,31888,31908,31917,31906,31915,31905,31912,31923,31922,31921,31918,31929,31933,31936,31941,31938,31960,31954,31964,31970,39739,31983,31986,31988,31990,31994,32006,32002,32028,32021,32010,32069,32075,32046,32050,32063,32053,32070,32115,32086,32078,32114,32104,32110,32079,32099,32147,32137,32091,32143,32125,32155,32186,32174,32163,32181,32199,32189,32171,32317,32162,32175,32220,32184,32159,32176,32216,32221,32228,32222,32251,32242,32225,32261,32266,32291,32289,32274,32305,32287,32265,32267,32290,32326,32358,32315,32309,32313,32323,32311,32306,32314,32359,32349,32342,32350,32345,32346,32377,32362,32361,32380,32379,32387,32213,32381,36782,32383,32392,32393,32396,32402,32400,32403,32404,32406,32398,32411,32412,32568,32570,32581,32588,32589,32590,32592,32593,32597,32596,32600,32607,32608,32616,32617,32615,32632,32642,32646,32643,32648,32647,32652,32660,32670,32669,32666,32675,32687,32690,32697,32686,32694,32696,35697,32709,32710,32714,32725,32724,32737,32742,32745,32755,32761,39132,32774,32772,32779,32786,32792,32793,32796,32801,32808,32831,32827,32842,32838,32850,32856,32858,32863,32866,32872,32883,32882,32880,32886,32889,32893,32895,32900,32902,32901,32923,32915,32922,32941,20880,32940,32987,32997,32985,32989,32964,32986,32982,33033,33007,33009,33051,33065,33059,33071,33099,38539,33094,33086,33107,33105,33020,33137,33134,33125,33126,33140,33155,33160,33162,33152,33154,33184,33173,33188,33187,33119,33171,33193,33200,33205,33214,33208,33213,33216,33218,33210,33225,33229,33233,33241,33240,33224,33242,33247,33248,33255,33274,33275,33278,33281,33282,33285,33287,33290,33293,33296,33302,33321,33323,33336,33331,33344,33369,33368,33373,33370,33375,33380,33378,33384,33386,33387,33326,33393,33399,33400,33406,33421,33426,33451,33439,33467,33452,33505,33507,33503,33490,33524,33523,33530,33683,33539,33531,33529,33502,33542,33500,33545,33497,33589,33588,33558,33586,33585,33600,33593,33616,33605,33583,33579,33559,33560,33669,33690,33706,33695,33698,33686,33571,33678,33671,33674,33660,33717,33651,33653,33696,33673,33704,33780,33811,33771,33742,33789,33795,33752,33803,33729,33783,33799,33760,33778,33805,33826,33824,33725,33848,34054,33787,33901,33834,33852,34138,33924,33911,33899,33965,33902,33922,33897,33862,33836,33903,33913,33845,33994,33890,33977,33983,33951,34009,33997,33979,34010,34000,33985,33990,34006,33953,34081,34047,34036,34071,34072,34092,34079,34069,34068,34044,34112,34147,34136,34120,34113,34306,34123,34133,34176,34212,34184,34193,34186,34216,34157,34196,34203,34282,34183,34204,34167,34174,34192,34249,34234,34255,34233,34256,34261,34269,34277,34268,34297,34314,34323,34315,34302,34298,34310,34338,34330,34352,34367,34381,20053,34388,34399,34407,34417,34451,34467,34473,34474,34443,34444,34486,34479,34500,34502,34480,34505,34851,34475,34516,34526,34537,34540,34527,34523,34543,34578,34566,34568,34560,34563,34555,34577,34569,34573,34553,34570,34612,34623,34615,34619,34597,34601,34586,34656,34655,34680,34636,34638,34676,34647,34664,34670,34649,34643,34659,34666,34821,34722,34719,34690,34735,34763,34749,34752,34768,38614,34731,34756,34739,34759,34758,34747,34799,34802,34784,34831,34829,34814,34806,34807,34830,34770,34833,34838,34837,34850,34849,34865,34870,34873,34855,34875,34884,34882,34898,34905,34910,34914,34923,34945,34942,34974,34933,34941,34997,34930,34946,34967,34962,34990,34969,34978,34957,34980,34992,35007,34993,35011,35012,35028,35032,35033,35037,35065,35074,35068,35060,35048,35058,35076,35084,35082,35091,35139,35102,35109,35114,35115,35137,35140,35131,35126,35128,35148,35101,35168,35166,35174,35172,35181,35178,35183,35188,35191,35198,35203,35208,35210,35219,35224,35233,35241,35238,35244,35247,35250,35258,35261,35263,35264,35290,35292,35293,35303,35316,35320,35331,35350,35344,35340,35355,35357,35365,35382,35393,35419,35410,35398,35400,35452,35437,35436,35426,35461,35458,35460,35496,35489,35473,35493,35494,35482,35491,35524,35533,35522,35546,35563,35571,35559,35556,35569,35604,35552,35554,35575,35550,35547,35596,35591,35610,35553,35606,35600,35607,35616,35635,38827,35622,35627,35646,35624,35649,35660,35663,35662,35657,35670,35675,35674,35691,35679,35692,35695,35700,35709,35712,35724,35726,35730,35731,35734,35737,35738,35898,35905,35903,35912,35916,35918,35920,35925,35938,35948,35960,35962,35970,35977,35973,35978,35981,35982,35988,35964,35992,25117,36013,36010,36029,36018,36019,36014,36022,36040,36033,36068,36067,36058,36093,36090,36091,36100,36101,36106,36103,36111,36109,36112,40782,36115,36045,36116,36118,36199,36205,36209,36211,36225,36249,36290,36286,36282,36303,36314,36310,36300,36315,36299,36330,36331,36319,36323,36348,36360,36361,36351,36381,36382,36368,36383,36418,36405,36400,36404,36426,36423,36425,36428,36432,36424,36441,36452,36448,36394,36451,36437,36470,36466,36476,36481,36487,36485,36484,36491,36490,36499,36497,36500,36505,36522,36513,36524,36528,36550,36529,36542,36549,36552,36555,36571,36579,36604,36603,36587,36606,36618,36613,36629,36626,36633,36627,36636,36639,36635,36620,36646,36659,36667,36665,36677,36674,36670,36684,36681,36678,36686,36695,36700,36706,36707,36708,36764,36767,36771,36781,36783,36791,36826,36837,36834,36842,36847,36999,36852,36869,36857,36858,36881,36885,36897,36877,36894,36886,36875,36903,36918,36917,36921,36856,36943,36944,36945,36946,36878,36937,36926,36950,36952,36958,36968,36975,36982,38568,36978,36994,36989,36993,36992,37002,37001,37007,37032,37039,37041,37045,37090,37092,25160,37083,37122,37138,37145,37170,37168,37194,37206,37208,37219,37221,37225,37235,37234,37259,37257,37250,37282,37291,37295,37290,37301,37300,37306,37312,37313,37321,37323,37328,37334,37343,37345,37339,37372,37365,37366,37406,37375,37396,37420,37397,37393,37470,37463,37445,37449,37476,37448,37525,37439,37451,37456,37532,37526,37523,37531,37466,37583,37561,37559,37609,37647,37626,37700,37678,37657,37666,37658,37667,37690,37685,37691,37724,37728,37756,37742,37718,37808,37804,37805,37780,37817,37846,37847,37864,37861,37848,37827,37853,37840,37832,37860,37914,37908,37907,37891,37895,37904,37942,37931,37941,37921,37946,37953,37970,37956,37979,37984,37986,37982,37994,37417,38000,38005,38007,38013,37978,38012,38014,38017,38015,38274,38279,38282,38292,38294,38296,38297,38304,38312,38311,38317,38332,38331,38329,38334,38346,28662,38339,38349,38348,38357,38356,38358,38364,38369,38373,38370,38433,38440,38446,38447,38466,38476,38479,38475,38519,38492,38494,38493,38495,38502,38514,38508,38541,38552,38549,38551,38570,38567,38577,38578,38576,38580,38582,38584,38585,38606,38603,38601,38605,35149,38620,38669,38613,38649,38660,38662,38664,38675,38670,38673,38671,38678,38681,38692,38698,38704,38713,38717,38718,38724,38726,38728,38722,38729,38748,38752,38756,38758,38760,21202,38763,38769,38777,38789,38780,38785,38778,38790,38795,38799,38800,38812,38824,38822,38819,38835,38836,38851,38854,38856,38859,38876,38893,40783,38898,31455,38902,38901,38927,38924,38968,38948,38945,38967,38973,38982,38991,38987,39019,39023,39024,39025,39028,39027,39082,39087,39089,39094,39108,39107,39110,39145,39147,39171,39177,39186,39188,39192,39201,39197,39198,39204,39200,39212,39214,39229,39230,39234,39241,39237,39248,39243,39249,39250,39244,39253,39319,39320,39333,39341,39342,39356,39391,39387,39389,39384,39377,39405,39406,39409,39410,39419,39416,39425,39439,39429,39394,39449,39467,39479,39493,39490,39488,39491,39486,39509,39501,39515,39511,39519,39522,39525,39524,39529,39531,39530,39597,39600,39612,39616,39631,39633,39635,39636,39646,39647,39650,39651,39654,39663,39659,39662,39668,39665,39671,39675,39686,39704,39706,39711,39714,39715,39717,39719,39720,39721,39722,39726,39727,39730,39748,39747,39759,39757,39758,39761,39768,39796,39827,39811,39825,39830,39831,39839,39840,39848,39860,39872,39882,39865,39878,39887,39889,39890,39907,39906,39908,39892,39905,39994,39922,39921,39920,39957,39956,39945,39955,39948,39942,39944,39954,39946,39940,39982,39963,39973,39972,39969,39984,40007,39986,40006,39998,40026,40032,40039,40054,40056,40167,40172,40176,40201,40200,40171,40195,40198,40234,40230,40367,40227,40223,40260,40213,40210,40257,40255,40254,40262,40264,40285,40286,40292,40273,40272,40281,40306,40329,40327,40363,40303,40314,40346,40356,40361,40370,40388,40385,40379,40376,40378,40390,40399,40386,40409,40403,40440,40422,40429,40431,40445,40474,40475,40478,40565,40569,40573,40577,40584,40587,40588,40594,40597,40593,40605,40613,40617,40632,40618,40621,38753,40652,40654,40655,40656,40660,40668,40670,40669,40672,40677,40680,40687,40692,40694,40695,40697,40699,40700,40701,40711,40712,30391,40725,40737,40748,40766,40778,40786,40788,40803,40799,40800,40801,40806,40807,40812,40810,40823,40818,40822,40853,40860,40864,22575,27079,36953,29796,20956,29081,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,32394,35100,37704,37512,34012,20425,28859,26161,26824,37625,26363,24389,20008,20193,20220,20224,20227,20281,20310,20370,20362,20378,20372,20429,20544,20514,20479,20510,20550,20592,20546,20628,20724,20696,20810,20836,20893,20926,20972,21013,21148,21158,21184,21211,21248,21255,21284,21362,21395,21426,21469,64014,21660,21642,21673,21759,21894,22361,22373,22444,22472,22471,64015,64016,22686,22706,22795,22867,22875,22877,22883,22948,22970,23382,23488,29999,23512,23532,23582,23718,23738,23797,23847,23891,64017,23874,23917,23992,23993,24016,24353,24372,24423,24503,24542,24669,24709,24714,24798,24789,24864,24818,24849,24887,24880,24984,25107,25254,25589,25696,25757,25806,25934,26112,26133,26171,26121,26158,26142,26148,26213,26199,26201,64018,26227,26265,26272,26290,26303,26362,26382,63785,26470,26555,26706,26560,26625,26692,26831,64019,26984,64020,27032,27106,27184,27243,27206,27251,27262,27362,27364,27606,27711,27740,27782,27759,27866,27908,28039,28015,28054,28076,28111,28152,28146,28156,28217,28252,28199,28220,28351,28552,28597,28661,28677,28679,28712,28805,28843,28943,28932,29020,28998,28999,64021,29121,29182,29361,29374,29476,64022,29559,29629,29641,29654,29667,29650,29703,29685,29734,29738,29737,29742,29794,29833,29855,29953,30063,30338,30364,30366,30363,30374,64023,30534,21167,30753,30798,30820,30842,31024,64024,64025,64026,31124,64027,31131,31441,31463,64028,31467,31646,64029,32072,32092,32183,32160,32214,32338,32583,32673,64030,33537,33634,33663,33735,33782,33864,33972,34131,34137,34155,64031,34224,64032,64033,34823,35061,35346,35383,35449,35495,35518,35551,64034,35574,35667,35711,36080,36084,36114,36214,64035,36559,64036,64037,36967,37086,64038,37141,37159,37338,37335,37342,37357,37358,37348,37349,37382,37392,37386,37434,37440,37436,37454,37465,37457,37433,37479,37543,37495,37496,37607,37591,37593,37584,64039,37589,37600,37587,37669,37665,37627,64040,37662,37631,37661,37634,37744,37719,37796,37830,37854,37880,37937,37957,37960,38290,63964,64041,38557,38575,38707,38715,38723,38733,38735,38737,38741,38999,39013,64042,64043,39207,64044,39326,39502,39641,39644,39797,39794,39823,39857,39867,39936,40304,40299,64045,40473,40657,null,null,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,65506,65508,65287,65282,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,8560,8561,8562,8563,8564,8565,8566,8567,8568,8569,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,65506,65508,65287,65282,12849,8470,8481,8757,32394,35100,37704,37512,34012,20425,28859,26161,26824,37625,26363,24389,20008,20193,20220,20224,20227,20281,20310,20370,20362,20378,20372,20429,20544,20514,20479,20510,20550,20592,20546,20628,20724,20696,20810,20836,20893,20926,20972,21013,21148,21158,21184,21211,21248,21255,21284,21362,21395,21426,21469,64014,21660,21642,21673,21759,21894,22361,22373,22444,22472,22471,64015,64016,22686,22706,22795,22867,22875,22877,22883,22948,22970,23382,23488,29999,23512,23532,23582,23718,23738,23797,23847,23891,64017,23874,23917,23992,23993,24016,24353,24372,24423,24503,24542,24669,24709,24714,24798,24789,24864,24818,24849,24887,24880,24984,25107,25254,25589,25696,25757,25806,25934,26112,26133,26171,26121,26158,26142,26148,26213,26199,26201,64018,26227,26265,26272,26290,26303,26362,26382,63785,26470,26555,26706,26560,26625,26692,26831,64019,26984,64020,27032,27106,27184,27243,27206,27251,27262,27362,27364,27606,27711,27740,27782,27759,27866,27908,28039,28015,28054,28076,28111,28152,28146,28156,28217,28252,28199,28220,28351,28552,28597,28661,28677,28679,28712,28805,28843,28943,28932,29020,28998,28999,64021,29121,29182,29361,29374,29476,64022,29559,29629,29641,29654,29667,29650,29703,29685,29734,29738,29737,29742,29794,29833,29855,29953,30063,30338,30364,30366,30363,30374,64023,30534,21167,30753,30798,30820,30842,31024,64024,64025,64026,31124,64027,31131,31441,31463,64028,31467,31646,64029,32072,32092,32183,32160,32214,32338,32583,32673,64030,33537,33634,33663,33735,33782,33864,33972,34131,34137,34155,64031,34224,64032,64033,34823,35061,35346,35383,35449,35495,35518,35551,64034,35574,35667,35711,36080,36084,36114,36214,64035,36559,64036,64037,36967,37086,64038,37141,37159,37338,37335,37342,37357,37358,37348,37349,37382,37392,37386,37434,37440,37436,37454,37465,37457,37433,37479,37543,37495,37496,37607,37591,37593,37584,64039,37589,37600,37587,37669,37665,37627,64040,37662,37631,37661,37634,37744,37719,37796,37830,37854,37880,37937,37957,37960,38290,63964,64041,38557,38575,38707,38715,38723,38733,38735,38737,38741,38999,39013,64042,64043,39207,64044,39326,39502,39641,39644,39797,39794,39823,39857,39867,39936,40304,40299,64045,40473,40657,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],
+ "jis0212":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,728,711,184,729,733,175,731,730,65374,900,901,null,null,null,null,null,null,null,null,161,166,191,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,186,170,169,174,8482,164,8470,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,902,904,905,906,938,null,908,null,910,939,null,911,null,null,null,null,940,941,942,943,970,912,972,962,973,971,944,974,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1038,1039,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,1118,1119,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,198,272,null,294,null,306,null,321,319,null,330,216,338,null,358,222,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,230,273,240,295,305,307,312,322,320,329,331,248,339,223,359,254,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,193,192,196,194,258,461,256,260,197,195,262,264,268,199,266,270,201,200,203,202,282,278,274,280,null,284,286,290,288,292,205,204,207,206,463,304,298,302,296,308,310,313,317,315,323,327,325,209,211,210,214,212,465,336,332,213,340,344,342,346,348,352,350,356,354,218,217,220,219,364,467,368,362,370,366,360,471,475,473,469,372,221,376,374,377,381,379,null,null,null,null,null,null,null,225,224,228,226,259,462,257,261,229,227,263,265,269,231,267,271,233,232,235,234,283,279,275,281,501,285,287,null,289,293,237,236,239,238,464,null,299,303,297,309,311,314,318,316,324,328,326,241,243,242,246,244,466,337,333,245,341,345,343,347,349,353,351,357,355,250,249,252,251,365,468,369,363,371,367,361,472,476,474,470,373,253,255,375,378,382,380,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,19970,19972,19973,19980,19986,19999,20003,20004,20008,20011,20014,20015,20016,20021,20032,20033,20036,20039,20049,20058,20060,20067,20072,20073,20084,20085,20089,20095,20109,20118,20119,20125,20143,20153,20163,20176,20186,20187,20192,20193,20194,20200,20207,20209,20211,20213,20221,20222,20223,20224,20226,20227,20232,20235,20236,20242,20245,20246,20247,20249,20270,20273,20320,20275,20277,20279,20281,20283,20286,20288,20290,20296,20297,20299,20300,20306,20308,20310,20312,20319,20323,20330,20332,20334,20337,20343,20344,20345,20346,20349,20350,20353,20354,20356,20357,20361,20362,20364,20366,20368,20370,20371,20372,20375,20377,20378,20382,20383,20402,20407,20409,20411,20412,20413,20414,20416,20417,20421,20422,20424,20425,20427,20428,20429,20431,20434,20444,20448,20450,20464,20466,20476,20477,20479,20480,20481,20484,20487,20490,20492,20494,20496,20499,20503,20504,20507,20508,20509,20510,20514,20519,20526,20528,20530,20531,20533,20544,20545,20546,20549,20550,20554,20556,20558,20561,20562,20563,20567,20569,20575,20576,20578,20579,20582,20583,20586,20589,20592,20593,20539,20609,20611,20612,20614,20618,20622,20623,20624,20626,20627,20628,20630,20635,20636,20638,20639,20640,20641,20642,20650,20655,20656,20665,20666,20669,20672,20675,20676,20679,20684,20686,20688,20691,20692,20696,20700,20701,20703,20706,20708,20710,20712,20713,20719,20721,20726,20730,20734,20739,20742,20743,20744,20747,20748,20749,20750,20722,20752,20759,20761,20763,20764,20765,20766,20771,20775,20776,20780,20781,20783,20785,20787,20788,20789,20792,20793,20802,20810,20815,20819,20821,20823,20824,20831,20836,20838,20862,20867,20868,20875,20878,20888,20893,20897,20899,20909,20920,20922,20924,20926,20927,20930,20936,20943,20945,20946,20947,20949,20952,20958,20962,20965,20974,20978,20979,20980,20983,20993,20994,20997,21010,21011,21013,21014,21016,21026,21032,21041,21042,21045,21052,21061,21065,21077,21079,21080,21082,21084,21087,21088,21089,21094,21102,21111,21112,21113,21120,21122,21125,21130,21132,21139,21141,21142,21143,21144,21146,21148,21156,21157,21158,21159,21167,21168,21174,21175,21176,21178,21179,21181,21184,21188,21190,21192,21196,21199,21201,21204,21206,21211,21212,21217,21221,21224,21225,21226,21228,21232,21233,21236,21238,21239,21248,21251,21258,21259,21260,21265,21267,21272,21275,21276,21278,21279,21285,21287,21288,21289,21291,21292,21293,21296,21298,21301,21308,21309,21310,21314,21324,21323,21337,21339,21345,21347,21349,21356,21357,21362,21369,21374,21379,21383,21384,21390,21395,21396,21401,21405,21409,21412,21418,21419,21423,21426,21428,21429,21431,21432,21434,21437,21440,21445,21455,21458,21459,21461,21466,21469,21470,21472,21478,21479,21493,21506,21523,21530,21537,21543,21544,21546,21551,21553,21556,21557,21571,21572,21575,21581,21583,21598,21602,21604,21606,21607,21609,21611,21613,21614,21620,21631,21633,21635,21637,21640,21641,21645,21649,21653,21654,21660,21663,21665,21670,21671,21673,21674,21677,21678,21681,21687,21689,21690,21691,21695,21702,21706,21709,21710,21728,21738,21740,21743,21750,21756,21758,21759,21760,21761,21765,21768,21769,21772,21773,21774,21781,21802,21803,21810,21813,21814,21819,21820,21821,21825,21831,21833,21834,21837,21840,21841,21848,21850,21851,21854,21856,21857,21860,21862,21887,21889,21890,21894,21896,21902,21903,21905,21906,21907,21908,21911,21923,21924,21933,21938,21951,21953,21955,21958,21961,21963,21964,21966,21969,21970,21971,21975,21976,21979,21982,21986,21993,22006,22015,22021,22024,22026,22029,22030,22031,22032,22033,22034,22041,22060,22064,22067,22069,22071,22073,22075,22076,22077,22079,22080,22081,22083,22084,22086,22089,22091,22093,22095,22100,22110,22112,22113,22114,22115,22118,22121,22125,22127,22129,22130,22133,22148,22149,22152,22155,22156,22165,22169,22170,22173,22174,22175,22182,22183,22184,22185,22187,22188,22189,22193,22195,22199,22206,22213,22217,22218,22219,22223,22224,22220,22221,22233,22236,22237,22239,22241,22244,22245,22246,22247,22248,22257,22251,22253,22262,22263,22273,22274,22279,22282,22284,22289,22293,22298,22299,22301,22304,22306,22307,22308,22309,22313,22314,22316,22318,22319,22323,22324,22333,22334,22335,22341,22342,22348,22349,22354,22370,22373,22375,22376,22379,22381,22382,22383,22384,22385,22387,22388,22389,22391,22393,22394,22395,22396,22398,22401,22403,22412,22420,22423,22425,22426,22428,22429,22430,22431,22433,22421,22439,22440,22441,22444,22456,22461,22471,22472,22476,22479,22485,22493,22494,22500,22502,22503,22505,22509,22512,22517,22518,22520,22525,22526,22527,22531,22532,22536,22537,22497,22540,22541,22555,22558,22559,22560,22566,22567,22573,22578,22585,22591,22601,22604,22605,22607,22608,22613,22623,22625,22628,22631,22632,22648,22652,22655,22656,22657,22663,22664,22665,22666,22668,22669,22671,22672,22676,22678,22685,22688,22689,22690,22694,22697,22705,22706,22724,22716,22722,22728,22733,22734,22736,22738,22740,22742,22746,22749,22753,22754,22761,22771,22789,22790,22795,22796,22802,22803,22804,34369,22813,22817,22819,22820,22824,22831,22832,22835,22837,22838,22847,22851,22854,22866,22867,22873,22875,22877,22878,22879,22881,22883,22891,22893,22895,22898,22901,22902,22905,22907,22908,22923,22924,22926,22930,22933,22935,22943,22948,22951,22957,22958,22959,22960,22963,22967,22970,22972,22977,22979,22980,22984,22986,22989,22994,23005,23006,23007,23011,23012,23015,23022,23023,23025,23026,23028,23031,23040,23044,23052,23053,23054,23058,23059,23070,23075,23076,23079,23080,23082,23085,23088,23108,23109,23111,23112,23116,23120,23125,23134,23139,23141,23143,23149,23159,23162,23163,23166,23179,23184,23187,23190,23193,23196,23198,23199,23200,23202,23207,23212,23217,23218,23219,23221,23224,23226,23227,23231,23236,23238,23240,23247,23258,23260,23264,23269,23274,23278,23285,23286,23293,23296,23297,23304,23319,23348,23321,23323,23325,23329,23333,23341,23352,23361,23371,23372,23378,23382,23390,23400,23406,23407,23420,23421,23422,23423,23425,23428,23430,23434,23438,23440,23441,23443,23444,23446,23464,23465,23468,23469,23471,23473,23474,23479,23482,23484,23488,23489,23501,23503,23510,23511,23512,23513,23514,23520,23535,23537,23540,23549,23564,23575,23582,23583,23587,23590,23593,23595,23596,23598,23600,23602,23605,23606,23641,23642,23644,23650,23651,23655,23656,23657,23661,23664,23668,23669,23674,23675,23676,23677,23687,23688,23690,23695,23698,23709,23711,23712,23714,23715,23718,23722,23730,23732,23733,23738,23753,23755,23762,23773,23767,23790,23793,23794,23796,23809,23814,23821,23826,23851,23843,23844,23846,23847,23857,23860,23865,23869,23871,23874,23875,23878,23880,23893,23889,23897,23882,23903,23904,23905,23906,23908,23914,23917,23920,23929,23930,23934,23935,23937,23939,23944,23946,23954,23955,23956,23957,23961,23963,23967,23968,23975,23979,23984,23988,23992,23993,24003,24007,24011,24016,24014,24024,24025,24032,24036,24041,24056,24057,24064,24071,24077,24082,24084,24085,24088,24095,24096,24110,24104,24114,24117,24126,24139,24144,24137,24145,24150,24152,24155,24156,24158,24168,24170,24171,24172,24173,24174,24176,24192,24203,24206,24226,24228,24229,24232,24234,24236,24241,24243,24253,24254,24255,24262,24268,24267,24270,24273,24274,24276,24277,24284,24286,24293,24299,24322,24326,24327,24328,24334,24345,24348,24349,24353,24354,24355,24356,24360,24363,24364,24366,24368,24372,24374,24379,24381,24383,24384,24388,24389,24391,24397,24400,24404,24408,24411,24416,24419,24420,24423,24431,24434,24436,24437,24440,24442,24445,24446,24457,24461,24463,24470,24476,24477,24482,24487,24491,24484,24492,24495,24496,24497,24504,24516,24519,24520,24521,24523,24528,24529,24530,24531,24532,24542,24545,24546,24552,24553,24554,24556,24557,24558,24559,24562,24563,24566,24570,24572,24583,24586,24589,24595,24596,24599,24600,24602,24607,24612,24621,24627,24629,24640,24647,24648,24649,24652,24657,24660,24662,24663,24669,24673,24679,24689,24702,24703,24706,24710,24712,24714,24718,24721,24723,24725,24728,24733,24734,24738,24740,24741,24744,24752,24753,24759,24763,24766,24770,24772,24776,24777,24778,24779,24782,24783,24788,24789,24793,24795,24797,24798,24802,24805,24818,24821,24824,24828,24829,24834,24839,24842,24844,24848,24849,24850,24851,24852,24854,24855,24857,24860,24862,24866,24874,24875,24880,24881,24885,24886,24887,24889,24897,24901,24902,24905,24926,24928,24940,24946,24952,24955,24956,24959,24960,24961,24963,24964,24971,24973,24978,24979,24983,24984,24988,24989,24991,24992,24997,25000,25002,25005,25016,25017,25020,25024,25025,25026,25038,25039,25045,25052,25053,25054,25055,25057,25058,25063,25065,25061,25068,25069,25071,25089,25091,25092,25095,25107,25109,25116,25120,25122,25123,25127,25129,25131,25145,25149,25154,25155,25156,25158,25164,25168,25169,25170,25172,25174,25178,25180,25188,25197,25199,25203,25210,25213,25229,25230,25231,25232,25254,25256,25267,25270,25271,25274,25278,25279,25284,25294,25301,25302,25306,25322,25330,25332,25340,25341,25347,25348,25354,25355,25357,25360,25363,25366,25368,25385,25386,25389,25397,25398,25401,25404,25409,25410,25411,25412,25414,25418,25419,25422,25426,25427,25428,25432,25435,25445,25446,25452,25453,25457,25460,25461,25464,25468,25469,25471,25474,25476,25479,25482,25488,25492,25493,25497,25498,25502,25508,25510,25517,25518,25519,25533,25537,25541,25544,25550,25553,25555,25556,25557,25564,25568,25573,25578,25580,25586,25587,25589,25592,25593,25609,25610,25616,25618,25620,25624,25630,25632,25634,25636,25637,25641,25642,25647,25648,25653,25661,25663,25675,25679,25681,25682,25683,25684,25690,25691,25692,25693,25695,25696,25697,25699,25709,25715,25716,25723,25725,25733,25735,25743,25744,25745,25752,25753,25755,25757,25759,25761,25763,25766,25768,25772,25779,25789,25790,25791,25796,25801,25802,25803,25804,25806,25808,25809,25813,25815,25828,25829,25833,25834,25837,25840,25845,25847,25851,25855,25857,25860,25864,25865,25866,25871,25875,25876,25878,25881,25883,25886,25887,25890,25894,25897,25902,25905,25914,25916,25917,25923,25927,25929,25936,25938,25940,25951,25952,25959,25963,25978,25981,25985,25989,25994,26002,26005,26008,26013,26016,26019,26022,26030,26034,26035,26036,26047,26050,26056,26057,26062,26064,26068,26070,26072,26079,26096,26098,26100,26101,26105,26110,26111,26112,26116,26120,26121,26125,26129,26130,26133,26134,26141,26142,26145,26146,26147,26148,26150,26153,26154,26155,26156,26158,26160,26161,26163,26169,26167,26176,26181,26182,26186,26188,26193,26190,26199,26200,26201,26203,26204,26208,26209,26363,26218,26219,26220,26238,26227,26229,26239,26231,26232,26233,26235,26240,26236,26251,26252,26253,26256,26258,26265,26266,26267,26268,26271,26272,26276,26285,26289,26290,26293,26299,26303,26304,26306,26307,26312,26316,26318,26319,26324,26331,26335,26344,26347,26348,26350,26362,26373,26375,26382,26387,26393,26396,26400,26402,26419,26430,26437,26439,26440,26444,26452,26453,26461,26470,26476,26478,26484,26486,26491,26497,26500,26510,26511,26513,26515,26518,26520,26521,26523,26544,26545,26546,26549,26555,26556,26557,26617,26560,26562,26563,26565,26568,26569,26578,26583,26585,26588,26593,26598,26608,26610,26614,26615,26706,26644,26649,26653,26655,26664,26663,26668,26669,26671,26672,26673,26675,26683,26687,26692,26693,26698,26700,26709,26711,26712,26715,26731,26734,26735,26736,26737,26738,26741,26745,26746,26747,26748,26754,26756,26758,26760,26774,26776,26778,26780,26785,26787,26789,26793,26794,26798,26802,26811,26821,26824,26828,26831,26832,26833,26835,26838,26841,26844,26845,26853,26856,26858,26859,26860,26861,26864,26865,26869,26870,26875,26876,26877,26886,26889,26890,26896,26897,26899,26902,26903,26929,26931,26933,26936,26939,26946,26949,26953,26958,26967,26971,26979,26980,26981,26982,26984,26985,26988,26992,26993,26994,27002,27003,27007,27008,27021,27026,27030,27032,27041,27045,27046,27048,27051,27053,27055,27063,27064,27066,27068,27077,27080,27089,27094,27095,27106,27109,27118,27119,27121,27123,27125,27134,27136,27137,27139,27151,27153,27157,27162,27165,27168,27172,27176,27184,27186,27188,27191,27195,27198,27199,27205,27206,27209,27210,27214,27216,27217,27218,27221,27222,27227,27236,27239,27242,27249,27251,27262,27265,27267,27270,27271,27273,27275,27281,27291,27293,27294,27295,27301,27307,27311,27312,27313,27316,27325,27326,27327,27334,27337,27336,27340,27344,27348,27349,27350,27356,27357,27364,27367,27372,27376,27377,27378,27388,27389,27394,27395,27398,27399,27401,27407,27408,27409,27415,27419,27422,27428,27432,27435,27436,27439,27445,27446,27451,27455,27462,27466,27469,27474,27478,27480,27485,27488,27495,27499,27502,27504,27509,27517,27518,27522,27525,27543,27547,27551,27552,27554,27555,27560,27561,27564,27565,27566,27568,27576,27577,27581,27582,27587,27588,27593,27596,27606,27610,27617,27619,27622,27623,27630,27633,27639,27641,27647,27650,27652,27653,27657,27661,27662,27664,27666,27673,27679,27686,27687,27688,27692,27694,27699,27701,27702,27706,27707,27711,27722,27723,27725,27727,27730,27732,27737,27739,27740,27755,27757,27759,27764,27766,27768,27769,27771,27781,27782,27783,27785,27796,27797,27799,27800,27804,27807,27824,27826,27828,27842,27846,27853,27855,27856,27857,27858,27860,27862,27866,27868,27872,27879,27881,27883,27884,27886,27890,27892,27908,27911,27914,27918,27919,27921,27923,27930,27942,27943,27944,27751,27950,27951,27953,27961,27964,27967,27991,27998,27999,28001,28005,28007,28015,28016,28028,28034,28039,28049,28050,28052,28054,28055,28056,28074,28076,28084,28087,28089,28093,28095,28100,28104,28106,28110,28111,28118,28123,28125,28127,28128,28130,28133,28137,28143,28144,28148,28150,28156,28160,28164,28190,28194,28199,28210,28214,28217,28219,28220,28228,28229,28232,28233,28235,28239,28241,28242,28243,28244,28247,28252,28253,28254,28258,28259,28264,28275,28283,28285,28301,28307,28313,28320,28327,28333,28334,28337,28339,28347,28351,28352,28353,28355,28359,28360,28362,28365,28366,28367,28395,28397,28398,28409,28411,28413,28420,28424,28426,28428,28429,28438,28440,28442,28443,28454,28457,28458,28463,28464,28467,28470,28475,28476,28461,28495,28497,28498,28499,28503,28505,28506,28509,28510,28513,28514,28520,28524,28541,28542,28547,28551,28552,28555,28556,28557,28560,28562,28563,28564,28566,28570,28575,28576,28581,28582,28583,28584,28590,28591,28592,28597,28598,28604,28613,28615,28616,28618,28634,28638,28648,28649,28656,28661,28665,28668,28669,28672,28677,28678,28679,28685,28695,28704,28707,28719,28724,28727,28729,28732,28739,28740,28744,28745,28746,28747,28756,28757,28765,28766,28750,28772,28773,28780,28782,28789,28790,28798,28801,28805,28806,28820,28821,28822,28823,28824,28827,28836,28843,28848,28849,28852,28855,28874,28881,28883,28884,28885,28886,28888,28892,28900,28922,28931,28932,28933,28934,28935,28939,28940,28943,28958,28960,28971,28973,28975,28976,28977,28984,28993,28997,28998,28999,29002,29003,29008,29010,29015,29018,29020,29022,29024,29032,29049,29056,29061,29063,29068,29074,29082,29083,29088,29090,29103,29104,29106,29107,29114,29119,29120,29121,29124,29131,29132,29139,29142,29145,29146,29148,29176,29182,29184,29191,29192,29193,29203,29207,29210,29213,29215,29220,29227,29231,29236,29240,29241,29249,29250,29251,29253,29262,29263,29264,29267,29269,29270,29274,29276,29278,29280,29283,29288,29291,29294,29295,29297,29303,29304,29307,29308,29311,29316,29321,29325,29326,29331,29339,29352,29357,29358,29361,29364,29374,29377,29383,29385,29388,29397,29398,29400,29407,29413,29427,29428,29434,29435,29438,29442,29444,29445,29447,29451,29453,29458,29459,29464,29465,29470,29474,29476,29479,29480,29484,29489,29490,29493,29498,29499,29501,29507,29517,29520,29522,29526,29528,29533,29534,29535,29536,29542,29543,29545,29547,29548,29550,29551,29553,29559,29561,29564,29568,29569,29571,29573,29574,29582,29584,29587,29589,29591,29592,29596,29598,29599,29600,29602,29605,29606,29610,29611,29613,29621,29623,29625,29628,29629,29631,29637,29638,29641,29643,29644,29647,29650,29651,29654,29657,29661,29665,29667,29670,29671,29673,29684,29685,29687,29689,29690,29691,29693,29695,29696,29697,29700,29703,29706,29713,29722,29723,29732,29734,29736,29737,29738,29739,29740,29741,29742,29743,29744,29745,29753,29760,29763,29764,29766,29767,29771,29773,29777,29778,29783,29789,29794,29798,29799,29800,29803,29805,29806,29809,29810,29824,29825,29829,29830,29831,29833,29839,29840,29841,29842,29848,29849,29850,29852,29855,29856,29857,29859,29862,29864,29865,29866,29867,29870,29871,29873,29874,29877,29881,29883,29887,29896,29897,29900,29904,29907,29912,29914,29915,29918,29919,29924,29928,29930,29931,29935,29940,29946,29947,29948,29951,29958,29970,29974,29975,29984,29985,29988,29991,29993,29994,29999,30006,30009,30013,30014,30015,30016,30019,30023,30024,30030,30032,30034,30039,30046,30047,30049,30063,30065,30073,30074,30075,30076,30077,30078,30081,30085,30096,30098,30099,30101,30105,30108,30114,30116,30132,30138,30143,30144,30145,30148,30150,30156,30158,30159,30167,30172,30175,30176,30177,30180,30183,30188,30190,30191,30193,30201,30208,30210,30211,30212,30215,30216,30218,30220,30223,30226,30227,30229,30230,30233,30235,30236,30237,30238,30243,30245,30246,30249,30253,30258,30259,30261,30264,30265,30266,30268,30282,30272,30273,30275,30276,30277,30281,30283,30293,30297,30303,30308,30309,30317,30318,30319,30321,30324,30337,30341,30348,30349,30357,30363,30364,30365,30367,30368,30370,30371,30372,30373,30374,30375,30376,30378,30381,30397,30401,30405,30409,30411,30412,30414,30420,30425,30432,30438,30440,30444,30448,30449,30454,30457,30460,30464,30470,30474,30478,30482,30484,30485,30487,30489,30490,30492,30498,30504,30509,30510,30511,30516,30517,30518,30521,30525,30526,30530,30533,30534,30538,30541,30542,30543,30546,30550,30551,30556,30558,30559,30560,30562,30564,30567,30570,30572,30576,30578,30579,30580,30586,30589,30592,30596,30604,30605,30612,30613,30614,30618,30623,30626,30631,30634,30638,30639,30641,30645,30654,30659,30665,30673,30674,30677,30681,30686,30687,30688,30692,30694,30698,30700,30704,30705,30708,30712,30715,30725,30726,30729,30733,30734,30737,30749,30753,30754,30755,30765,30766,30768,30773,30775,30787,30788,30791,30792,30796,30798,30802,30812,30814,30816,30817,30819,30820,30824,30826,30830,30842,30846,30858,30863,30868,30872,30881,30877,30878,30879,30884,30888,30892,30893,30896,30897,30898,30899,30907,30909,30911,30919,30920,30921,30924,30926,30930,30931,30933,30934,30948,30939,30943,30944,30945,30950,30954,30962,30963,30976,30966,30967,30970,30971,30975,30982,30988,30992,31002,31004,31006,31007,31008,31013,31015,31017,31021,31025,31028,31029,31035,31037,31039,31044,31045,31046,31050,31051,31055,31057,31060,31064,31067,31068,31079,31081,31083,31090,31097,31099,31100,31102,31115,31116,31121,31123,31124,31125,31126,31128,31131,31132,31137,31144,31145,31147,31151,31153,31156,31160,31163,31170,31172,31175,31176,31178,31183,31188,31190,31194,31197,31198,31200,31202,31205,31210,31211,31213,31217,31224,31228,31234,31235,31239,31241,31242,31244,31249,31253,31259,31262,31265,31271,31275,31277,31279,31280,31284,31285,31288,31289,31290,31300,31301,31303,31304,31308,31317,31318,31321,31324,31325,31327,31328,31333,31335,31338,31341,31349,31352,31358,31360,31362,31365,31366,31370,31371,31376,31377,31380,31390,31392,31395,31404,31411,31413,31417,31419,31420,31430,31433,31436,31438,31441,31451,31464,31465,31467,31468,31473,31476,31483,31485,31486,31495,31508,31519,31523,31527,31529,31530,31531,31533,31534,31535,31536,31537,31540,31549,31551,31552,31553,31559,31566,31573,31584,31588,31590,31593,31594,31597,31599,31602,31603,31607,31620,31625,31630,31632,31633,31638,31643,31646,31648,31653,31660,31663,31664,31666,31669,31670,31674,31675,31676,31677,31682,31685,31688,31690,31700,31702,31703,31705,31706,31707,31720,31722,31730,31732,31733,31736,31737,31738,31740,31742,31745,31746,31747,31748,31750,31753,31755,31756,31758,31759,31769,31771,31776,31781,31782,31784,31788,31793,31795,31796,31798,31801,31802,31814,31818,31829,31825,31826,31827,31833,31834,31835,31836,31837,31838,31841,31843,31847,31849,31853,31854,31856,31858,31865,31868,31869,31878,31879,31887,31892,31902,31904,31910,31920,31926,31927,31930,31931,31932,31935,31940,31943,31944,31945,31949,31951,31955,31956,31957,31959,31961,31962,31965,31974,31977,31979,31989,32003,32007,32008,32009,32015,32017,32018,32019,32022,32029,32030,32035,32038,32042,32045,32049,32060,32061,32062,32064,32065,32071,32072,32077,32081,32083,32087,32089,32090,32092,32093,32101,32103,32106,32112,32120,32122,32123,32127,32129,32130,32131,32133,32134,32136,32139,32140,32141,32145,32150,32151,32157,32158,32166,32167,32170,32179,32182,32183,32185,32194,32195,32196,32197,32198,32204,32205,32206,32215,32217,32256,32226,32229,32230,32234,32235,32237,32241,32245,32246,32249,32250,32264,32272,32273,32277,32279,32284,32285,32288,32295,32296,32300,32301,32303,32307,32310,32319,32324,32325,32327,32334,32336,32338,32344,32351,32353,32354,32357,32363,32366,32367,32371,32376,32382,32385,32390,32391,32394,32397,32401,32405,32408,32410,32413,32414,32572,32571,32573,32574,32575,32579,32580,32583,32591,32594,32595,32603,32604,32605,32609,32611,32612,32613,32614,32621,32625,32637,32638,32639,32640,32651,32653,32655,32656,32657,32662,32663,32668,32673,32674,32678,32682,32685,32692,32700,32703,32704,32707,32712,32718,32719,32731,32735,32739,32741,32744,32748,32750,32751,32754,32762,32765,32766,32767,32775,32776,32778,32781,32782,32783,32785,32787,32788,32790,32797,32798,32799,32800,32804,32806,32812,32814,32816,32820,32821,32823,32825,32826,32828,32830,32832,32836,32864,32868,32870,32877,32881,32885,32897,32904,32910,32924,32926,32934,32935,32939,32952,32953,32968,32973,32975,32978,32980,32981,32983,32984,32992,33005,33006,33008,33010,33011,33014,33017,33018,33022,33027,33035,33046,33047,33048,33052,33054,33056,33060,33063,33068,33072,33077,33082,33084,33093,33095,33098,33100,33106,33111,33120,33121,33127,33128,33129,33133,33135,33143,33153,33168,33156,33157,33158,33163,33166,33174,33176,33179,33182,33186,33198,33202,33204,33211,33227,33219,33221,33226,33230,33231,33237,33239,33243,33245,33246,33249,33252,33259,33260,33264,33265,33266,33269,33270,33272,33273,33277,33279,33280,33283,33295,33299,33300,33305,33306,33309,33313,33314,33320,33330,33332,33338,33347,33348,33349,33350,33355,33358,33359,33361,33366,33372,33376,33379,33383,33389,33396,33403,33405,33407,33408,33409,33411,33412,33415,33417,33418,33422,33425,33428,33430,33432,33434,33435,33440,33441,33443,33444,33447,33448,33449,33450,33454,33456,33458,33460,33463,33466,33468,33470,33471,33478,33488,33493,33498,33504,33506,33508,33512,33514,33517,33519,33526,33527,33533,33534,33536,33537,33543,33544,33546,33547,33620,33563,33565,33566,33567,33569,33570,33580,33581,33582,33584,33587,33591,33594,33596,33597,33602,33603,33604,33607,33613,33614,33617,33621,33622,33623,33648,33656,33661,33663,33664,33666,33668,33670,33677,33682,33684,33685,33688,33689,33691,33692,33693,33702,33703,33705,33708,33726,33727,33728,33735,33737,33743,33744,33745,33748,33757,33619,33768,33770,33782,33784,33785,33788,33793,33798,33802,33807,33809,33813,33817,33709,33839,33849,33861,33863,33864,33866,33869,33871,33873,33874,33878,33880,33881,33882,33884,33888,33892,33893,33895,33898,33904,33907,33908,33910,33912,33916,33917,33921,33925,33938,33939,33941,33950,33958,33960,33961,33962,33967,33969,33972,33978,33981,33982,33984,33986,33991,33992,33996,33999,34003,34012,34023,34026,34031,34032,34033,34034,34039,34098,34042,34043,34045,34050,34051,34055,34060,34062,34064,34076,34078,34082,34083,34084,34085,34087,34090,34091,34095,34099,34100,34102,34111,34118,34127,34128,34129,34130,34131,34134,34137,34140,34141,34142,34143,34144,34145,34146,34148,34155,34159,34169,34170,34171,34173,34175,34177,34181,34182,34185,34187,34188,34191,34195,34200,34205,34207,34208,34210,34213,34215,34228,34230,34231,34232,34236,34237,34238,34239,34242,34247,34250,34251,34254,34221,34264,34266,34271,34272,34278,34280,34285,34291,34294,34300,34303,34304,34308,34309,34317,34318,34320,34321,34322,34328,34329,34331,34334,34337,34343,34345,34358,34360,34362,34364,34365,34368,34370,34374,34386,34387,34390,34391,34392,34393,34397,34400,34401,34402,34403,34404,34409,34412,34415,34421,34422,34423,34426,34445,34449,34454,34456,34458,34460,34465,34470,34471,34472,34477,34481,34483,34484,34485,34487,34488,34489,34495,34496,34497,34499,34501,34513,34514,34517,34519,34522,34524,34528,34531,34533,34535,34440,34554,34556,34557,34564,34565,34567,34571,34574,34575,34576,34579,34580,34585,34590,34591,34593,34595,34600,34606,34607,34609,34610,34617,34618,34620,34621,34622,34624,34627,34629,34637,34648,34653,34657,34660,34661,34671,34673,34674,34683,34691,34692,34693,34694,34695,34696,34697,34699,34700,34704,34707,34709,34711,34712,34713,34718,34720,34723,34727,34732,34733,34734,34737,34741,34750,34751,34753,34760,34761,34762,34766,34773,34774,34777,34778,34780,34783,34786,34787,34788,34794,34795,34797,34801,34803,34808,34810,34815,34817,34819,34822,34825,34826,34827,34832,34841,34834,34835,34836,34840,34842,34843,34844,34846,34847,34856,34861,34862,34864,34866,34869,34874,34876,34881,34883,34885,34888,34889,34890,34891,34894,34897,34901,34902,34904,34906,34908,34911,34912,34916,34921,34929,34937,34939,34944,34968,34970,34971,34972,34975,34976,34984,34986,35002,35005,35006,35008,35018,35019,35020,35021,35022,35025,35026,35027,35035,35038,35047,35055,35056,35057,35061,35063,35073,35078,35085,35086,35087,35093,35094,35096,35097,35098,35100,35104,35110,35111,35112,35120,35121,35122,35125,35129,35130,35134,35136,35138,35141,35142,35145,35151,35154,35159,35162,35163,35164,35169,35170,35171,35179,35182,35184,35187,35189,35194,35195,35196,35197,35209,35213,35216,35220,35221,35227,35228,35231,35232,35237,35248,35252,35253,35254,35255,35260,35284,35285,35286,35287,35288,35301,35305,35307,35309,35313,35315,35318,35321,35325,35327,35332,35333,35335,35343,35345,35346,35348,35349,35358,35360,35362,35364,35366,35371,35372,35375,35381,35383,35389,35390,35392,35395,35397,35399,35401,35405,35406,35411,35414,35415,35416,35420,35421,35425,35429,35431,35445,35446,35447,35449,35450,35451,35454,35455,35456,35459,35462,35467,35471,35472,35474,35478,35479,35481,35487,35495,35497,35502,35503,35507,35510,35511,35515,35518,35523,35526,35528,35529,35530,35537,35539,35540,35541,35543,35549,35551,35564,35568,35572,35573,35574,35580,35583,35589,35590,35595,35601,35612,35614,35615,35594,35629,35632,35639,35644,35650,35651,35652,35653,35654,35656,35666,35667,35668,35673,35661,35678,35683,35693,35702,35704,35705,35708,35710,35713,35716,35717,35723,35725,35727,35732,35733,35740,35742,35743,35896,35897,35901,35902,35909,35911,35913,35915,35919,35921,35923,35924,35927,35928,35931,35933,35929,35939,35940,35942,35944,35945,35949,35955,35957,35958,35963,35966,35974,35975,35979,35984,35986,35987,35993,35995,35996,36004,36025,36026,36037,36038,36041,36043,36047,36054,36053,36057,36061,36065,36072,36076,36079,36080,36082,36085,36087,36088,36094,36095,36097,36099,36105,36114,36119,36123,36197,36201,36204,36206,36223,36226,36228,36232,36237,36240,36241,36245,36254,36255,36256,36262,36267,36268,36271,36274,36277,36279,36281,36283,36288,36293,36294,36295,36296,36298,36302,36305,36308,36309,36311,36313,36324,36325,36327,36332,36336,36284,36337,36338,36340,36349,36353,36356,36357,36358,36363,36369,36372,36374,36384,36385,36386,36387,36390,36391,36401,36403,36406,36407,36408,36409,36413,36416,36417,36427,36429,36430,36431,36436,36443,36444,36445,36446,36449,36450,36457,36460,36461,36463,36464,36465,36473,36474,36475,36482,36483,36489,36496,36498,36501,36506,36507,36509,36510,36514,36519,36521,36525,36526,36531,36533,36538,36539,36544,36545,36547,36548,36551,36559,36561,36564,36572,36584,36590,36592,36593,36599,36601,36602,36589,36608,36610,36615,36616,36623,36624,36630,36631,36632,36638,36640,36641,36643,36645,36647,36648,36652,36653,36654,36660,36661,36662,36663,36666,36672,36673,36675,36679,36687,36689,36690,36691,36692,36693,36696,36701,36702,36709,36765,36768,36769,36772,36773,36774,36789,36790,36792,36798,36800,36801,36806,36810,36811,36813,36816,36818,36819,36821,36832,36835,36836,36840,36846,36849,36853,36854,36859,36862,36866,36868,36872,36876,36888,36891,36904,36905,36911,36906,36908,36909,36915,36916,36919,36927,36931,36932,36940,36955,36957,36962,36966,36967,36972,36976,36980,36985,36997,37000,37003,37004,37006,37008,37013,37015,37016,37017,37019,37024,37025,37026,37029,37040,37042,37043,37044,37046,37053,37068,37054,37059,37060,37061,37063,37064,37077,37079,37080,37081,37084,37085,37087,37093,37074,37110,37099,37103,37104,37108,37118,37119,37120,37124,37125,37126,37128,37133,37136,37140,37142,37143,37144,37146,37148,37150,37152,37157,37154,37155,37159,37161,37166,37167,37169,37172,37174,37175,37177,37178,37180,37181,37187,37191,37192,37199,37203,37207,37209,37210,37211,37217,37220,37223,37229,37236,37241,37242,37243,37249,37251,37253,37254,37258,37262,37265,37267,37268,37269,37272,37278,37281,37286,37288,37292,37293,37294,37296,37297,37298,37299,37302,37307,37308,37309,37311,37314,37315,37317,37331,37332,37335,37337,37338,37342,37348,37349,37353,37354,37356,37357,37358,37359,37360,37361,37367,37369,37371,37373,37376,37377,37380,37381,37382,37383,37385,37386,37388,37392,37394,37395,37398,37400,37404,37405,37411,37412,37413,37414,37416,37422,37423,37424,37427,37429,37430,37432,37433,37434,37436,37438,37440,37442,37443,37446,37447,37450,37453,37454,37455,37457,37464,37465,37468,37469,37472,37473,37477,37479,37480,37481,37486,37487,37488,37493,37494,37495,37496,37497,37499,37500,37501,37503,37512,37513,37514,37517,37518,37522,37527,37529,37535,37536,37540,37541,37543,37544,37547,37551,37554,37558,37560,37562,37563,37564,37565,37567,37568,37569,37570,37571,37573,37574,37575,37576,37579,37580,37581,37582,37584,37587,37589,37591,37592,37593,37596,37597,37599,37600,37601,37603,37605,37607,37608,37612,37614,37616,37625,37627,37631,37632,37634,37640,37645,37649,37652,37653,37660,37661,37662,37663,37665,37668,37669,37671,37673,37674,37683,37684,37686,37687,37703,37704,37705,37712,37713,37714,37717,37719,37720,37722,37726,37732,37733,37735,37737,37738,37741,37743,37744,37745,37747,37748,37750,37754,37757,37759,37760,37761,37762,37768,37770,37771,37773,37775,37778,37781,37784,37787,37790,37793,37795,37796,37798,37800,37803,37812,37813,37814,37818,37801,37825,37828,37829,37830,37831,37833,37834,37835,37836,37837,37843,37849,37852,37854,37855,37858,37862,37863,37881,37879,37880,37882,37883,37885,37889,37890,37892,37896,37897,37901,37902,37903,37909,37910,37911,37919,37934,37935,37937,37938,37939,37940,37947,37951,37949,37955,37957,37960,37962,37964,37973,37977,37980,37983,37985,37987,37992,37995,37997,37998,37999,38001,38002,38020,38019,38264,38265,38270,38276,38280,38284,38285,38286,38301,38302,38303,38305,38310,38313,38315,38316,38324,38326,38330,38333,38335,38342,38344,38345,38347,38352,38353,38354,38355,38361,38362,38365,38366,38367,38368,38372,38374,38429,38430,38434,38436,38437,38438,38444,38449,38451,38455,38456,38457,38458,38460,38461,38465,38482,38484,38486,38487,38488,38497,38510,38516,38523,38524,38526,38527,38529,38530,38531,38532,38537,38545,38550,38554,38557,38559,38564,38565,38566,38569,38574,38575,38579,38586,38602,38610,23986,38616,38618,38621,38622,38623,38633,38639,38641,38650,38658,38659,38661,38665,38682,38683,38685,38689,38690,38691,38696,38705,38707,38721,38723,38730,38734,38735,38741,38743,38744,38746,38747,38755,38759,38762,38766,38771,38774,38775,38776,38779,38781,38783,38784,38793,38805,38806,38807,38809,38810,38814,38815,38818,38828,38830,38833,38834,38837,38838,38840,38841,38842,38844,38846,38847,38849,38852,38853,38855,38857,38858,38860,38861,38862,38864,38865,38868,38871,38872,38873,38877,38878,38880,38875,38881,38884,38895,38897,38900,38903,38904,38906,38919,38922,38937,38925,38926,38932,38934,38940,38942,38944,38947,38950,38955,38958,38959,38960,38962,38963,38965,38949,38974,38980,38983,38986,38993,38994,38995,38998,38999,39001,39002,39010,39011,39013,39014,39018,39020,39083,39085,39086,39088,39092,39095,39096,39098,39099,39103,39106,39109,39112,39116,39137,39139,39141,39142,39143,39146,39155,39158,39170,39175,39176,39185,39189,39190,39191,39194,39195,39196,39199,39202,39206,39207,39211,39217,39218,39219,39220,39221,39225,39226,39227,39228,39232,39233,39238,39239,39240,39245,39246,39252,39256,39257,39259,39260,39262,39263,39264,39323,39325,39327,39334,39344,39345,39346,39349,39353,39354,39357,39359,39363,39369,39379,39380,39385,39386,39388,39390,39399,39402,39403,39404,39408,39412,39413,39417,39421,39422,39426,39427,39428,39435,39436,39440,39441,39446,39454,39456,39458,39459,39460,39463,39469,39470,39475,39477,39478,39480,39495,39489,39492,39498,39499,39500,39502,39505,39508,39510,39517,39594,39596,39598,39599,39602,39604,39605,39606,39609,39611,39614,39615,39617,39619,39622,39624,39630,39632,39634,39637,39638,39639,39643,39644,39648,39652,39653,39655,39657,39660,39666,39667,39669,39673,39674,39677,39679,39680,39681,39682,39683,39684,39685,39688,39689,39691,39692,39693,39694,39696,39698,39702,39705,39707,39708,39712,39718,39723,39725,39731,39732,39733,39735,39737,39738,39741,39752,39755,39756,39765,39766,39767,39771,39774,39777,39779,39781,39782,39784,39786,39787,39788,39789,39790,39795,39797,39799,39800,39801,39807,39808,39812,39813,39814,39815,39817,39818,39819,39821,39823,39824,39828,39834,39837,39838,39846,39847,39849,39852,39856,39857,39858,39863,39864,39867,39868,39870,39871,39873,39879,39880,39886,39888,39895,39896,39901,39903,39909,39911,39914,39915,39919,39923,39927,39928,39929,39930,39933,39935,39936,39938,39947,39951,39953,39958,39960,39961,39962,39964,39966,39970,39971,39974,39975,39976,39977,39978,39985,39989,39990,39991,39997,40001,40003,40004,40005,40009,40010,40014,40015,40016,40019,40020,40022,40024,40027,40029,40030,40031,40035,40041,40042,40028,40043,40040,40046,40048,40050,40053,40055,40059,40166,40178,40183,40185,40203,40194,40209,40215,40216,40220,40221,40222,40239,40240,40242,40243,40244,40250,40252,40261,40253,40258,40259,40263,40266,40275,40276,40287,40291,40290,40293,40297,40298,40299,40304,40310,40311,40315,40316,40318,40323,40324,40326,40330,40333,40334,40338,40339,40341,40342,40343,40344,40353,40362,40364,40366,40369,40373,40377,40380,40383,40387,40391,40393,40394,40404,40405,40406,40407,40410,40414,40415,40416,40421,40423,40425,40427,40430,40432,40435,40436,40446,40458,40450,40455,40462,40464,40465,40466,40469,40470,40473,40476,40477,40570,40571,40572,40576,40578,40579,40580,40581,40583,40590,40591,40598,40600,40603,40606,40612,40616,40620,40622,40623,40624,40627,40628,40629,40646,40648,40651,40661,40671,40676,40679,40684,40685,40686,40688,40689,40690,40693,40696,40703,40706,40707,40713,40719,40720,40721,40722,40724,40726,40727,40729,40730,40731,40735,40738,40742,40746,40747,40751,40753,40754,40756,40759,40761,40762,40764,40765,40767,40769,40771,40772,40773,40774,40775,40787,40789,40790,40791,40792,40794,40797,40798,40808,40809,40813,40814,40815,40816,40817,40819,40821,40826,40829,40847,40848,40849,40850,40852,40854,40855,40862,40865,40866,40867,40869,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],
+ "ibm866":[1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,9617,9618,9619,9474,9508,9569,9570,9558,9557,9571,9553,9559,9565,9564,9563,9488,9492,9524,9516,9500,9472,9532,9566,9567,9562,9556,9577,9574,9568,9552,9580,9575,9576,9572,9573,9561,9560,9554,9555,9579,9578,9496,9484,9608,9604,9612,9616,9600,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,1025,1105,1028,1108,1031,1111,1038,1118,176,8729,183,8730,8470,164,9632,160],
+ "iso-8859-2":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,260,728,321,164,317,346,167,168,352,350,356,377,173,381,379,176,261,731,322,180,318,347,711,184,353,351,357,378,733,382,380,340,193,194,258,196,313,262,199,268,201,280,203,282,205,206,270,272,323,327,211,212,336,214,215,344,366,218,368,220,221,354,223,341,225,226,259,228,314,263,231,269,233,281,235,283,237,238,271,273,324,328,243,244,337,246,247,345,367,250,369,252,253,355,729],
+ "iso-8859-3":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,294,728,163,164,null,292,167,168,304,350,286,308,173,null,379,176,295,178,179,180,181,293,183,184,305,351,287,309,189,null,380,192,193,194,null,196,266,264,199,200,201,202,203,204,205,206,207,null,209,210,211,212,288,214,215,284,217,218,219,220,364,348,223,224,225,226,null,228,267,265,231,232,233,234,235,236,237,238,239,null,241,242,243,244,289,246,247,285,249,250,251,252,365,349,729],
+ "iso-8859-4":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,260,312,342,164,296,315,167,168,352,274,290,358,173,381,175,176,261,731,343,180,297,316,711,184,353,275,291,359,330,382,331,256,193,194,195,196,197,198,302,268,201,280,203,278,205,206,298,272,325,332,310,212,213,214,215,216,370,218,219,220,360,362,223,257,225,226,227,228,229,230,303,269,233,281,235,279,237,238,299,273,326,333,311,244,245,246,247,248,371,250,251,252,361,363,729],
+ "iso-8859-5":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,1025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,173,1038,1039,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103,8470,1105,1106,1107,1108,1109,1110,1111,1112,1113,1114,1115,1116,167,1118,1119],
+ "iso-8859-6":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,null,null,null,164,null,null,null,null,null,null,null,1548,173,null,null,null,null,null,null,null,null,null,null,null,null,null,1563,null,null,null,1567,null,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,1591,1592,1593,1594,null,null,null,null,null,1600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,1615,1616,1617,1618,null,null,null,null,null,null,null,null,null,null,null,null,null],
+ "iso-8859-7":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,8216,8217,163,8364,8367,166,167,168,169,890,171,172,173,null,8213,176,177,178,179,900,901,902,183,904,905,906,187,908,189,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,null,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,null],
+ "iso-8859-8":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,null,162,163,164,165,166,167,168,169,215,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,247,187,188,189,190,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,8215,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,null,null,8206,8207,null],
+ "iso-8859-10":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,260,274,290,298,296,310,167,315,272,352,358,381,173,362,330,176,261,275,291,299,297,311,183,316,273,353,359,382,8213,363,331,256,193,194,195,196,197,198,302,268,201,280,203,278,205,206,207,208,325,332,211,212,213,214,360,216,370,218,219,220,221,222,223,257,225,226,227,228,229,230,303,269,233,281,235,279,237,238,239,240,326,333,243,244,245,246,361,248,371,250,251,252,253,254,312],
+ "iso-8859-13":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,8221,162,163,164,8222,166,167,216,169,342,171,172,173,174,198,176,177,178,179,8220,181,182,183,248,185,343,187,188,189,190,230,260,302,256,262,196,197,280,274,268,201,377,278,290,310,298,315,352,323,325,211,332,213,214,215,370,321,346,362,220,379,381,223,261,303,257,263,228,229,281,275,269,233,378,279,291,311,299,316,353,324,326,243,333,245,246,247,371,322,347,363,252,380,382,8217],
+ "iso-8859-14":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,7682,7683,163,266,267,7690,167,7808,169,7810,7691,7922,173,174,376,7710,7711,288,289,7744,7745,182,7766,7809,7767,7811,7776,7923,7812,7813,7777,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,372,209,210,211,212,213,214,7786,216,217,218,219,220,221,374,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,373,241,242,243,244,245,246,7787,248,249,250,251,252,253,375,255],
+ "iso-8859-15":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,8364,165,352,167,353,169,170,171,172,173,174,175,176,177,178,179,381,181,182,183,382,185,186,187,338,339,376,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255],
+ "iso-8859-16":[128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,260,261,321,8364,8222,352,167,353,169,536,171,377,173,378,379,176,177,268,322,381,8221,182,183,382,269,537,187,338,339,376,380,192,193,194,258,196,262,198,199,200,201,202,203,204,205,206,207,272,323,210,211,212,336,214,346,368,217,218,219,220,280,538,223,224,225,226,259,228,263,230,231,232,233,234,235,236,237,238,239,273,324,242,243,244,337,246,347,369,249,250,251,252,281,539,255],
+ "koi8-r":[9472,9474,9484,9488,9492,9496,9500,9508,9516,9524,9532,9600,9604,9608,9612,9616,9617,9618,9619,8992,9632,8729,8730,8776,8804,8805,160,8993,176,178,183,247,9552,9553,9554,1105,9555,9556,9557,9558,9559,9560,9561,9562,9563,9564,9565,9566,9567,9568,9569,1025,9570,9571,9572,9573,9574,9575,9576,9577,9578,9579,9580,169,1102,1072,1073,1094,1076,1077,1092,1075,1093,1080,1081,1082,1083,1084,1085,1086,1087,1103,1088,1089,1090,1091,1078,1074,1100,1099,1079,1096,1101,1097,1095,1098,1070,1040,1041,1062,1044,1045,1060,1043,1061,1048,1049,1050,1051,1052,1053,1054,1055,1071,1056,1057,1058,1059,1046,1042,1068,1067,1047,1064,1069,1065,1063,1066],
+ "koi8-u":[9472,9474,9484,9488,9492,9496,9500,9508,9516,9524,9532,9600,9604,9608,9612,9616,9617,9618,9619,8992,9632,8729,8730,8776,8804,8805,160,8993,176,178,183,247,9552,9553,9554,1105,1108,9556,1110,1111,9559,9560,9561,9562,9563,1169,1118,9566,9567,9568,9569,1025,1028,9571,1030,1031,9574,9575,9576,9577,9578,1168,1038,169,1102,1072,1073,1094,1076,1077,1092,1075,1093,1080,1081,1082,1083,1084,1085,1086,1087,1103,1088,1089,1090,1091,1078,1074,1100,1099,1079,1096,1101,1097,1095,1098,1070,1040,1041,1062,1044,1045,1060,1043,1061,1048,1049,1050,1051,1052,1053,1054,1055,1071,1056,1057,1058,1059,1046,1042,1068,1067,1047,1064,1069,1065,1063,1066],
+ "macintosh":[196,197,199,201,209,214,220,225,224,226,228,227,229,231,233,232,234,235,237,236,238,239,241,243,242,244,246,245,250,249,251,252,8224,176,162,163,167,8226,182,223,174,169,8482,180,168,8800,198,216,8734,177,8804,8805,165,181,8706,8721,8719,960,8747,170,186,937,230,248,191,161,172,8730,402,8776,8710,171,187,8230,160,192,195,213,338,339,8211,8212,8220,8221,8216,8217,247,9674,255,376,8260,8364,8249,8250,64257,64258,8225,183,8218,8222,8240,194,202,193,203,200,205,206,207,204,211,212,63743,210,218,219,217,305,710,732,175,728,729,730,184,733,731,711],
+ "windows-874":[8364,129,130,131,132,8230,134,135,136,137,138,139,140,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,152,153,154,155,156,157,158,159,160,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,null,null,null,null,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,3674,3675,null,null,null,null],
+ "windows-1250":[8364,129,8218,131,8222,8230,8224,8225,136,8240,352,8249,346,356,381,377,144,8216,8217,8220,8221,8226,8211,8212,152,8482,353,8250,347,357,382,378,160,711,728,321,164,260,166,167,168,169,350,171,172,173,174,379,176,177,731,322,180,181,182,183,184,261,351,187,317,733,318,380,340,193,194,258,196,313,262,199,268,201,280,203,282,205,206,270,272,323,327,211,212,336,214,215,344,366,218,368,220,221,354,223,341,225,226,259,228,314,263,231,269,233,281,235,283,237,238,271,273,324,328,243,244,337,246,247,345,367,250,369,252,253,355,729],
+ "windows-1251":[1026,1027,8218,1107,8222,8230,8224,8225,8364,8240,1033,8249,1034,1036,1035,1039,1106,8216,8217,8220,8221,8226,8211,8212,152,8482,1113,8250,1114,1116,1115,1119,160,1038,1118,1032,164,1168,166,167,1025,169,1028,171,172,173,174,1031,176,177,1030,1110,1169,181,182,183,1105,8470,1108,187,1112,1029,1109,1111,1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,1103],
+ "windows-1252":[8364,129,8218,402,8222,8230,8224,8225,710,8240,352,8249,338,141,381,143,144,8216,8217,8220,8221,8226,8211,8212,732,8482,353,8250,339,157,382,376,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255],
+ "windows-1253":[8364,129,8218,402,8222,8230,8224,8225,136,8240,138,8249,140,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,152,8482,154,8250,156,157,158,159,160,901,902,163,164,165,166,167,168,169,null,171,172,173,174,8213,176,177,178,179,900,181,182,183,904,905,906,187,908,189,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,null,931,932,933,934,935,936,937,938,939,940,941,942,943,944,945,946,947,948,949,950,951,952,953,954,955,956,957,958,959,960,961,962,963,964,965,966,967,968,969,970,971,972,973,974,null],
+ "windows-1254":[8364,129,8218,402,8222,8230,8224,8225,710,8240,352,8249,338,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,732,8482,353,8250,339,157,158,376,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,286,209,210,211,212,213,214,215,216,217,218,219,220,304,350,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,287,241,242,243,244,245,246,247,248,249,250,251,252,305,351,255],
+ "windows-1255":[8364,129,8218,402,8222,8230,8224,8225,710,8240,138,8249,140,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,732,8482,154,8250,156,157,158,159,160,161,162,163,8362,165,166,167,168,169,215,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,247,187,188,189,190,191,1456,1457,1458,1459,1460,1461,1462,1463,1464,1465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1520,1521,1522,1523,1524,null,null,null,null,null,null,null,1488,1489,1490,1491,1492,1493,1494,1495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,1510,1511,1512,1513,1514,null,null,8206,8207,null],
+ "windows-1256":[8364,1662,8218,402,8222,8230,8224,8225,710,8240,1657,8249,338,1670,1688,1672,1711,8216,8217,8220,8221,8226,8211,8212,1705,8482,1681,8250,339,8204,8205,1722,160,1548,162,163,164,165,166,167,168,169,1726,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,1563,187,188,189,190,1567,1729,1569,1570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,1585,1586,1587,1588,1589,1590,215,1591,1592,1593,1594,1600,1601,1602,1603,224,1604,226,1605,1606,1607,1608,231,232,233,234,235,1609,1610,238,239,1611,1612,1613,1614,244,1615,1616,247,1617,249,1618,251,252,8206,8207,1746],
+ "windows-1257":[8364,129,8218,131,8222,8230,8224,8225,136,8240,138,8249,140,168,711,184,144,8216,8217,8220,8221,8226,8211,8212,152,8482,154,8250,156,175,731,159,160,null,162,163,164,null,166,167,216,169,342,171,172,173,174,198,176,177,178,179,180,181,182,183,248,185,343,187,188,189,190,230,260,302,256,262,196,197,280,274,268,201,377,278,290,310,298,315,352,323,325,211,332,213,214,215,370,321,346,362,220,379,381,223,261,303,257,263,228,229,281,275,269,233,378,279,291,311,299,316,353,324,326,243,333,245,246,247,371,322,347,363,252,380,382,729],
+ "windows-1258":[8364,129,8218,402,8222,8230,8224,8225,710,8240,138,8249,338,141,142,143,144,8216,8217,8220,8221,8226,8211,8212,732,8482,154,8250,339,157,158,376,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,258,196,197,198,199,200,201,202,203,768,205,206,207,272,209,777,211,212,416,214,215,216,217,218,219,220,431,771,223,224,225,226,259,228,229,230,231,232,233,234,235,769,237,238,239,273,241,803,243,244,417,246,247,248,249,250,251,252,432,8363,255],
+ "x-mac-cyrillic":[1040,1041,1042,1043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,8224,176,1168,163,167,8226,182,1030,174,169,8482,1026,1106,8800,1027,1107,8734,177,8804,8805,1110,181,1169,1032,1028,1108,1031,1111,1033,1113,1034,1114,1112,1029,172,8730,402,8776,8710,171,187,8230,160,1035,1115,1036,1116,1109,8211,8212,8220,8221,8216,8217,247,8222,1038,1118,1039,1119,8470,1025,1105,1103,1072,1073,1074,1075,1076,1077,1078,1079,1080,1081,1082,1083,1084,1085,1086,1087,1088,1089,1090,1091,1092,1093,1094,1095,1096,1097,1098,1099,1100,1101,1102,8364]
+};
+
+// For strict environments where `this` inside the global scope
+// is `undefined`, take a pure object instead
+}(this || {}));
+},{}],71:[function(require,module,exports){
+// This is free and unencumbered software released into the public domain.
+// See LICENSE.md for more information.
+
+/**
+ * @fileoverview Global |this| required for resolving indexes in node.
+ * @suppress {globalThis}
+ */
+(function(global) {
+ 'use strict';
+
+ // If we're in node require encoding-indexes and attach it to the global.
+ if (typeof module !== "undefined" && module.exports &&
+ !global["encoding-indexes"]) {
+ global["encoding-indexes"] =
+ require("./encoding-indexes.js")["encoding-indexes"];
+ }
+
+ //
+ // Utilities
+ //
+
+ /**
+ * @param {number} a The number to test.
+ * @param {number} min The minimum value in the range, inclusive.
+ * @param {number} max The maximum value in the range, inclusive.
+ * @return {boolean} True if a >= min and a <= max.
+ */
+ function inRange(a, min, max) {
+ return min <= a && a <= max;
+ }
+
+ /**
+ * @param {!Array.<*>} array The array to check.
+ * @param {*} item The item to look for in the array.
+ * @return {boolean} True if the item appears in the array.
+ */
+ function includes(array, item) {
+ return array.indexOf(item) !== -1;
+ }
+
+ var floor = Math.floor;
+
+ /**
+ * @param {*} o
+ * @return {Object}
+ */
+ function ToDictionary(o) {
+ if (o === undefined) return {};
+ if (o === Object(o)) return o;
+ throw TypeError('Could not convert argument to dictionary');
+ }
+
+ /**
+ * @param {string} string Input string of UTF-16 code units.
+ * @return {!Array.<number>} Code points.
+ */
+ function stringToCodePoints(string) {
+ // https://heycam.github.io/webidl/#dfn-obtain-unicode
+
+ // 1. Let S be the DOMString value.
+ var s = String(string);
+
+ // 2. Let n be the length of S.
+ var n = s.length;
+
+ // 3. Initialize i to 0.
+ var i = 0;
+
+ // 4. Initialize U to be an empty sequence of Unicode characters.
+ var u = [];
+
+ // 5. While i < n:
+ while (i < n) {
+
+ // 1. Let c be the code unit in S at index i.
+ var c = s.charCodeAt(i);
+
+ // 2. Depending on the value of c:
+
+ // c < 0xD800 or c > 0xDFFF
+ if (c < 0xD800 || c > 0xDFFF) {
+ // Append to U the Unicode character with code point c.
+ u.push(c);
+ }
+
+ // 0xDC00 ≤ c ≤ 0xDFFF
+ else if (0xDC00 <= c && c <= 0xDFFF) {
+ // Append to U a U+FFFD REPLACEMENT CHARACTER.
+ u.push(0xFFFD);
+ }
+
+ // 0xD800 ≤ c ≤ 0xDBFF
+ else if (0xD800 <= c && c <= 0xDBFF) {
+ // 1. If i = n−1, then append to U a U+FFFD REPLACEMENT
+ // CHARACTER.
+ if (i === n - 1) {
+ u.push(0xFFFD);
+ }
+ // 2. Otherwise, i < n−1:
+ else {
+ // 1. Let d be the code unit in S at index i+1.
+ var d = s.charCodeAt(i + 1);
+
+ // 2. If 0xDC00 ≤ d ≤ 0xDFFF, then:
+ if (0xDC00 <= d && d <= 0xDFFF) {
+ // 1. Let a be c & 0x3FF.
+ var a = c & 0x3FF;
+
+ // 2. Let b be d & 0x3FF.
+ var b = d & 0x3FF;
+
+ // 3. Append to U the Unicode character with code point
+ // 2^16+2^10*a+b.
+ u.push(0x10000 + (a << 10) + b);
+
+ // 4. Set i to i+1.
+ i += 1;
+ }
+
+ // 3. Otherwise, d < 0xDC00 or d > 0xDFFF. Append to U a
+ // U+FFFD REPLACEMENT CHARACTER.
+ else {
+ u.push(0xFFFD);
+ }
+ }
+ }
+
+ // 3. Set i to i+1.
+ i += 1;
+ }
+
+ // 6. Return U.
+ return u;
+ }
+
+ /**
+ * @param {!Array.<number>} code_points Array of code points.
+ * @return {string} string String of UTF-16 code units.
+ */
+ function codePointsToString(code_points) {
+ var s = '';
+ for (var i = 0; i < code_points.length; ++i) {
+ var cp = code_points[i];
+ if (cp <= 0xFFFF) {
+ s += String.fromCharCode(cp);
+ } else {
+ cp -= 0x10000;
+ s += String.fromCharCode((cp >> 10) + 0xD800,
+ (cp & 0x3FF) + 0xDC00);
+ }
+ }
+ return s;
+ }
+
+
+ //
+ // Implementation of Encoding specification
+ // https://encoding.spec.whatwg.org/
+ //
+
+ //
+ // 4. Terminology
+ //
+
+ /**
+ * An ASCII byte is a byte in the range 0x00 to 0x7F, inclusive.
+ * @param {number} a The number to test.
+ * @return {boolean} True if a is in the range 0x00 to 0x7F, inclusive.
+ */
+ function isASCIIByte(a) {
+ return 0x00 <= a && a <= 0x7F;
+ }
+
+ /**
+ * An ASCII code point is a code point in the range U+0000 to
+ * U+007F, inclusive.
+ */
+ var isASCIICodePoint = isASCIIByte;
+
+
+ /**
+ * End-of-stream is a special token that signifies no more tokens
+ * are in the stream.
+ * @const
+ */ var end_of_stream = -1;
+
+ /**
+ * A stream represents an ordered sequence of tokens.
+ *
+ * @constructor
+ * @param {!(Array.<number>|Uint8Array)} tokens Array of tokens that provide
+ * the stream.
+ */
+ function Stream(tokens) {
+ /** @type {!Array.<number>} */
+ this.tokens = [].slice.call(tokens);
+ // Reversed as push/pop is more efficient than shift/unshift.
+ this.tokens.reverse();
+ }
+
+ Stream.prototype = {
+ /**
+ * @return {boolean} True if end-of-stream has been hit.
+ */
+ endOfStream: function() {
+ return !this.tokens.length;
+ },
+
+ /**
+ * When a token is read from a stream, the first token in the
+ * stream must be returned and subsequently removed, and
+ * end-of-stream must be returned otherwise.
+ *
+ * @return {number} Get the next token from the stream, or
+ * end_of_stream.
+ */
+ read: function() {
+ if (!this.tokens.length)
+ return end_of_stream;
+ return this.tokens.pop();
+ },
+
+ /**
+ * When one or more tokens are prepended to a stream, those tokens
+ * must be inserted, in given order, before the first token in the
+ * stream.
+ *
+ * @param {(number|!Array.<number>)} token The token(s) to prepend to the
+ * stream.
+ */
+ prepend: function(token) {
+ if (Array.isArray(token)) {
+ var tokens = /**@type {!Array.<number>}*/(token);
+ while (tokens.length)
+ this.tokens.push(tokens.pop());
+ } else {
+ this.tokens.push(token);
+ }
+ },
+
+ /**
+ * When one or more tokens are pushed to a stream, those tokens
+ * must be inserted, in given order, after the last token in the
+ * stream.
+ *
+ * @param {(number|!Array.<number>)} token The tokens(s) to push to the
+ * stream.
+ */
+ push: function(token) {
+ if (Array.isArray(token)) {
+ var tokens = /**@type {!Array.<number>}*/(token);
+ while (tokens.length)
+ this.tokens.unshift(tokens.shift());
+ } else {
+ this.tokens.unshift(token);
+ }
+ }
+ };
+
+ //
+ // 5. Encodings
+ //
+
+ // 5.1 Encoders and decoders
+
+ /** @const */
+ var finished = -1;
+
+ /**
+ * @param {boolean} fatal If true, decoding errors raise an exception.
+ * @param {number=} opt_code_point Override the standard fallback code point.
+ * @return {number} The code point to insert on a decoding error.
+ */
+ function decoderError(fatal, opt_code_point) {
+ if (fatal)
+ throw TypeError('Decoder error');
+ return opt_code_point || 0xFFFD;
+ }
+
+ /**
+ * @param {number} code_point The code point that could not be encoded.
+ * @return {number} Always throws, no value is actually returned.
+ */
+ function encoderError(code_point) {
+ throw TypeError('The code point ' + code_point + ' could not be encoded.');
+ }
+
+ /** @interface */
+ function Decoder() {}
+ Decoder.prototype = {
+ /**
+ * @param {Stream} stream The stream of bytes being decoded.
+ * @param {number} bite The next byte read from the stream.
+ * @return {?(number|!Array.<number>)} The next code point(s)
+ * decoded, or null if not enough data exists in the input
+ * stream to decode a complete code point, or |finished|.
+ */
+ handler: function(stream, bite) {}
+ };
+
+ /** @interface */
+ function Encoder() {}
+ Encoder.prototype = {
+ /**
+ * @param {Stream} stream The stream of code points being encoded.
+ * @param {number} code_point Next code point read from the stream.
+ * @return {(number|!Array.<number>)} Byte(s) to emit, or |finished|.
+ */
+ handler: function(stream, code_point) {}
+ };
+
+ // 5.2 Names and labels
+
+ // TODO: Define @typedef for Encoding: {name:string,labels:Array.<string>}
+ // https://github.com/google/closure-compiler/issues/247
+
+ /**
+ * @param {string} label The encoding label.
+ * @return {?{name:string,labels:Array.<string>}}
+ */
+ function getEncoding(label) {
+ // 1. Remove any leading and trailing ASCII whitespace from label.
+ label = String(label).trim().toLowerCase();
+
+ // 2. If label is an ASCII case-insensitive match for any of the
+ // labels listed in the table below, return the corresponding
+ // encoding, and failure otherwise.
+ if (Object.prototype.hasOwnProperty.call(label_to_encoding, label)) {
+ return label_to_encoding[label];
+ }
+ return null;
+ }
+
+ /**
+ * Encodings table: https://encoding.spec.whatwg.org/encodings.json
+ * @const
+ * @type {!Array.<{
+ * heading: string,
+ * encodings: Array.<{name:string,labels:Array.<string>}>
+ * }>}
+ */
+ var encodings = [
+ {
+ "encodings": [
+ {
+ "labels": [
+ "unicode-1-1-utf-8",
+ "utf-8",
+ "utf8"
+ ],
+ "name": "UTF-8"
+ }
+ ],
+ "heading": "The Encoding"
+ },
+ {
+ "encodings": [
+ {
+ "labels": [
+ "866",
+ "cp866",
+ "csibm866",
+ "ibm866"
+ ],
+ "name": "IBM866"
+ },
+ {
+ "labels": [
+ "csisolatin2",
+ "iso-8859-2",
+ "iso-ir-101",
+ "iso8859-2",
+ "iso88592",
+ "iso_8859-2",
+ "iso_8859-2:1987",
+ "l2",
+ "latin2"
+ ],
+ "name": "ISO-8859-2"
+ },
+ {
+ "labels": [
+ "csisolatin3",
+ "iso-8859-3",
+ "iso-ir-109",
+ "iso8859-3",
+ "iso88593",
+ "iso_8859-3",
+ "iso_8859-3:1988",
+ "l3",
+ "latin3"
+ ],
+ "name": "ISO-8859-3"
+ },
+ {
+ "labels": [
+ "csisolatin4",
+ "iso-8859-4",
+ "iso-ir-110",
+ "iso8859-4",
+ "iso88594",
+ "iso_8859-4",
+ "iso_8859-4:1988",
+ "l4",
+ "latin4"
+ ],
+ "name": "ISO-8859-4"
+ },
+ {
+ "labels": [
+ "csisolatincyrillic",
+ "cyrillic",
+ "iso-8859-5",
+ "iso-ir-144",
+ "iso8859-5",
+ "iso88595",
+ "iso_8859-5",
+ "iso_8859-5:1988"
+ ],
+ "name": "ISO-8859-5"
+ },
+ {
+ "labels": [
+ "arabic",
+ "asmo-708",
+ "csiso88596e",
+ "csiso88596i",
+ "csisolatinarabic",
+ "ecma-114",
+ "iso-8859-6",
+ "iso-8859-6-e",
+ "iso-8859-6-i",
+ "iso-ir-127",
+ "iso8859-6",
+ "iso88596",
+ "iso_8859-6",
+ "iso_8859-6:1987"
+ ],
+ "name": "ISO-8859-6"
+ },
+ {
+ "labels": [
+ "csisolatingreek",
+ "ecma-118",
+ "elot_928",
+ "greek",
+ "greek8",
+ "iso-8859-7",
+ "iso-ir-126",
+ "iso8859-7",
+ "iso88597",
+ "iso_8859-7",
+ "iso_8859-7:1987",
+ "sun_eu_greek"
+ ],
+ "name": "ISO-8859-7"
+ },
+ {
+ "labels": [
+ "csiso88598e",
+ "csisolatinhebrew",
+ "hebrew",
+ "iso-8859-8",
+ "iso-8859-8-e",
+ "iso-ir-138",
+ "iso8859-8",
+ "iso88598",
+ "iso_8859-8",
+ "iso_8859-8:1988",
+ "visual"
+ ],
+ "name": "ISO-8859-8"
+ },
+ {
+ "labels": [
+ "csiso88598i",
+ "iso-8859-8-i",
+ "logical"
+ ],
+ "name": "ISO-8859-8-I"
+ },
+ {
+ "labels": [
+ "csisolatin6",
+ "iso-8859-10",
+ "iso-ir-157",
+ "iso8859-10",
+ "iso885910",
+ "l6",
+ "latin6"
+ ],
+ "name": "ISO-8859-10"
+ },
+ {
+ "labels": [
+ "iso-8859-13",
+ "iso8859-13",
+ "iso885913"
+ ],
+ "name": "ISO-8859-13"
+ },
+ {
+ "labels": [
+ "iso-8859-14",
+ "iso8859-14",
+ "iso885914"
+ ],
+ "name": "ISO-8859-14"
+ },
+ {
+ "labels": [
+ "csisolatin9",
+ "iso-8859-15",
+ "iso8859-15",
+ "iso885915",
+ "iso_8859-15",
+ "l9"
+ ],
+ "name": "ISO-8859-15"
+ },
+ {
+ "labels": [
+ "iso-8859-16"
+ ],
+ "name": "ISO-8859-16"
+ },
+ {
+ "labels": [
+ "cskoi8r",
+ "koi",
+ "koi8",
+ "koi8-r",
+ "koi8_r"
+ ],
+ "name": "KOI8-R"
+ },
+ {
+ "labels": [
+ "koi8-ru",
+ "koi8-u"
+ ],
+ "name": "KOI8-U"
+ },
+ {
+ "labels": [
+ "csmacintosh",
+ "mac",
+ "macintosh",
+ "x-mac-roman"
+ ],
+ "name": "macintosh"
+ },
+ {
+ "labels": [
+ "dos-874",
+ "iso-8859-11",
+ "iso8859-11",
+ "iso885911",
+ "tis-620",
+ "windows-874"
+ ],
+ "name": "windows-874"
+ },
+ {
+ "labels": [
+ "cp1250",
+ "windows-1250",
+ "x-cp1250"
+ ],
+ "name": "windows-1250"
+ },
+ {
+ "labels": [
+ "cp1251",
+ "windows-1251",
+ "x-cp1251"
+ ],
+ "name": "windows-1251"
+ },
+ {
+ "labels": [
+ "ansi_x3.4-1968",
+ "ascii",
+ "cp1252",
+ "cp819",
+ "csisolatin1",
+ "ibm819",
+ "iso-8859-1",
+ "iso-ir-100",
+ "iso8859-1",
+ "iso88591",
+ "iso_8859-1",
+ "iso_8859-1:1987",
+ "l1",
+ "latin1",
+ "us-ascii",
+ "windows-1252",
+ "x-cp1252"
+ ],
+ "name": "windows-1252"
+ },
+ {
+ "labels": [
+ "cp1253",
+ "windows-1253",
+ "x-cp1253"
+ ],
+ "name": "windows-1253"
+ },
+ {
+ "labels": [
+ "cp1254",
+ "csisolatin5",
+ "iso-8859-9",
+ "iso-ir-148",
+ "iso8859-9",
+ "iso88599",
+ "iso_8859-9",
+ "iso_8859-9:1989",
+ "l5",
+ "latin5",
+ "windows-1254",
+ "x-cp1254"
+ ],
+ "name": "windows-1254"
+ },
+ {
+ "labels": [
+ "cp1255",
+ "windows-1255",
+ "x-cp1255"
+ ],
+ "name": "windows-1255"
+ },
+ {
+ "labels": [
+ "cp1256",
+ "windows-1256",
+ "x-cp1256"
+ ],
+ "name": "windows-1256"
+ },
+ {
+ "labels": [
+ "cp1257",
+ "windows-1257",
+ "x-cp1257"
+ ],
+ "name": "windows-1257"
+ },
+ {
+ "labels": [
+ "cp1258",
+ "windows-1258",
+ "x-cp1258"
+ ],
+ "name": "windows-1258"
+ },
+ {
+ "labels": [
+ "x-mac-cyrillic",
+ "x-mac-ukrainian"
+ ],
+ "name": "x-mac-cyrillic"
+ }
+ ],
+ "heading": "Legacy single-byte encodings"
+ },
+ {
+ "encodings": [
+ {
+ "labels": [
+ "chinese",
+ "csgb2312",
+ "csiso58gb231280",
+ "gb2312",
+ "gb_2312",
+ "gb_2312-80",
+ "gbk",
+ "iso-ir-58",
+ "x-gbk"
+ ],
+ "name": "GBK"
+ },
+ {
+ "labels": [
+ "gb18030"
+ ],
+ "name": "gb18030"
+ }
+ ],
+ "heading": "Legacy multi-byte Chinese (simplified) encodings"
+ },
+ {
+ "encodings": [
+ {
+ "labels": [
+ "big5",
+ "big5-hkscs",
+ "cn-big5",
+ "csbig5",
+ "x-x-big5"
+ ],
+ "name": "Big5"
+ }
+ ],
+ "heading": "Legacy multi-byte Chinese (traditional) encodings"
+ },
+ {
+ "encodings": [
+ {
+ "labels": [
+ "cseucpkdfmtjapanese",
+ "euc-jp",
+ "x-euc-jp"
+ ],
+ "name": "EUC-JP"
+ },
+ {
+ "labels": [
+ "csiso2022jp",
+ "iso-2022-jp"
+ ],
+ "name": "ISO-2022-JP"
+ },
+ {
+ "labels": [
+ "csshiftjis",
+ "ms932",
+ "ms_kanji",
+ "shift-jis",
+ "shift_jis",
+ "sjis",
+ "windows-31j",
+ "x-sjis"
+ ],
+ "name": "Shift_JIS"
+ }
+ ],
+ "heading": "Legacy multi-byte Japanese encodings"
+ },
+ {
+ "encodings": [
+ {
+ "labels": [
+ "cseuckr",
+ "csksc56011987",
+ "euc-kr",
+ "iso-ir-149",
+ "korean",
+ "ks_c_5601-1987",
+ "ks_c_5601-1989",
+ "ksc5601",
+ "ksc_5601",
+ "windows-949"
+ ],
+ "name": "EUC-KR"
+ }
+ ],
+ "heading": "Legacy multi-byte Korean encodings"
+ },
+ {
+ "encodings": [
+ {
+ "labels": [
+ "csiso2022kr",
+ "hz-gb-2312",
+ "iso-2022-cn",
+ "iso-2022-cn-ext",
+ "iso-2022-kr"
+ ],
+ "name": "replacement"
+ },
+ {
+ "labels": [
+ "utf-16be"
+ ],
+ "name": "UTF-16BE"
+ },
+ {
+ "labels": [
+ "utf-16",
+ "utf-16le"
+ ],
+ "name": "UTF-16LE"
+ },
+ {
+ "labels": [
+ "x-user-defined"
+ ],
+ "name": "x-user-defined"
+ }
+ ],
+ "heading": "Legacy miscellaneous encodings"
+ }
+ ];
+
+ // Label to encoding registry.
+ /** @type {Object.<string,{name:string,labels:Array.<string>}>} */
+ var label_to_encoding = {};
+ encodings.forEach(function(category) {
+ category.encodings.forEach(function(encoding) {
+ encoding.labels.forEach(function(label) {
+ label_to_encoding[label] = encoding;
+ });
+ });
+ });
+
+ // Registry of of encoder/decoder factories, by encoding name.
+ /** @type {Object.<string, function({fatal:boolean}): Encoder>} */
+ var encoders = {};
+ /** @type {Object.<string, function({fatal:boolean}): Decoder>} */
+ var decoders = {};
+
+ //
+ // 6. Indexes
+ //
+
+ /**
+ * @param {number} pointer The |pointer| to search for.
+ * @param {(!Array.<?number>|undefined)} index The |index| to search within.
+ * @return {?number} The code point corresponding to |pointer| in |index|,
+ * or null if |code point| is not in |index|.
+ */
+ function indexCodePointFor(pointer, index) {
+ if (!index) return null;
+ return index[pointer] || null;
+ }
+
+ /**
+ * @param {number} code_point The |code point| to search for.
+ * @param {!Array.<?number>} index The |index| to search within.
+ * @return {?number} The first pointer corresponding to |code point| in
+ * |index|, or null if |code point| is not in |index|.
+ */
+ function indexPointerFor(code_point, index) {
+ var pointer = index.indexOf(code_point);
+ return pointer === -1 ? null : pointer;
+ }
+
+ /**
+ * @param {string} name Name of the index.
+ * @return {(!Array.<number>|!Array.<Array.<number>>)}
+ * */
+ function index(name) {
+ if (!('encoding-indexes' in global)) {
+ throw Error("Indexes missing." +
+ " Did you forget to include encoding-indexes.js first?");
+ }
+ return global['encoding-indexes'][name];
+ }
+
+ /**
+ * @param {number} pointer The |pointer| to search for in the gb18030 index.
+ * @return {?number} The code point corresponding to |pointer| in |index|,
+ * or null if |code point| is not in the gb18030 index.
+ */
+ function indexGB18030RangesCodePointFor(pointer) {
+ // 1. If pointer is greater than 39419 and less than 189000, or
+ // pointer is greater than 1237575, return null.
+ if ((pointer > 39419 && pointer < 189000) || (pointer > 1237575))
+ return null;
+
+ // 2. If pointer is 7457, return code point U+E7C7.
+ if (pointer === 7457) return 0xE7C7;
+
+ // 3. Let offset be the last pointer in index gb18030 ranges that
+ // is equal to or less than pointer and let code point offset be
+ // its corresponding code point.
+ var offset = 0;
+ var code_point_offset = 0;
+ var idx = index('gb18030-ranges');
+ var i;
+ for (i = 0; i < idx.length; ++i) {
+ /** @type {!Array.<number>} */
+ var entry = idx[i];
+ if (entry[0] <= pointer) {
+ offset = entry[0];
+ code_point_offset = entry[1];
+ } else {
+ break;
+ }
+ }
+
+ // 4. Return a code point whose value is code point offset +
+ // pointer − offset.
+ return code_point_offset + pointer - offset;
+ }
+
+ /**
+ * @param {number} code_point The |code point| to locate in the gb18030 index.
+ * @return {number} The first pointer corresponding to |code point| in the
+ * gb18030 index.
+ */
+ function indexGB18030RangesPointerFor(code_point) {
+ // 1. If code point is U+E7C7, return pointer 7457.
+ if (code_point === 0xE7C7) return 7457;
+
+ // 2. Let offset be the last code point in index gb18030 ranges
+ // that is equal to or less than code point and let pointer offset
+ // be its corresponding pointer.
+ var offset = 0;
+ var pointer_offset = 0;
+ var idx = index('gb18030-ranges');
+ var i;
+ for (i = 0; i < idx.length; ++i) {
+ /** @type {!Array.<number>} */
+ var entry = idx[i];
+ if (entry[1] <= code_point) {
+ offset = entry[1];
+ pointer_offset = entry[0];
+ } else {
+ break;
+ }
+ }
+
+ // 3. Return a pointer whose value is pointer offset + code point
+ // − offset.
+ return pointer_offset + code_point - offset;
+ }
+
+ /**
+ * @param {number} code_point The |code_point| to search for in the Shift_JIS
+ * index.
+ * @return {?number} The code point corresponding to |pointer| in |index|,
+ * or null if |code point| is not in the Shift_JIS index.
+ */
+ function indexShiftJISPointerFor(code_point) {
+ // 1. Let index be index jis0208 excluding all entries whose
+ // pointer is in the range 8272 to 8835, inclusive.
+ shift_jis_index = shift_jis_index ||
+ index('jis0208').map(function(code_point, pointer) {
+ return inRange(pointer, 8272, 8835) ? null : code_point;
+ });
+ var index_ = shift_jis_index;
+
+ // 2. Return the index pointer for code point in index.
+ return index_.indexOf(code_point);
+ }
+ var shift_jis_index;
+
+ /**
+ * @param {number} code_point The |code_point| to search for in the big5
+ * index.
+ * @return {?number} The code point corresponding to |pointer| in |index|,
+ * or null if |code point| is not in the big5 index.
+ */
+ function indexBig5PointerFor(code_point) {
+ // 1. Let index be index Big5 excluding all entries whose pointer
+ big5_index_no_hkscs = big5_index_no_hkscs ||
+ index('big5').map(function(code_point, pointer) {
+ return (pointer < (0xA1 - 0x81) * 157) ? null : code_point;
+ });
+ var index_ = big5_index_no_hkscs;
+
+ // 2. If code point is U+2550, U+255E, U+2561, U+256A, U+5341, or
+ // U+5345, return the last pointer corresponding to code point in
+ // index.
+ if (code_point === 0x2550 || code_point === 0x255E ||
+ code_point === 0x2561 || code_point === 0x256A ||
+ code_point === 0x5341 || code_point === 0x5345) {
+ return index_.lastIndexOf(code_point);
+ }
+
+ // 3. Return the index pointer for code point in index.
+ return indexPointerFor(code_point, index_);
+ }
+ var big5_index_no_hkscs;
+
+ //
+ // 8. API
+ //
+
+ /** @const */ var DEFAULT_ENCODING = 'utf-8';
+
+ // 8.1 Interface TextDecoder
+
+ /**
+ * @constructor
+ * @param {string=} label The label of the encoding;
+ * defaults to 'utf-8'.
+ * @param {Object=} options
+ */
+ function TextDecoder(label, options) {
+ // Web IDL conventions
+ if (!(this instanceof TextDecoder))
+ throw TypeError('Called as a function. Did you forget \'new\'?');
+ label = label !== undefined ? String(label) : DEFAULT_ENCODING;
+ options = ToDictionary(options);
+
+ // A TextDecoder object has an associated encoding, decoder,
+ // stream, ignore BOM flag (initially unset), BOM seen flag
+ // (initially unset), error mode (initially replacement), and do
+ // not flush flag (initially unset).
+
+ /** @private */
+ this._encoding = null;
+ /** @private @type {?Decoder} */
+ this._decoder = null;
+ /** @private @type {boolean} */
+ this._ignoreBOM = false;
+ /** @private @type {boolean} */
+ this._BOMseen = false;
+ /** @private @type {string} */
+ this._error_mode = 'replacement';
+ /** @private @type {boolean} */
+ this._do_not_flush = false;
+
+
+ // 1. Let encoding be the result of getting an encoding from
+ // label.
+ var encoding = getEncoding(label);
+
+ // 2. If encoding is failure or replacement, throw a RangeError.
+ if (encoding === null || encoding.name === 'replacement')
+ throw RangeError('Unknown encoding: ' + label);
+ if (!decoders[encoding.name]) {
+ throw Error('Decoder not present.' +
+ ' Did you forget to include encoding-indexes.js first?');
+ }
+
+ // 3. Let dec be a new TextDecoder object.
+ var dec = this;
+
+ // 4. Set dec's encoding to encoding.
+ dec._encoding = encoding;
+
+ // 5. If options's fatal member is true, set dec's error mode to
+ // fatal.
+ if (Boolean(options['fatal']))
+ dec._error_mode = 'fatal';
+
+ // 6. If options's ignoreBOM member is true, set dec's ignore BOM
+ // flag.
+ if (Boolean(options['ignoreBOM']))
+ dec._ignoreBOM = true;
+
+ // For pre-ES5 runtimes:
+ if (!Object.defineProperty) {
+ this.encoding = dec._encoding.name.toLowerCase();
+ this.fatal = dec._error_mode === 'fatal';
+ this.ignoreBOM = dec._ignoreBOM;
+ }
+
+ // 7. Return dec.
+ return dec;
+ }
+
+ if (Object.defineProperty) {
+ // The encoding attribute's getter must return encoding's name.
+ Object.defineProperty(TextDecoder.prototype, 'encoding', {
+ /** @this {TextDecoder} */
+ get: function() { return this._encoding.name.toLowerCase(); }
+ });
+
+ // The fatal attribute's getter must return true if error mode
+ // is fatal, and false otherwise.
+ Object.defineProperty(TextDecoder.prototype, 'fatal', {
+ /** @this {TextDecoder} */
+ get: function() { return this._error_mode === 'fatal'; }
+ });
+
+ // The ignoreBOM attribute's getter must return true if ignore
+ // BOM flag is set, and false otherwise.
+ Object.defineProperty(TextDecoder.prototype, 'ignoreBOM', {
+ /** @this {TextDecoder} */
+ get: function() { return this._ignoreBOM; }
+ });
+ }
+
+ /**
+ * @param {BufferSource=} input The buffer of bytes to decode.
+ * @param {Object=} options
+ * @return {string} The decoded string.
+ */
+ TextDecoder.prototype.decode = function decode(input, options) {
+ var bytes;
+ if (typeof input === 'object' && input instanceof ArrayBuffer) {
+ bytes = new Uint8Array(input);
+ } else if (typeof input === 'object' && 'buffer' in input &&
+ input.buffer instanceof ArrayBuffer) {
+ bytes = new Uint8Array(input.buffer,
+ input.byteOffset,
+ input.byteLength);
+ } else {
+ bytes = new Uint8Array(0);
+ }
+
+ options = ToDictionary(options);
+
+ // 1. If the do not flush flag is unset, set decoder to a new
+ // encoding's decoder, set stream to a new stream, and unset the
+ // BOM seen flag.
+ if (!this._do_not_flush) {
+ this._decoder = decoders[this._encoding.name]({
+ fatal: this._error_mode === 'fatal'});
+ this._BOMseen = false;
+ }
+
+ // 2. If options's stream is true, set the do not flush flag, and
+ // unset the do not flush flag otherwise.
+ this._do_not_flush = Boolean(options['stream']);
+
+ // 3. If input is given, push a copy of input to stream.
+ // TODO: Align with spec algorithm - maintain stream on instance.
+ var input_stream = new Stream(bytes);
+
+ // 4. Let output be a new stream.
+ var output = [];
+
+ /** @type {?(number|!Array.<number>)} */
+ var result;
+
+ // 5. While true:
+ while (true) {
+ // 1. Let token be the result of reading from stream.
+ var token = input_stream.read();
+
+ // 2. If token is end-of-stream and the do not flush flag is
+ // set, return output, serialized.
+ // TODO: Align with spec algorithm.
+ if (token === end_of_stream)
+ break;
+
+ // 3. Otherwise, run these subsubsteps:
+
+ // 1. Let result be the result of processing token for decoder,
+ // stream, output, and error mode.
+ result = this._decoder.handler(input_stream, token);
+
+ // 2. If result is finished, return output, serialized.
+ if (result === finished)
+ break;
+
+ if (result !== null) {
+ if (Array.isArray(result))
+ output.push.apply(output, /**@type {!Array.<number>}*/(result));
+ else
+ output.push(result);
+ }
+
+ // 3. Otherwise, if result is error, throw a TypeError.
+ // (Thrown in handler)
+
+ // 4. Otherwise, do nothing.
+ }
+ // TODO: Align with spec algorithm.
+ if (!this._do_not_flush) {
+ do {
+ result = this._decoder.handler(input_stream, input_stream.read());
+ if (result === finished)
+ break;
+ if (result === null)
+ continue;
+ if (Array.isArray(result))
+ output.push.apply(output, /**@type {!Array.<number>}*/(result));
+ else
+ output.push(result);
+ } while (!input_stream.endOfStream());
+ this._decoder = null;
+ }
+
+ // A TextDecoder object also has an associated serialize stream
+ // algorithm...
+ /**
+ * @param {!Array.<number>} stream
+ * @return {string}
+ * @this {TextDecoder}
+ */
+ function serializeStream(stream) {
+ // 1. Let token be the result of reading from stream.
+ // (Done in-place on array, rather than as a stream)
+
+ // 2. If encoding is UTF-8, UTF-16BE, or UTF-16LE, and ignore
+ // BOM flag and BOM seen flag are unset, run these subsubsteps:
+ if (includes(['UTF-8', 'UTF-16LE', 'UTF-16BE'], this._encoding.name) &&
+ !this._ignoreBOM && !this._BOMseen) {
+ if (stream.length > 0 && stream[0] === 0xFEFF) {
+ // 1. If token is U+FEFF, set BOM seen flag.
+ this._BOMseen = true;
+ stream.shift();
+ } else if (stream.length > 0) {
+ // 2. Otherwise, if token is not end-of-stream, set BOM seen
+ // flag and append token to stream.
+ this._BOMseen = true;
+ } else {
+ // 3. Otherwise, if token is not end-of-stream, append token
+ // to output.
+ // (no-op)
+ }
+ }
+ // 4. Otherwise, return output.
+ return codePointsToString(stream);
+ }
+
+ return serializeStream.call(this, output);
+ };
+
+ // 8.2 Interface TextEncoder
+
+ /**
+ * @constructor
+ * @param {string=} label The label of the encoding. NONSTANDARD.
+ * @param {Object=} options NONSTANDARD.
+ */
+ function TextEncoder(label, options) {
+ // Web IDL conventions
+ if (!(this instanceof TextEncoder))
+ throw TypeError('Called as a function. Did you forget \'new\'?');
+ options = ToDictionary(options);
+
+ // A TextEncoder object has an associated encoding and encoder.
+
+ /** @private */
+ this._encoding = null;
+ /** @private @type {?Encoder} */
+ this._encoder = null;
+
+ // Non-standard
+ /** @private @type {boolean} */
+ this._do_not_flush = false;
+ /** @private @type {string} */
+ this._fatal = Boolean(options['fatal']) ? 'fatal' : 'replacement';
+
+ // 1. Let enc be a new TextEncoder object.
+ var enc = this;
+
+ // 2. Set enc's encoding to UTF-8's encoder.
+ if (Boolean(options['NONSTANDARD_allowLegacyEncoding'])) {
+ // NONSTANDARD behavior.
+ label = label !== undefined ? String(label) : DEFAULT_ENCODING;
+ var encoding = getEncoding(label);
+ if (encoding === null || encoding.name === 'replacement')
+ throw RangeError('Unknown encoding: ' + label);
+ if (!encoders[encoding.name]) {
+ throw Error('Encoder not present.' +
+ ' Did you forget to include encoding-indexes.js first?');
+ }
+ enc._encoding = encoding;
+ } else {
+ // Standard behavior.
+ enc._encoding = getEncoding('utf-8');
+
+ if (label !== undefined && 'console' in global) {
+ console.warn('TextEncoder constructor called with encoding label, '
+ + 'which is ignored.');
+ }
+ }
+
+ // For pre-ES5 runtimes:
+ if (!Object.defineProperty)
+ this.encoding = enc._encoding.name.toLowerCase();
+
+ // 3. Return enc.
+ return enc;
+ }
+
+ if (Object.defineProperty) {
+ // The encoding attribute's getter must return encoding's name.
+ Object.defineProperty(TextEncoder.prototype, 'encoding', {
+ /** @this {TextEncoder} */
+ get: function() { return this._encoding.name.toLowerCase(); }
+ });
+ }
+
+ /**
+ * @param {string=} opt_string The string to encode.
+ * @param {Object=} options
+ * @return {!Uint8Array} Encoded bytes, as a Uint8Array.
+ */
+ TextEncoder.prototype.encode = function encode(opt_string, options) {
+ opt_string = opt_string === undefined ? '' : String(opt_string);
+ options = ToDictionary(options);
+
+ // NOTE: This option is nonstandard. None of the encodings
+ // permitted for encoding (i.e. UTF-8, UTF-16) are stateful when
+ // the input is a USVString so streaming is not necessary.
+ if (!this._do_not_flush)
+ this._encoder = encoders[this._encoding.name]({
+ fatal: this._fatal === 'fatal'});
+ this._do_not_flush = Boolean(options['stream']);
+
+ // 1. Convert input to a stream.
+ var input = new Stream(stringToCodePoints(opt_string));
+
+ // 2. Let output be a new stream
+ var output = [];
+
+ /** @type {?(number|!Array.<number>)} */
+ var result;
+ // 3. While true, run these substeps:
+ while (true) {
+ // 1. Let token be the result of reading from input.
+ var token = input.read();
+ if (token === end_of_stream)
+ break;
+ // 2. Let result be the result of processing token for encoder,
+ // input, output.
+ result = this._encoder.handler(input, token);
+ if (result === finished)
+ break;
+ if (Array.isArray(result))
+ output.push.apply(output, /**@type {!Array.<number>}*/(result));
+ else
+ output.push(result);
+ }
+ // TODO: Align with spec algorithm.
+ if (!this._do_not_flush) {
+ while (true) {
+ result = this._encoder.handler(input, input.read());
+ if (result === finished)
+ break;
+ if (Array.isArray(result))
+ output.push.apply(output, /**@type {!Array.<number>}*/(result));
+ else
+ output.push(result);
+ }
+ this._encoder = null;
+ }
+ // 3. If result is finished, convert output into a byte sequence,
+ // and then return a Uint8Array object wrapping an ArrayBuffer
+ // containing output.
+ return new Uint8Array(output);
+ };
+
+
+ //
+ // 9. The encoding
+ //
+
+ // 9.1 utf-8
+
+ // 9.1.1 utf-8 decoder
+ /**
+ * @constructor
+ * @implements {Decoder}
+ * @param {{fatal: boolean}} options
+ */
+ function UTF8Decoder(options) {
+ var fatal = options.fatal;
+
+ // utf-8's decoder's has an associated utf-8 code point, utf-8
+ // bytes seen, and utf-8 bytes needed (all initially 0), a utf-8
+ // lower boundary (initially 0x80), and a utf-8 upper boundary
+ // (initially 0xBF).
+ var /** @type {number} */ utf8_code_point = 0,
+ /** @type {number} */ utf8_bytes_seen = 0,
+ /** @type {number} */ utf8_bytes_needed = 0,
+ /** @type {number} */ utf8_lower_boundary = 0x80,
+ /** @type {number} */ utf8_upper_boundary = 0xBF;
+
+ /**
+ * @param {Stream} stream The stream of bytes being decoded.
+ * @param {number} bite The next byte read from the stream.
+ * @return {?(number|!Array.<number>)} The next code point(s)
+ * decoded, or null if not enough data exists in the input
+ * stream to decode a complete code point.
+ */
+ this.handler = function(stream, bite) {
+ // 1. If byte is end-of-stream and utf-8 bytes needed is not 0,
+ // set utf-8 bytes needed to 0 and return error.
+ if (bite === end_of_stream && utf8_bytes_needed !== 0) {
+ utf8_bytes_needed = 0;
+ return decoderError(fatal);
+ }
+
+ // 2. If byte is end-of-stream, return finished.
+ if (bite === end_of_stream)
+ return finished;
+
+ // 3. If utf-8 bytes needed is 0, based on byte:
+ if (utf8_bytes_needed === 0) {
+
+ // 0x00 to 0x7F
+ if (inRange(bite, 0x00, 0x7F)) {
+ // Return a code point whose value is byte.
+ return bite;
+ }
+
+ // 0xC2 to 0xDF
+ else if (inRange(bite, 0xC2, 0xDF)) {
+ // 1. Set utf-8 bytes needed to 1.
+ utf8_bytes_needed = 1;
+
+ // 2. Set UTF-8 code point to byte & 0x1F.
+ utf8_code_point = bite & 0x1F;
+ }
+
+ // 0xE0 to 0xEF
+ else if (inRange(bite, 0xE0, 0xEF)) {
+ // 1. If byte is 0xE0, set utf-8 lower boundary to 0xA0.
+ if (bite === 0xE0)
+ utf8_lower_boundary = 0xA0;
+ // 2. If byte is 0xED, set utf-8 upper boundary to 0x9F.
+ if (bite === 0xED)
+ utf8_upper_boundary = 0x9F;
+ // 3. Set utf-8 bytes needed to 2.
+ utf8_bytes_needed = 2;
+ // 4. Set UTF-8 code point to byte & 0xF.
+ utf8_code_point = bite & 0xF;
+ }
+
+ // 0xF0 to 0xF4
+ else if (inRange(bite, 0xF0, 0xF4)) {
+ // 1. If byte is 0xF0, set utf-8 lower boundary to 0x90.
+ if (bite === 0xF0)
+ utf8_lower_boundary = 0x90;
+ // 2. If byte is 0xF4, set utf-8 upper boundary to 0x8F.
+ if (bite === 0xF4)
+ utf8_upper_boundary = 0x8F;
+ // 3. Set utf-8 bytes needed to 3.
+ utf8_bytes_needed = 3;
+ // 4. Set UTF-8 code point to byte & 0x7.
+ utf8_code_point = bite & 0x7;
+ }
+
+ // Otherwise
+ else {
+ // Return error.
+ return decoderError(fatal);
+ }
+
+ // Return continue.
+ return null;
+ }
+
+ // 4. If byte is not in the range utf-8 lower boundary to utf-8
+ // upper boundary, inclusive, run these substeps:
+ if (!inRange(bite, utf8_lower_boundary, utf8_upper_boundary)) {
+
+ // 1. Set utf-8 code point, utf-8 bytes needed, and utf-8
+ // bytes seen to 0, set utf-8 lower boundary to 0x80, and set
+ // utf-8 upper boundary to 0xBF.
+ utf8_code_point = utf8_bytes_needed = utf8_bytes_seen = 0;
+ utf8_lower_boundary = 0x80;
+ utf8_upper_boundary = 0xBF;
+
+ // 2. Prepend byte to stream.
+ stream.prepend(bite);
+
+ // 3. Return error.
+ return decoderError(fatal);
+ }
+
+ // 5. Set utf-8 lower boundary to 0x80 and utf-8 upper boundary
+ // to 0xBF.
+ utf8_lower_boundary = 0x80;
+ utf8_upper_boundary = 0xBF;
+
+ // 6. Set UTF-8 code point to (UTF-8 code point << 6) | (byte &
+ // 0x3F)
+ utf8_code_point = (utf8_code_point << 6) | (bite & 0x3F);
+
+ // 7. Increase utf-8 bytes seen by one.
+ utf8_bytes_seen += 1;
+
+ // 8. If utf-8 bytes seen is not equal to utf-8 bytes needed,
+ // continue.
+ if (utf8_bytes_seen !== utf8_bytes_needed)
+ return null;
+
+ // 9. Let code point be utf-8 code point.
+ var code_point = utf8_code_point;
+
+ // 10. Set utf-8 code point, utf-8 bytes needed, and utf-8 bytes
+ // seen to 0.
+ utf8_code_point = utf8_bytes_needed = utf8_bytes_seen = 0;
+
+ // 11. Return a code point whose value is code point.
+ return code_point;
+ };
+ }
+
+ // 9.1.2 utf-8 encoder
+ /**
+ * @constructor
+ * @implements {Encoder}
+ * @param {{fatal: boolean}} options
+ */
+ function UTF8Encoder(options) {
+ var fatal = options.fatal;
+ /**
+ * @param {Stream} stream Input stream.
+ * @param {number} code_point Next code point read from the stream.
+ * @return {(number|!Array.<number>)} Byte(s) to emit.
+ */
+ this.handler = function(stream, code_point) {
+ // 1. If code point is end-of-stream, return finished.
+ if (code_point === end_of_stream)
+ return finished;
+
+ // 2. If code point is an ASCII code point, return a byte whose
+ // value is code point.
+ if (isASCIICodePoint(code_point))
+ return code_point;
+
+ // 3. Set count and offset based on the range code point is in:
+ var count, offset;
+ // U+0080 to U+07FF, inclusive:
+ if (inRange(code_point, 0x0080, 0x07FF)) {
+ // 1 and 0xC0
+ count = 1;
+ offset = 0xC0;
+ }
+ // U+0800 to U+FFFF, inclusive:
+ else if (inRange(code_point, 0x0800, 0xFFFF)) {
+ // 2 and 0xE0
+ count = 2;
+ offset = 0xE0;
+ }
+ // U+10000 to U+10FFFF, inclusive:
+ else if (inRange(code_point, 0x10000, 0x10FFFF)) {
+ // 3 and 0xF0
+ count = 3;
+ offset = 0xF0;
+ }
+
+ // 4. Let bytes be a byte sequence whose first byte is (code
+ // point >> (6 × count)) + offset.
+ var bytes = [(code_point >> (6 * count)) + offset];
+
+ // 5. Run these substeps while count is greater than 0:
+ while (count > 0) {
+
+ // 1. Set temp to code point >> (6 × (count − 1)).
+ var temp = code_point >> (6 * (count - 1));
+
+ // 2. Append to bytes 0x80 | (temp & 0x3F).
+ bytes.push(0x80 | (temp & 0x3F));
+
+ // 3. Decrease count by one.
+ count -= 1;
+ }
+
+ // 6. Return bytes bytes, in order.
+ return bytes;
+ };
+ }
+
+ /** @param {{fatal: boolean}} options */
+ encoders['UTF-8'] = function(options) {
+ return new UTF8Encoder(options);
+ };
+ /** @param {{fatal: boolean}} options */
+ decoders['UTF-8'] = function(options) {
+ return new UTF8Decoder(options);
+ };
+
+ //
+ // 10. Legacy single-byte encodings
+ //
+
+ // 10.1 single-byte decoder
+ /**
+ * @constructor
+ * @implements {Decoder}
+ * @param {!Array.<number>} index The encoding index.
+ * @param {{fatal: boolean}} options
+ */
+ function SingleByteDecoder(index, options) {
+ var fatal = options.fatal;
+ /**
+ * @param {Stream} stream The stream of bytes being decoded.
+ * @param {number} bite The next byte read from the stream.
+ * @return {?(number|!Array.<number>)} The next code point(s)
+ * decoded, or null if not enough data exists in the input
+ * stream to decode a complete code point.
+ */
+ this.handler = function(stream, bite) {
+ // 1. If byte is end-of-stream, return finished.
+ if (bite === end_of_stream)
+ return finished;
+
+ // 2. If byte is an ASCII byte, return a code point whose value
+ // is byte.
+ if (isASCIIByte(bite))
+ return bite;
+
+ // 3. Let code point be the index code point for byte − 0x80 in
+ // index single-byte.
+ var code_point = index[bite - 0x80];
+
+ // 4. If code point is null, return error.
+ if (code_point === null)
+ return decoderError(fatal);
+
+ // 5. Return a code point whose value is code point.
+ return code_point;
+ };
+ }
+
+ // 10.2 single-byte encoder
+ /**
+ * @constructor
+ * @implements {Encoder}
+ * @param {!Array.<?number>} index The encoding index.
+ * @param {{fatal: boolean}} options
+ */
+ function SingleByteEncoder(index, options) {
+ var fatal = options.fatal;
+ /**
+ * @param {Stream} stream Input stream.
+ * @param {number} code_point Next code point read from the stream.
+ * @return {(number|!Array.<number>)} Byte(s) to emit.
+ */
+ this.handler = function(stream, code_point) {
+ // 1. If code point is end-of-stream, return finished.
+ if (code_point === end_of_stream)
+ return finished;
+
+ // 2. If code point is an ASCII code point, return a byte whose
+ // value is code point.
+ if (isASCIICodePoint(code_point))
+ return code_point;
+
+ // 3. Let pointer be the index pointer for code point in index
+ // single-byte.
+ var pointer = indexPointerFor(code_point, index);
+
+ // 4. If pointer is null, return error with code point.
+ if (pointer === null)
+ encoderError(code_point);
+
+ // 5. Return a byte whose value is pointer + 0x80.
+ return pointer + 0x80;
+ };
+ }
+
+ (function() {
+ if (!('encoding-indexes' in global))
+ return;
+ encodings.forEach(function(category) {
+ if (category.heading !== 'Legacy single-byte encodings')
+ return;
+ category.encodings.forEach(function(encoding) {
+ var name = encoding.name;
+ var idx = index(name.toLowerCase());
+ /** @param {{fatal: boolean}} options */
+ decoders[name] = function(options) {
+ return new SingleByteDecoder(idx, options);
+ };
+ /** @param {{fatal: boolean}} options */
+ encoders[name] = function(options) {
+ return new SingleByteEncoder(idx, options);
+ };
+ });
+ });
+ }());
+
+ //
+ // 11. Legacy multi-byte Chinese (simplified) encodings
+ //
+
+ // 11.1 gbk
+
+ // 11.1.1 gbk decoder
+ // gbk's decoder is gb18030's decoder.
+ /** @param {{fatal: boolean}} options */
+ decoders['GBK'] = function(options) {
+ return new GB18030Decoder(options);
+ };
+
+ // 11.1.2 gbk encoder
+ // gbk's encoder is gb18030's encoder with its gbk flag set.
+ /** @param {{fatal: boolean}} options */
+ encoders['GBK'] = function(options) {
+ return new GB18030Encoder(options, true);
+ };
+
+ // 11.2 gb18030
+
+ // 11.2.1 gb18030 decoder
+ /**
+ * @constructor
+ * @implements {Decoder}
+ * @param {{fatal: boolean}} options
+ */
+ function GB18030Decoder(options) {
+ var fatal = options.fatal;
+ // gb18030's decoder has an associated gb18030 first, gb18030
+ // second, and gb18030 third (all initially 0x00).
+ var /** @type {number} */ gb18030_first = 0x00,
+ /** @type {number} */ gb18030_second = 0x00,
+ /** @type {number} */ gb18030_third = 0x00;
+ /**
+ * @param {Stream} stream The stream of bytes being decoded.
+ * @param {number} bite The next byte read from the stream.
+ * @return {?(number|!Array.<number>)} The next code point(s)
+ * decoded, or null if not enough data exists in the input
+ * stream to decode a complete code point.
+ */
+ this.handler = function(stream, bite) {
+ // 1. If byte is end-of-stream and gb18030 first, gb18030
+ // second, and gb18030 third are 0x00, return finished.
+ if (bite === end_of_stream && gb18030_first === 0x00 &&
+ gb18030_second === 0x00 && gb18030_third === 0x00) {
+ return finished;
+ }
+ // 2. If byte is end-of-stream, and gb18030 first, gb18030
+ // second, or gb18030 third is not 0x00, set gb18030 first,
+ // gb18030 second, and gb18030 third to 0x00, and return error.
+ if (bite === end_of_stream &&
+ (gb18030_first !== 0x00 || gb18030_second !== 0x00 ||
+ gb18030_third !== 0x00)) {
+ gb18030_first = 0x00;
+ gb18030_second = 0x00;
+ gb18030_third = 0x00;
+ decoderError(fatal);
+ }
+ var code_point;
+ // 3. If gb18030 third is not 0x00, run these substeps:
+ if (gb18030_third !== 0x00) {
+ // 1. Let code point be null.
+ code_point = null;
+ // 2. If byte is in the range 0x30 to 0x39, inclusive, set
+ // code point to the index gb18030 ranges code point for
+ // (((gb18030 first − 0x81) × 10 + gb18030 second − 0x30) ×
+ // 126 + gb18030 third − 0x81) × 10 + byte − 0x30.
+ if (inRange(bite, 0x30, 0x39)) {
+ code_point = indexGB18030RangesCodePointFor(
+ (((gb18030_first - 0x81) * 10 + gb18030_second - 0x30) * 126 +
+ gb18030_third - 0x81) * 10 + bite - 0x30);
+ }
+
+ // 3. Let buffer be a byte sequence consisting of gb18030
+ // second, gb18030 third, and byte, in order.
+ var buffer = [gb18030_second, gb18030_third, bite];
+
+ // 4. Set gb18030 first, gb18030 second, and gb18030 third to
+ // 0x00.
+ gb18030_first = 0x00;
+ gb18030_second = 0x00;
+ gb18030_third = 0x00;
+
+ // 5. If code point is null, prepend buffer to stream and
+ // return error.
+ if (code_point === null) {
+ stream.prepend(buffer);
+ return decoderError(fatal);
+ }
+
+ // 6. Return a code point whose value is code point.
+ return code_point;
+ }
+
+ // 4. If gb18030 second is not 0x00, run these substeps:
+ if (gb18030_second !== 0x00) {
+
+ // 1. If byte is in the range 0x81 to 0xFE, inclusive, set
+ // gb18030 third to byte and return continue.
+ if (inRange(bite, 0x81, 0xFE)) {
+ gb18030_third = bite;
+ return null;
+ }
+
+ // 2. Prepend gb18030 second followed by byte to stream, set
+ // gb18030 first and gb18030 second to 0x00, and return error.
+ stream.prepend([gb18030_second, bite]);
+ gb18030_first = 0x00;
+ gb18030_second = 0x00;
+ return decoderError(fatal);
+ }
+
+ // 5. If gb18030 first is not 0x00, run these substeps:
+ if (gb18030_first !== 0x00) {
+
+ // 1. If byte is in the range 0x30 to 0x39, inclusive, set
+ // gb18030 second to byte and return continue.
+ if (inRange(bite, 0x30, 0x39)) {
+ gb18030_second = bite;
+ return null;
+ }
+
+ // 2. Let lead be gb18030 first, let pointer be null, and set
+ // gb18030 first to 0x00.
+ var lead = gb18030_first;
+ var pointer = null;
+ gb18030_first = 0x00;
+
+ // 3. Let offset be 0x40 if byte is less than 0x7F and 0x41
+ // otherwise.
+ var offset = bite < 0x7F ? 0x40 : 0x41;
+
+ // 4. If byte is in the range 0x40 to 0x7E, inclusive, or 0x80
+ // to 0xFE, inclusive, set pointer to (lead − 0x81) × 190 +
+ // (byte − offset).
+ if (inRange(bite, 0x40, 0x7E) || inRange(bite, 0x80, 0xFE))
+ pointer = (lead - 0x81) * 190 + (bite - offset);
+
+ // 5. Let code point be null if pointer is null and the index
+ // code point for pointer in index gb18030 otherwise.
+ code_point = pointer === null ? null :
+ indexCodePointFor(pointer, index('gb18030'));
+
+ // 6. If code point is null and byte is an ASCII byte, prepend
+ // byte to stream.
+ if (code_point === null && isASCIIByte(bite))
+ stream.prepend(bite);
+
+ // 7. If code point is null, return error.
+ if (code_point === null)
+ return decoderError(fatal);
+
+ // 8. Return a code point whose value is code point.
+ return code_point;
+ }
+
+ // 6. If byte is an ASCII byte, return a code point whose value
+ // is byte.
+ if (isASCIIByte(bite))
+ return bite;
+
+ // 7. If byte is 0x80, return code point U+20AC.
+ if (bite === 0x80)
+ return 0x20AC;
+
+ // 8. If byte is in the range 0x81 to 0xFE, inclusive, set
+ // gb18030 first to byte and return continue.
+ if (inRange(bite, 0x81, 0xFE)) {
+ gb18030_first = bite;
+ return null;
+ }
+
+ // 9. Return error.
+ return decoderError(fatal);
+ };
+ }
+
+ // 11.2.2 gb18030 encoder
+ /**
+ * @constructor
+ * @implements {Encoder}
+ * @param {{fatal: boolean}} options
+ * @param {boolean=} gbk_flag
+ */
+ function GB18030Encoder(options, gbk_flag) {
+ var fatal = options.fatal;
+ // gb18030's decoder has an associated gbk flag (initially unset).
+ /**
+ * @param {Stream} stream Input stream.
+ * @param {number} code_point Next code point read from the stream.
+ * @return {(number|!Array.<number>)} Byte(s) to emit.
+ */
+ this.handler = function(stream, code_point) {
+ // 1. If code point is end-of-stream, return finished.
+ if (code_point === end_of_stream)
+ return finished;
+
+ // 2. If code point is an ASCII code point, return a byte whose
+ // value is code point.
+ if (isASCIICodePoint(code_point))
+ return code_point;
+
+ // 3. If code point is U+E5E5, return error with code point.
+ if (code_point === 0xE5E5)
+ return encoderError(code_point);
+
+ // 4. If the gbk flag is set and code point is U+20AC, return
+ // byte 0x80.
+ if (gbk_flag && code_point === 0x20AC)
+ return 0x80;
+
+ // 5. Let pointer be the index pointer for code point in index
+ // gb18030.
+ var pointer = indexPointerFor(code_point, index('gb18030'));
+
+ // 6. If pointer is not null, run these substeps:
+ if (pointer !== null) {
+
+ // 1. Let lead be floor(pointer / 190) + 0x81.
+ var lead = floor(pointer / 190) + 0x81;
+
+ // 2. Let trail be pointer % 190.
+ var trail = pointer % 190;
+
+ // 3. Let offset be 0x40 if trail is less than 0x3F and 0x41 otherwise.
+ var offset = trail < 0x3F ? 0x40 : 0x41;
+
+ // 4. Return two bytes whose values are lead and trail + offset.
+ return [lead, trail + offset];
+ }
+
+ // 7. If gbk flag is set, return error with code point.
+ if (gbk_flag)
+ return encoderError(code_point);
+
+ // 8. Set pointer to the index gb18030 ranges pointer for code
+ // point.
+ pointer = indexGB18030RangesPointerFor(code_point);
+
+ // 9. Let byte1 be floor(pointer / 10 / 126 / 10).
+ var byte1 = floor(pointer / 10 / 126 / 10);
+
+ // 10. Set pointer to pointer − byte1 × 10 × 126 × 10.
+ pointer = pointer - byte1 * 10 * 126 * 10;
+
+ // 11. Let byte2 be floor(pointer / 10 / 126).
+ var byte2 = floor(pointer / 10 / 126);
+
+ // 12. Set pointer to pointer − byte2 × 10 × 126.
+ pointer = pointer - byte2 * 10 * 126;
+
+ // 13. Let byte3 be floor(pointer / 10).
+ var byte3 = floor(pointer / 10);
+
+ // 14. Let byte4 be pointer − byte3 × 10.
+ var byte4 = pointer - byte3 * 10;
+
+ // 15. Return four bytes whose values are byte1 + 0x81, byte2 +
+ // 0x30, byte3 + 0x81, byte4 + 0x30.
+ return [byte1 + 0x81,
+ byte2 + 0x30,
+ byte3 + 0x81,
+ byte4 + 0x30];
+ };
+ }
+
+ /** @param {{fatal: boolean}} options */
+ encoders['gb18030'] = function(options) {
+ return new GB18030Encoder(options);
+ };
+ /** @param {{fatal: boolean}} options */
+ decoders['gb18030'] = function(options) {
+ return new GB18030Decoder(options);
+ };
+
+
+ //
+ // 12. Legacy multi-byte Chinese (traditional) encodings
+ //
+
+ // 12.1 Big5
+
+ // 12.1.1 Big5 decoder
+ /**
+ * @constructor
+ * @implements {Decoder}
+ * @param {{fatal: boolean}} options
+ */
+ function Big5Decoder(options) {
+ var fatal = options.fatal;
+ // Big5's decoder has an associated Big5 lead (initially 0x00).
+ var /** @type {number} */ Big5_lead = 0x00;
+
+ /**
+ * @param {Stream} stream The stream of bytes being decoded.
+ * @param {number} bite The next byte read from the stream.
+ * @return {?(number|!Array.<number>)} The next code point(s)
+ * decoded, or null if not enough data exists in the input
+ * stream to decode a complete code point.
+ */
+ this.handler = function(stream, bite) {
+ // 1. If byte is end-of-stream and Big5 lead is not 0x00, set
+ // Big5 lead to 0x00 and return error.
+ if (bite === end_of_stream && Big5_lead !== 0x00) {
+ Big5_lead = 0x00;
+ return decoderError(fatal);
+ }
+
+ // 2. If byte is end-of-stream and Big5 lead is 0x00, return
+ // finished.
+ if (bite === end_of_stream && Big5_lead === 0x00)
+ return finished;
+
+ // 3. If Big5 lead is not 0x00, let lead be Big5 lead, let
+ // pointer be null, set Big5 lead to 0x00, and then run these
+ // substeps:
+ if (Big5_lead !== 0x00) {
+ var lead = Big5_lead;
+ var pointer = null;
+ Big5_lead = 0x00;
+
+ // 1. Let offset be 0x40 if byte is less than 0x7F and 0x62
+ // otherwise.
+ var offset = bite < 0x7F ? 0x40 : 0x62;
+
+ // 2. If byte is in the range 0x40 to 0x7E, inclusive, or 0xA1
+ // to 0xFE, inclusive, set pointer to (lead − 0x81) × 157 +
+ // (byte − offset).
+ if (inRange(bite, 0x40, 0x7E) || inRange(bite, 0xA1, 0xFE))
+ pointer = (lead - 0x81) * 157 + (bite - offset);
+
+ // 3. If there is a row in the table below whose first column
+ // is pointer, return the two code points listed in its second
+ // column
+ // Pointer | Code points
+ // --------+--------------
+ // 1133 | U+00CA U+0304
+ // 1135 | U+00CA U+030C
+ // 1164 | U+00EA U+0304
+ // 1166 | U+00EA U+030C
+ switch (pointer) {
+ case 1133: return [0x00CA, 0x0304];
+ case 1135: return [0x00CA, 0x030C];
+ case 1164: return [0x00EA, 0x0304];
+ case 1166: return [0x00EA, 0x030C];
+ }
+
+ // 4. Let code point be null if pointer is null and the index
+ // code point for pointer in index Big5 otherwise.
+ var code_point = (pointer === null) ? null :
+ indexCodePointFor(pointer, index('big5'));
+
+ // 5. If code point is null and byte is an ASCII byte, prepend
+ // byte to stream.
+ if (code_point === null && isASCIIByte(bite))
+ stream.prepend(bite);
+
+ // 6. If code point is null, return error.
+ if (code_point === null)
+ return decoderError(fatal);
+
+ // 7. Return a code point whose value is code point.
+ return code_point;
+ }
+
+ // 4. If byte is an ASCII byte, return a code point whose value
+ // is byte.
+ if (isASCIIByte(bite))
+ return bite;
+
+ // 5. If byte is in the range 0x81 to 0xFE, inclusive, set Big5
+ // lead to byte and return continue.
+ if (inRange(bite, 0x81, 0xFE)) {
+ Big5_lead = bite;
+ return null;
+ }
+
+ // 6. Return error.
+ return decoderError(fatal);
+ };
+ }
+
+ // 12.1.2 Big5 encoder
+ /**
+ * @constructor
+ * @implements {Encoder}
+ * @param {{fatal: boolean}} options
+ */
+ function Big5Encoder(options) {
+ var fatal = options.fatal;
+ /**
+ * @param {Stream} stream Input stream.
+ * @param {number} code_point Next code point read from the stream.
+ * @return {(number|!Array.<number>)} Byte(s) to emit.
+ */
+ this.handler = function(stream, code_point) {
+ // 1. If code point is end-of-stream, return finished.
+ if (code_point === end_of_stream)
+ return finished;
+
+ // 2. If code point is an ASCII code point, return a byte whose
+ // value is code point.
+ if (isASCIICodePoint(code_point))
+ return code_point;
+
+ // 3. Let pointer be the index Big5 pointer for code point.
+ var pointer = indexBig5PointerFor(code_point);
+
+ // 4. If pointer is null, return error with code point.
+ if (pointer === null)
+ return encoderError(code_point);
+
+ // 5. Let lead be floor(pointer / 157) + 0x81.
+ var lead = floor(pointer / 157) + 0x81;
+
+ // 6. If lead is less than 0xA1, return error with code point.
+ if (lead < 0xA1)
+ return encoderError(code_point);
+
+ // 7. Let trail be pointer % 157.
+ var trail = pointer % 157;
+
+ // 8. Let offset be 0x40 if trail is less than 0x3F and 0x62
+ // otherwise.
+ var offset = trail < 0x3F ? 0x40 : 0x62;
+
+ // Return two bytes whose values are lead and trail + offset.
+ return [lead, trail + offset];
+ };
+ }
+
+ /** @param {{fatal: boolean}} options */
+ encoders['Big5'] = function(options) {
+ return new Big5Encoder(options);
+ };
+ /** @param {{fatal: boolean}} options */
+ decoders['Big5'] = function(options) {
+ return new Big5Decoder(options);
+ };
+
+
+ //
+ // 13. Legacy multi-byte Japanese encodings
+ //
+
+ // 13.1 euc-jp
+
+ // 13.1.1 euc-jp decoder
+ /**
+ * @constructor
+ * @implements {Decoder}
+ * @param {{fatal: boolean}} options
+ */
+ function EUCJPDecoder(options) {
+ var fatal = options.fatal;
+
+ // euc-jp's decoder has an associated euc-jp jis0212 flag
+ // (initially unset) and euc-jp lead (initially 0x00).
+ var /** @type {boolean} */ eucjp_jis0212_flag = false,
+ /** @type {number} */ eucjp_lead = 0x00;
+
+ /**
+ * @param {Stream} stream The stream of bytes being decoded.
+ * @param {number} bite The next byte read from the stream.
+ * @return {?(number|!Array.<number>)} The next code point(s)
+ * decoded, or null if not enough data exists in the input
+ * stream to decode a complete code point.
+ */
+ this.handler = function(stream, bite) {
+ // 1. If byte is end-of-stream and euc-jp lead is not 0x00, set
+ // euc-jp lead to 0x00, and return error.
+ if (bite === end_of_stream && eucjp_lead !== 0x00) {
+ eucjp_lead = 0x00;
+ return decoderError(fatal);
+ }
+
+ // 2. If byte is end-of-stream and euc-jp lead is 0x00, return
+ // finished.
+ if (bite === end_of_stream && eucjp_lead === 0x00)
+ return finished;
+
+ // 3. If euc-jp lead is 0x8E and byte is in the range 0xA1 to
+ // 0xDF, inclusive, set euc-jp lead to 0x00 and return a code
+ // point whose value is 0xFF61 − 0xA1 + byte.
+ if (eucjp_lead === 0x8E && inRange(bite, 0xA1, 0xDF)) {
+ eucjp_lead = 0x00;
+ return 0xFF61 - 0xA1 + bite;
+ }
+
+ // 4. If euc-jp lead is 0x8F and byte is in the range 0xA1 to
+ // 0xFE, inclusive, set the euc-jp jis0212 flag, set euc-jp lead
+ // to byte, and return continue.
+ if (eucjp_lead === 0x8F && inRange(bite, 0xA1, 0xFE)) {
+ eucjp_jis0212_flag = true;
+ eucjp_lead = bite;
+ return null;
+ }
+
+ // 5. If euc-jp lead is not 0x00, let lead be euc-jp lead, set
+ // euc-jp lead to 0x00, and run these substeps:
+ if (eucjp_lead !== 0x00) {
+ var lead = eucjp_lead;
+ eucjp_lead = 0x00;
+
+ // 1. Let code point be null.
+ var code_point = null;
+
+ // 2. If lead and byte are both in the range 0xA1 to 0xFE,
+ // inclusive, set code point to the index code point for (lead
+ // − 0xA1) × 94 + byte − 0xA1 in index jis0208 if the euc-jp
+ // jis0212 flag is unset and in index jis0212 otherwise.
+ if (inRange(lead, 0xA1, 0xFE) && inRange(bite, 0xA1, 0xFE)) {
+ code_point = indexCodePointFor(
+ (lead - 0xA1) * 94 + (bite - 0xA1),
+ index(!eucjp_jis0212_flag ? 'jis0208' : 'jis0212'));
+ }
+
+ // 3. Unset the euc-jp jis0212 flag.
+ eucjp_jis0212_flag = false;
+
+ // 4. If byte is not in the range 0xA1 to 0xFE, inclusive,
+ // prepend byte to stream.
+ if (!inRange(bite, 0xA1, 0xFE))
+ stream.prepend(bite);
+
+ // 5. If code point is null, return error.
+ if (code_point === null)
+ return decoderError(fatal);
+
+ // 6. Return a code point whose value is code point.
+ return code_point;
+ }
+
+ // 6. If byte is an ASCII byte, return a code point whose value
+ // is byte.
+ if (isASCIIByte(bite))
+ return bite;
+
+ // 7. If byte is 0x8E, 0x8F, or in the range 0xA1 to 0xFE,
+ // inclusive, set euc-jp lead to byte and return continue.
+ if (bite === 0x8E || bite === 0x8F || inRange(bite, 0xA1, 0xFE)) {
+ eucjp_lead = bite;
+ return null;
+ }
+
+ // 8. Return error.
+ return decoderError(fatal);
+ };
+ }
+
+ // 13.1.2 euc-jp encoder
+ /**
+ * @constructor
+ * @implements {Encoder}
+ * @param {{fatal: boolean}} options
+ */
+ function EUCJPEncoder(options) {
+ var fatal = options.fatal;
+ /**
+ * @param {Stream} stream Input stream.
+ * @param {number} code_point Next code point read from the stream.
+ * @return {(number|!Array.<number>)} Byte(s) to emit.
+ */
+ this.handler = function(stream, code_point) {
+ // 1. If code point is end-of-stream, return finished.
+ if (code_point === end_of_stream)
+ return finished;
+
+ // 2. If code point is an ASCII code point, return a byte whose
+ // value is code point.
+ if (isASCIICodePoint(code_point))
+ return code_point;
+
+ // 3. If code point is U+00A5, return byte 0x5C.
+ if (code_point === 0x00A5)
+ return 0x5C;
+
+ // 4. If code point is U+203E, return byte 0x7E.
+ if (code_point === 0x203E)
+ return 0x7E;
+
+ // 5. If code point is in the range U+FF61 to U+FF9F, inclusive,
+ // return two bytes whose values are 0x8E and code point −
+ // 0xFF61 + 0xA1.
+ if (inRange(code_point, 0xFF61, 0xFF9F))
+ return [0x8E, code_point - 0xFF61 + 0xA1];
+
+ // 6. If code point is U+2212, set it to U+FF0D.
+ if (code_point === 0x2212)
+ code_point = 0xFF0D;
+
+ // 7. Let pointer be the index pointer for code point in index
+ // jis0208.
+ var pointer = indexPointerFor(code_point, index('jis0208'));
+
+ // 8. If pointer is null, return error with code point.
+ if (pointer === null)
+ return encoderError(code_point);
+
+ // 9. Let lead be floor(pointer / 94) + 0xA1.
+ var lead = floor(pointer / 94) + 0xA1;
+
+ // 10. Let trail be pointer % 94 + 0xA1.
+ var trail = pointer % 94 + 0xA1;
+
+ // 11. Return two bytes whose values are lead and trail.
+ return [lead, trail];
+ };
+ }
+
+ /** @param {{fatal: boolean}} options */
+ encoders['EUC-JP'] = function(options) {
+ return new EUCJPEncoder(options);
+ };
+ /** @param {{fatal: boolean}} options */
+ decoders['EUC-JP'] = function(options) {
+ return new EUCJPDecoder(options);
+ };
+
+ // 13.2 iso-2022-jp
+
+ // 13.2.1 iso-2022-jp decoder
+ /**
+ * @constructor
+ * @implements {Decoder}
+ * @param {{fatal: boolean}} options
+ */
+ function ISO2022JPDecoder(options) {
+ var fatal = options.fatal;
+ /** @enum */
+ var states = {
+ ASCII: 0,
+ Roman: 1,
+ Katakana: 2,
+ LeadByte: 3,
+ TrailByte: 4,
+ EscapeStart: 5,
+ Escape: 6
+ };
+ // iso-2022-jp's decoder has an associated iso-2022-jp decoder
+ // state (initially ASCII), iso-2022-jp decoder output state
+ // (initially ASCII), iso-2022-jp lead (initially 0x00), and
+ // iso-2022-jp output flag (initially unset).
+ var /** @type {number} */ iso2022jp_decoder_state = states.ASCII,
+ /** @type {number} */ iso2022jp_decoder_output_state = states.ASCII,
+ /** @type {number} */ iso2022jp_lead = 0x00,
+ /** @type {boolean} */ iso2022jp_output_flag = false;
+ /**
+ * @param {Stream} stream The stream of bytes being decoded.
+ * @param {number} bite The next byte read from the stream.
+ * @return {?(number|!Array.<number>)} The next code point(s)
+ * decoded, or null if not enough data exists in the input
+ * stream to decode a complete code point.
+ */
+ this.handler = function(stream, bite) {
+ // switching on iso-2022-jp decoder state:
+ switch (iso2022jp_decoder_state) {
+ default:
+ case states.ASCII:
+ // ASCII
+ // Based on byte:
+
+ // 0x1B
+ if (bite === 0x1B) {
+ // Set iso-2022-jp decoder state to escape start and return
+ // continue.
+ iso2022jp_decoder_state = states.EscapeStart;
+ return null;
+ }
+
+ // 0x00 to 0x7F, excluding 0x0E, 0x0F, and 0x1B
+ if (inRange(bite, 0x00, 0x7F) && bite !== 0x0E
+ && bite !== 0x0F && bite !== 0x1B) {
+ // Unset the iso-2022-jp output flag and return a code point
+ // whose value is byte.
+ iso2022jp_output_flag = false;
+ return bite;
+ }
+
+ // end-of-stream
+ if (bite === end_of_stream) {
+ // Return finished.
+ return finished;
+ }
+
+ // Otherwise
+ // Unset the iso-2022-jp output flag and return error.
+ iso2022jp_output_flag = false;
+ return decoderError(fatal);
+
+ case states.Roman:
+ // Roman
+ // Based on byte:
+
+ // 0x1B
+ if (bite === 0x1B) {
+ // Set iso-2022-jp decoder state to escape start and return
+ // continue.
+ iso2022jp_decoder_state = states.EscapeStart;
+ return null;
+ }
+
+ // 0x5C
+ if (bite === 0x5C) {
+ // Unset the iso-2022-jp output flag and return code point
+ // U+00A5.
+ iso2022jp_output_flag = false;
+ return 0x00A5;
+ }
+
+ // 0x7E
+ if (bite === 0x7E) {
+ // Unset the iso-2022-jp output flag and return code point
+ // U+203E.
+ iso2022jp_output_flag = false;
+ return 0x203E;
+ }
+
+ // 0x00 to 0x7F, excluding 0x0E, 0x0F, 0x1B, 0x5C, and 0x7E
+ if (inRange(bite, 0x00, 0x7F) && bite !== 0x0E && bite !== 0x0F
+ && bite !== 0x1B && bite !== 0x5C && bite !== 0x7E) {
+ // Unset the iso-2022-jp output flag and return a code point
+ // whose value is byte.
+ iso2022jp_output_flag = false;
+ return bite;
+ }
+
+ // end-of-stream
+ if (bite === end_of_stream) {
+ // Return finished.
+ return finished;
+ }
+
+ // Otherwise
+ // Unset the iso-2022-jp output flag and return error.
+ iso2022jp_output_flag = false;
+ return decoderError(fatal);
+
+ case states.Katakana:
+ // Katakana
+ // Based on byte:
+
+ // 0x1B
+ if (bite === 0x1B) {
+ // Set iso-2022-jp decoder state to escape start and return
+ // continue.
+ iso2022jp_decoder_state = states.EscapeStart;
+ return null;
+ }
+
+ // 0x21 to 0x5F
+ if (inRange(bite, 0x21, 0x5F)) {
+ // Unset the iso-2022-jp output flag and return a code point
+ // whose value is 0xFF61 − 0x21 + byte.
+ iso2022jp_output_flag = false;
+ return 0xFF61 - 0x21 + bite;
+ }
+
+ // end-of-stream
+ if (bite === end_of_stream) {
+ // Return finished.
+ return finished;
+ }
+
+ // Otherwise
+ // Unset the iso-2022-jp output flag and return error.
+ iso2022jp_output_flag = false;
+ return decoderError(fatal);
+
+ case states.LeadByte:
+ // Lead byte
+ // Based on byte:
+
+ // 0x1B
+ if (bite === 0x1B) {
+ // Set iso-2022-jp decoder state to escape start and return
+ // continue.
+ iso2022jp_decoder_state = states.EscapeStart;
+ return null;
+ }
+
+ // 0x21 to 0x7E
+ if (inRange(bite, 0x21, 0x7E)) {
+ // Unset the iso-2022-jp output flag, set iso-2022-jp lead
+ // to byte, iso-2022-jp decoder state to trail byte, and
+ // return continue.
+ iso2022jp_output_flag = false;
+ iso2022jp_lead = bite;
+ iso2022jp_decoder_state = states.TrailByte;
+ return null;
+ }
+
+ // end-of-stream
+ if (bite === end_of_stream) {
+ // Return finished.
+ return finished;
+ }
+
+ // Otherwise
+ // Unset the iso-2022-jp output flag and return error.
+ iso2022jp_output_flag = false;
+ return decoderError(fatal);
+
+ case states.TrailByte:
+ // Trail byte
+ // Based on byte:
+
+ // 0x1B
+ if (bite === 0x1B) {
+ // Set iso-2022-jp decoder state to escape start and return
+ // continue.
+ iso2022jp_decoder_state = states.EscapeStart;
+ return decoderError(fatal);
+ }
+
+ // 0x21 to 0x7E
+ if (inRange(bite, 0x21, 0x7E)) {
+ // 1. Set the iso-2022-jp decoder state to lead byte.
+ iso2022jp_decoder_state = states.LeadByte;
+
+ // 2. Let pointer be (iso-2022-jp lead − 0x21) × 94 + byte − 0x21.
+ var pointer = (iso2022jp_lead - 0x21) * 94 + bite - 0x21;
+
+ // 3. Let code point be the index code point for pointer in
+ // index jis0208.
+ var code_point = indexCodePointFor(pointer, index('jis0208'));
+
+ // 4. If code point is null, return error.
+ if (code_point === null)
+ return decoderError(fatal);
+
+ // 5. Return a code point whose value is code point.
+ return code_point;
+ }
+
+ // end-of-stream
+ if (bite === end_of_stream) {
+ // Set the iso-2022-jp decoder state to lead byte, prepend
+ // byte to stream, and return error.
+ iso2022jp_decoder_state = states.LeadByte;
+ stream.prepend(bite);
+ return decoderError(fatal);
+ }
+
+ // Otherwise
+ // Set iso-2022-jp decoder state to lead byte and return
+ // error.
+ iso2022jp_decoder_state = states.LeadByte;
+ return decoderError(fatal);
+
+ case states.EscapeStart:
+ // Escape start
+
+ // 1. If byte is either 0x24 or 0x28, set iso-2022-jp lead to
+ // byte, iso-2022-jp decoder state to escape, and return
+ // continue.
+ if (bite === 0x24 || bite === 0x28) {
+ iso2022jp_lead = bite;
+ iso2022jp_decoder_state = states.Escape;
+ return null;
+ }
+
+ // 2. Prepend byte to stream.
+ stream.prepend(bite);
+
+ // 3. Unset the iso-2022-jp output flag, set iso-2022-jp
+ // decoder state to iso-2022-jp decoder output state, and
+ // return error.
+ iso2022jp_output_flag = false;
+ iso2022jp_decoder_state = iso2022jp_decoder_output_state;
+ return decoderError(fatal);
+
+ case states.Escape:
+ // Escape
+
+ // 1. Let lead be iso-2022-jp lead and set iso-2022-jp lead to
+ // 0x00.
+ var lead = iso2022jp_lead;
+ iso2022jp_lead = 0x00;
+
+ // 2. Let state be null.
+ var state = null;
+
+ // 3. If lead is 0x28 and byte is 0x42, set state to ASCII.
+ if (lead === 0x28 && bite === 0x42)
+ state = states.ASCII;
+
+ // 4. If lead is 0x28 and byte is 0x4A, set state to Roman.
+ if (lead === 0x28 && bite === 0x4A)
+ state = states.Roman;
+
+ // 5. If lead is 0x28 and byte is 0x49, set state to Katakana.
+ if (lead === 0x28 && bite === 0x49)
+ state = states.Katakana;
+
+ // 6. If lead is 0x24 and byte is either 0x40 or 0x42, set
+ // state to lead byte.
+ if (lead === 0x24 && (bite === 0x40 || bite === 0x42))
+ state = states.LeadByte;
+
+ // 7. If state is non-null, run these substeps:
+ if (state !== null) {
+ // 1. Set iso-2022-jp decoder state and iso-2022-jp decoder
+ // output state to states.
+ iso2022jp_decoder_state = iso2022jp_decoder_state = state;
+
+ // 2. Let output flag be the iso-2022-jp output flag.
+ var output_flag = iso2022jp_output_flag;
+
+ // 3. Set the iso-2022-jp output flag.
+ iso2022jp_output_flag = true;
+
+ // 4. Return continue, if output flag is unset, and error
+ // otherwise.
+ return !output_flag ? null : decoderError(fatal);
+ }
+
+ // 8. Prepend lead and byte to stream.
+ stream.prepend([lead, bite]);
+
+ // 9. Unset the iso-2022-jp output flag, set iso-2022-jp
+ // decoder state to iso-2022-jp decoder output state and
+ // return error.
+ iso2022jp_output_flag = false;
+ iso2022jp_decoder_state = iso2022jp_decoder_output_state;
+ return decoderError(fatal);
+ }
+ };
+ }
+
+ // 13.2.2 iso-2022-jp encoder
+ /**
+ * @constructor
+ * @implements {Encoder}
+ * @param {{fatal: boolean}} options
+ */
+ function ISO2022JPEncoder(options) {
+ var fatal = options.fatal;
+ // iso-2022-jp's encoder has an associated iso-2022-jp encoder
+ // state which is one of ASCII, Roman, and jis0208 (initially
+ // ASCII).
+ /** @enum */
+ var states = {
+ ASCII: 0,
+ Roman: 1,
+ jis0208: 2
+ };
+ var /** @type {number} */ iso2022jp_state = states.ASCII;
+ /**
+ * @param {Stream} stream Input stream.
+ * @param {number} code_point Next code point read from the stream.
+ * @return {(number|!Array.<number>)} Byte(s) to emit.
+ */
+ this.handler = function(stream, code_point) {
+ // 1. If code point is end-of-stream and iso-2022-jp encoder
+ // state is not ASCII, prepend code point to stream, set
+ // iso-2022-jp encoder state to ASCII, and return three bytes
+ // 0x1B 0x28 0x42.
+ if (code_point === end_of_stream &&
+ iso2022jp_state !== states.ASCII) {
+ stream.prepend(code_point);
+ iso2022jp_state = states.ASCII;
+ return [0x1B, 0x28, 0x42];
+ }
+
+ // 2. If code point is end-of-stream and iso-2022-jp encoder
+ // state is ASCII, return finished.
+ if (code_point === end_of_stream && iso2022jp_state === states.ASCII)
+ return finished;
+
+ // 3. If ISO-2022-JP encoder state is ASCII or Roman, and code
+ // point is U+000E, U+000F, or U+001B, return error with U+FFFD.
+ if ((iso2022jp_state === states.ASCII ||
+ iso2022jp_state === states.Roman) &&
+ (code_point === 0x000E || code_point === 0x000F ||
+ code_point === 0x001B)) {
+ return encoderError(0xFFFD);
+ }
+
+ // 4. If iso-2022-jp encoder state is ASCII and code point is an
+ // ASCII code point, return a byte whose value is code point.
+ if (iso2022jp_state === states.ASCII &&
+ isASCIICodePoint(code_point))
+ return code_point;
+
+ // 5. If iso-2022-jp encoder state is Roman and code point is an
+ // ASCII code point, excluding U+005C and U+007E, or is U+00A5
+ // or U+203E, run these substeps:
+ if (iso2022jp_state === states.Roman &&
+ ((isASCIICodePoint(code_point) &&
+ code_point !== 0x005C && code_point !== 0x007E) ||
+ (code_point == 0x00A5 || code_point == 0x203E))) {
+
+ // 1. If code point is an ASCII code point, return a byte
+ // whose value is code point.
+ if (isASCIICodePoint(code_point))
+ return code_point;
+
+ // 2. If code point is U+00A5, return byte 0x5C.
+ if (code_point === 0x00A5)
+ return 0x5C;
+
+ // 3. If code point is U+203E, return byte 0x7E.
+ if (code_point === 0x203E)
+ return 0x7E;
+ }
+
+ // 6. If code point is an ASCII code point, and iso-2022-jp
+ // encoder state is not ASCII, prepend code point to stream, set
+ // iso-2022-jp encoder state to ASCII, and return three bytes
+ // 0x1B 0x28 0x42.
+ if (isASCIICodePoint(code_point) &&
+ iso2022jp_state !== states.ASCII) {
+ stream.prepend(code_point);
+ iso2022jp_state = states.ASCII;
+ return [0x1B, 0x28, 0x42];
+ }
+
+ // 7. If code point is either U+00A5 or U+203E, and iso-2022-jp
+ // encoder state is not Roman, prepend code point to stream, set
+ // iso-2022-jp encoder state to Roman, and return three bytes
+ // 0x1B 0x28 0x4A.
+ if ((code_point === 0x00A5 || code_point === 0x203E) &&
+ iso2022jp_state !== states.Roman) {
+ stream.prepend(code_point);
+ iso2022jp_state = states.Roman;
+ return [0x1B, 0x28, 0x4A];
+ }
+
+ // 8. If code point is U+2212, set it to U+FF0D.
+ if (code_point === 0x2212)
+ code_point = 0xFF0D;
+
+ // 9. Let pointer be the index pointer for code point in index
+ // jis0208.
+ var pointer = indexPointerFor(code_point, index('jis0208'));
+
+ // 10. If pointer is null, return error with code point.
+ if (pointer === null)
+ return encoderError(code_point);
+
+ // 11. If iso-2022-jp encoder state is not jis0208, prepend code
+ // point to stream, set iso-2022-jp encoder state to jis0208,
+ // and return three bytes 0x1B 0x24 0x42.
+ if (iso2022jp_state !== states.jis0208) {
+ stream.prepend(code_point);
+ iso2022jp_state = states.jis0208;
+ return [0x1B, 0x24, 0x42];
+ }
+
+ // 12. Let lead be floor(pointer / 94) + 0x21.
+ var lead = floor(pointer / 94) + 0x21;
+
+ // 13. Let trail be pointer % 94 + 0x21.
+ var trail = pointer % 94 + 0x21;
+
+ // 14. Return two bytes whose values are lead and trail.
+ return [lead, trail];
+ };
+ }
+
+ /** @param {{fatal: boolean}} options */
+ encoders['ISO-2022-JP'] = function(options) {
+ return new ISO2022JPEncoder(options);
+ };
+ /** @param {{fatal: boolean}} options */
+ decoders['ISO-2022-JP'] = function(options) {
+ return new ISO2022JPDecoder(options);
+ };
+
+ // 13.3 Shift_JIS
+
+ // 13.3.1 Shift_JIS decoder
+ /**
+ * @constructor
+ * @implements {Decoder}
+ * @param {{fatal: boolean}} options
+ */
+ function ShiftJISDecoder(options) {
+ var fatal = options.fatal;
+ // Shift_JIS's decoder has an associated Shift_JIS lead (initially
+ // 0x00).
+ var /** @type {number} */ Shift_JIS_lead = 0x00;
+ /**
+ * @param {Stream} stream The stream of bytes being decoded.
+ * @param {number} bite The next byte read from the stream.
+ * @return {?(number|!Array.<number>)} The next code point(s)
+ * decoded, or null if not enough data exists in the input
+ * stream to decode a complete code point.
+ */
+ this.handler = function(stream, bite) {
+ // 1. If byte is end-of-stream and Shift_JIS lead is not 0x00,
+ // set Shift_JIS lead to 0x00 and return error.
+ if (bite === end_of_stream && Shift_JIS_lead !== 0x00) {
+ Shift_JIS_lead = 0x00;
+ return decoderError(fatal);
+ }
+
+ // 2. If byte is end-of-stream and Shift_JIS lead is 0x00,
+ // return finished.
+ if (bite === end_of_stream && Shift_JIS_lead === 0x00)
+ return finished;
+
+ // 3. If Shift_JIS lead is not 0x00, let lead be Shift_JIS lead,
+ // let pointer be null, set Shift_JIS lead to 0x00, and then run
+ // these substeps:
+ if (Shift_JIS_lead !== 0x00) {
+ var lead = Shift_JIS_lead;
+ var pointer = null;
+ Shift_JIS_lead = 0x00;
+
+ // 1. Let offset be 0x40, if byte is less than 0x7F, and 0x41
+ // otherwise.
+ var offset = (bite < 0x7F) ? 0x40 : 0x41;
+
+ // 2. Let lead offset be 0x81, if lead is less than 0xA0, and
+ // 0xC1 otherwise.
+ var lead_offset = (lead < 0xA0) ? 0x81 : 0xC1;
+
+ // 3. If byte is in the range 0x40 to 0x7E, inclusive, or 0x80
+ // to 0xFC, inclusive, set pointer to (lead − lead offset) ×
+ // 188 + byte − offset.
+ if (inRange(bite, 0x40, 0x7E) || inRange(bite, 0x80, 0xFC))
+ pointer = (lead - lead_offset) * 188 + bite - offset;
+
+ // 4. If pointer is in the range 8836 to 10715, inclusive,
+ // return a code point whose value is 0xE000 − 8836 + pointer.
+ if (inRange(pointer, 8836, 10715))
+ return 0xE000 - 8836 + pointer;
+
+ // 5. Let code point be null, if pointer is null, and the
+ // index code point for pointer in index jis0208 otherwise.
+ var code_point = (pointer === null) ? null :
+ indexCodePointFor(pointer, index('jis0208'));
+
+ // 6. If code point is null and byte is an ASCII byte, prepend
+ // byte to stream.
+ if (code_point === null && isASCIIByte(bite))
+ stream.prepend(bite);
+
+ // 7. If code point is null, return error.
+ if (code_point === null)
+ return decoderError(fatal);
+
+ // 8. Return a code point whose value is code point.
+ return code_point;
+ }
+
+ // 4. If byte is an ASCII byte or 0x80, return a code point
+ // whose value is byte.
+ if (isASCIIByte(bite) || bite === 0x80)
+ return bite;
+
+ // 5. If byte is in the range 0xA1 to 0xDF, inclusive, return a
+ // code point whose value is 0xFF61 − 0xA1 + byte.
+ if (inRange(bite, 0xA1, 0xDF))
+ return 0xFF61 - 0xA1 + bite;
+
+ // 6. If byte is in the range 0x81 to 0x9F, inclusive, or 0xE0
+ // to 0xFC, inclusive, set Shift_JIS lead to byte and return
+ // continue.
+ if (inRange(bite, 0x81, 0x9F) || inRange(bite, 0xE0, 0xFC)) {
+ Shift_JIS_lead = bite;
+ return null;
+ }
+
+ // 7. Return error.
+ return decoderError(fatal);
+ };
+ }
+
+ // 13.3.2 Shift_JIS encoder
+ /**
+ * @constructor
+ * @implements {Encoder}
+ * @param {{fatal: boolean}} options
+ */
+ function ShiftJISEncoder(options) {
+ var fatal = options.fatal;
+ /**
+ * @param {Stream} stream Input stream.
+ * @param {number} code_point Next code point read from the stream.
+ * @return {(number|!Array.<number>)} Byte(s) to emit.
+ */
+ this.handler = function(stream, code_point) {
+ // 1. If code point is end-of-stream, return finished.
+ if (code_point === end_of_stream)
+ return finished;
+
+ // 2. If code point is an ASCII code point or U+0080, return a
+ // byte whose value is code point.
+ if (isASCIICodePoint(code_point) || code_point === 0x0080)
+ return code_point;
+
+ // 3. If code point is U+00A5, return byte 0x5C.
+ if (code_point === 0x00A5)
+ return 0x5C;
+
+ // 4. If code point is U+203E, return byte 0x7E.
+ if (code_point === 0x203E)
+ return 0x7E;
+
+ // 5. If code point is in the range U+FF61 to U+FF9F, inclusive,
+ // return a byte whose value is code point − 0xFF61 + 0xA1.
+ if (inRange(code_point, 0xFF61, 0xFF9F))
+ return code_point - 0xFF61 + 0xA1;
+
+ // 6. If code point is U+2212, set it to U+FF0D.
+ if (code_point === 0x2212)
+ code_point = 0xFF0D;
+
+ // 7. Let pointer be the index Shift_JIS pointer for code point.
+ var pointer = indexShiftJISPointerFor(code_point);
+
+ // 8. If pointer is null, return error with code point.
+ if (pointer === null)
+ return encoderError(code_point);
+
+ // 9. Let lead be floor(pointer / 188).
+ var lead = floor(pointer / 188);
+
+ // 10. Let lead offset be 0x81, if lead is less than 0x1F, and
+ // 0xC1 otherwise.
+ var lead_offset = (lead < 0x1F) ? 0x81 : 0xC1;
+
+ // 11. Let trail be pointer % 188.
+ var trail = pointer % 188;
+
+ // 12. Let offset be 0x40, if trail is less than 0x3F, and 0x41
+ // otherwise.
+ var offset = (trail < 0x3F) ? 0x40 : 0x41;
+
+ // 13. Return two bytes whose values are lead + lead offset and
+ // trail + offset.
+ return [lead + lead_offset, trail + offset];
+ };
+ }
+
+ /** @param {{fatal: boolean}} options */
+ encoders['Shift_JIS'] = function(options) {
+ return new ShiftJISEncoder(options);
+ };
+ /** @param {{fatal: boolean}} options */
+ decoders['Shift_JIS'] = function(options) {
+ return new ShiftJISDecoder(options);
+ };
+
+ //
+ // 14. Legacy multi-byte Korean encodings
+ //
+
+ // 14.1 euc-kr
+
+ // 14.1.1 euc-kr decoder
+ /**
+ * @constructor
+ * @implements {Decoder}
+ * @param {{fatal: boolean}} options
+ */
+ function EUCKRDecoder(options) {
+ var fatal = options.fatal;
+
+ // euc-kr's decoder has an associated euc-kr lead (initially 0x00).
+ var /** @type {number} */ euckr_lead = 0x00;
+ /**
+ * @param {Stream} stream The stream of bytes being decoded.
+ * @param {number} bite The next byte read from the stream.
+ * @return {?(number|!Array.<number>)} The next code point(s)
+ * decoded, or null if not enough data exists in the input
+ * stream to decode a complete code point.
+ */
+ this.handler = function(stream, bite) {
+ // 1. If byte is end-of-stream and euc-kr lead is not 0x00, set
+ // euc-kr lead to 0x00 and return error.
+ if (bite === end_of_stream && euckr_lead !== 0) {
+ euckr_lead = 0x00;
+ return decoderError(fatal);
+ }
+
+ // 2. If byte is end-of-stream and euc-kr lead is 0x00, return
+ // finished.
+ if (bite === end_of_stream && euckr_lead === 0)
+ return finished;
+
+ // 3. If euc-kr lead is not 0x00, let lead be euc-kr lead, let
+ // pointer be null, set euc-kr lead to 0x00, and then run these
+ // substeps:
+ if (euckr_lead !== 0x00) {
+ var lead = euckr_lead;
+ var pointer = null;
+ euckr_lead = 0x00;
+
+ // 1. If byte is in the range 0x41 to 0xFE, inclusive, set
+ // pointer to (lead − 0x81) × 190 + (byte − 0x41).
+ if (inRange(bite, 0x41, 0xFE))
+ pointer = (lead - 0x81) * 190 + (bite - 0x41);
+
+ // 2. Let code point be null, if pointer is null, and the
+ // index code point for pointer in index euc-kr otherwise.
+ var code_point = (pointer === null)
+ ? null : indexCodePointFor(pointer, index('euc-kr'));
+
+ // 3. If code point is null and byte is an ASCII byte, prepend
+ // byte to stream.
+ if (pointer === null && isASCIIByte(bite))
+ stream.prepend(bite);
+
+ // 4. If code point is null, return error.
+ if (code_point === null)
+ return decoderError(fatal);
+
+ // 5. Return a code point whose value is code point.
+ return code_point;
+ }
+
+ // 4. If byte is an ASCII byte, return a code point whose value
+ // is byte.
+ if (isASCIIByte(bite))
+ return bite;
+
+ // 5. If byte is in the range 0x81 to 0xFE, inclusive, set
+ // euc-kr lead to byte and return continue.
+ if (inRange(bite, 0x81, 0xFE)) {
+ euckr_lead = bite;
+ return null;
+ }
+
+ // 6. Return error.
+ return decoderError(fatal);
+ };
+ }
+
+ // 14.1.2 euc-kr encoder
+ /**
+ * @constructor
+ * @implements {Encoder}
+ * @param {{fatal: boolean}} options
+ */
+ function EUCKREncoder(options) {
+ var fatal = options.fatal;
+ /**
+ * @param {Stream} stream Input stream.
+ * @param {number} code_point Next code point read from the stream.
+ * @return {(number|!Array.<number>)} Byte(s) to emit.
+ */
+ this.handler = function(stream, code_point) {
+ // 1. If code point is end-of-stream, return finished.
+ if (code_point === end_of_stream)
+ return finished;
+
+ // 2. If code point is an ASCII code point, return a byte whose
+ // value is code point.
+ if (isASCIICodePoint(code_point))
+ return code_point;
+
+ // 3. Let pointer be the index pointer for code point in index
+ // euc-kr.
+ var pointer = indexPointerFor(code_point, index('euc-kr'));
+
+ // 4. If pointer is null, return error with code point.
+ if (pointer === null)
+ return encoderError(code_point);
+
+ // 5. Let lead be floor(pointer / 190) + 0x81.
+ var lead = floor(pointer / 190) + 0x81;
+
+ // 6. Let trail be pointer % 190 + 0x41.
+ var trail = (pointer % 190) + 0x41;
+
+ // 7. Return two bytes whose values are lead and trail.
+ return [lead, trail];
+ };
+ }
+
+ /** @param {{fatal: boolean}} options */
+ encoders['EUC-KR'] = function(options) {
+ return new EUCKREncoder(options);
+ };
+ /** @param {{fatal: boolean}} options */
+ decoders['EUC-KR'] = function(options) {
+ return new EUCKRDecoder(options);
+ };
+
+
+ //
+ // 15. Legacy miscellaneous encodings
+ //
+
+ // 15.1 replacement
+
+ // Not needed - API throws RangeError
+
+ // 15.2 Common infrastructure for utf-16be and utf-16le
+
+ /**
+ * @param {number} code_unit
+ * @param {boolean} utf16be
+ * @return {!Array.<number>} bytes
+ */
+ function convertCodeUnitToBytes(code_unit, utf16be) {
+ // 1. Let byte1 be code unit >> 8.
+ var byte1 = code_unit >> 8;
+
+ // 2. Let byte2 be code unit & 0x00FF.
+ var byte2 = code_unit & 0x00FF;
+
+ // 3. Then return the bytes in order:
+ // utf-16be flag is set: byte1, then byte2.
+ if (utf16be)
+ return [byte1, byte2];
+ // utf-16be flag is unset: byte2, then byte1.
+ return [byte2, byte1];
+ }
+
+ // 15.2.1 shared utf-16 decoder
+ /**
+ * @constructor
+ * @implements {Decoder}
+ * @param {boolean} utf16_be True if big-endian, false if little-endian.
+ * @param {{fatal: boolean}} options
+ */
+ function UTF16Decoder(utf16_be, options) {
+ var fatal = options.fatal;
+ var /** @type {?number} */ utf16_lead_byte = null,
+ /** @type {?number} */ utf16_lead_surrogate = null;
+ /**
+ * @param {Stream} stream The stream of bytes being decoded.
+ * @param {number} bite The next byte read from the stream.
+ * @return {?(number|!Array.<number>)} The next code point(s)
+ * decoded, or null if not enough data exists in the input
+ * stream to decode a complete code point.
+ */
+ this.handler = function(stream, bite) {
+ // 1. If byte is end-of-stream and either utf-16 lead byte or
+ // utf-16 lead surrogate is not null, set utf-16 lead byte and
+ // utf-16 lead surrogate to null, and return error.
+ if (bite === end_of_stream && (utf16_lead_byte !== null ||
+ utf16_lead_surrogate !== null)) {
+ return decoderError(fatal);
+ }
+
+ // 2. If byte is end-of-stream and utf-16 lead byte and utf-16
+ // lead surrogate are null, return finished.
+ if (bite === end_of_stream && utf16_lead_byte === null &&
+ utf16_lead_surrogate === null) {
+ return finished;
+ }
+
+ // 3. If utf-16 lead byte is null, set utf-16 lead byte to byte
+ // and return continue.
+ if (utf16_lead_byte === null) {
+ utf16_lead_byte = bite;
+ return null;
+ }
+
+ // 4. Let code unit be the result of:
+ var code_unit;
+ if (utf16_be) {
+ // utf-16be decoder flag is set
+ // (utf-16 lead byte << 8) + byte.
+ code_unit = (utf16_lead_byte << 8) + bite;
+ } else {
+ // utf-16be decoder flag is unset
+ // (byte << 8) + utf-16 lead byte.
+ code_unit = (bite << 8) + utf16_lead_byte;
+ }
+ // Then set utf-16 lead byte to null.
+ utf16_lead_byte = null;
+
+ // 5. If utf-16 lead surrogate is not null, let lead surrogate
+ // be utf-16 lead surrogate, set utf-16 lead surrogate to null,
+ // and then run these substeps:
+ if (utf16_lead_surrogate !== null) {
+ var lead_surrogate = utf16_lead_surrogate;
+ utf16_lead_surrogate = null;
+
+ // 1. If code unit is in the range U+DC00 to U+DFFF,
+ // inclusive, return a code point whose value is 0x10000 +
+ // ((lead surrogate − 0xD800) << 10) + (code unit − 0xDC00).
+ if (inRange(code_unit, 0xDC00, 0xDFFF)) {
+ return 0x10000 + (lead_surrogate - 0xD800) * 0x400 +
+ (code_unit - 0xDC00);
+ }
+
+ // 2. Prepend the sequence resulting of converting code unit
+ // to bytes using utf-16be decoder flag to stream and return
+ // error.
+ stream.prepend(convertCodeUnitToBytes(code_unit, utf16_be));
+ return decoderError(fatal);
+ }
+
+ // 6. If code unit is in the range U+D800 to U+DBFF, inclusive,
+ // set utf-16 lead surrogate to code unit and return continue.
+ if (inRange(code_unit, 0xD800, 0xDBFF)) {
+ utf16_lead_surrogate = code_unit;
+ return null;
+ }
+
+ // 7. If code unit is in the range U+DC00 to U+DFFF, inclusive,
+ // return error.
+ if (inRange(code_unit, 0xDC00, 0xDFFF))
+ return decoderError(fatal);
+
+ // 8. Return code point code unit.
+ return code_unit;
+ };
+ }
+
+ // 15.2.2 shared utf-16 encoder
+ /**
+ * @constructor
+ * @implements {Encoder}
+ * @param {boolean} utf16_be True if big-endian, false if little-endian.
+ * @param {{fatal: boolean}} options
+ */
+ function UTF16Encoder(utf16_be, options) {
+ var fatal = options.fatal;
+ /**
+ * @param {Stream} stream Input stream.
+ * @param {number} code_point Next code point read from the stream.
+ * @return {(number|!Array.<number>)} Byte(s) to emit.
+ */
+ this.handler = function(stream, code_point) {
+ // 1. If code point is end-of-stream, return finished.
+ if (code_point === end_of_stream)
+ return finished;
+
+ // 2. If code point is in the range U+0000 to U+FFFF, inclusive,
+ // return the sequence resulting of converting code point to
+ // bytes using utf-16be encoder flag.
+ if (inRange(code_point, 0x0000, 0xFFFF))
+ return convertCodeUnitToBytes(code_point, utf16_be);
+
+ // 3. Let lead be ((code point − 0x10000) >> 10) + 0xD800,
+ // converted to bytes using utf-16be encoder flag.
+ var lead = convertCodeUnitToBytes(
+ ((code_point - 0x10000) >> 10) + 0xD800, utf16_be);
+
+ // 4. Let trail be ((code point − 0x10000) & 0x3FF) + 0xDC00,
+ // converted to bytes using utf-16be encoder flag.
+ var trail = convertCodeUnitToBytes(
+ ((code_point - 0x10000) & 0x3FF) + 0xDC00, utf16_be);
+
+ // 5. Return a byte sequence of lead followed by trail.
+ return lead.concat(trail);
+ };
+ }
+
+ // 15.3 utf-16be
+ // 15.3.1 utf-16be decoder
+ /** @param {{fatal: boolean}} options */
+ encoders['UTF-16BE'] = function(options) {
+ return new UTF16Encoder(true, options);
+ };
+ // 15.3.2 utf-16be encoder
+ /** @param {{fatal: boolean}} options */
+ decoders['UTF-16BE'] = function(options) {
+ return new UTF16Decoder(true, options);
+ };
+
+ // 15.4 utf-16le
+ // 15.4.1 utf-16le decoder
+ /** @param {{fatal: boolean}} options */
+ encoders['UTF-16LE'] = function(options) {
+ return new UTF16Encoder(false, options);
+ };
+ // 15.4.2 utf-16le encoder
+ /** @param {{fatal: boolean}} options */
+ decoders['UTF-16LE'] = function(options) {
+ return new UTF16Decoder(false, options);
+ };
+
+ // 15.5 x-user-defined
+
+ // 15.5.1 x-user-defined decoder
+ /**
+ * @constructor
+ * @implements {Decoder}
+ * @param {{fatal: boolean}} options
+ */
+ function XUserDefinedDecoder(options) {
+ var fatal = options.fatal;
+ /**
+ * @param {Stream} stream The stream of bytes being decoded.
+ * @param {number} bite The next byte read from the stream.
+ * @return {?(number|!Array.<number>)} The next code point(s)
+ * decoded, or null if not enough data exists in the input
+ * stream to decode a complete code point.
+ */
+ this.handler = function(stream, bite) {
+ // 1. If byte is end-of-stream, return finished.
+ if (bite === end_of_stream)
+ return finished;
+
+ // 2. If byte is an ASCII byte, return a code point whose value
+ // is byte.
+ if (isASCIIByte(bite))
+ return bite;
+
+ // 3. Return a code point whose value is 0xF780 + byte − 0x80.
+ return 0xF780 + bite - 0x80;
+ };
+ }
+
+ // 15.5.2 x-user-defined encoder
+ /**
+ * @constructor
+ * @implements {Encoder}
+ * @param {{fatal: boolean}} options
+ */
+ function XUserDefinedEncoder(options) {
+ var fatal = options.fatal;
+ /**
+ * @param {Stream} stream Input stream.
+ * @param {number} code_point Next code point read from the stream.
+ * @return {(number|!Array.<number>)} Byte(s) to emit.
+ */
+ this.handler = function(stream, code_point) {
+ // 1.If code point is end-of-stream, return finished.
+ if (code_point === end_of_stream)
+ return finished;
+
+ // 2. If code point is an ASCII code point, return a byte whose
+ // value is code point.
+ if (isASCIICodePoint(code_point))
+ return code_point;
+
+ // 3. If code point is in the range U+F780 to U+F7FF, inclusive,
+ // return a byte whose value is code point − 0xF780 + 0x80.
+ if (inRange(code_point, 0xF780, 0xF7FF))
+ return code_point - 0xF780 + 0x80;
+
+ // 4. Return error with code point.
+ return encoderError(code_point);
+ };
+ }
+
+ /** @param {{fatal: boolean}} options */
+ encoders['x-user-defined'] = function(options) {
+ return new XUserDefinedEncoder(options);
+ };
+ /** @param {{fatal: boolean}} options */
+ decoders['x-user-defined'] = function(options) {
+ return new XUserDefinedDecoder(options);
+ };
+
+ if (!global['TextEncoder'])
+ global['TextEncoder'] = TextEncoder;
+ if (!global['TextDecoder'])
+ global['TextDecoder'] = TextDecoder;
+
+ if (typeof module !== "undefined" && module.exports) {
+ module.exports = {
+ TextEncoder: global['TextEncoder'],
+ TextDecoder: global['TextDecoder'],
+ EncodingIndexes: global["encoding-indexes"]
+ };
+ }
+
+// For strict environments where `this` inside the global scope
+// is `undefined`, take a pure object instead
+}(this || {}));
+},{"./encoding-indexes.js":70}],72:[function(require,module,exports){
+(function (global){
+'use strict';
+/* !
+ * type-detect
+ * Copyright(c) 2013 jake luer <jake@alogicalparadox.com>
+ * MIT Licensed
+ */
+var promiseExists = typeof Promise === 'function';
+var globalObject = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : self; // eslint-disable-line
+var isDom = 'location' in globalObject && 'document' in globalObject;
+var symbolExists = typeof Symbol !== 'undefined';
+var mapExists = typeof Map !== 'undefined';
+var setExists = typeof Set !== 'undefined';
+var weakMapExists = typeof WeakMap !== 'undefined';
+var weakSetExists = typeof WeakSet !== 'undefined';
+var dataViewExists = typeof DataView !== 'undefined';
+var symbolIteratorExists = symbolExists && typeof Symbol.iterator !== 'undefined';
+var symbolToStringTagExists = symbolExists && typeof Symbol.toStringTag !== 'undefined';
+var setEntriesExists = setExists && typeof Set.prototype.entries === 'function';
+var mapEntriesExists = mapExists && typeof Map.prototype.entries === 'function';
+var setIteratorPrototype = setEntriesExists && Object.getPrototypeOf(new Set().entries());
+var mapIteratorPrototype = mapEntriesExists && Object.getPrototypeOf(new Map().entries());
+var arrayIteratorExists = symbolIteratorExists && typeof Array.prototype[Symbol.iterator] === 'function';
+var arrayIteratorPrototype = arrayIteratorExists && Object.getPrototypeOf([][Symbol.iterator]());
+var stringIteratorExists = symbolIteratorExists && typeof Array.prototype[Symbol.iterator] === 'function';
+var stringIteratorPrototype = stringIteratorExists && Object.getPrototypeOf(''[Symbol.iterator]());
+var toStringLeftSliceLength = 8;
+var toStringRightSliceLength = -1;
+/**
+ * ### typeOf (obj)
+ *
+ * Uses `Object.prototype.toString` to determine the type of an object,
+ * normalising behaviour across engine versions & well optimised.
+ *
+ * @param {Mixed} object
+ * @return {String} object type
+ * @api public
+ */
+module.exports = function typeDetect(obj) {
+ /* ! Speed optimisation
+ * Pre:
+ * string literal x 3,039,035 ops/sec ±1.62% (78 runs sampled)
+ * boolean literal x 1,424,138 ops/sec ±4.54% (75 runs sampled)
+ * number literal x 1,653,153 ops/sec ±1.91% (82 runs sampled)
+ * undefined x 9,978,660 ops/sec ±1.92% (75 runs sampled)
+ * function x 2,556,769 ops/sec ±1.73% (77 runs sampled)
+ * Post:
+ * string literal x 38,564,796 ops/sec ±1.15% (79 runs sampled)
+ * boolean literal x 31,148,940 ops/sec ±1.10% (79 runs sampled)
+ * number literal x 32,679,330 ops/sec ±1.90% (78 runs sampled)
+ * undefined x 32,363,368 ops/sec ±1.07% (82 runs sampled)
+ * function x 31,296,870 ops/sec ±0.96% (83 runs sampled)
+ */
+ var typeofObj = typeof obj;
+ if (typeofObj !== 'object') {
+ return typeofObj;
+ }
+
+ /* ! Speed optimisation
+ * Pre:
+ * null x 28,645,765 ops/sec ±1.17% (82 runs sampled)
+ * Post:
+ * null x 36,428,962 ops/sec ±1.37% (84 runs sampled)
+ */
+ if (obj === null) {
+ return 'null';
+ }
+
+ /* ! Spec Conformance
+ * Test: `Object.prototype.toString.call(window)``
+ * - Node === "[object global]"
+ * - Chrome === "[object global]"
+ * - Firefox === "[object Window]"
+ * - PhantomJS === "[object Window]"
+ * - Safari === "[object Window]"
+ * - IE 11 === "[object Window]"
+ * - IE Edge === "[object Window]"
+ * Test: `Object.prototype.toString.call(this)``
+ * - Chrome Worker === "[object global]"
+ * - Firefox Worker === "[object DedicatedWorkerGlobalScope]"
+ * - Safari Worker === "[object DedicatedWorkerGlobalScope]"
+ * - IE 11 Worker === "[object WorkerGlobalScope]"
+ * - IE Edge Worker === "[object WorkerGlobalScope]"
+ */
+ if (obj === globalObject) {
+ return 'global';
+ }
+
+ /* ! Speed optimisation
+ * Pre:
+ * array literal x 2,888,352 ops/sec ±0.67% (82 runs sampled)
+ * Post:
+ * array literal x 22,479,650 ops/sec ±0.96% (81 runs sampled)
+ */
+ if (Array.isArray(obj)) {
+ return 'Array';
+ }
+
+ if (isDom) {
+ /* ! Spec Conformance
+ * (https://html.spec.whatwg.org/multipage/browsers.html#location)
+ * WhatWG HTML$7.7.3 - The `Location` interface
+ * Test: `Object.prototype.toString.call(window.location)``
+ * - IE <=11 === "[object Object]"
+ * - IE Edge <=13 === "[object Object]"
+ */
+ if (obj === globalObject.location) {
+ return 'Location';
+ }
+
+ /* ! Spec Conformance
+ * (https://html.spec.whatwg.org/#document)
+ * WhatWG HTML$3.1.1 - The `Document` object
+ * Note: Most browsers currently adher to the W3C DOM Level 2 spec
+ * (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-26809268)
+ * which suggests that browsers should use HTMLTableCellElement for
+ * both TD and TH elements. WhatWG separates these.
+ * WhatWG HTML states:
+ * > For historical reasons, Window objects must also have a
+ * > writable, configurable, non-enumerable property named
+ * > HTMLDocument whose value is the Document interface object.
+ * Test: `Object.prototype.toString.call(document)``
+ * - Chrome === "[object HTMLDocument]"
+ * - Firefox === "[object HTMLDocument]"
+ * - Safari === "[object HTMLDocument]"
+ * - IE <=10 === "[object Document]"
+ * - IE 11 === "[object HTMLDocument]"
+ * - IE Edge <=13 === "[object HTMLDocument]"
+ */
+ if (obj === globalObject.document) {
+ return 'Document';
+ }
+
+ /* ! Spec Conformance
+ * (https://html.spec.whatwg.org/multipage/webappapis.html#mimetypearray)
+ * WhatWG HTML$8.6.1.5 - Plugins - Interface MimeTypeArray
+ * Test: `Object.prototype.toString.call(navigator.mimeTypes)``
+ * - IE <=10 === "[object MSMimeTypesCollection]"
+ */
+ if (obj === (globalObject.navigator || {}).mimeTypes) {
+ return 'MimeTypeArray';
+ }
+
+ /* ! Spec Conformance
+ * (https://html.spec.whatwg.org/multipage/webappapis.html#pluginarray)
+ * WhatWG HTML$8.6.1.5 - Plugins - Interface PluginArray
+ * Test: `Object.prototype.toString.call(navigator.plugins)``
+ * - IE <=10 === "[object MSPluginsCollection]"
+ */
+ if (obj === (globalObject.navigator || {}).plugins) {
+ return 'PluginArray';
+ }
+
+ /* ! Spec Conformance
+ * (https://html.spec.whatwg.org/multipage/webappapis.html#pluginarray)
+ * WhatWG HTML$4.4.4 - The `blockquote` element - Interface `HTMLQuoteElement`
+ * Test: `Object.prototype.toString.call(document.createElement('blockquote'))``
+ * - IE <=10 === "[object HTMLBlockElement]"
+ */
+ if (obj instanceof HTMLElement && obj.tagName === 'BLOCKQUOTE') {
+ return 'HTMLQuoteElement';
+ }
+
+ /* ! Spec Conformance
+ * (https://html.spec.whatwg.org/#htmltabledatacellelement)
+ * WhatWG HTML$4.9.9 - The `td` element - Interface `HTMLTableDataCellElement`
+ * Note: Most browsers currently adher to the W3C DOM Level 2 spec
+ * (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-82915075)
+ * which suggests that browsers should use HTMLTableCellElement for
+ * both TD and TH elements. WhatWG separates these.
+ * Test: Object.prototype.toString.call(document.createElement('td'))
+ * - Chrome === "[object HTMLTableCellElement]"
+ * - Firefox === "[object HTMLTableCellElement]"
+ * - Safari === "[object HTMLTableCellElement]"
+ */
+ if (obj instanceof HTMLElement && obj.tagName === 'TD') {
+ return 'HTMLTableDataCellElement';
+ }
+
+ /* ! Spec Conformance
+ * (https://html.spec.whatwg.org/#htmltableheadercellelement)
+ * WhatWG HTML$4.9.9 - The `td` element - Interface `HTMLTableHeaderCellElement`
+ * Note: Most browsers currently adher to the W3C DOM Level 2 spec
+ * (https://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-82915075)
+ * which suggests that browsers should use HTMLTableCellElement for
+ * both TD and TH elements. WhatWG separates these.
+ * Test: Object.prototype.toString.call(document.createElement('th'))
+ * - Chrome === "[object HTMLTableCellElement]"
+ * - Firefox === "[object HTMLTableCellElement]"
+ * - Safari === "[object HTMLTableCellElement]"
+ */
+ if (obj instanceof HTMLElement && obj.tagName === 'TH') {
+ return 'HTMLTableHeaderCellElement';
+ }
+ }
+
+ /* ! Speed optimisation
+ * Pre:
+ * Float64Array x 625,644 ops/sec ±1.58% (80 runs sampled)
+ * Float32Array x 1,279,852 ops/sec ±2.91% (77 runs sampled)
+ * Uint32Array x 1,178,185 ops/sec ±1.95% (83 runs sampled)
+ * Uint16Array x 1,008,380 ops/sec ±2.25% (80 runs sampled)
+ * Uint8Array x 1,128,040 ops/sec ±2.11% (81 runs sampled)
+ * Int32Array x 1,170,119 ops/sec ±2.88% (80 runs sampled)
+ * Int16Array x 1,176,348 ops/sec ±5.79% (86 runs sampled)
+ * Int8Array x 1,058,707 ops/sec ±4.94% (77 runs sampled)
+ * Uint8ClampedArray x 1,110,633 ops/sec ±4.20% (80 runs sampled)
+ * Post:
+ * Float64Array x 7,105,671 ops/sec ±13.47% (64 runs sampled)
+ * Float32Array x 5,887,912 ops/sec ±1.46% (82 runs sampled)
+ * Uint32Array x 6,491,661 ops/sec ±1.76% (79 runs sampled)
+ * Uint16Array x 6,559,795 ops/sec ±1.67% (82 runs sampled)
+ * Uint8Array x 6,463,966 ops/sec ±1.43% (85 runs sampled)
+ * Int32Array x 5,641,841 ops/sec ±3.49% (81 runs sampled)
+ * Int16Array x 6,583,511 ops/sec ±1.98% (80 runs sampled)
+ * Int8Array x 6,606,078 ops/sec ±1.74% (81 runs sampled)
+ * Uint8ClampedArray x 6,602,224 ops/sec ±1.77% (83 runs sampled)
+ */
+ var stringTag = (symbolToStringTagExists && obj[Symbol.toStringTag]);
+ if (typeof stringTag === 'string') {
+ return stringTag;
+ }
+
+ var objPrototype = Object.getPrototypeOf(obj);
+ /* ! Speed optimisation
+ * Pre:
+ * regex literal x 1,772,385 ops/sec ±1.85% (77 runs sampled)
+ * regex constructor x 2,143,634 ops/sec ±2.46% (78 runs sampled)
+ * Post:
+ * regex literal x 3,928,009 ops/sec ±0.65% (78 runs sampled)
+ * regex constructor x 3,931,108 ops/sec ±0.58% (84 runs sampled)
+ */
+ if (objPrototype === RegExp.prototype) {
+ return 'RegExp';
+ }
+
+ /* ! Speed optimisation
+ * Pre:
+ * date x 2,130,074 ops/sec ±4.42% (68 runs sampled)
+ * Post:
+ * date x 3,953,779 ops/sec ±1.35% (77 runs sampled)
+ */
+ if (objPrototype === Date.prototype) {
+ return 'Date';
+ }
+
+ /* ! Spec Conformance
+ * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-promise.prototype-@@tostringtag)
+ * ES6$25.4.5.4 - Promise.prototype[@@toStringTag] should be "Promise":
+ * Test: `Object.prototype.toString.call(Promise.resolve())``
+ * - Chrome <=47 === "[object Object]"
+ * - Edge <=20 === "[object Object]"
+ * - Firefox 29-Latest === "[object Promise]"
+ * - Safari 7.1-Latest === "[object Promise]"
+ */
+ if (promiseExists && objPrototype === Promise.prototype) {
+ return 'Promise';
+ }
+
+ /* ! Speed optimisation
+ * Pre:
+ * set x 2,222,186 ops/sec ±1.31% (82 runs sampled)
+ * Post:
+ * set x 4,545,879 ops/sec ±1.13% (83 runs sampled)
+ */
+ if (setExists && objPrototype === Set.prototype) {
+ return 'Set';
+ }
+
+ /* ! Speed optimisation
+ * Pre:
+ * map x 2,396,842 ops/sec ±1.59% (81 runs sampled)
+ * Post:
+ * map x 4,183,945 ops/sec ±6.59% (82 runs sampled)
+ */
+ if (mapExists && objPrototype === Map.prototype) {
+ return 'Map';
+ }
+
+ /* ! Speed optimisation
+ * Pre:
+ * weakset x 1,323,220 ops/sec ±2.17% (76 runs sampled)
+ * Post:
+ * weakset x 4,237,510 ops/sec ±2.01% (77 runs sampled)
+ */
+ if (weakSetExists && objPrototype === WeakSet.prototype) {
+ return 'WeakSet';
+ }
+
+ /* ! Speed optimisation
+ * Pre:
+ * weakmap x 1,500,260 ops/sec ±2.02% (78 runs sampled)
+ * Post:
+ * weakmap x 3,881,384 ops/sec ±1.45% (82 runs sampled)
+ */
+ if (weakMapExists && objPrototype === WeakMap.prototype) {
+ return 'WeakMap';
+ }
+
+ /* ! Spec Conformance
+ * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-dataview.prototype-@@tostringtag)
+ * ES6$24.2.4.21 - DataView.prototype[@@toStringTag] should be "DataView":
+ * Test: `Object.prototype.toString.call(new DataView(new ArrayBuffer(1)))``
+ * - Edge <=13 === "[object Object]"
+ */
+ if (dataViewExists && objPrototype === DataView.prototype) {
+ return 'DataView';
+ }
+
+ /* ! Spec Conformance
+ * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%mapiteratorprototype%-@@tostringtag)
+ * ES6$23.1.5.2.2 - %MapIteratorPrototype%[@@toStringTag] should be "Map Iterator":
+ * Test: `Object.prototype.toString.call(new Map().entries())``
+ * - Edge <=13 === "[object Object]"
+ */
+ if (mapExists && objPrototype === mapIteratorPrototype) {
+ return 'Map Iterator';
+ }
+
+ /* ! Spec Conformance
+ * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%setiteratorprototype%-@@tostringtag)
+ * ES6$23.2.5.2.2 - %SetIteratorPrototype%[@@toStringTag] should be "Set Iterator":
+ * Test: `Object.prototype.toString.call(new Set().entries())``
+ * - Edge <=13 === "[object Object]"
+ */
+ if (setExists && objPrototype === setIteratorPrototype) {
+ return 'Set Iterator';
+ }
+
+ /* ! Spec Conformance
+ * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%arrayiteratorprototype%-@@tostringtag)
+ * ES6$22.1.5.2.2 - %ArrayIteratorPrototype%[@@toStringTag] should be "Array Iterator":
+ * Test: `Object.prototype.toString.call([][Symbol.iterator]())``
+ * - Edge <=13 === "[object Object]"
+ */
+ if (arrayIteratorExists && objPrototype === arrayIteratorPrototype) {
+ return 'Array Iterator';
+ }
+
+ /* ! Spec Conformance
+ * (http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%stringiteratorprototype%-@@tostringtag)
+ * ES6$21.1.5.2.2 - %StringIteratorPrototype%[@@toStringTag] should be "String Iterator":
+ * Test: `Object.prototype.toString.call(''[Symbol.iterator]())``
+ * - Edge <=13 === "[object Object]"
+ */
+ if (stringIteratorExists && objPrototype === stringIteratorPrototype) {
+ return 'String Iterator';
+ }
+
+ /* ! Speed optimisation
+ * Pre:
+ * object from null x 2,424,320 ops/sec ±1.67% (76 runs sampled)
+ * Post:
+ * object from null x 5,838,000 ops/sec ±0.99% (84 runs sampled)
+ */
+ if (objPrototype === null) {
+ return 'Object';
+ }
+
+ return Object
+ .prototype
+ .toString
+ .call(obj)
+ .slice(toStringLeftSliceLength, toStringRightSliceLength);
+};
+
+module.exports.typeDetect = module.exports;
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+
+},{}]},{},[1])(1)
+});
+//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJsaWIvc2lub24uanMiLCJsaWIvc2lub24vYXNzZXJ0LmpzIiwibGliL3Npbm9uL2JlaGF2aW9yLmpzIiwibGliL3Npbm9uL2Jsb2IuanMiLCJsaWIvc2lub24vY2FsbC5qcyIsImxpYi9zaW5vbi9jb2xsZWN0LW93bi1tZXRob2RzLmpzIiwibGliL3Npbm9uL2NvbGxlY3Rpb24uanMiLCJsaWIvc2lub24vY29sb3IuanMiLCJsaWIvc2lub24vZGVmYXVsdC1iZWhhdmlvcnMuanMiLCJsaWIvc2lub24vbWF0Y2guanMiLCJsaWIvc2lub24vbW9jay1leHBlY3RhdGlvbi5qcyIsImxpYi9zaW5vbi9tb2NrLmpzIiwibGliL3Npbm9uL3NhbmRib3guanMiLCJsaWIvc2lub24vc3B5LWZvcm1hdHRlcnMuanMiLCJsaWIvc2lub24vc3B5LmpzIiwibGliL3Npbm9uL3N0dWItZGVzY3JpcHRvci5qcyIsImxpYi9zaW5vbi9zdHViLWVudGlyZS1vYmplY3QuanMiLCJsaWIvc2lub24vc3R1Yi1ub24tZnVuY3Rpb24tcHJvcGVydHkuanMiLCJsaWIvc2lub24vc3R1Yi5qcyIsImxpYi9zaW5vbi90aHJvdy1vbi1mYWxzeS1vYmplY3QuanMiLCJsaWIvc2lub24vdXRpbC9jb3JlL2NhbGxlZC1pbi1vcmRlci5qcyIsImxpYi9zaW5vbi91dGlsL2NvcmUvZGVlcC1lcXVhbC5qcyIsImxpYi9zaW5vbi91dGlsL2NvcmUvZGVmYXVsdC1jb25maWcuanMiLCJsaWIvc2lub24vdXRpbC9jb3JlL2RlcHJlY2F0ZWQuanMiLCJsaWIvc2lub24vdXRpbC9jb3JlL2V2ZXJ5LmpzIiwibGliL3Npbm9uL3V0aWwvY29yZS9leHRlbmQuanMiLCJsaWIvc2lub24vdXRpbC9jb3JlL2Zvcm1hdC5qcyIsImxpYi9zaW5vbi91dGlsL2NvcmUvZnVuY3Rpb24tbmFtZS5qcyIsImxpYi9zaW5vbi91dGlsL2NvcmUvZnVuY3Rpb24tdG8tc3RyaW5nLmpzIiwibGliL3Npbm9uL3V0aWwvY29yZS9nZXQtY29uZmlnLmpzIiwibGliL3Npbm9uL3V0aWwvY29yZS9nZXQtcHJvcGVydHktZGVzY3JpcHRvci5qcyIsImxpYi9zaW5vbi91dGlsL2NvcmUvaW5kZXguanMiLCJsaWIvc2lub24vdXRpbC9jb3JlL2l0ZXJhYmxlLXRvLXN0cmluZy5qcyIsImxpYi9zaW5vbi91dGlsL2NvcmUvbG9nX2Vycm9yLmpzIiwibGliL3Npbm9uL3V0aWwvY29yZS9vcmRlci1ieS1maXJzdC1jYWxsLmpzIiwibGliL3Npbm9uL3V0aWwvY29yZS9yZXN0b3JlLmpzIiwibGliL3Npbm9uL3V0aWwvY29yZS90aW1lcy1pbi13b3Jkcy5qcyIsImxpYi9zaW5vbi91dGlsL2NvcmUvdHlwZU9mLmpzIiwibGliL3Npbm9uL3V0aWwvY29yZS92YWx1ZS10by1zdHJpbmcuanMiLCJsaWIvc2lub24vdXRpbC9jb3JlL3dhbGsuanMiLCJsaWIvc2lub24vdXRpbC9jb3JlL3dyYXAtbWV0aG9kLmpzIiwibGliL3Npbm9uL3V0aWwvZXZlbnQuanMiLCJsaWIvc2lub24vdXRpbC9mYWtlX3NlcnZlci5qcyIsImxpYi9zaW5vbi91dGlsL2Zha2Vfc2VydmVyX3dpdGhfY2xvY2suanMiLCJsaWIvc2lub24vdXRpbC9mYWtlX3RpbWVycy5qcyIsImxpYi9zaW5vbi91dGlsL2Zha2VfeG1sX2h0dHBfcmVxdWVzdC5qcyIsIm5vZGVfbW9kdWxlcy9kaWZmL3NyYy9jb252ZXJ0L2RtcC5qcyIsIm5vZGVfbW9kdWxlcy9kaWZmL3NyYy9jb252ZXJ0L3htbC5qcyIsIm5vZGVfbW9kdWxlcy9kaWZmL3NyYy9kaWZmL2FycmF5LmpzIiwibm9kZV9tb2R1bGVzL2RpZmYvc3JjL2RpZmYvYmFzZS5qcyIsIm5vZGVfbW9kdWxlcy9kaWZmL3NyYy9kaWZmL2NoYXJhY3Rlci5qcyIsIm5vZGVfbW9kdWxlcy9kaWZmL3NyYy9kaWZmL2Nzcy5qcyIsIm5vZGVfbW9kdWxlcy9kaWZmL3NyYy9kaWZmL2pzb24uanMiLCJub2RlX21vZHVsZXMvZGlmZi9zcmMvZGlmZi9saW5lLmpzIiwibm9kZV9tb2R1bGVzL2RpZmYvc3JjL2RpZmYvc2VudGVuY2UuanMiLCJub2RlX21vZHVsZXMvZGlmZi9zcmMvZGlmZi93b3JkLmpzIiwibm9kZV9tb2R1bGVzL2RpZmYvc3JjL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2RpZmYvc3JjL3BhdGNoL2FwcGx5LmpzIiwibm9kZV9tb2R1bGVzL2RpZmYvc3JjL3BhdGNoL2NyZWF0ZS5qcyIsIm5vZGVfbW9kdWxlcy9kaWZmL3NyYy9wYXRjaC9wYXJzZS5qcyIsIm5vZGVfbW9kdWxlcy9kaWZmL3NyYy91dGlsL2Rpc3RhbmNlLWl0ZXJhdG9yLmpzIiwibm9kZV9tb2R1bGVzL2RpZmYvc3JjL3V0aWwvcGFyYW1zLmpzIiwibm9kZV9tb2R1bGVzL2Zvcm1hdGlvL2xpYi9mb3JtYXRpby5qcyIsIm5vZGVfbW9kdWxlcy9pc2FycmF5L2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2xvbGV4L3NyYy9sb2xleC1zcmMuanMiLCJub2RlX21vZHVsZXMvcGF0aC10by1yZWdleHAvaW5kZXguanMiLCJub2RlX21vZHVsZXMvcHJvY2Vzcy9icm93c2VyLmpzIiwibm9kZV9tb2R1bGVzL3NhbXNhbS9saWIvc2Ftc2FtLmpzIiwibm9kZV9tb2R1bGVzL3RleHQtZW5jb2RpbmcvaW5kZXguanMiLCJub2RlX21vZHVsZXMvdGV4dC1lbmNvZGluZy9saWIvZW5jb2RpbmctaW5kZXhlcy5qcyIsIm5vZGVfbW9kdWxlcy90ZXh0LWVuY29kaW5nL2xpYi9lbmNvZGluZy5qcyIsIm5vZGVfbW9kdWxlcy90eXBlLWRldGVjdC9pbmRleC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FDdkVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUMzTUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUN6TUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNWQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1TUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FDdkhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUNuQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsVEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaFNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hhQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbktBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNYQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNmQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9DQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNQQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDN0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdkpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzUUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ2xDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7OztnQ0Nwb0JnQixtQixHQUFBLG1COztBQUFULFNBQVMsbUJBQVQsQ0FBNkIsT0FBN0IsRUFBc0M7QUFDM0MsTUFBSSxNQUFNLEVBQVY7QUFBQSxNQUNJLFMseUJBQUEsTSx3QkFESjtBQUFBLE1BRUksWSx5QkFBQSxNLHdCQUZKO0FBR0EsT0FBSyxJQUFJLElBQUksQ0FBYixFQUFnQixJQUFJLFFBQVEsTUFBNUIsRUFBb0MsR0FBcEMsRUFBeUM7QUFDdkMsYUFBUyxRQUFRLENBQVIsQ0FBVDtBQUNBLFFBQUksT0FBTyxLQUFYLEVBQWtCO0FBQ2hCLGtCQUFZLENBQVo7QUFDRCxLQUZELE1BRU8sSUFBSSxPQUFPLE9BQVgsRUFBb0I7QUFDekIsa0JBQVksQ0FBQyxDQUFiO0FBQ0QsS0FGTSxNQUVBO0FBQ0wsa0JBQVksQ0FBWjtBQUNEOztBQUVELFFBQUksSUFBSixDQUFTLENBQUMsU0FBRCxFQUFZLE9BQU8sS0FBbkIsQ0FBVDtBQUNEO0FBQ0QsU0FBTyxHQUFQO0FBQ0Q7Ozs7Ozs7Z0NDbEJlLG1CLEdBQUEsbUI7QUFBVCxTQUFTLG1CQUFULENBQTZCLE9BQTdCLEVBQXNDO0FBQzNDLE1BQUksTUFBTSxFQUFWO0FBQ0EsT0FBSyxJQUFJLElBQUksQ0FBYixFQUFnQixJQUFJLFFBQVEsTUFBNUIsRUFBb0MsR0FBcEMsRUFBeUM7QUFDdkMsUUFBSSxTQUFTLFFBQVEsQ0FBUixDQUFiO0FBQ0EsUUFBSSxPQUFPLEtBQVgsRUFBa0I7QUFDaEIsVUFBSSxJQUFKLENBQVMsT0FBVDtBQUNELEtBRkQsTUFFTyxJQUFJLE9BQU8sT0FBWCxFQUFvQjtBQUN6QixVQUFJLElBQUosQ0FBUyxPQUFUO0FBQ0Q7O0FBRUQsUUFBSSxJQUFKLENBQVMsV0FBVyxPQUFPLEtBQWxCLENBQVQ7O0FBRUEsUUFBSSxPQUFPLEtBQVgsRUFBa0I7QUFDaEIsVUFBSSxJQUFKLENBQVMsUUFBVDtBQUNELEtBRkQsTUFFTyxJQUFJLE9BQU8sT0FBWCxFQUFvQjtBQUN6QixVQUFJLElBQUosQ0FBUyxRQUFUO0FBQ0Q7QUFDRjtBQUNELFNBQU8sSUFBSSxJQUFKLENBQVMsRUFBVCxDQUFQO0FBQ0Q7O0FBRUQsU0FBUyxVQUFULENBQW9CLENBQXBCLEVBQXVCO0FBQ3JCLE1BQUksSUFBSSxDQUFSO0FBQ0EsTUFBSSxFQUFFLE9BQUYsQ0FBVSxJQUFWLEVBQWdCLE9BQWhCLENBQUo7QUFDQSxNQUFJLEVBQUUsT0FBRixDQUFVLElBQVYsRUFBZ0IsTUFBaEIsQ0FBSjtBQUNBLE1BQUksRUFBRSxPQUFGLENBQVUsSUFBVixFQUFnQixNQUFoQixDQUFKO0FBQ0EsTUFBSSxFQUFFLE9BQUYsQ0FBVSxJQUFWLEVBQWdCLFFBQWhCLENBQUo7O0FBRUEsU0FBTyxDQUFQO0FBQ0Q7Ozs7Ozs7O2dDQ3RCZSxVLEdBQUEsVTs7QUFQaEIsSSx5QkFBQSx5Qix3QkFBQTs7Ozs7Ozt1QkFFTyxJQUFNLFkseUJBQUEsUSx3QkFBQSxZQUFZLEkseUJBQUEsbUIsd0JBQWxCO0FBQ1AsVUFBVSxRQUFWLEdBQXFCLFVBQVUsSUFBVixHQUFpQixVQUFTLEtBQVQsRUFBZ0I7QUFDcEQsU0FBTyxNQUFNLEtBQU4sRUFBUDtBQUNELENBRkQ7O0FBSU8sU0FBUyxVQUFULENBQW9CLE1BQXBCLEVBQTRCLE1BQTVCLEVBQW9DLFFBQXBDLEVBQThDO0FBQUUsU0FBTyxVQUFVLElBQVYsQ0FBZSxNQUFmLEVBQXVCLE1BQXZCLEVBQStCLFFBQS9CLENBQVA7QUFBa0Q7Ozs7Ozs7NENDUGpGLEk7QUFBVCxTQUFTLElBQVQsR0FBZ0IsQ0FBRTs7QUFFakMsS0FBSyxTQUFMLEdBQWlCLEU7eUJBQ2YsSUFEZSxnQkFDVixTQURVLEVBQ0MsU0FERCxFQUMwQjs2QkFBQSxJLHVCQUFkLE9BQWMseURBQUosRUFBSTs7QUFDdkMsUUFBSSxXQUFXLFFBQVEsUUFBdkI7QUFDQSxRQUFJLE9BQU8sT0FBUCxLQUFtQixVQUF2QixFQUFtQztBQUNqQyxpQkFBVyxPQUFYO0FBQ0EsZ0JBQVUsRUFBVjtBQUNEO0FBQ0QsU0FBSyxPQUFMLEdBQWUsT0FBZjs7QUFFQSxRQUFJLE9BQU8sSUFBWDs7QUFFQSxhQUFTLElBQVQsQ0FBYyxLQUFkLEVBQXFCO0FBQ25CLFVBQUksUUFBSixFQUFjO0FBQ1osbUJBQVcsWUFBVztBQUFFLG1CQUFTLFNBQVQsRUFBb0IsS0FBcEI7QUFBNkIsU0FBckQsRUFBdUQsQ0FBdkQ7QUFDQSxlQUFPLElBQVA7QUFDRCxPQUhELE1BR087QUFDTCxlQUFPLEtBQVA7QUFDRDtBQUNGOzs7QUFHRCxnQkFBWSxLQUFLLFNBQUwsQ0FBZSxTQUFmLENBQVo7QUFDQSxnQkFBWSxLQUFLLFNBQUwsQ0FBZSxTQUFmLENBQVo7O0FBRUEsZ0JBQVksS0FBSyxXQUFMLENBQWlCLEtBQUssUUFBTCxDQUFjLFNBQWQsQ0FBakIsQ0FBWjtBQUNBLGdCQUFZLEtBQUssV0FBTCxDQUFpQixLQUFLLFFBQUwsQ0FBYyxTQUFkLENBQWpCLENBQVo7O0FBRUEsUUFBSSxTQUFTLFVBQVUsTUFBdkI7QUFBQSxRQUErQixTQUFTLFVBQVUsTUFBbEQ7QUFDQSxRQUFJLGFBQWEsQ0FBakI7QUFDQSxRQUFJLGdCQUFnQixTQUFTLE1BQTdCO0FBQ0EsUUFBSSxXQUFXLENBQUMsRUFBRSxRQUFRLENBQUMsQ0FBWCxFQUFjLFlBQVksRUFBMUIsRUFBRCxDQUFmOzs7QUFHQSxRQUFJLFNBQVMsS0FBSyxhQUFMLENBQW1CLFNBQVMsQ0FBVCxDQUFuQixFQUFnQyxTQUFoQyxFQUEyQyxTQUEzQyxFQUFzRCxDQUF0RCxDQUFiO0FBQ0EsUUFBSSxTQUFTLENBQVQsRUFBWSxNQUFaLEdBQXFCLENBQXJCLElBQTBCLE1BQTFCLElBQW9DLFNBQVMsQ0FBVCxJQUFjLE1BQXRELEVBQThEOztBQUU1RCxhQUFPLEtBQUssQ0FBQyxFQUFDLE9BQU8sS0FBSyxJQUFMLENBQVUsU0FBVixDQUFSLEVBQThCLE9BQU8sVUFBVSxNQUEvQyxFQUFELENBQUwsQ0FBUDtBQUNEOzs7QUFHRCxhQUFTLGNBQVQsR0FBMEI7QUFDeEIsV0FBSyxJQUFJLGVBQWUsQ0FBQyxDQUFELEdBQUssVUFBN0IsRUFBeUMsZ0JBQWdCLFVBQXpELEVBQXFFLGdCQUFnQixDQUFyRixFQUF3RjtBQUN0RixZQUFJLFcseUJBQUEsTSx3QkFBSjtBQUNBLFlBQUksVUFBVSxTQUFTLGVBQWUsQ0FBeEIsQ0FBZDtBQUFBLFlBQ0ksYUFBYSxTQUFTLGVBQWUsQ0FBeEIsQ0FEakI7QUFBQSxZQUVJLFVBQVMsQ0FBQyxhQUFhLFdBQVcsTUFBeEIsR0FBaUMsQ0FBbEMsSUFBdUMsWUFGcEQ7QUFHQSxZQUFJLE9BQUosRUFBYTs7QUFFWCxtQkFBUyxlQUFlLENBQXhCLElBQTZCLFNBQTdCO0FBQ0Q7O0FBRUQsWUFBSSxTQUFTLFdBQVcsUUFBUSxNQUFSLEdBQWlCLENBQWpCLEdBQXFCLE1BQTdDO0FBQUEsWUFDSSxZQUFZLGNBQWMsS0FBSyxPQUFuQixJQUE2QixVQUFTLE1BRHREO0FBRUEsWUFBSSxDQUFDLE1BQUQsSUFBVyxDQUFDLFNBQWhCLEVBQTJCOztBQUV6QixtQkFBUyxZQUFULElBQXlCLFNBQXpCO0FBQ0E7QUFDRDs7Ozs7QUFLRCxZQUFJLENBQUMsTUFBRCxJQUFZLGFBQWEsUUFBUSxNQUFSLEdBQWlCLFdBQVcsTUFBekQsRUFBa0U7QUFDaEUscUJBQVcsVUFBVSxVQUFWLENBQVg7QUFDQSxlQUFLLGFBQUwsQ0FBbUIsU0FBUyxVQUE1QixFQUF3QyxTQUF4QyxFQUFtRCxJQUFuRDtBQUNELFNBSEQsTUFHTztBQUNMLHFCQUFXLE9BQVgsQztBQUNBLG1CQUFTLE1BQVQ7QUFDQSxlQUFLLGFBQUwsQ0FBbUIsU0FBUyxVQUE1QixFQUF3QyxJQUF4QyxFQUE4QyxTQUE5QztBQUNEOztBQUVELGtCQUFTLEtBQUssYUFBTCxDQUFtQixRQUFuQixFQUE2QixTQUE3QixFQUF3QyxTQUF4QyxFQUFtRCxZQUFuRCxDQUFUOzs7QUFHQSxZQUFJLFNBQVMsTUFBVCxHQUFrQixDQUFsQixJQUF1QixNQUF2QixJQUFpQyxVQUFTLENBQVQsSUFBYyxNQUFuRCxFQUEyRDtBQUN6RCxpQkFBTyxLQUFLLFlBQVksSUFBWixFQUFrQixTQUFTLFVBQTNCLEVBQXVDLFNBQXZDLEVBQWtELFNBQWxELEVBQTZELEtBQUssZUFBbEUsQ0FBTCxDQUFQO0FBQ0QsU0FGRCxNQUVPOztBQUVMLG1CQUFTLFlBQVQsSUFBeUIsUUFBekI7QUFDRDtBQUNGOztBQUVEO0FBQ0Q7Ozs7O0FBS0QsUUFBSSxRQUFKLEVBQWM7QUFDWCxnQkFBUyxJQUFULEdBQWdCO0FBQ2YsbUJBQVcsWUFBVzs7O0FBR3BCLGNBQUksYUFBYSxhQUFqQixFQUFnQztBQUM5QixtQkFBTyxVQUFQO0FBQ0Q7O0FBRUQsY0FBSSxDQUFDLGdCQUFMLEVBQXVCO0FBQ3JCO0FBQ0Q7QUFDRixTQVZELEVBVUcsQ0FWSDtBQVdELE9BWkEsR0FBRDtBQWFELEtBZEQsTUFjTztBQUNMLGFBQU8sY0FBYyxhQUFyQixFQUFvQztBQUNsQyxZQUFJLE1BQU0sZ0JBQVY7QUFDQSxZQUFJLEdBQUosRUFBUztBQUNQLGlCQUFPLEdBQVA7QUFDRDtBQUNGO0FBQ0Y7QUFDRixHQTlHYzttREFnSGYsYUFoSGUseUJBZ0hELFVBaEhDLEVBZ0hXLEtBaEhYLEVBZ0hrQixPQWhIbEIsRUFnSDJCO0FBQ3hDLFFBQUksT0FBTyxXQUFXLFdBQVcsTUFBWCxHQUFvQixDQUEvQixDQUFYO0FBQ0EsUUFBSSxRQUFRLEtBQUssS0FBTCxLQUFlLEtBQXZCLElBQWdDLEtBQUssT0FBTCxLQUFpQixPQUFyRCxFQUE4RDs7O0FBRzVELGlCQUFXLFdBQVcsTUFBWCxHQUFvQixDQUEvQixJQUFvQyxFQUFDLE9BQU8sS0FBSyxLQUFMLEdBQWEsQ0FBckIsRUFBd0IsT0FBTyxLQUEvQixFQUFzQyxTQUFTLE9BQS9DLEVBQXBDO0FBQ0QsS0FKRCxNQUlPO0FBQ0wsaUJBQVcsSUFBWCxDQUFnQixFQUFDLE9BQU8sQ0FBUixFQUFXLE9BQU8sS0FBbEIsRUFBeUIsU0FBUyxPQUFsQyxFQUFoQjtBQUNEO0FBQ0YsR0F6SGM7bURBMEhmLGFBMUhlLHlCQTBIRCxRQTFIQyxFQTBIUyxTQTFIVCxFQTBIb0IsU0ExSHBCLEVBMEgrQixZQTFIL0IsRUEwSDZDO0FBQzFELFFBQUksU0FBUyxVQUFVLE1BQXZCO0FBQUEsUUFDSSxTQUFTLFVBQVUsTUFEdkI7QUFBQSxRQUVJLFNBQVMsU0FBUyxNQUZ0QjtBQUFBLFFBR0ksU0FBUyxTQUFTLFlBSHRCO0FBQUEsUUFLSSxjQUFjLENBTGxCO0FBTUEsV0FBTyxTQUFTLENBQVQsR0FBYSxNQUFiLElBQXVCLFNBQVMsQ0FBVCxHQUFhLE1BQXBDLElBQThDLEtBQUssTUFBTCxDQUFZLFVBQVUsU0FBUyxDQUFuQixDQUFaLEVBQW1DLFVBQVUsU0FBUyxDQUFuQixDQUFuQyxDQUFyRCxFQUFnSDtBQUM5RztBQUNBO0FBQ0E7QUFDRDs7QUFFRCxRQUFJLFdBQUosRUFBaUI7QUFDZixlQUFTLFVBQVQsQ0FBb0IsSUFBcEIsQ0FBeUIsRUFBQyxPQUFPLFdBQVIsRUFBekI7QUFDRDs7QUFFRCxhQUFTLE1BQVQsR0FBa0IsTUFBbEI7QUFDQSxXQUFPLE1BQVA7QUFDRCxHQTdJYzttREErSWYsTUEvSWUsa0JBK0lSLElBL0lRLEVBK0lGLEtBL0lFLEVBK0lLO0FBQ2xCLFdBQU8sU0FBUyxLQUFoQjtBQUNELEdBakpjO21EQWtKZixXQWxKZSx1QkFrSkgsS0FsSkcsRUFrSkk7QUFDakIsUUFBSSxNQUFNLEVBQVY7QUFDQSxTQUFLLElBQUksSUFBSSxDQUFiLEVBQWdCLElBQUksTUFBTSxNQUExQixFQUFrQyxHQUFsQyxFQUF1QztBQUNyQyxVQUFJLE1BQU0sQ0FBTixDQUFKLEVBQWM7QUFDWixZQUFJLElBQUosQ0FBUyxNQUFNLENBQU4sQ0FBVDtBQUNEO0FBQ0Y7QUFDRCxXQUFPLEdBQVA7QUFDRCxHQTFKYzttREEySmYsU0EzSmUscUJBMkpMLEtBM0pLLEVBMkpFO0FBQ2YsV0FBTyxLQUFQO0FBQ0QsR0E3SmM7bURBOEpmLFFBOUplLG9CQThKTixLQTlKTSxFQThKQztBQUNkLFdBQU8sTUFBTSxLQUFOLENBQVksRUFBWixDQUFQO0FBQ0QsR0FoS2M7bURBaUtmLElBaktlLGdCQWlLVixLQWpLVSxFQWlLSDtBQUNWLFdBQU8sTUFBTSxJQUFOLENBQVcsRUFBWCxDQUFQO0FBQ0Q7QUFuS2MsQ0FBakI7O0FBc0tBLFNBQVMsV0FBVCxDQUFxQixJQUFyQixFQUEyQixVQUEzQixFQUF1QyxTQUF2QyxFQUFrRCxTQUFsRCxFQUE2RCxlQUE3RCxFQUE4RTtBQUM1RSxNQUFJLGVBQWUsQ0FBbkI7QUFBQSxNQUNJLGVBQWUsV0FBVyxNQUQ5QjtBQUFBLE1BRUksU0FBUyxDQUZiO0FBQUEsTUFHSSxTQUFTLENBSGI7O0FBS0EsU0FBTyxlQUFlLFlBQXRCLEVBQW9DLGNBQXBDLEVBQW9EO0FBQ2xELFFBQUksWUFBWSxXQUFXLFlBQVgsQ0FBaEI7QUFDQSxRQUFJLENBQUMsVUFBVSxPQUFmLEVBQXdCO0FBQ3RCLFVBQUksQ0FBQyxVQUFVLEtBQVgsSUFBb0IsZUFBeEIsRUFBeUM7QUFDdkMsWUFBSSxRQUFRLFVBQVUsS0FBVixDQUFnQixNQUFoQixFQUF3QixTQUFTLFVBQVUsS0FBM0MsQ0FBWjtBQUNBLGdCQUFRLE1BQU0sR0FBTixDQUFVLFVBQVMsS0FBVCxFQUFnQixDQUFoQixFQUFtQjtBQUNuQyxjQUFJLFdBQVcsVUFBVSxTQUFTLENBQW5CLENBQWY7QUFDQSxpQkFBTyxTQUFTLE1BQVQsR0FBa0IsTUFBTSxNQUF4QixHQUFpQyxRQUFqQyxHQUE0QyxLQUFuRDtBQUNELFNBSE8sQ0FBUjs7QUFLQSxrQkFBVSxLQUFWLEdBQWtCLEtBQUssSUFBTCxDQUFVLEtBQVYsQ0FBbEI7QUFDRCxPQVJELE1BUU87QUFDTCxrQkFBVSxLQUFWLEdBQWtCLEtBQUssSUFBTCxDQUFVLFVBQVUsS0FBVixDQUFnQixNQUFoQixFQUF3QixTQUFTLFVBQVUsS0FBM0MsQ0FBVixDQUFsQjtBQUNEO0FBQ0QsZ0JBQVUsVUFBVSxLQUFwQjs7O0FBR0EsVUFBSSxDQUFDLFVBQVUsS0FBZixFQUFzQjtBQUNwQixrQkFBVSxVQUFVLEtBQXBCO0FBQ0Q7QUFDRixLQWxCRCxNQWtCTztBQUNMLGdCQUFVLEtBQVYsR0FBa0IsS0FBSyxJQUFMLENBQVUsVUFBVSxLQUFWLENBQWdCLE1BQWhCLEVBQXdCLFNBQVMsVUFBVSxLQUEzQyxDQUFWLENBQWxCO0FBQ0EsZ0JBQVUsVUFBVSxLQUFwQjs7Ozs7QUFLQSxVQUFJLGdCQUFnQixXQUFXLGVBQWUsQ0FBMUIsRUFBNkIsS0FBakQsRUFBd0Q7QUFDdEQsWUFBSSxNQUFNLFdBQVcsZUFBZSxDQUExQixDQUFWO0FBQ0EsbUJBQVcsZUFBZSxDQUExQixJQUErQixXQUFXLFlBQVgsQ0FBL0I7QUFDQSxtQkFBVyxZQUFYLElBQTJCLEdBQTNCO0FBQ0Q7QUFDRjtBQUNGOzs7O0FBSUQsTUFBSSxnQkFBZ0IsV0FBVyxlQUFlLENBQTFCLENBQXBCO0FBQ0EsTUFBSSxlQUFlLENBQWYsS0FDSSxjQUFjLEtBQWQsSUFBdUIsY0FBYyxPQUR6QyxLQUVHLEtBQUssTUFBTCxDQUFZLEVBQVosRUFBZ0IsY0FBYyxLQUE5QixDQUZQLEVBRTZDO0FBQzNDLGVBQVcsZUFBZSxDQUExQixFQUE2QixLQUE3QixJQUFzQyxjQUFjLEtBQXBEO0FBQ0EsZUFBVyxHQUFYO0FBQ0Q7O0FBRUQsU0FBTyxVQUFQO0FBQ0Q7O0FBRUQsU0FBUyxTQUFULENBQW1CLElBQW5CLEVBQXlCO0FBQ3ZCLFNBQU8sRUFBRSxRQUFRLEtBQUssTUFBZixFQUF1QixZQUFZLEtBQUssVUFBTCxDQUFnQixLQUFoQixDQUFzQixDQUF0QixDQUFuQyxFQUFQO0FBQ0Q7Ozs7Ozs7O2dDQzdOZSxTLEdBQUEsUzs7QUFIaEIsSSx5QkFBQSx5Qix3QkFBQTs7Ozs7Ozt1QkFFTyxJQUFNLGdCLHlCQUFBLFEsd0JBQUEsZ0JBQWdCLEkseUJBQUEsbUIsd0JBQXRCO0FBQ0EsU0FBUyxTQUFULENBQW1CLE1BQW5CLEVBQTJCLE1BQTNCLEVBQW1DLFFBQW5DLEVBQTZDO0FBQUUsU0FBTyxjQUFjLElBQWQsQ0FBbUIsTUFBbkIsRUFBMkIsTUFBM0IsRUFBbUMsUUFBbkMsQ0FBUDtBQUFzRDs7Ozs7Ozs7Z0NDSTVGLE8sR0FBQSxPOztBQVBoQixJLHlCQUFBLHlCLHdCQUFBOzs7Ozs7O3VCQUVPLElBQU0sVSx5QkFBQSxRLHdCQUFBLFVBQVUsSSx5QkFBQSxtQix3QkFBaEI7QUFDUCxRQUFRLFFBQVIsR0FBbUIsVUFBUyxLQUFULEVBQWdCO0FBQ2pDLFNBQU8sTUFBTSxLQUFOLENBQVksZUFBWixDQUFQO0FBQ0QsQ0FGRDs7QUFJTyxTQUFTLE9BQVQsQ0FBaUIsTUFBakIsRUFBeUIsTUFBekIsRUFBaUMsUUFBakMsRUFBMkM7QUFBRSxTQUFPLFFBQVEsSUFBUixDQUFhLE1BQWIsRUFBcUIsTUFBckIsRUFBNkIsUUFBN0IsQ0FBUDtBQUFnRDs7Ozs7Ozs7Ozs7Z0NDb0JwRixRLEdBQUEsUTt5REFJQSxZLEdBQUEsWTs7QUEvQmhCLEkseUJBQUEseUIsd0JBQUE7Ozs7OztBQUNBLEkseUJBQUEseUIsd0JBQUE7Ozs7Ozs7QUFFQSxJQUFNLDBCQUEwQixPQUFPLFNBQVAsQ0FBaUIsUUFBakQ7O0FBR08sSUFBTSxXLHlCQUFBLFEsd0JBQUEsV0FBVyxJLHlCQUFBLG1CLHdCQUFqQjs7O0FBR1AsU0FBUyxlQUFULEdBQTJCLElBQTNCOztBQUVBLFNBQVMsUUFBVCxHLHlCQUFvQixlLHdCQUFTLFFBQTdCO0FBQ0EsU0FBUyxTQUFULEdBQXFCLFVBQVMsS0FBVCxFQUFnQjsyQkFBQSxJLHVCQUM1QixvQkFENEIsR0FDSixLQUFLLE9BREQsQ0FDNUIsb0JBRDRCOzs7QUFHbkMsU0FBTyxPQUFPLEtBQVAsS0FBaUIsUUFBakIsR0FBNEIsS0FBNUIsR0FBb0MsS0FBSyxTQUFMLENBQWUsYUFBYSxLQUFiLENBQWYsRUFBb0MsVUFBUyxDQUFULEVBQVksQ0FBWixFQUFlO0FBQzVGLFFBQUksT0FBTyxDQUFQLEtBQWEsV0FBakIsRUFBOEI7QUFDNUIsYUFBTyxvQkFBUDtBQUNEOztBQUVELFdBQU8sQ0FBUDtBQUNELEdBTjBDLEVBTXhDLElBTndDLENBQTNDO0FBT0QsQ0FWRDtBQVdBLFNBQVMsTUFBVCxHQUFrQixVQUFTLElBQVQsRUFBZSxLQUFmLEVBQXNCO0FBQ3RDLFMsMEJBQU8sa0Isd0JBQUssU0FBTCxDQUFlLE1BQWYsQ0FBc0IsS0FBSyxPQUFMLENBQWEsWUFBYixFQUEyQixJQUEzQixDQUF0QixFQUF3RCxNQUFNLE9BQU4sQ0FBYyxZQUFkLEVBQTRCLElBQTVCLENBQXhEO0FBQVA7QUFDRCxDQUZEOztBQUlPLFNBQVMsUUFBVCxDQUFrQixNQUFsQixFQUEwQixNQUExQixFQUFrQyxPQUFsQyxFQUEyQztBQUFFLFNBQU8sU0FBUyxJQUFULENBQWMsTUFBZCxFQUFzQixNQUF0QixFQUE4QixPQUE5QixDQUFQO0FBQWdEOzs7O0FBSTdGLFNBQVMsWUFBVCxDQUFzQixHQUF0QixFQUEyQixLQUEzQixFQUFrQyxnQkFBbEMsRUFBb0Q7QUFDekQsVUFBUSxTQUFTLEVBQWpCO0FBQ0EscUJBQW1CLG9CQUFvQixFQUF2Qzs7QUFFQSxNQUFJLEkseUJBQUEsTSx3QkFBSjs7QUFFQSxPQUFLLElBQUksQ0FBVCxFQUFZLElBQUksTUFBTSxNQUF0QixFQUE4QixLQUFLLENBQW5DLEVBQXNDO0FBQ3BDLFFBQUksTUFBTSxDQUFOLE1BQWEsR0FBakIsRUFBc0I7QUFDcEIsYUFBTyxpQkFBaUIsQ0FBakIsQ0FBUDtBQUNEO0FBQ0Y7O0FBRUQsTUFBSSxtQix5QkFBQSxNLHdCQUFKOztBQUVBLE1BQUkscUJBQXFCLHdCQUF3QixJQUF4QixDQUE2QixHQUE3QixDQUF6QixFQUE0RDtBQUMxRCxVQUFNLElBQU4sQ0FBVyxHQUFYO0FBQ0EsdUJBQW1CLElBQUksS0FBSixDQUFVLElBQUksTUFBZCxDQUFuQjtBQUNBLHFCQUFpQixJQUFqQixDQUFzQixnQkFBdEI7QUFDQSxTQUFLLElBQUksQ0FBVCxFQUFZLElBQUksSUFBSSxNQUFwQixFQUE0QixLQUFLLENBQWpDLEVBQW9DO0FBQ2xDLHVCQUFpQixDQUFqQixJQUFzQixhQUFhLElBQUksQ0FBSixDQUFiLEVBQXFCLEtBQXJCLEVBQTRCLGdCQUE1QixDQUF0QjtBQUNEO0FBQ0QsVUFBTSxHQUFOO0FBQ0EscUJBQWlCLEdBQWpCO0FBQ0EsV0FBTyxnQkFBUDtBQUNEOztBQUVELE1BQUksT0FBTyxJQUFJLE1BQWYsRUFBdUI7QUFDckIsVUFBTSxJQUFJLE1BQUosRUFBTjtBQUNEOztBQUVELE0sMEJBQUksUSx1QkFBTyxHQUFQLHlDQUFPLEdBQVAsT0FBZSxRQUFmLElBQTJCLFFBQVEsSUFBdkMsRUFBNkM7QUFDM0MsVUFBTSxJQUFOLENBQVcsR0FBWDtBQUNBLHVCQUFtQixFQUFuQjtBQUNBLHFCQUFpQixJQUFqQixDQUFzQixnQkFBdEI7QUFDQSxRQUFJLGFBQWEsRUFBakI7QUFBQSxRQUNJLE0seUJBQUEsTSx3QkFESjtBQUVBLFNBQUssR0FBTCxJQUFZLEdBQVosRUFBaUI7O0FBRWYsVUFBSSxJQUFJLGNBQUosQ0FBbUIsR0FBbkIsQ0FBSixFQUE2QjtBQUMzQixtQkFBVyxJQUFYLENBQWdCLEdBQWhCO0FBQ0Q7QUFDRjtBQUNELGVBQVcsSUFBWDtBQUNBLFNBQUssSUFBSSxDQUFULEVBQVksSUFBSSxXQUFXLE1BQTNCLEVBQW1DLEtBQUssQ0FBeEMsRUFBMkM7QUFDekMsWUFBTSxXQUFXLENBQVgsQ0FBTjtBQUNBLHVCQUFpQixHQUFqQixJQUF3QixhQUFhLElBQUksR0FBSixDQUFiLEVBQXVCLEtBQXZCLEVBQThCLGdCQUE5QixDQUF4QjtBQUNEO0FBQ0QsVUFBTSxHQUFOO0FBQ0EscUJBQWlCLEdBQWpCO0FBQ0QsR0FuQkQsTUFtQk87QUFDTCx1QkFBbUIsR0FBbkI7QUFDRDtBQUNELFNBQU8sZ0JBQVA7QUFDRDs7Ozs7Ozs7Z0NDdERlLFMsR0FBQSxTO3lEQUNBLGdCLEdBQUEsZ0I7O0FBL0JoQixJLHlCQUFBLHlCLHdCQUFBOzs7Ozs7QUFDQSxJLHlCQUFBLG1DLHdCQUFBOzs7Ozt1QkFFTyxJQUFNLFcseUJBQUEsUSx3QkFBQSxXQUFXLEkseUJBQUEsbUIsd0JBQWpCO0FBQ1AsU0FBUyxRQUFULEdBQW9CLFVBQVMsS0FBVCxFQUFnQjtBQUNsQyxNQUFJLFdBQVcsRUFBZjtBQUFBLE1BQ0ksbUJBQW1CLE1BQU0sS0FBTixDQUFZLFdBQVosQ0FEdkI7OztBQUlBLE1BQUksQ0FBQyxpQkFBaUIsaUJBQWlCLE1BQWpCLEdBQTBCLENBQTNDLENBQUwsRUFBb0Q7QUFDbEQscUJBQWlCLEdBQWpCO0FBQ0Q7OztBQUdELE9BQUssSUFBSSxJQUFJLENBQWIsRUFBZ0IsSUFBSSxpQkFBaUIsTUFBckMsRUFBNkMsR0FBN0MsRUFBa0Q7QUFDaEQsUUFBSSxPQUFPLGlCQUFpQixDQUFqQixDQUFYOztBQUVBLFFBQUksSUFBSSxDQUFKLElBQVMsQ0FBQyxLQUFLLE9BQUwsQ0FBYSxjQUEzQixFQUEyQztBQUN6QyxlQUFTLFNBQVMsTUFBVCxHQUFrQixDQUEzQixLQUFpQyxJQUFqQztBQUNELEtBRkQsTUFFTztBQUNMLFVBQUksS0FBSyxPQUFMLENBQWEsZ0JBQWpCLEVBQW1DO0FBQ2pDLGVBQU8sS0FBSyxJQUFMLEVBQVA7QUFDRDtBQUNELGVBQVMsSUFBVCxDQUFjLElBQWQ7QUFDRDtBQUNGOztBQUVELFNBQU8sUUFBUDtBQUNELENBeEJEOztBQTBCTyxTQUFTLFNBQVQsQ0FBbUIsTUFBbkIsRUFBMkIsTUFBM0IsRUFBbUMsUUFBbkMsRUFBNkM7QUFBRSxTQUFPLFNBQVMsSUFBVCxDQUFjLE1BQWQsRUFBc0IsTUFBdEIsRUFBOEIsUUFBOUIsQ0FBUDtBQUFpRDtBQUNoRyxTQUFTLGdCQUFULENBQTBCLE1BQTFCLEVBQWtDLE1BQWxDLEVBQTBDLFFBQTFDLEVBQW9EO0FBQ3pELE1BQUksVSx5QkFBVSw0Qix3QkFBQSxDQUFnQixRQUFoQixFQUEwQixFQUFDLGtCQUFrQixJQUFuQixFQUExQixDQUFkO0FBQ0EsU0FBTyxTQUFTLElBQVQsQ0FBYyxNQUFkLEVBQXNCLE1BQXRCLEVBQThCLE9BQTlCLENBQVA7QUFDRDs7Ozs7Ozs7Z0NDMUJlLGEsR0FBQSxhOztBQVJoQixJLHlCQUFBLHlCLHdCQUFBOzs7Ozs7O3VCQUdPLElBQU0sZSx5QkFBQSxRLHdCQUFBLGVBQWUsSSx5QkFBQSxtQix3QkFBckI7QUFDUCxhQUFhLFFBQWIsR0FBd0IsVUFBUyxLQUFULEVBQWdCO0FBQ3RDLFNBQU8sTUFBTSxLQUFOLENBQVksdUJBQVosQ0FBUDtBQUNELENBRkQ7O0FBSU8sU0FBUyxhQUFULENBQXVCLE1BQXZCLEVBQStCLE1BQS9CLEVBQXVDLFFBQXZDLEVBQWlEO0FBQUUsU0FBTyxhQUFhLElBQWIsQ0FBa0IsTUFBbEIsRUFBMEIsTUFBMUIsRUFBa0MsUUFBbEMsQ0FBUDtBQUFxRDs7Ozs7Ozs7Z0NDdUMvRixTLEdBQUEsUzt5REFJQSxrQixHQUFBLGtCOztBQW5EaEIsSSx5QkFBQSx5Qix3QkFBQTs7Ozs7O0FBQ0EsSSx5QkFBQSxtQyx3QkFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQW9CQSxJQUFNLG9CQUFvQiwrREFBMUI7O0FBRUEsSUFBTSxlQUFlLElBQXJCOztBQUVPLElBQU0sVyx5QkFBQSxRLHdCQUFBLFdBQVcsSSx5QkFBQSxtQix3QkFBakI7QUFDUCxTQUFTLE1BQVQsR0FBa0IsVUFBUyxJQUFULEVBQWUsS0FBZixFQUFzQjtBQUN0QyxTQUFPLFNBQVMsS0FBVCxJQUFtQixLQUFLLE9BQUwsQ0FBYSxnQkFBYixJQUFpQyxDQUFDLGFBQWEsSUFBYixDQUFrQixJQUFsQixDQUFsQyxJQUE2RCxDQUFDLGFBQWEsSUFBYixDQUFrQixLQUFsQixDQUF4RjtBQUNELENBRkQ7QUFHQSxTQUFTLFFBQVQsR0FBb0IsVUFBUyxLQUFULEVBQWdCO0FBQ2xDLE1BQUksU0FBUyxNQUFNLEtBQU4sQ0FBWSxVQUFaLENBQWI7OztBQUdBLE9BQUssSUFBSSxJQUFJLENBQWIsRUFBZ0IsSUFBSSxPQUFPLE1BQVAsR0FBZ0IsQ0FBcEMsRUFBdUMsR0FBdkMsRUFBNEM7O0FBRTFDLFFBQUksQ0FBQyxPQUFPLElBQUksQ0FBWCxDQUFELElBQWtCLE9BQU8sSUFBSSxDQUFYLENBQWxCLElBQ0ssa0JBQWtCLElBQWxCLENBQXVCLE9BQU8sQ0FBUCxDQUF2QixDQURMLElBRUssa0JBQWtCLElBQWxCLENBQXVCLE9BQU8sSUFBSSxDQUFYLENBQXZCLENBRlQsRUFFZ0Q7QUFDOUMsYUFBTyxDQUFQLEtBQWEsT0FBTyxJQUFJLENBQVgsQ0FBYjtBQUNBLGFBQU8sTUFBUCxDQUFjLElBQUksQ0FBbEIsRUFBcUIsQ0FBckI7QUFDQTtBQUNEO0FBQ0Y7O0FBRUQsU0FBTyxNQUFQO0FBQ0QsQ0FoQkQ7O0FBa0JPLFNBQVMsU0FBVCxDQUFtQixNQUFuQixFQUEyQixNQUEzQixFQUFtQyxRQUFuQyxFQUE2QztBQUNsRCxNQUFJLFUseUJBQVUsNEIsd0JBQUEsQ0FBZ0IsUUFBaEIsRUFBMEIsRUFBQyxrQkFBa0IsSUFBbkIsRUFBMUIsQ0FBZDtBQUNBLFNBQU8sU0FBUyxJQUFULENBQWMsTUFBZCxFQUFzQixNQUF0QixFQUE4QixPQUE5QixDQUFQO0FBQ0Q7QUFDTSxTQUFTLGtCQUFULENBQTRCLE1BQTVCLEVBQW9DLE1BQXBDLEVBQTRDLFFBQTVDLEVBQXNEO0FBQzNELFNBQU8sU0FBUyxJQUFULENBQWMsTUFBZCxFQUFzQixNQUF0QixFQUE4QixRQUE5QixDQUFQO0FBQ0Q7Ozs7Ozs7OztBQ3JDRCxJLHlCQUFBLDhCLHdCQUFBOzs7Ozs7QUFDQSxJLHlCQUFBLHdDLHdCQUFBOztBQUNBLEkseUJBQUEsOEIsd0JBQUE7O0FBQ0EsSSx5QkFBQSw4Qix3QkFBQTs7QUFDQSxJLHlCQUFBLHNDLHdCQUFBOztBQUVBLEkseUJBQUEsNEIsd0JBQUE7O0FBQ0EsSSx5QkFBQSw4Qix3QkFBQTs7QUFFQSxJLHlCQUFBLGdDLHdCQUFBOztBQUVBLEkseUJBQUEsaUMsd0JBQUE7O0FBQ0EsSSx5QkFBQSxpQyx3QkFBQTs7QUFDQSxJLHlCQUFBLG1DLHdCQUFBOztBQUVBLEkseUJBQUEsK0Isd0JBQUE7O0FBQ0EsSSx5QkFBQSwrQix3QkFBQTs7Ozs7Z0NBR0UsSTt5REFFQSxTO3lEQUNBLFM7eURBQ0Esa0I7eURBQ0EsUzt5REFDQSxnQjt5REFDQSxhO3lEQUVBLE87eURBQ0EsUTt5REFFQSxVO3lEQUVBLGU7eURBQ0EsbUI7eURBQ0EsVzt5REFDQSxVO3lEQUNBLFk7eURBQ0EsVTt5REFDQSxtQjt5REFDQSxtQjt5REFDQSxZOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O2dDQ3REYyxVLEdBQUEsVTt5REErSEEsWSxHQUFBLFk7O0FBbEloQixJLHlCQUFBLDJCLHdCQUFBOztBQUNBLEkseUJBQUEsd0Qsd0JBQUE7Ozs7Ozs7dUJBRU8sU0FBUyxVQUFULENBQW9CLE1BQXBCLEVBQTRCLE9BQTVCLEVBQW1EOzJCQUFBLEksdUJBQWQsT0FBYyx5REFBSixFQUFJOztBQUN4RCxNQUFJLE9BQU8sT0FBUCxLQUFtQixRQUF2QixFQUFpQztBQUMvQixjLHlCQUFVLHNCLHdCQUFBLENBQVcsT0FBWCxDQUFWO0FBQ0Q7O0FBRUQsTUFBSSxNQUFNLE9BQU4sQ0FBYyxPQUFkLENBQUosRUFBNEI7QUFDMUIsUUFBSSxRQUFRLE1BQVIsR0FBaUIsQ0FBckIsRUFBd0I7QUFDdEIsWUFBTSxJQUFJLEtBQUosQ0FBVSw0Q0FBVixDQUFOO0FBQ0Q7O0FBRUQsY0FBVSxRQUFRLENBQVIsQ0FBVjtBQUNEOzs7QUFHRCxNQUFJLFFBQVEsT0FBTyxLQUFQLENBQWEscUJBQWIsQ0FBWjtBQUFBLE1BQ0ksYUFBYSxPQUFPLEtBQVAsQ0FBYSxzQkFBYixLQUF3QyxFQUR6RDtBQUFBLE1BRUksUUFBUSxRQUFRLEtBRnBCO0FBQUEsTUFJSSxjQUFjLFFBQVEsV0FBUixJQUF3QixVQUFDLFVBQUQsRUFBYSxJQUFiLEVBQW1CLFNBQW5CLEVBQThCLFlBQTlCLEUseUJBQUE7QUFBQSxXLHdCQUErQyxTQUFTO0FBQXhEO0FBQUEsR0FKMUM7QUFBQSxNQUtJLGFBQWEsQ0FMakI7QUFBQSxNQU1JLGFBQWEsUUFBUSxVQUFSLElBQXNCLENBTnZDO0FBQUEsTUFPSSxVQUFVLENBUGQ7QUFBQSxNQVFJLFNBQVMsQ0FSYjtBQUFBLE1BVUksYyx5QkFBQSxNLHdCQVZKO0FBQUEsTUFXSSxXLHlCQUFBLE0sd0JBWEo7Ozs7O0FBZ0JBLFdBQVMsUUFBVCxDQUFrQixJQUFsQixFQUF3QixLQUF4QixFQUErQjtBQUM3QixTQUFLLElBQUksSUFBSSxDQUFiLEVBQWdCLElBQUksS0FBSyxLQUFMLENBQVcsTUFBL0IsRUFBdUMsR0FBdkMsRUFBNEM7QUFDMUMsVUFBSSxPQUFPLEtBQUssS0FBTCxDQUFXLENBQVgsQ0FBWDtBQUFBLFVBQ0ksWUFBWSxLQUFLLENBQUwsQ0FEaEI7QUFBQSxVQUVJLFVBQVUsS0FBSyxNQUFMLENBQVksQ0FBWixDQUZkOztBQUlBLFVBQUksY0FBYyxHQUFkLElBQXFCLGNBQWMsR0FBdkMsRUFBNEM7O0FBRTFDLFlBQUksQ0FBQyxZQUFZLFFBQVEsQ0FBcEIsRUFBdUIsTUFBTSxLQUFOLENBQXZCLEVBQXFDLFNBQXJDLEVBQWdELE9BQWhELENBQUwsRUFBK0Q7QUFDN0Q7O0FBRUEsY0FBSSxhQUFhLFVBQWpCLEVBQTZCO0FBQzNCLG1CQUFPLEtBQVA7QUFDRDtBQUNGO0FBQ0Q7QUFDRDtBQUNGOztBQUVELFdBQU8sSUFBUDtBQUNEOzs7QUFHRCxPQUFLLElBQUksSUFBSSxDQUFiLEVBQWdCLElBQUksTUFBTSxNQUExQixFQUFrQyxHQUFsQyxFQUF1QztBQUNyQyxRQUFJLE9BQU8sTUFBTSxDQUFOLENBQVg7QUFBQSxRQUNJLFVBQVUsTUFBTSxNQUFOLEdBQWUsS0FBSyxRQURsQztBQUFBLFFBRUksY0FBYyxDQUZsQjtBQUFBLFFBR0ksUUFBUSxTQUFTLEtBQUssUUFBZCxHQUF5QixDQUhyQzs7QUFLQSxRQUFJLFcseUJBQVcsa0Msd0JBQUEsQ0FBaUIsS0FBakIsRUFBd0IsT0FBeEIsRUFBaUMsT0FBakMsQ0FBZjs7QUFFQSxXQUFPLGdCQUFnQixTQUF2QixFQUFrQyxjQUFjLFVBQWhELEVBQTREO0FBQzFELFVBQUksU0FBUyxJQUFULEVBQWUsUUFBUSxXQUF2QixDQUFKLEVBQXlDO0FBQ3ZDLGFBQUssTUFBTCxHQUFjLFVBQVUsV0FBeEI7QUFDQTtBQUNEO0FBQ0Y7O0FBRUQsUUFBSSxnQkFBZ0IsU0FBcEIsRUFBK0I7QUFDN0IsYUFBTyxLQUFQO0FBQ0Q7Ozs7QUFJRCxjQUFVLEtBQUssTUFBTCxHQUFjLEtBQUssUUFBbkIsR0FBOEIsS0FBSyxRQUE3QztBQUNEOzs7QUFHRCxPQUFLLElBQUksS0FBSSxDQUFiLEVBQWdCLEtBQUksTUFBTSxNQUExQixFQUFrQyxJQUFsQyxFQUF1QztBQUNyQyxRQUFJLFFBQU8sTUFBTSxFQUFOLENBQVg7QUFBQSxRQUNJLFNBQVEsTUFBSyxNQUFMLEdBQWMsTUFBSyxRQUFuQixHQUE4QixDQUQxQztBQUVBLFFBQUksTUFBSyxRQUFMLElBQWlCLENBQXJCLEVBQXdCO0FBQUU7QUFBVTs7QUFFcEMsU0FBSyxJQUFJLElBQUksQ0FBYixFQUFnQixJQUFJLE1BQUssS0FBTCxDQUFXLE1BQS9CLEVBQXVDLEdBQXZDLEVBQTRDO0FBQzFDLFVBQUksT0FBTyxNQUFLLEtBQUwsQ0FBVyxDQUFYLENBQVg7QUFBQSxVQUNJLFlBQVksS0FBSyxDQUFMLENBRGhCO0FBQUEsVUFFSSxVQUFVLEtBQUssTUFBTCxDQUFZLENBQVosQ0FGZDtBQUFBLFVBR0ksWUFBWSxNQUFLLGNBQUwsQ0FBb0IsQ0FBcEIsQ0FIaEI7O0FBS0EsVUFBSSxjQUFjLEdBQWxCLEVBQXVCO0FBQ3JCO0FBQ0QsT0FGRCxNQUVPLElBQUksY0FBYyxHQUFsQixFQUF1QjtBQUM1QixjQUFNLE1BQU4sQ0FBYSxNQUFiLEVBQW9CLENBQXBCO0FBQ0EsbUJBQVcsTUFBWCxDQUFrQixNQUFsQixFQUF5QixDQUF6Qjs7QUFFRCxPQUpNLE1BSUEsSUFBSSxjQUFjLEdBQWxCLEVBQXVCO0FBQzVCLGdCQUFNLE1BQU4sQ0FBYSxNQUFiLEVBQW9CLENBQXBCLEVBQXVCLE9BQXZCO0FBQ0EscUJBQVcsTUFBWCxDQUFrQixNQUFsQixFQUF5QixDQUF6QixFQUE0QixTQUE1QjtBQUNBO0FBQ0QsU0FKTSxNQUlBLElBQUksY0FBYyxJQUFsQixFQUF3QjtBQUM3QixjQUFJLG9CQUFvQixNQUFLLEtBQUwsQ0FBVyxJQUFJLENBQWYsSUFBb0IsTUFBSyxLQUFMLENBQVcsSUFBSSxDQUFmLEVBQWtCLENBQWxCLENBQXBCLEdBQTJDLElBQW5FO0FBQ0EsY0FBSSxzQkFBc0IsR0FBMUIsRUFBK0I7QUFDN0IsMEJBQWMsSUFBZDtBQUNELFdBRkQsTUFFTyxJQUFJLHNCQUFzQixHQUExQixFQUErQjtBQUNwQyx1QkFBVyxJQUFYO0FBQ0Q7QUFDRjtBQUNGO0FBQ0Y7OztBQUdELE1BQUksV0FBSixFQUFpQjtBQUNmLFdBQU8sQ0FBQyxNQUFNLE1BQU0sTUFBTixHQUFlLENBQXJCLENBQVIsRUFBaUM7QUFDL0IsWUFBTSxHQUFOO0FBQ0EsaUJBQVcsR0FBWDtBQUNEO0FBQ0YsR0FMRCxNQUtPLElBQUksUUFBSixFQUFjO0FBQ25CLFVBQU0sSUFBTixDQUFXLEVBQVg7QUFDQSxlQUFXLElBQVgsQ0FBZ0IsSUFBaEI7QUFDRDtBQUNELE9BQUssSUFBSSxLQUFLLENBQWQsRUFBaUIsS0FBSyxNQUFNLE1BQU4sR0FBZSxDQUFyQyxFQUF3QyxJQUF4QyxFQUE4QztBQUM1QyxVQUFNLEVBQU4sSUFBWSxNQUFNLEVBQU4sSUFBWSxXQUFXLEVBQVgsQ0FBeEI7QUFDRDtBQUNELFNBQU8sTUFBTSxJQUFOLENBQVcsRUFBWCxDQUFQO0FBQ0Q7OztBQUdNLFNBQVMsWUFBVCxDQUFzQixPQUF0QixFQUErQixPQUEvQixFQUF3QztBQUM3QyxNQUFJLE9BQU8sT0FBUCxLQUFtQixRQUF2QixFQUFpQztBQUMvQixjLHlCQUFVLHNCLHdCQUFBLENBQVcsT0FBWCxDQUFWO0FBQ0Q7O0FBRUQsTUFBSSxlQUFlLENBQW5CO0FBQ0EsV0FBUyxZQUFULEdBQXdCO0FBQ3RCLFFBQUksUUFBUSxRQUFRLGNBQVIsQ0FBWjtBQUNBLFFBQUksQ0FBQyxLQUFMLEVBQVk7QUFDVixhQUFPLFFBQVEsUUFBUixFQUFQO0FBQ0Q7O0FBRUQsWUFBUSxRQUFSLENBQWlCLEtBQWpCLEVBQXdCLFVBQVMsR0FBVCxFQUFjLElBQWQsRUFBb0I7QUFDMUMsVUFBSSxHQUFKLEVBQVM7QUFDUCxlQUFPLFFBQVEsUUFBUixDQUFpQixHQUFqQixDQUFQO0FBQ0Q7O0FBRUQsVUFBSSxpQkFBaUIsV0FBVyxJQUFYLEVBQWlCLEtBQWpCLEVBQXdCLE9BQXhCLENBQXJCO0FBQ0EsY0FBUSxPQUFSLENBQWdCLEtBQWhCLEVBQXVCLGNBQXZCLEVBQXVDLFVBQVMsR0FBVCxFQUFjO0FBQ25ELFlBQUksR0FBSixFQUFTO0FBQ1AsaUJBQU8sUUFBUSxRQUFSLENBQWlCLEdBQWpCLENBQVA7QUFDRDs7QUFFRDtBQUNELE9BTkQ7QUFPRCxLQWJEO0FBY0Q7QUFDRDtBQUNEOzs7Ozs7O2dDQzVKZSxlLEdBQUEsZTt5REFpR0EsbUIsR0FBQSxtQjt5REF3QkEsVyxHQUFBLFc7O0FBM0hoQixJLHlCQUFBLCtCLHdCQUFBOzs7Ozt1QkFFTyxTQUFTLGVBQVQsQ0FBeUIsV0FBekIsRUFBc0MsV0FBdEMsRUFBbUQsTUFBbkQsRUFBMkQsTUFBM0QsRUFBbUUsU0FBbkUsRUFBOEUsU0FBOUUsRUFBeUYsT0FBekYsRUFBa0c7QUFDdkcsTUFBSSxDQUFDLE9BQUwsRUFBYztBQUNaLGNBQVUsRUFBVjtBQUNEO0FBQ0QsTUFBSSxPQUFPLFFBQVEsT0FBZixLQUEyQixXQUEvQixFQUE0QztBQUMxQyxZQUFRLE9BQVIsR0FBa0IsQ0FBbEI7QUFDRDs7QUFFRCxNQUFNLE8seUJBQU8sb0Isd0JBQUEsQ0FBVSxNQUFWLEVBQWtCLE1BQWxCLEVBQTBCLE9BQTFCLENBQWI7QUFDQSxPQUFLLElBQUwsQ0FBVSxFQUFDLE9BQU8sRUFBUixFQUFZLE9BQU8sRUFBbkIsRUFBVixFOztBQUVBLFdBQVMsWUFBVCxDQUFzQixLQUF0QixFQUE2QjtBQUMzQixXQUFPLE1BQU0sR0FBTixDQUFVLFVBQVMsS0FBVCxFQUFnQjtBQUFFLGFBQU8sTUFBTSxLQUFiO0FBQXFCLEtBQWpELENBQVA7QUFDRDs7QUFFRCxNQUFJLFFBQVEsRUFBWjtBQUNBLE1BQUksZ0JBQWdCLENBQXBCO0FBQUEsTUFBdUIsZ0JBQWdCLENBQXZDO0FBQUEsTUFBMEMsV0FBVyxFQUFyRDtBQUFBLE1BQ0ksVUFBVSxDQURkO0FBQUEsTUFDaUIsVUFBVSxDQUQzQjs7QUFoQnVHLDZCLHdCQWtCOUYsQ0FsQjhGO0FBbUJyRyxRQUFNLFVBQVUsS0FBSyxDQUFMLENBQWhCO0FBQUEsUUFDTSxRQUFRLFFBQVEsS0FBUixJQUFpQixRQUFRLEtBQVIsQ0FBYyxPQUFkLENBQXNCLEtBQXRCLEVBQTZCLEVBQTdCLEVBQWlDLEtBQWpDLENBQXVDLElBQXZDLENBRC9CO0FBRUEsWUFBUSxLQUFSLEdBQWdCLEtBQWhCOztBQUVBLFFBQUksUUFBUSxLQUFSLElBQWlCLFFBQVEsT0FBN0IsRUFBc0M7O0FBQUE7Ozs7QUFFcEMsVUFBSSxDQUFDLGFBQUwsRUFBb0I7QUFDbEIsWUFBTSxPQUFPLEtBQUssSUFBSSxDQUFULENBQWI7QUFDQSx3QkFBZ0IsT0FBaEI7QUFDQSx3QkFBZ0IsT0FBaEI7O0FBRUEsWUFBSSxJQUFKLEVBQVU7QUFDUixxQkFBVyxRQUFRLE9BQVIsR0FBa0IsQ0FBbEIsR0FBc0IsYUFBYSxLQUFLLEtBQUwsQ0FBVyxLQUFYLENBQWlCLENBQUMsUUFBUSxPQUExQixDQUFiLENBQXRCLEdBQXlFLEVBQXBGO0FBQ0EsMkJBQWlCLFNBQVMsTUFBMUI7QUFDQSwyQkFBaUIsU0FBUyxNQUExQjtBQUNEO0FBQ0Y7OzsrQkFHRCxhLHVCQUFBLFVBQVMsSUFBVCxDLDBCQUFBLEssd0JBQUEsQywwQkFBQSxTLHdCQUFBLEUseUJBQUEsbUIsd0JBQWtCLE1BQU0sR0FBTixDQUFVLFVBQVMsS0FBVCxFQUFnQjtBQUMxQyxlQUFPLENBQUMsUUFBUSxLQUFSLEdBQWdCLEdBQWhCLEdBQXNCLEdBQXZCLElBQThCLEtBQXJDO0FBQ0QsT0FGaUIsQ0FBbEI7OztBQUtBLFVBQUksUUFBUSxLQUFaLEVBQW1CO0FBQ2pCLG1CQUFXLE1BQU0sTUFBakI7QUFDRCxPQUZELE1BRU87QUFDTCxtQkFBVyxNQUFNLE1BQWpCO0FBQ0Q7QUFDRixLQXpCRCxNQXlCTzs7QUFFTCxVQUFJLGFBQUosRUFBbUI7O0FBRWpCLFlBQUksTUFBTSxNQUFOLElBQWdCLFFBQVEsT0FBUixHQUFrQixDQUFsQyxJQUF1QyxJQUFJLEtBQUssTUFBTCxHQUFjLENBQTdELEVBQWdFOztBQUFBOzs7O21DQUU5RCxjLHVCQUFBLFVBQVMsSUFBVCxDLDBCQUFBLEssd0JBQUEsQywwQkFBQSxVLHdCQUFBLEUseUJBQUEsbUIsd0JBQWtCLGFBQWEsS0FBYixDQUFsQjtBQUNELFNBSEQsTUFHTzs7QUFBQTs7OztBQUVMLGNBQUksY0FBYyxLQUFLLEdBQUwsQ0FBUyxNQUFNLE1BQWYsRUFBdUIsUUFBUSxPQUEvQixDQUFsQjttQ0FDQSxjLHVCQUFBLFVBQVMsSUFBVCxDLDBCQUFBLEssd0JBQUEsQywwQkFBQSxVLHdCQUFBLEUseUJBQUEsbUIsd0JBQWtCLGFBQWEsTUFBTSxLQUFOLENBQVksQ0FBWixFQUFlLFdBQWYsQ0FBYixDQUFsQjs7QUFFQSxjQUFJLE9BQU87QUFDVCxzQkFBVSxhQUREO0FBRVQsc0JBQVcsVUFBVSxhQUFWLEdBQTBCLFdBRjVCO0FBR1Qsc0JBQVUsYUFIRDtBQUlULHNCQUFXLFVBQVUsYUFBVixHQUEwQixXQUo1QjtBQUtULG1CQUFPO0FBTEUsV0FBWDtBQU9BLGNBQUksS0FBSyxLQUFLLE1BQUwsR0FBYyxDQUFuQixJQUF3QixNQUFNLE1BQU4sSUFBZ0IsUUFBUSxPQUFwRCxFQUE2RDs7QUFFM0QsZ0JBQUksZ0JBQWlCLE1BQU0sSUFBTixDQUFXLE1BQVgsQ0FBckI7QUFDQSxnQkFBSSxnQkFBaUIsTUFBTSxJQUFOLENBQVcsTUFBWCxDQUFyQjtBQUNBLGdCQUFJLE1BQU0sTUFBTixJQUFnQixDQUFoQixJQUFxQixDQUFDLGFBQTFCLEVBQXlDOztBQUV2Qyx1QkFBUyxNQUFULENBQWdCLEtBQUssUUFBckIsRUFBK0IsQ0FBL0IsRUFBa0MsOEJBQWxDO0FBQ0QsYUFIRCxNQUdPLElBQUksQ0FBQyxhQUFELElBQWtCLENBQUMsYUFBdkIsRUFBc0M7QUFDM0MsdUJBQVMsSUFBVCxDQUFjLDhCQUFkO0FBQ0Q7QUFDRjtBQUNELGdCQUFNLElBQU4sQ0FBVyxJQUFYOztBQUVBLDBCQUFnQixDQUFoQjtBQUNBLDBCQUFnQixDQUFoQjtBQUNBLHFCQUFXLEVBQVg7QUFDRDtBQUNGO0FBQ0QsaUJBQVcsTUFBTSxNQUFqQjtBQUNBLGlCQUFXLE1BQU0sTUFBakI7QUFDRDtBQXZGb0c7O0FBa0J2RyxPQUFLLElBQUksSUFBSSxDQUFiLEVBQWdCLElBQUksS0FBSyxNQUF6QixFQUFpQyxHQUFqQyxFQUFzQzs7QUFBQSxVLHdCQUE3QixDQUE2QjtBQXNFckM7O0FBRUQsU0FBTztBQUNMLGlCQUFhLFdBRFIsRUFDcUIsYUFBYSxXQURsQztBQUVMLGVBQVcsU0FGTixFQUVpQixXQUFXLFNBRjVCO0FBR0wsV0FBTztBQUhGLEdBQVA7QUFLRDs7QUFFTSxTQUFTLG1CQUFULENBQTZCLFdBQTdCLEVBQTBDLFdBQTFDLEVBQXVELE1BQXZELEVBQStELE1BQS9ELEVBQXVFLFNBQXZFLEVBQWtGLFNBQWxGLEVBQTZGLE9BQTdGLEVBQXNHO0FBQzNHLE1BQU0sT0FBTyxnQkFBZ0IsV0FBaEIsRUFBNkIsV0FBN0IsRUFBMEMsTUFBMUMsRUFBa0QsTUFBbEQsRUFBMEQsU0FBMUQsRUFBcUUsU0FBckUsRUFBZ0YsT0FBaEYsQ0FBYjs7QUFFQSxNQUFNLE1BQU0sRUFBWjtBQUNBLE1BQUksZUFBZSxXQUFuQixFQUFnQztBQUM5QixRQUFJLElBQUosQ0FBUyxZQUFZLFdBQXJCO0FBQ0Q7QUFDRCxNQUFJLElBQUosQ0FBUyxxRUFBVDtBQUNBLE1BQUksSUFBSixDQUFTLFNBQVMsS0FBSyxXQUFkLElBQTZCLE9BQU8sS0FBSyxTQUFaLEtBQTBCLFdBQTFCLEdBQXdDLEVBQXhDLEdBQTZDLE9BQU8sS0FBSyxTQUF0RixDQUFUO0FBQ0EsTUFBSSxJQUFKLENBQVMsU0FBUyxLQUFLLFdBQWQsSUFBNkIsT0FBTyxLQUFLLFNBQVosS0FBMEIsV0FBMUIsR0FBd0MsRUFBeEMsR0FBNkMsT0FBTyxLQUFLLFNBQXRGLENBQVQ7O0FBRUEsT0FBSyxJQUFJLElBQUksQ0FBYixFQUFnQixJQUFJLEtBQUssS0FBTCxDQUFXLE1BQS9CLEVBQXVDLEdBQXZDLEVBQTRDO0FBQzFDLFFBQU0sT0FBTyxLQUFLLEtBQUwsQ0FBVyxDQUFYLENBQWI7QUFDQSxRQUFJLElBQUosQ0FDRSxTQUFTLEtBQUssUUFBZCxHQUF5QixHQUF6QixHQUErQixLQUFLLFFBQXBDLEdBQ0UsSUFERixHQUNTLEtBQUssUUFEZCxHQUN5QixHQUR6QixHQUMrQixLQUFLLFFBRHBDLEdBRUUsS0FISjtBQUtBLFFBQUksSUFBSixDQUFTLEtBQVQsQ0FBZSxHQUFmLEVBQW9CLEtBQUssS0FBekI7QUFDRDs7QUFFRCxTQUFPLElBQUksSUFBSixDQUFTLElBQVQsSUFBaUIsSUFBeEI7QUFDRDs7QUFFTSxTQUFTLFdBQVQsQ0FBcUIsUUFBckIsRUFBK0IsTUFBL0IsRUFBdUMsTUFBdkMsRUFBK0MsU0FBL0MsRUFBMEQsU0FBMUQsRUFBcUUsT0FBckUsRUFBOEU7QUFDbkYsU0FBTyxvQkFBb0IsUUFBcEIsRUFBOEIsUUFBOUIsRUFBd0MsTUFBeEMsRUFBZ0QsTUFBaEQsRUFBd0QsU0FBeEQsRUFBbUUsU0FBbkUsRUFBOEUsT0FBOUUsQ0FBUDtBQUNEOzs7Ozs7O2dDQzdIZSxVLEdBQUEsVTtBQUFULFNBQVMsVUFBVCxDQUFvQixPQUFwQixFQUEyQzsyQkFBQSxJLHVCQUFkLE9BQWMseURBQUosRUFBSTs7QUFDaEQsTUFBSSxVQUFVLFFBQVEsS0FBUixDQUFjLHFCQUFkLENBQWQ7QUFBQSxNQUNJLGFBQWEsUUFBUSxLQUFSLENBQWMsc0JBQWQsS0FBeUMsRUFEMUQ7QUFBQSxNQUVJLE9BQU8sRUFGWDtBQUFBLE1BR0ksSUFBSSxDQUhSOztBQUtBLFdBQVMsVUFBVCxHQUFzQjtBQUNwQixRQUFJLFFBQVEsRUFBWjtBQUNBLFNBQUssSUFBTCxDQUFVLEtBQVY7OztBQUdBLFdBQU8sSUFBSSxRQUFRLE1BQW5CLEVBQTJCO0FBQ3pCLFVBQUksT0FBTyxRQUFRLENBQVIsQ0FBWDs7O0FBR0EsVUFBSSx3QkFBd0IsSUFBeEIsQ0FBNkIsSUFBN0IsQ0FBSixFQUF3QztBQUN0QztBQUNEOzs7QUFHRCxVQUFJLFNBQVUsMENBQUQsQ0FBNkMsSUFBN0MsQ0FBa0QsSUFBbEQsQ0FBYjtBQUNBLFVBQUksTUFBSixFQUFZO0FBQ1YsY0FBTSxLQUFOLEdBQWMsT0FBTyxDQUFQLENBQWQ7QUFDRDs7QUFFRDtBQUNEOzs7O0FBSUQsb0JBQWdCLEtBQWhCO0FBQ0Esb0JBQWdCLEtBQWhCOzs7QUFHQSxVQUFNLEtBQU4sR0FBYyxFQUFkOztBQUVBLFdBQU8sSUFBSSxRQUFRLE1BQW5CLEVBQTJCO0FBQ3pCLFVBQUksUUFBTyxRQUFRLENBQVIsQ0FBWDs7QUFFQSxVQUFJLGlDQUFpQyxJQUFqQyxDQUFzQyxLQUF0QyxDQUFKLEVBQWlEO0FBQy9DO0FBQ0QsT0FGRCxNQUVPLElBQUksTUFBTSxJQUFOLENBQVcsS0FBWCxDQUFKLEVBQXNCO0FBQzNCLGNBQU0sS0FBTixDQUFZLElBQVosQ0FBaUIsV0FBakI7QUFDRCxPQUZNLE1BRUEsSUFBSSxTQUFRLFFBQVEsTUFBcEIsRUFBNEI7O0FBRWpDLGNBQU0sSUFBSSxLQUFKLENBQVUsbUJBQW1CLElBQUksQ0FBdkIsSUFBNEIsR0FBNUIsR0FBa0MsS0FBSyxTQUFMLENBQWUsS0FBZixDQUE1QyxDQUFOO0FBQ0QsT0FITSxNQUdBO0FBQ0w7QUFDRDtBQUNGO0FBQ0Y7Ozs7QUFJRCxXQUFTLGVBQVQsQ0FBeUIsS0FBekIsRUFBZ0M7QUFDOUIsUUFBTSxnQkFBZ0IsMENBQXRCO0FBQ0EsUUFBTSxhQUFhLGNBQWMsSUFBZCxDQUFtQixRQUFRLENBQVIsQ0FBbkIsQ0FBbkI7QUFDQSxRQUFJLFVBQUosRUFBZ0I7QUFDZCxVQUFJLFlBQVksV0FBVyxDQUFYLE1BQWtCLEtBQWxCLEdBQTBCLEtBQTFCLEdBQWtDLEtBQWxEO0FBQ0EsWUFBTSxZQUFZLFVBQWxCLElBQWdDLFdBQVcsQ0FBWCxDQUFoQztBQUNBLFlBQU0sWUFBWSxRQUFsQixJQUE4QixXQUFXLENBQVgsQ0FBOUI7O0FBRUE7QUFDRDtBQUNGOzs7O0FBSUQsV0FBUyxTQUFULEdBQXFCO0FBQ25CLFFBQUksbUJBQW1CLENBQXZCO0FBQUEsUUFDSSxrQkFBa0IsUUFBUSxHQUFSLENBRHRCO0FBQUEsUUFFSSxjQUFjLGdCQUFnQixLQUFoQixDQUFzQiw0Q0FBdEIsQ0FGbEI7O0FBSUEsUUFBSSxPQUFPO0FBQ1QsZ0JBQVUsQ0FBQyxZQUFZLENBQVosQ0FERjtBQUVULGdCQUFVLENBQUMsWUFBWSxDQUFaLENBQUQsSUFBbUIsQ0FGcEI7QUFHVCxnQkFBVSxDQUFDLFlBQVksQ0FBWixDQUhGO0FBSVQsZ0JBQVUsQ0FBQyxZQUFZLENBQVosQ0FBRCxJQUFtQixDQUpwQjtBQUtULGFBQU8sRUFMRTtBQU1ULHNCQUFnQjtBQU5QLEtBQVg7O0FBU0EsUUFBSSxXQUFXLENBQWY7QUFBQSxRQUNJLGNBQWMsQ0FEbEI7QUFFQSxXQUFPLElBQUksUUFBUSxNQUFuQixFQUEyQixHQUEzQixFQUFnQzs7O0FBRzlCLFVBQUksUUFBUSxDQUFSLEVBQVcsT0FBWCxDQUFtQixNQUFuQixNQUErQixDQUEvQixJQUNNLElBQUksQ0FBSixHQUFRLFFBQVEsTUFEdEIsSUFFSyxRQUFRLElBQUksQ0FBWixFQUFlLE9BQWYsQ0FBdUIsTUFBdkIsTUFBbUMsQ0FGeEMsSUFHSyxRQUFRLElBQUksQ0FBWixFQUFlLE9BQWYsQ0FBdUIsSUFBdkIsTUFBaUMsQ0FIMUMsRUFHNkM7QUFDekM7QUFDSDtBQUNELFVBQUksWUFBWSxRQUFRLENBQVIsRUFBVyxDQUFYLENBQWhCOztBQUVBLFVBQUksY0FBYyxHQUFkLElBQXFCLGNBQWMsR0FBbkMsSUFBMEMsY0FBYyxHQUF4RCxJQUErRCxjQUFjLElBQWpGLEVBQXVGO0FBQ3JGLGFBQUssS0FBTCxDQUFXLElBQVgsQ0FBZ0IsUUFBUSxDQUFSLENBQWhCO0FBQ0EsYUFBSyxjQUFMLENBQW9CLElBQXBCLENBQXlCLFdBQVcsQ0FBWCxLQUFpQixJQUExQzs7QUFFQSxZQUFJLGNBQWMsR0FBbEIsRUFBdUI7QUFDckI7QUFDRCxTQUZELE1BRU8sSUFBSSxjQUFjLEdBQWxCLEVBQXVCO0FBQzVCO0FBQ0QsU0FGTSxNQUVBLElBQUksY0FBYyxHQUFsQixFQUF1QjtBQUM1QjtBQUNBO0FBQ0Q7QUFDRixPQVpELE1BWU87QUFDTDtBQUNEO0FBQ0Y7OztBQUdELFFBQUksQ0FBQyxRQUFELElBQWEsS0FBSyxRQUFMLEtBQWtCLENBQW5DLEVBQXNDO0FBQ3BDLFdBQUssUUFBTCxHQUFnQixDQUFoQjtBQUNEO0FBQ0QsUUFBSSxDQUFDLFdBQUQsSUFBZ0IsS0FBSyxRQUFMLEtBQWtCLENBQXRDLEVBQXlDO0FBQ3ZDLFdBQUssUUFBTCxHQUFnQixDQUFoQjtBQUNEOzs7QUFHRCxRQUFJLFFBQVEsTUFBWixFQUFvQjtBQUNsQixVQUFJLGFBQWEsS0FBSyxRQUF0QixFQUFnQztBQUM5QixjQUFNLElBQUksS0FBSixDQUFVLHNEQUFzRCxtQkFBbUIsQ0FBekUsQ0FBVixDQUFOO0FBQ0Q7QUFDRCxVQUFJLGdCQUFnQixLQUFLLFFBQXpCLEVBQW1DO0FBQ2pDLGNBQU0sSUFBSSxLQUFKLENBQVUsd0RBQXdELG1CQUFtQixDQUEzRSxDQUFWLENBQU47QUFDRDtBQUNGOztBQUVELFdBQU8sSUFBUDtBQUNEOztBQUVELFNBQU8sSUFBSSxRQUFRLE1BQW5CLEVBQTJCO0FBQ3pCO0FBQ0Q7O0FBRUQsU0FBTyxJQUFQO0FBQ0Q7Ozs7Ozs7OzRDQ3ZJYyxVQUFTLEtBQVQsRUFBZ0IsT0FBaEIsRUFBeUIsT0FBekIsRUFBa0M7QUFDL0MsTUFBSSxjQUFjLElBQWxCO0FBQUEsTUFDSSxvQkFBb0IsS0FEeEI7QUFBQSxNQUVJLG1CQUFtQixLQUZ2QjtBQUFBLE1BR0ksY0FBYyxDQUhsQjs7QUFLQSxTQUFPLFNBQVMsUUFBVCxHQUFvQjtBQUN6QixRQUFJLGVBQWUsQ0FBQyxnQkFBcEIsRUFBc0M7QUFDcEMsVUFBSSxpQkFBSixFQUF1QjtBQUNyQjtBQUNELE9BRkQsTUFFTztBQUNMLHNCQUFjLEtBQWQ7QUFDRDs7OztBQUlELFVBQUksUUFBUSxXQUFSLElBQXVCLE9BQTNCLEVBQW9DO0FBQ2xDLGVBQU8sV0FBUDtBQUNEOztBQUVELHlCQUFtQixJQUFuQjtBQUNEOztBQUVELFFBQUksQ0FBQyxpQkFBTCxFQUF3QjtBQUN0QixVQUFJLENBQUMsZ0JBQUwsRUFBdUI7QUFDckIsc0JBQWMsSUFBZDtBQUNEOzs7O0FBSUQsVUFBSSxXQUFXLFFBQVEsV0FBdkIsRUFBb0M7QUFDbEMsZUFBTyxDQUFDLGFBQVI7QUFDRDs7QUFFRCwwQkFBb0IsSUFBcEI7QUFDQSxhQUFPLFVBQVA7QUFDRDs7OztBQUlGLEdBbENEO0FBbUNELEM7Ozs7Ozs7Z0NDNUNlLGUsR0FBQSxlO0FBQVQsU0FBUyxlQUFULENBQXlCLE9BQXpCLEVBQWtDLFFBQWxDLEVBQTRDO0FBQ2pELE1BQUksT0FBTyxPQUFQLEtBQW1CLFVBQXZCLEVBQW1DO0FBQ2pDLGFBQVMsUUFBVCxHQUFvQixPQUFwQjtBQUNELEdBRkQsTUFFTyxJQUFJLE9BQUosRUFBYTtBQUNsQixTQUFLLElBQUksSUFBVCxJQUFpQixPQUFqQixFQUEwQjs7QUFFeEIsVUFBSSxRQUFRLGNBQVIsQ0FBdUIsSUFBdkIsQ0FBSixFQUFrQztBQUNoQyxpQkFBUyxJQUFULElBQWlCLFFBQVEsSUFBUixDQUFqQjtBQUNEO0FBQ0Y7QUFDRjtBQUNELFNBQU8sUUFBUDtBQUNEOzs7OztBQ1pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUNyT0E7QUFDQTtBQUNBO0FBQ0E7OztBQ0hBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQ2hwQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMWFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcmJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUNodkdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIlwidXNlIHN0cmljdFwiO1xuXG52YXIgbWF0Y2ggPSByZXF1aXJlKFwiLi9zaW5vbi9tYXRjaFwiKTtcbnZhciBkZWVwRXF1YWwgPSByZXF1aXJlKFwiLi9zaW5vbi91dGlsL2NvcmUvZGVlcC1lcXVhbFwiKTtcbnZhciBkZXByZWNhdGVkID0gcmVxdWlyZShcIi4vc2lub24vdXRpbC9jb3JlL2RlcHJlY2F0ZWRcIik7XG5cbmZ1bmN0aW9uIGV4cG9zZUNvcmVVdGlscyh0YXJnZXQsIHV0aWxzKSB7XG4gICAgdmFyIGtleXMgPSBPYmplY3Qua2V5cyh1dGlscyk7XG5cbiAgICBrZXlzLmZvckVhY2goZnVuY3Rpb24gKGtleSkge1xuICAgICAgICB2YXIgdmFsdWUgPSB1dGlsc1trZXldO1xuXG4gICAgICAgIC8vIGFsbG93IGRlZXBFcXVhbCB0byBjaGVjayBlcXVhbGl0eSBvZiBtYXRjaGVycyB0aHJvdWdoIGRlcGVuZGVuY3kgaW5qZWN0aW9uLiBPdGhlcndpc2Ugd2UgZ2V0IGEgY2lyY3VsYXJcbiAgICAgICAgLy8gZGVwZW5kZW5jeVxuICAgICAgICBpZiAoa2V5ID09PSBcImRlZXBFcXVhbFwiKSB7XG4gICAgICAgICAgICB2YWx1ZSA9IGRlZXBFcXVhbC51c2UobWF0Y2gpO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgdmFsdWUgPSBkZXByZWNhdGVkLndyYXAodmFsdWUsIGRlcHJlY2F0ZWQuZGVmYXVsdE1zZyhrZXkpKTtcbiAgICAgICAgfVxuICAgICAgICB0YXJnZXRba2V5XSA9IHZhbHVlO1xuICAgIH0pO1xufVxuXG5mdW5jdGlvbiBleHBvc2VFdmVudFRhcmdldCh0YXJnZXQsIGV2ZW50VGFyZ2V0KSB7XG4gICAgdmFyIGtleXMgPSBPYmplY3Qua2V5cyhldmVudFRhcmdldCk7XG5cbiAgICBrZXlzLmZvckVhY2goZnVuY3Rpb24gKGtleSkge1xuICAgICAgICB0YXJnZXRba2V5XSA9IGRlcHJlY2F0ZWQud3JhcChldmVudFRhcmdldFtrZXldLCBkZXByZWNhdGVkLmRlZmF1bHRNc2coXCJFdmVudFRhcmdldFwiKSk7XG4gICAgfSk7XG59XG5cbi8vIEV4cG9zZSBpbnRlcm5hbCB1dGlsaXRpZXMgb24gYHNpbm9uYCBnbG9iYWwgZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5LlxuZXhwb3NlQ29yZVV0aWxzKGV4cG9ydHMsIHJlcXVpcmUoXCIuL3Npbm9uL3V0aWwvY29yZS9pbmRleFwiKSk7XG5cbmV4cG9ydHMuYXNzZXJ0ID0gcmVxdWlyZShcIi4vc2lub24vYXNzZXJ0XCIpO1xuZXhwb3J0cy5jb2xsZWN0aW9uID0gcmVxdWlyZShcIi4vc2lub24vY29sbGVjdGlvblwiKTtcbmV4cG9ydHMubWF0Y2ggPSBtYXRjaDtcbmV4cG9ydHMuc3B5ID0gcmVxdWlyZShcIi4vc2lub24vc3B5XCIpO1xuZXhwb3J0cy5zcHlDYWxsID0gcmVxdWlyZShcIi4vc2lub24vY2FsbFwiKTtcbmV4cG9ydHMuc3R1YiA9IHJlcXVpcmUoXCIuL3Npbm9uL3N0dWJcIik7XG5leHBvcnRzLm1vY2sgPSByZXF1aXJlKFwiLi9zaW5vbi9tb2NrXCIpO1xuZXhwb3J0cy5zYW5kYm94ID0gcmVxdWlyZShcIi4vc2lub24vc2FuZGJveFwiKTtcbmV4cG9ydHMuZXhwZWN0YXRpb24gPSByZXF1aXJlKFwiLi9zaW5vbi9tb2NrLWV4cGVjdGF0aW9uXCIpO1xuZXhwb3J0cy5jcmVhdGVTdHViSW5zdGFuY2UgPSByZXF1aXJlKFwiLi9zaW5vbi9zdHViXCIpLmNyZWF0ZVN0dWJJbnN0YW5jZTtcblxudmFyIGZha2VUaW1lcnMgPSByZXF1aXJlKFwiLi9zaW5vbi91dGlsL2Zha2VfdGltZXJzXCIpO1xuZXhwb3J0cy51c2VGYWtlVGltZXJzID0gZmFrZVRpbWVycy51c2VGYWtlVGltZXJzO1xuZXhwb3J0cy5jbG9jayA9IGZha2VUaW1lcnMuY2xvY2s7XG5leHBvcnRzLnRpbWVycyA9IGZha2VUaW1lcnMudGltZXJzO1xuXG52YXIgZXZlbnQgPSByZXF1aXJlKFwiLi9zaW5vbi91dGlsL2V2ZW50XCIpO1xuZXhwb3J0cy5FdmVudCA9IGRlcHJlY2F0ZWQud3JhcChldmVudC5FdmVudCwgZGVwcmVjYXRlZC5kZWZhdWx0TXNnKFwiRXZlbnRcIikpO1xuZXhwb3J0cy5DdXN0b21FdmVudCA9IGRlcHJlY2F0ZWQud3JhcChldmVudC5DdXN0b21FdmVudCwgZGVwcmVjYXRlZC5kZWZhdWx0TXNnKFwiQ3VzdG9tRXZlbnRcIikpO1xuZXhwb3J0cy5Qcm9ncmVzc0V2ZW50ID0gZGVwcmVjYXRlZC53cmFwKGV2ZW50LlByb2dyZXNzRXZlbnQsIGRlcHJlY2F0ZWQuZGVmYXVsdE1zZyhcIlByb2dyZXNzRXZlbnRcIikpO1xuZXhwb3J0cy5FdmVudFRhcmdldCA9IHt9O1xuZXhwb3NlRXZlbnRUYXJnZXQoZXhwb3J0cy5FdmVudFRhcmdldCwgZXZlbnQuRXZlbnRUYXJnZXQpO1xuXG52YXIgZmFrZVhociA9IHJlcXVpcmUoXCIuL3Npbm9uL3V0aWwvZmFrZV94bWxfaHR0cF9yZXF1ZXN0XCIpO1xuZXhwb3J0cy54aHIgPSBmYWtlWGhyLnhocjtcbmV4cG9ydHMuRmFrZVhNTEh0dHBSZXF1ZXN0ID0gZmFrZVhoci5GYWtlWE1MSHR0cFJlcXVlc3Q7XG5leHBvcnRzLnVzZUZha2VYTUxIdHRwUmVxdWVzdCA9IGZha2VYaHIudXNlRmFrZVhNTEh0dHBSZXF1ZXN0O1xuXG5leHBvcnRzLmZha2VTZXJ2ZXIgPSByZXF1aXJlKFwiLi9zaW5vbi91dGlsL2Zha2Vfc2VydmVyXCIpO1xuZXhwb3J0cy5mYWtlU2VydmVyV2l0aENsb2NrID0gcmVxdWlyZShcIi4vc2lub24vdXRpbC9mYWtlX3NlcnZlcl93aXRoX2Nsb2NrXCIpO1xuXG52YXIgYmVoYXZpb3IgPSByZXF1aXJlKFwiLi9zaW5vbi9iZWhhdmlvclwiKTtcblxuZXhwb3J0cy5hZGRCZWhhdmlvciA9IGZ1bmN0aW9uIChuYW1lLCBmbikge1xuICAgIGJlaGF2aW9yLmFkZEJlaGF2aW9yKGV4cG9ydHMuc3R1YiwgbmFtZSwgZm4pO1xufTtcbiIsIlwidXNlIHN0cmljdFwiO1xuXG52YXIgY2FsbGVkSW5PcmRlciA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS9jYWxsZWQtaW4tb3JkZXJcIik7XG52YXIgb3JkZXJCeUZpcnN0Q2FsbCA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS9vcmRlci1ieS1maXJzdC1jYWxsXCIpO1xudmFyIHRpbWVzSW5Xb3JkcyA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS90aW1lcy1pbi13b3Jkc1wiKTtcbnZhciBmb3JtYXQgPSByZXF1aXJlKFwiLi91dGlsL2NvcmUvZm9ybWF0XCIpO1xudmFyIHNpbm9uTWF0Y2ggPSByZXF1aXJlKFwiLi9tYXRjaFwiKTtcblxudmFyIHNsaWNlID0gQXJyYXkucHJvdG90eXBlLnNsaWNlO1xuXG52YXIgYXNzZXJ0O1xuXG5mdW5jdGlvbiB2ZXJpZnlJc1N0dWIoKSB7XG4gICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuXG4gICAgYXJncy5mb3JFYWNoKGZ1bmN0aW9uIChtZXRob2QpIHtcbiAgICAgICAgaWYgKCFtZXRob2QpIHtcbiAgICAgICAgICAgIGFzc2VydC5mYWlsKFwiZmFrZSBpcyBub3QgYSBzcHlcIik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAobWV0aG9kLnByb3h5ICYmIG1ldGhvZC5wcm94eS5pc1Npbm9uUHJveHkpIHtcbiAgICAgICAgICAgIHZlcmlmeUlzU3R1YihtZXRob2QucHJveHkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBtZXRob2QgIT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgICAgIGFzc2VydC5mYWlsKG1ldGhvZCArIFwiIGlzIG5vdCBhIGZ1bmN0aW9uXCIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodHlwZW9mIG1ldGhvZC5nZXRDYWxsICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICBhc3NlcnQuZmFpbChtZXRob2QgKyBcIiBpcyBub3Qgc3R1YmJlZFwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0pO1xufVxuXG5mdW5jdGlvbiB2ZXJpZnlJc1ZhbGlkQXNzZXJ0aW9uKGFzc2VydGlvbk1ldGhvZCwgYXNzZXJ0aW9uQXJncykge1xuICAgIHN3aXRjaCAoYXNzZXJ0aW9uTWV0aG9kKSB7XG4gICAgICAgIGNhc2UgXCJub3RDYWxsZWRcIjpcbiAgICAgICAgY2FzZSBcImNhbGxlZFwiOlxuICAgICAgICBjYXNlIFwiY2FsbGVkT25jZVwiOlxuICAgICAgICBjYXNlIFwiY2FsbGVkVHdpY2VcIjpcbiAgICAgICAgY2FzZSBcImNhbGxlZFRocmljZVwiOlxuICAgICAgICAgICAgaWYgKGFzc2VydGlvbkFyZ3MubGVuZ3RoICE9PSAwKSB7XG4gICAgICAgICAgICAgICAgYXNzZXJ0LmZhaWwoYXNzZXJ0aW9uTWV0aG9kICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIiB0YWtlcyAxIGFyZ3VtZW50IGJ1dCB3YXMgY2FsbGVkIHdpdGggXCIgKyAoYXNzZXJ0aW9uQXJncy5sZW5ndGggKyAxKSArIFwiIGFyZ3VtZW50c1wiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgYnJlYWs7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBmYWlsQXNzZXJ0aW9uKG9iamVjdCwgbXNnKSB7XG4gICAgb2JqZWN0ID0gb2JqZWN0IHx8IGdsb2JhbDtcbiAgICB2YXIgZmFpbE1ldGhvZCA9IG9iamVjdC5mYWlsIHx8IGFzc2VydC5mYWlsO1xuICAgIGZhaWxNZXRob2QuY2FsbChvYmplY3QsIG1zZyk7XG59XG5cbmZ1bmN0aW9uIG1pcnJvclByb3BBc0Fzc2VydGlvbihuYW1lLCBtZXRob2QsIG1lc3NhZ2UpIHtcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMikge1xuICAgICAgICBtZXNzYWdlID0gbWV0aG9kO1xuICAgICAgICBtZXRob2QgPSBuYW1lO1xuICAgIH1cblxuICAgIGFzc2VydFtuYW1lXSA9IGZ1bmN0aW9uIChmYWtlKSB7XG4gICAgICAgIHZlcmlmeUlzU3R1YihmYWtlKTtcblxuICAgICAgICB2YXIgYXJncyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICAgICAgdmFyIGZhaWxlZCA9IGZhbHNlO1xuXG4gICAgICAgIHZlcmlmeUlzVmFsaWRBc3NlcnRpb24obmFtZSwgYXJncyk7XG5cbiAgICAgICAgaWYgKHR5cGVvZiBtZXRob2QgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgZmFpbGVkID0gIW1ldGhvZChmYWtlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGZhaWxlZCA9IHR5cGVvZiBmYWtlW21ldGhvZF0gPT09IFwiZnVuY3Rpb25cIiA/XG4gICAgICAgICAgICAgICAgIWZha2VbbWV0aG9kXS5hcHBseShmYWtlLCBhcmdzKSA6ICFmYWtlW21ldGhvZF07XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZmFpbGVkKSB7XG4gICAgICAgICAgICBmYWlsQXNzZXJ0aW9uKHRoaXMsIChmYWtlLnByaW50ZiB8fCBmYWtlLnByb3h5LnByaW50ZikuYXBwbHkoZmFrZSwgW21lc3NhZ2VdLmNvbmNhdChhcmdzKSkpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYXNzZXJ0LnBhc3MobmFtZSk7XG4gICAgICAgIH1cbiAgICB9O1xufVxuXG5mdW5jdGlvbiBleHBvc2VkTmFtZShwcmVmaXgsIHByb3ApIHtcbiAgICByZXR1cm4gIXByZWZpeCB8fCAvXmZhaWwvLnRlc3QocHJvcCkgPyBwcm9wIDpcbiAgICAgICAgcHJlZml4ICsgcHJvcC5zbGljZSgwLCAxKS50b1VwcGVyQ2FzZSgpICsgcHJvcC5zbGljZSgxKTtcbn1cblxuYXNzZXJ0ID0ge1xuICAgIGZhaWxFeGNlcHRpb246IFwiQXNzZXJ0RXJyb3JcIixcblxuICAgIGZhaWw6IGZ1bmN0aW9uIGZhaWwobWVzc2FnZSkge1xuICAgICAgICB2YXIgZXJyb3IgPSBuZXcgRXJyb3IobWVzc2FnZSk7XG4gICAgICAgIGVycm9yLm5hbWUgPSB0aGlzLmZhaWxFeGNlcHRpb24gfHwgYXNzZXJ0LmZhaWxFeGNlcHRpb247XG5cbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfSxcblxuICAgIHBhc3M6IGZ1bmN0aW9uIHBhc3MoKSB7fSxcblxuICAgIGNhbGxPcmRlcjogZnVuY3Rpb24gYXNzZXJ0Q2FsbE9yZGVyKCkge1xuICAgICAgICB2ZXJpZnlJc1N0dWIuYXBwbHkobnVsbCwgYXJndW1lbnRzKTtcbiAgICAgICAgdmFyIGV4cGVjdGVkID0gXCJcIjtcbiAgICAgICAgdmFyIGFjdHVhbCA9IFwiXCI7XG5cbiAgICAgICAgaWYgKCFjYWxsZWRJbk9yZGVyKGFyZ3VtZW50cykpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgZXhwZWN0ZWQgPSBbXS5qb2luLmNhbGwoYXJndW1lbnRzLCBcIiwgXCIpO1xuICAgICAgICAgICAgICAgIHZhciBjYWxscyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICB2YXIgaSA9IGNhbGxzLmxlbmd0aDtcbiAgICAgICAgICAgICAgICB3aGlsZSAoaSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIWNhbGxzWy0taV0uY2FsbGVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYWxscy5zcGxpY2UoaSwgMSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYWN0dWFsID0gb3JkZXJCeUZpcnN0Q2FsbChjYWxscykuam9pbihcIiwgXCIpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIC8vIElmIHRoaXMgZmFpbHMsIHdlJ2xsIGp1c3QgZmFsbCBiYWNrIHRvIHRoZSBibGFuayBzdHJpbmdcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZmFpbEFzc2VydGlvbih0aGlzLCBcImV4cGVjdGVkIFwiICsgZXhwZWN0ZWQgKyBcIiB0byBiZSBcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICBcImNhbGxlZCBpbiBvcmRlciBidXQgd2VyZSBjYWxsZWQgYXMgXCIgKyBhY3R1YWwpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgYXNzZXJ0LnBhc3MoXCJjYWxsT3JkZXJcIik7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgY2FsbENvdW50OiBmdW5jdGlvbiBhc3NlcnRDYWxsQ291bnQobWV0aG9kLCBjb3VudCkge1xuICAgICAgICB2ZXJpZnlJc1N0dWIobWV0aG9kKTtcblxuICAgICAgICBpZiAobWV0aG9kLmNhbGxDb3VudCAhPT0gY291bnQpIHtcbiAgICAgICAgICAgIHZhciBtc2cgPSBcImV4cGVjdGVkICVuIHRvIGJlIGNhbGxlZCBcIiArIHRpbWVzSW5Xb3Jkcyhjb3VudCkgK1xuICAgICAgICAgICAgICAgIFwiIGJ1dCB3YXMgY2FsbGVkICVjJUNcIjtcbiAgICAgICAgICAgIGZhaWxBc3NlcnRpb24odGhpcywgbWV0aG9kLnByaW50Zihtc2cpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGFzc2VydC5wYXNzKFwiY2FsbENvdW50XCIpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIGV4cG9zZTogZnVuY3Rpb24gZXhwb3NlKHRhcmdldCwgb3B0aW9ucykge1xuICAgICAgICBpZiAoIXRhcmdldCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcInRhcmdldCBpcyBudWxsIG9yIHVuZGVmaW5lZFwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBvID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgdmFyIHByZWZpeCA9IHR5cGVvZiBvLnByZWZpeCA9PT0gXCJ1bmRlZmluZWRcIiAmJiBcImFzc2VydFwiIHx8IG8ucHJlZml4O1xuICAgICAgICB2YXIgaW5jbHVkZUZhaWwgPSB0eXBlb2Ygby5pbmNsdWRlRmFpbCA9PT0gXCJ1bmRlZmluZWRcIiB8fCAhIW8uaW5jbHVkZUZhaWw7XG4gICAgICAgIHZhciBpbnN0YW5jZSA9IHRoaXM7XG5cbiAgICAgICAgT2JqZWN0LmtleXMoaW5zdGFuY2UpLmZvckVhY2goZnVuY3Rpb24gKG1ldGhvZCkge1xuICAgICAgICAgICAgaWYgKG1ldGhvZCAhPT0gXCJleHBvc2VcIiAmJiAoaW5jbHVkZUZhaWwgfHwgIS9eKGZhaWwpLy50ZXN0KG1ldGhvZCkpKSB7XG4gICAgICAgICAgICAgICAgdGFyZ2V0W2V4cG9zZWROYW1lKHByZWZpeCwgbWV0aG9kKV0gPSBpbnN0YW5jZVttZXRob2RdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gdGFyZ2V0O1xuICAgIH0sXG5cbiAgICBtYXRjaDogZnVuY3Rpb24gbWF0Y2goYWN0dWFsLCBleHBlY3RhdGlvbikge1xuICAgICAgICB2YXIgbWF0Y2hlciA9IHNpbm9uTWF0Y2goZXhwZWN0YXRpb24pO1xuICAgICAgICBpZiAobWF0Y2hlci50ZXN0KGFjdHVhbCkpIHtcbiAgICAgICAgICAgIGFzc2VydC5wYXNzKFwibWF0Y2hcIik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB2YXIgZm9ybWF0dGVkID0gW1xuICAgICAgICAgICAgICAgIFwiZXhwZWN0ZWQgdmFsdWUgdG8gbWF0Y2hcIixcbiAgICAgICAgICAgICAgICBcIiAgICBleHBlY3RlZCA9IFwiICsgZm9ybWF0KGV4cGVjdGF0aW9uKSxcbiAgICAgICAgICAgICAgICBcIiAgICBhY3R1YWwgPSBcIiArIGZvcm1hdChhY3R1YWwpXG4gICAgICAgICAgICBdO1xuXG4gICAgICAgICAgICBmYWlsQXNzZXJ0aW9uKHRoaXMsIGZvcm1hdHRlZC5qb2luKFwiXFxuXCIpKTtcbiAgICAgICAgfVxuICAgIH1cbn07XG5cbm1pcnJvclByb3BBc0Fzc2VydGlvbihcImNhbGxlZFwiLCBcImV4cGVjdGVkICVuIHRvIGhhdmUgYmVlbiBjYWxsZWQgYXQgbGVhc3Qgb25jZSBidXQgd2FzIG5ldmVyIGNhbGxlZFwiKTtcbm1pcnJvclByb3BBc0Fzc2VydGlvbihcIm5vdENhbGxlZFwiLCBmdW5jdGlvbiAoc3B5KSB7XG4gICAgcmV0dXJuICFzcHkuY2FsbGVkO1xufSwgXCJleHBlY3RlZCAlbiB0byBub3QgaGF2ZSBiZWVuIGNhbGxlZCBidXQgd2FzIGNhbGxlZCAlYyVDXCIpO1xubWlycm9yUHJvcEFzQXNzZXJ0aW9uKFwiY2FsbGVkT25jZVwiLCBcImV4cGVjdGVkICVuIHRvIGJlIGNhbGxlZCBvbmNlIGJ1dCB3YXMgY2FsbGVkICVjJUNcIik7XG5taXJyb3JQcm9wQXNBc3NlcnRpb24oXCJjYWxsZWRUd2ljZVwiLCBcImV4cGVjdGVkICVuIHRvIGJlIGNhbGxlZCB0d2ljZSBidXQgd2FzIGNhbGxlZCAlYyVDXCIpO1xubWlycm9yUHJvcEFzQXNzZXJ0aW9uKFwiY2FsbGVkVGhyaWNlXCIsIFwiZXhwZWN0ZWQgJW4gdG8gYmUgY2FsbGVkIHRocmljZSBidXQgd2FzIGNhbGxlZCAlYyVDXCIpO1xubWlycm9yUHJvcEFzQXNzZXJ0aW9uKFwiY2FsbGVkT25cIiwgXCJleHBlY3RlZCAlbiB0byBiZSBjYWxsZWQgd2l0aCAlMSBhcyB0aGlzIGJ1dCB3YXMgY2FsbGVkIHdpdGggJXRcIik7XG5taXJyb3JQcm9wQXNBc3NlcnRpb24oXG4gICAgXCJhbHdheXNDYWxsZWRPblwiLFxuICAgIFwiZXhwZWN0ZWQgJW4gdG8gYWx3YXlzIGJlIGNhbGxlZCB3aXRoICUxIGFzIHRoaXMgYnV0IHdhcyBjYWxsZWQgd2l0aCAldFwiXG4pO1xubWlycm9yUHJvcEFzQXNzZXJ0aW9uKFwiY2FsbGVkV2l0aE5ld1wiLCBcImV4cGVjdGVkICVuIHRvIGJlIGNhbGxlZCB3aXRoIG5ld1wiKTtcbm1pcnJvclByb3BBc0Fzc2VydGlvbihcImFsd2F5c0NhbGxlZFdpdGhOZXdcIiwgXCJleHBlY3RlZCAlbiB0byBhbHdheXMgYmUgY2FsbGVkIHdpdGggbmV3XCIpO1xubWlycm9yUHJvcEFzQXNzZXJ0aW9uKFwiY2FsbGVkV2l0aFwiLCBcImV4cGVjdGVkICVuIHRvIGJlIGNhbGxlZCB3aXRoIGFyZ3VtZW50cyAlRFwiKTtcbm1pcnJvclByb3BBc0Fzc2VydGlvbihcImNhbGxlZFdpdGhNYXRjaFwiLCBcImV4cGVjdGVkICVuIHRvIGJlIGNhbGxlZCB3aXRoIG1hdGNoICVEXCIpO1xubWlycm9yUHJvcEFzQXNzZXJ0aW9uKFwiYWx3YXlzQ2FsbGVkV2l0aFwiLCBcImV4cGVjdGVkICVuIHRvIGFsd2F5cyBiZSBjYWxsZWQgd2l0aCBhcmd1bWVudHMgJURcIik7XG5taXJyb3JQcm9wQXNBc3NlcnRpb24oXCJhbHdheXNDYWxsZWRXaXRoTWF0Y2hcIiwgXCJleHBlY3RlZCAlbiB0byBhbHdheXMgYmUgY2FsbGVkIHdpdGggbWF0Y2ggJURcIik7XG5taXJyb3JQcm9wQXNBc3NlcnRpb24oXCJjYWxsZWRXaXRoRXhhY3RseVwiLCBcImV4cGVjdGVkICVuIHRvIGJlIGNhbGxlZCB3aXRoIGV4YWN0IGFyZ3VtZW50cyAlRFwiKTtcbm1pcnJvclByb3BBc0Fzc2VydGlvbihcImFsd2F5c0NhbGxlZFdpdGhFeGFjdGx5XCIsIFwiZXhwZWN0ZWQgJW4gdG8gYWx3YXlzIGJlIGNhbGxlZCB3aXRoIGV4YWN0IGFyZ3VtZW50cyAlRFwiKTtcbm1pcnJvclByb3BBc0Fzc2VydGlvbihcIm5ldmVyQ2FsbGVkV2l0aFwiLCBcImV4cGVjdGVkICVuIHRvIG5ldmVyIGJlIGNhbGxlZCB3aXRoIGFyZ3VtZW50cyAlKiVDXCIpO1xubWlycm9yUHJvcEFzQXNzZXJ0aW9uKFwibmV2ZXJDYWxsZWRXaXRoTWF0Y2hcIiwgXCJleHBlY3RlZCAlbiB0byBuZXZlciBiZSBjYWxsZWQgd2l0aCBtYXRjaCAlKiVDXCIpO1xubWlycm9yUHJvcEFzQXNzZXJ0aW9uKFwidGhyZXdcIiwgXCIlbiBkaWQgbm90IHRocm93IGV4Y2VwdGlvbiVDXCIpO1xubWlycm9yUHJvcEFzQXNzZXJ0aW9uKFwiYWx3YXlzVGhyZXdcIiwgXCIlbiBkaWQgbm90IGFsd2F5cyB0aHJvdyBleGNlcHRpb24lQ1wiKTtcblxubW9kdWxlLmV4cG9ydHMgPSBhc3NlcnQ7XG4iLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIGV4dGVuZCA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS9leHRlbmRcIik7XG52YXIgZnVuY3Rpb25OYW1lID0gcmVxdWlyZShcIi4vdXRpbC9jb3JlL2Z1bmN0aW9uLW5hbWVcIik7XG52YXIgdmFsdWVUb1N0cmluZyA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS92YWx1ZS10by1zdHJpbmdcIik7XG5cbnZhciBzbGljZSA9IEFycmF5LnByb3RvdHlwZS5zbGljZTtcbnZhciBqb2luID0gQXJyYXkucHJvdG90eXBlLmpvaW47XG52YXIgdXNlTGVmdE1vc3RDYWxsYmFjayA9IC0xO1xudmFyIHVzZVJpZ2h0TW9zdENhbGxiYWNrID0gLTI7XG5cbnZhciBuZXh0VGljayA9IChmdW5jdGlvbiAoKSB7XG4gICAgaWYgKHR5cGVvZiBwcm9jZXNzID09PSBcIm9iamVjdFwiICYmIHR5cGVvZiBwcm9jZXNzLm5leHRUaWNrID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgcmV0dXJuIHByb2Nlc3MubmV4dFRpY2s7XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiBzZXRJbW1lZGlhdGUgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICByZXR1cm4gc2V0SW1tZWRpYXRlO1xuICAgIH1cblxuICAgIHJldHVybiBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICAgICAgc2V0VGltZW91dChjYWxsYmFjaywgMCk7XG4gICAgfTtcbn0pKCk7XG5cbmZ1bmN0aW9uIGdldENhbGxiYWNrKGJlaGF2aW9yLCBhcmdzKSB7XG4gICAgdmFyIGNhbGxBcmdBdCA9IGJlaGF2aW9yLmNhbGxBcmdBdDtcblxuICAgIGlmIChjYWxsQXJnQXQgPj0gMCkge1xuICAgICAgICByZXR1cm4gYXJnc1tjYWxsQXJnQXRdO1xuICAgIH1cblxuICAgIHZhciBhcmd1bWVudExpc3Q7XG5cbiAgICBpZiAoY2FsbEFyZ0F0ID09PSB1c2VMZWZ0TW9zdENhbGxiYWNrKSB7XG4gICAgICAgIGFyZ3VtZW50TGlzdCA9IGFyZ3M7XG4gICAgfVxuXG4gICAgaWYgKGNhbGxBcmdBdCA9PT0gdXNlUmlnaHRNb3N0Q2FsbGJhY2spIHtcbiAgICAgICAgYXJndW1lbnRMaXN0ID0gc2xpY2UuY2FsbChhcmdzKS5yZXZlcnNlKCk7XG4gICAgfVxuXG4gICAgdmFyIGNhbGxBcmdQcm9wID0gYmVoYXZpb3IuY2FsbEFyZ1Byb3A7XG5cbiAgICBmb3IgKHZhciBpID0gMCwgbCA9IGFyZ3VtZW50TGlzdC5sZW5ndGg7IGkgPCBsOyArK2kpIHtcbiAgICAgICAgaWYgKCFjYWxsQXJnUHJvcCAmJiB0eXBlb2YgYXJndW1lbnRMaXN0W2ldID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgIHJldHVybiBhcmd1bWVudExpc3RbaV07XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY2FsbEFyZ1Byb3AgJiYgYXJndW1lbnRMaXN0W2ldICYmXG4gICAgICAgICAgICB0eXBlb2YgYXJndW1lbnRMaXN0W2ldW2NhbGxBcmdQcm9wXSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICByZXR1cm4gYXJndW1lbnRMaXN0W2ldW2NhbGxBcmdQcm9wXTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBudWxsO1xufVxuXG5mdW5jdGlvbiBnZXRDYWxsYmFja0Vycm9yKGJlaGF2aW9yLCBmdW5jLCBhcmdzKSB7XG4gICAgaWYgKGJlaGF2aW9yLmNhbGxBcmdBdCA8IDApIHtcbiAgICAgICAgdmFyIG1zZztcblxuICAgICAgICBpZiAoYmVoYXZpb3IuY2FsbEFyZ1Byb3ApIHtcbiAgICAgICAgICAgIG1zZyA9IGZ1bmN0aW9uTmFtZShiZWhhdmlvci5zdHViKSArXG4gICAgICAgICAgICAgICAgXCIgZXhwZWN0ZWQgdG8geWllbGQgdG8gJ1wiICsgdmFsdWVUb1N0cmluZyhiZWhhdmlvci5jYWxsQXJnUHJvcCkgK1xuICAgICAgICAgICAgICAgIFwiJywgYnV0IG5vIG9iamVjdCB3aXRoIHN1Y2ggYSBwcm9wZXJ0eSB3YXMgcGFzc2VkLlwiO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbXNnID0gZnVuY3Rpb25OYW1lKGJlaGF2aW9yLnN0dWIpICtcbiAgICAgICAgICAgICAgICBcIiBleHBlY3RlZCB0byB5aWVsZCwgYnV0IG5vIGNhbGxiYWNrIHdhcyBwYXNzZWQuXCI7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoYXJncy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBtc2cgKz0gXCIgUmVjZWl2ZWQgW1wiICsgam9pbi5jYWxsKGFyZ3MsIFwiLCBcIikgKyBcIl1cIjtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBtc2c7XG4gICAgfVxuXG4gICAgcmV0dXJuIFwiYXJndW1lbnQgYXQgaW5kZXggXCIgKyBiZWhhdmlvci5jYWxsQXJnQXQgKyBcIiBpcyBub3QgYSBmdW5jdGlvbjogXCIgKyBmdW5jO1xufVxuXG5mdW5jdGlvbiBjYWxsQ2FsbGJhY2soYmVoYXZpb3IsIGFyZ3MpIHtcbiAgICBpZiAodHlwZW9mIGJlaGF2aW9yLmNhbGxBcmdBdCA9PT0gXCJudW1iZXJcIikge1xuICAgICAgICB2YXIgZnVuYyA9IGdldENhbGxiYWNrKGJlaGF2aW9yLCBhcmdzKTtcblxuICAgICAgICBpZiAodHlwZW9mIGZ1bmMgIT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihnZXRDYWxsYmFja0Vycm9yKGJlaGF2aW9yLCBmdW5jLCBhcmdzKSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoYmVoYXZpb3IuY2FsbGJhY2tBc3luYykge1xuICAgICAgICAgICAgbmV4dFRpY2soZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIGZ1bmMuYXBwbHkoYmVoYXZpb3IuY2FsbGJhY2tDb250ZXh0LCBiZWhhdmlvci5jYWxsYmFja0FyZ3VtZW50cyk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGZ1bmMuYXBwbHkoYmVoYXZpb3IuY2FsbGJhY2tDb250ZXh0LCBiZWhhdmlvci5jYWxsYmFja0FyZ3VtZW50cyk7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbnZhciBwcm90byA9IHtcbiAgICBjcmVhdGU6IGZ1bmN0aW9uIGNyZWF0ZShzdHViKSB7XG4gICAgICAgIHZhciBiZWhhdmlvciA9IGV4dGVuZCh7fSwgcHJvdG8pO1xuICAgICAgICBkZWxldGUgYmVoYXZpb3IuY3JlYXRlO1xuICAgICAgICBkZWxldGUgYmVoYXZpb3IuYWRkQmVoYXZpb3I7XG4gICAgICAgIGRlbGV0ZSBiZWhhdmlvci5jcmVhdGVCZWhhdmlvcjtcbiAgICAgICAgYmVoYXZpb3Iuc3R1YiA9IHN0dWI7XG5cbiAgICAgICAgcmV0dXJuIGJlaGF2aW9yO1xuICAgIH0sXG5cbiAgICBpc1ByZXNlbnQ6IGZ1bmN0aW9uIGlzUHJlc2VudCgpIHtcbiAgICAgICAgcmV0dXJuICh0eXBlb2YgdGhpcy5jYWxsQXJnQXQgPT09IFwibnVtYmVyXCIgfHxcbiAgICAgICAgICAgICAgICB0aGlzLmV4Y2VwdGlvbiB8fFxuICAgICAgICAgICAgICAgIHR5cGVvZiB0aGlzLnJldHVybkFyZ0F0ID09PSBcIm51bWJlclwiIHx8XG4gICAgICAgICAgICAgICAgdGhpcy5yZXR1cm5UaGlzIHx8XG4gICAgICAgICAgICAgICAgdGhpcy5mYWtlRm4gfHxcbiAgICAgICAgICAgICAgICB0aGlzLnJldHVyblZhbHVlRGVmaW5lZCk7XG4gICAgfSxcblxuICAgIGludm9rZTogZnVuY3Rpb24gaW52b2tlKGNvbnRleHQsIGFyZ3MpIHtcbiAgICAgICAgY2FsbENhbGxiYWNrKHRoaXMsIGFyZ3MpO1xuXG4gICAgICAgIGlmICh0aGlzLmV4Y2VwdGlvbikge1xuICAgICAgICAgICAgdGhyb3cgdGhpcy5leGNlcHRpb247XG4gICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIHRoaXMucmV0dXJuQXJnQXQgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICAgIHJldHVybiBhcmdzW3RoaXMucmV0dXJuQXJnQXRdO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMucmV0dXJuVGhpcykge1xuICAgICAgICAgICAgcmV0dXJuIGNvbnRleHQ7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5mYWtlRm4pIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmZha2VGbi5hcHBseShjb250ZXh0LCBhcmdzKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLnJlc29sdmUpIHtcbiAgICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUodGhpcy5yZXR1cm5WYWx1ZSk7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5yZWplY3QpIHtcbiAgICAgICAgICAgIHJldHVybiBQcm9taXNlLnJlamVjdCh0aGlzLnJldHVyblZhbHVlKTtcbiAgICAgICAgfSBlbHNlIGlmICh0aGlzLmNhbGxzVGhyb3VnaCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuc3R1Yi53cmFwcGVkTWV0aG9kLmFwcGx5KGNvbnRleHQsIGFyZ3MpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLnJldHVyblZhbHVlO1xuICAgIH0sXG5cbiAgICBvbkNhbGw6IGZ1bmN0aW9uIG9uQ2FsbChpbmRleCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zdHViLm9uQ2FsbChpbmRleCk7XG4gICAgfSxcblxuICAgIG9uRmlyc3RDYWxsOiBmdW5jdGlvbiBvbkZpcnN0Q2FsbCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3R1Yi5vbkZpcnN0Q2FsbCgpO1xuICAgIH0sXG5cbiAgICBvblNlY29uZENhbGw6IGZ1bmN0aW9uIG9uU2Vjb25kQ2FsbCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3R1Yi5vblNlY29uZENhbGwoKTtcbiAgICB9LFxuXG4gICAgb25UaGlyZENhbGw6IGZ1bmN0aW9uIG9uVGhpcmRDYWxsKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zdHViLm9uVGhpcmRDYWxsKCk7XG4gICAgfSxcblxuICAgIHdpdGhBcmdzOiBmdW5jdGlvbiB3aXRoQXJncygvKiBhcmd1bWVudHMgKi8pIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgXCJEZWZpbmluZyBhIHN0dWIgYnkgaW52b2tpbmcgXFxcInN0dWIub25DYWxsKC4uLikud2l0aEFyZ3MoLi4uKVxcXCIgXCIgK1xuICAgICAgICAgICAgXCJpcyBub3Qgc3VwcG9ydGVkLiBVc2UgXFxcInN0dWIud2l0aEFyZ3MoLi4uKS5vbkNhbGwoLi4uKVxcXCIgXCIgK1xuICAgICAgICAgICAgXCJ0byBkZWZpbmUgc2VxdWVudGlhbCBiZWhhdmlvciBmb3IgY2FsbHMgd2l0aCBjZXJ0YWluIGFyZ3VtZW50cy5cIlxuICAgICAgICApO1xuICAgIH1cbn07XG5cbmZ1bmN0aW9uIGNyZWF0ZUFzeW5jVmVyc2lvbihzeW5jRm5OYW1lKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHJlc3VsdCA9IHRoaXNbc3luY0ZuTmFtZV0uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgdGhpcy5jYWxsYmFja0FzeW5jID0gdHJ1ZTtcbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9O1xufVxuXG4vLyBjcmVhdGUgYXN5bmNocm9ub3VzIHZlcnNpb25zIG9mIGNhbGxzQXJnKiBhbmQgeWllbGRzKiBtZXRob2RzXG5PYmplY3Qua2V5cyhwcm90bykuZm9yRWFjaChmdW5jdGlvbiAobWV0aG9kKSB7XG4gICAgLy8gbmVlZCB0byBhdm9pZCBjcmVhdGluZyBhbm90aGVyYXN5bmMgdmVyc2lvbnMgb2YgdGhlIG5ld2x5IGFkZGVkIGFzeW5jIG1ldGhvZHNcbiAgICBpZiAobWV0aG9kLm1hdGNoKC9eKGNhbGxzQXJnfHlpZWxkcykvKSAmJiAhbWV0aG9kLm1hdGNoKC9Bc3luYy8pKSB7XG4gICAgICAgIHByb3RvW21ldGhvZCArIFwiQXN5bmNcIl0gPSBjcmVhdGVBc3luY1ZlcnNpb24obWV0aG9kKTtcbiAgICB9XG59KTtcblxuZnVuY3Rpb24gY3JlYXRlQmVoYXZpb3IoYmVoYXZpb3JNZXRob2QpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLmRlZmF1bHRCZWhhdmlvciA9IHRoaXMuZGVmYXVsdEJlaGF2aW9yIHx8IHByb3RvLmNyZWF0ZSh0aGlzKTtcbiAgICAgICAgdGhpcy5kZWZhdWx0QmVoYXZpb3JbYmVoYXZpb3JNZXRob2RdLmFwcGx5KHRoaXMuZGVmYXVsdEJlaGF2aW9yLCBhcmd1bWVudHMpO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9O1xufVxuXG5mdW5jdGlvbiBhZGRCZWhhdmlvcihzdHViLCBuYW1lLCBmbikge1xuICAgIHByb3RvW25hbWVdID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBmbi5hcHBseSh0aGlzLCBbdGhpc10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICByZXR1cm4gdGhpcy5zdHViIHx8IHRoaXM7XG4gICAgfTtcblxuICAgIHN0dWJbbmFtZV0gPSBjcmVhdGVCZWhhdmlvcihuYW1lKTtcbn1cblxucHJvdG8uYWRkQmVoYXZpb3IgPSBhZGRCZWhhdmlvcjtcbnByb3RvLmNyZWF0ZUJlaGF2aW9yID0gY3JlYXRlQmVoYXZpb3I7XG5tb2R1bGUuZXhwb3J0cyA9IHByb3RvO1xuIiwiLypnbG9iYWwgQmxvYiAqL1xuXCJ1c2Ugc3RyaWN0XCI7XG5cbmV4cG9ydHMuaXNTdXBwb3J0ZWQgPSAoZnVuY3Rpb24gKCkge1xuICAgIHRyeSB7XG4gICAgICAgIHJldHVybiAhIW5ldyBCbG9iKCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxufSgpKTtcbiIsIlwidXNlIHN0cmljdFwiO1xuXG52YXIgc2lub25NYXRjaCA9IHJlcXVpcmUoXCIuL21hdGNoXCIpO1xudmFyIGRlZXBFcXVhbCA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS9kZWVwLWVxdWFsXCIpLnVzZShzaW5vbk1hdGNoKTtcbnZhciBmdW5jdGlvbk5hbWUgPSByZXF1aXJlKFwiLi91dGlsL2NvcmUvZnVuY3Rpb24tbmFtZVwiKTtcbnZhciBzaW5vbkZvcm1hdCA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS9mb3JtYXRcIik7XG52YXIgdmFsdWVUb1N0cmluZyA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS92YWx1ZS10by1zdHJpbmdcIik7XG52YXIgc2xpY2UgPSBBcnJheS5wcm90b3R5cGUuc2xpY2U7XG5cbmZ1bmN0aW9uIHRocm93WWllbGRFcnJvcihwcm94eSwgdGV4dCwgYXJncykge1xuICAgIHZhciBtc2cgPSBmdW5jdGlvbk5hbWUocHJveHkpICsgdGV4dDtcbiAgICBpZiAoYXJncy5sZW5ndGgpIHtcbiAgICAgICAgbXNnICs9IFwiIFJlY2VpdmVkIFtcIiArIHNsaWNlLmNhbGwoYXJncykuam9pbihcIiwgXCIpICsgXCJdXCI7XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcihtc2cpO1xufVxuXG52YXIgY2FsbFByb3RvID0ge1xuICAgIGNhbGxlZE9uOiBmdW5jdGlvbiBjYWxsZWRPbih0aGlzVmFsdWUpIHtcbiAgICAgICAgaWYgKHNpbm9uTWF0Y2ggJiYgc2lub25NYXRjaC5pc01hdGNoZXIodGhpc1ZhbHVlKSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXNWYWx1ZS50ZXN0KHRoaXMudGhpc1ZhbHVlKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy50aGlzVmFsdWUgPT09IHRoaXNWYWx1ZTtcbiAgICB9LFxuXG4gICAgY2FsbGVkV2l0aDogZnVuY3Rpb24gY2FsbGVkV2l0aCgpIHtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICB2YXIgY2FsbGVkV2l0aEFyZ3MgPSBzbGljZS5jYWxsKGFyZ3VtZW50cyk7XG5cbiAgICAgICAgaWYgKGNhbGxlZFdpdGhBcmdzLmxlbmd0aCA+IHNlbGYuYXJncy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBjYWxsZWRXaXRoQXJncy5yZWR1Y2UoZnVuY3Rpb24gKHByZXYsIGFyZywgaSkge1xuICAgICAgICAgICAgcmV0dXJuIHByZXYgJiYgZGVlcEVxdWFsKGFyZywgc2VsZi5hcmdzW2ldKTtcbiAgICAgICAgfSwgdHJ1ZSk7XG4gICAgfSxcblxuICAgIGNhbGxlZFdpdGhNYXRjaDogZnVuY3Rpb24gY2FsbGVkV2l0aE1hdGNoKCkge1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgIHZhciBjYWxsZWRXaXRoTWF0Y2hBcmdzID0gc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuXG4gICAgICAgIGlmIChjYWxsZWRXaXRoTWF0Y2hBcmdzLmxlbmd0aCA+IHNlbGYuYXJncy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBjYWxsZWRXaXRoTWF0Y2hBcmdzLnJlZHVjZShmdW5jdGlvbiAocHJldiwgZXhwZWN0YXRpb24sIGkpIHtcbiAgICAgICAgICAgIHZhciBhY3R1YWwgPSBzZWxmLmFyZ3NbaV07XG5cbiAgICAgICAgICAgIHJldHVybiBwcmV2ICYmIChzaW5vbk1hdGNoICYmIHNpbm9uTWF0Y2goZXhwZWN0YXRpb24pLnRlc3QoYWN0dWFsKSk7XG4gICAgICAgIH0sIHRydWUpO1xuICAgIH0sXG5cbiAgICBjYWxsZWRXaXRoRXhhY3RseTogZnVuY3Rpb24gY2FsbGVkV2l0aEV4YWN0bHkoKSB7XG4gICAgICAgIHJldHVybiBhcmd1bWVudHMubGVuZ3RoID09PSB0aGlzLmFyZ3MubGVuZ3RoICYmXG4gICAgICAgICAgICB0aGlzLmNhbGxlZFdpdGguYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgbm90Q2FsbGVkV2l0aDogZnVuY3Rpb24gbm90Q2FsbGVkV2l0aCgpIHtcbiAgICAgICAgcmV0dXJuICF0aGlzLmNhbGxlZFdpdGguYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgbm90Q2FsbGVkV2l0aE1hdGNoOiBmdW5jdGlvbiBub3RDYWxsZWRXaXRoTWF0Y2goKSB7XG4gICAgICAgIHJldHVybiAhdGhpcy5jYWxsZWRXaXRoTWF0Y2guYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB9LFxuXG4gICAgcmV0dXJuZWQ6IGZ1bmN0aW9uIHJldHVybmVkKHZhbHVlKSB7XG4gICAgICAgIHJldHVybiBkZWVwRXF1YWwodmFsdWUsIHRoaXMucmV0dXJuVmFsdWUpO1xuICAgIH0sXG5cbiAgICB0aHJldzogZnVuY3Rpb24gdGhyZXcoZXJyb3IpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBlcnJvciA9PT0gXCJ1bmRlZmluZWRcIiB8fCAhdGhpcy5leGNlcHRpb24pIHtcbiAgICAgICAgICAgIHJldHVybiAhIXRoaXMuZXhjZXB0aW9uO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuZXhjZXB0aW9uID09PSBlcnJvciB8fCB0aGlzLmV4Y2VwdGlvbi5uYW1lID09PSBlcnJvcjtcbiAgICB9LFxuXG4gICAgY2FsbGVkV2l0aE5ldzogZnVuY3Rpb24gY2FsbGVkV2l0aE5ldygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucHJveHkucHJvdG90eXBlICYmIHRoaXMudGhpc1ZhbHVlIGluc3RhbmNlb2YgdGhpcy5wcm94eTtcbiAgICB9LFxuXG4gICAgY2FsbGVkQmVmb3JlOiBmdW5jdGlvbiAob3RoZXIpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY2FsbElkIDwgb3RoZXIuY2FsbElkO1xuICAgIH0sXG5cbiAgICBjYWxsZWRBZnRlcjogZnVuY3Rpb24gKG90aGVyKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmNhbGxJZCA+IG90aGVyLmNhbGxJZDtcbiAgICB9LFxuXG4gICAgY2FsbEFyZzogZnVuY3Rpb24gKHBvcykge1xuICAgICAgICB0aGlzLmFyZ3NbcG9zXSgpO1xuICAgIH0sXG5cbiAgICBjYWxsQXJnT246IGZ1bmN0aW9uIChwb3MsIHRoaXNWYWx1ZSkge1xuICAgICAgICB0aGlzLmFyZ3NbcG9zXS5hcHBseSh0aGlzVmFsdWUpO1xuICAgIH0sXG5cbiAgICBjYWxsQXJnV2l0aDogZnVuY3Rpb24gKHBvcykge1xuICAgICAgICB0aGlzLmNhbGxBcmdPbldpdGguYXBwbHkodGhpcywgW3BvcywgbnVsbF0uY29uY2F0KHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSkpO1xuICAgIH0sXG5cbiAgICBjYWxsQXJnT25XaXRoOiBmdW5jdGlvbiAocG9zLCB0aGlzVmFsdWUpIHtcbiAgICAgICAgdmFyIGFyZ3MgPSBzbGljZS5jYWxsKGFyZ3VtZW50cywgMik7XG4gICAgICAgIHRoaXMuYXJnc1twb3NdLmFwcGx5KHRoaXNWYWx1ZSwgYXJncyk7XG4gICAgfSxcblxuICAgIFwieWllbGRcIjogZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLnlpZWxkT24uYXBwbHkodGhpcywgW251bGxdLmNvbmNhdChzbGljZS5jYWxsKGFyZ3VtZW50cywgMCkpKTtcbiAgICB9LFxuXG4gICAgeWllbGRPbjogZnVuY3Rpb24gKHRoaXNWYWx1ZSkge1xuICAgICAgICB2YXIgYXJncyA9IHNsaWNlLmNhbGwodGhpcy5hcmdzKTtcbiAgICAgICAgdmFyIHlpZWxkRm4gPSBhcmdzLmZpbHRlcihmdW5jdGlvbiAoYXJnKSB7XG4gICAgICAgICAgICByZXR1cm4gdHlwZW9mIGFyZyA9PT0gXCJmdW5jdGlvblwiO1xuICAgICAgICB9KVswXTtcblxuICAgICAgICBpZiAoIXlpZWxkRm4pIHtcbiAgICAgICAgICAgIHRocm93WWllbGRFcnJvcih0aGlzLnByb3h5LCBcIiBjYW5ub3QgeWllbGQgc2luY2Ugbm8gY2FsbGJhY2sgd2FzIHBhc3NlZC5cIiwgYXJncyk7XG4gICAgICAgIH1cblxuICAgICAgICB5aWVsZEZuLmFwcGx5KHRoaXNWYWx1ZSwgc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpKTtcbiAgICB9LFxuXG4gICAgeWllbGRUbzogZnVuY3Rpb24gKHByb3ApIHtcbiAgICAgICAgdGhpcy55aWVsZFRvT24uYXBwbHkodGhpcywgW3Byb3AsIG51bGxdLmNvbmNhdChzbGljZS5jYWxsKGFyZ3VtZW50cywgMSkpKTtcbiAgICB9LFxuXG4gICAgeWllbGRUb09uOiBmdW5jdGlvbiAocHJvcCwgdGhpc1ZhbHVlKSB7XG4gICAgICAgIHZhciBhcmdzID0gc2xpY2UuY2FsbCh0aGlzLmFyZ3MpO1xuICAgICAgICB2YXIgeWllbGRBcmcgPSBhcmdzLmZpbHRlcihmdW5jdGlvbiAoYXJnKSB7XG4gICAgICAgICAgICByZXR1cm4gYXJnICYmIHR5cGVvZiBhcmdbcHJvcF0gPT09IFwiZnVuY3Rpb25cIjtcbiAgICAgICAgfSlbMF07XG4gICAgICAgIHZhciB5aWVsZEZuID0geWllbGRBcmcgJiYgeWllbGRBcmdbcHJvcF07XG5cbiAgICAgICAgaWYgKCF5aWVsZEZuKSB7XG4gICAgICAgICAgICB0aHJvd1lpZWxkRXJyb3IodGhpcy5wcm94eSwgXCIgY2Fubm90IHlpZWxkIHRvICdcIiArIHZhbHVlVG9TdHJpbmcocHJvcCkgK1xuICAgICAgICAgICAgICAgIFwiJyBzaW5jZSBubyBjYWxsYmFjayB3YXMgcGFzc2VkLlwiLCBhcmdzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHlpZWxkRm4uYXBwbHkodGhpc1ZhbHVlLCBzbGljZS5jYWxsKGFyZ3VtZW50cywgMikpO1xuICAgIH0sXG5cbiAgICB0b1N0cmluZzogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgY2FsbFN0ciA9IHRoaXMucHJveHkgPyB0aGlzLnByb3h5LnRvU3RyaW5nKCkgKyBcIihcIiA6IFwiXCI7XG4gICAgICAgIHZhciBmb3JtYXR0ZWRBcmdzO1xuXG4gICAgICAgIGlmICghdGhpcy5hcmdzKSB7XG4gICAgICAgICAgICByZXR1cm4gXCI6KFwiO1xuICAgICAgICB9XG5cbiAgICAgICAgZm9ybWF0dGVkQXJncyA9IHNsaWNlLmNhbGwodGhpcy5hcmdzKS5tYXAoZnVuY3Rpb24gKGFyZykge1xuICAgICAgICAgICAgcmV0dXJuIHNpbm9uRm9ybWF0KGFyZyk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNhbGxTdHIgPSBjYWxsU3RyICsgZm9ybWF0dGVkQXJncy5qb2luKFwiLCBcIikgKyBcIilcIjtcblxuICAgICAgICBpZiAodHlwZW9mIHRoaXMucmV0dXJuVmFsdWUgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICAgIGNhbGxTdHIgKz0gXCIgPT4gXCIgKyBzaW5vbkZvcm1hdCh0aGlzLnJldHVyblZhbHVlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLmV4Y2VwdGlvbikge1xuICAgICAgICAgICAgY2FsbFN0ciArPSBcIiAhXCIgKyB0aGlzLmV4Y2VwdGlvbi5uYW1lO1xuXG4gICAgICAgICAgICBpZiAodGhpcy5leGNlcHRpb24ubWVzc2FnZSkge1xuICAgICAgICAgICAgICAgIGNhbGxTdHIgKz0gXCIoXCIgKyB0aGlzLmV4Y2VwdGlvbi5tZXNzYWdlICsgXCIpXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuc3RhY2spIHtcbiAgICAgICAgICAgIC8vIE9taXQgdGhlIGVycm9yIG1lc3NhZ2UgYW5kIHRoZSB0d28gdG9wIHN0YWNrIGZyYW1lcyBpbiBzaW5vbiBpdHNlbGY6XG4gICAgICAgICAgICBjYWxsU3RyICs9IHRoaXMuc3RhY2suc3BsaXQoXCJcXG5cIilbM10ucmVwbGFjZSgvXlxccyooPzphdFxccyt8QCk/LywgXCIgYXQgXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGNhbGxTdHI7XG4gICAgfVxufTtcbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShjYWxsUHJvdG8sIFwic3RhY2tcIiwge1xuICAgIGVudW1lcmFibGU6IHRydWUsXG4gICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgIGdldDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5lcnJvcldpdGhDYWxsU3RhY2sgJiYgdGhpcy5lcnJvcldpdGhDYWxsU3RhY2suc3RhY2sgfHwgXCJcIjtcbiAgICB9XG59KTtcblxuY2FsbFByb3RvLmludm9rZUNhbGxiYWNrID0gY2FsbFByb3RvLnlpZWxkO1xuXG5mdW5jdGlvbiBjcmVhdGVTcHlDYWxsKHNweSwgdGhpc1ZhbHVlLCBhcmdzLCByZXR1cm5WYWx1ZSwgZXhjZXB0aW9uLCBpZCwgZXJyb3JXaXRoQ2FsbFN0YWNrKSB7XG4gICAgaWYgKHR5cGVvZiBpZCAhPT0gXCJudW1iZXJcIikge1xuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiQ2FsbCBpZCBpcyBub3QgYSBudW1iZXJcIik7XG4gICAgfVxuICAgIHZhciBwcm94eUNhbGwgPSBPYmplY3QuY3JlYXRlKGNhbGxQcm90byk7XG4gICAgcHJveHlDYWxsLnByb3h5ID0gc3B5O1xuICAgIHByb3h5Q2FsbC50aGlzVmFsdWUgPSB0aGlzVmFsdWU7XG4gICAgcHJveHlDYWxsLmFyZ3MgPSBhcmdzO1xuICAgIHByb3h5Q2FsbC5yZXR1cm5WYWx1ZSA9IHJldHVyblZhbHVlO1xuICAgIHByb3h5Q2FsbC5leGNlcHRpb24gPSBleGNlcHRpb247XG4gICAgcHJveHlDYWxsLmNhbGxJZCA9IGlkO1xuICAgIHByb3h5Q2FsbC5lcnJvcldpdGhDYWxsU3RhY2sgPSBlcnJvcldpdGhDYWxsU3RhY2s7XG5cbiAgICByZXR1cm4gcHJveHlDYWxsO1xufVxuY3JlYXRlU3B5Q2FsbC50b1N0cmluZyA9IGNhbGxQcm90by50b1N0cmluZzsgLy8gdXNlZCBieSBtb2Nrc1xuXG5tb2R1bGUuZXhwb3J0cyA9IGNyZWF0ZVNweUNhbGw7XG4iLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIHdhbGsgPSByZXF1aXJlKFwiLi91dGlsL2NvcmUvd2Fsa1wiKTtcbnZhciBnZXRQcm9wZXJ0eURlc2NyaXB0b3IgPSByZXF1aXJlKFwiLi91dGlsL2NvcmUvZ2V0LXByb3BlcnR5LWRlc2NyaXB0b3JcIik7XG5cbmZ1bmN0aW9uIGNvbGxlY3RNZXRob2QobWV0aG9kcywgb2JqZWN0LCBwcm9wLCBwcm9wT3duZXIpIHtcbiAgICBpZiAoXG4gICAgICAgIHR5cGVvZiBnZXRQcm9wZXJ0eURlc2NyaXB0b3IocHJvcE93bmVyLCBwcm9wKS52YWx1ZSA9PT0gXCJmdW5jdGlvblwiICYmXG4gICAgICAgIG9iamVjdC5oYXNPd25Qcm9wZXJ0eShwcm9wKVxuICAgICkge1xuICAgICAgICBtZXRob2RzLnB1c2gob2JqZWN0W3Byb3BdKTtcbiAgICB9XG59XG5cbi8vIFRoaXMgZnVuY3Rpb24gcmV0dXJucyBhbiBhcnJheSBvZiBhbGwgdGhlIG93biBtZXRob2RzIG9uIHRoZSBwYXNzZWQgb2JqZWN0XG5mdW5jdGlvbiBjb2xsZWN0T3duTWV0aG9kcyhvYmplY3QpIHtcbiAgICB2YXIgbWV0aG9kcyA9IFtdO1xuXG4gICAgd2FsayhvYmplY3QsIGNvbGxlY3RNZXRob2QuYmluZChudWxsLCBtZXRob2RzLCBvYmplY3QpKTtcblxuICAgIHJldHVybiBtZXRob2RzO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGNvbGxlY3RPd25NZXRob2RzO1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBzaW5vblNweSA9IHJlcXVpcmUoXCIuL3NweVwiKTtcbnZhciBzaW5vblN0dWIgPSByZXF1aXJlKFwiLi9zdHViXCIpO1xudmFyIHNpbm9uTW9jayA9IHJlcXVpcmUoXCIuL21vY2tcIik7XG52YXIgdGhyb3dPbkZhbHN5T2JqZWN0ID0gcmVxdWlyZShcIi4vdGhyb3ctb24tZmFsc3ktb2JqZWN0XCIpO1xudmFyIGNvbGxlY3RPd25NZXRob2RzID0gcmVxdWlyZShcIi4vY29sbGVjdC1vd24tbWV0aG9kc1wiKTtcbnZhciBzdHViTm9uRnVuY3Rpb25Qcm9wZXJ0eSA9IHJlcXVpcmUoXCIuL3N0dWItbm9uLWZ1bmN0aW9uLXByb3BlcnR5XCIpO1xuXG52YXIgcHVzaCA9IFtdLnB1c2g7XG5cbmZ1bmN0aW9uIGdldEZha2VzKGZha2VDb2xsZWN0aW9uKSB7XG4gICAgaWYgKCFmYWtlQ29sbGVjdGlvbi5mYWtlcykge1xuICAgICAgICBmYWtlQ29sbGVjdGlvbi5mYWtlcyA9IFtdO1xuICAgIH1cblxuICAgIHJldHVybiBmYWtlQ29sbGVjdGlvbi5mYWtlcztcbn1cblxuZnVuY3Rpb24gZWFjaChmYWtlQ29sbGVjdGlvbiwgbWV0aG9kKSB7XG4gICAgdmFyIGZha2VzID0gZ2V0RmFrZXMoZmFrZUNvbGxlY3Rpb24pO1xuICAgIHZhciBtYXRjaGluZ0Zha2VzID0gZmFrZXMuZmlsdGVyKGZ1bmN0aW9uIChmYWtlKSB7XG4gICAgICAgIHJldHVybiB0eXBlb2YgZmFrZVttZXRob2RdID09PSBcImZ1bmN0aW9uXCI7XG4gICAgfSk7XG5cbiAgICBtYXRjaGluZ0Zha2VzLmZvckVhY2goZnVuY3Rpb24gKGZha2UpIHtcbiAgICAgICAgZmFrZVttZXRob2RdKCk7XG4gICAgfSk7XG59XG5cbnZhciBjb2xsZWN0aW9uID0ge1xuICAgIHZlcmlmeTogZnVuY3Rpb24gdmVyaWZ5KCkge1xuICAgICAgICBlYWNoKHRoaXMsIFwidmVyaWZ5XCIpO1xuICAgIH0sXG5cbiAgICByZXN0b3JlOiBmdW5jdGlvbiByZXN0b3JlKCkge1xuICAgICAgICBlYWNoKHRoaXMsIFwicmVzdG9yZVwiKTtcbiAgICAgICAgdGhpcy5mYWtlcyA9IFtdO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gcmVzZXQoKSB7XG4gICAgICAgIGVhY2godGhpcywgXCJyZXNldFwiKTtcbiAgICB9LFxuXG4gICAgcmVzZXRCZWhhdmlvcjogZnVuY3Rpb24gcmVzZXRCZWhhdmlvcigpIHtcbiAgICAgICAgZWFjaCh0aGlzLCBcInJlc2V0QmVoYXZpb3JcIik7XG4gICAgfSxcblxuICAgIHJlc2V0SGlzdG9yeTogZnVuY3Rpb24gcmVzZXRIaXN0b3J5KCkge1xuICAgICAgICBlYWNoKHRoaXMsIFwicmVzZXRIaXN0b3J5XCIpO1xuICAgIH0sXG5cbiAgICB2ZXJpZnlBbmRSZXN0b3JlOiBmdW5jdGlvbiB2ZXJpZnlBbmRSZXN0b3JlKCkge1xuICAgICAgICB2YXIgZXhjZXB0aW9uO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICB0aGlzLnZlcmlmeSgpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBleGNlcHRpb24gPSBlO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5yZXN0b3JlKCk7XG5cbiAgICAgICAgaWYgKGV4Y2VwdGlvbikge1xuICAgICAgICAgICAgdGhyb3cgZXhjZXB0aW9uO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIGFkZDogZnVuY3Rpb24gYWRkKGZha2UpIHtcbiAgICAgICAgcHVzaC5jYWxsKGdldEZha2VzKHRoaXMpLCBmYWtlKTtcbiAgICAgICAgcmV0dXJuIGZha2U7XG4gICAgfSxcblxuICAgIHNweTogZnVuY3Rpb24gc3B5KCkge1xuICAgICAgICByZXR1cm4gdGhpcy5hZGQoc2lub25TcHkuYXBwbHkoc2lub25TcHksIGFyZ3VtZW50cykpO1xuICAgIH0sXG5cbiAgICBzdHViOiBmdW5jdGlvbiBzdHViKG9iamVjdCwgcHJvcGVydHkvKiwgdmFsdWUqLykge1xuICAgICAgICB0aHJvd09uRmFsc3lPYmplY3QuYXBwbHkobnVsbCwgYXJndW1lbnRzKTtcblxuICAgICAgICB2YXIgaXNTdHViYmluZ0VudGlyZU9iamVjdCA9IHR5cGVvZiBwcm9wZXJ0eSA9PT0gXCJ1bmRlZmluZWRcIiAmJiB0eXBlb2Ygb2JqZWN0ID09PSBcIm9iamVjdFwiO1xuICAgICAgICB2YXIgaXNTdHViYmluZ05vbkZ1bmN0aW9uUHJvcGVydHkgPSBwcm9wZXJ0eSAmJiB0eXBlb2Ygb2JqZWN0W3Byb3BlcnR5XSAhPT0gXCJmdW5jdGlvblwiO1xuICAgICAgICB2YXIgc3R1YmJlZCA9IGlzU3R1YmJpbmdOb25GdW5jdGlvblByb3BlcnR5ID9cbiAgICAgICAgICAgICAgICAgICAgICAgIHN0dWJOb25GdW5jdGlvblByb3BlcnR5LmFwcGx5KG51bGwsIGFyZ3VtZW50cykgOlxuICAgICAgICAgICAgICAgICAgICAgICAgc2lub25TdHViLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7XG5cbiAgICAgICAgaWYgKGlzU3R1YmJpbmdFbnRpcmVPYmplY3QpIHtcbiAgICAgICAgICAgIGNvbGxlY3RPd25NZXRob2RzKHN0dWJiZWQpLmZvckVhY2godGhpcy5hZGQuYmluZCh0aGlzKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmFkZChzdHViYmVkKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBzdHViYmVkO1xuICAgIH0sXG5cbiAgICBtb2NrOiBmdW5jdGlvbiBtb2NrKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5hZGQoc2lub25Nb2NrLmFwcGx5KG51bGwsIGFyZ3VtZW50cykpO1xuICAgIH0sXG5cbiAgICBpbmplY3Q6IGZ1bmN0aW9uIGluamVjdChvYmopIHtcbiAgICAgICAgdmFyIGNvbCA9IHRoaXM7XG5cbiAgICAgICAgb2JqLnNweSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb2wuc3B5LmFwcGx5KGNvbCwgYXJndW1lbnRzKTtcbiAgICAgICAgfTtcblxuICAgICAgICBvYmouc3R1YiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBjb2wuc3R1Yi5hcHBseShjb2wsIGFyZ3VtZW50cyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgb2JqLm1vY2sgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY29sLm1vY2suYXBwbHkoY29sLCBhcmd1bWVudHMpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiBvYmo7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBjb2xsZWN0aW9uO1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBjYW5Db2xvciA9IHR5cGVvZiBwcm9jZXNzICE9PSBcInVuZGVmaW5lZFwiO1xuXG5mdW5jdGlvbiBjb2xvcml6ZShzdHIsIGNvbG9yKSB7XG4gICAgaWYgKCFjYW5Db2xvcikge1xuICAgICAgICByZXR1cm4gc3RyO1xuICAgIH1cblxuICAgIHJldHVybiBcIlxceDFiW1wiICsgY29sb3IgKyBcIm1cIiArIHN0ciArIFwiXFx4MWJbMG1cIjtcbn1cblxuZXhwb3J0cy5yZWQgPSBmdW5jdGlvbiAoc3RyKSB7XG4gICAgcmV0dXJuIGNvbG9yaXplKHN0ciwgMzEpO1xufTtcblxuZXhwb3J0cy5ncmVlbiA9IGZ1bmN0aW9uIChzdHIpIHtcbiAgICByZXR1cm4gY29sb3JpemUoc3RyLCAzMik7XG59O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBzbGljZSA9IFtdLnNsaWNlO1xudmFyIHVzZUxlZnRNb3N0Q2FsbGJhY2sgPSAtMTtcbnZhciB1c2VSaWdodE1vc3RDYWxsYmFjayA9IC0yO1xuXG5mdW5jdGlvbiB0aHJvd3NFeGNlcHRpb24oZmFrZSwgZXJyb3IsIG1lc3NhZ2UpIHtcbiAgICBpZiAodHlwZW9mIGVycm9yID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIGZha2UuZXhjZXB0aW9uID0gbmV3IEVycm9yKG1lc3NhZ2UgfHwgXCJcIik7XG4gICAgICAgIGZha2UuZXhjZXB0aW9uLm5hbWUgPSBlcnJvcjtcbiAgICB9IGVsc2UgaWYgKCFlcnJvcikge1xuICAgICAgICBmYWtlLmV4Y2VwdGlvbiA9IG5ldyBFcnJvcihcIkVycm9yXCIpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGZha2UuZXhjZXB0aW9uID0gZXJyb3I7XG4gICAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBjYWxsc0Zha2U6IGZ1bmN0aW9uIGNhbGxzRmFrZShmYWtlLCBmbikge1xuICAgICAgICBmYWtlLmZha2VGbiA9IGZuO1xuICAgIH0sXG5cbiAgICBjYWxsc0FyZzogZnVuY3Rpb24gY2FsbHNBcmcoZmFrZSwgcG9zKSB7XG4gICAgICAgIGlmICh0eXBlb2YgcG9zICE9PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiYXJndW1lbnQgaW5kZXggaXMgbm90IG51bWJlclwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZha2UuY2FsbEFyZ0F0ID0gcG9zO1xuICAgICAgICBmYWtlLmNhbGxiYWNrQXJndW1lbnRzID0gW107XG4gICAgICAgIGZha2UuY2FsbGJhY2tDb250ZXh0ID0gdW5kZWZpbmVkO1xuICAgICAgICBmYWtlLmNhbGxBcmdQcm9wID0gdW5kZWZpbmVkO1xuICAgICAgICBmYWtlLmNhbGxiYWNrQXN5bmMgPSBmYWxzZTtcbiAgICB9LFxuXG4gICAgY2FsbHNBcmdPbjogZnVuY3Rpb24gY2FsbHNBcmdPbihmYWtlLCBwb3MsIGNvbnRleHQpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBwb3MgIT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJhcmd1bWVudCBpbmRleCBpcyBub3QgbnVtYmVyXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgZmFrZS5jYWxsQXJnQXQgPSBwb3M7XG4gICAgICAgIGZha2UuY2FsbGJhY2tBcmd1bWVudHMgPSBbXTtcbiAgICAgICAgZmFrZS5jYWxsYmFja0NvbnRleHQgPSBjb250ZXh0O1xuICAgICAgICBmYWtlLmNhbGxBcmdQcm9wID0gdW5kZWZpbmVkO1xuICAgICAgICBmYWtlLmNhbGxiYWNrQXN5bmMgPSBmYWxzZTtcbiAgICB9LFxuXG4gICAgY2FsbHNBcmdXaXRoOiBmdW5jdGlvbiBjYWxsc0FyZ1dpdGgoZmFrZSwgcG9zKSB7XG4gICAgICAgIGlmICh0eXBlb2YgcG9zICE9PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiYXJndW1lbnQgaW5kZXggaXMgbm90IG51bWJlclwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZha2UuY2FsbEFyZ0F0ID0gcG9zO1xuICAgICAgICBmYWtlLmNhbGxiYWNrQXJndW1lbnRzID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDIpO1xuICAgICAgICBmYWtlLmNhbGxiYWNrQ29udGV4dCA9IHVuZGVmaW5lZDtcbiAgICAgICAgZmFrZS5jYWxsQXJnUHJvcCA9IHVuZGVmaW5lZDtcbiAgICAgICAgZmFrZS5jYWxsYmFja0FzeW5jID0gZmFsc2U7XG4gICAgfSxcblxuICAgIGNhbGxzQXJnT25XaXRoOiBmdW5jdGlvbiBjYWxsc0FyZ1dpdGgoZmFrZSwgcG9zLCBjb250ZXh0KSB7XG4gICAgICAgIGlmICh0eXBlb2YgcG9zICE9PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiYXJndW1lbnQgaW5kZXggaXMgbm90IG51bWJlclwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZha2UuY2FsbEFyZ0F0ID0gcG9zO1xuICAgICAgICBmYWtlLmNhbGxiYWNrQXJndW1lbnRzID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDMpO1xuICAgICAgICBmYWtlLmNhbGxiYWNrQ29udGV4dCA9IGNvbnRleHQ7XG4gICAgICAgIGZha2UuY2FsbEFyZ1Byb3AgPSB1bmRlZmluZWQ7XG4gICAgICAgIGZha2UuY2FsbGJhY2tBc3luYyA9IGZhbHNlO1xuICAgIH0sXG5cbiAgICB5aWVsZHM6IGZ1bmN0aW9uIChmYWtlKSB7XG4gICAgICAgIGZha2UuY2FsbEFyZ0F0ID0gdXNlTGVmdE1vc3RDYWxsYmFjaztcbiAgICAgICAgZmFrZS5jYWxsYmFja0FyZ3VtZW50cyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICAgICAgZmFrZS5jYWxsYmFja0NvbnRleHQgPSB1bmRlZmluZWQ7XG4gICAgICAgIGZha2UuY2FsbEFyZ1Byb3AgPSB1bmRlZmluZWQ7XG4gICAgICAgIGZha2UuY2FsbGJhY2tBc3luYyA9IGZhbHNlO1xuICAgIH0sXG5cbiAgICB5aWVsZHNSaWdodDogZnVuY3Rpb24gKGZha2UpIHtcbiAgICAgICAgZmFrZS5jYWxsQXJnQXQgPSB1c2VSaWdodE1vc3RDYWxsYmFjaztcbiAgICAgICAgZmFrZS5jYWxsYmFja0FyZ3VtZW50cyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICAgICAgZmFrZS5jYWxsYmFja0NvbnRleHQgPSB1bmRlZmluZWQ7XG4gICAgICAgIGZha2UuY2FsbEFyZ1Byb3AgPSB1bmRlZmluZWQ7XG4gICAgICAgIGZha2UuY2FsbGJhY2tBc3luYyA9IGZhbHNlO1xuICAgIH0sXG5cbiAgICB5aWVsZHNPbjogZnVuY3Rpb24gKGZha2UsIGNvbnRleHQpIHtcbiAgICAgICAgZmFrZS5jYWxsQXJnQXQgPSB1c2VMZWZ0TW9zdENhbGxiYWNrO1xuICAgICAgICBmYWtlLmNhbGxiYWNrQXJndW1lbnRzID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDIpO1xuICAgICAgICBmYWtlLmNhbGxiYWNrQ29udGV4dCA9IGNvbnRleHQ7XG4gICAgICAgIGZha2UuY2FsbEFyZ1Byb3AgPSB1bmRlZmluZWQ7XG4gICAgICAgIGZha2UuY2FsbGJhY2tBc3luYyA9IGZhbHNlO1xuICAgIH0sXG5cbiAgICB5aWVsZHNUbzogZnVuY3Rpb24gKGZha2UsIHByb3ApIHtcbiAgICAgICAgZmFrZS5jYWxsQXJnQXQgPSB1c2VMZWZ0TW9zdENhbGxiYWNrO1xuICAgICAgICBmYWtlLmNhbGxiYWNrQXJndW1lbnRzID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDIpO1xuICAgICAgICBmYWtlLmNhbGxiYWNrQ29udGV4dCA9IHVuZGVmaW5lZDtcbiAgICAgICAgZmFrZS5jYWxsQXJnUHJvcCA9IHByb3A7XG4gICAgICAgIGZha2UuY2FsbGJhY2tBc3luYyA9IGZhbHNlO1xuICAgIH0sXG5cbiAgICB5aWVsZHNUb09uOiBmdW5jdGlvbiAoZmFrZSwgcHJvcCwgY29udGV4dCkge1xuICAgICAgICBmYWtlLmNhbGxBcmdBdCA9IHVzZUxlZnRNb3N0Q2FsbGJhY2s7XG4gICAgICAgIGZha2UuY2FsbGJhY2tBcmd1bWVudHMgPSBzbGljZS5jYWxsKGFyZ3VtZW50cywgMyk7XG4gICAgICAgIGZha2UuY2FsbGJhY2tDb250ZXh0ID0gY29udGV4dDtcbiAgICAgICAgZmFrZS5jYWxsQXJnUHJvcCA9IHByb3A7XG4gICAgICAgIGZha2UuY2FsbGJhY2tBc3luYyA9IGZhbHNlO1xuICAgIH0sXG5cbiAgICB0aHJvd3M6IHRocm93c0V4Y2VwdGlvbixcbiAgICB0aHJvd3NFeGNlcHRpb246IHRocm93c0V4Y2VwdGlvbixcblxuICAgIHJldHVybnM6IGZ1bmN0aW9uIHJldHVybnMoZmFrZSwgdmFsdWUpIHtcbiAgICAgICAgZmFrZS5yZXR1cm5WYWx1ZSA9IHZhbHVlO1xuICAgICAgICBmYWtlLnJlc29sdmUgPSBmYWxzZTtcbiAgICAgICAgZmFrZS5yZWplY3QgPSBmYWxzZTtcbiAgICAgICAgZmFrZS5yZXR1cm5WYWx1ZURlZmluZWQgPSB0cnVlO1xuICAgICAgICBmYWtlLmV4Y2VwdGlvbiA9IHVuZGVmaW5lZDtcbiAgICAgICAgZmFrZS5mYWtlRm4gPSB1bmRlZmluZWQ7XG4gICAgfSxcblxuICAgIHJldHVybnNBcmc6IGZ1bmN0aW9uIHJldHVybnNBcmcoZmFrZSwgcG9zKSB7XG4gICAgICAgIGlmICh0eXBlb2YgcG9zICE9PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiYXJndW1lbnQgaW5kZXggaXMgbm90IG51bWJlclwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZha2UucmV0dXJuQXJnQXQgPSBwb3M7XG4gICAgfSxcblxuICAgIHJldHVybnNUaGlzOiBmdW5jdGlvbiByZXR1cm5zVGhpcyhmYWtlKSB7XG4gICAgICAgIGZha2UucmV0dXJuVGhpcyA9IHRydWU7XG4gICAgfSxcblxuICAgIHJlc29sdmVzOiBmdW5jdGlvbiByZXNvbHZlcyhmYWtlLCB2YWx1ZSkge1xuICAgICAgICBmYWtlLnJldHVyblZhbHVlID0gdmFsdWU7XG4gICAgICAgIGZha2UucmVzb2x2ZSA9IHRydWU7XG4gICAgICAgIGZha2UucmVqZWN0ID0gZmFsc2U7XG4gICAgICAgIGZha2UucmV0dXJuVmFsdWVEZWZpbmVkID0gdHJ1ZTtcbiAgICAgICAgZmFrZS5leGNlcHRpb24gPSB1bmRlZmluZWQ7XG4gICAgICAgIGZha2UuZmFrZUZuID0gdW5kZWZpbmVkO1xuICAgIH0sXG5cbiAgICByZWplY3RzOiBmdW5jdGlvbiByZWplY3RzKGZha2UsIGVycm9yLCBtZXNzYWdlKSB7XG4gICAgICAgIHZhciByZWFzb247XG4gICAgICAgIGlmICh0eXBlb2YgZXJyb3IgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgIHJlYXNvbiA9IG5ldyBFcnJvcihtZXNzYWdlIHx8IFwiXCIpO1xuICAgICAgICAgICAgcmVhc29uLm5hbWUgPSBlcnJvcjtcbiAgICAgICAgfSBlbHNlIGlmICghZXJyb3IpIHtcbiAgICAgICAgICAgIHJlYXNvbiA9IG5ldyBFcnJvcihcIkVycm9yXCIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmVhc29uID0gZXJyb3I7XG4gICAgICAgIH1cbiAgICAgICAgZmFrZS5yZXR1cm5WYWx1ZSA9IHJlYXNvbjtcbiAgICAgICAgZmFrZS5yZXNvbHZlID0gZmFsc2U7XG4gICAgICAgIGZha2UucmVqZWN0ID0gdHJ1ZTtcbiAgICAgICAgZmFrZS5yZXR1cm5WYWx1ZURlZmluZWQgPSB0cnVlO1xuICAgICAgICBmYWtlLmV4Y2VwdGlvbiA9IHVuZGVmaW5lZDtcbiAgICAgICAgZmFrZS5mYWtlRm4gPSB1bmRlZmluZWQ7XG5cbiAgICAgICAgcmV0dXJuIGZha2U7XG4gICAgfSxcblxuICAgIGNhbGxUaHJvdWdoOiBmdW5jdGlvbiBjYWxsVGhyb3VnaChmYWtlKSB7XG4gICAgICAgIGZha2UuY2FsbHNUaHJvdWdoID0gdHJ1ZTtcbiAgICB9LFxuXG4gICAgZ2V0OiBmdW5jdGlvbiBnZXQoZmFrZSwgZ2V0dGVyRnVuY3Rpb24pIHtcbiAgICAgICAgdmFyIHJvb3RTdHViID0gZmFrZS5zdHViIHx8IGZha2U7XG5cbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHJvb3RTdHViLnJvb3RPYmosIHJvb3RTdHViLnByb3BOYW1lLCB7XG4gICAgICAgICAgICBnZXQ6IGdldHRlckZ1bmN0aW9uXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBmYWtlO1xuICAgIH0sXG5cbiAgICBzZXQ6IGZ1bmN0aW9uIHNldChmYWtlLCBzZXR0ZXJGdW5jdGlvbikge1xuICAgICAgICB2YXIgcm9vdFN0dWIgPSBmYWtlLnN0dWIgfHwgZmFrZTtcblxuICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkocm9vdFN0dWIucm9vdE9iaiwgcm9vdFN0dWIucHJvcE5hbWUsIHsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBhY2Nlc3Nvci1wYWlyc1xuICAgICAgICAgICAgc2V0OiBzZXR0ZXJGdW5jdGlvblxuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gZmFrZTtcbiAgICB9XG59O1xuXG5mdW5jdGlvbiBjcmVhdGVBc3luY1ZlcnNpb24oc3luY0ZuTmFtZSkge1xuICAgIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSBtb2R1bGUuZXhwb3J0c1tzeW5jRm5OYW1lXS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICB0aGlzLmNhbGxiYWNrQXN5bmMgPSB0cnVlO1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH07XG59XG5cbi8vIGNyZWF0ZSBhc3luY2hyb25vdXMgdmVyc2lvbnMgb2YgY2FsbHNBcmcqIGFuZCB5aWVsZHMqIG1ldGhvZHNcbk9iamVjdC5rZXlzKG1vZHVsZS5leHBvcnRzKS5mb3JFYWNoKGZ1bmN0aW9uIChtZXRob2QpIHtcbiAgICAvLyBuZWVkIHRvIGF2b2lkIGNyZWF0aW5nIGFub3RoZXJhc3luYyB2ZXJzaW9ucyBvZiB0aGUgbmV3bHkgYWRkZWQgYXN5bmMgbWV0aG9kc1xuICAgIGlmIChtZXRob2QubWF0Y2goL14oY2FsbHNBcmd8eWllbGRzKS8pICYmICFtZXRob2QubWF0Y2goL0FzeW5jLykpIHtcbiAgICAgICAgbW9kdWxlLmV4cG9ydHNbbWV0aG9kICsgXCJBc3luY1wiXSA9IGNyZWF0ZUFzeW5jVmVyc2lvbihtZXRob2QpO1xuICAgIH1cbn0pO1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBkZWVwRXF1YWwgPSByZXF1aXJlKFwiLi91dGlsL2NvcmUvZGVlcC1lcXVhbFwiKS51c2UobWF0Y2gpOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVzZS1iZWZvcmUtZGVmaW5lXG52YXIgZXZlcnkgPSByZXF1aXJlKFwiLi91dGlsL2NvcmUvZXZlcnlcIik7XG52YXIgZnVuY3Rpb25OYW1lID0gcmVxdWlyZShcIi4vdXRpbC9jb3JlL2Z1bmN0aW9uLW5hbWVcIik7XG52YXIgaXRlcmFibGVUb1N0cmluZyA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS9pdGVyYWJsZS10by1zdHJpbmdcIik7XG52YXIgdHlwZU9mID0gcmVxdWlyZShcIi4vdXRpbC9jb3JlL3R5cGVPZlwiKTtcbnZhciB2YWx1ZVRvU3RyaW5nID0gcmVxdWlyZShcIi4vdXRpbC9jb3JlL3ZhbHVlLXRvLXN0cmluZ1wiKTtcblxudmFyIGluZGV4T2YgPSBBcnJheS5wcm90b3R5cGUuaW5kZXhPZjtcblxuZnVuY3Rpb24gYXNzZXJ0VHlwZSh2YWx1ZSwgdHlwZSwgbmFtZSkge1xuICAgIHZhciBhY3R1YWwgPSB0eXBlT2YodmFsdWUpO1xuICAgIGlmIChhY3R1YWwgIT09IHR5cGUpIHtcbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkV4cGVjdGVkIHR5cGUgb2YgXCIgKyBuYW1lICsgXCIgdG8gYmUgXCIgK1xuICAgICAgICAgICAgdHlwZSArIFwiLCBidXQgd2FzIFwiICsgYWN0dWFsKTtcbiAgICB9XG59XG5cbnZhciBtYXRjaGVyID0ge1xuICAgIHRvU3RyaW5nOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm1lc3NhZ2U7XG4gICAgfVxufTtcblxuZnVuY3Rpb24gaXNNYXRjaGVyKG9iamVjdCkge1xuICAgIHJldHVybiBtYXRjaGVyLmlzUHJvdG90eXBlT2Yob2JqZWN0KTtcbn1cblxuZnVuY3Rpb24gbWF0Y2hPYmplY3QoZXhwZWN0YXRpb24sIGFjdHVhbCkge1xuICAgIGlmIChhY3R1YWwgPT09IG51bGwgfHwgYWN0dWFsID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIHJldHVybiBPYmplY3Qua2V5cyhleHBlY3RhdGlvbikuZXZlcnkoZnVuY3Rpb24gKGtleSkge1xuICAgICAgICB2YXIgZXhwID0gZXhwZWN0YXRpb25ba2V5XTtcbiAgICAgICAgdmFyIGFjdCA9IGFjdHVhbFtrZXldO1xuXG4gICAgICAgIGlmIChpc01hdGNoZXIoZXhwKSkge1xuICAgICAgICAgICAgaWYgKCFleHAudGVzdChhY3QpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKHR5cGVPZihleHApID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICBpZiAoIW1hdGNoT2JqZWN0KGV4cCwgYWN0KSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmICghZGVlcEVxdWFsKGV4cCwgYWN0KSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSk7XG59XG5cbnZhciBUWVBFX01BUCA9IHtcbiAgICBcImZ1bmN0aW9uXCI6IGZ1bmN0aW9uIChtLCBleHBlY3RhdGlvbiwgbWVzc2FnZSkge1xuICAgICAgICBtLnRlc3QgPSBleHBlY3RhdGlvbjtcbiAgICAgICAgbS5tZXNzYWdlID0gbWVzc2FnZSB8fCBcIm1hdGNoKFwiICsgZnVuY3Rpb25OYW1lKGV4cGVjdGF0aW9uKSArIFwiKVwiO1xuICAgIH0sXG4gICAgbnVtYmVyOiBmdW5jdGlvbiAobSwgZXhwZWN0YXRpb24pIHtcbiAgICAgICAgbS50ZXN0ID0gZnVuY3Rpb24gKGFjdHVhbCkge1xuICAgICAgICAgICAgLy8gd2UgbmVlZCB0eXBlIGNvZXJjaW9uIGhlcmVcbiAgICAgICAgICAgIHJldHVybiBleHBlY3RhdGlvbiA9PSBhY3R1YWw7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgZXFlcWVxXG4gICAgICAgIH07XG4gICAgfSxcbiAgICBvYmplY3Q6IGZ1bmN0aW9uIChtLCBleHBlY3RhdGlvbikge1xuICAgICAgICB2YXIgYXJyYXkgPSBbXTtcblxuICAgICAgICBpZiAodHlwZW9mIGV4cGVjdGF0aW9uLnRlc3QgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgbS50ZXN0ID0gZnVuY3Rpb24gKGFjdHVhbCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBleHBlY3RhdGlvbi50ZXN0KGFjdHVhbCkgPT09IHRydWU7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgbS5tZXNzYWdlID0gXCJtYXRjaChcIiArIGZ1bmN0aW9uTmFtZShleHBlY3RhdGlvbi50ZXN0KSArIFwiKVwiO1xuICAgICAgICAgICAgcmV0dXJuIG07XG4gICAgICAgIH1cblxuICAgICAgICBhcnJheSA9IE9iamVjdC5rZXlzKGV4cGVjdGF0aW9uKS5tYXAoZnVuY3Rpb24gKGtleSkge1xuICAgICAgICAgICAgcmV0dXJuIGtleSArIFwiOiBcIiArIHZhbHVlVG9TdHJpbmcoZXhwZWN0YXRpb25ba2V5XSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIG0udGVzdCA9IGZ1bmN0aW9uIChhY3R1YWwpIHtcbiAgICAgICAgICAgIHJldHVybiBtYXRjaE9iamVjdChleHBlY3RhdGlvbiwgYWN0dWFsKTtcbiAgICAgICAgfTtcbiAgICAgICAgbS5tZXNzYWdlID0gXCJtYXRjaChcIiArIGFycmF5LmpvaW4oXCIsIFwiKSArIFwiKVwiO1xuXG4gICAgICAgIHJldHVybiBtO1xuICAgIH0sXG4gICAgcmVnZXhwOiBmdW5jdGlvbiAobSwgZXhwZWN0YXRpb24pIHtcbiAgICAgICAgbS50ZXN0ID0gZnVuY3Rpb24gKGFjdHVhbCkge1xuICAgICAgICAgICAgcmV0dXJuIHR5cGVvZiBhY3R1YWwgPT09IFwic3RyaW5nXCIgJiYgZXhwZWN0YXRpb24udGVzdChhY3R1YWwpO1xuICAgICAgICB9O1xuICAgIH0sXG4gICAgc3RyaW5nOiBmdW5jdGlvbiAobSwgZXhwZWN0YXRpb24pIHtcbiAgICAgICAgbS50ZXN0ID0gZnVuY3Rpb24gKGFjdHVhbCkge1xuICAgICAgICAgICAgcmV0dXJuIHR5cGVvZiBhY3R1YWwgPT09IFwic3RyaW5nXCIgJiYgYWN0dWFsLmluZGV4T2YoZXhwZWN0YXRpb24pICE9PSAtMTtcbiAgICAgICAgfTtcbiAgICAgICAgbS5tZXNzYWdlID0gXCJtYXRjaChcXFwiXCIgKyBleHBlY3RhdGlvbiArIFwiXFxcIilcIjtcbiAgICB9XG59O1xuXG5mdW5jdGlvbiBtYXRjaChleHBlY3RhdGlvbiwgbWVzc2FnZSkge1xuICAgIHZhciBtID0gT2JqZWN0LmNyZWF0ZShtYXRjaGVyKTtcbiAgICB2YXIgdHlwZSA9IHR5cGVPZihleHBlY3RhdGlvbik7XG5cbiAgICBpZiAodHlwZSBpbiBUWVBFX01BUCkge1xuICAgICAgICBUWVBFX01BUFt0eXBlXShtLCBleHBlY3RhdGlvbiwgbWVzc2FnZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgbS50ZXN0ID0gZnVuY3Rpb24gKGFjdHVhbCkge1xuICAgICAgICAgICAgcmV0dXJuIGRlZXBFcXVhbChleHBlY3RhdGlvbiwgYWN0dWFsKTtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBpZiAoIW0ubWVzc2FnZSkge1xuICAgICAgICBtLm1lc3NhZ2UgPSBcIm1hdGNoKFwiICsgdmFsdWVUb1N0cmluZyhleHBlY3RhdGlvbikgKyBcIilcIjtcbiAgICB9XG5cbiAgICByZXR1cm4gbTtcbn1cblxubWF0Y2hlci5vciA9IGZ1bmN0aW9uIChtMikge1xuICAgIGlmICghYXJndW1lbnRzLmxlbmd0aCkge1xuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiTWF0Y2hlciBleHBlY3RlZFwiKTtcbiAgICB9IGVsc2UgaWYgKCFpc01hdGNoZXIobTIpKSB7XG4gICAgICAgIG0yID0gbWF0Y2gobTIpO1xuICAgIH1cbiAgICB2YXIgbTEgPSB0aGlzO1xuICAgIHZhciBvciA9IE9iamVjdC5jcmVhdGUobWF0Y2hlcik7XG4gICAgb3IudGVzdCA9IGZ1bmN0aW9uIChhY3R1YWwpIHtcbiAgICAgICAgcmV0dXJuIG0xLnRlc3QoYWN0dWFsKSB8fCBtMi50ZXN0KGFjdHVhbCk7XG4gICAgfTtcbiAgICBvci5tZXNzYWdlID0gbTEubWVzc2FnZSArIFwiLm9yKFwiICsgbTIubWVzc2FnZSArIFwiKVwiO1xuICAgIHJldHVybiBvcjtcbn07XG5cbm1hdGNoZXIuYW5kID0gZnVuY3Rpb24gKG0yKSB7XG4gICAgaWYgKCFhcmd1bWVudHMubGVuZ3RoKSB7XG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJNYXRjaGVyIGV4cGVjdGVkXCIpO1xuICAgIH0gZWxzZSBpZiAoIWlzTWF0Y2hlcihtMikpIHtcbiAgICAgICAgbTIgPSBtYXRjaChtMik7XG4gICAgfVxuICAgIHZhciBtMSA9IHRoaXM7XG4gICAgdmFyIGFuZCA9IE9iamVjdC5jcmVhdGUobWF0Y2hlcik7XG4gICAgYW5kLnRlc3QgPSBmdW5jdGlvbiAoYWN0dWFsKSB7XG4gICAgICAgIHJldHVybiBtMS50ZXN0KGFjdHVhbCkgJiYgbTIudGVzdChhY3R1YWwpO1xuICAgIH07XG4gICAgYW5kLm1lc3NhZ2UgPSBtMS5tZXNzYWdlICsgXCIuYW5kKFwiICsgbTIubWVzc2FnZSArIFwiKVwiO1xuICAgIHJldHVybiBhbmQ7XG59O1xuXG5tYXRjaC5pc01hdGNoZXIgPSBpc01hdGNoZXI7XG5cbm1hdGNoLmFueSA9IG1hdGNoKGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbn0sIFwiYW55XCIpO1xuXG5tYXRjaC5kZWZpbmVkID0gbWF0Y2goZnVuY3Rpb24gKGFjdHVhbCkge1xuICAgIHJldHVybiBhY3R1YWwgIT09IG51bGwgJiYgYWN0dWFsICE9PSB1bmRlZmluZWQ7XG59LCBcImRlZmluZWRcIik7XG5cbm1hdGNoLnRydXRoeSA9IG1hdGNoKGZ1bmN0aW9uIChhY3R1YWwpIHtcbiAgICByZXR1cm4gISFhY3R1YWw7XG59LCBcInRydXRoeVwiKTtcblxubWF0Y2guZmFsc3kgPSBtYXRjaChmdW5jdGlvbiAoYWN0dWFsKSB7XG4gICAgcmV0dXJuICFhY3R1YWw7XG59LCBcImZhbHN5XCIpO1xuXG5tYXRjaC5zYW1lID0gZnVuY3Rpb24gKGV4cGVjdGF0aW9uKSB7XG4gICAgcmV0dXJuIG1hdGNoKGZ1bmN0aW9uIChhY3R1YWwpIHtcbiAgICAgICAgcmV0dXJuIGV4cGVjdGF0aW9uID09PSBhY3R1YWw7XG4gICAgfSwgXCJzYW1lKFwiICsgdmFsdWVUb1N0cmluZyhleHBlY3RhdGlvbikgKyBcIilcIik7XG59O1xuXG5tYXRjaC50eXBlT2YgPSBmdW5jdGlvbiAodHlwZSkge1xuICAgIGFzc2VydFR5cGUodHlwZSwgXCJzdHJpbmdcIiwgXCJ0eXBlXCIpO1xuICAgIHJldHVybiBtYXRjaChmdW5jdGlvbiAoYWN0dWFsKSB7XG4gICAgICAgIHJldHVybiB0eXBlT2YoYWN0dWFsKSA9PT0gdHlwZTtcbiAgICB9LCBcInR5cGVPZihcXFwiXCIgKyB0eXBlICsgXCJcXFwiKVwiKTtcbn07XG5cbm1hdGNoLmluc3RhbmNlT2YgPSBmdW5jdGlvbiAodHlwZSkge1xuICAgIGFzc2VydFR5cGUodHlwZSwgXCJmdW5jdGlvblwiLCBcInR5cGVcIik7XG4gICAgcmV0dXJuIG1hdGNoKGZ1bmN0aW9uIChhY3R1YWwpIHtcbiAgICAgICAgcmV0dXJuIGFjdHVhbCBpbnN0YW5jZW9mIHR5cGU7XG4gICAgfSwgXCJpbnN0YW5jZU9mKFwiICsgZnVuY3Rpb25OYW1lKHR5cGUpICsgXCIpXCIpO1xufTtcblxuZnVuY3Rpb24gY3JlYXRlUHJvcGVydHlNYXRjaGVyKHByb3BlcnR5VGVzdCwgbWVzc2FnZVByZWZpeCkge1xuICAgIHJldHVybiBmdW5jdGlvbiAocHJvcGVydHksIHZhbHVlKSB7XG4gICAgICAgIGFzc2VydFR5cGUocHJvcGVydHksIFwic3RyaW5nXCIsIFwicHJvcGVydHlcIik7XG4gICAgICAgIHZhciBvbmx5UHJvcGVydHkgPSBhcmd1bWVudHMubGVuZ3RoID09PSAxO1xuICAgICAgICB2YXIgbWVzc2FnZSA9IG1lc3NhZ2VQcmVmaXggKyBcIihcXFwiXCIgKyBwcm9wZXJ0eSArIFwiXFxcIlwiO1xuICAgICAgICBpZiAoIW9ubHlQcm9wZXJ0eSkge1xuICAgICAgICAgICAgbWVzc2FnZSArPSBcIiwgXCIgKyB2YWx1ZVRvU3RyaW5nKHZhbHVlKTtcbiAgICAgICAgfVxuICAgICAgICBtZXNzYWdlICs9IFwiKVwiO1xuICAgICAgICByZXR1cm4gbWF0Y2goZnVuY3Rpb24gKGFjdHVhbCkge1xuICAgICAgICAgICAgaWYgKGFjdHVhbCA9PT0gdW5kZWZpbmVkIHx8IGFjdHVhbCA9PT0gbnVsbCB8fFxuICAgICAgICAgICAgICAgICAgICAhcHJvcGVydHlUZXN0KGFjdHVhbCwgcHJvcGVydHkpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIG9ubHlQcm9wZXJ0eSB8fCBkZWVwRXF1YWwodmFsdWUsIGFjdHVhbFtwcm9wZXJ0eV0pO1xuICAgICAgICB9LCBtZXNzYWdlKTtcbiAgICB9O1xufVxuXG5tYXRjaC5oYXMgPSBjcmVhdGVQcm9wZXJ0eU1hdGNoZXIoZnVuY3Rpb24gKGFjdHVhbCwgcHJvcGVydHkpIHtcbiAgICBpZiAodHlwZW9mIGFjdHVhbCA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICByZXR1cm4gcHJvcGVydHkgaW4gYWN0dWFsO1xuICAgIH1cbiAgICByZXR1cm4gYWN0dWFsW3Byb3BlcnR5XSAhPT0gdW5kZWZpbmVkO1xufSwgXCJoYXNcIik7XG5cbm1hdGNoLmhhc093biA9IGNyZWF0ZVByb3BlcnR5TWF0Y2hlcihmdW5jdGlvbiAoYWN0dWFsLCBwcm9wZXJ0eSkge1xuICAgIHJldHVybiBhY3R1YWwuaGFzT3duUHJvcGVydHkocHJvcGVydHkpO1xufSwgXCJoYXNPd25cIik7XG5cbm1hdGNoLmFycmF5ID0gbWF0Y2gudHlwZU9mKFwiYXJyYXlcIik7XG5cbm1hdGNoLmFycmF5LmRlZXBFcXVhbHMgPSBmdW5jdGlvbiAoZXhwZWN0YXRpb24pIHtcbiAgICByZXR1cm4gbWF0Y2goZnVuY3Rpb24gKGFjdHVhbCkge1xuICAgICAgICAvLyBDb21wYXJpbmcgbGVuZ3RocyBpcyB0aGUgZmFzdGVzdCB3YXkgdG8gc3BvdCBhIGRpZmZlcmVuY2UgYmVmb3JlIGl0ZXJhdGluZyB0aHJvdWdoIGV2ZXJ5IGl0ZW1cbiAgICAgICAgdmFyIHNhbWVMZW5ndGggPSBhY3R1YWwubGVuZ3RoID09PSBleHBlY3RhdGlvbi5sZW5ndGg7XG4gICAgICAgIHJldHVybiB0eXBlT2YoYWN0dWFsKSA9PT0gXCJhcnJheVwiICYmIHNhbWVMZW5ndGggJiYgZXZlcnkoYWN0dWFsLCBmdW5jdGlvbiAoZWxlbWVudCwgaW5kZXgpIHtcbiAgICAgICAgICAgIHJldHVybiBleHBlY3RhdGlvbltpbmRleF0gPT09IGVsZW1lbnQ7XG4gICAgICAgIH0pO1xuICAgIH0sIFwiZGVlcEVxdWFscyhbXCIgKyBpdGVyYWJsZVRvU3RyaW5nKGV4cGVjdGF0aW9uKSArIFwiXSlcIik7XG59O1xuXG5tYXRjaC5hcnJheS5zdGFydHNXaXRoID0gZnVuY3Rpb24gKGV4cGVjdGF0aW9uKSB7XG4gICAgcmV0dXJuIG1hdGNoKGZ1bmN0aW9uIChhY3R1YWwpIHtcbiAgICAgICAgcmV0dXJuIHR5cGVPZihhY3R1YWwpID09PSBcImFycmF5XCIgJiYgZXZlcnkoZXhwZWN0YXRpb24sIGZ1bmN0aW9uIChleHBlY3RlZEVsZW1lbnQsIGluZGV4KSB7XG4gICAgICAgICAgICByZXR1cm4gYWN0dWFsW2luZGV4XSA9PT0gZXhwZWN0ZWRFbGVtZW50O1xuICAgICAgICB9KTtcbiAgICB9LCBcInN0YXJ0c1dpdGgoW1wiICsgaXRlcmFibGVUb1N0cmluZyhleHBlY3RhdGlvbikgKyBcIl0pXCIpO1xufTtcblxubWF0Y2guYXJyYXkuZW5kc1dpdGggPSBmdW5jdGlvbiAoZXhwZWN0YXRpb24pIHtcbiAgICByZXR1cm4gbWF0Y2goZnVuY3Rpb24gKGFjdHVhbCkge1xuICAgICAgICAvLyBUaGlzIGluZGljYXRlcyB0aGUgaW5kZXggaW4gd2hpY2ggd2Ugc2hvdWxkIHN0YXJ0IG1hdGNoaW5nXG4gICAgICAgIHZhciBvZmZzZXQgPSBhY3R1YWwubGVuZ3RoIC0gZXhwZWN0YXRpb24ubGVuZ3RoO1xuXG4gICAgICAgIHJldHVybiB0eXBlT2YoYWN0dWFsKSA9PT0gXCJhcnJheVwiICYmIGV2ZXJ5KGV4cGVjdGF0aW9uLCBmdW5jdGlvbiAoZXhwZWN0ZWRFbGVtZW50LCBpbmRleCkge1xuICAgICAgICAgICAgcmV0dXJuIGFjdHVhbFtvZmZzZXQgKyBpbmRleF0gPT09IGV4cGVjdGVkRWxlbWVudDtcbiAgICAgICAgfSk7XG4gICAgfSwgXCJlbmRzV2l0aChbXCIgKyBpdGVyYWJsZVRvU3RyaW5nKGV4cGVjdGF0aW9uKSArIFwiXSlcIik7XG59O1xuXG5tYXRjaC5hcnJheS5jb250YWlucyA9IGZ1bmN0aW9uIChleHBlY3RhdGlvbikge1xuICAgIHJldHVybiBtYXRjaChmdW5jdGlvbiAoYWN0dWFsKSB7XG4gICAgICAgIHJldHVybiB0eXBlT2YoYWN0dWFsKSA9PT0gXCJhcnJheVwiICYmIGV2ZXJ5KGV4cGVjdGF0aW9uLCBmdW5jdGlvbiAoZXhwZWN0ZWRFbGVtZW50KSB7XG4gICAgICAgICAgICByZXR1cm4gaW5kZXhPZi5jYWxsKGFjdHVhbCwgZXhwZWN0ZWRFbGVtZW50KSAhPT0gLTE7XG4gICAgICAgIH0pO1xuICAgIH0sIFwiY29udGFpbnMoW1wiICsgaXRlcmFibGVUb1N0cmluZyhleHBlY3RhdGlvbikgKyBcIl0pXCIpO1xufTtcblxubWF0Y2gubWFwID0gbWF0Y2gudHlwZU9mKFwibWFwXCIpO1xuXG5tYXRjaC5tYXAuZGVlcEVxdWFscyA9IGZ1bmN0aW9uIG1hcERlZXBFcXVhbHMoZXhwZWN0YXRpb24pIHtcbiAgICByZXR1cm4gbWF0Y2goZnVuY3Rpb24gKGFjdHVhbCkge1xuICAgICAgICAvLyBDb21wYXJpbmcgbGVuZ3RocyBpcyB0aGUgZmFzdGVzdCB3YXkgdG8gc3BvdCBhIGRpZmZlcmVuY2UgYmVmb3JlIGl0ZXJhdGluZyB0aHJvdWdoIGV2ZXJ5IGl0ZW1cbiAgICAgICAgdmFyIHNhbWVMZW5ndGggPSBhY3R1YWwuc2l6ZSA9PT0gZXhwZWN0YXRpb24uc2l6ZTtcbiAgICAgICAgcmV0dXJuIHR5cGVPZihhY3R1YWwpID09PSBcIm1hcFwiICYmIHNhbWVMZW5ndGggJiYgZXZlcnkoYWN0dWFsLCBmdW5jdGlvbiAoZWxlbWVudCwga2V5KSB7XG4gICAgICAgICAgICByZXR1cm4gZXhwZWN0YXRpb24uaGFzKGtleSkgJiYgZXhwZWN0YXRpb24uZ2V0KGtleSkgPT09IGVsZW1lbnQ7XG4gICAgICAgIH0pO1xuICAgIH0sIFwiZGVlcEVxdWFscyhNYXBbXCIgKyBpdGVyYWJsZVRvU3RyaW5nKGV4cGVjdGF0aW9uKSArIFwiXSlcIik7XG59O1xuXG5tYXRjaC5tYXAuY29udGFpbnMgPSBmdW5jdGlvbiBtYXBDb250YWlucyhleHBlY3RhdGlvbikge1xuICAgIHJldHVybiBtYXRjaChmdW5jdGlvbiAoYWN0dWFsKSB7XG4gICAgICAgIHJldHVybiB0eXBlT2YoYWN0dWFsKSA9PT0gXCJtYXBcIiAmJiBldmVyeShleHBlY3RhdGlvbiwgZnVuY3Rpb24gKGVsZW1lbnQsIGtleSkge1xuICAgICAgICAgICAgcmV0dXJuIGFjdHVhbC5oYXMoa2V5KSAmJiBhY3R1YWwuZ2V0KGtleSkgPT09IGVsZW1lbnQ7XG4gICAgICAgIH0pO1xuICAgIH0sIFwiY29udGFpbnMoTWFwW1wiICsgaXRlcmFibGVUb1N0cmluZyhleHBlY3RhdGlvbikgKyBcIl0pXCIpO1xufTtcblxubWF0Y2guc2V0ID0gbWF0Y2gudHlwZU9mKFwic2V0XCIpO1xuXG5tYXRjaC5zZXQuZGVlcEVxdWFscyA9IGZ1bmN0aW9uIHNldERlZXBFcXVhbHMoZXhwZWN0YXRpb24pIHtcbiAgICByZXR1cm4gbWF0Y2goZnVuY3Rpb24gKGFjdHVhbCkge1xuICAgICAgICAvLyBDb21wYXJpbmcgbGVuZ3RocyBpcyB0aGUgZmFzdGVzdCB3YXkgdG8gc3BvdCBhIGRpZmZlcmVuY2UgYmVmb3JlIGl0ZXJhdGluZyB0aHJvdWdoIGV2ZXJ5IGl0ZW1cbiAgICAgICAgdmFyIHNhbWVMZW5ndGggPSBhY3R1YWwuc2l6ZSA9PT0gZXhwZWN0YXRpb24uc2l6ZTtcbiAgICAgICAgcmV0dXJuIHR5cGVPZihhY3R1YWwpID09PSBcInNldFwiICYmIHNhbWVMZW5ndGggJiYgZXZlcnkoYWN0dWFsLCBmdW5jdGlvbiAoZWxlbWVudCkge1xuICAgICAgICAgICAgcmV0dXJuIGV4cGVjdGF0aW9uLmhhcyhlbGVtZW50KTtcbiAgICAgICAgfSk7XG4gICAgfSwgXCJkZWVwRXF1YWxzKFNldFtcIiArIGl0ZXJhYmxlVG9TdHJpbmcoZXhwZWN0YXRpb24pICsgXCJdKVwiKTtcbn07XG5cbm1hdGNoLnNldC5jb250YWlucyA9IGZ1bmN0aW9uIHNldENvbnRhaW5zKGV4cGVjdGF0aW9uKSB7XG4gICAgcmV0dXJuIG1hdGNoKGZ1bmN0aW9uIChhY3R1YWwpIHtcbiAgICAgICAgcmV0dXJuIHR5cGVPZihhY3R1YWwpID09PSBcInNldFwiICYmIGV2ZXJ5KGV4cGVjdGF0aW9uLCBmdW5jdGlvbiAoZWxlbWVudCkge1xuICAgICAgICAgICAgcmV0dXJuIGFjdHVhbC5oYXMoZWxlbWVudCk7XG4gICAgICAgIH0pO1xuICAgIH0sIFwiY29udGFpbnMoU2V0W1wiICsgaXRlcmFibGVUb1N0cmluZyhleHBlY3RhdGlvbikgKyBcIl0pXCIpO1xufTtcblxubWF0Y2guYm9vbCA9IG1hdGNoLnR5cGVPZihcImJvb2xlYW5cIik7XG5tYXRjaC5udW1iZXIgPSBtYXRjaC50eXBlT2YoXCJudW1iZXJcIik7XG5tYXRjaC5zdHJpbmcgPSBtYXRjaC50eXBlT2YoXCJzdHJpbmdcIik7XG5tYXRjaC5vYmplY3QgPSBtYXRjaC50eXBlT2YoXCJvYmplY3RcIik7XG5tYXRjaC5mdW5jID0gbWF0Y2gudHlwZU9mKFwiZnVuY3Rpb25cIik7XG5tYXRjaC5yZWdleHAgPSBtYXRjaC50eXBlT2YoXCJyZWdleHBcIik7XG5tYXRjaC5kYXRlID0gbWF0Y2gudHlwZU9mKFwiZGF0ZVwiKTtcbm1hdGNoLnN5bWJvbCA9IG1hdGNoLnR5cGVPZihcInN5bWJvbFwiKTtcblxubW9kdWxlLmV4cG9ydHMgPSBtYXRjaDtcbiIsIlwidXNlIHN0cmljdFwiO1xuXG52YXIgc3B5SW52b2tlID0gcmVxdWlyZShcIi4vc3B5XCIpLmludm9rZTtcbnZhciBzcHlDYWxsVG9TdHJpbmcgPSByZXF1aXJlKFwiLi9jYWxsXCIpLnRvU3RyaW5nO1xudmFyIHRpbWVzSW5Xb3JkcyA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS90aW1lcy1pbi13b3Jkc1wiKTtcbnZhciBleHRlbmQgPSByZXF1aXJlKFwiLi91dGlsL2NvcmUvZXh0ZW5kXCIpO1xudmFyIG1hdGNoID0gcmVxdWlyZShcIi4vbWF0Y2hcIik7XG52YXIgc3R1YiA9IHJlcXVpcmUoXCIuL3N0dWJcIik7XG52YXIgYXNzZXJ0ID0gcmVxdWlyZShcIi4vYXNzZXJ0XCIpO1xudmFyIGRlZXBFcXVhbCA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS9kZWVwLWVxdWFsXCIpLnVzZShtYXRjaCk7XG52YXIgZm9ybWF0ID0gcmVxdWlyZShcIi4vdXRpbC9jb3JlL2Zvcm1hdFwiKTtcbnZhciB2YWx1ZVRvU3RyaW5nID0gcmVxdWlyZShcIi4vdXRpbC9jb3JlL3ZhbHVlLXRvLXN0cmluZ1wiKTtcblxudmFyIHNsaWNlID0gQXJyYXkucHJvdG90eXBlLnNsaWNlO1xudmFyIHB1c2ggPSBBcnJheS5wcm90b3R5cGUucHVzaDtcblxuZnVuY3Rpb24gY2FsbENvdW50SW5Xb3JkcyhjYWxsQ291bnQpIHtcbiAgICBpZiAoY2FsbENvdW50ID09PSAwKSB7XG4gICAgICAgIHJldHVybiBcIm5ldmVyIGNhbGxlZFwiO1xuICAgIH1cblxuICAgIHJldHVybiBcImNhbGxlZCBcIiArIHRpbWVzSW5Xb3JkcyhjYWxsQ291bnQpO1xufVxuXG5mdW5jdGlvbiBleHBlY3RlZENhbGxDb3VudEluV29yZHMoZXhwZWN0YXRpb24pIHtcbiAgICB2YXIgbWluID0gZXhwZWN0YXRpb24ubWluQ2FsbHM7XG4gICAgdmFyIG1heCA9IGV4cGVjdGF0aW9uLm1heENhbGxzO1xuXG4gICAgaWYgKHR5cGVvZiBtaW4gPT09IFwibnVtYmVyXCIgJiYgdHlwZW9mIG1heCA9PT0gXCJudW1iZXJcIikge1xuICAgICAgICB2YXIgc3RyID0gdGltZXNJbldvcmRzKG1pbik7XG5cbiAgICAgICAgaWYgKG1pbiAhPT0gbWF4KSB7XG4gICAgICAgICAgICBzdHIgPSBcImF0IGxlYXN0IFwiICsgc3RyICsgXCIgYW5kIGF0IG1vc3QgXCIgKyB0aW1lc0luV29yZHMobWF4KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBzdHI7XG4gICAgfVxuXG4gICAgaWYgKHR5cGVvZiBtaW4gPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgcmV0dXJuIFwiYXQgbGVhc3QgXCIgKyB0aW1lc0luV29yZHMobWluKTtcbiAgICB9XG5cbiAgICByZXR1cm4gXCJhdCBtb3N0IFwiICsgdGltZXNJbldvcmRzKG1heCk7XG59XG5cbmZ1bmN0aW9uIHJlY2VpdmVkTWluQ2FsbHMoZXhwZWN0YXRpb24pIHtcbiAgICB2YXIgaGFzTWluTGltaXQgPSB0eXBlb2YgZXhwZWN0YXRpb24ubWluQ2FsbHMgPT09IFwibnVtYmVyXCI7XG4gICAgcmV0dXJuICFoYXNNaW5MaW1pdCB8fCBleHBlY3RhdGlvbi5jYWxsQ291bnQgPj0gZXhwZWN0YXRpb24ubWluQ2FsbHM7XG59XG5cbmZ1bmN0aW9uIHJlY2VpdmVkTWF4Q2FsbHMoZXhwZWN0YXRpb24pIHtcbiAgICBpZiAodHlwZW9mIGV4cGVjdGF0aW9uLm1heENhbGxzICE9PSBcIm51bWJlclwiKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICByZXR1cm4gZXhwZWN0YXRpb24uY2FsbENvdW50ID09PSBleHBlY3RhdGlvbi5tYXhDYWxscztcbn1cblxuZnVuY3Rpb24gdmVyaWZ5TWF0Y2hlcihwb3NzaWJsZU1hdGNoZXIsIGFyZykge1xuICAgIHZhciBpc01hdGNoZXIgPSBtYXRjaCAmJiBtYXRjaC5pc01hdGNoZXIocG9zc2libGVNYXRjaGVyKTtcblxuICAgIHJldHVybiBpc01hdGNoZXIgJiYgcG9zc2libGVNYXRjaGVyLnRlc3QoYXJnKSB8fCB0cnVlO1xufVxuXG52YXIgbW9ja0V4cGVjdGF0aW9uID0ge1xuICAgIG1pbkNhbGxzOiAxLFxuICAgIG1heENhbGxzOiAxLFxuXG4gICAgY3JlYXRlOiBmdW5jdGlvbiBjcmVhdGUobWV0aG9kTmFtZSkge1xuICAgICAgICB2YXIgZXhwZWN0YXRpb24gPSBleHRlbmQoc3R1Yi5jcmVhdGUoKSwgbW9ja0V4cGVjdGF0aW9uKTtcbiAgICAgICAgZGVsZXRlIGV4cGVjdGF0aW9uLmNyZWF0ZTtcbiAgICAgICAgZXhwZWN0YXRpb24ubWV0aG9kID0gbWV0aG9kTmFtZTtcblxuICAgICAgICByZXR1cm4gZXhwZWN0YXRpb247XG4gICAgfSxcblxuICAgIGludm9rZTogZnVuY3Rpb24gaW52b2tlKGZ1bmMsIHRoaXNWYWx1ZSwgYXJncykge1xuICAgICAgICB0aGlzLnZlcmlmeUNhbGxBbGxvd2VkKHRoaXNWYWx1ZSwgYXJncyk7XG5cbiAgICAgICAgcmV0dXJuIHNweUludm9rZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICBhdExlYXN0OiBmdW5jdGlvbiBhdExlYXN0KG51bSkge1xuICAgICAgICBpZiAodHlwZW9mIG51bSAhPT0gXCJudW1iZXJcIikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIidcIiArIHZhbHVlVG9TdHJpbmcobnVtKSArIFwiJyBpcyBub3QgbnVtYmVyXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCF0aGlzLmxpbWl0c1NldCkge1xuICAgICAgICAgICAgdGhpcy5tYXhDYWxscyA9IG51bGw7XG4gICAgICAgICAgICB0aGlzLmxpbWl0c1NldCA9IHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLm1pbkNhbGxzID0gbnVtO1xuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICBhdE1vc3Q6IGZ1bmN0aW9uIGF0TW9zdChudW0pIHtcbiAgICAgICAgaWYgKHR5cGVvZiBudW0gIT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCInXCIgKyB2YWx1ZVRvU3RyaW5nKG51bSkgKyBcIicgaXMgbm90IG51bWJlclwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghdGhpcy5saW1pdHNTZXQpIHtcbiAgICAgICAgICAgIHRoaXMubWluQ2FsbHMgPSBudWxsO1xuICAgICAgICAgICAgdGhpcy5saW1pdHNTZXQgPSB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5tYXhDYWxscyA9IG51bTtcblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuXG4gICAgbmV2ZXI6IGZ1bmN0aW9uIG5ldmVyKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5leGFjdGx5KDApO1xuICAgIH0sXG5cbiAgICBvbmNlOiBmdW5jdGlvbiBvbmNlKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5leGFjdGx5KDEpO1xuICAgIH0sXG5cbiAgICB0d2ljZTogZnVuY3Rpb24gdHdpY2UoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmV4YWN0bHkoMik7XG4gICAgfSxcblxuICAgIHRocmljZTogZnVuY3Rpb24gdGhyaWNlKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5leGFjdGx5KDMpO1xuICAgIH0sXG5cbiAgICBleGFjdGx5OiBmdW5jdGlvbiBleGFjdGx5KG51bSkge1xuICAgICAgICBpZiAodHlwZW9mIG51bSAhPT0gXCJudW1iZXJcIikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIidcIiArIHZhbHVlVG9TdHJpbmcobnVtKSArIFwiJyBpcyBub3QgYSBudW1iZXJcIik7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmF0TGVhc3QobnVtKTtcbiAgICAgICAgcmV0dXJuIHRoaXMuYXRNb3N0KG51bSk7XG4gICAgfSxcblxuICAgIG1ldDogZnVuY3Rpb24gbWV0KCkge1xuICAgICAgICByZXR1cm4gIXRoaXMuZmFpbGVkICYmIHJlY2VpdmVkTWluQ2FsbHModGhpcyk7XG4gICAgfSxcblxuICAgIHZlcmlmeUNhbGxBbGxvd2VkOiBmdW5jdGlvbiB2ZXJpZnlDYWxsQWxsb3dlZCh0aGlzVmFsdWUsIGFyZ3MpIHtcbiAgICAgICAgdmFyIGV4cGVjdGVkQXJndW1lbnRzID0gdGhpcy5leHBlY3RlZEFyZ3VtZW50cztcblxuICAgICAgICBpZiAocmVjZWl2ZWRNYXhDYWxscyh0aGlzKSkge1xuICAgICAgICAgICAgdGhpcy5mYWlsZWQgPSB0cnVlO1xuICAgICAgICAgICAgbW9ja0V4cGVjdGF0aW9uLmZhaWwodGhpcy5tZXRob2QgKyBcIiBhbHJlYWR5IGNhbGxlZCBcIiArIHRpbWVzSW5Xb3Jkcyh0aGlzLm1heENhbGxzKSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoXCJleHBlY3RlZFRoaXNcIiBpbiB0aGlzICYmIHRoaXMuZXhwZWN0ZWRUaGlzICE9PSB0aGlzVmFsdWUpIHtcbiAgICAgICAgICAgIG1vY2tFeHBlY3RhdGlvbi5mYWlsKHRoaXMubWV0aG9kICsgXCIgY2FsbGVkIHdpdGggXCIgKyB2YWx1ZVRvU3RyaW5nKHRoaXNWYWx1ZSkgK1xuICAgICAgICAgICAgICAgIFwiIGFzIHRoaXNWYWx1ZSwgZXhwZWN0ZWQgXCIgKyB2YWx1ZVRvU3RyaW5nKHRoaXMuZXhwZWN0ZWRUaGlzKSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIShcImV4cGVjdGVkQXJndW1lbnRzXCIgaW4gdGhpcykpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghYXJncykge1xuICAgICAgICAgICAgbW9ja0V4cGVjdGF0aW9uLmZhaWwodGhpcy5tZXRob2QgKyBcIiByZWNlaXZlZCBubyBhcmd1bWVudHMsIGV4cGVjdGVkIFwiICtcbiAgICAgICAgICAgICAgICBmb3JtYXQoZXhwZWN0ZWRBcmd1bWVudHMpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChhcmdzLmxlbmd0aCA8IGV4cGVjdGVkQXJndW1lbnRzLmxlbmd0aCkge1xuICAgICAgICAgICAgbW9ja0V4cGVjdGF0aW9uLmZhaWwodGhpcy5tZXRob2QgKyBcIiByZWNlaXZlZCB0b28gZmV3IGFyZ3VtZW50cyAoXCIgKyBmb3JtYXQoYXJncykgK1xuICAgICAgICAgICAgICAgIFwiKSwgZXhwZWN0ZWQgXCIgKyBmb3JtYXQoZXhwZWN0ZWRBcmd1bWVudHMpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLmV4cGVjdHNFeGFjdEFyZ0NvdW50ICYmXG4gICAgICAgICAgICBhcmdzLmxlbmd0aCAhPT0gZXhwZWN0ZWRBcmd1bWVudHMubGVuZ3RoKSB7XG4gICAgICAgICAgICBtb2NrRXhwZWN0YXRpb24uZmFpbCh0aGlzLm1ldGhvZCArIFwiIHJlY2VpdmVkIHRvbyBtYW55IGFyZ3VtZW50cyAoXCIgKyBmb3JtYXQoYXJncykgK1xuICAgICAgICAgICAgICAgIFwiKSwgZXhwZWN0ZWQgXCIgKyBmb3JtYXQoZXhwZWN0ZWRBcmd1bWVudHMpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGV4cGVjdGVkQXJndW1lbnRzLmZvckVhY2goZnVuY3Rpb24gKGV4cGVjdGVkQXJndW1lbnQsIGkpIHtcbiAgICAgICAgICAgIGlmICghdmVyaWZ5TWF0Y2hlcihleHBlY3RlZEFyZ3VtZW50LCBhcmdzW2ldKSkge1xuICAgICAgICAgICAgICAgIG1vY2tFeHBlY3RhdGlvbi5mYWlsKHRoaXMubWV0aG9kICsgXCIgcmVjZWl2ZWQgd3JvbmcgYXJndW1lbnRzIFwiICsgZm9ybWF0KGFyZ3MpICtcbiAgICAgICAgICAgICAgICAgICAgXCIsIGRpZG4ndCBtYXRjaCBcIiArIGV4cGVjdGVkQXJndW1lbnRzLnRvU3RyaW5nKCkpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIWRlZXBFcXVhbChleHBlY3RlZEFyZ3VtZW50LCBhcmdzW2ldKSkge1xuICAgICAgICAgICAgICAgIG1vY2tFeHBlY3RhdGlvbi5mYWlsKHRoaXMubWV0aG9kICsgXCIgcmVjZWl2ZWQgd3JvbmcgYXJndW1lbnRzIFwiICsgZm9ybWF0KGFyZ3MpICtcbiAgICAgICAgICAgICAgICAgICAgXCIsIGV4cGVjdGVkIFwiICsgZm9ybWF0KGV4cGVjdGVkQXJndW1lbnRzKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICBhbGxvd3NDYWxsOiBmdW5jdGlvbiBhbGxvd3NDYWxsKHRoaXNWYWx1ZSwgYXJncykge1xuICAgICAgICB2YXIgZXhwZWN0ZWRBcmd1bWVudHMgPSB0aGlzLmV4cGVjdGVkQXJndW1lbnRzO1xuXG4gICAgICAgIGlmICh0aGlzLm1ldCgpICYmIHJlY2VpdmVkTWF4Q2FsbHModGhpcykpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChcImV4cGVjdGVkVGhpc1wiIGluIHRoaXMgJiYgdGhpcy5leHBlY3RlZFRoaXMgIT09IHRoaXNWYWx1ZSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCEoXCJleHBlY3RlZEFyZ3VtZW50c1wiIGluIHRoaXMpKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGFyZ3MgPSBhcmdzIHx8IFtdO1xuXG4gICAgICAgIGlmIChhcmdzLmxlbmd0aCA8IGV4cGVjdGVkQXJndW1lbnRzLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuZXhwZWN0c0V4YWN0QXJnQ291bnQgJiZcbiAgICAgICAgICAgIGFyZ3MubGVuZ3RoICE9PSBleHBlY3RlZEFyZ3VtZW50cy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBleHBlY3RlZEFyZ3VtZW50cy5ldmVyeShmdW5jdGlvbiAoZXhwZWN0ZWRBcmd1bWVudCwgaSkge1xuICAgICAgICAgICAgaWYgKCF2ZXJpZnlNYXRjaGVyKGV4cGVjdGVkQXJndW1lbnQsIGFyZ3NbaV0pKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIWRlZXBFcXVhbChleHBlY3RlZEFyZ3VtZW50LCBhcmdzW2ldKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICB3aXRoQXJnczogZnVuY3Rpb24gd2l0aEFyZ3MoKSB7XG4gICAgICAgIHRoaXMuZXhwZWN0ZWRBcmd1bWVudHMgPSBzbGljZS5jYWxsKGFyZ3VtZW50cyk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICB3aXRoRXhhY3RBcmdzOiBmdW5jdGlvbiB3aXRoRXhhY3RBcmdzKCkge1xuICAgICAgICB0aGlzLndpdGhBcmdzLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgIHRoaXMuZXhwZWN0c0V4YWN0QXJnQ291bnQgPSB0cnVlO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuXG4gICAgb246IGZ1bmN0aW9uIG9uKHRoaXNWYWx1ZSkge1xuICAgICAgICB0aGlzLmV4cGVjdGVkVGhpcyA9IHRoaXNWYWx1ZTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIHRvU3RyaW5nOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBhcmdzID0gKHRoaXMuZXhwZWN0ZWRBcmd1bWVudHMgfHwgW10pLnNsaWNlKCk7XG5cbiAgICAgICAgaWYgKCF0aGlzLmV4cGVjdHNFeGFjdEFyZ0NvdW50KSB7XG4gICAgICAgICAgICBwdXNoLmNhbGwoYXJncywgXCJbLi4uXVwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBjYWxsU3RyID0gc3B5Q2FsbFRvU3RyaW5nLmNhbGwoe1xuICAgICAgICAgICAgcHJveHk6IHRoaXMubWV0aG9kIHx8IFwiYW5vbnltb3VzIG1vY2sgZXhwZWN0YXRpb25cIixcbiAgICAgICAgICAgIGFyZ3M6IGFyZ3NcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdmFyIG1lc3NhZ2UgPSBjYWxsU3RyLnJlcGxhY2UoXCIsIFsuLi5cIiwgXCJbLCAuLi5cIikgKyBcIiBcIiArXG4gICAgICAgICAgICBleHBlY3RlZENhbGxDb3VudEluV29yZHModGhpcyk7XG5cbiAgICAgICAgaWYgKHRoaXMubWV0KCkpIHtcbiAgICAgICAgICAgIHJldHVybiBcIkV4cGVjdGF0aW9uIG1ldDogXCIgKyBtZXNzYWdlO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIFwiRXhwZWN0ZWQgXCIgKyBtZXNzYWdlICsgXCIgKFwiICtcbiAgICAgICAgICAgIGNhbGxDb3VudEluV29yZHModGhpcy5jYWxsQ291bnQpICsgXCIpXCI7XG4gICAgfSxcblxuICAgIHZlcmlmeTogZnVuY3Rpb24gdmVyaWZ5KCkge1xuICAgICAgICBpZiAoIXRoaXMubWV0KCkpIHtcbiAgICAgICAgICAgIG1vY2tFeHBlY3RhdGlvbi5mYWlsKHRoaXMudG9TdHJpbmcoKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBtb2NrRXhwZWN0YXRpb24ucGFzcyh0aGlzLnRvU3RyaW5nKCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSxcblxuICAgIHBhc3M6IGZ1bmN0aW9uIHBhc3MobWVzc2FnZSkge1xuICAgICAgICBhc3NlcnQucGFzcyhtZXNzYWdlKTtcbiAgICB9LFxuXG4gICAgZmFpbDogZnVuY3Rpb24gZmFpbChtZXNzYWdlKSB7XG4gICAgICAgIHZhciBleGNlcHRpb24gPSBuZXcgRXJyb3IobWVzc2FnZSk7XG4gICAgICAgIGV4Y2VwdGlvbi5uYW1lID0gXCJFeHBlY3RhdGlvbkVycm9yXCI7XG5cbiAgICAgICAgdGhyb3cgZXhjZXB0aW9uO1xuICAgIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gbW9ja0V4cGVjdGF0aW9uO1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBtb2NrRXhwZWN0YXRpb24gPSByZXF1aXJlKFwiLi9tb2NrLWV4cGVjdGF0aW9uXCIpO1xudmFyIHNweUNhbGxUb1N0cmluZyA9IHJlcXVpcmUoXCIuL2NhbGxcIikudG9TdHJpbmc7XG52YXIgZXh0ZW5kID0gcmVxdWlyZShcIi4vdXRpbC9jb3JlL2V4dGVuZFwiKTtcbnZhciBtYXRjaCA9IHJlcXVpcmUoXCIuL21hdGNoXCIpO1xudmFyIGRlZXBFcXVhbCA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS9kZWVwLWVxdWFsXCIpLnVzZShtYXRjaCk7XG52YXIgd3JhcE1ldGhvZCA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS93cmFwLW1ldGhvZFwiKTtcblxudmFyIHB1c2ggPSBBcnJheS5wcm90b3R5cGUucHVzaDtcblxuZnVuY3Rpb24gbW9jayhvYmplY3QpIHtcbiAgICBpZiAoIW9iamVjdCkge1xuICAgICAgICByZXR1cm4gbW9ja0V4cGVjdGF0aW9uLmNyZWF0ZShcIkFub255bW91cyBtb2NrXCIpO1xuICAgIH1cblxuICAgIHJldHVybiBtb2NrLmNyZWF0ZShvYmplY3QpO1xufVxuXG5mdW5jdGlvbiBlYWNoKGNvbGxlY3Rpb24sIGNhbGxiYWNrKSB7XG4gICAgdmFyIGNvbCA9IGNvbGxlY3Rpb24gfHwgW107XG5cbiAgICBjb2wuZm9yRWFjaChjYWxsYmFjayk7XG59XG5cbmZ1bmN0aW9uIGFycmF5RXF1YWxzKGFycjEsIGFycjIsIGNvbXBhcmVMZW5ndGgpIHtcbiAgICBpZiAoY29tcGFyZUxlbmd0aCAmJiAoYXJyMS5sZW5ndGggIT09IGFycjIubGVuZ3RoKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgcmV0dXJuIGFycjEuZXZlcnkoZnVuY3Rpb24gKGVsZW1lbnQsIGkpIHtcbiAgICAgICAgcmV0dXJuIGRlZXBFcXVhbChlbGVtZW50LCBhcnIyW2ldKTtcblxuICAgIH0pO1xufVxuXG5leHRlbmQobW9jaywge1xuICAgIGNyZWF0ZTogZnVuY3Rpb24gY3JlYXRlKG9iamVjdCkge1xuICAgICAgICBpZiAoIW9iamVjdCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIm9iamVjdCBpcyBudWxsXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIG1vY2tPYmplY3QgPSBleHRlbmQoe30sIG1vY2spO1xuICAgICAgICBtb2NrT2JqZWN0Lm9iamVjdCA9IG9iamVjdDtcbiAgICAgICAgZGVsZXRlIG1vY2tPYmplY3QuY3JlYXRlO1xuXG4gICAgICAgIHJldHVybiBtb2NrT2JqZWN0O1xuICAgIH0sXG5cbiAgICBleHBlY3RzOiBmdW5jdGlvbiBleHBlY3RzKG1ldGhvZCkge1xuICAgICAgICBpZiAoIW1ldGhvZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIm1ldGhvZCBpcyBmYWxzeVwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghdGhpcy5leHBlY3RhdGlvbnMpIHtcbiAgICAgICAgICAgIHRoaXMuZXhwZWN0YXRpb25zID0ge307XG4gICAgICAgICAgICB0aGlzLnByb3hpZXMgPSBbXTtcbiAgICAgICAgICAgIHRoaXMuZmFpbHVyZXMgPSBbXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghdGhpcy5leHBlY3RhdGlvbnNbbWV0aG9kXSkge1xuICAgICAgICAgICAgdGhpcy5leHBlY3RhdGlvbnNbbWV0aG9kXSA9IFtdO1xuICAgICAgICAgICAgdmFyIG1vY2tPYmplY3QgPSB0aGlzO1xuXG4gICAgICAgICAgICB3cmFwTWV0aG9kKHRoaXMub2JqZWN0LCBtZXRob2QsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbW9ja09iamVjdC5pbnZva2VNZXRob2QobWV0aG9kLCB0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHB1c2guY2FsbCh0aGlzLnByb3hpZXMsIG1ldGhvZCk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgZXhwZWN0YXRpb24gPSBtb2NrRXhwZWN0YXRpb24uY3JlYXRlKG1ldGhvZCk7XG4gICAgICAgIHB1c2guY2FsbCh0aGlzLmV4cGVjdGF0aW9uc1ttZXRob2RdLCBleHBlY3RhdGlvbik7XG5cbiAgICAgICAgcmV0dXJuIGV4cGVjdGF0aW9uO1xuICAgIH0sXG5cbiAgICByZXN0b3JlOiBmdW5jdGlvbiByZXN0b3JlKCkge1xuICAgICAgICB2YXIgb2JqZWN0ID0gdGhpcy5vYmplY3Q7XG5cbiAgICAgICAgZWFjaCh0aGlzLnByb3hpZXMsIGZ1bmN0aW9uIChwcm94eSkge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBvYmplY3RbcHJveHldLnJlc3RvcmUgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgICAgIG9iamVjdFtwcm94eV0ucmVzdG9yZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgdmVyaWZ5OiBmdW5jdGlvbiB2ZXJpZnkoKSB7XG4gICAgICAgIHZhciBleHBlY3RhdGlvbnMgPSB0aGlzLmV4cGVjdGF0aW9ucyB8fCB7fTtcbiAgICAgICAgdmFyIG1lc3NhZ2VzID0gdGhpcy5mYWlsdXJlcyA/IHRoaXMuZmFpbHVyZXMuc2xpY2UoKSA6IFtdO1xuICAgICAgICB2YXIgbWV0ID0gW107XG5cbiAgICAgICAgZWFjaCh0aGlzLnByb3hpZXMsIGZ1bmN0aW9uIChwcm94eSkge1xuICAgICAgICAgICAgZWFjaChleHBlY3RhdGlvbnNbcHJveHldLCBmdW5jdGlvbiAoZXhwZWN0YXRpb24pIHtcbiAgICAgICAgICAgICAgICBpZiAoIWV4cGVjdGF0aW9uLm1ldCgpKSB7XG4gICAgICAgICAgICAgICAgICAgIHB1c2guY2FsbChtZXNzYWdlcywgZXhwZWN0YXRpb24udG9TdHJpbmcoKSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgcHVzaC5jYWxsKG1ldCwgZXhwZWN0YXRpb24udG9TdHJpbmcoKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMucmVzdG9yZSgpO1xuXG4gICAgICAgIGlmIChtZXNzYWdlcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBtb2NrRXhwZWN0YXRpb24uZmFpbChtZXNzYWdlcy5jb25jYXQobWV0KS5qb2luKFwiXFxuXCIpKTtcbiAgICAgICAgfSBlbHNlIGlmIChtZXQubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgbW9ja0V4cGVjdGF0aW9uLnBhc3MobWVzc2FnZXMuY29uY2F0KG1ldCkuam9pbihcIlxcblwiKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9LFxuXG4gICAgaW52b2tlTWV0aG9kOiBmdW5jdGlvbiBpbnZva2VNZXRob2QobWV0aG9kLCB0aGlzVmFsdWUsIGFyZ3MpIHtcbiAgICAgICAgLyogaWYgd2UgY2Fubm90IGZpbmQgYW55IG1hdGNoaW5nIGZpbGVzIHdlIHdpbGwgZXhwbGljaXRseSBjYWxsIG1vY2tFeHBlY3Rpb24jZmFpbCB3aXRoIGVycm9yIG1lc3NhZ2VzICovXG4gICAgICAgIC8qIGVzbGludCBjb25zaXN0ZW50LXJldHVybjogXCJvZmZcIiAqL1xuICAgICAgICB2YXIgZXhwZWN0YXRpb25zID0gdGhpcy5leHBlY3RhdGlvbnMgJiYgdGhpcy5leHBlY3RhdGlvbnNbbWV0aG9kXSA/IHRoaXMuZXhwZWN0YXRpb25zW21ldGhvZF0gOiBbXTtcbiAgICAgICAgdmFyIGN1cnJlbnRBcmdzID0gYXJncyB8fCBbXTtcbiAgICAgICAgdmFyIGF2YWlsYWJsZTtcblxuICAgICAgICB2YXIgZXhwZWN0YXRpb25zV2l0aE1hdGNoaW5nQXJncyA9IGV4cGVjdGF0aW9ucy5maWx0ZXIoZnVuY3Rpb24gKGV4cGVjdGF0aW9uKSB7XG4gICAgICAgICAgICB2YXIgZXhwZWN0ZWRBcmdzID0gZXhwZWN0YXRpb24uZXhwZWN0ZWRBcmd1bWVudHMgfHwgW107XG5cbiAgICAgICAgICAgIHJldHVybiBhcnJheUVxdWFscyhleHBlY3RlZEFyZ3MsIGN1cnJlbnRBcmdzLCBleHBlY3RhdGlvbi5leHBlY3RzRXhhY3RBcmdDb3VudCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHZhciBleHBlY3RhdGlvbnNUb0FwcGx5ID0gZXhwZWN0YXRpb25zV2l0aE1hdGNoaW5nQXJncy5maWx0ZXIoZnVuY3Rpb24gKGV4cGVjdGF0aW9uKSB7XG4gICAgICAgICAgICByZXR1cm4gIWV4cGVjdGF0aW9uLm1ldCgpICYmIGV4cGVjdGF0aW9uLmFsbG93c0NhbGwodGhpc1ZhbHVlLCBhcmdzKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKGV4cGVjdGF0aW9uc1RvQXBwbHkubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgcmV0dXJuIGV4cGVjdGF0aW9uc1RvQXBwbHlbMF0uYXBwbHkodGhpc1ZhbHVlLCBhcmdzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBtZXNzYWdlcyA9IFtdO1xuICAgICAgICB2YXIgZXhoYXVzdGVkID0gMDtcblxuICAgICAgICBleHBlY3RhdGlvbnNXaXRoTWF0Y2hpbmdBcmdzLmZvckVhY2goZnVuY3Rpb24gKGV4cGVjdGF0aW9uKSB7XG4gICAgICAgICAgICBpZiAoZXhwZWN0YXRpb24uYWxsb3dzQ2FsbCh0aGlzVmFsdWUsIGFyZ3MpKSB7XG4gICAgICAgICAgICAgICAgYXZhaWxhYmxlID0gYXZhaWxhYmxlIHx8IGV4cGVjdGF0aW9uO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBleGhhdXN0ZWQgKz0gMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKGF2YWlsYWJsZSAmJiBleGhhdXN0ZWQgPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybiBhdmFpbGFibGUuYXBwbHkodGhpc1ZhbHVlLCBhcmdzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGV4cGVjdGF0aW9ucy5mb3JFYWNoKGZ1bmN0aW9uIChleHBlY3RhdGlvbikge1xuICAgICAgICAgICAgcHVzaC5jYWxsKG1lc3NhZ2VzLCBcIiAgICBcIiArIGV4cGVjdGF0aW9uLnRvU3RyaW5nKCkpO1xuICAgICAgICB9KTtcblxuICAgICAgICBtZXNzYWdlcy51bnNoaWZ0KFwiVW5leHBlY3RlZCBjYWxsOiBcIiArIHNweUNhbGxUb1N0cmluZy5jYWxsKHtcbiAgICAgICAgICAgIHByb3h5OiBtZXRob2QsXG4gICAgICAgICAgICBhcmdzOiBhcmdzXG4gICAgICAgIH0pKTtcblxuICAgICAgICB2YXIgZXJyID0gbmV3IEVycm9yKCk7XG4gICAgICAgIGlmICghZXJyLnN0YWNrKSB7XG4gICAgICAgICAgICAvLyBQaGFudG9tSlMgZG9lcyBub3Qgc2VyaWFsaXplIHRoZSBzdGFjayB0cmFjZSB1bnRpbCB0aGUgZXJyb3IgaGFzIGJlZW4gdGhyb3duXG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHsvKiBlbXB0eSAqL31cbiAgICAgICAgfVxuICAgICAgICB0aGlzLmZhaWx1cmVzLnB1c2goXCJVbmV4cGVjdGVkIGNhbGw6IFwiICsgc3B5Q2FsbFRvU3RyaW5nLmNhbGwoe1xuICAgICAgICAgICAgcHJveHk6IG1ldGhvZCxcbiAgICAgICAgICAgIGFyZ3M6IGFyZ3MsXG4gICAgICAgICAgICBzdGFjazogZXJyLnN0YWNrXG4gICAgICAgIH0pKTtcblxuICAgICAgICBtb2NrRXhwZWN0YXRpb24uZmFpbChtZXNzYWdlcy5qb2luKFwiXFxuXCIpKTtcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBtb2NrO1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBleHRlbmQgPSByZXF1aXJlKFwiLi91dGlsL2NvcmUvZXh0ZW5kXCIpO1xudmFyIHNpbm9uQ29sbGVjdGlvbiA9IHJlcXVpcmUoXCIuL2NvbGxlY3Rpb25cIik7XG52YXIgc2lub25NYXRjaCA9IHJlcXVpcmUoXCIuL21hdGNoXCIpO1xudmFyIHNpbm9uQXNzZXJ0ID0gcmVxdWlyZShcIi4vYXNzZXJ0XCIpO1xudmFyIHNpbm9uQ2xvY2sgPSByZXF1aXJlKFwiLi91dGlsL2Zha2VfdGltZXJzXCIpO1xudmFyIGZha2VTZXJ2ZXIgPSByZXF1aXJlKFwiLi91dGlsL2Zha2Vfc2VydmVyXCIpO1xudmFyIGZha2VYaHIgPSByZXF1aXJlKFwiLi91dGlsL2Zha2VfeG1sX2h0dHBfcmVxdWVzdFwiKTtcbnZhciBmYWtlU2VydmVyV2l0aENsb2NrID0gcmVxdWlyZShcIi4vdXRpbC9mYWtlX3NlcnZlcl93aXRoX2Nsb2NrXCIpO1xuXG52YXIgcHVzaCA9IFtdLnB1c2g7XG5cbnZhciBzaW5vblNhbmRib3ggPSBPYmplY3QuY3JlYXRlKHNpbm9uQ29sbGVjdGlvbik7XG5cbmZ1bmN0aW9uIGV4cG9zZVZhbHVlKHNhbmRib3gsIGNvbmZpZywga2V5LCB2YWx1ZSkge1xuICAgIGlmICghdmFsdWUpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChjb25maWcuaW5qZWN0SW50byAmJiAhKGtleSBpbiBjb25maWcuaW5qZWN0SW50bykpIHtcbiAgICAgICAgY29uZmlnLmluamVjdEludG9ba2V5XSA9IHZhbHVlO1xuICAgICAgICBzYW5kYm94LmluamVjdGVkS2V5cy5wdXNoKGtleSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgcHVzaC5jYWxsKHNhbmRib3guYXJncywgdmFsdWUpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gcHJlcGFyZVNhbmRib3hGcm9tQ29uZmlnKGNvbmZpZykge1xuICAgIHZhciBzYW5kYm94ID0gT2JqZWN0LmNyZWF0ZShzaW5vblNhbmRib3gpO1xuXG4gICAgaWYgKGNvbmZpZy51c2VGYWtlU2VydmVyKSB7XG4gICAgICAgIGlmICh0eXBlb2YgY29uZmlnLnVzZUZha2VTZXJ2ZXIgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgICAgIHNhbmRib3guc2VydmVyUHJvdG90eXBlID0gY29uZmlnLnVzZUZha2VTZXJ2ZXI7XG4gICAgICAgIH1cblxuICAgICAgICBzYW5kYm94LnVzZUZha2VTZXJ2ZXIoKTtcbiAgICB9XG5cbiAgICBpZiAoY29uZmlnLnVzZUZha2VUaW1lcnMpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBjb25maWcudXNlRmFrZVRpbWVycyA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICAgICAgc2FuZGJveC51c2VGYWtlVGltZXJzLmFwcGx5KHNhbmRib3gsIGNvbmZpZy51c2VGYWtlVGltZXJzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHNhbmRib3gudXNlRmFrZVRpbWVycygpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHNhbmRib3g7XG59XG5cbmV4dGVuZChzaW5vblNhbmRib3gsIHtcbiAgICB1c2VGYWtlVGltZXJzOiBmdW5jdGlvbiB1c2VGYWtlVGltZXJzKCkge1xuICAgICAgICB0aGlzLmNsb2NrID0gc2lub25DbG9jay51c2VGYWtlVGltZXJzLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuYWRkKHRoaXMuY2xvY2spO1xuICAgIH0sXG5cbiAgICBzZXJ2ZXJQcm90b3R5cGU6IGZha2VTZXJ2ZXJXaXRoQ2xvY2ssXG5cbiAgICB1c2VGYWtlU2VydmVyOiBmdW5jdGlvbiB1c2VGYWtlU2VydmVyKCkge1xuICAgICAgICB2YXIgcHJvdG8gPSB0aGlzLnNlcnZlclByb3RvdHlwZSB8fCBmYWtlU2VydmVyO1xuXG4gICAgICAgIGlmICghcHJvdG8gfHwgIXByb3RvLmNyZWF0ZSkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNlcnZlciA9IHByb3RvLmNyZWF0ZSgpO1xuICAgICAgICByZXR1cm4gdGhpcy5hZGQodGhpcy5zZXJ2ZXIpO1xuICAgIH0sXG5cbiAgICB1c2VGYWtlWE1MSHR0cFJlcXVlc3Q6IGZ1bmN0aW9uIHVzZUZha2VYTUxIdHRwUmVxdWVzdCgpIHtcbiAgICAgICAgdmFyIHhociA9IGZha2VYaHIudXNlRmFrZVhNTEh0dHBSZXF1ZXN0KCk7XG4gICAgICAgIHJldHVybiB0aGlzLmFkZCh4aHIpO1xuICAgIH0sXG5cbiAgICBpbmplY3Q6IGZ1bmN0aW9uIChvYmopIHtcbiAgICAgICAgc2lub25Db2xsZWN0aW9uLmluamVjdC5jYWxsKHRoaXMsIG9iaik7XG5cbiAgICAgICAgaWYgKHRoaXMuY2xvY2spIHtcbiAgICAgICAgICAgIG9iai5jbG9jayA9IHRoaXMuY2xvY2s7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5zZXJ2ZXIpIHtcbiAgICAgICAgICAgIG9iai5zZXJ2ZXIgPSB0aGlzLnNlcnZlcjtcbiAgICAgICAgICAgIG9iai5yZXF1ZXN0cyA9IHRoaXMuc2VydmVyLnJlcXVlc3RzO1xuICAgICAgICB9XG5cbiAgICAgICAgb2JqLm1hdGNoID0gc2lub25NYXRjaDtcblxuICAgICAgICByZXR1cm4gb2JqO1xuICAgIH0sXG5cbiAgICByZXN0b3JlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJzYW5kYm94LnJlc3RvcmUoKSBkb2VzIG5vdCB0YWtlIGFueSBwYXJhbWV0ZXJzLiBQZXJoYXBzIHlvdSBtZWFudCBzdHViLnJlc3RvcmUoKVwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHNpbm9uQ29sbGVjdGlvbi5yZXN0b3JlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgIHRoaXMucmVzdG9yZUNvbnRleHQoKTtcbiAgICB9LFxuXG4gICAgcmVzdG9yZUNvbnRleHQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGluamVjdGVkS2V5cyA9IHRoaXMuaW5qZWN0ZWRLZXlzO1xuICAgICAgICB2YXIgaW5qZWN0SW50byA9IHRoaXMuaW5qZWN0SW50bztcblxuICAgICAgICBpZiAoIWluamVjdGVkS2V5cykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaW5qZWN0ZWRLZXlzLmZvckVhY2goZnVuY3Rpb24gKGluamVjdGVkS2V5KSB7XG4gICAgICAgICAgICBkZWxldGUgaW5qZWN0SW50b1tpbmplY3RlZEtleV07XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGluamVjdGVkS2V5cyA9IFtdO1xuICAgIH0sXG5cbiAgICBjcmVhdGU6IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAgICAgaWYgKCFjb25maWcpIHtcbiAgICAgICAgICAgIHJldHVybiBPYmplY3QuY3JlYXRlKHNpbm9uU2FuZGJveCk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgc2FuZGJveCA9IHByZXBhcmVTYW5kYm94RnJvbUNvbmZpZyhjb25maWcpO1xuICAgICAgICBzYW5kYm94LmFyZ3MgPSBzYW5kYm94LmFyZ3MgfHwgW107XG4gICAgICAgIHNhbmRib3guaW5qZWN0ZWRLZXlzID0gW107XG4gICAgICAgIHNhbmRib3guaW5qZWN0SW50byA9IGNvbmZpZy5pbmplY3RJbnRvO1xuICAgICAgICB2YXIgZXhwb3NlZCA9IHNhbmRib3guaW5qZWN0KHt9KTtcblxuICAgICAgICBpZiAoY29uZmlnLnByb3BlcnRpZXMpIHtcbiAgICAgICAgICAgIGNvbmZpZy5wcm9wZXJ0aWVzLmZvckVhY2goZnVuY3Rpb24gKHByb3ApIHtcbiAgICAgICAgICAgICAgICB2YXIgdmFsdWUgPSBleHBvc2VkW3Byb3BdIHx8IHByb3AgPT09IFwic2FuZGJveFwiICYmIHNhbmRib3g7XG4gICAgICAgICAgICAgICAgZXhwb3NlVmFsdWUoc2FuZGJveCwgY29uZmlnLCBwcm9wLCB2YWx1ZSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGV4cG9zZVZhbHVlKHNhbmRib3gsIGNvbmZpZywgXCJzYW5kYm94XCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHNhbmRib3g7XG4gICAgfSxcblxuICAgIG1hdGNoOiBzaW5vbk1hdGNoLFxuXG4gICAgYXNzZXJ0OiBzaW5vbkFzc2VydFxufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gc2lub25TYW5kYm94O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBjb2xvciA9IHJlcXVpcmUoXCIuL2NvbG9yXCIpO1xudmFyIHRpbWVzSW5Xb3JkcyA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS90aW1lcy1pbi13b3Jkc1wiKTtcbnZhciBzaW5vbkZvcm1hdCA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS9mb3JtYXRcIik7XG52YXIgc2lub25NYXRjaCA9IHJlcXVpcmUoXCIuL21hdGNoXCIpO1xudmFyIGpzRGlmZiA9IHJlcXVpcmUoXCJkaWZmXCIpO1xudmFyIHB1c2ggPSBBcnJheS5wcm90b3R5cGUucHVzaDtcblxuZnVuY3Rpb24gY29sb3JTaW5vbk1hdGNoVGV4dChtYXRjaGVyLCBjYWxsZWRBcmcsIGNhbGxlZEFyZ01lc3NhZ2UpIHtcbiAgICBpZiAoIW1hdGNoZXIudGVzdChjYWxsZWRBcmcpKSB7XG4gICAgICAgIG1hdGNoZXIubWVzc2FnZSA9IGNvbG9yLnJlZChtYXRjaGVyLm1lc3NhZ2UpO1xuICAgICAgICBpZiAoY2FsbGVkQXJnTWVzc2FnZSkge1xuICAgICAgICAgICAgY2FsbGVkQXJnTWVzc2FnZSA9IGNvbG9yLmdyZWVuKGNhbGxlZEFyZ01lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBjYWxsZWRBcmdNZXNzYWdlICsgXCIgXCIgKyBtYXRjaGVyLm1lc3NhZ2U7XG59XG5cbmZ1bmN0aW9uIGNvbG9yRGlmZlRleHQoZGlmZikge1xuICAgIHZhciBvYmplY3RzID0gZGlmZi5tYXAoZnVuY3Rpb24gKHBhcnQpIHtcbiAgICAgICAgdmFyIHRleHQgPSBwYXJ0LnZhbHVlO1xuICAgICAgICBpZiAocGFydC5hZGRlZCkge1xuICAgICAgICAgICAgdGV4dCA9IGNvbG9yLmdyZWVuKHRleHQpO1xuICAgICAgICB9IGVsc2UgaWYgKHBhcnQucmVtb3ZlZCkge1xuICAgICAgICAgICAgdGV4dCA9IGNvbG9yLnJlZCh0ZXh0KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZGlmZi5sZW5ndGggPT09IDIpIHtcbiAgICAgICAgICAgIHRleHQgKz0gXCIgXCI7IC8vIGZvcm1hdCBzaW1wbGUgZGlmZnNcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGV4dDtcbiAgICB9KTtcbiAgICByZXR1cm4gb2JqZWN0cy5qb2luKFwiXCIpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBjOiBmdW5jdGlvbiAoc3B5SW5zdGFuY2UpIHtcbiAgICAgICAgcmV0dXJuIHRpbWVzSW5Xb3JkcyhzcHlJbnN0YW5jZS5jYWxsQ291bnQpO1xuICAgIH0sXG5cbiAgICBuOiBmdW5jdGlvbiAoc3B5SW5zdGFuY2UpIHtcbiAgICAgICAgcmV0dXJuIHNweUluc3RhbmNlLnRvU3RyaW5nKCk7XG4gICAgfSxcblxuICAgIEQ6IGZ1bmN0aW9uIChzcHlJbnN0YW5jZSwgYXJncykge1xuICAgICAgICB2YXIgbWVzc2FnZSA9IFwiXCI7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDAsIGwgPSBzcHlJbnN0YW5jZS5jYWxsQ291bnQ7IGkgPCBsOyArK2kpIHtcbiAgICAgICAgICAgIC8vIGRlc2NyaWJlIG11bHRpcGxlIGNhbGxzXG4gICAgICAgICAgICBpZiAobCA+IDEpIHtcbiAgICAgICAgICAgICAgICBpZiAoaSA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSArPSBcIlxcblwiO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBtZXNzYWdlICs9IFwiQ2FsbCBcIiArIChpICsgMSkgKyBcIjpcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBjYWxsZWRBcmdzID0gc3B5SW5zdGFuY2UuZ2V0Q2FsbChpKS5hcmdzO1xuICAgICAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBjYWxsZWRBcmdzLmxlbmd0aCB8fCBqIDwgYXJncy5sZW5ndGg7ICsraikge1xuICAgICAgICAgICAgICAgIG1lc3NhZ2UgKz0gXCJcXG5cIjtcbiAgICAgICAgICAgICAgICB2YXIgY2FsbGVkQXJnTWVzc2FnZSA9IGogPCBjYWxsZWRBcmdzLmxlbmd0aCA/IHNpbm9uRm9ybWF0KGNhbGxlZEFyZ3Nbal0pIDogXCJcIjtcbiAgICAgICAgICAgICAgICBpZiAoc2lub25NYXRjaC5pc01hdGNoZXIoYXJnc1tqXSkpIHtcbiAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSArPSBjb2xvclNpbm9uTWF0Y2hUZXh0KGFyZ3Nbal0sIGNhbGxlZEFyZ3Nbal0sIGNhbGxlZEFyZ01lc3NhZ2UpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBleHBlY3RlZEFyZ01lc3NhZ2UgPSBqIDwgYXJncy5sZW5ndGggPyBzaW5vbkZvcm1hdChhcmdzW2pdKSA6IFwiXCI7XG4gICAgICAgICAgICAgICAgICAgIHZhciBkaWZmID0ganNEaWZmLmRpZmZKc29uKGNhbGxlZEFyZ01lc3NhZ2UsIGV4cGVjdGVkQXJnTWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgKz0gY29sb3JEaWZmVGV4dChkaWZmKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbWVzc2FnZTtcbiAgICB9LFxuXG4gICAgQzogZnVuY3Rpb24gKHNweUluc3RhbmNlKSB7XG4gICAgICAgIHZhciBjYWxscyA9IFtdO1xuXG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBsID0gc3B5SW5zdGFuY2UuY2FsbENvdW50OyBpIDwgbDsgKytpKSB7XG4gICAgICAgICAgICB2YXIgc3RyaW5naWZpZWRDYWxsID0gXCIgICAgXCIgKyBzcHlJbnN0YW5jZS5nZXRDYWxsKGkpLnRvU3RyaW5nKCk7XG4gICAgICAgICAgICBpZiAoL1xcbi8udGVzdChjYWxsc1tpIC0gMV0pKSB7XG4gICAgICAgICAgICAgICAgc3RyaW5naWZpZWRDYWxsID0gXCJcXG5cIiArIHN0cmluZ2lmaWVkQ2FsbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHB1c2guY2FsbChjYWxscywgc3RyaW5naWZpZWRDYWxsKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBjYWxscy5sZW5ndGggPiAwID8gXCJcXG5cIiArIGNhbGxzLmpvaW4oXCJcXG5cIikgOiBcIlwiO1xuICAgIH0sXG5cbiAgICB0OiBmdW5jdGlvbiAoc3B5SW5zdGFuY2UpIHtcbiAgICAgICAgdmFyIG9iamVjdHMgPSBbXTtcblxuICAgICAgICBmb3IgKHZhciBpID0gMCwgbCA9IHNweUluc3RhbmNlLmNhbGxDb3VudDsgaSA8IGw7ICsraSkge1xuICAgICAgICAgICAgcHVzaC5jYWxsKG9iamVjdHMsIHNpbm9uRm9ybWF0KHNweUluc3RhbmNlLnRoaXNWYWx1ZXNbaV0pKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBvYmplY3RzLmpvaW4oXCIsIFwiKTtcbiAgICB9LFxuXG4gICAgXCIqXCI6IGZ1bmN0aW9uIChzcHlJbnN0YW5jZSwgYXJncykge1xuICAgICAgICByZXR1cm4gYXJncy5tYXAoc2lub25Gb3JtYXQpLmpvaW4oXCIsIFwiKTtcbiAgICB9XG59O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBleHRlbmQgPSByZXF1aXJlKFwiLi91dGlsL2NvcmUvZXh0ZW5kXCIpO1xudmFyIGZ1bmN0aW9uTmFtZSA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS9mdW5jdGlvbi1uYW1lXCIpO1xudmFyIGZ1bmN0aW9uVG9TdHJpbmcgPSByZXF1aXJlKFwiLi91dGlsL2NvcmUvZnVuY3Rpb24tdG8tc3RyaW5nXCIpO1xudmFyIGdldFByb3BlcnR5RGVzY3JpcHRvciA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS9nZXQtcHJvcGVydHktZGVzY3JpcHRvclwiKTtcbnZhciBzaW5vbk1hdGNoID0gcmVxdWlyZShcIi4vbWF0Y2hcIik7XG52YXIgZGVlcEVxdWFsID0gcmVxdWlyZShcIi4vdXRpbC9jb3JlL2RlZXAtZXF1YWxcIikudXNlKHNpbm9uTWF0Y2gpO1xudmFyIHNweUNhbGwgPSByZXF1aXJlKFwiLi9jYWxsXCIpO1xudmFyIHdyYXBNZXRob2QgPSByZXF1aXJlKFwiLi91dGlsL2NvcmUvd3JhcC1tZXRob2RcIik7XG52YXIgc2lub25Gb3JtYXQgPSByZXF1aXJlKFwiLi91dGlsL2NvcmUvZm9ybWF0XCIpO1xudmFyIHZhbHVlVG9TdHJpbmcgPSByZXF1aXJlKFwiLi91dGlsL2NvcmUvdmFsdWUtdG8tc3RyaW5nXCIpO1xuXG52YXIgcHVzaCA9IEFycmF5LnByb3RvdHlwZS5wdXNoO1xudmFyIHNsaWNlID0gQXJyYXkucHJvdG90eXBlLnNsaWNlO1xudmFyIGNhbGxJZCA9IDA7XG52YXIgRXJyb3JDb25zdHJ1Y3RvciA9IEVycm9yLnByb3RvdHlwZS5jb25zdHJ1Y3RvcjtcblxuZnVuY3Rpb24gc3B5KG9iamVjdCwgcHJvcGVydHksIHR5cGVzKSB7XG4gICAgdmFyIGRlc2NyaXB0b3IsIG1ldGhvZERlc2M7XG5cbiAgICBpZiAoIXByb3BlcnR5ICYmIHR5cGVvZiBvYmplY3QgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICByZXR1cm4gc3B5LmNyZWF0ZShvYmplY3QpO1xuICAgIH1cblxuICAgIGlmICghb2JqZWN0ICYmICFwcm9wZXJ0eSkge1xuICAgICAgICByZXR1cm4gc3B5LmNyZWF0ZShmdW5jdGlvbiAoKSB7IH0pO1xuICAgIH1cblxuICAgIGlmICghdHlwZXMpIHtcbiAgICAgICAgcmV0dXJuIHdyYXBNZXRob2Qob2JqZWN0LCBwcm9wZXJ0eSwgc3B5LmNyZWF0ZShvYmplY3RbcHJvcGVydHldKSk7XG4gICAgfVxuXG4gICAgZGVzY3JpcHRvciA9IHt9O1xuICAgIG1ldGhvZERlc2MgPSBnZXRQcm9wZXJ0eURlc2NyaXB0b3Iob2JqZWN0LCBwcm9wZXJ0eSk7XG5cbiAgICB0eXBlcy5mb3JFYWNoKGZ1bmN0aW9uICh0eXBlKSB7XG4gICAgICAgIGRlc2NyaXB0b3JbdHlwZV0gPSBzcHkuY3JlYXRlKG1ldGhvZERlc2NbdHlwZV0pO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIHdyYXBNZXRob2Qob2JqZWN0LCBwcm9wZXJ0eSwgZGVzY3JpcHRvcik7XG59XG5cbmZ1bmN0aW9uIG1hdGNoaW5nRmFrZShmYWtlcywgYXJncywgc3RyaWN0KSB7XG4gICAgaWYgKCFmYWtlcykge1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cblxuICAgIHZhciBtYXRjaGluZ0Zha2VzID0gZmFrZXMuZmlsdGVyKGZ1bmN0aW9uIChmYWtlKSB7XG4gICAgICAgIHJldHVybiBmYWtlLm1hdGNoZXMoYXJncywgc3RyaWN0KTtcbiAgICB9KTtcblxuICAgIHJldHVybiBtYXRjaGluZ0Zha2VzLnBvcCgpO1xufVxuXG5mdW5jdGlvbiBpbmNyZW1lbnRDYWxsQ291bnQoKSB7XG4gICAgdGhpcy5jYWxsZWQgPSB0cnVlO1xuICAgIHRoaXMuY2FsbENvdW50ICs9IDE7XG4gICAgdGhpcy5ub3RDYWxsZWQgPSBmYWxzZTtcbiAgICB0aGlzLmNhbGxlZE9uY2UgPSB0aGlzLmNhbGxDb3VudCA9PT0gMTtcbiAgICB0aGlzLmNhbGxlZFR3aWNlID0gdGhpcy5jYWxsQ291bnQgPT09IDI7XG4gICAgdGhpcy5jYWxsZWRUaHJpY2UgPSB0aGlzLmNhbGxDb3VudCA9PT0gMztcbn1cblxuZnVuY3Rpb24gY3JlYXRlQ2FsbFByb3BlcnRpZXMoKSB7XG4gICAgdGhpcy5maXJzdENhbGwgPSB0aGlzLmdldENhbGwoMCk7XG4gICAgdGhpcy5zZWNvbmRDYWxsID0gdGhpcy5nZXRDYWxsKDEpO1xuICAgIHRoaXMudGhpcmRDYWxsID0gdGhpcy5nZXRDYWxsKDIpO1xuICAgIHRoaXMubGFzdENhbGwgPSB0aGlzLmdldENhbGwodGhpcy5jYWxsQ291bnQgLSAxKTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlUHJveHkoZnVuYywgcHJveHlMZW5ndGgpIHtcbiAgICAvLyBSZXRhaW4gdGhlIGZ1bmN0aW9uIGxlbmd0aDpcbiAgICB2YXIgcDtcbiAgICBpZiAocHJveHlMZW5ndGgpIHtcbiAgICAgICAgLy8gRG8gbm90IGNoYW5nZSB0aGlzIHRvIHVzZSBhbiBldmFsLiBQcm9qZWN0cyB0aGF0IGRlcGVuZCBvbiBzaW5vbiBibG9jayB0aGUgdXNlIG9mIGV2YWwuXG4gICAgICAgIC8vIHJlZjogaHR0cHM6Ly9naXRodWIuY29tL3Npbm9uanMvc2lub24vaXNzdWVzLzcxMFxuICAgICAgICBzd2l0Y2ggKHByb3h5TGVuZ3RoKSB7XG4gICAgICAgICAgICAvKmVzbGludC1kaXNhYmxlIG5vLXVudXNlZC12YXJzLCBtYXgtbGVuKi9cbiAgICAgICAgICAgIGNhc2UgMTogcCA9IGZ1bmN0aW9uIHByb3h5KGEpIHsgcmV0dXJuIHAuaW52b2tlKGZ1bmMsIHRoaXMsIHNsaWNlLmNhbGwoYXJndW1lbnRzKSk7IH07IGJyZWFrO1xuICAgICAgICAgICAgY2FzZSAyOiBwID0gZnVuY3Rpb24gcHJveHkoYSwgYikgeyByZXR1cm4gcC5pbnZva2UoZnVuYywgdGhpcywgc2xpY2UuY2FsbChhcmd1bWVudHMpKTsgfTsgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIDM6IHAgPSBmdW5jdGlvbiBwcm94eShhLCBiLCBjKSB7IHJldHVybiBwLmludm9rZShmdW5jLCB0aGlzLCBzbGljZS5jYWxsKGFyZ3VtZW50cykpOyB9OyBicmVhaztcbiAgICAgICAgICAgIGNhc2UgNDogcCA9IGZ1bmN0aW9uIHByb3h5KGEsIGIsIGMsIGQpIHsgcmV0dXJuIHAuaW52b2tlKGZ1bmMsIHRoaXMsIHNsaWNlLmNhbGwoYXJndW1lbnRzKSk7IH07IGJyZWFrO1xuICAgICAgICAgICAgY2FzZSA1OiBwID0gZnVuY3Rpb24gcHJveHkoYSwgYiwgYywgZCwgZSkgeyByZXR1cm4gcC5pbnZva2UoZnVuYywgdGhpcywgc2xpY2UuY2FsbChhcmd1bWVudHMpKTsgfTsgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIDY6IHAgPSBmdW5jdGlvbiBwcm94eShhLCBiLCBjLCBkLCBlLCBmKSB7IHJldHVybiBwLmludm9rZShmdW5jLCB0aGlzLCBzbGljZS5jYWxsKGFyZ3VtZW50cykpOyB9OyBicmVhaztcbiAgICAgICAgICAgIGNhc2UgNzogcCA9IGZ1bmN0aW9uIHByb3h5KGEsIGIsIGMsIGQsIGUsIGYsIGcpIHsgcmV0dXJuIHAuaW52b2tlKGZ1bmMsIHRoaXMsIHNsaWNlLmNhbGwoYXJndW1lbnRzKSk7IH07IGJyZWFrO1xuICAgICAgICAgICAgY2FzZSA4OiBwID0gZnVuY3Rpb24gcHJveHkoYSwgYiwgYywgZCwgZSwgZiwgZywgaCkgeyByZXR1cm4gcC5pbnZva2UoZnVuYywgdGhpcywgc2xpY2UuY2FsbChhcmd1bWVudHMpKTsgfTsgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIDk6IHAgPSBmdW5jdGlvbiBwcm94eShhLCBiLCBjLCBkLCBlLCBmLCBnLCBoLCBpKSB7IHJldHVybiBwLmludm9rZShmdW5jLCB0aGlzLCBzbGljZS5jYWxsKGFyZ3VtZW50cykpOyB9OyBicmVhaztcbiAgICAgICAgICAgIGNhc2UgMTA6IHAgPSBmdW5jdGlvbiBwcm94eShhLCBiLCBjLCBkLCBlLCBmLCBnLCBoLCBpLCBqKSB7IHJldHVybiBwLmludm9rZShmdW5jLCB0aGlzLCBzbGljZS5jYWxsKGFyZ3VtZW50cykpOyB9OyBicmVhaztcbiAgICAgICAgICAgIGNhc2UgMTE6IHAgPSBmdW5jdGlvbiBwcm94eShhLCBiLCBjLCBkLCBlLCBmLCBnLCBoLCBpLCBqLCBrKSB7IHJldHVybiBwLmludm9rZShmdW5jLCB0aGlzLCBzbGljZS5jYWxsKGFyZ3VtZW50cykpOyB9OyBicmVhaztcbiAgICAgICAgICAgIGNhc2UgMTI6IHAgPSBmdW5jdGlvbiBwcm94eShhLCBiLCBjLCBkLCBlLCBmLCBnLCBoLCBpLCBqLCBrLCBsKSB7IHJldHVybiBwLmludm9rZShmdW5jLCB0aGlzLCBzbGljZS5jYWxsKGFyZ3VtZW50cykpOyB9OyBicmVhaztcbiAgICAgICAgICAgIGRlZmF1bHQ6IHAgPSBmdW5jdGlvbiBwcm94eSgpIHsgcmV0dXJuIHAuaW52b2tlKGZ1bmMsIHRoaXMsIHNsaWNlLmNhbGwoYXJndW1lbnRzKSk7IH07IGJyZWFrO1xuICAgICAgICAgICAgLyplc2xpbnQtZW5hYmxlKi9cbiAgICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAgIHAgPSBmdW5jdGlvbiBwcm94eSgpIHtcbiAgICAgICAgICAgIHJldHVybiBwLmludm9rZShmdW5jLCB0aGlzLCBzbGljZS5jYWxsKGFyZ3VtZW50cykpO1xuICAgICAgICB9O1xuICAgIH1cbiAgICBwLmlzU2lub25Qcm94eSA9IHRydWU7XG4gICAgcmV0dXJuIHA7XG59XG5cbnZhciB1dWlkID0gMDtcblxuLy8gUHVibGljIEFQSVxudmFyIHNweUFwaSA9IHtcbiAgICBmb3JtYXR0ZXJzOiByZXF1aXJlKFwiLi9zcHktZm9ybWF0dGVyc1wiKSxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmICh0aGlzLmludm9raW5nKSB7XG4gICAgICAgICAgICB2YXIgZXJyID0gbmV3IEVycm9yKFwiQ2Fubm90IHJlc2V0IFNpbm9uIGZ1bmN0aW9uIHdoaWxlIGludm9raW5nIGl0LiBcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiTW92ZSB0aGUgY2FsbCB0byAucmVzZXQgb3V0c2lkZSBvZiB0aGUgY2FsbGJhY2suXCIpO1xuICAgICAgICAgICAgZXJyLm5hbWUgPSBcIkludmFsaWRSZXNldEV4Y2VwdGlvblwiO1xuICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5jYWxsZWQgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5ub3RDYWxsZWQgPSB0cnVlO1xuICAgICAgICB0aGlzLmNhbGxlZE9uY2UgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5jYWxsZWRUd2ljZSA9IGZhbHNlO1xuICAgICAgICB0aGlzLmNhbGxlZFRocmljZSA9IGZhbHNlO1xuICAgICAgICB0aGlzLmNhbGxDb3VudCA9IDA7XG4gICAgICAgIHRoaXMuZmlyc3RDYWxsID0gbnVsbDtcbiAgICAgICAgdGhpcy5zZWNvbmRDYWxsID0gbnVsbDtcbiAgICAgICAgdGhpcy50aGlyZENhbGwgPSBudWxsO1xuICAgICAgICB0aGlzLmxhc3RDYWxsID0gbnVsbDtcbiAgICAgICAgdGhpcy5hcmdzID0gW107XG4gICAgICAgIHRoaXMucmV0dXJuVmFsdWVzID0gW107XG4gICAgICAgIHRoaXMudGhpc1ZhbHVlcyA9IFtdO1xuICAgICAgICB0aGlzLmV4Y2VwdGlvbnMgPSBbXTtcbiAgICAgICAgdGhpcy5jYWxsSWRzID0gW107XG4gICAgICAgIHRoaXMuZXJyb3JzV2l0aENhbGxTdGFjayA9IFtdO1xuICAgICAgICBpZiAodGhpcy5mYWtlcykge1xuICAgICAgICAgICAgdGhpcy5mYWtlcy5mb3JFYWNoKGZ1bmN0aW9uIChmYWtlKSB7XG4gICAgICAgICAgICAgICAgZmFrZS5yZXNldCgpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuXG4gICAgY3JlYXRlOiBmdW5jdGlvbiBjcmVhdGUoZnVuYywgc3B5TGVuZ3RoKSB7XG4gICAgICAgIHZhciBuYW1lO1xuXG4gICAgICAgIGlmICh0eXBlb2YgZnVuYyAhPT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICBmdW5jID0gZnVuY3Rpb24gKCkgeyB9O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbmFtZSA9IGZ1bmN0aW9uTmFtZShmdW5jKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghc3B5TGVuZ3RoKSB7XG4gICAgICAgICAgICBzcHlMZW5ndGggPSBmdW5jLmxlbmd0aDtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBwcm94eSA9IGNyZWF0ZVByb3h5KGZ1bmMsIHNweUxlbmd0aCk7XG5cbiAgICAgICAgZXh0ZW5kKHByb3h5LCBzcHkpO1xuICAgICAgICBkZWxldGUgcHJveHkuY3JlYXRlO1xuICAgICAgICBleHRlbmQocHJveHksIGZ1bmMpO1xuXG4gICAgICAgIHByb3h5LnJlc2V0KCk7XG4gICAgICAgIHByb3h5LnByb3RvdHlwZSA9IGZ1bmMucHJvdG90eXBlO1xuICAgICAgICBwcm94eS5kaXNwbGF5TmFtZSA9IG5hbWUgfHwgXCJzcHlcIjtcbiAgICAgICAgcHJveHkudG9TdHJpbmcgPSBmdW5jdGlvblRvU3RyaW5nO1xuICAgICAgICBwcm94eS5pbnN0YW50aWF0ZUZha2UgPSBzcHkuY3JlYXRlO1xuICAgICAgICBwcm94eS5pZCA9IFwic3B5I1wiICsgdXVpZCsrO1xuXG4gICAgICAgIHJldHVybiBwcm94eTtcbiAgICB9LFxuXG4gICAgaW52b2tlOiBmdW5jdGlvbiBpbnZva2UoZnVuYywgdGhpc1ZhbHVlLCBhcmdzKSB7XG4gICAgICAgIHZhciBtYXRjaGluZyA9IG1hdGNoaW5nRmFrZSh0aGlzLmZha2VzLCBhcmdzKTtcbiAgICAgICAgdmFyIGV4Y2VwdGlvbiwgcmV0dXJuVmFsdWU7XG5cbiAgICAgICAgaW5jcmVtZW50Q2FsbENvdW50LmNhbGwodGhpcyk7XG4gICAgICAgIHB1c2guY2FsbCh0aGlzLnRoaXNWYWx1ZXMsIHRoaXNWYWx1ZSk7XG4gICAgICAgIHB1c2guY2FsbCh0aGlzLmFyZ3MsIGFyZ3MpO1xuICAgICAgICBwdXNoLmNhbGwodGhpcy5jYWxsSWRzLCBjYWxsSWQrKyk7XG5cbiAgICAgICAgLy8gTWFrZSBjYWxsIHByb3BlcnRpZXMgYXZhaWxhYmxlIGZyb20gd2l0aGluIHRoZSBzcGllZCBmdW5jdGlvbjpcbiAgICAgICAgY3JlYXRlQ2FsbFByb3BlcnRpZXMuY2FsbCh0aGlzKTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgdGhpcy5pbnZva2luZyA9IHRydWU7XG5cbiAgICAgICAgICAgIGlmIChtYXRjaGluZykge1xuICAgICAgICAgICAgICAgIHJldHVyblZhbHVlID0gbWF0Y2hpbmcuaW52b2tlKGZ1bmMsIHRoaXNWYWx1ZSwgYXJncyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVyblZhbHVlID0gKHRoaXMuZnVuYyB8fCBmdW5jKS5hcHBseSh0aGlzVmFsdWUsIGFyZ3MpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgdGhpc0NhbGwgPSB0aGlzLmdldENhbGwodGhpcy5jYWxsQ291bnQgLSAxKTtcbiAgICAgICAgICAgIGlmICh0aGlzQ2FsbC5jYWxsZWRXaXRoTmV3KCkgJiYgdHlwZW9mIHJldHVyblZhbHVlICE9PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuVmFsdWUgPSB0aGlzVmFsdWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGV4Y2VwdGlvbiA9IGU7XG4gICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgICBkZWxldGUgdGhpcy5pbnZva2luZztcbiAgICAgICAgfVxuXG4gICAgICAgIHB1c2guY2FsbCh0aGlzLmV4Y2VwdGlvbnMsIGV4Y2VwdGlvbik7XG4gICAgICAgIHB1c2guY2FsbCh0aGlzLnJldHVyblZhbHVlcywgcmV0dXJuVmFsdWUpO1xuICAgICAgICB2YXIgZXJyID0gbmV3IEVycm9yQ29uc3RydWN0b3IoKTtcbiAgICAgICAgLy8gMS4gUGxlYXNlIGRvIG5vdCBnZXQgc3RhY2sgYXQgdGhpcyBwb2ludC4gSXQncyBtYXkgYmUgc28gdmVyeSBzbG93LCBhbmQgbm90IGFjdHVhbGx5IHVzZWRcbiAgICAgICAgLy8gMi4gUGhhbnRvbUpTIGRvZXMgbm90IHNlcmlhbGl6ZSB0aGUgc3RhY2sgdHJhY2UgdW50aWwgdGhlIGVycm9yIGhhcyBiZWVuIHRocm93bjpcbiAgICAgICAgLy8gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvRXJyb3IvU3RhY2tcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgfSBjYXRjaCAoZSkgey8qIGVtcHR5ICovfVxuICAgICAgICBwdXNoLmNhbGwodGhpcy5lcnJvcnNXaXRoQ2FsbFN0YWNrLCBlcnIpO1xuXG4gICAgICAgIC8vIE1ha2UgcmV0dXJuIHZhbHVlIGFuZCBleGNlcHRpb24gYXZhaWxhYmxlIGluIHRoZSBjYWxsczpcbiAgICAgICAgY3JlYXRlQ2FsbFByb3BlcnRpZXMuY2FsbCh0aGlzKTtcblxuICAgICAgICBpZiAoZXhjZXB0aW9uICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIHRocm93IGV4Y2VwdGlvbjtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXR1cm5WYWx1ZTtcbiAgICB9LFxuXG4gICAgbmFtZWQ6IGZ1bmN0aW9uIG5hbWVkKG5hbWUpIHtcbiAgICAgICAgdGhpcy5kaXNwbGF5TmFtZSA9IG5hbWU7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICBnZXRDYWxsOiBmdW5jdGlvbiBnZXRDYWxsKGkpIHtcbiAgICAgICAgaWYgKGkgPCAwIHx8IGkgPj0gdGhpcy5jYWxsQ291bnQpIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHNweUNhbGwodGhpcywgdGhpcy50aGlzVmFsdWVzW2ldLCB0aGlzLmFyZ3NbaV0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucmV0dXJuVmFsdWVzW2ldLCB0aGlzLmV4Y2VwdGlvbnNbaV0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2FsbElkc1tpXSwgdGhpcy5lcnJvcnNXaXRoQ2FsbFN0YWNrW2ldKTtcbiAgICB9LFxuXG4gICAgZ2V0Q2FsbHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGNhbGxzID0gW107XG4gICAgICAgIHZhciBpO1xuXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCB0aGlzLmNhbGxDb3VudDsgaSsrKSB7XG4gICAgICAgICAgICBjYWxscy5wdXNoKHRoaXMuZ2V0Q2FsbChpKSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gY2FsbHM7XG4gICAgfSxcblxuICAgIGNhbGxlZEJlZm9yZTogZnVuY3Rpb24gY2FsbGVkQmVmb3JlKHNweUZuKSB7XG4gICAgICAgIGlmICghdGhpcy5jYWxsZWQpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghc3B5Rm4uY2FsbGVkKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzLmNhbGxJZHNbMF0gPCBzcHlGbi5jYWxsSWRzW3NweUZuLmNhbGxJZHMubGVuZ3RoIC0gMV07XG4gICAgfSxcblxuICAgIGNhbGxlZEFmdGVyOiBmdW5jdGlvbiBjYWxsZWRBZnRlcihzcHlGbikge1xuICAgICAgICBpZiAoIXRoaXMuY2FsbGVkIHx8ICFzcHlGbi5jYWxsZWQpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aGlzLmNhbGxJZHNbdGhpcy5jYWxsQ291bnQgLSAxXSA+IHNweUZuLmNhbGxJZHNbc3B5Rm4uY2FsbENvdW50IC0gMV07XG4gICAgfSxcblxuICAgIHdpdGhBcmdzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBhcmdzID0gc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuXG4gICAgICAgIGlmICh0aGlzLmZha2VzKSB7XG4gICAgICAgICAgICB2YXIgbWF0Y2ggPSBtYXRjaGluZ0Zha2UodGhpcy5mYWtlcywgYXJncywgdHJ1ZSk7XG5cbiAgICAgICAgICAgIGlmIChtYXRjaCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBtYXRjaDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuZmFrZXMgPSBbXTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBvcmlnaW5hbCA9IHRoaXM7XG4gICAgICAgIHZhciBmYWtlID0gdGhpcy5pbnN0YW50aWF0ZUZha2UoKTtcbiAgICAgICAgZmFrZS5tYXRjaGluZ0FyZ3VtZW50cyA9IGFyZ3M7XG4gICAgICAgIGZha2UucGFyZW50ID0gdGhpcztcbiAgICAgICAgcHVzaC5jYWxsKHRoaXMuZmFrZXMsIGZha2UpO1xuXG4gICAgICAgIGZha2Uud2l0aEFyZ3MgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gb3JpZ2luYWwud2l0aEFyZ3MuYXBwbHkob3JpZ2luYWwsIGFyZ3VtZW50cyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgb3JpZ2luYWwuYXJncy5mb3JFYWNoKGZ1bmN0aW9uIChhcmcsIGkpIHtcbiAgICAgICAgICAgIGlmICghZmFrZS5tYXRjaGVzKGFyZykpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGluY3JlbWVudENhbGxDb3VudC5jYWxsKGZha2UpO1xuICAgICAgICAgICAgcHVzaC5jYWxsKGZha2UudGhpc1ZhbHVlcywgb3JpZ2luYWwudGhpc1ZhbHVlc1tpXSk7XG4gICAgICAgICAgICBwdXNoLmNhbGwoZmFrZS5hcmdzLCBhcmcpO1xuICAgICAgICAgICAgcHVzaC5jYWxsKGZha2UucmV0dXJuVmFsdWVzLCBvcmlnaW5hbC5yZXR1cm5WYWx1ZXNbaV0pO1xuICAgICAgICAgICAgcHVzaC5jYWxsKGZha2UuZXhjZXB0aW9ucywgb3JpZ2luYWwuZXhjZXB0aW9uc1tpXSk7XG4gICAgICAgICAgICBwdXNoLmNhbGwoZmFrZS5jYWxsSWRzLCBvcmlnaW5hbC5jYWxsSWRzW2ldKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgY3JlYXRlQ2FsbFByb3BlcnRpZXMuY2FsbChmYWtlKTtcblxuICAgICAgICByZXR1cm4gZmFrZTtcbiAgICB9LFxuXG4gICAgbWF0Y2hlczogZnVuY3Rpb24gKGFyZ3MsIHN0cmljdCkge1xuICAgICAgICB2YXIgbWFyZ3MgPSB0aGlzLm1hdGNoaW5nQXJndW1lbnRzO1xuXG4gICAgICAgIGlmIChtYXJncy5sZW5ndGggPD0gYXJncy5sZW5ndGggJiZcbiAgICAgICAgICAgIGRlZXBFcXVhbChtYXJncywgYXJncy5zbGljZSgwLCBtYXJncy5sZW5ndGgpKSkge1xuICAgICAgICAgICAgcmV0dXJuICFzdHJpY3QgfHwgbWFyZ3MubGVuZ3RoID09PSBhcmdzLmxlbmd0aDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfSxcblxuICAgIHByaW50ZjogZnVuY3Rpb24gKGZvcm1hdCkge1xuICAgICAgICB2YXIgc3B5SW5zdGFuY2UgPSB0aGlzO1xuICAgICAgICB2YXIgYXJncyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICAgICAgdmFyIGZvcm1hdHRlcjtcblxuICAgICAgICByZXR1cm4gKGZvcm1hdCB8fCBcIlwiKS5yZXBsYWNlKC8lKC4pL2csIGZ1bmN0aW9uIChtYXRjaCwgc3BlY2lmeWVyKSB7XG4gICAgICAgICAgICBmb3JtYXR0ZXIgPSBzcHlBcGkuZm9ybWF0dGVyc1tzcGVjaWZ5ZXJdO1xuXG4gICAgICAgICAgICBpZiAodHlwZW9mIGZvcm1hdHRlciA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZvcm1hdHRlci5jYWxsKG51bGwsIHNweUluc3RhbmNlLCBhcmdzKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoIWlzTmFOKHBhcnNlSW50KHNwZWNpZnllciwgMTApKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBzaW5vbkZvcm1hdChhcmdzW3NwZWNpZnllciAtIDFdKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIFwiJVwiICsgc3BlY2lmeWVyO1xuICAgICAgICB9KTtcbiAgICB9XG59O1xuXG5mdW5jdGlvbiBkZWxlZ2F0ZVRvQ2FsbHMobWV0aG9kLCBtYXRjaEFueSwgYWN0dWFsLCBub3RDYWxsZWQpIHtcbiAgICBzcHlBcGlbbWV0aG9kXSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCF0aGlzLmNhbGxlZCkge1xuICAgICAgICAgICAgaWYgKG5vdENhbGxlZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBub3RDYWxsZWQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBjdXJyZW50Q2FsbDtcbiAgICAgICAgdmFyIG1hdGNoZXMgPSAwO1xuXG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBsID0gdGhpcy5jYWxsQ291bnQ7IGkgPCBsOyBpICs9IDEpIHtcbiAgICAgICAgICAgIGN1cnJlbnRDYWxsID0gdGhpcy5nZXRDYWxsKGkpO1xuXG4gICAgICAgICAgICBpZiAoY3VycmVudENhbGxbYWN0dWFsIHx8IG1ldGhvZF0uYXBwbHkoY3VycmVudENhbGwsIGFyZ3VtZW50cykpIHtcbiAgICAgICAgICAgICAgICBtYXRjaGVzICs9IDE7XG5cbiAgICAgICAgICAgICAgICBpZiAobWF0Y2hBbnkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG1hdGNoZXMgPT09IHRoaXMuY2FsbENvdW50O1xuICAgIH07XG59XG5cbmRlbGVnYXRlVG9DYWxscyhcImNhbGxlZE9uXCIsIHRydWUpO1xuZGVsZWdhdGVUb0NhbGxzKFwiYWx3YXlzQ2FsbGVkT25cIiwgZmFsc2UsIFwiY2FsbGVkT25cIik7XG5kZWxlZ2F0ZVRvQ2FsbHMoXCJjYWxsZWRXaXRoXCIsIHRydWUpO1xuZGVsZWdhdGVUb0NhbGxzKFwiY2FsbGVkV2l0aE1hdGNoXCIsIHRydWUpO1xuZGVsZWdhdGVUb0NhbGxzKFwiYWx3YXlzQ2FsbGVkV2l0aFwiLCBmYWxzZSwgXCJjYWxsZWRXaXRoXCIpO1xuZGVsZWdhdGVUb0NhbGxzKFwiYWx3YXlzQ2FsbGVkV2l0aE1hdGNoXCIsIGZhbHNlLCBcImNhbGxlZFdpdGhNYXRjaFwiKTtcbmRlbGVnYXRlVG9DYWxscyhcImNhbGxlZFdpdGhFeGFjdGx5XCIsIHRydWUpO1xuZGVsZWdhdGVUb0NhbGxzKFwiYWx3YXlzQ2FsbGVkV2l0aEV4YWN0bHlcIiwgZmFsc2UsIFwiY2FsbGVkV2l0aEV4YWN0bHlcIik7XG5kZWxlZ2F0ZVRvQ2FsbHMoXCJuZXZlckNhbGxlZFdpdGhcIiwgZmFsc2UsIFwibm90Q2FsbGVkV2l0aFwiLCBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRydWU7XG59KTtcbmRlbGVnYXRlVG9DYWxscyhcIm5ldmVyQ2FsbGVkV2l0aE1hdGNoXCIsIGZhbHNlLCBcIm5vdENhbGxlZFdpdGhNYXRjaFwiLCBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRydWU7XG59KTtcbmRlbGVnYXRlVG9DYWxscyhcInRocmV3XCIsIHRydWUpO1xuZGVsZWdhdGVUb0NhbGxzKFwiYWx3YXlzVGhyZXdcIiwgZmFsc2UsIFwidGhyZXdcIik7XG5kZWxlZ2F0ZVRvQ2FsbHMoXCJyZXR1cm5lZFwiLCB0cnVlKTtcbmRlbGVnYXRlVG9DYWxscyhcImFsd2F5c1JldHVybmVkXCIsIGZhbHNlLCBcInJldHVybmVkXCIpO1xuZGVsZWdhdGVUb0NhbGxzKFwiY2FsbGVkV2l0aE5ld1wiLCB0cnVlKTtcbmRlbGVnYXRlVG9DYWxscyhcImFsd2F5c0NhbGxlZFdpdGhOZXdcIiwgZmFsc2UsIFwiY2FsbGVkV2l0aE5ld1wiKTtcbmRlbGVnYXRlVG9DYWxscyhcImNhbGxBcmdcIiwgZmFsc2UsIFwiY2FsbEFyZ1dpdGhcIiwgZnVuY3Rpb24gKCkge1xuICAgIHRocm93IG5ldyBFcnJvcih0aGlzLnRvU3RyaW5nKCkgKyBcIiBjYW5ub3QgY2FsbCBhcmcgc2luY2UgaXQgd2FzIG5vdCB5ZXQgaW52b2tlZC5cIik7XG59KTtcbnNweUFwaS5jYWxsQXJnV2l0aCA9IHNweUFwaS5jYWxsQXJnO1xuZGVsZWdhdGVUb0NhbGxzKFwiY2FsbEFyZ09uXCIsIGZhbHNlLCBcImNhbGxBcmdPbldpdGhcIiwgZnVuY3Rpb24gKCkge1xuICAgIHRocm93IG5ldyBFcnJvcih0aGlzLnRvU3RyaW5nKCkgKyBcIiBjYW5ub3QgY2FsbCBhcmcgc2luY2UgaXQgd2FzIG5vdCB5ZXQgaW52b2tlZC5cIik7XG59KTtcbnNweUFwaS5jYWxsQXJnT25XaXRoID0gc3B5QXBpLmNhbGxBcmdPbjtcbmRlbGVnYXRlVG9DYWxscyhcInlpZWxkXCIsIGZhbHNlLCBcInlpZWxkXCIsIGZ1bmN0aW9uICgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IodGhpcy50b1N0cmluZygpICsgXCIgY2Fubm90IHlpZWxkIHNpbmNlIGl0IHdhcyBub3QgeWV0IGludm9rZWQuXCIpO1xufSk7XG4vLyBcImludm9rZUNhbGxiYWNrXCIgaXMgYW4gYWxpYXMgZm9yIFwieWllbGRcIiBzaW5jZSBcInlpZWxkXCIgaXMgaW52YWxpZCBpbiBzdHJpY3QgbW9kZS5cbnNweUFwaS5pbnZva2VDYWxsYmFjayA9IHNweUFwaS55aWVsZDtcbmRlbGVnYXRlVG9DYWxscyhcInlpZWxkT25cIiwgZmFsc2UsIFwieWllbGRPblwiLCBmdW5jdGlvbiAoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKHRoaXMudG9TdHJpbmcoKSArIFwiIGNhbm5vdCB5aWVsZCBzaW5jZSBpdCB3YXMgbm90IHlldCBpbnZva2VkLlwiKTtcbn0pO1xuZGVsZWdhdGVUb0NhbGxzKFwieWllbGRUb1wiLCBmYWxzZSwgXCJ5aWVsZFRvXCIsIGZ1bmN0aW9uIChwcm9wZXJ0eSkge1xuICAgIHRocm93IG5ldyBFcnJvcih0aGlzLnRvU3RyaW5nKCkgKyBcIiBjYW5ub3QgeWllbGQgdG8gJ1wiICsgdmFsdWVUb1N0cmluZyhwcm9wZXJ0eSkgK1xuICAgICAgICBcIicgc2luY2UgaXQgd2FzIG5vdCB5ZXQgaW52b2tlZC5cIik7XG59KTtcbmRlbGVnYXRlVG9DYWxscyhcInlpZWxkVG9PblwiLCBmYWxzZSwgXCJ5aWVsZFRvT25cIiwgZnVuY3Rpb24gKHByb3BlcnR5KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKHRoaXMudG9TdHJpbmcoKSArIFwiIGNhbm5vdCB5aWVsZCB0byAnXCIgKyB2YWx1ZVRvU3RyaW5nKHByb3BlcnR5KSArXG4gICAgICAgIFwiJyBzaW5jZSBpdCB3YXMgbm90IHlldCBpbnZva2VkLlwiKTtcbn0pO1xuXG5leHRlbmQoc3B5LCBzcHlBcGkpO1xuc3B5LnNweUNhbGwgPSBzcHlDYWxsO1xubW9kdWxlLmV4cG9ydHMgPSBzcHk7XG4iLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIGRlcHJlY2F0ZWQgPSByZXF1aXJlKFwiLi91dGlsL2NvcmUvZGVwcmVjYXRlZFwiKTtcbnZhciBzcHkgPSByZXF1aXJlKFwiLi9zcHlcIik7XG52YXIgd3JhcE1ldGhvZCA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS93cmFwLW1ldGhvZFwiKTtcblxuLy8gVGhpcyBpcyBkZXByZWNhdGVkIGFuZCB3aWxsIGJlIHJlbW92ZWQgaW4gYSBmdXR1cmUgdmVyc2lvbiBvZiBzaW5vbi5cbi8vIFdlIHdpbGwgb25seSBjb25zaWRlciBwdWxsIHJlcXVlc3RzIHRoYXQgZml4IHNlcmlvdXMgYnVncyBpbiB0aGUgaW1wbGVtZW50YXRpb25cbmZ1bmN0aW9uIHN0dWJEZXNjcmlwdG9yKG9iamVjdCwgcHJvcGVydHksIGRlc2NyaXB0b3IpIHtcbiAgICB2YXIgd3JhcHBlcjtcblxuICAgIGRlcHJlY2F0ZWQucHJpbnRXYXJuaW5nKFxuICAgICAgXCJzaW5vbi5zdHViKG9iaiwgJ21ldGgnLCBmbikgaXMgZGVwcmVjYXRlZCBhbmQgd2lsbCBiZSByZW1vdmVkIGZyb21cIiArXG4gICAgICBcInRoZSBwdWJsaWMgQVBJIGluIGEgZnV0dXJlIHZlcnNpb24gb2Ygc2lub24uXCIgK1xuICAgICAgXCJcXG4gVXNlIHN0dWIob2JqLCAnbWV0aCcpLmNhbGxzRmFrZShmbikuXCIgK1xuICAgICAgXCJcXG4gQ29kZW1vZCBhdmFpbGFibGUgYXQgaHR0cHM6Ly9naXRodWIuY29tL2h1cnJ5bWFwbGVsYWQvc2lub24tY29kZW1vZFwiXG4gICAgKTtcblxuICAgIGlmICghIWRlc2NyaXB0b3IgJiYgdHlwZW9mIGRlc2NyaXB0b3IgIT09IFwiZnVuY3Rpb25cIiAmJiB0eXBlb2YgZGVzY3JpcHRvciAhPT0gXCJvYmplY3RcIikge1xuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiQ3VzdG9tIHN0dWIgc2hvdWxkIGJlIGEgcHJvcGVydHkgZGVzY3JpcHRvclwiKTtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIGRlc2NyaXB0b3IgPT09IFwib2JqZWN0XCIgJiYgT2JqZWN0LmtleXMoZGVzY3JpcHRvcikubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJFeHBlY3RlZCBwcm9wZXJ0eSBkZXNjcmlwdG9yIHRvIGhhdmUgYXQgbGVhc3Qgb25lIGtleVwiKTtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIGRlc2NyaXB0b3IgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICB3cmFwcGVyID0gc3B5ICYmIHNweS5jcmVhdGUgPyBzcHkuY3JlYXRlKGRlc2NyaXB0b3IpIDogZGVzY3JpcHRvcjtcbiAgICB9IGVsc2Uge1xuICAgICAgICB3cmFwcGVyID0gZGVzY3JpcHRvcjtcbiAgICAgICAgaWYgKHNweSAmJiBzcHkuY3JlYXRlKSB7XG4gICAgICAgICAgICBPYmplY3Qua2V5cyh3cmFwcGVyKS5mb3JFYWNoKGZ1bmN0aW9uICh0eXBlKSB7XG4gICAgICAgICAgICAgICAgd3JhcHBlclt0eXBlXSA9IHNweS5jcmVhdGUod3JhcHBlclt0eXBlXSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB3cmFwTWV0aG9kKG9iamVjdCwgcHJvcGVydHksIHdyYXBwZXIpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHN0dWJEZXNjcmlwdG9yO1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBnZXRQcm9wZXJ0eURlc2NyaXB0b3IgPSByZXF1aXJlKFwiLi91dGlsL2NvcmUvZ2V0LXByb3BlcnR5LWRlc2NyaXB0b3JcIik7XG52YXIgd2FsayA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS93YWxrXCIpO1xuXG5mdW5jdGlvbiBzdHViRW50aXJlT2JqZWN0KHN0dWIsIG9iamVjdCkge1xuICAgIHdhbGsob2JqZWN0IHx8IHt9LCBmdW5jdGlvbiAocHJvcCwgcHJvcE93bmVyKSB7XG4gICAgICAgIC8vIHdlIGRvbid0IHdhbnQgdG8gc3R1YiB0aGluZ3MgbGlrZSB0b1N0cmluZygpLCB2YWx1ZU9mKCksIGV0Yy4gc28gd2Ugb25seSBzdHViIGlmIHRoZSBvYmplY3RcbiAgICAgICAgLy8gaXMgbm90IE9iamVjdC5wcm90b3R5cGVcbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgcHJvcE93bmVyICE9PSBPYmplY3QucHJvdG90eXBlICYmXG4gICAgICAgICAgICBwcm9wICE9PSBcImNvbnN0cnVjdG9yXCIgJiZcbiAgICAgICAgICAgIHR5cGVvZiBnZXRQcm9wZXJ0eURlc2NyaXB0b3IocHJvcE93bmVyLCBwcm9wKS52YWx1ZSA9PT0gXCJmdW5jdGlvblwiXG4gICAgICAgICkge1xuICAgICAgICAgICAgc3R1YihvYmplY3QsIHByb3ApO1xuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICByZXR1cm4gb2JqZWN0O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHN0dWJFbnRpcmVPYmplY3Q7XG4iLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIHZhbHVlVG9TdHJpbmcgPSByZXF1aXJlKFwiLi91dGlsL2NvcmUvdmFsdWUtdG8tc3RyaW5nXCIpO1xudmFyIGhhc093blByb3BlcnR5ID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eTtcblxuZnVuY3Rpb24gc3R1Yk5vbkZ1bmN0aW9uUHJvcGVydHkob2JqZWN0LCBwcm9wZXJ0eSwgdmFsdWUpIHtcbiAgICB2YXIgb3JpZ2luYWwgPSBvYmplY3RbcHJvcGVydHldO1xuXG4gICAgaWYgKCFoYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdCwgcHJvcGVydHkpKSB7XG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJDYW5ub3Qgc3R1YiBub24tZXhpc3RlbnQgb3duIHByb3BlcnR5IFwiICsgdmFsdWVUb1N0cmluZyhwcm9wZXJ0eSkpO1xuICAgIH1cblxuICAgIG9iamVjdFtwcm9wZXJ0eV0gPSB2YWx1ZTtcblxuICAgIHJldHVybiB7XG4gICAgICAgIHJlc3RvcmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIG9iamVjdFtwcm9wZXJ0eV0gPSBvcmlnaW5hbDtcbiAgICAgICAgfVxuICAgIH07XG59XG5cbm1vZHVsZS5leHBvcnRzID0gc3R1Yk5vbkZ1bmN0aW9uUHJvcGVydHk7XG4iLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIGJlaGF2aW9yID0gcmVxdWlyZShcIi4vYmVoYXZpb3JcIik7XG52YXIgYmVoYXZpb3JzID0gcmVxdWlyZShcIi4vZGVmYXVsdC1iZWhhdmlvcnNcIik7XG52YXIgc3B5ID0gcmVxdWlyZShcIi4vc3B5XCIpO1xudmFyIGV4dGVuZCA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS9leHRlbmRcIik7XG52YXIgZnVuY3Rpb25Ub1N0cmluZyA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZS9mdW5jdGlvbi10by1zdHJpbmdcIik7XG52YXIgZ2V0UHJvcGVydHlEZXNjcmlwdG9yID0gcmVxdWlyZShcIi4vdXRpbC9jb3JlL2dldC1wcm9wZXJ0eS1kZXNjcmlwdG9yXCIpO1xudmFyIHdyYXBNZXRob2QgPSByZXF1aXJlKFwiLi91dGlsL2NvcmUvd3JhcC1tZXRob2RcIik7XG52YXIgc3R1YkVudGlyZU9iamVjdCA9IHJlcXVpcmUoXCIuL3N0dWItZW50aXJlLW9iamVjdFwiKTtcbnZhciBzdHViRGVzY3JpcHRvciA9IHJlcXVpcmUoXCIuL3N0dWItZGVzY3JpcHRvclwiKTtcbnZhciB0aHJvd09uRmFsc3lPYmplY3QgPSByZXF1aXJlKFwiLi90aHJvdy1vbi1mYWxzeS1vYmplY3RcIik7XG5cbmZ1bmN0aW9uIHN0dWIob2JqZWN0LCBwcm9wZXJ0eSwgZGVzY3JpcHRvcikge1xuICAgIHRocm93T25GYWxzeU9iamVjdC5hcHBseShudWxsLCBhcmd1bWVudHMpO1xuXG4gICAgdmFyIGFjdHVhbERlc2NyaXB0b3IgPSBnZXRQcm9wZXJ0eURlc2NyaXB0b3Iob2JqZWN0LCBwcm9wZXJ0eSk7XG4gICAgdmFyIGlzU3R1YmJpbmdFbnRpcmVPYmplY3QgPSB0eXBlb2YgcHJvcGVydHkgPT09IFwidW5kZWZpbmVkXCIgJiYgdHlwZW9mIG9iamVjdCA9PT0gXCJvYmplY3RcIjtcbiAgICB2YXIgaXNDcmVhdGluZ05ld1N0dWIgPSAhb2JqZWN0ICYmIHR5cGVvZiBwcm9wZXJ0eSA9PT0gXCJ1bmRlZmluZWRcIjtcbiAgICB2YXIgaXNTdHViYmluZ0Rlc2NyaXB0b3IgPSBvYmplY3QgJiYgcHJvcGVydHkgJiYgQm9vbGVhbihkZXNjcmlwdG9yKTtcbiAgICB2YXIgaXNTdHViYmluZ05vbkZ1bmNQcm9wZXJ0eSA9IHR5cGVvZiBvYmplY3QgPT09IFwib2JqZWN0XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICYmIHR5cGVvZiBwcm9wZXJ0eSAhPT0gXCJ1bmRlZmluZWRcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJiYgKHR5cGVvZiBhY3R1YWxEZXNjcmlwdG9yID09PSBcInVuZGVmaW5lZFwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8fCB0eXBlb2YgYWN0dWFsRGVzY3JpcHRvci52YWx1ZSAhPT0gXCJmdW5jdGlvblwiKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJiYgdHlwZW9mIGRlc2NyaXB0b3IgPT09IFwidW5kZWZpbmVkXCI7XG4gICAgdmFyIGlzU3R1YmJpbmdFeGlzdGluZ01ldGhvZCA9ICFpc1N0dWJiaW5nRGVzY3JpcHRvclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJiYgdHlwZW9mIG9iamVjdCA9PT0gXCJvYmplY3RcIlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJiYgdHlwZW9mIGFjdHVhbERlc2NyaXB0b3IgIT09IFwidW5kZWZpbmVkXCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICYmIHR5cGVvZiBhY3R1YWxEZXNjcmlwdG9yLnZhbHVlID09PSBcImZ1bmN0aW9uXCI7XG4gICAgdmFyIGFyaXR5ID0gaXNTdHViYmluZ0V4aXN0aW5nTWV0aG9kID8gb2JqZWN0W3Byb3BlcnR5XS5sZW5ndGggOiAwO1xuXG4gICAgaWYgKGlzU3R1YmJpbmdFbnRpcmVPYmplY3QpIHtcbiAgICAgICAgcmV0dXJuIHN0dWJFbnRpcmVPYmplY3Qoc3R1Yiwgb2JqZWN0KTtcbiAgICB9XG5cbiAgICBpZiAoaXNTdHViYmluZ0Rlc2NyaXB0b3IpIHtcbiAgICAgICAgcmV0dXJuIHN0dWJEZXNjcmlwdG9yLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7XG4gICAgfVxuXG4gICAgaWYgKGlzQ3JlYXRpbmdOZXdTdHViKSB7XG4gICAgICAgIHJldHVybiBzdHViLmNyZWF0ZSgpO1xuICAgIH1cblxuICAgIHZhciBzID0gc3R1Yi5jcmVhdGUoYXJpdHkpO1xuICAgIHMucm9vdE9iaiA9IG9iamVjdDtcbiAgICBzLnByb3BOYW1lID0gcHJvcGVydHk7XG4gICAgcy5yZXN0b3JlID0gZnVuY3Rpb24gcmVzdG9yZSgpIHtcbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG9iamVjdCwgcHJvcGVydHksIGFjdHVhbERlc2NyaXB0b3IpO1xuICAgIH07XG5cbiAgICByZXR1cm4gaXNTdHViYmluZ05vbkZ1bmNQcm9wZXJ0eSA/IHMgOiB3cmFwTWV0aG9kKG9iamVjdCwgcHJvcGVydHksIHMpO1xufVxuXG5zdHViLmNyZWF0ZVN0dWJJbnN0YW5jZSA9IGZ1bmN0aW9uIChjb25zdHJ1Y3Rvcikge1xuICAgIGlmICh0eXBlb2YgY29uc3RydWN0b3IgIT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiVGhlIGNvbnN0cnVjdG9yIHNob3VsZCBiZSBhIGZ1bmN0aW9uLlwiKTtcbiAgICB9XG4gICAgcmV0dXJuIHN0dWIoT2JqZWN0LmNyZWF0ZShjb25zdHJ1Y3Rvci5wcm90b3R5cGUpKTtcbn07XG5cbi8qZXNsaW50LWRpc2FibGUgbm8tdXNlLWJlZm9yZS1kZWZpbmUqL1xuZnVuY3Rpb24gZ2V0UGFyZW50QmVoYXZpb3VyKHN0dWJJbnN0YW5jZSkge1xuICAgIHJldHVybiAoc3R1Ykluc3RhbmNlLnBhcmVudCAmJiBnZXRDdXJyZW50QmVoYXZpb3Ioc3R1Ykluc3RhbmNlLnBhcmVudCkpO1xufVxuXG5mdW5jdGlvbiBnZXREZWZhdWx0QmVoYXZpb3Ioc3R1Ykluc3RhbmNlKSB7XG4gICAgcmV0dXJuIHN0dWJJbnN0YW5jZS5kZWZhdWx0QmVoYXZpb3IgfHxcbiAgICAgICAgICAgIGdldFBhcmVudEJlaGF2aW91cihzdHViSW5zdGFuY2UpIHx8XG4gICAgICAgICAgICBiZWhhdmlvci5jcmVhdGUoc3R1Ykluc3RhbmNlKTtcbn1cblxuZnVuY3Rpb24gZ2V0Q3VycmVudEJlaGF2aW9yKHN0dWJJbnN0YW5jZSkge1xuICAgIHZhciBjdXJyZW50QmVoYXZpb3IgPSBzdHViSW5zdGFuY2UuYmVoYXZpb3JzW3N0dWJJbnN0YW5jZS5jYWxsQ291bnQgLSAxXTtcbiAgICByZXR1cm4gY3VycmVudEJlaGF2aW9yICYmIGN1cnJlbnRCZWhhdmlvci5pc1ByZXNlbnQoKSA/IGN1cnJlbnRCZWhhdmlvciA6IGdldERlZmF1bHRCZWhhdmlvcihzdHViSW5zdGFuY2UpO1xufVxuLyplc2xpbnQtZW5hYmxlIG5vLXVzZS1iZWZvcmUtZGVmaW5lKi9cblxudmFyIHV1aWQgPSAwO1xuXG52YXIgcHJvdG8gPSB7XG4gICAgY3JlYXRlOiBmdW5jdGlvbiBjcmVhdGUoc3R1Ykxlbmd0aCkge1xuICAgICAgICB2YXIgZnVuY3Rpb25TdHViID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGdldEN1cnJlbnRCZWhhdmlvcihmdW5jdGlvblN0dWIpLmludm9rZSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICB9O1xuXG4gICAgICAgIGZ1bmN0aW9uU3R1Yi5pZCA9IFwic3R1YiNcIiArIHV1aWQrKztcbiAgICAgICAgdmFyIG9yaWcgPSBmdW5jdGlvblN0dWI7XG4gICAgICAgIGZ1bmN0aW9uU3R1YiA9IHNweS5jcmVhdGUoZnVuY3Rpb25TdHViLCBzdHViTGVuZ3RoKTtcbiAgICAgICAgZnVuY3Rpb25TdHViLmZ1bmMgPSBvcmlnO1xuXG4gICAgICAgIGV4dGVuZChmdW5jdGlvblN0dWIsIHN0dWIpO1xuICAgICAgICBmdW5jdGlvblN0dWIuaW5zdGFudGlhdGVGYWtlID0gc3R1Yi5jcmVhdGU7XG4gICAgICAgIGZ1bmN0aW9uU3R1Yi5kaXNwbGF5TmFtZSA9IFwic3R1YlwiO1xuICAgICAgICBmdW5jdGlvblN0dWIudG9TdHJpbmcgPSBmdW5jdGlvblRvU3RyaW5nO1xuXG4gICAgICAgIGZ1bmN0aW9uU3R1Yi5kZWZhdWx0QmVoYXZpb3IgPSBudWxsO1xuICAgICAgICBmdW5jdGlvblN0dWIuYmVoYXZpb3JzID0gW107XG5cbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uU3R1YjtcbiAgICB9LFxuXG4gICAgcmVzZXRCZWhhdmlvcjogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgZmFrZXMgPSB0aGlzLmZha2VzIHx8IFtdO1xuXG4gICAgICAgIHRoaXMuZGVmYXVsdEJlaGF2aW9yID0gbnVsbDtcbiAgICAgICAgdGhpcy5iZWhhdmlvcnMgPSBbXTtcblxuICAgICAgICBkZWxldGUgdGhpcy5yZXR1cm5WYWx1ZTtcbiAgICAgICAgZGVsZXRlIHRoaXMucmV0dXJuQXJnQXQ7XG4gICAgICAgIGRlbGV0ZSB0aGlzLmZha2VGbjtcbiAgICAgICAgdGhpcy5yZXR1cm5UaGlzID0gZmFsc2U7XG5cbiAgICAgICAgZmFrZXMuZm9yRWFjaChmdW5jdGlvbiAoZmFrZSkge1xuICAgICAgICAgICAgZmFrZS5yZXNldEJlaGF2aW9yKCk7XG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICByZXNldEhpc3Rvcnk6IHNweS5yZXNldCxcblxuICAgIHJlc2V0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMucmVzZXRIaXN0b3J5KCk7XG4gICAgICAgIHRoaXMucmVzZXRCZWhhdmlvcigpO1xuICAgIH0sXG5cbiAgICBvbkNhbGw6IGZ1bmN0aW9uIG9uQ2FsbChpbmRleCkge1xuICAgICAgICBpZiAoIXRoaXMuYmVoYXZpb3JzW2luZGV4XSkge1xuICAgICAgICAgICAgdGhpcy5iZWhhdmlvcnNbaW5kZXhdID0gYmVoYXZpb3IuY3JlYXRlKHRoaXMpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuYmVoYXZpb3JzW2luZGV4XTtcbiAgICB9LFxuXG4gICAgb25GaXJzdENhbGw6IGZ1bmN0aW9uIG9uRmlyc3RDYWxsKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5vbkNhbGwoMCk7XG4gICAgfSxcblxuICAgIG9uU2Vjb25kQ2FsbDogZnVuY3Rpb24gb25TZWNvbmRDYWxsKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5vbkNhbGwoMSk7XG4gICAgfSxcblxuICAgIG9uVGhpcmRDYWxsOiBmdW5jdGlvbiBvblRoaXJkQ2FsbCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub25DYWxsKDIpO1xuICAgIH1cbn07XG5cbk9iamVjdC5rZXlzKGJlaGF2aW9yKS5mb3JFYWNoKGZ1bmN0aW9uIChtZXRob2QpIHtcbiAgICBpZiAoYmVoYXZpb3IuaGFzT3duUHJvcGVydHkobWV0aG9kKSAmJlxuICAgICAgICAhcHJvdG8uaGFzT3duUHJvcGVydHkobWV0aG9kKSAmJlxuICAgICAgICBtZXRob2QgIT09IFwiY3JlYXRlXCIgJiZcbiAgICAgICAgbWV0aG9kICE9PSBcIndpdGhBcmdzXCIgJiZcbiAgICAgICAgbWV0aG9kICE9PSBcImludm9rZVwiKSB7XG4gICAgICAgIHByb3RvW21ldGhvZF0gPSBiZWhhdmlvci5jcmVhdGVCZWhhdmlvcihtZXRob2QpO1xuICAgIH1cbn0pO1xuXG5PYmplY3Qua2V5cyhiZWhhdmlvcnMpLmZvckVhY2goZnVuY3Rpb24gKG1ldGhvZCkge1xuICAgIGlmIChiZWhhdmlvcnMuaGFzT3duUHJvcGVydHkobWV0aG9kKSAmJiAhcHJvdG8uaGFzT3duUHJvcGVydHkobWV0aG9kKSkge1xuICAgICAgICBiZWhhdmlvci5hZGRCZWhhdmlvcihzdHViLCBtZXRob2QsIGJlaGF2aW9yc1ttZXRob2RdKTtcbiAgICB9XG59KTtcblxuZXh0ZW5kKHN0dWIsIHByb3RvKTtcbm1vZHVsZS5leHBvcnRzID0gc3R1YjtcbiIsIlwidXNlIHN0cmljdFwiO1xudmFyIHZhbHVlVG9TdHJpbmcgPSByZXF1aXJlKFwiLi91dGlsL2NvcmUvdmFsdWUtdG8tc3RyaW5nXCIpO1xuXG5mdW5jdGlvbiB0aHJvd09uRmFsc3lPYmplY3Qob2JqZWN0LCBwcm9wZXJ0eSkge1xuICAgIGlmIChwcm9wZXJ0eSAmJiAhb2JqZWN0KSB7XG4gICAgICAgIHZhciB0eXBlID0gb2JqZWN0ID09PSBudWxsID8gXCJudWxsXCIgOiBcInVuZGVmaW5lZFwiO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUcnlpbmcgdG8gc3R1YiBwcm9wZXJ0eSAnXCIgKyB2YWx1ZVRvU3RyaW5nKHByb3BlcnR5KSArIFwiJyBvZiBcIiArIHR5cGUpO1xuICAgIH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSB0aHJvd09uRmFsc3lPYmplY3Q7XG4iLCJcInVzZSBzdHJpY3RcIjtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBjYWxsZWRJbk9yZGVyKHNwaWVzKSB7XG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICAgIHNwaWVzID0gYXJndW1lbnRzO1xuICAgIH1cblxuICAgIGZvciAodmFyIGkgPSAxLCBsID0gc3BpZXMubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgIGlmICghc3BpZXNbaSAtIDFdLmNhbGxlZEJlZm9yZShzcGllc1tpXSkgfHwgIXNwaWVzW2ldLmNhbGxlZCkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG59O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBkaXYgPSB0eXBlb2YgZG9jdW1lbnQgIT09IFwidW5kZWZpbmVkXCIgJiYgZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKTtcblxuZnVuY3Rpb24gaXNSZWFsbHlOYU4odmFsKSB7XG4gICAgcmV0dXJuIHZhbCAhPT0gdmFsO1xufVxuXG5mdW5jdGlvbiBpc0RPTU5vZGUob2JqKSB7XG4gICAgdmFyIHN1Y2Nlc3MgPSBmYWxzZTtcblxuICAgIHRyeSB7XG4gICAgICAgIG9iai5hcHBlbmRDaGlsZChkaXYpO1xuICAgICAgICBzdWNjZXNzID0gZGl2LnBhcmVudE5vZGUgPT09IG9iajtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9IGZpbmFsbHkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgb2JqLnJlbW92ZUNoaWxkKGRpdik7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIC8vIFJlbW92ZSBmYWlsZWQsIG5vdCBtdWNoIHdlIGNhbiBkbyBhYm91dCB0aGF0XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gc3VjY2Vzcztcbn1cblxuZnVuY3Rpb24gaXNFbGVtZW50KG9iaikge1xuICAgIHJldHVybiBkaXYgJiYgb2JqICYmIG9iai5ub2RlVHlwZSA9PT0gMSAmJiBpc0RPTU5vZGUob2JqKTtcbn1cblxudmFyIGRlZXBFcXVhbCA9IG1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gZGVlcEVxdWFsKGEsIGIpIHtcbiAgICBpZiAodHlwZW9mIGEgIT09IFwib2JqZWN0XCIgfHwgdHlwZW9mIGIgIT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgcmV0dXJuIGlzUmVhbGx5TmFOKGEpICYmIGlzUmVhbGx5TmFOKGIpIHx8IGEgPT09IGI7XG4gICAgfVxuXG4gICAgaWYgKGlzRWxlbWVudChhKSB8fCBpc0VsZW1lbnQoYikpIHtcbiAgICAgICAgcmV0dXJuIGEgPT09IGI7XG4gICAgfVxuXG4gICAgaWYgKGEgPT09IGIpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgaWYgKChhID09PSBudWxsICYmIGIgIT09IG51bGwpIHx8IChhICE9PSBudWxsICYmIGIgPT09IG51bGwpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBpZiAoYSBpbnN0YW5jZW9mIFJlZ0V4cCAmJiBiIGluc3RhbmNlb2YgUmVnRXhwKSB7XG4gICAgICAgIHJldHVybiAoYS5zb3VyY2UgPT09IGIuc291cmNlKSAmJiAoYS5nbG9iYWwgPT09IGIuZ2xvYmFsKSAmJlxuICAgICAgICAgICAgKGEuaWdub3JlQ2FzZSA9PT0gYi5pZ25vcmVDYXNlKSAmJiAoYS5tdWx0aWxpbmUgPT09IGIubXVsdGlsaW5lKTtcbiAgICB9XG5cbiAgICBpZiAoYSBpbnN0YW5jZW9mIEVycm9yICYmIGIgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICByZXR1cm4gYSA9PT0gYjtcbiAgICB9XG5cbiAgICB2YXIgYVN0cmluZyA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChhKTtcbiAgICBpZiAoYVN0cmluZyAhPT0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGIpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBpZiAoYVN0cmluZyA9PT0gXCJbb2JqZWN0IERhdGVdXCIpIHtcbiAgICAgICAgcmV0dXJuIGEudmFsdWVPZigpID09PSBiLnZhbHVlT2YoKTtcbiAgICB9XG5cbiAgICB2YXIgcHJvcDtcbiAgICB2YXIgYUxlbmd0aCA9IDA7XG4gICAgdmFyIGJMZW5ndGggPSAwO1xuXG4gICAgaWYgKGFTdHJpbmcgPT09IFwiW29iamVjdCBBcnJheV1cIiAmJiBhLmxlbmd0aCAhPT0gYi5sZW5ndGgpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGZvciAocHJvcCBpbiBhKSB7XG4gICAgICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoYSwgcHJvcCkpIHtcbiAgICAgICAgICAgIGFMZW5ndGggKz0gMTtcblxuICAgICAgICAgICAgaWYgKCEocHJvcCBpbiBiKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gYWxsb3cgYWx0ZXJuYXRpdmUgZnVuY3Rpb24gZm9yIHJlY3Vyc2lvblxuICAgICAgICAgICAgaWYgKCEoYXJndW1lbnRzWzJdIHx8IGRlZXBFcXVhbCkoYVtwcm9wXSwgYltwcm9wXSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IgKHByb3AgaW4gYikge1xuICAgICAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGIsIHByb3ApKSB7XG4gICAgICAgICAgICBiTGVuZ3RoICs9IDE7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gYUxlbmd0aCA9PT0gYkxlbmd0aDtcbn07XG5cbmRlZXBFcXVhbC51c2UgPSBmdW5jdGlvbiAobWF0Y2gpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gZGVlcEVxdWFsJG1hdGNoZXIoYSwgYikge1xuICAgICAgICAvLyBJZiBib3RoIGFyZSBtYXRjaGVycyB0aGV5IG11c3QgYmUgdGhlIHNhbWUgaW5zdGFuY2UgaW4gb3JkZXIgdG8gYmUgY29uc2lkZXJlZCBlcXVhbFxuICAgICAgICAvLyBJZiB3ZSBkaWRuJ3QgZG8gdGhhdCB3ZSB3b3VsZCBlbmQgdXAgcnVubmluZyBvbmUgbWF0Y2hlciBhZ2FpbnN0IHRoZSBvdGhlclxuICAgICAgICBpZiAobWF0Y2guaXNNYXRjaGVyKGEpKSB7XG4gICAgICAgICAgICBpZiAobWF0Y2guaXNNYXRjaGVyKGIpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGEgPT09IGI7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBhLnRlc3QoYik7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gZGVlcEVxdWFsKGEsIGIsIGRlZXBFcXVhbCRtYXRjaGVyKTtcbiAgICB9O1xufTtcbiIsIlwidXNlIHN0cmljdFwiO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBpbmplY3RJbnRvVGhpczogdHJ1ZSxcbiAgICBpbmplY3RJbnRvOiBudWxsLFxuICAgIHByb3BlcnRpZXM6IFtcInNweVwiLCBcInN0dWJcIiwgXCJtb2NrXCIsIFwiY2xvY2tcIiwgXCJzZXJ2ZXJcIiwgXCJyZXF1ZXN0c1wiXSxcbiAgICB1c2VGYWtlVGltZXJzOiB0cnVlLFxuICAgIHVzZUZha2VTZXJ2ZXI6IHRydWVcbn07XG4iLCIvKmVzbGludCBuby1jb25zb2xlOiAwICovXG5cInVzZSBzdHJpY3RcIjtcblxuLy8gd3JhcCByZXR1cm5zIGEgZnVuY3Rpb24gdGhhdCB3aWxsIGludm9rZSB0aGUgc3VwcGxpZWQgZnVuY3Rpb24gYW5kIHByaW50IGEgZGVwcmVjYXRpb24gd2FybmluZyB0byB0aGUgY29uc29sZSBlYWNoXG4vLyB0aW1lIGl0IGlzIGNhbGxlZC5cbmV4cG9ydHMud3JhcCA9IGZ1bmN0aW9uIChmdW5jLCBtc2cpIHtcbiAgICB2YXIgd3JhcHBlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgZXhwb3J0cy5wcmludFdhcm5pbmcobXNnKTtcbiAgICAgICAgcmV0dXJuIGZ1bmMuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB9O1xuICAgIGlmIChmdW5jLnByb3RvdHlwZSkge1xuICAgICAgICB3cmFwcGVkLnByb3RvdHlwZSA9IGZ1bmMucHJvdG90eXBlO1xuICAgIH1cbiAgICByZXR1cm4gd3JhcHBlZDtcbn07XG5cbi8vIGRlZmF1bHRNc2cgcmV0dXJucyBhIHN0cmluZyB3aGljaCBjYW4gYmUgc3VwcGxpZWQgdG8gYHdyYXAoKWAgdG8gbm90aWZ5IHRoZSB1c2VyIHRoYXQgYSBwYXJ0aWN1bGFyIHBhcnQgb2YgdGhlXG4vLyBzaW5vbiBBUEkgaGFzIGJlZW4gZGVwcmVjYXRlZC5cbmV4cG9ydHMuZGVmYXVsdE1zZyA9IGZ1bmN0aW9uIChmdW5jTmFtZSkge1xuICAgIHJldHVybiBcInNpbm9uLlwiICsgZnVuY05hbWUgKyBcIiBpcyBkZXByZWNhdGVkIGFuZCB3aWxsIGJlIHJlbW92ZWQgZnJvbSB0aGUgcHVibGljIEFQSSBpbiBhIGZ1dHVyZSB2ZXJzaW9uIG9mIHNpbm9uLlwiO1xufTtcblxuZXhwb3J0cy5wcmludFdhcm5pbmcgPSBmdW5jdGlvbiAobXNnKSB7XG4gICAgLy8gV2F0Y2ggb3V0IGZvciBJRTcgYW5kIGJlbG93ISA6KFxuICAgIGlmICh0eXBlb2YgY29uc29sZSAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICBpZiAoY29uc29sZS5pbmZvKSB7XG4gICAgICAgICAgICBjb25zb2xlLmluZm8obXNnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKG1zZyk7XG4gICAgICAgIH1cbiAgICB9XG59O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbi8vIFRoaXMgaXMgYW4gYGV2ZXJ5YCBpbXBsZW1lbnRhdGlvbiB0aGF0IHdvcmtzIGZvciBhbGwgaXRlcmFibGVzXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIGV2ZXJ5KG9iaiwgZm4pIHtcbiAgICB2YXIgcGFzcyA9IHRydWU7XG5cbiAgICB0cnkge1xuICAgICAgICBvYmouZm9yRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZiAoIWZuLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykpIHtcbiAgICAgICAgICAgICAgICAvLyBUaHJvd2luZyBhbiBlcnJvciBpcyB0aGUgb25seSB3YXkgdG8gYnJlYWsgYGZvckVhY2hgXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcGFzcyA9IGZhbHNlO1xuICAgIH1cblxuICAgIHJldHVybiBwYXNzO1xufTtcbiIsIlwidXNlIHN0cmljdFwiO1xuXG4vLyBBZGFwdGVkIGZyb20gaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4vZG9jcy9FQ01BU2NyaXB0X0RvbnRFbnVtX2F0dHJpYnV0ZSNKU2NyaXB0X0RvbnRFbnVtX0J1Z1xudmFyIGhhc0RvbnRFbnVtQnVnID0gKGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgb2JqID0ge1xuICAgICAgICBjb25zdHJ1Y3RvcjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIFwiMFwiO1xuICAgICAgICB9LFxuICAgICAgICB0b1N0cmluZzogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIFwiMVwiO1xuICAgICAgICB9LFxuICAgICAgICB2YWx1ZU9mOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gXCIyXCI7XG4gICAgICAgIH0sXG4gICAgICAgIHRvTG9jYWxlU3RyaW5nOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gXCIzXCI7XG4gICAgICAgIH0sXG4gICAgICAgIHByb3RvdHlwZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIFwiNFwiO1xuICAgICAgICB9LFxuICAgICAgICBpc1Byb3RvdHlwZU9mOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gXCI1XCI7XG4gICAgICAgIH0sXG4gICAgICAgIHByb3BlcnR5SXNFbnVtZXJhYmxlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gXCI2XCI7XG4gICAgICAgIH0sXG4gICAgICAgIGhhc093blByb3BlcnR5OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gXCI3XCI7XG4gICAgICAgIH0sXG4gICAgICAgIGxlbmd0aDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIFwiOFwiO1xuICAgICAgICB9LFxuICAgICAgICB1bmlxdWU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBcIjlcIjtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICB2YXIgcmVzdWx0ID0gW107XG4gICAgZm9yICh2YXIgcHJvcCBpbiBvYmopIHtcbiAgICAgICAgaWYgKG9iai5oYXNPd25Qcm9wZXJ0eShwcm9wKSkge1xuICAgICAgICAgICAgcmVzdWx0LnB1c2gob2JqW3Byb3BdKCkpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQuam9pbihcIlwiKSAhPT0gXCIwMTIzNDU2Nzg5XCI7XG59KSgpO1xuXG4vKiBQdWJsaWM6IEV4dGVuZCB0YXJnZXQgaW4gcGxhY2Ugd2l0aCBhbGwgKG93bikgcHJvcGVydGllcyBmcm9tIHNvdXJjZXMgaW4tb3JkZXIuIFRodXMsIGxhc3Qgc291cmNlIHdpbGxcbiAqICAgICAgICAgb3ZlcnJpZGUgcHJvcGVydGllcyBpbiBwcmV2aW91cyBzb3VyY2VzLlxuICpcbiAqIHRhcmdldCAtIFRoZSBPYmplY3QgdG8gZXh0ZW5kXG4gKiBzb3VyY2VzIC0gT2JqZWN0cyB0byBjb3B5IHByb3BlcnRpZXMgZnJvbS5cbiAqXG4gKiBSZXR1cm5zIHRoZSBleHRlbmRlZCB0YXJnZXRcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBleHRlbmQodGFyZ2V0IC8qLCBzb3VyY2VzICovKSB7XG4gICAgdmFyIHNvdXJjZXMgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgIHZhciBzb3VyY2UsIGksIHByb3A7XG5cbiAgICBmb3IgKGkgPSAwOyBpIDwgc291cmNlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICBzb3VyY2UgPSBzb3VyY2VzW2ldO1xuXG4gICAgICAgIGZvciAocHJvcCBpbiBzb3VyY2UpIHtcbiAgICAgICAgICAgIGlmIChzb3VyY2UuaGFzT3duUHJvcGVydHkocHJvcCkpIHtcbiAgICAgICAgICAgICAgICB0YXJnZXRbcHJvcF0gPSBzb3VyY2VbcHJvcF07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBNYWtlIHN1cmUgd2UgY29weSAob3duKSB0b1N0cmluZyBtZXRob2QgZXZlbiB3aGVuIGluIEpTY3JpcHQgd2l0aCBEb250RW51bSBidWdcbiAgICAgICAgLy8gU2VlIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuL2RvY3MvRUNNQVNjcmlwdF9Eb250RW51bV9hdHRyaWJ1dGUjSlNjcmlwdF9Eb250RW51bV9CdWdcbiAgICAgICAgaWYgKGhhc0RvbnRFbnVtQnVnICYmIHNvdXJjZS5oYXNPd25Qcm9wZXJ0eShcInRvU3RyaW5nXCIpICYmIHNvdXJjZS50b1N0cmluZyAhPT0gdGFyZ2V0LnRvU3RyaW5nKSB7XG4gICAgICAgICAgICB0YXJnZXQudG9TdHJpbmcgPSBzb3VyY2UudG9TdHJpbmc7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdGFyZ2V0O1xufTtcbiIsIlwidXNlIHN0cmljdFwiO1xuXG52YXIgZm9ybWF0aW8gPSByZXF1aXJlKFwiZm9ybWF0aW9cIik7XG5cbnZhciBmb3JtYXR0ZXIgPSBmb3JtYXRpby5jb25maWd1cmUoe1xuICAgIHF1b3RlU3RyaW5nczogZmFsc2UsXG4gICAgbGltaXRDaGlsZHJlbkNvdW50OiAyNTBcbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIGZvcm1hdCgpIHtcbiAgICByZXR1cm4gZm9ybWF0dGVyLmFzY2lpLmFwcGx5KGZvcm1hdHRlciwgYXJndW1lbnRzKTtcbn07XG4iLCJcInVzZSBzdHJpY3RcIjtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBmdW5jdGlvbk5hbWUoZnVuYykge1xuICAgIHZhciBuYW1lID0gZnVuYy5kaXNwbGF5TmFtZSB8fCBmdW5jLm5hbWU7XG4gICAgdmFyIG1hdGNoZXM7XG5cbiAgICAvLyBVc2UgZnVuY3Rpb24gZGVjb21wb3NpdGlvbiBhcyBhIGxhc3QgcmVzb3J0IHRvIGdldCBmdW5jdGlvblxuICAgIC8vIG5hbWUuIERvZXMgbm90IHJlbHkgb24gZnVuY3Rpb24gZGVjb21wb3NpdGlvbiB0byB3b3JrIC0gaWYgaXRcbiAgICAvLyBkb2Vzbid0IGRlYnVnZ2luZyB3aWxsIGJlIHNsaWdodGx5IGxlc3MgaW5mb3JtYXRpdmVcbiAgICAvLyAoaS5lLiB0b1N0cmluZyB3aWxsIHNheSAnc3B5JyByYXRoZXIgdGhhbiAnbXlGdW5jJykuXG4gICAgaWYgKCFuYW1lICYmIChtYXRjaGVzID0gZnVuYy50b1N0cmluZygpLm1hdGNoKC9mdW5jdGlvbiAoW15cXHNcXChdKykvKSkpIHtcbiAgICAgICAgbmFtZSA9IG1hdGNoZXNbMV07XG4gICAgfVxuXG4gICAgcmV0dXJuIG5hbWU7XG59O1xuXG4iLCJcInVzZSBzdHJpY3RcIjtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiB0b1N0cmluZygpIHtcbiAgICB2YXIgaSwgcHJvcCwgdGhpc1ZhbHVlO1xuICAgIGlmICh0aGlzLmdldENhbGwgJiYgdGhpcy5jYWxsQ291bnQpIHtcbiAgICAgICAgaSA9IHRoaXMuY2FsbENvdW50O1xuXG4gICAgICAgIHdoaWxlIChpLS0pIHtcbiAgICAgICAgICAgIHRoaXNWYWx1ZSA9IHRoaXMuZ2V0Q2FsbChpKS50aGlzVmFsdWU7XG5cbiAgICAgICAgICAgIGZvciAocHJvcCBpbiB0aGlzVmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpc1ZhbHVlW3Byb3BdID09PSB0aGlzKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBwcm9wO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0aGlzLmRpc3BsYXlOYW1lIHx8IFwic2lub24gZmFrZVwiO1xufTtcbiIsIlwidXNlIHN0cmljdFwiO1xuXG52YXIgZGVmYXVsdENvbmZpZyA9IHJlcXVpcmUoXCIuL2RlZmF1bHQtY29uZmlnXCIpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIGdldENvbmZpZyhjdXN0b20pIHtcbiAgICB2YXIgY29uZmlnID0ge307XG4gICAgdmFyIHByb3A7XG5cbiAgICBjdXN0b20gPSBjdXN0b20gfHwge307XG5cbiAgICBmb3IgKHByb3AgaW4gZGVmYXVsdENvbmZpZykge1xuICAgICAgICBpZiAoZGVmYXVsdENvbmZpZy5oYXNPd25Qcm9wZXJ0eShwcm9wKSkge1xuICAgICAgICAgICAgY29uZmlnW3Byb3BdID0gY3VzdG9tLmhhc093blByb3BlcnR5KHByb3ApID8gY3VzdG9tW3Byb3BdIDogZGVmYXVsdENvbmZpZ1twcm9wXTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBjb25maWc7XG59O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gZ2V0UHJvcGVydHlEZXNjcmlwdG9yKG9iamVjdCwgcHJvcGVydHkpIHtcbiAgICB2YXIgcHJvdG8gPSBvYmplY3Q7XG4gICAgdmFyIGRlc2NyaXB0b3I7XG5cbiAgICB3aGlsZSAocHJvdG8gJiYgIShkZXNjcmlwdG9yID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihwcm90bywgcHJvcGVydHkpKSkge1xuICAgICAgICBwcm90byA9IE9iamVjdC5nZXRQcm90b3R5cGVPZihwcm90byk7XG4gICAgfVxuICAgIHJldHVybiBkZXNjcmlwdG9yO1xufTtcbiIsIlwidXNlIHN0cmljdFwiO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBjYWxsZWRJbk9yZGVyOiByZXF1aXJlKFwiLi9jYWxsZWQtaW4tb3JkZXJcIiksXG4gICAgY29uZmlndXJlTG9nRXJyb3I6IHJlcXVpcmUoXCIuL2xvZ19lcnJvclwiKSxcbiAgICBkZWZhdWx0Q29uZmlnOiByZXF1aXJlKFwiLi9kZWZhdWx0LWNvbmZpZ1wiKSxcbiAgICBkZWVwRXF1YWw6IHJlcXVpcmUoXCIuL2RlZXAtZXF1YWxcIiksXG4gICAgZXZlcnk6IHJlcXVpcmUoXCIuL2V2ZXJ5XCIpLFxuICAgIGV4dGVuZDogcmVxdWlyZShcIi4vZXh0ZW5kXCIpLFxuICAgIGZvcm1hdDogcmVxdWlyZShcIi4vZm9ybWF0XCIpLFxuICAgIGZ1bmN0aW9uTmFtZTogcmVxdWlyZShcIi4vZnVuY3Rpb24tbmFtZVwiKSxcbiAgICBmdW5jdGlvblRvU3RyaW5nOiByZXF1aXJlKFwiLi9mdW5jdGlvbi10by1zdHJpbmdcIiksXG4gICAgZ2V0Q29uZmlnOiByZXF1aXJlKFwiLi9nZXQtY29uZmlnXCIpLFxuICAgIGdldFByb3BlcnR5RGVzY3JpcHRvcjogcmVxdWlyZShcIi4vZ2V0LXByb3BlcnR5LWRlc2NyaXB0b3JcIiksXG4gICAgaXRlcmFibGVUb1N0cmluZzogcmVxdWlyZShcIi4vaXRlcmFibGUtdG8tc3RyaW5nXCIpLFxuICAgIG9yZGVyQnlGaXJzdENhbGw6IHJlcXVpcmUoXCIuL29yZGVyLWJ5LWZpcnN0LWNhbGxcIiksXG4gICAgcmVzdG9yZTogcmVxdWlyZShcIi4vcmVzdG9yZVwiKSxcbiAgICB0aW1lc0luV29yZHM6IHJlcXVpcmUoXCIuL3RpbWVzLWluLXdvcmRzXCIpLFxuICAgIHR5cGVPZjogcmVxdWlyZShcIi4vdHlwZU9mXCIpLFxuICAgIHdhbGs6IHJlcXVpcmUoXCIuL3dhbGtcIiksXG4gICAgd3JhcE1ldGhvZDogcmVxdWlyZShcIi4vd3JhcC1tZXRob2RcIilcbn07XG4iLCJcInVzZSBzdHJpY3RcIjtcbnZhciB0eXBlT2YgPSByZXF1aXJlKFwiLi90eXBlT2ZcIik7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gaXRlcmFibGVUb1N0cmluZyhvYmopIHtcbiAgICB2YXIgcmVwcmVzZW50YXRpb24gPSBcIlwiO1xuXG4gICAgZnVuY3Rpb24gc3RyaW5naWZ5KGl0ZW0pIHtcbiAgICAgICAgcmV0dXJuIHR5cGVvZiBpdGVtID09PSBcInN0cmluZ1wiID8gXCInXCIgKyBpdGVtICsgXCInXCIgOiBTdHJpbmcoaXRlbSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbWFwVG9TdHJpbmcobWFwKSB7XG4gICAgICAgIG1hcC5mb3JFYWNoKGZ1bmN0aW9uICh2YWx1ZSwga2V5KSB7XG4gICAgICAgICAgICByZXByZXNlbnRhdGlvbiArPSBcIltcIiArIHN0cmluZ2lmeShrZXkpICsgXCIsXCIgKyBzdHJpbmdpZnkodmFsdWUpICsgXCJdLFwiO1xuICAgICAgICB9KTtcblxuICAgICAgICByZXByZXNlbnRhdGlvbiA9IHJlcHJlc2VudGF0aW9uLnNsaWNlKDAsIC0xKTtcbiAgICAgICAgcmV0dXJuIHJlcHJlc2VudGF0aW9uO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdlbmVyaWNJdGVyYWJsZVRvU3RyaW5nKGl0ZXJhYmxlKSB7XG4gICAgICAgIGl0ZXJhYmxlLmZvckVhY2goZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICByZXByZXNlbnRhdGlvbiArPSBzdHJpbmdpZnkodmFsdWUpICsgXCIsXCI7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJlcHJlc2VudGF0aW9uID0gcmVwcmVzZW50YXRpb24uc2xpY2UoMCwgLTEpO1xuICAgICAgICByZXR1cm4gcmVwcmVzZW50YXRpb247XG4gICAgfVxuXG4gICAgaWYgKHR5cGVPZihvYmopID09PSBcIm1hcFwiKSB7XG4gICAgICAgIHJldHVybiBtYXBUb1N0cmluZyhvYmopO1xuICAgIH1cblxuICAgIHJldHVybiBnZW5lcmljSXRlcmFibGVUb1N0cmluZyhvYmopO1xufTtcbiIsIlwidXNlIHN0cmljdFwiO1xuXG4vLyBjYWNoZSBhIHJlZmVyZW5jZSB0byBzZXRUaW1lb3V0LCBzbyB0aGF0IG91ciByZWZlcmVuY2Ugd29uJ3QgYmUgc3R1YmJlZCBvdXRcbi8vIHdoZW4gdXNpbmcgZmFrZSB0aW1lcnMgYW5kIGVycm9ycyB3aWxsIHN0aWxsIGdldCBsb2dnZWRcbi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9jam9oYW5zZW4vU2lub24uSlMvaXNzdWVzLzM4MVxudmFyIHJlYWxTZXRUaW1lb3V0ID0gc2V0VGltZW91dDtcblxuZnVuY3Rpb24gY29uZmlndXJlKGNvbmZpZykge1xuICAgIGNvbmZpZyA9IGNvbmZpZyB8fCB7fTtcbiAgICAvLyBGdW5jdGlvbiB3aGljaCBwcmludHMgZXJyb3JzLlxuICAgIGlmICghY29uZmlnLmhhc093blByb3BlcnR5KFwibG9nZ2VyXCIpKSB7XG4gICAgICAgIGNvbmZpZy5sb2dnZXIgPSBmdW5jdGlvbiAoKSB7IH07XG4gICAgfVxuICAgIC8vIFdoZW4gc2V0IHRvIHRydWUsIGFueSBlcnJvcnMgbG9nZ2VkIHdpbGwgYmUgdGhyb3duIGltbWVkaWF0ZWx5O1xuICAgIC8vIElmIHNldCB0byBmYWxzZSwgdGhlIGVycm9ycyB3aWxsIGJlIHRocm93biBpbiBzZXBhcmF0ZSBleGVjdXRpb24gZnJhbWUuXG4gICAgaWYgKCFjb25maWcuaGFzT3duUHJvcGVydHkoXCJ1c2VJbW1lZGlhdGVFeGNlcHRpb25zXCIpKSB7XG4gICAgICAgIGNvbmZpZy51c2VJbW1lZGlhdGVFeGNlcHRpb25zID0gdHJ1ZTtcbiAgICB9XG4gICAgLy8gd3JhcCByZWFsU2V0VGltZW91dCB3aXRoIHNvbWV0aGluZyB3ZSBjYW4gc3R1YiBpbiB0ZXN0c1xuICAgIGlmICghY29uZmlnLmhhc093blByb3BlcnR5KFwic2V0VGltZW91dFwiKSkge1xuICAgICAgICBjb25maWcuc2V0VGltZW91dCA9IHJlYWxTZXRUaW1lb3V0O1xuICAgIH1cblxuICAgIHJldHVybiBmdW5jdGlvbiBsb2dFcnJvcihsYWJlbCwgZSkge1xuICAgICAgICB2YXIgbXNnID0gbGFiZWwgKyBcIiB0aHJldyBleGNlcHRpb246IFwiO1xuICAgICAgICB2YXIgZXJyID0geyBuYW1lOiBlLm5hbWUgfHwgbGFiZWwsIG1lc3NhZ2U6IGUubWVzc2FnZSB8fCBlLnRvU3RyaW5nKCksIHN0YWNrOiBlLnN0YWNrIH07XG5cbiAgICAgICAgZnVuY3Rpb24gdGhyb3dMb2dnZWRFcnJvcigpIHtcbiAgICAgICAgICAgIGVyci5tZXNzYWdlID0gbXNnICsgZXJyLm1lc3NhZ2U7XG4gICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgIH1cblxuICAgICAgICBjb25maWcubG9nZ2VyKG1zZyArIFwiW1wiICsgZXJyLm5hbWUgKyBcIl0gXCIgKyBlcnIubWVzc2FnZSk7XG5cbiAgICAgICAgaWYgKGVyci5zdGFjaykge1xuICAgICAgICAgICAgY29uZmlnLmxvZ2dlcihlcnIuc3RhY2spO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNvbmZpZy51c2VJbW1lZGlhdGVFeGNlcHRpb25zKSB7XG4gICAgICAgICAgICB0aHJvd0xvZ2dlZEVycm9yKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25maWcuc2V0VGltZW91dCh0aHJvd0xvZ2dlZEVycm9yLCAwKTtcbiAgICAgICAgfVxuICAgIH07XG59XG5cbm1vZHVsZS5leHBvcnRzID0gY29uZmlndXJlO1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gb3JkZXJCeUZpcnN0Q2FsbChzcGllcykge1xuICAgIHJldHVybiBzcGllcy5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7XG4gICAgICAgIC8vIHV1aWQsIHdvbid0IGV2ZXIgYmUgZXF1YWxcbiAgICAgICAgdmFyIGFDYWxsID0gYS5nZXRDYWxsKDApO1xuICAgICAgICB2YXIgYkNhbGwgPSBiLmdldENhbGwoMCk7XG4gICAgICAgIHZhciBhSWQgPSBhQ2FsbCAmJiBhQ2FsbC5jYWxsSWQgfHwgLTE7XG4gICAgICAgIHZhciBiSWQgPSBiQ2FsbCAmJiBiQ2FsbC5jYWxsSWQgfHwgLTE7XG5cbiAgICAgICAgcmV0dXJuIGFJZCA8IGJJZCA/IC0xIDogMTtcbiAgICB9KTtcbn07XG4iLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIHdhbGsgPSByZXF1aXJlKFwiLi93YWxrXCIpO1xuXG5mdW5jdGlvbiBpc1Jlc3RvcmFibGUob2JqKSB7XG4gICAgcmV0dXJuIHR5cGVvZiBvYmogPT09IFwiZnVuY3Rpb25cIiAmJiB0eXBlb2Ygb2JqLnJlc3RvcmUgPT09IFwiZnVuY3Rpb25cIiAmJiBvYmoucmVzdG9yZS5zaW5vbjtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiByZXN0b3JlKG9iamVjdCkge1xuICAgIGlmIChvYmplY3QgIT09IG51bGwgJiYgdHlwZW9mIG9iamVjdCA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICB3YWxrKG9iamVjdCwgZnVuY3Rpb24gKHByb3ApIHtcbiAgICAgICAgICAgIGlmIChpc1Jlc3RvcmFibGUob2JqZWN0W3Byb3BdKSkge1xuICAgICAgICAgICAgICAgIG9iamVjdFtwcm9wXS5yZXN0b3JlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH0gZWxzZSBpZiAoaXNSZXN0b3JhYmxlKG9iamVjdCkpIHtcbiAgICAgICAgb2JqZWN0LnJlc3RvcmUoKTtcbiAgICB9XG59O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBhcnJheSA9IFtudWxsLCBcIm9uY2VcIiwgXCJ0d2ljZVwiLCBcInRocmljZVwiXTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiB0aW1lc0luV29yZHMoY291bnQpIHtcbiAgICByZXR1cm4gYXJyYXlbY291bnRdIHx8IChjb3VudCB8fCAwKSArIFwiIHRpbWVzXCI7XG59O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciB0eXBlID0gcmVxdWlyZShcInR5cGUtZGV0ZWN0XCIpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIHR5cGVPZih2YWx1ZSkge1xuICAgIHJldHVybiB0eXBlKHZhbHVlKS50b0xvd2VyQ2FzZSgpO1xufTtcbiIsIlwidXNlIHN0cmljdFwiO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIGlmICh2YWx1ZSAmJiB2YWx1ZS50b1N0cmluZykge1xuICAgICAgICByZXR1cm4gdmFsdWUudG9TdHJpbmcoKTtcbiAgICB9XG4gICAgcmV0dXJuIFN0cmluZyh2YWx1ZSk7XG59O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbmZ1bmN0aW9uIHdhbGtJbnRlcm5hbChvYmosIGl0ZXJhdG9yLCBjb250ZXh0LCBvcmlnaW5hbE9iaiwgc2Vlbikge1xuICAgIHZhciBwcm90bywgcHJvcDtcblxuICAgIGlmICh0eXBlb2YgT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMgIT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAvLyBXZSBleHBsaWNpdGx5IHdhbnQgdG8gZW51bWVyYXRlIHRocm91Z2ggYWxsIG9mIHRoZSBwcm90b3R5cGUncyBwcm9wZXJ0aWVzXG4gICAgICAgIC8vIGluIHRoaXMgY2FzZSwgdGhlcmVmb3JlIHdlIGRlbGliZXJhdGVseSBsZWF2ZSBvdXQgYW4gb3duIHByb3BlcnR5IGNoZWNrLlxuICAgICAgICAvKiBlc2xpbnQtZGlzYWJsZSBndWFyZC1mb3ItaW4gKi9cbiAgICAgICAgZm9yIChwcm9wIGluIG9iaikge1xuICAgICAgICAgICAgaXRlcmF0b3IuY2FsbChjb250ZXh0LCBvYmpbcHJvcF0sIHByb3AsIG9iaik7XG4gICAgICAgIH1cbiAgICAgICAgLyogZXNsaW50LWVuYWJsZSBndWFyZC1mb3ItaW4gKi9cblxuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMob2JqKS5mb3JFYWNoKGZ1bmN0aW9uIChrKSB7XG4gICAgICAgIGlmIChzZWVuW2tdICE9PSB0cnVlKSB7XG4gICAgICAgICAgICBzZWVuW2tdID0gdHJ1ZTtcbiAgICAgICAgICAgIHZhciB0YXJnZXQgPSB0eXBlb2YgT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihvYmosIGspLmdldCA9PT0gXCJmdW5jdGlvblwiID9cbiAgICAgICAgICAgICAgICBvcmlnaW5hbE9iaiA6IG9iajtcbiAgICAgICAgICAgIGl0ZXJhdG9yLmNhbGwoY29udGV4dCwgaywgdGFyZ2V0KTtcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgcHJvdG8gPSBPYmplY3QuZ2V0UHJvdG90eXBlT2Yob2JqKTtcbiAgICBpZiAocHJvdG8pIHtcbiAgICAgICAgd2Fsa0ludGVybmFsKHByb3RvLCBpdGVyYXRvciwgY29udGV4dCwgb3JpZ2luYWxPYmosIHNlZW4pO1xuICAgIH1cbn1cblxuLyogV2Fsa3MgdGhlIHByb3RvdHlwZSBjaGFpbiBvZiBhbiBvYmplY3QgYW5kIGl0ZXJhdGVzIG92ZXIgZXZlcnkgb3duIHByb3BlcnR5XG4gKiBuYW1lIGVuY291bnRlcmVkLiBUaGUgaXRlcmF0b3IgaXMgY2FsbGVkIGluIHRoZSBzYW1lIGZhc2hpb24gdGhhdCBBcnJheS5wcm90b3R5cGUuZm9yRWFjaFxuICogd29ya3MsIHdoZXJlIGl0IGlzIHBhc3NlZCB0aGUgdmFsdWUsIGtleSwgYW5kIG93biBvYmplY3QgYXMgdGhlIDFzdCwgMm5kLCBhbmQgM3JkIHBvc2l0aW9uYWxcbiAqIGFyZ3VtZW50LCByZXNwZWN0aXZlbHkuIEluIGNhc2VzIHdoZXJlIE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzIGlzIG5vdCBhdmFpbGFibGUsIHdhbGsgd2lsbFxuICogZGVmYXVsdCB0byB1c2luZyBhIHNpbXBsZSBmb3IuLmluIGxvb3AuXG4gKlxuICogb2JqIC0gVGhlIG9iamVjdCB0byB3YWxrIHRoZSBwcm90b3R5cGUgY2hhaW4gZm9yLlxuICogaXRlcmF0b3IgLSBUaGUgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIG9uIGVhY2ggcGFzcyBvZiB0aGUgd2Fsay5cbiAqIGNvbnRleHQgLSAoT3B0aW9uYWwpIFdoZW4gZ2l2ZW4sIHRoZSBpdGVyYXRvciB3aWxsIGJlIGNhbGxlZCB3aXRoIHRoaXMgb2JqZWN0IGFzIHRoZSByZWNlaXZlci5cbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiB3YWxrKG9iaiwgaXRlcmF0b3IsIGNvbnRleHQpIHtcbiAgICByZXR1cm4gd2Fsa0ludGVybmFsKG9iaiwgaXRlcmF0b3IsIGNvbnRleHQsIG9iaiwge30pO1xufTtcbiIsIlwidXNlIHN0cmljdFwiO1xuXG52YXIgZ2V0UHJvcGVydHlEZXNjcmlwdG9yID0gcmVxdWlyZShcIi4vZ2V0LXByb3BlcnR5LWRlc2NyaXB0b3JcIik7XG52YXIgdmFsdWVUb1N0cmluZyA9IHJlcXVpcmUoXCIuL3ZhbHVlLXRvLXN0cmluZ1wiKTtcblxudmFyIGhhc093biA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHk7XG5cbmZ1bmN0aW9uIGlzRnVuY3Rpb24ob2JqKSB7XG4gICAgcmV0dXJuIHR5cGVvZiBvYmogPT09IFwiZnVuY3Rpb25cIiB8fCAhIShvYmogJiYgb2JqLmNvbnN0cnVjdG9yICYmIG9iai5jYWxsICYmIG9iai5hcHBseSk7XG59XG5cbmZ1bmN0aW9uIG1pcnJvclByb3BlcnRpZXModGFyZ2V0LCBzb3VyY2UpIHtcbiAgICBmb3IgKHZhciBwcm9wIGluIHNvdXJjZSkge1xuICAgICAgICBpZiAoIWhhc093bi5jYWxsKHRhcmdldCwgcHJvcCkpIHtcbiAgICAgICAgICAgIHRhcmdldFtwcm9wXSA9IHNvdXJjZVtwcm9wXTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuLy8gQ2hlYXAgd2F5IHRvIGRldGVjdCBpZiB3ZSBoYXZlIEVTNSBzdXBwb3J0LlxudmFyIGhhc0VTNVN1cHBvcnQgPSBcImtleXNcIiBpbiBPYmplY3Q7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gd3JhcE1ldGhvZChvYmplY3QsIHByb3BlcnR5LCBtZXRob2QpIHtcbiAgICBpZiAoIW9iamVjdCkge1xuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiU2hvdWxkIHdyYXAgcHJvcGVydHkgb2Ygb2JqZWN0XCIpO1xuICAgIH1cblxuICAgIGlmICh0eXBlb2YgbWV0aG9kICE9PSBcImZ1bmN0aW9uXCIgJiYgdHlwZW9mIG1ldGhvZCAhPT0gXCJvYmplY3RcIikge1xuICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiTWV0aG9kIHdyYXBwZXIgc2hvdWxkIGJlIGEgZnVuY3Rpb24gb3IgYSBwcm9wZXJ0eSBkZXNjcmlwdG9yXCIpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGNoZWNrV3JhcHBlZE1ldGhvZCh3cmFwcGVkTWV0aG9kKSB7XG4gICAgICAgIHZhciBlcnJvcjtcblxuICAgICAgICBpZiAoIWlzRnVuY3Rpb24od3JhcHBlZE1ldGhvZCkpIHtcbiAgICAgICAgICAgIGVycm9yID0gbmV3IFR5cGVFcnJvcihcIkF0dGVtcHRlZCB0byB3cmFwIFwiICsgKHR5cGVvZiB3cmFwcGVkTWV0aG9kKSArIFwiIHByb3BlcnR5IFwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVUb1N0cmluZyhwcm9wZXJ0eSkgKyBcIiBhcyBmdW5jdGlvblwiKTtcbiAgICAgICAgfSBlbHNlIGlmICh3cmFwcGVkTWV0aG9kLnJlc3RvcmUgJiYgd3JhcHBlZE1ldGhvZC5yZXN0b3JlLnNpbm9uKSB7XG4gICAgICAgICAgICBlcnJvciA9IG5ldyBUeXBlRXJyb3IoXCJBdHRlbXB0ZWQgdG8gd3JhcCBcIiArIHZhbHVlVG9TdHJpbmcocHJvcGVydHkpICsgXCIgd2hpY2ggaXMgYWxyZWFkeSB3cmFwcGVkXCIpO1xuICAgICAgICB9IGVsc2UgaWYgKHdyYXBwZWRNZXRob2QuY2FsbGVkQmVmb3JlKSB7XG4gICAgICAgICAgICB2YXIgdmVyYiA9IHdyYXBwZWRNZXRob2QucmV0dXJucyA/IFwic3R1YmJlZFwiIDogXCJzcGllZCBvblwiO1xuICAgICAgICAgICAgZXJyb3IgPSBuZXcgVHlwZUVycm9yKFwiQXR0ZW1wdGVkIHRvIHdyYXAgXCIgKyB2YWx1ZVRvU3RyaW5nKHByb3BlcnR5KSArIFwiIHdoaWNoIGlzIGFscmVhZHkgXCIgKyB2ZXJiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgaWYgKHdyYXBwZWRNZXRob2QgJiYgd3JhcHBlZE1ldGhvZC5zdGFja1RyYWNlKSB7XG4gICAgICAgICAgICAgICAgZXJyb3Iuc3RhY2sgKz0gXCJcXG4tLS0tLS0tLS0tLS0tLVxcblwiICsgd3JhcHBlZE1ldGhvZC5zdGFja1RyYWNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB2YXIgZXJyb3IsIHdyYXBwZWRNZXRob2QsIGk7XG5cbiAgICBmdW5jdGlvbiBzaW1wbGVQcm9wZXJ0eUFzc2lnbm1lbnQoKSB7XG4gICAgICAgIHdyYXBwZWRNZXRob2QgPSBvYmplY3RbcHJvcGVydHldO1xuICAgICAgICBjaGVja1dyYXBwZWRNZXRob2Qod3JhcHBlZE1ldGhvZCk7XG4gICAgICAgIG9iamVjdFtwcm9wZXJ0eV0gPSBtZXRob2Q7XG4gICAgICAgIG1ldGhvZC5kaXNwbGF5TmFtZSA9IHByb3BlcnR5O1xuICAgIH1cblxuICAgIC8vIEZpcmVmb3ggaGFzIGEgcHJvYmxlbSB3aGVuIHVzaW5nIGhhc093bi5jYWxsIG9uIG9iamVjdHMgZnJvbSBvdGhlciBmcmFtZXMuXG4gICAgdmFyIG93bmVkID0gb2JqZWN0Lmhhc093blByb3BlcnR5ID8gb2JqZWN0Lmhhc093blByb3BlcnR5KHByb3BlcnR5KSA6IGhhc093bi5jYWxsKG9iamVjdCwgcHJvcGVydHkpO1xuXG4gICAgaWYgKGhhc0VTNVN1cHBvcnQpIHtcbiAgICAgICAgdmFyIG1ldGhvZERlc2MgPSAodHlwZW9mIG1ldGhvZCA9PT0gXCJmdW5jdGlvblwiKSA/IHt2YWx1ZTogbWV0aG9kfSA6IG1ldGhvZDtcbiAgICAgICAgdmFyIHdyYXBwZWRNZXRob2REZXNjID0gZ2V0UHJvcGVydHlEZXNjcmlwdG9yKG9iamVjdCwgcHJvcGVydHkpO1xuXG4gICAgICAgIGlmICghd3JhcHBlZE1ldGhvZERlc2MpIHtcbiAgICAgICAgICAgIGVycm9yID0gbmV3IFR5cGVFcnJvcihcIkF0dGVtcHRlZCB0byB3cmFwIFwiICsgKHR5cGVvZiB3cmFwcGVkTWV0aG9kKSArIFwiIHByb3BlcnR5IFwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvcGVydHkgKyBcIiBhcyBmdW5jdGlvblwiKTtcbiAgICAgICAgfSBlbHNlIGlmICh3cmFwcGVkTWV0aG9kRGVzYy5yZXN0b3JlICYmIHdyYXBwZWRNZXRob2REZXNjLnJlc3RvcmUuc2lub24pIHtcbiAgICAgICAgICAgIGVycm9yID0gbmV3IFR5cGVFcnJvcihcIkF0dGVtcHRlZCB0byB3cmFwIFwiICsgcHJvcGVydHkgKyBcIiB3aGljaCBpcyBhbHJlYWR5IHdyYXBwZWRcIik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICBpZiAod3JhcHBlZE1ldGhvZERlc2MgJiYgd3JhcHBlZE1ldGhvZERlc2Muc3RhY2tUcmFjZSkge1xuICAgICAgICAgICAgICAgIGVycm9yLnN0YWNrICs9IFwiXFxuLS0tLS0tLS0tLS0tLS1cXG5cIiArIHdyYXBwZWRNZXRob2REZXNjLnN0YWNrVHJhY2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB0eXBlcyA9IE9iamVjdC5rZXlzKG1ldGhvZERlc2MpO1xuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgdHlwZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIHdyYXBwZWRNZXRob2QgPSB3cmFwcGVkTWV0aG9kRGVzY1t0eXBlc1tpXV07XG4gICAgICAgICAgICBjaGVja1dyYXBwZWRNZXRob2Qod3JhcHBlZE1ldGhvZCk7XG4gICAgICAgIH1cblxuICAgICAgICBtaXJyb3JQcm9wZXJ0aWVzKG1ldGhvZERlc2MsIHdyYXBwZWRNZXRob2REZXNjKTtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHR5cGVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBtaXJyb3JQcm9wZXJ0aWVzKG1ldGhvZERlc2NbdHlwZXNbaV1dLCB3cmFwcGVkTWV0aG9kRGVzY1t0eXBlc1tpXV0pO1xuICAgICAgICB9XG4gICAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShvYmplY3QsIHByb3BlcnR5LCBtZXRob2REZXNjKTtcblxuICAgICAgICAvLyBjYXRjaCBmYWlsaW5nIGFzc2lnbm1lbnRcbiAgICAgICAgLy8gdGhpcyBpcyB0aGUgY29udmVyc2Ugb2YgdGhlIGNoZWNrIGluIGAucmVzdG9yZWAgYmVsb3dcbiAgICAgICAgaWYgKCB0eXBlb2YgbWV0aG9kID09PSBcImZ1bmN0aW9uXCIgJiYgb2JqZWN0W3Byb3BlcnR5XSAhPT0gbWV0aG9kICkge1xuICAgICAgICAgICAgLy8gY29ycmVjdCBhbnkgd3Jvbmdkb2luZ3MgY2F1c2VkIGJ5IHRoZSBkZWZpbmVQcm9wZXJ0eSBjYWxsIGFib3ZlLFxuICAgICAgICAgICAgLy8gc3VjaCBhcyBhZGRpbmcgbmV3IGl0ZW1zIChpZiBvYmplY3Qgd2FzIGEgU3RvcmFnZSBvYmplY3QpXG4gICAgICAgICAgICBkZWxldGUgb2JqZWN0W3Byb3BlcnR5XTtcbiAgICAgICAgICAgIHNpbXBsZVByb3BlcnR5QXNzaWdubWVudCgpO1xuICAgICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgICAgc2ltcGxlUHJvcGVydHlBc3NpZ25tZW50KCk7XG4gICAgfVxuXG4gICAgbWV0aG9kLmRpc3BsYXlOYW1lID0gcHJvcGVydHk7XG5cbiAgICAvLyBTZXQgdXAgYSBzdGFjayB0cmFjZSB3aGljaCBjYW4gYmUgdXNlZCBsYXRlciB0byBmaW5kIHdoYXQgbGluZSBvZlxuICAgIC8vIGNvZGUgdGhlIG9yaWdpbmFsIG1ldGhvZCB3YXMgY3JlYXRlZCBvbi5cbiAgICBtZXRob2Quc3RhY2tUcmFjZSA9IChuZXcgRXJyb3IoXCJTdGFjayBUcmFjZSBmb3Igb3JpZ2luYWxcIikpLnN0YWNrO1xuXG4gICAgbWV0aG9kLnJlc3RvcmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIEZvciBwcm90b3R5cGUgcHJvcGVydGllcyB0cnkgdG8gcmVzZXQgYnkgZGVsZXRlIGZpcnN0LlxuICAgICAgICAvLyBJZiB0aGlzIGZhaWxzIChleDogbG9jYWxTdG9yYWdlIG9uIG1vYmlsZSBzYWZhcmkpIHRoZW4gZm9yY2UgYSByZXNldFxuICAgICAgICAvLyB2aWEgZGlyZWN0IGFzc2lnbm1lbnQuXG4gICAgICAgIGlmICghb3duZWQpIHtcbiAgICAgICAgICAgIC8vIEluIHNvbWUgY2FzZXMgYGRlbGV0ZWAgbWF5IHRocm93IGFuIGVycm9yXG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBvYmplY3RbcHJvcGVydHldO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge30gLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby1lbXB0eVxuICAgICAgICAgICAgLy8gRm9yIG5hdGl2ZSBjb2RlIGZ1bmN0aW9ucyBgZGVsZXRlYCBmYWlscyB3aXRob3V0IHRocm93aW5nIGFuIGVycm9yXG4gICAgICAgICAgICAvLyBvbiBDaHJvbWUgPCA0MywgUGhhbnRvbUpTLCBldGMuXG4gICAgICAgIH0gZWxzZSBpZiAoaGFzRVM1U3VwcG9ydCkge1xuICAgICAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG9iamVjdCwgcHJvcGVydHksIHdyYXBwZWRNZXRob2REZXNjKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChoYXNFUzVTdXBwb3J0KSB7XG4gICAgICAgICAgICB2YXIgZGVzY3JpcHRvciA9IGdldFByb3BlcnR5RGVzY3JpcHRvcihvYmplY3QsIHByb3BlcnR5KTtcbiAgICAgICAgICAgIGlmIChkZXNjcmlwdG9yICYmIGRlc2NyaXB0b3IudmFsdWUgPT09IG1ldGhvZCkge1xuICAgICAgICAgICAgICAgIG9iamVjdFtwcm9wZXJ0eV0gPSB3cmFwcGVkTWV0aG9kO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAvLyBVc2Ugc3RyaWN0IGVxdWFsaXR5IGNvbXBhcmlzb24gdG8gY2hlY2sgZmFpbHVyZXMgdGhlbiBmb3JjZSBhIHJlc2V0XG4gICAgICAgIC8vIHZpYSBkaXJlY3QgYXNzaWdubWVudC5cbiAgICAgICAgICAgIGlmIChvYmplY3RbcHJvcGVydHldID09PSBtZXRob2QpIHtcbiAgICAgICAgICAgICAgICBvYmplY3RbcHJvcGVydHldID0gd3JhcHBlZE1ldGhvZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBtZXRob2Qud3JhcHBlZE1ldGhvZCA9IHdyYXBwZWRNZXRob2Q7XG5cbiAgICBtZXRob2QucmVzdG9yZS5zaW5vbiA9IHRydWU7XG5cbiAgICBpZiAoIWhhc0VTNVN1cHBvcnQpIHtcbiAgICAgICAgbWlycm9yUHJvcGVydGllcyhtZXRob2QsIHdyYXBwZWRNZXRob2QpO1xuICAgIH1cblxuICAgIHJldHVybiBtZXRob2Q7XG59O1xuIiwiXCJ1c2Ugc3RyaWN0XCI7XG5cbnZhciBwdXNoID0gW10ucHVzaDtcblxuZnVuY3Rpb24gRXZlbnQodHlwZSwgYnViYmxlcywgY2FuY2VsYWJsZSwgdGFyZ2V0KSB7XG4gICAgdGhpcy5pbml0RXZlbnQodHlwZSwgYnViYmxlcywgY2FuY2VsYWJsZSwgdGFyZ2V0KTtcbn1cblxuRXZlbnQucHJvdG90eXBlID0ge1xuICAgIGluaXRFdmVudDogZnVuY3Rpb24gKHR5cGUsIGJ1YmJsZXMsIGNhbmNlbGFibGUsIHRhcmdldCkge1xuICAgICAgICB0aGlzLnR5cGUgPSB0eXBlO1xuICAgICAgICB0aGlzLmJ1YmJsZXMgPSBidWJibGVzO1xuICAgICAgICB0aGlzLmNhbmNlbGFibGUgPSBjYW5jZWxhYmxlO1xuICAgICAgICB0aGlzLnRhcmdldCA9IHRhcmdldDtcbiAgICB9LFxuXG4gICAgc3RvcFByb3BhZ2F0aW9uOiBmdW5jdGlvbiAoKSB7fSxcblxuICAgIHByZXZlbnREZWZhdWx0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuZGVmYXVsdFByZXZlbnRlZCA9IHRydWU7XG4gICAgfVxufTtcblxuZnVuY3Rpb24gUHJvZ3Jlc3NFdmVudCh0eXBlLCBwcm9ncmVzc0V2ZW50UmF3LCB0YXJnZXQpIHtcbiAgICB0aGlzLmluaXRFdmVudCh0eXBlLCBmYWxzZSwgZmFsc2UsIHRhcmdldCk7XG4gICAgdGhpcy5sb2FkZWQgPSB0eXBlb2YgcHJvZ3Jlc3NFdmVudFJhdy5sb2FkZWQgPT09IFwibnVtYmVyXCIgPyBwcm9ncmVzc0V2ZW50UmF3LmxvYWRlZCA6IG51bGw7XG4gICAgdGhpcy50b3RhbCA9IHR5cGVvZiBwcm9ncmVzc0V2ZW50UmF3LnRvdGFsID09PSBcIm51bWJlclwiID8gcHJvZ3Jlc3NFdmVudFJhdy50b3RhbCA6IG51bGw7XG4gICAgdGhpcy5sZW5ndGhDb21wdXRhYmxlID0gISFwcm9ncmVzc0V2ZW50UmF3LnRvdGFsO1xufVxuXG5Qcm9ncmVzc0V2ZW50LnByb3RvdHlwZSA9IG5ldyBFdmVudCgpO1xuXG5Qcm9ncmVzc0V2ZW50LnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFByb2dyZXNzRXZlbnQ7XG5cbmZ1bmN0aW9uIEN1c3RvbUV2ZW50KHR5cGUsIGN1c3RvbURhdGEsIHRhcmdldCkge1xuICAgIHRoaXMuaW5pdEV2ZW50KHR5cGUsIGZhbHNlLCBmYWxzZSwgdGFyZ2V0KTtcbiAgICB0aGlzLmRldGFpbCA9IGN1c3RvbURhdGEuZGV0YWlsIHx8IG51bGw7XG59XG5cbkN1c3RvbUV2ZW50LnByb3RvdHlwZSA9IG5ldyBFdmVudCgpO1xuXG5DdXN0b21FdmVudC5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBDdXN0b21FdmVudDtcblxudmFyIEV2ZW50VGFyZ2V0ID0ge1xuICAgIGFkZEV2ZW50TGlzdGVuZXI6IGZ1bmN0aW9uIGFkZEV2ZW50TGlzdGVuZXIoZXZlbnQsIGxpc3RlbmVyKSB7XG4gICAgICAgIHRoaXMuZXZlbnRMaXN0ZW5lcnMgPSB0aGlzLmV2ZW50TGlzdGVuZXJzIHx8IHt9O1xuICAgICAgICB0aGlzLmV2ZW50TGlzdGVuZXJzW2V2ZW50XSA9IHRoaXMuZXZlbnRMaXN0ZW5lcnNbZXZlbnRdIHx8IFtdO1xuICAgICAgICBwdXNoLmNhbGwodGhpcy5ldmVudExpc3RlbmVyc1tldmVudF0sIGxpc3RlbmVyKTtcbiAgICB9LFxuXG4gICAgcmVtb3ZlRXZlbnRMaXN0ZW5lcjogZnVuY3Rpb24gcmVtb3ZlRXZlbnRMaXN0ZW5lcihldmVudCwgbGlzdGVuZXIpIHtcbiAgICAgICAgdmFyIGxpc3RlbmVycyA9IHRoaXMuZXZlbnRMaXN0ZW5lcnMgJiYgdGhpcy5ldmVudExpc3RlbmVyc1tldmVudF0gfHwgW107XG4gICAgICAgIHZhciBpbmRleCA9IGxpc3RlbmVycy5pbmRleE9mKGxpc3RlbmVyKTtcblxuICAgICAgICBpZiAoaW5kZXggPT09IC0xKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBsaXN0ZW5lcnMuc3BsaWNlKGluZGV4LCAxKTtcbiAgICB9LFxuXG4gICAgZGlzcGF0Y2hFdmVudDogZnVuY3Rpb24gZGlzcGF0Y2hFdmVudChldmVudCkge1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgIHZhciB0eXBlID0gZXZlbnQudHlwZTtcbiAgICAgICAgdmFyIGxpc3RlbmVycyA9IHNlbGYuZXZlbnRMaXN0ZW5lcnMgJiYgc2VsZi5ldmVudExpc3RlbmVyc1t0eXBlXSB8fCBbXTtcblxuICAgICAgICBsaXN0ZW5lcnMuZm9yRWFjaChmdW5jdGlvbiAobGlzdGVuZXIpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgbGlzdGVuZXIgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgICAgIGxpc3RlbmVyLmNhbGwoc2VsZiwgZXZlbnQpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBsaXN0ZW5lci5oYW5kbGVFdmVudChldmVudCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiAhIWV2ZW50LmRlZmF1bHRQcmV2ZW50ZWQ7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgRXZlbnQ6IEV2ZW50LFxuICAgIFByb2dyZXNzRXZlbnQ6IFByb2dyZXNzRXZlbnQsXG4gICAgQ3VzdG9tRXZlbnQ6IEN1c3RvbUV2ZW50LFxuICAgIEV2ZW50VGFyZ2V0OiBFdmVudFRhcmdldFxufTtcbiIsIlwidXNlIHN0cmljdFwiO1xuXG52YXIgZmFrZVhociA9IHJlcXVpcmUoXCIuL2Zha2VfeG1sX2h0dHBfcmVxdWVzdFwiKTtcbnZhciBwdXNoID0gW10ucHVzaDtcbnZhciBmb3JtYXQgPSByZXF1aXJlKFwiLi9jb3JlL2Zvcm1hdFwiKTtcbnZhciBjb25maWd1cmVMb2dFcnJvciA9IHJlcXVpcmUoXCIuL2NvcmUvbG9nX2Vycm9yXCIpO1xudmFyIHBhdGhUb1JlZ2V4cCA9IHJlcXVpcmUoXCJwYXRoLXRvLXJlZ2V4cFwiKTtcblxuZnVuY3Rpb24gcmVzcG9uc2VBcnJheShoYW5kbGVyKSB7XG4gICAgdmFyIHJlc3BvbnNlID0gaGFuZGxlcjtcblxuICAgIGlmIChPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoaGFuZGxlcikgIT09IFwiW29iamVjdCBBcnJheV1cIikge1xuICAgICAgICByZXNwb25zZSA9IFsyMDAsIHt9LCBoYW5kbGVyXTtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIHJlc3BvbnNlWzJdICE9PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJGYWtlIHNlcnZlciByZXNwb25zZSBib2R5IHNob3VsZCBiZSBzdHJpbmcsIGJ1dCB3YXMgXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGVvZiByZXNwb25zZVsyXSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3BvbnNlO1xufVxuXG52YXIgd2xvYyA9IHR5cGVvZiB3aW5kb3cgIT09IFwidW5kZWZpbmVkXCIgPyB3aW5kb3cubG9jYXRpb24gOiB7IFwiaG9zdFwiOiBcImxvY2FsaG9zdFwiLCBcInByb3RvY29sXCI6IFwiaHR0cFwifTtcbnZhciByQ3VyckxvYyA9IG5ldyBSZWdFeHAoXCJeXCIgKyB3bG9jLnByb3RvY29sICsgXCIvL1wiICsgd2xvYy5ob3N0KTtcblxuZnVuY3Rpb24gbWF0Y2hPbmUocmVzcG9uc2UsIHJlcU1ldGhvZCwgcmVxVXJsKSB7XG4gICAgdmFyIHJtZXRoID0gcmVzcG9uc2UubWV0aG9kO1xuICAgIHZhciBtYXRjaE1ldGhvZCA9ICFybWV0aCB8fCBybWV0aC50b0xvd2VyQ2FzZSgpID09PSByZXFNZXRob2QudG9Mb3dlckNhc2UoKTtcbiAgICB2YXIgdXJsID0gcmVzcG9uc2UudXJsO1xuICAgIHZhciBtYXRjaFVybCA9ICF1cmwgfHwgdXJsID09PSByZXFVcmwgfHwgKHR5cGVvZiB1cmwudGVzdCA9PT0gXCJmdW5jdGlvblwiICYmIHVybC50ZXN0KHJlcVVybCkpO1xuXG4gICAgcmV0dXJuIG1hdGNoTWV0aG9kICYmIG1hdGNoVXJsO1xufVxuXG5mdW5jdGlvbiBtYXRjaChyZXNwb25zZSwgcmVxdWVzdCkge1xuICAgIHZhciByZXF1ZXN0VXJsID0gcmVxdWVzdC51cmw7XG5cbiAgICBpZiAoIS9eaHR0cHM/OlxcL1xcLy8udGVzdChyZXF1ZXN0VXJsKSB8fCByQ3VyckxvYy50ZXN0KHJlcXVlc3RVcmwpKSB7XG4gICAgICAgIHJlcXVlc3RVcmwgPSByZXF1ZXN0VXJsLnJlcGxhY2UockN1cnJMb2MsIFwiXCIpO1xuICAgIH1cblxuICAgIGlmIChtYXRjaE9uZShyZXNwb25zZSwgdGhpcy5nZXRIVFRQTWV0aG9kKHJlcXVlc3QpLCByZXF1ZXN0VXJsKSkge1xuICAgICAgICBpZiAodHlwZW9mIHJlc3BvbnNlLnJlc3BvbnNlID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgIHZhciBydSA9IHJlc3BvbnNlLnVybDtcbiAgICAgICAgICAgIHZhciBhcmdzID0gW3JlcXVlc3RdLmNvbmNhdChydSAmJiB0eXBlb2YgcnUuZXhlYyA9PT0gXCJmdW5jdGlvblwiID8gcnUuZXhlYyhyZXF1ZXN0VXJsKS5zbGljZSgxKSA6IFtdKTtcbiAgICAgICAgICAgIHJldHVybiByZXNwb25zZS5yZXNwb25zZS5hcHBseShyZXNwb25zZSwgYXJncyk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2U7XG59XG5cbmZ1bmN0aW9uIGluY3JlbWVudFJlcXVlc3RDb3VudCgpIHtcbiAgICB2YXIgY291bnQgPSArK3RoaXMucmVxdWVzdENvdW50O1xuXG4gICAgdGhpcy5yZXF1ZXN0ZWQgPSB0cnVlO1xuXG4gICAgdGhpcy5yZXF1ZXN0ZWRPbmNlID0gY291bnQgPT09IDE7XG4gICAgdGhpcy5yZXF1ZXN0ZWRUd2ljZSA9IGNvdW50ID09PSAyO1xuICAgIHRoaXMucmVxdWVzdGVkVGhyaWNlID0gY291bnQgPT09IDM7XG5cbiAgICB0aGlzLmZpcnN0UmVxdWVzdCA9IHRoaXMuZ2V0UmVxdWVzdCgwKTtcbiAgICB0aGlzLnNlY29uZFJlcXVlc3QgPSB0aGlzLmdldFJlcXVlc3QoMSk7XG4gICAgdGhpcy50aGlyZFJlcXVlc3QgPSB0aGlzLmdldFJlcXVlc3QoMik7XG5cbiAgICB0aGlzLmxhc3RSZXF1ZXN0ID0gdGhpcy5nZXRSZXF1ZXN0KGNvdW50IC0gMSk7XG59XG5cbnZhciBmYWtlU2VydmVyID0ge1xuICAgIGNyZWF0ZTogZnVuY3Rpb24gKGNvbmZpZykge1xuICAgICAgICB2YXIgc2VydmVyID0gT2JqZWN0LmNyZWF0ZSh0aGlzKTtcbiAgICAgICAgc2VydmVyLmNvbmZpZ3VyZShjb25maWcpO1xuICAgICAgICB0aGlzLnhociA9IGZha2VYaHIudXNlRmFrZVhNTEh0dHBSZXF1ZXN0KCk7XG4gICAgICAgIHNlcnZlci5yZXF1ZXN0cyA9IFtdO1xuICAgICAgICBzZXJ2ZXIucmVxdWVzdENvdW50ID0gMDtcblxuICAgICAgICB0aGlzLnhoci5vbkNyZWF0ZSA9IGZ1bmN0aW9uICh4aHJPYmopIHtcbiAgICAgICAgICAgIHhock9iai51bnNhZmVIZWFkZXJzRW5hYmxlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gIShzZXJ2ZXIudW5zYWZlSGVhZGVyc0VuYWJsZWQgPT09IGZhbHNlKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBzZXJ2ZXIuYWRkUmVxdWVzdCh4aHJPYmopO1xuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiBzZXJ2ZXI7XG4gICAgfSxcblxuICAgIGNvbmZpZ3VyZTogZnVuY3Rpb24gKGNvbmZpZykge1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgIHZhciB3aGl0ZWxpc3QgPSB7XG4gICAgICAgICAgICBcImF1dG9SZXNwb25kXCI6IHRydWUsXG4gICAgICAgICAgICBcImF1dG9SZXNwb25kQWZ0ZXJcIjogdHJ1ZSxcbiAgICAgICAgICAgIFwicmVzcG9uZEltbWVkaWF0ZWx5XCI6IHRydWUsXG4gICAgICAgICAgICBcImZha2VIVFRQTWV0aG9kc1wiOiB0cnVlLFxuICAgICAgICAgICAgXCJsb2dnZXJcIjogdHJ1ZSxcbiAgICAgICAgICAgIFwidW5zYWZlSGVhZGVyc0VuYWJsZWRcIjogdHJ1ZVxuICAgICAgICB9O1xuXG4gICAgICAgIGNvbmZpZyA9IGNvbmZpZyB8fCB7fTtcblxuICAgICAgICBPYmplY3Qua2V5cyhjb25maWcpLmZvckVhY2goZnVuY3Rpb24gKHNldHRpbmcpIHtcbiAgICAgICAgICAgIGlmIChzZXR0aW5nIGluIHdoaXRlbGlzdCkge1xuICAgICAgICAgICAgICAgIHNlbGZbc2V0dGluZ10gPSBjb25maWdbc2V0dGluZ107XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHNlbGYubG9nRXJyb3IgPSBjb25maWd1cmVMb2dFcnJvcihjb25maWcpO1xuICAgIH0sXG5cbiAgICBhZGRSZXF1ZXN0OiBmdW5jdGlvbiBhZGRSZXF1ZXN0KHhock9iaikge1xuICAgICAgICB2YXIgc2VydmVyID0gdGhpcztcbiAgICAgICAgcHVzaC5jYWxsKHRoaXMucmVxdWVzdHMsIHhock9iaik7XG5cbiAgICAgICAgaW5jcmVtZW50UmVxdWVzdENvdW50LmNhbGwodGhpcyk7XG5cbiAgICAgICAgeGhyT2JqLm9uU2VuZCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHNlcnZlci5oYW5kbGVSZXF1ZXN0KHRoaXMpO1xuXG4gICAgICAgICAgICBpZiAoc2VydmVyLnJlc3BvbmRJbW1lZGlhdGVseSkge1xuICAgICAgICAgICAgICAgIHNlcnZlci5yZXNwb25kKCk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHNlcnZlci5hdXRvUmVzcG9uZCAmJiAhc2VydmVyLnJlc3BvbmRpbmcpIHtcbiAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgc2VydmVyLnJlc3BvbmRpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgc2VydmVyLnJlc3BvbmQoKTtcbiAgICAgICAgICAgICAgICB9LCBzZXJ2ZXIuYXV0b1Jlc3BvbmRBZnRlciB8fCAxMCk7XG5cbiAgICAgICAgICAgICAgICBzZXJ2ZXIucmVzcG9uZGluZyA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgfSxcblxuICAgIGdldEhUVFBNZXRob2Q6IGZ1bmN0aW9uIGdldEhUVFBNZXRob2QocmVxdWVzdCkge1xuICAgICAgICBpZiAodGhpcy5mYWtlSFRUUE1ldGhvZHMgJiYgL3Bvc3QvaS50ZXN0KHJlcXVlc3QubWV0aG9kKSkge1xuICAgICAgICAgICAgdmFyIG1hdGNoZXMgPSAocmVxdWVzdC5yZXF1ZXN0Qm9keSB8fCBcIlwiKS5tYXRjaCgvX21ldGhvZD0oW15cXGI7XSspLyk7XG4gICAgICAgICAgICByZXR1cm4gbWF0Y2hlcyA/IG1hdGNoZXNbMV0gOiByZXF1ZXN0Lm1ldGhvZDtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiByZXF1ZXN0Lm1ldGhvZDtcbiAgICB9LFxuXG4gICAgaGFuZGxlUmVxdWVzdDogZnVuY3Rpb24gaGFuZGxlUmVxdWVzdCh4aHIpIHtcbiAgICAgICAgaWYgKHhoci5hc3luYykge1xuICAgICAgICAgICAgaWYgKCF0aGlzLnF1ZXVlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5xdWV1ZSA9IFtdO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBwdXNoLmNhbGwodGhpcy5xdWV1ZSwgeGhyKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMucHJvY2Vzc1JlcXVlc3QoeGhyKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBsb2dnZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgLy8gbm8tb3A7IG92ZXJyaWRlIHZpYSBjb25maWd1cmUoKVxuICAgIH0sXG5cbiAgICBsb2dFcnJvcjogY29uZmlndXJlTG9nRXJyb3Ioe30pLFxuXG4gICAgbG9nOiBmdW5jdGlvbiBsb2cocmVzcG9uc2UsIHJlcXVlc3QpIHtcbiAgICAgICAgdmFyIHN0cjtcblxuICAgICAgICBzdHIgPSBcIlJlcXVlc3Q6XFxuXCIgKyBmb3JtYXQocmVxdWVzdCkgKyBcIlxcblxcblwiO1xuICAgICAgICBzdHIgKz0gXCJSZXNwb25zZTpcXG5cIiArIGZvcm1hdChyZXNwb25zZSkgKyBcIlxcblxcblwiO1xuXG4gICAgICAgIGlmICh0eXBlb2YgdGhpcy5sb2dnZXIgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgdGhpcy5sb2dnZXIoc3RyKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICByZXNwb25kV2l0aDogZnVuY3Rpb24gcmVzcG9uZFdpdGgobWV0aG9kLCB1cmwsIGJvZHkpIHtcbiAgICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPT09IDEgJiYgdHlwZW9mIG1ldGhvZCAhPT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICB0aGlzLnJlc3BvbnNlID0gcmVzcG9uc2VBcnJheShtZXRob2QpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCF0aGlzLnJlc3BvbnNlcykge1xuICAgICAgICAgICAgdGhpcy5yZXNwb25zZXMgPSBbXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgICBib2R5ID0gbWV0aG9kO1xuICAgICAgICAgICAgdXJsID0gbWV0aG9kID0gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAyKSB7XG4gICAgICAgICAgICBib2R5ID0gdXJsO1xuICAgICAgICAgICAgdXJsID0gbWV0aG9kO1xuICAgICAgICAgICAgbWV0aG9kID0gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIHB1c2guY2FsbCh0aGlzLnJlc3BvbnNlcywge1xuICAgICAgICAgICAgbWV0aG9kOiBtZXRob2QsXG4gICAgICAgICAgICB1cmw6IHR5cGVvZiB1cmwgPT09IFwic3RyaW5nXCIgJiYgdXJsICE9PSBcIlwiID8gcGF0aFRvUmVnZXhwKHVybCkgOiB1cmwsXG4gICAgICAgICAgICByZXNwb25zZTogdHlwZW9mIGJvZHkgPT09IFwiZnVuY3Rpb25cIiA/IGJvZHkgOiByZXNwb25zZUFycmF5KGJvZHkpXG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICByZXNwb25kOiBmdW5jdGlvbiByZXNwb25kKCkge1xuICAgICAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHRoaXMucmVzcG9uZFdpdGguYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBxdWV1ZSA9IHRoaXMucXVldWUgfHwgW107XG4gICAgICAgIHZhciByZXF1ZXN0cyA9IHF1ZXVlLnNwbGljZSgwLCBxdWV1ZS5sZW5ndGgpO1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG5cbiAgICAgICAgcmVxdWVzdHMuZm9yRWFjaChmdW5jdGlvbiAocmVxdWVzdCkge1xuICAgICAgICAgICAgc2VsZi5wcm9jZXNzUmVxdWVzdChyZXF1ZXN0KTtcbiAgICAgICAgfSk7XG4gICAgfSxcblxuICAgIHByb2Nlc3NSZXF1ZXN0OiBmdW5jdGlvbiBwcm9jZXNzUmVxdWVzdChyZXF1ZXN0KSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBpZiAocmVxdWVzdC5hYm9ydGVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcmVzcG9uc2UgPSB0aGlzLnJlc3BvbnNlIHx8IFs0MDQsIHt9LCBcIlwiXTtcblxuICAgICAgICAgICAgaWYgKHRoaXMucmVzcG9uc2VzKSB7XG4gICAgICAgICAgICAgICAgZm9yICh2YXIgbCA9IHRoaXMucmVzcG9uc2VzLmxlbmd0aCwgaSA9IGwgLSAxOyBpID49IDA7IGktLSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAobWF0Y2guY2FsbCh0aGlzLCB0aGlzLnJlc3BvbnNlc1tpXSwgcmVxdWVzdCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlID0gdGhpcy5yZXNwb25zZXNbaV0ucmVzcG9uc2U7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHJlcXVlc3QucmVhZHlTdGF0ZSAhPT0gNCkge1xuICAgICAgICAgICAgICAgIHRoaXMubG9nKHJlc3BvbnNlLCByZXF1ZXN0KTtcblxuICAgICAgICAgICAgICAgIHJlcXVlc3QucmVzcG9uZChyZXNwb25zZVswXSwgcmVzcG9uc2VbMV0sIHJlc3BvbnNlWzJdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgdGhpcy5sb2dFcnJvcihcIkZha2Ugc2VydmVyIHJlcXVlc3QgcHJvY2Vzc2luZ1wiLCBlKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICByZXN0b3JlOiBmdW5jdGlvbiByZXN0b3JlKCkge1xuICAgICAgICByZXR1cm4gdGhpcy54aHIucmVzdG9yZSAmJiB0aGlzLnhoci5yZXN0b3JlLmFwcGx5KHRoaXMueGhyLCBhcmd1bWVudHMpO1xuICAgIH0sXG5cbiAgICBnZXRSZXF1ZXN0OiBmdW5jdGlvbiBnZXRSZXF1ZXN0KGluZGV4KSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJlcXVlc3RzW2luZGV4XSB8fCBudWxsO1xuICAgIH0sXG5cbiAgICByZXNldDogZnVuY3Rpb24gcmVzZXQoKSB7XG4gICAgICAgIHRoaXMucmVzZXRCZWhhdmlvcigpO1xuICAgICAgICB0aGlzLnJlc2V0SGlzdG9yeSgpO1xuICAgIH0sXG5cbiAgICByZXNldEJlaGF2aW9yOiBmdW5jdGlvbiByZXNldEJlaGF2aW9yKCkge1xuICAgICAgICB0aGlzLnJlc3BvbnNlcy5sZW5ndGggPSB0aGlzLnF1ZXVlLmxlbmd0aCA9IDA7XG4gICAgfSxcblxuICAgIHJlc2V0SGlzdG9yeTogZnVuY3Rpb24gcmVzZXRIaXN0b3J5KCkge1xuICAgICAgICB0aGlzLnJlcXVlc3RzLmxlbmd0aCA9IHRoaXMucmVxdWVzdENvdW50ID0gMDtcblxuICAgICAgICB0aGlzLnJlcXVlc3RlZE9uY2UgPSB0aGlzLnJlcXVlc3RlZFR3aWNlID0gdGhpcy5yZXF1ZXN0ZWRUaHJpY2UgPSB0aGlzLnJlcXVlc3RlZCA9IGZhbHNlO1xuXG4gICAgICAgIHRoaXMuZmlyc3RSZXF1ZXN0ID0gdGhpcy5zZWNvbmRSZXF1ZXN0ID0gdGhpcy50aGlyZFJlcXVlc3QgPSB0aGlzLmxhc3RSZXF1ZXN0ID0gbnVsbDtcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZha2VTZXJ2ZXI7XG4iLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIGZha2VTZXJ2ZXIgPSByZXF1aXJlKFwiLi9mYWtlX3NlcnZlclwiKTtcbnZhciBmYWtlVGltZXJzID0gcmVxdWlyZShcIi4vZmFrZV90aW1lcnNcIik7XG5cbmZ1bmN0aW9uIFNlcnZlcigpIHt9XG5TZXJ2ZXIucHJvdG90eXBlID0gZmFrZVNlcnZlcjtcblxudmFyIGZha2VTZXJ2ZXJXaXRoQ2xvY2sgPSBuZXcgU2VydmVyKCk7XG5cbmZha2VTZXJ2ZXJXaXRoQ2xvY2suYWRkUmVxdWVzdCA9IGZ1bmN0aW9uIGFkZFJlcXVlc3QoeGhyKSB7XG4gICAgaWYgKHhoci5hc3luYykge1xuICAgICAgICBpZiAodHlwZW9mIHNldFRpbWVvdXQuY2xvY2sgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgICAgIHRoaXMuY2xvY2sgPSBzZXRUaW1lb3V0LmNsb2NrO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5jbG9jayA9IGZha2VUaW1lcnMudXNlRmFrZVRpbWVycygpO1xuICAgICAgICAgICAgdGhpcy5yZXNldENsb2NrID0gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghdGhpcy5sb25nZXN0VGltZW91dCkge1xuICAgICAgICAgICAgdmFyIGNsb2NrU2V0VGltZW91dCA9IHRoaXMuY2xvY2suc2V0VGltZW91dDtcbiAgICAgICAgICAgIHZhciBjbG9ja1NldEludGVydmFsID0gdGhpcy5jbG9jay5zZXRJbnRlcnZhbDtcbiAgICAgICAgICAgIHZhciBzZXJ2ZXIgPSB0aGlzO1xuXG4gICAgICAgICAgICB0aGlzLmNsb2NrLnNldFRpbWVvdXQgPSBmdW5jdGlvbiAoZm4sIHRpbWVvdXQpIHtcbiAgICAgICAgICAgICAgICBzZXJ2ZXIubG9uZ2VzdFRpbWVvdXQgPSBNYXRoLm1heCh0aW1lb3V0LCBzZXJ2ZXIubG9uZ2VzdFRpbWVvdXQgfHwgMCk7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gY2xvY2tTZXRUaW1lb3V0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB0aGlzLmNsb2NrLnNldEludGVydmFsID0gZnVuY3Rpb24gKGZuLCB0aW1lb3V0KSB7XG4gICAgICAgICAgICAgICAgc2VydmVyLmxvbmdlc3RUaW1lb3V0ID0gTWF0aC5tYXgodGltZW91dCwgc2VydmVyLmxvbmdlc3RUaW1lb3V0IHx8IDApO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIGNsb2NrU2V0SW50ZXJ2YWwuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZmFrZVNlcnZlci5hZGRSZXF1ZXN0LmNhbGwodGhpcywgeGhyKTtcbn07XG5cbmZha2VTZXJ2ZXJXaXRoQ2xvY2sucmVzcG9uZCA9IGZ1bmN0aW9uIHJlc3BvbmQoKSB7XG4gICAgdmFyIHJldHVyblZhbCA9IGZha2VTZXJ2ZXIucmVzcG9uZC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuXG4gICAgaWYgKHRoaXMuY2xvY2spIHtcbiAgICAgICAgdGhpcy5jbG9jay50aWNrKHRoaXMubG9uZ2VzdFRpbWVvdXQgfHwgMCk7XG4gICAgICAgIHRoaXMubG9uZ2VzdFRpbWVvdXQgPSAwO1xuXG4gICAgICAgIGlmICh0aGlzLnJlc2V0Q2xvY2spIHtcbiAgICAgICAgICAgIHRoaXMuY2xvY2sucmVzdG9yZSgpO1xuICAgICAgICAgICAgdGhpcy5yZXNldENsb2NrID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gcmV0dXJuVmFsO1xufTtcblxuZmFrZVNlcnZlcldpdGhDbG9jay5yZXN0b3JlID0gZnVuY3Rpb24gcmVzdG9yZSgpIHtcbiAgICBpZiAodGhpcy5jbG9jaykge1xuICAgICAgICB0aGlzLmNsb2NrLnJlc3RvcmUoKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZmFrZVNlcnZlci5yZXN0b3JlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZha2VTZXJ2ZXJXaXRoQ2xvY2s7XG4iLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIGxseCA9IHJlcXVpcmUoXCJsb2xleFwiKTtcblxuZXhwb3J0cy51c2VGYWtlVGltZXJzID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBub3c7XG4gICAgdmFyIG1ldGhvZHMgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuXG4gICAgaWYgKHR5cGVvZiBtZXRob2RzWzBdID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIG5vdyA9IDA7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgbm93ID0gbWV0aG9kcy5zaGlmdCgpO1xuICAgIH1cblxuICAgIHZhciBjbG9jayA9IGxseC5pbnN0YWxsKG5vdyB8fCAwLCBtZXRob2RzKTtcbiAgICBjbG9jay5yZXN0b3JlID0gY2xvY2sudW5pbnN0YWxsO1xuICAgIHJldHVybiBjbG9jaztcbn07XG5cbmV4cG9ydHMuY2xvY2sgPSB7XG4gICAgY3JlYXRlOiBmdW5jdGlvbiAobm93KSB7XG4gICAgICAgIHJldHVybiBsbHguY3JlYXRlQ2xvY2sobm93KTtcbiAgICB9XG59O1xuXG5leHBvcnRzLnRpbWVycyA9IHtcbiAgICBzZXRUaW1lb3V0OiBzZXRUaW1lb3V0LFxuICAgIGNsZWFyVGltZW91dDogY2xlYXJUaW1lb3V0LFxuICAgIHNldEltbWVkaWF0ZTogKHR5cGVvZiBzZXRJbW1lZGlhdGUgIT09IFwidW5kZWZpbmVkXCIgPyBzZXRJbW1lZGlhdGUgOiB1bmRlZmluZWQpLFxuICAgIGNsZWFySW1tZWRpYXRlOiAodHlwZW9mIGNsZWFySW1tZWRpYXRlICE9PSBcInVuZGVmaW5lZFwiID8gY2xlYXJJbW1lZGlhdGUgOiB1bmRlZmluZWQpLFxuICAgIHNldEludGVydmFsOiBzZXRJbnRlcnZhbCxcbiAgICBjbGVhckludGVydmFsOiBjbGVhckludGVydmFsLFxuICAgIERhdGU6IERhdGVcbn07XG4iLCJcInVzZSBzdHJpY3RcIjtcblxudmFyIFRleHRFbmNvZGVyID0gcmVxdWlyZShcInRleHQtZW5jb2RpbmdcIikuVGV4dEVuY29kZXI7XG5cbnZhciBjb25maWd1cmVMb2dFcnJvciA9IHJlcXVpcmUoXCIuL2NvcmUvbG9nX2Vycm9yXCIpO1xudmFyIHNpbm9uRXZlbnQgPSByZXF1aXJlKFwiLi9ldmVudFwiKTtcbnZhciBleHRlbmQgPSByZXF1aXJlKFwiLi9jb3JlL2V4dGVuZFwiKTtcblxuZnVuY3Rpb24gZ2V0V29ya2luZ1hIUihnbG9iYWxTY29wZSkge1xuICAgIHZhciBzdXBwb3J0c1hIUiA9IHR5cGVvZiBnbG9iYWxTY29wZS5YTUxIdHRwUmVxdWVzdCAhPT0gXCJ1bmRlZmluZWRcIjtcbiAgICBpZiAoc3VwcG9ydHNYSFIpIHtcbiAgICAgICAgcmV0dXJuIGdsb2JhbFNjb3BlLlhNTEh0dHBSZXF1ZXN0O1xuICAgIH1cblxuICAgIHZhciBzdXBwb3J0c0FjdGl2ZVggPSB0eXBlb2YgZ2xvYmFsU2NvcGUuQWN0aXZlWE9iamVjdCAhPT0gXCJ1bmRlZmluZWRcIjtcbiAgICBpZiAoc3VwcG9ydHNBY3RpdmVYKSB7XG4gICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IGdsb2JhbFNjb3BlLkFjdGl2ZVhPYmplY3QoXCJNU1hNTDIuWE1MSFRUUC4zLjBcIik7XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIGZhbHNlO1xufVxuXG52YXIgc3VwcG9ydHNQcm9ncmVzcyA9IHR5cGVvZiBQcm9ncmVzc0V2ZW50ICE9PSBcInVuZGVmaW5lZFwiO1xudmFyIHN1cHBvcnRzQ3VzdG9tRXZlbnQgPSB0eXBlb2YgQ3VzdG9tRXZlbnQgIT09IFwidW5kZWZpbmVkXCI7XG52YXIgc3VwcG9ydHNGb3JtRGF0YSA9IHR5cGVvZiBGb3JtRGF0YSAhPT0gXCJ1bmRlZmluZWRcIjtcbnZhciBzdXBwb3J0c0FycmF5QnVmZmVyID0gdHlwZW9mIEFycmF5QnVmZmVyICE9PSBcInVuZGVmaW5lZFwiO1xudmFyIHN1cHBvcnRzQmxvYiA9IHJlcXVpcmUoXCIuLi9ibG9iXCIpLmlzU3VwcG9ydGVkO1xudmFyIGlzUmVhY3ROYXRpdmUgPSBnbG9iYWwubmF2aWdhdG9yICYmIGdsb2JhbC5uYXZpZ2F0b3IucHJvZHVjdCA9PT0gXCJSZWFjdE5hdGl2ZVwiO1xudmFyIHNpbm9uWGhyID0geyBYTUxIdHRwUmVxdWVzdDogZ2xvYmFsLlhNTEh0dHBSZXF1ZXN0IH07XG5zaW5vblhoci5HbG9iYWxYTUxIdHRwUmVxdWVzdCA9IGdsb2JhbC5YTUxIdHRwUmVxdWVzdDtcbnNpbm9uWGhyLkdsb2JhbEFjdGl2ZVhPYmplY3QgPSBnbG9iYWwuQWN0aXZlWE9iamVjdDtcbnNpbm9uWGhyLnN1cHBvcnRzQWN0aXZlWCA9IHR5cGVvZiBzaW5vblhoci5HbG9iYWxBY3RpdmVYT2JqZWN0ICE9PSBcInVuZGVmaW5lZFwiO1xuc2lub25YaHIuc3VwcG9ydHNYSFIgPSB0eXBlb2Ygc2lub25YaHIuR2xvYmFsWE1MSHR0cFJlcXVlc3QgIT09IFwidW5kZWZpbmVkXCI7XG5zaW5vblhoci53b3JraW5nWEhSID0gZ2V0V29ya2luZ1hIUihnbG9iYWwpO1xuc2lub25YaHIuc3VwcG9ydHNDT1JTID0gaXNSZWFjdE5hdGl2ZSB8fFxuICAgIChzaW5vblhoci5zdXBwb3J0c1hIUiAmJiBcIndpdGhDcmVkZW50aWFsc1wiIGluIChuZXcgc2lub25YaHIuR2xvYmFsWE1MSHR0cFJlcXVlc3QoKSkpO1xuXG52YXIgdW5zYWZlSGVhZGVycyA9IHtcbiAgICBcIkFjY2VwdC1DaGFyc2V0XCI6IHRydWUsXG4gICAgXCJBY2NlcHQtRW5jb2RpbmdcIjogdHJ1ZSxcbiAgICBcIkNvbm5lY3Rpb25cIjogdHJ1ZSxcbiAgICBcIkNvbnRlbnQtTGVuZ3RoXCI6IHRydWUsXG4gICAgXCJDb29raWVcIjogdHJ1ZSxcbiAgICBcIkNvb2tpZTJcIjogdHJ1ZSxcbiAgICBcIkNvbnRlbnQtVHJhbnNmZXItRW5jb2RpbmdcIjogdHJ1ZSxcbiAgICBcIkRhdGVcIjogdHJ1ZSxcbiAgICBcIkV4cGVjdFwiOiB0cnVlLFxuICAgIFwiSG9zdFwiOiB0cnVlLFxuICAgIFwiS2VlcC1BbGl2ZVwiOiB0cnVlLFxuICAgIFwiUmVmZXJlclwiOiB0cnVlLFxuICAgIFwiVEVcIjogdHJ1ZSxcbiAgICBcIlRyYWlsZXJcIjogdHJ1ZSxcbiAgICBcIlRyYW5zZmVyLUVuY29kaW5nXCI6IHRydWUsXG4gICAgXCJVcGdyYWRlXCI6IHRydWUsXG4gICAgXCJVc2VyLUFnZW50XCI6IHRydWUsXG4gICAgXCJWaWFcIjogdHJ1ZVxufTtcblxuXG5mdW5jdGlvbiBFdmVudFRhcmdldEhhbmRsZXIoKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHZhciBldmVudHMgPSBbXCJsb2Fkc3RhcnRcIiwgXCJwcm9ncmVzc1wiLCBcImFib3J0XCIsIFwiZXJyb3JcIiwgXCJsb2FkXCIsIFwidGltZW91dFwiLCBcImxvYWRlbmRcIl07XG5cbiAgICBmdW5jdGlvbiBhZGRFdmVudExpc3RlbmVyKGV2ZW50TmFtZSkge1xuICAgICAgICBzZWxmLmFkZEV2ZW50TGlzdGVuZXIoZXZlbnROYW1lLCBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgIHZhciBsaXN0ZW5lciA9IHNlbGZbXCJvblwiICsgZXZlbnROYW1lXTtcblxuICAgICAgICAgICAgaWYgKGxpc3RlbmVyICYmIHR5cGVvZiBsaXN0ZW5lciA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgICAgbGlzdGVuZXIuY2FsbCh0aGlzLCBldmVudCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGV2ZW50cy5mb3JFYWNoKGFkZEV2ZW50TGlzdGVuZXIpO1xufVxuXG5FdmVudFRhcmdldEhhbmRsZXIucHJvdG90eXBlID0gc2lub25FdmVudC5FdmVudFRhcmdldDtcblxuLy8gTm90ZSB0aGF0IGZvciBGYWtlWE1MSHR0cFJlcXVlc3QgdG8gd29yayBwcmUgRVM1XG4vLyB3ZSBsb3NlIHNvbWUgb2YgdGhlIGFsaWdubWVudCB3aXRoIHRoZSBzcGVjLlxuLy8gVG8gZW5zdXJlIGFzIGNsb3NlIGEgbWF0Y2ggYXMgcG9zc2libGUsXG4vLyBzZXQgcmVzcG9uc2VUeXBlIGJlZm9yZSBjYWxsaW5nIG9wZW4sIHNlbmQgb3IgcmVzcG9uZDtcbmZ1bmN0aW9uIEZha2VYTUxIdHRwUmVxdWVzdChjb25maWcpIHtcbiAgICBFdmVudFRhcmdldEhhbmRsZXIuY2FsbCh0aGlzKTtcbiAgICB0aGlzLnJlYWR5U3RhdGUgPSBGYWtlWE1MSHR0cFJlcXVlc3QuVU5TRU5UO1xuICAgIHRoaXMucmVxdWVzdEhlYWRlcnMgPSB7fTtcbiAgICB0aGlzLnJlcXVlc3RCb2R5ID0gbnVsbDtcbiAgICB0aGlzLnN0YXR1cyA9IDA7XG4gICAgdGhpcy5zdGF0dXNUZXh0ID0gXCJcIjtcbiAgICB0aGlzLnVwbG9hZCA9IG5ldyBFdmVudFRhcmdldEhhbmRsZXIoKTtcbiAgICB0aGlzLnJlc3BvbnNlVHlwZSA9IFwiXCI7XG4gICAgdGhpcy5yZXNwb25zZSA9IFwiXCI7XG4gICAgdGhpcy5sb2dFcnJvciA9IGNvbmZpZ3VyZUxvZ0Vycm9yKGNvbmZpZyk7XG4gICAgaWYgKHNpbm9uWGhyLnN1cHBvcnRzQ09SUykge1xuICAgICAgICB0aGlzLndpdGhDcmVkZW50aWFscyA9IGZhbHNlO1xuICAgIH1cblxuICAgIGlmICh0eXBlb2YgRmFrZVhNTEh0dHBSZXF1ZXN0Lm9uQ3JlYXRlID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgRmFrZVhNTEh0dHBSZXF1ZXN0Lm9uQ3JlYXRlKHRoaXMpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gdmVyaWZ5U3RhdGUoeGhyKSB7XG4gICAgaWYgKHhoci5yZWFkeVN0YXRlICE9PSBGYWtlWE1MSHR0cFJlcXVlc3QuT1BFTkVEKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIklOVkFMSURfU1RBVEVfRVJSXCIpO1xuICAgIH1cblxuICAgIGlmICh4aHIuc2VuZEZsYWcpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSU5WQUxJRF9TVEFURV9FUlJcIik7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBnZXRIZWFkZXIoaGVhZGVycywgaGVhZGVyKSB7XG4gICAgdmFyIGZvdW5kSGVhZGVyID0gT2JqZWN0LmtleXMoaGVhZGVycykuZmlsdGVyKGZ1bmN0aW9uIChoKSB7XG4gICAgICAgIHJldHVybiBoLnRvTG93ZXJDYXNlKCkgPT09IGhlYWRlci50b0xvd2VyQ2FzZSgpO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIGZvdW5kSGVhZGVyWzBdIHx8IG51bGw7XG59XG5cbmZ1bmN0aW9uIGV4Y2x1ZGVTZXRDb29raWUySGVhZGVyKGhlYWRlcikge1xuICAgIHJldHVybiAhL15TZXQtQ29va2llMj8kL2kudGVzdChoZWFkZXIpO1xufVxuXG4vLyBsYXJnZXN0IGFyaXR5IGluIFhIUiBpcyA1IC0gWEhSI29wZW5cbnZhciBhcHBseSA9IGZ1bmN0aW9uIChvYmosIG1ldGhvZCwgYXJncykge1xuICAgIHN3aXRjaCAoYXJncy5sZW5ndGgpIHtcbiAgICAgICAgY2FzZSAwOiByZXR1cm4gb2JqW21ldGhvZF0oKTtcbiAgICAgICAgY2FzZSAxOiByZXR1cm4gb2JqW21ldGhvZF0oYXJnc1swXSk7XG4gICAgICAgIGNhc2UgMjogcmV0dXJuIG9ialttZXRob2RdKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgICAgICBjYXNlIDM6IHJldHVybiBvYmpbbWV0aG9kXShhcmdzWzBdLCBhcmdzWzFdLCBhcmdzWzJdKTtcbiAgICAgICAgY2FzZSA0OiByZXR1cm4gb2JqW21ldGhvZF0oYXJnc1swXSwgYXJnc1sxXSwgYXJnc1syXSwgYXJnc1szXSk7XG4gICAgICAgIGNhc2UgNTogcmV0dXJuIG9ialttZXRob2RdKGFyZ3NbMF0sIGFyZ3NbMV0sIGFyZ3NbMl0sIGFyZ3NbM10sIGFyZ3NbNF0pO1xuICAgICAgICBkZWZhdWx0OiB0aHJvdyBuZXcgRXJyb3IoXCJVbmhhbmRsZWQgY2FzZVwiKTtcbiAgICB9XG59O1xuXG5GYWtlWE1MSHR0cFJlcXVlc3QuZmlsdGVycyA9IFtdO1xuRmFrZVhNTEh0dHBSZXF1ZXN0LmFkZEZpbHRlciA9IGZ1bmN0aW9uIGFkZEZpbHRlcihmbikge1xuICAgIHRoaXMuZmlsdGVycy5wdXNoKGZuKTtcbn07XG5GYWtlWE1MSHR0cFJlcXVlc3QuZGVmYWtlID0gZnVuY3Rpb24gZGVmYWtlKGZha2VYaHIsIHhockFyZ3MpIHtcbiAgICB2YXIgeGhyID0gbmV3IHNpbm9uWGhyLndvcmtpbmdYSFIoKTsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuZXctY2FwXG5cbiAgICBbXG4gICAgICAgIFwib3BlblwiLFxuICAgICAgICBcInNldFJlcXVlc3RIZWFkZXJcIixcbiAgICAgICAgXCJzZW5kXCIsXG4gICAgICAgIFwiYWJvcnRcIixcbiAgICAgICAgXCJnZXRSZXNwb25zZUhlYWRlclwiLFxuICAgICAgICBcImdldEFsbFJlc3BvbnNlSGVhZGVyc1wiLFxuICAgICAgICBcImFkZEV2ZW50TGlzdGVuZXJcIixcbiAgICAgICAgXCJvdmVycmlkZU1pbWVUeXBlXCIsXG4gICAgICAgIFwicmVtb3ZlRXZlbnRMaXN0ZW5lclwiXG4gICAgXS5mb3JFYWNoKGZ1bmN0aW9uIChtZXRob2QpIHtcbiAgICAgICAgZmFrZVhoclttZXRob2RdID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIGFwcGx5KHhociwgbWV0aG9kLCBhcmd1bWVudHMpO1xuICAgICAgICB9O1xuICAgIH0pO1xuXG4gICAgdmFyIGNvcHlBdHRycyA9IGZ1bmN0aW9uIChhcmdzKSB7XG4gICAgICAgIGFyZ3MuZm9yRWFjaChmdW5jdGlvbiAoYXR0cikge1xuICAgICAgICAgICAgZmFrZVhoclthdHRyXSA9IHhoclthdHRyXTtcbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIHZhciBzdGF0ZUNoYW5nZSA9IGZ1bmN0aW9uIHN0YXRlQ2hhbmdlKCkge1xuICAgICAgICBmYWtlWGhyLnJlYWR5U3RhdGUgPSB4aHIucmVhZHlTdGF0ZTtcbiAgICAgICAgaWYgKHhoci5yZWFkeVN0YXRlID49IEZha2VYTUxIdHRwUmVxdWVzdC5IRUFERVJTX1JFQ0VJVkVEKSB7XG4gICAgICAgICAgICBjb3B5QXR0cnMoW1wic3RhdHVzXCIsIFwic3RhdHVzVGV4dFwiXSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHhoci5yZWFkeVN0YXRlID49IEZha2VYTUxIdHRwUmVxdWVzdC5MT0FESU5HKSB7XG4gICAgICAgICAgICBjb3B5QXR0cnMoW1wicmVzcG9uc2VUZXh0XCIsIFwicmVzcG9uc2VcIl0pO1xuICAgICAgICB9XG4gICAgICAgIGlmICh4aHIucmVhZHlTdGF0ZSA9PT0gRmFrZVhNTEh0dHBSZXF1ZXN0LkRPTkUpIHtcbiAgICAgICAgICAgIGNvcHlBdHRycyhbXCJyZXNwb25zZVhNTFwiXSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGZha2VYaHIub25yZWFkeXN0YXRlY2hhbmdlKSB7XG4gICAgICAgICAgICBmYWtlWGhyLm9ucmVhZHlzdGF0ZWNoYW5nZS5jYWxsKGZha2VYaHIsIHsgdGFyZ2V0OiBmYWtlWGhyIH0pO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIGlmICh4aHIuYWRkRXZlbnRMaXN0ZW5lcikge1xuICAgICAgICBPYmplY3Qua2V5cyhmYWtlWGhyLmV2ZW50TGlzdGVuZXJzKS5mb3JFYWNoKGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAgICAgLyplc2xpbnQtZGlzYWJsZSBuby1sb29wLWZ1bmMqL1xuICAgICAgICAgICAgZmFrZVhoci5ldmVudExpc3RlbmVyc1tldmVudF0uZm9yRWFjaChmdW5jdGlvbiAoaGFuZGxlcikge1xuICAgICAgICAgICAgICAgIHhoci5hZGRFdmVudExpc3RlbmVyKGV2ZW50LCBoYW5kbGVyKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgLyplc2xpbnQtZW5hYmxlIG5vLWxvb3AtZnVuYyovXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHhoci5hZGRFdmVudExpc3RlbmVyKFwicmVhZHlzdGF0ZWNoYW5nZVwiLCBzdGF0ZUNoYW5nZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgeGhyLm9ucmVhZHlzdGF0ZWNoYW5nZSA9IHN0YXRlQ2hhbmdlO1xuICAgIH1cbiAgICBhcHBseSh4aHIsIFwib3BlblwiLCB4aHJBcmdzKTtcbn07XG5GYWtlWE1MSHR0cFJlcXVlc3QudXNlRmlsdGVycyA9IGZhbHNlO1xuXG5mdW5jdGlvbiB2ZXJpZnlSZXF1ZXN0T3BlbmVkKHhocikge1xuICAgIGlmICh4aHIucmVhZHlTdGF0ZSAhPT0gRmFrZVhNTEh0dHBSZXF1ZXN0Lk9QRU5FRCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJTlZBTElEX1NUQVRFX0VSUiAtIFwiICsgeGhyLnJlYWR5U3RhdGUpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gdmVyaWZ5UmVxdWVzdFNlbnQoeGhyKSB7XG4gICAgaWYgKHhoci5yZWFkeVN0YXRlID09PSBGYWtlWE1MSHR0cFJlcXVlc3QuRE9ORSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJSZXF1ZXN0IGRvbmVcIik7XG4gICAgfVxufVxuXG5mdW5jdGlvbiB2ZXJpZnlIZWFkZXJzUmVjZWl2ZWQoeGhyKSB7XG4gICAgaWYgKHhoci5hc3luYyAmJiB4aHIucmVhZHlTdGF0ZSAhPT0gRmFrZVhNTEh0dHBSZXF1ZXN0LkhFQURFUlNfUkVDRUlWRUQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTm8gaGVhZGVycyByZWNlaXZlZFwiKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIHZlcmlmeVJlc3BvbnNlQm9keVR5cGUoYm9keSkge1xuICAgIGlmICh0eXBlb2YgYm9keSAhPT0gXCJzdHJpbmdcIikge1xuICAgICAgICB2YXIgZXJyb3IgPSBuZXcgRXJyb3IoXCJBdHRlbXB0ZWQgdG8gcmVzcG9uZCB0byBmYWtlIFhNTEh0dHBSZXF1ZXN0IHdpdGggXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICBib2R5ICsgXCIsIHdoaWNoIGlzIG5vdCBhIHN0cmluZy5cIik7XG4gICAgICAgIGVycm9yLm5hbWUgPSBcIkludmFsaWRCb2R5RXhjZXB0aW9uXCI7XG4gICAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gY29udmVydFRvQXJyYXlCdWZmZXIoYm9keSwgZW5jb2RpbmcpIHtcbiAgICByZXR1cm4gbmV3IFRleHRFbmNvZGVyKGVuY29kaW5nIHx8IFwidXRmLThcIikuZW5jb2RlKGJvZHkpLmJ1ZmZlcjtcbn1cblxuZnVuY3Rpb24gaXNYbWxDb250ZW50VHlwZShjb250ZW50VHlwZSkge1xuICAgIHJldHVybiAhY29udGVudFR5cGUgfHwgLyh0ZXh0XFwveG1sKXwoYXBwbGljYXRpb25cXC94bWwpfChcXCt4bWwpLy50ZXN0KGNvbnRlbnRUeXBlKTtcbn1cblxuZnVuY3Rpb24gY29udmVydFJlc3BvbnNlQm9keShyZXNwb25zZVR5cGUsIGNvbnRlbnRUeXBlLCBib2R5KSB7XG4gICAgaWYgKHJlc3BvbnNlVHlwZSA9PT0gXCJcIiB8fCByZXNwb25zZVR5cGUgPT09IFwidGV4dFwiKSB7XG4gICAgICAgIHJldHVybiBib2R5O1xuICAgIH0gZWxzZSBpZiAoc3VwcG9ydHNBcnJheUJ1ZmZlciAmJiByZXNwb25zZVR5cGUgPT09IFwiYXJyYXlidWZmZXJcIikge1xuICAgICAgICByZXR1cm4gY29udmVydFRvQXJyYXlCdWZmZXIoYm9keSk7XG4gICAgfSBlbHNlIGlmIChyZXNwb25zZVR5cGUgPT09IFwianNvblwiKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShib2R5KTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgLy8gUmV0dXJuIHBhcnNpbmcgZmFpbHVyZSBhcyBudWxsXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgIH0gZWxzZSBpZiAoc3VwcG9ydHNCbG9iICYmIHJlc3BvbnNlVHlwZSA9PT0gXCJibG9iXCIpIHtcbiAgICAgICAgdmFyIGJsb2JPcHRpb25zID0ge307XG4gICAgICAgIGlmIChjb250ZW50VHlwZSkge1xuICAgICAgICAgICAgYmxvYk9wdGlvbnMudHlwZSA9IGNvbnRlbnRUeXBlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZXcgQmxvYihbY29udmVydFRvQXJyYXlCdWZmZXIoYm9keSldLCBibG9iT3B0aW9ucyk7XG4gICAgfSBlbHNlIGlmIChyZXNwb25zZVR5cGUgPT09IFwiZG9jdW1lbnRcIikge1xuICAgICAgICBpZiAoaXNYbWxDb250ZW50VHlwZShjb250ZW50VHlwZSkpIHtcbiAgICAgICAgICAgIHJldHVybiBGYWtlWE1MSHR0cFJlcXVlc3QucGFyc2VYTUwoYm9keSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgcmVzcG9uc2VUeXBlIFwiICsgcmVzcG9uc2VUeXBlKTtcbn1cblxuZnVuY3Rpb24gY2xlYXJSZXNwb25zZSh4aHIpIHtcbiAgICBpZiAoeGhyLnJlc3BvbnNlVHlwZSA9PT0gXCJcIiB8fCB4aHIucmVzcG9uc2VUeXBlID09PSBcInRleHRcIikge1xuICAgICAgICB4aHIucmVzcG9uc2UgPSB4aHIucmVzcG9uc2VUZXh0ID0gXCJcIjtcbiAgICB9IGVsc2Uge1xuICAgICAgICB4aHIucmVzcG9uc2UgPSB4aHIucmVzcG9uc2VUZXh0ID0gbnVsbDtcbiAgICB9XG4gICAgeGhyLnJlc3BvbnNlWE1MID0gbnVsbDtcbn1cblxuRmFrZVhNTEh0dHBSZXF1ZXN0LnBhcnNlWE1MID0gZnVuY3Rpb24gcGFyc2VYTUwodGV4dCkge1xuICAgIC8vIFRyZWF0IGVtcHR5IHN0cmluZyBhcyBwYXJzaW5nIGZhaWx1cmVcbiAgICBpZiAodGV4dCAhPT0gXCJcIikge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBET01QYXJzZXIgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICAgICAgICB2YXIgcGFyc2VyID0gbmV3IERPTVBhcnNlcigpO1xuICAgICAgICAgICAgICAgIHJldHVybiBwYXJzZXIucGFyc2VGcm9tU3RyaW5nKHRleHQsIFwidGV4dC94bWxcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgeG1sRG9jID0gbmV3IHdpbmRvdy5BY3RpdmVYT2JqZWN0KFwiTWljcm9zb2Z0LlhNTERPTVwiKTtcbiAgICAgICAgICAgIHhtbERvYy5hc3luYyA9IFwiZmFsc2VcIjtcbiAgICAgICAgICAgIHhtbERvYy5sb2FkWE1MKHRleHQpO1xuICAgICAgICAgICAgcmV0dXJuIHhtbERvYztcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgLy8gVW5hYmxlIHRvIHBhcnNlIFhNTCAtIG5vIGJpZ2dpZVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIG51bGw7XG59O1xuXG5GYWtlWE1MSHR0cFJlcXVlc3Quc3RhdHVzQ29kZXMgPSB7XG4gICAgMTAwOiBcIkNvbnRpbnVlXCIsXG4gICAgMTAxOiBcIlN3aXRjaGluZyBQcm90b2NvbHNcIixcbiAgICAyMDA6IFwiT0tcIixcbiAgICAyMDE6IFwiQ3JlYXRlZFwiLFxuICAgIDIwMjogXCJBY2NlcHRlZFwiLFxuICAgIDIwMzogXCJOb24tQXV0aG9yaXRhdGl2ZSBJbmZvcm1hdGlvblwiLFxuICAgIDIwNDogXCJObyBDb250ZW50XCIsXG4gICAgMjA1OiBcIlJlc2V0IENvbnRlbnRcIixcbiAgICAyMDY6IFwiUGFydGlhbCBDb250ZW50XCIsXG4gICAgMjA3OiBcIk11bHRpLVN0YXR1c1wiLFxuICAgIDMwMDogXCJNdWx0aXBsZSBDaG9pY2VcIixcbiAgICAzMDE6IFwiTW92ZWQgUGVybWFuZW50bHlcIixcbiAgICAzMDI6IFwiRm91bmRcIixcbiAgICAzMDM6IFwiU2VlIE90aGVyXCIsXG4gICAgMzA0OiBcIk5vdCBNb2RpZmllZFwiLFxuICAgIDMwNTogXCJVc2UgUHJveHlcIixcbiAgICAzMDc6IFwiVGVtcG9yYXJ5IFJlZGlyZWN0XCIsXG4gICAgNDAwOiBcIkJhZCBSZXF1ZXN0XCIsXG4gICAgNDAxOiBcIlVuYXV0aG9yaXplZFwiLFxuICAgIDQwMjogXCJQYXltZW50IFJlcXVpcmVkXCIsXG4gICAgNDAzOiBcIkZvcmJpZGRlblwiLFxuICAgIDQwNDogXCJOb3QgRm91bmRcIixcbiAgICA0MDU6IFwiTWV0aG9kIE5vdCBBbGxvd2VkXCIsXG4gICAgNDA2OiBcIk5vdCBBY2NlcHRhYmxlXCIsXG4gICAgNDA3OiBcIlByb3h5IEF1dGhlbnRpY2F0aW9uIFJlcXVpcmVkXCIsXG4gICAgNDA4OiBcIlJlcXVlc3QgVGltZW91dFwiLFxuICAgIDQwOTogXCJDb25mbGljdFwiLFxuICAgIDQxMDogXCJHb25lXCIsXG4gICAgNDExOiBcIkxlbmd0aCBSZXF1aXJlZFwiLFxuICAgIDQxMjogXCJQcmVjb25kaXRpb24gRmFpbGVkXCIsXG4gICAgNDEzOiBcIlJlcXVlc3QgRW50aXR5IFRvbyBMYXJnZVwiLFxuICAgIDQxNDogXCJSZXF1ZXN0LVVSSSBUb28gTG9uZ1wiLFxuICAgIDQxNTogXCJVbnN1cHBvcnRlZCBNZWRpYSBUeXBlXCIsXG4gICAgNDE2OiBcIlJlcXVlc3RlZCBSYW5nZSBOb3QgU2F0aXNmaWFibGVcIixcbiAgICA0MTc6IFwiRXhwZWN0YXRpb24gRmFpbGVkXCIsXG4gICAgNDIyOiBcIlVucHJvY2Vzc2FibGUgRW50aXR5XCIsXG4gICAgNTAwOiBcIkludGVybmFsIFNlcnZlciBFcnJvclwiLFxuICAgIDUwMTogXCJOb3QgSW1wbGVtZW50ZWRcIixcbiAgICA1MDI6IFwiQmFkIEdhdGV3YXlcIixcbiAgICA1MDM6IFwiU2VydmljZSBVbmF2YWlsYWJsZVwiLFxuICAgIDUwNDogXCJHYXRld2F5IFRpbWVvdXRcIixcbiAgICA1MDU6IFwiSFRUUCBWZXJzaW9uIE5vdCBTdXBwb3J0ZWRcIlxufTtcblxuZXh0ZW5kKEZha2VYTUxIdHRwUmVxdWVzdC5wcm90b3R5cGUsIHNpbm9uRXZlbnQuRXZlbnRUYXJnZXQsIHtcbiAgICBhc3luYzogdHJ1ZSxcblxuICAgIG9wZW46IGZ1bmN0aW9uIG9wZW4obWV0aG9kLCB1cmwsIGFzeW5jLCB1c2VybmFtZSwgcGFzc3dvcmQpIHtcbiAgICAgICAgdGhpcy5tZXRob2QgPSBtZXRob2Q7XG4gICAgICAgIHRoaXMudXJsID0gdXJsO1xuICAgICAgICB0aGlzLmFzeW5jID0gdHlwZW9mIGFzeW5jID09PSBcImJvb2xlYW5cIiA/IGFzeW5jIDogdHJ1ZTtcbiAgICAgICAgdGhpcy51c2VybmFtZSA9IHVzZXJuYW1lO1xuICAgICAgICB0aGlzLnBhc3N3b3JkID0gcGFzc3dvcmQ7XG4gICAgICAgIGNsZWFyUmVzcG9uc2UodGhpcyk7XG4gICAgICAgIHRoaXMucmVxdWVzdEhlYWRlcnMgPSB7fTtcbiAgICAgICAgdGhpcy5zZW5kRmxhZyA9IGZhbHNlO1xuXG4gICAgICAgIGlmIChGYWtlWE1MSHR0cFJlcXVlc3QudXNlRmlsdGVycyA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgdmFyIHhockFyZ3MgPSBhcmd1bWVudHM7XG4gICAgICAgICAgICB2YXIgZGVmYWtlID0gRmFrZVhNTEh0dHBSZXF1ZXN0LmZpbHRlcnMuc29tZShmdW5jdGlvbiAoZmlsdGVyKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZpbHRlci5hcHBseSh0aGlzLCB4aHJBcmdzKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaWYgKGRlZmFrZSkge1xuICAgICAgICAgICAgICAgIEZha2VYTUxIdHRwUmVxdWVzdC5kZWZha2UodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5yZWFkeVN0YXRlQ2hhbmdlKEZha2VYTUxIdHRwUmVxdWVzdC5PUEVORUQpO1xuICAgIH0sXG5cbiAgICByZWFkeVN0YXRlQ2hhbmdlOiBmdW5jdGlvbiByZWFkeVN0YXRlQ2hhbmdlKHN0YXRlKSB7XG4gICAgICAgIHRoaXMucmVhZHlTdGF0ZSA9IHN0YXRlO1xuXG4gICAgICAgIHZhciByZWFkeVN0YXRlQ2hhbmdlRXZlbnQgPSBuZXcgc2lub25FdmVudC5FdmVudChcInJlYWR5c3RhdGVjaGFuZ2VcIiwgZmFsc2UsIGZhbHNlLCB0aGlzKTtcbiAgICAgICAgdmFyIGV2ZW50LCBwcm9ncmVzcztcblxuICAgICAgICBpZiAodHlwZW9mIHRoaXMub25yZWFkeXN0YXRlY2hhbmdlID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgdGhpcy5vbnJlYWR5c3RhdGVjaGFuZ2UocmVhZHlTdGF0ZUNoYW5nZUV2ZW50KTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmxvZ0Vycm9yKFwiRmFrZSBYSFIgb25yZWFkeXN0YXRlY2hhbmdlIGhhbmRsZXJcIiwgZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5yZWFkeVN0YXRlID09PSBGYWtlWE1MSHR0cFJlcXVlc3QuRE9ORSkge1xuICAgICAgICAgICAgaWYgKHRoaXMuYWJvcnRlZCB8fCB0aGlzLnN0YXR1cyA9PT0gMCkge1xuICAgICAgICAgICAgICAgIHByb2dyZXNzID0ge2xvYWRlZDogMCwgdG90YWw6IDB9O1xuICAgICAgICAgICAgICAgIGV2ZW50ID0gdGhpcy5hYm9ydGVkID8gXCJhYm9ydFwiIDogXCJlcnJvclwiO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwcm9ncmVzcyA9IHtsb2FkZWQ6IDEwMCwgdG90YWw6IDEwMH07XG4gICAgICAgICAgICAgICAgZXZlbnQgPSBcImxvYWRcIjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHN1cHBvcnRzUHJvZ3Jlc3MpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnVwbG9hZC5kaXNwYXRjaEV2ZW50KG5ldyBzaW5vbkV2ZW50LlByb2dyZXNzRXZlbnQoXCJwcm9ncmVzc1wiLCBwcm9ncmVzcywgdGhpcykpO1xuICAgICAgICAgICAgICAgIHRoaXMudXBsb2FkLmRpc3BhdGNoRXZlbnQobmV3IHNpbm9uRXZlbnQuUHJvZ3Jlc3NFdmVudChldmVudCwgcHJvZ3Jlc3MsIHRoaXMpKTtcbiAgICAgICAgICAgICAgICB0aGlzLnVwbG9hZC5kaXNwYXRjaEV2ZW50KG5ldyBzaW5vbkV2ZW50LlByb2dyZXNzRXZlbnQoXCJsb2FkZW5kXCIsIHByb2dyZXNzLCB0aGlzKSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRoaXMuZGlzcGF0Y2hFdmVudChuZXcgc2lub25FdmVudC5Qcm9ncmVzc0V2ZW50KFwicHJvZ3Jlc3NcIiwgcHJvZ3Jlc3MsIHRoaXMpKTtcbiAgICAgICAgICAgIHRoaXMuZGlzcGF0Y2hFdmVudChuZXcgc2lub25FdmVudC5Qcm9ncmVzc0V2ZW50KGV2ZW50LCBwcm9ncmVzcywgdGhpcykpO1xuICAgICAgICAgICAgdGhpcy5kaXNwYXRjaEV2ZW50KG5ldyBzaW5vbkV2ZW50LlByb2dyZXNzRXZlbnQoXCJsb2FkZW5kXCIsIHByb2dyZXNzLCB0aGlzKSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmRpc3BhdGNoRXZlbnQocmVhZHlTdGF0ZUNoYW5nZUV2ZW50KTtcbiAgICB9LFxuXG4gICAgc2V0UmVxdWVzdEhlYWRlcjogZnVuY3Rpb24gc2V0UmVxdWVzdEhlYWRlcihoZWFkZXIsIHZhbHVlKSB7XG4gICAgICAgIHZlcmlmeVN0YXRlKHRoaXMpO1xuXG4gICAgICAgIHZhciBjaGVja1Vuc2FmZUhlYWRlcnMgPSB0cnVlO1xuICAgICAgICBpZiAodHlwZW9mIHRoaXMudW5zYWZlSGVhZGVyc0VuYWJsZWQgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgY2hlY2tVbnNhZmVIZWFkZXJzID0gdGhpcy51bnNhZmVIZWFkZXJzRW5hYmxlZCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNoZWNrVW5zYWZlSGVhZGVycyAmJiAodW5zYWZlSGVhZGVyc1toZWFkZXJdIHx8IC9eKFNlYy18UHJveHktKS8udGVzdChoZWFkZXIpKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUmVmdXNlZCB0byBzZXQgdW5zYWZlIGhlYWRlciBcXFwiXCIgKyBoZWFkZXIgKyBcIlxcXCJcIik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5yZXF1ZXN0SGVhZGVyc1toZWFkZXJdKSB7XG4gICAgICAgICAgICB0aGlzLnJlcXVlc3RIZWFkZXJzW2hlYWRlcl0gKz0gXCIsXCIgKyB2YWx1ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMucmVxdWVzdEhlYWRlcnNbaGVhZGVyXSA9IHZhbHVlO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIHNldFN0YXR1czogZnVuY3Rpb24gc2V0U3RhdHVzKHN0YXR1cykge1xuICAgICAgICB2YXIgc2FuaXRpemVkU3RhdHVzID0gdHlwZW9mIHN0YXR1cyA9PT0gXCJudW1iZXJcIiA/IHN0YXR1cyA6IDIwMDtcblxuICAgICAgICB2ZXJpZnlSZXF1ZXN0T3BlbmVkKHRoaXMpO1xuICAgICAgICB0aGlzLnN0YXR1cyA9IHNhbml0aXplZFN0YXR1cztcbiAgICAgICAgdGhpcy5zdGF0dXNUZXh0ID0gRmFrZVhNTEh0dHBSZXF1ZXN0LnN0YXR1c0NvZGVzW3Nhbml0aXplZFN0YXR1c107XG4gICAgfSxcblxuICAgIC8vIEhlbHBzIHRlc3RpbmdcbiAgICBzZXRSZXNwb25zZUhlYWRlcnM6IGZ1bmN0aW9uIHNldFJlc3BvbnNlSGVhZGVycyhoZWFkZXJzKSB7XG4gICAgICAgIHZlcmlmeVJlcXVlc3RPcGVuZWQodGhpcyk7XG5cbiAgICAgICAgdmFyIHJlc3BvbnNlSGVhZGVycyA9IHRoaXMucmVzcG9uc2VIZWFkZXJzID0ge307XG5cbiAgICAgICAgT2JqZWN0LmtleXMoaGVhZGVycykuZm9yRWFjaChmdW5jdGlvbiAoaGVhZGVyKSB7XG4gICAgICAgICAgICByZXNwb25zZUhlYWRlcnNbaGVhZGVyXSA9IGhlYWRlcnNbaGVhZGVyXTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHRoaXMuYXN5bmMpIHtcbiAgICAgICAgICAgIHRoaXMucmVhZHlTdGF0ZUNoYW5nZShGYWtlWE1MSHR0cFJlcXVlc3QuSEVBREVSU19SRUNFSVZFRCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLnJlYWR5U3RhdGUgPSBGYWtlWE1MSHR0cFJlcXVlc3QuSEVBREVSU19SRUNFSVZFRDtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvLyBDdXJyZW50bHkgdHJlYXRzIEFMTCBkYXRhIGFzIGEgRE9NU3RyaW5nIChpLmUuIG5vIERvY3VtZW50KVxuICAgIHNlbmQ6IGZ1bmN0aW9uIHNlbmQoZGF0YSkge1xuICAgICAgICB2ZXJpZnlTdGF0ZSh0aGlzKTtcblxuICAgICAgICBpZiAoIS9eKGhlYWQpJC9pLnRlc3QodGhpcy5tZXRob2QpKSB7XG4gICAgICAgICAgICB2YXIgY29udGVudFR5cGUgPSBnZXRIZWFkZXIodGhpcy5yZXF1ZXN0SGVhZGVycywgXCJDb250ZW50LVR5cGVcIik7XG4gICAgICAgICAgICBpZiAodGhpcy5yZXF1ZXN0SGVhZGVyc1tjb250ZW50VHlwZV0pIHtcbiAgICAgICAgICAgICAgICB2YXIgdmFsdWUgPSB0aGlzLnJlcXVlc3RIZWFkZXJzW2NvbnRlbnRUeXBlXS5zcGxpdChcIjtcIik7XG4gICAgICAgICAgICAgICAgdGhpcy5yZXF1ZXN0SGVhZGVyc1tjb250ZW50VHlwZV0gPSB2YWx1ZVswXSArIFwiO2NoYXJzZXQ9dXRmLThcIjtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoc3VwcG9ydHNGb3JtRGF0YSAmJiAhKGRhdGEgaW5zdGFuY2VvZiBGb3JtRGF0YSkpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlcXVlc3RIZWFkZXJzW1wiQ29udGVudC1UeXBlXCJdID0gXCJ0ZXh0L3BsYWluO2NoYXJzZXQ9dXRmLThcIjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5yZXF1ZXN0Qm9keSA9IGRhdGE7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmVycm9yRmxhZyA9IGZhbHNlO1xuICAgICAgICB0aGlzLnNlbmRGbGFnID0gdGhpcy5hc3luYztcbiAgICAgICAgY2xlYXJSZXNwb25zZSh0aGlzKTtcbiAgICAgICAgdGhpcy5yZWFkeVN0YXRlQ2hhbmdlKEZha2VYTUxIdHRwUmVxdWVzdC5PUEVORUQpO1xuXG4gICAgICAgIGlmICh0eXBlb2YgdGhpcy5vblNlbmQgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgdGhpcy5vblNlbmQodGhpcyk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmRpc3BhdGNoRXZlbnQobmV3IHNpbm9uRXZlbnQuRXZlbnQoXCJsb2Fkc3RhcnRcIiwgZmFsc2UsIGZhbHNlLCB0aGlzKSk7XG4gICAgfSxcblxuICAgIGFib3J0OiBmdW5jdGlvbiBhYm9ydCgpIHtcbiAgICAgICAgdGhpcy5hYm9ydGVkID0gdHJ1ZTtcbiAgICAgICAgY2xlYXJSZXNwb25zZSh0aGlzKTtcbiAgICAgICAgdGhpcy5lcnJvckZsYWcgPSB0cnVlO1xuICAgICAgICB0aGlzLnJlcXVlc3RIZWFkZXJzID0ge307XG4gICAgICAgIHRoaXMucmVzcG9uc2VIZWFkZXJzID0ge307XG5cbiAgICAgICAgaWYgKHRoaXMucmVhZHlTdGF0ZSAhPT0gRmFrZVhNTEh0dHBSZXF1ZXN0LlVOU0VOVCAmJiB0aGlzLnNlbmRGbGFnXG4gICAgICAgICAgICAmJiB0aGlzLnJlYWR5U3RhdGUgIT09IEZha2VYTUxIdHRwUmVxdWVzdC5ET05FKSB7XG4gICAgICAgICAgICB0aGlzLnJlYWR5U3RhdGVDaGFuZ2UoRmFrZVhNTEh0dHBSZXF1ZXN0LkRPTkUpO1xuICAgICAgICAgICAgdGhpcy5zZW5kRmxhZyA9IGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5yZWFkeVN0YXRlID0gRmFrZVhNTEh0dHBSZXF1ZXN0LlVOU0VOVDtcbiAgICB9LFxuXG4gICAgZXJyb3I6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY2xlYXJSZXNwb25zZSh0aGlzKTtcbiAgICAgICAgdGhpcy5lcnJvckZsYWcgPSB0cnVlO1xuICAgICAgICB0aGlzLnJlcXVlc3RIZWFkZXJzID0ge307XG4gICAgICAgIHRoaXMucmVzcG9uc2VIZWFkZXJzID0ge307XG5cbiAgICAgICAgdGhpcy5yZWFkeVN0YXRlQ2hhbmdlKEZha2VYTUxIdHRwUmVxdWVzdC5ET05FKTtcbiAgICB9LFxuXG4gICAgZ2V0UmVzcG9uc2VIZWFkZXI6IGZ1bmN0aW9uIGdldFJlc3BvbnNlSGVhZGVyKGhlYWRlcikge1xuICAgICAgICBpZiAodGhpcy5yZWFkeVN0YXRlIDwgRmFrZVhNTEh0dHBSZXF1ZXN0LkhFQURFUlNfUkVDRUlWRUQpIHtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKC9eU2V0LUNvb2tpZTI/JC9pLnRlc3QoaGVhZGVyKSkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBoZWFkZXIgPSBnZXRIZWFkZXIodGhpcy5yZXNwb25zZUhlYWRlcnMsIGhlYWRlcik7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMucmVzcG9uc2VIZWFkZXJzW2hlYWRlcl0gfHwgbnVsbDtcbiAgICB9LFxuXG4gICAgZ2V0QWxsUmVzcG9uc2VIZWFkZXJzOiBmdW5jdGlvbiBnZXRBbGxSZXNwb25zZUhlYWRlcnMoKSB7XG4gICAgICAgIGlmICh0aGlzLnJlYWR5U3RhdGUgPCBGYWtlWE1MSHR0cFJlcXVlc3QuSEVBREVSU19SRUNFSVZFRCkge1xuICAgICAgICAgICAgcmV0dXJuIFwiXCI7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgcmVzcG9uc2VIZWFkZXJzID0gdGhpcy5yZXNwb25zZUhlYWRlcnM7XG4gICAgICAgIHZhciBoZWFkZXJzID0gT2JqZWN0LmtleXMocmVzcG9uc2VIZWFkZXJzKVxuICAgICAgICAgICAgLmZpbHRlcihleGNsdWRlU2V0Q29va2llMkhlYWRlcilcbiAgICAgICAgICAgIC5yZWR1Y2UoZnVuY3Rpb24gKHByZXYsIGhlYWRlcikge1xuICAgICAgICAgICAgICAgIHZhciB2YWx1ZSA9IHJlc3BvbnNlSGVhZGVyc1toZWFkZXJdO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHByZXYgKyAoaGVhZGVyICsgXCI6IFwiICsgdmFsdWUgKyBcIlxcclxcblwiKTtcbiAgICAgICAgICAgIH0sIFwiXCIpO1xuXG4gICAgICAgIHJldHVybiBoZWFkZXJzO1xuICAgIH0sXG5cbiAgICBzZXRSZXNwb25zZUJvZHk6IGZ1bmN0aW9uIHNldFJlc3BvbnNlQm9keShib2R5KSB7XG4gICAgICAgIHZlcmlmeVJlcXVlc3RTZW50KHRoaXMpO1xuICAgICAgICB2ZXJpZnlIZWFkZXJzUmVjZWl2ZWQodGhpcyk7XG4gICAgICAgIHZlcmlmeVJlc3BvbnNlQm9keVR5cGUoYm9keSk7XG4gICAgICAgIHZhciBjb250ZW50VHlwZSA9IHRoaXMub3ZlcnJpZGRlbk1pbWVUeXBlIHx8IHRoaXMuZ2V0UmVzcG9uc2VIZWFkZXIoXCJDb250ZW50LVR5cGVcIik7XG5cbiAgICAgICAgdmFyIGlzVGV4dFJlc3BvbnNlID0gdGhpcy5yZXNwb25zZVR5cGUgPT09IFwiXCIgfHwgdGhpcy5yZXNwb25zZVR5cGUgPT09IFwidGV4dFwiO1xuICAgICAgICBjbGVhclJlc3BvbnNlKHRoaXMpO1xuICAgICAgICBpZiAodGhpcy5hc3luYykge1xuICAgICAgICAgICAgdmFyIGNodW5rU2l6ZSA9IHRoaXMuY2h1bmtTaXplIHx8IDEwO1xuICAgICAgICAgICAgdmFyIGluZGV4ID0gMDtcblxuICAgICAgICAgICAgZG8ge1xuICAgICAgICAgICAgICAgIHRoaXMucmVhZHlTdGF0ZUNoYW5nZShGYWtlWE1MSHR0cFJlcXVlc3QuTE9BRElORyk7XG5cbiAgICAgICAgICAgICAgICBpZiAoaXNUZXh0UmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZXNwb25zZVRleHQgPSB0aGlzLnJlc3BvbnNlICs9IGJvZHkuc3Vic3RyaW5nKGluZGV4LCBpbmRleCArIGNodW5rU2l6ZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGluZGV4ICs9IGNodW5rU2l6ZTtcbiAgICAgICAgICAgIH0gd2hpbGUgKGluZGV4IDwgYm9keS5sZW5ndGgpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5yZXNwb25zZSA9IGNvbnZlcnRSZXNwb25zZUJvZHkodGhpcy5yZXNwb25zZVR5cGUsIGNvbnRlbnRUeXBlLCBib2R5KTtcbiAgICAgICAgaWYgKGlzVGV4dFJlc3BvbnNlKSB7XG4gICAgICAgICAgICB0aGlzLnJlc3BvbnNlVGV4dCA9IHRoaXMucmVzcG9uc2U7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5yZXNwb25zZVR5cGUgPT09IFwiZG9jdW1lbnRcIikge1xuICAgICAgICAgICAgdGhpcy5yZXNwb25zZVhNTCA9IHRoaXMucmVzcG9uc2U7XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5yZXNwb25zZVR5cGUgPT09IFwiXCIgJiYgaXNYbWxDb250ZW50VHlwZShjb250ZW50VHlwZSkpIHtcbiAgICAgICAgICAgIHRoaXMucmVzcG9uc2VYTUwgPSBGYWtlWE1MSHR0cFJlcXVlc3QucGFyc2VYTUwodGhpcy5yZXNwb25zZVRleHQpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucmVhZHlTdGF0ZUNoYW5nZShGYWtlWE1MSHR0cFJlcXVlc3QuRE9ORSk7XG4gICAgfSxcblxuICAgIHJlc3BvbmQ6IGZ1bmN0aW9uIHJlc3BvbmQoc3RhdHVzLCBoZWFkZXJzLCBib2R5KSB7XG4gICAgICAgIHRoaXMuc2V0U3RhdHVzKHN0YXR1cyk7XG4gICAgICAgIHRoaXMuc2V0UmVzcG9uc2VIZWFkZXJzKGhlYWRlcnMgfHwge30pO1xuICAgICAgICB0aGlzLnNldFJlc3BvbnNlQm9keShib2R5IHx8IFwiXCIpO1xuICAgIH0sXG5cbiAgICB1cGxvYWRQcm9ncmVzczogZnVuY3Rpb24gdXBsb2FkUHJvZ3Jlc3MocHJvZ3Jlc3NFdmVudFJhdykge1xuICAgICAgICBpZiAoc3VwcG9ydHNQcm9ncmVzcykge1xuICAgICAgICAgICAgdGhpcy51cGxvYWQuZGlzcGF0Y2hFdmVudChuZXcgc2lub25FdmVudC5Qcm9ncmVzc0V2ZW50KFwicHJvZ3Jlc3NcIiwgcHJvZ3Jlc3NFdmVudFJhdykpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIGRvd25sb2FkUHJvZ3Jlc3M6IGZ1bmN0aW9uIGRvd25sb2FkUHJvZ3Jlc3MocHJvZ3Jlc3NFdmVudFJhdykge1xuICAgICAgICBpZiAoc3VwcG9ydHNQcm9ncmVzcykge1xuICAgICAgICAgICAgdGhpcy5kaXNwYXRjaEV2ZW50KG5ldyBzaW5vbkV2ZW50LlByb2dyZXNzRXZlbnQoXCJwcm9ncmVzc1wiLCBwcm9ncmVzc0V2ZW50UmF3KSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgdXBsb2FkRXJyb3I6IGZ1bmN0aW9uIHVwbG9hZEVycm9yKGVycm9yKSB7XG4gICAgICAgIGlmIChzdXBwb3J0c0N1c3RvbUV2ZW50KSB7XG4gICAgICAgICAgICB0aGlzLnVwbG9hZC5kaXNwYXRjaEV2ZW50KG5ldyBzaW5vbkV2ZW50LkN1c3RvbUV2ZW50KFwiZXJyb3JcIiwge2RldGFpbDogZXJyb3J9KSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgb3ZlcnJpZGVNaW1lVHlwZTogZnVuY3Rpb24gb3ZlcnJpZGVNaW1lVHlwZSh0eXBlKSB7XG4gICAgICAgIGlmICh0aGlzLnJlYWR5U3RhdGUgPj0gRmFrZVhNTEh0dHBSZXF1ZXN0LkxPQURJTkcpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIklOVkFMSURfU1RBVEVfRVJSXCIpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMub3ZlcnJpZGRlbk1pbWVUeXBlID0gdHlwZTtcbiAgICB9XG59KTtcblxudmFyIHN0YXRlcyA9IHtcbiAgICBVTlNFTlQ6IDAsXG4gICAgT1BFTkVEOiAxLFxuICAgIEhFQURFUlNfUkVDRUlWRUQ6IDIsXG4gICAgTE9BRElORzogMyxcbiAgICBET05FOiA0XG59O1xuXG5leHRlbmQoRmFrZVhNTEh0dHBSZXF1ZXN0LCBzdGF0ZXMpO1xuZXh0ZW5kKEZha2VYTUxIdHRwUmVxdWVzdC5wcm90b3R5cGUsIHN0YXRlcyk7XG5cbmZ1bmN0aW9uIHVzZUZha2VYTUxIdHRwUmVxdWVzdCgpIHtcbiAgICBGYWtlWE1MSHR0cFJlcXVlc3QucmVzdG9yZSA9IGZ1bmN0aW9uIHJlc3RvcmUoa2VlcE9uQ3JlYXRlKSB7XG4gICAgICAgIGlmIChzaW5vblhoci5zdXBwb3J0c1hIUikge1xuICAgICAgICAgICAgZ2xvYmFsLlhNTEh0dHBSZXF1ZXN0ID0gc2lub25YaHIuR2xvYmFsWE1MSHR0cFJlcXVlc3Q7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoc2lub25YaHIuc3VwcG9ydHNBY3RpdmVYKSB7XG4gICAgICAgICAgICBnbG9iYWwuQWN0aXZlWE9iamVjdCA9IHNpbm9uWGhyLkdsb2JhbEFjdGl2ZVhPYmplY3Q7XG4gICAgICAgIH1cblxuICAgICAgICBkZWxldGUgRmFrZVhNTEh0dHBSZXF1ZXN0LnJlc3RvcmU7XG5cbiAgICAgICAgaWYgKGtlZXBPbkNyZWF0ZSAhPT0gdHJ1ZSkge1xuICAgICAgICAgICAgZGVsZXRlIEZha2VYTUxIdHRwUmVxdWVzdC5vbkNyZWF0ZTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgaWYgKHNpbm9uWGhyLnN1cHBvcnRzWEhSKSB7XG4gICAgICAgIGdsb2JhbC5YTUxIdHRwUmVxdWVzdCA9IEZha2VYTUxIdHRwUmVxdWVzdDtcbiAgICB9XG5cbiAgICBpZiAoc2lub25YaHIuc3VwcG9ydHNBY3RpdmVYKSB7XG4gICAgICAgIGdsb2JhbC5BY3RpdmVYT2JqZWN0ID0gZnVuY3Rpb24gQWN0aXZlWE9iamVjdChvYmpJZCkge1xuICAgICAgICAgICAgaWYgKG9iaklkID09PSBcIk1pY3Jvc29mdC5YTUxIVFRQXCIgfHwgL15Nc3htbDJcXC5YTUxIVFRQL2kudGVzdChvYmpJZCkpIHtcblxuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgRmFrZVhNTEh0dHBSZXF1ZXN0KCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBuZXcgc2lub25YaHIuR2xvYmFsQWN0aXZlWE9iamVjdChvYmpJZCk7XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIEZha2VYTUxIdHRwUmVxdWVzdDtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgeGhyOiBzaW5vblhocixcbiAgICBGYWtlWE1MSHR0cFJlcXVlc3Q6IEZha2VYTUxIdHRwUmVxdWVzdCxcbiAgICB1c2VGYWtlWE1MSHR0cFJlcXVlc3Q6IHVzZUZha2VYTUxIdHRwUmVxdWVzdFxufTtcbiIsIi8vIFNlZTogaHR0cDovL2NvZGUuZ29vZ2xlLmNvbS9wL2dvb2dsZS1kaWZmLW1hdGNoLXBhdGNoL3dpa2kvQVBJXG5leHBvcnQgZnVuY3Rpb24gY29udmVydENoYW5nZXNUb0RNUChjaGFuZ2VzKSB7XG4gIGxldCByZXQgPSBbXSxcbiAgICAgIGNoYW5nZSxcbiAgICAgIG9wZXJhdGlvbjtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBjaGFuZ2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgY2hhbmdlID0gY2hhbmdlc1tpXTtcbiAgICBpZiAoY2hhbmdlLmFkZGVkKSB7XG4gICAgICBvcGVyYXRpb24gPSAxO1xuICAgIH0gZWxzZSBpZiAoY2hhbmdlLnJlbW92ZWQpIHtcbiAgICAgIG9wZXJhdGlvbiA9IC0xO1xuICAgIH0gZWxzZSB7XG4gICAgICBvcGVyYXRpb24gPSAwO1xuICAgIH1cblxuICAgIHJldC5wdXNoKFtvcGVyYXRpb24sIGNoYW5nZS52YWx1ZV0pO1xuICB9XG4gIHJldHVybiByZXQ7XG59XG4iLCJleHBvcnQgZnVuY3Rpb24gY29udmVydENoYW5nZXNUb1hNTChjaGFuZ2VzKSB7XG4gIGxldCByZXQgPSBbXTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBjaGFuZ2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgbGV0IGNoYW5nZSA9IGNoYW5nZXNbaV07XG4gICAgaWYgKGNoYW5nZS5hZGRlZCkge1xuICAgICAgcmV0LnB1c2goJzxpbnM+Jyk7XG4gICAgfSBlbHNlIGlmIChjaGFuZ2UucmVtb3ZlZCkge1xuICAgICAgcmV0LnB1c2goJzxkZWw+Jyk7XG4gICAgfVxuXG4gICAgcmV0LnB1c2goZXNjYXBlSFRNTChjaGFuZ2UudmFsdWUpKTtcblxuICAgIGlmIChjaGFuZ2UuYWRkZWQpIHtcbiAgICAgIHJldC5wdXNoKCc8L2lucz4nKTtcbiAgICB9IGVsc2UgaWYgKGNoYW5nZS5yZW1vdmVkKSB7XG4gICAgICByZXQucHVzaCgnPC9kZWw+Jyk7XG4gICAgfVxuICB9XG4gIHJldHVybiByZXQuam9pbignJyk7XG59XG5cbmZ1bmN0aW9uIGVzY2FwZUhUTUwocykge1xuICBsZXQgbiA9IHM7XG4gIG4gPSBuLnJlcGxhY2UoLyYvZywgJyZhbXA7Jyk7XG4gIG4gPSBuLnJlcGxhY2UoLzwvZywgJyZsdDsnKTtcbiAgbiA9IG4ucmVwbGFjZSgvPi9nLCAnJmd0OycpO1xuICBuID0gbi5yZXBsYWNlKC9cIi9nLCAnJnF1b3Q7Jyk7XG5cbiAgcmV0dXJuIG47XG59XG4iLCJpbXBvcnQgRGlmZiBmcm9tICcuL2Jhc2UnO1xuXG5leHBvcnQgY29uc3QgYXJyYXlEaWZmID0gbmV3IERpZmYoKTtcbmFycmF5RGlmZi50b2tlbml6ZSA9IGFycmF5RGlmZi5qb2luID0gZnVuY3Rpb24odmFsdWUpIHtcbiAgcmV0dXJuIHZhbHVlLnNsaWNlKCk7XG59O1xuXG5leHBvcnQgZnVuY3Rpb24gZGlmZkFycmF5cyhvbGRBcnIsIG5ld0FyciwgY2FsbGJhY2spIHsgcmV0dXJuIGFycmF5RGlmZi5kaWZmKG9sZEFyciwgbmV3QXJyLCBjYWxsYmFjayk7IH1cbiIsImV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIERpZmYoKSB7fVxuXG5EaWZmLnByb3RvdHlwZSA9IHtcbiAgZGlmZihvbGRTdHJpbmcsIG5ld1N0cmluZywgb3B0aW9ucyA9IHt9KSB7XG4gICAgbGV0IGNhbGxiYWNrID0gb3B0aW9ucy5jYWxsYmFjaztcbiAgICBpZiAodHlwZW9mIG9wdGlvbnMgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIGNhbGxiYWNrID0gb3B0aW9ucztcbiAgICAgIG9wdGlvbnMgPSB7fTtcbiAgICB9XG4gICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcblxuICAgIGxldCBzZWxmID0gdGhpcztcblxuICAgIGZ1bmN0aW9uIGRvbmUodmFsdWUpIHtcbiAgICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkgeyBjYWxsYmFjayh1bmRlZmluZWQsIHZhbHVlKTsgfSwgMCk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHZhbHVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEFsbG93IHN1YmNsYXNzZXMgdG8gbWFzc2FnZSB0aGUgaW5wdXQgcHJpb3IgdG8gcnVubmluZ1xuICAgIG9sZFN0cmluZyA9IHRoaXMuY2FzdElucHV0KG9sZFN0cmluZyk7XG4gICAgbmV3U3RyaW5nID0gdGhpcy5jYXN0SW5wdXQobmV3U3RyaW5nKTtcblxuICAgIG9sZFN0cmluZyA9IHRoaXMucmVtb3ZlRW1wdHkodGhpcy50b2tlbml6ZShvbGRTdHJpbmcpKTtcbiAgICBuZXdTdHJpbmcgPSB0aGlzLnJlbW92ZUVtcHR5KHRoaXMudG9rZW5pemUobmV3U3RyaW5nKSk7XG5cbiAgICBsZXQgbmV3TGVuID0gbmV3U3RyaW5nLmxlbmd0aCwgb2xkTGVuID0gb2xkU3RyaW5nLmxlbmd0aDtcbiAgICBsZXQgZWRpdExlbmd0aCA9IDE7XG4gICAgbGV0IG1heEVkaXRMZW5ndGggPSBuZXdMZW4gKyBvbGRMZW47XG4gICAgbGV0IGJlc3RQYXRoID0gW3sgbmV3UG9zOiAtMSwgY29tcG9uZW50czogW10gfV07XG5cbiAgICAvLyBTZWVkIGVkaXRMZW5ndGggPSAwLCBpLmUuIHRoZSBjb250ZW50IHN0YXJ0cyB3aXRoIHRoZSBzYW1lIHZhbHVlc1xuICAgIGxldCBvbGRQb3MgPSB0aGlzLmV4dHJhY3RDb21tb24oYmVzdFBhdGhbMF0sIG5ld1N0cmluZywgb2xkU3RyaW5nLCAwKTtcbiAgICBpZiAoYmVzdFBhdGhbMF0ubmV3UG9zICsgMSA+PSBuZXdMZW4gJiYgb2xkUG9zICsgMSA+PSBvbGRMZW4pIHtcbiAgICAgIC8vIElkZW50aXR5IHBlciB0aGUgZXF1YWxpdHkgYW5kIHRva2VuaXplclxuICAgICAgcmV0dXJuIGRvbmUoW3t2YWx1ZTogdGhpcy5qb2luKG5ld1N0cmluZyksIGNvdW50OiBuZXdTdHJpbmcubGVuZ3RofV0pO1xuICAgIH1cblxuICAgIC8vIE1haW4gd29ya2VyIG1ldGhvZC4gY2hlY2tzIGFsbCBwZXJtdXRhdGlvbnMgb2YgYSBnaXZlbiBlZGl0IGxlbmd0aCBmb3IgYWNjZXB0YW5jZS5cbiAgICBmdW5jdGlvbiBleGVjRWRpdExlbmd0aCgpIHtcbiAgICAgIGZvciAobGV0IGRpYWdvbmFsUGF0aCA9IC0xICogZWRpdExlbmd0aDsgZGlhZ29uYWxQYXRoIDw9IGVkaXRMZW5ndGg7IGRpYWdvbmFsUGF0aCArPSAyKSB7XG4gICAgICAgIGxldCBiYXNlUGF0aDtcbiAgICAgICAgbGV0IGFkZFBhdGggPSBiZXN0UGF0aFtkaWFnb25hbFBhdGggLSAxXSxcbiAgICAgICAgICAgIHJlbW92ZVBhdGggPSBiZXN0UGF0aFtkaWFnb25hbFBhdGggKyAxXSxcbiAgICAgICAgICAgIG9sZFBvcyA9IChyZW1vdmVQYXRoID8gcmVtb3ZlUGF0aC5uZXdQb3MgOiAwKSAtIGRpYWdvbmFsUGF0aDtcbiAgICAgICAgaWYgKGFkZFBhdGgpIHtcbiAgICAgICAgICAvLyBObyBvbmUgZWxzZSBpcyBnb2luZyB0byBhdHRlbXB0IHRvIHVzZSB0aGlzIHZhbHVlLCBjbGVhciBpdFxuICAgICAgICAgIGJlc3RQYXRoW2RpYWdvbmFsUGF0aCAtIDFdID0gdW5kZWZpbmVkO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGNhbkFkZCA9IGFkZFBhdGggJiYgYWRkUGF0aC5uZXdQb3MgKyAxIDwgbmV3TGVuLFxuICAgICAgICAgICAgY2FuUmVtb3ZlID0gcmVtb3ZlUGF0aCAmJiAwIDw9IG9sZFBvcyAmJiBvbGRQb3MgPCBvbGRMZW47XG4gICAgICAgIGlmICghY2FuQWRkICYmICFjYW5SZW1vdmUpIHtcbiAgICAgICAgICAvLyBJZiB0aGlzIHBhdGggaXMgYSB0ZXJtaW5hbCB0aGVuIHBydW5lXG4gICAgICAgICAgYmVzdFBhdGhbZGlhZ29uYWxQYXRoXSA9IHVuZGVmaW5lZDtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFNlbGVjdCB0aGUgZGlhZ29uYWwgdGhhdCB3ZSB3YW50IHRvIGJyYW5jaCBmcm9tLiBXZSBzZWxlY3QgdGhlIHByaW9yXG4gICAgICAgIC8vIHBhdGggd2hvc2UgcG9zaXRpb24gaW4gdGhlIG5ldyBzdHJpbmcgaXMgdGhlIGZhcnRoZXN0IGZyb20gdGhlIG9yaWdpblxuICAgICAgICAvLyBhbmQgZG9lcyBub3QgcGFzcyB0aGUgYm91bmRzIG9mIHRoZSBkaWZmIGdyYXBoXG4gICAgICAgIGlmICghY2FuQWRkIHx8IChjYW5SZW1vdmUgJiYgYWRkUGF0aC5uZXdQb3MgPCByZW1vdmVQYXRoLm5ld1BvcykpIHtcbiAgICAgICAgICBiYXNlUGF0aCA9IGNsb25lUGF0aChyZW1vdmVQYXRoKTtcbiAgICAgICAgICBzZWxmLnB1c2hDb21wb25lbnQoYmFzZVBhdGguY29tcG9uZW50cywgdW5kZWZpbmVkLCB0cnVlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBiYXNlUGF0aCA9IGFkZFBhdGg7ICAgLy8gTm8gbmVlZCB0byBjbG9uZSwgd2UndmUgcHVsbGVkIGl0IGZyb20gdGhlIGxpc3RcbiAgICAgICAgICBiYXNlUGF0aC5uZXdQb3MrKztcbiAgICAgICAgICBzZWxmLnB1c2hDb21wb25lbnQoYmFzZVBhdGguY29tcG9uZW50cywgdHJ1ZSwgdW5kZWZpbmVkKTtcbiAgICAgICAgfVxuXG4gICAgICAgIG9sZFBvcyA9IHNlbGYuZXh0cmFjdENvbW1vbihiYXNlUGF0aCwgbmV3U3RyaW5nLCBvbGRTdHJpbmcsIGRpYWdvbmFsUGF0aCk7XG5cbiAgICAgICAgLy8gSWYgd2UgaGF2ZSBoaXQgdGhlIGVuZCBvZiBib3RoIHN0cmluZ3MsIHRoZW4gd2UgYXJlIGRvbmVcbiAgICAgICAgaWYgKGJhc2VQYXRoLm5ld1BvcyArIDEgPj0gbmV3TGVuICYmIG9sZFBvcyArIDEgPj0gb2xkTGVuKSB7XG4gICAgICAgICAgcmV0dXJuIGRvbmUoYnVpbGRWYWx1ZXMoc2VsZiwgYmFzZVBhdGguY29tcG9uZW50cywgbmV3U3RyaW5nLCBvbGRTdHJpbmcsIHNlbGYudXNlTG9uZ2VzdFRva2VuKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gT3RoZXJ3aXNlIHRyYWNrIHRoaXMgcGF0aCBhcyBhIHBvdGVudGlhbCBjYW5kaWRhdGUgYW5kIGNvbnRpbnVlLlxuICAgICAgICAgIGJlc3RQYXRoW2RpYWdvbmFsUGF0aF0gPSBiYXNlUGF0aDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBlZGl0TGVuZ3RoKys7XG4gICAgfVxuXG4gICAgLy8gUGVyZm9ybXMgdGhlIGxlbmd0aCBvZiBlZGl0IGl0ZXJhdGlvbi4gSXMgYSBiaXQgZnVnbHkgYXMgdGhpcyBoYXMgdG8gc3VwcG9ydCB0aGVcbiAgICAvLyBzeW5jIGFuZCBhc3luYyBtb2RlIHdoaWNoIGlzIG5ldmVyIGZ1bi4gTG9vcHMgb3ZlciBleGVjRWRpdExlbmd0aCB1bnRpbCBhIHZhbHVlXG4gICAgLy8gaXMgcHJvZHVjZWQuXG4gICAgaWYgKGNhbGxiYWNrKSB7XG4gICAgICAoZnVuY3Rpb24gZXhlYygpIHtcbiAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgICAvLyBUaGlzIHNob3VsZCBub3QgaGFwcGVuLCBidXQgd2Ugd2FudCB0byBiZSBzYWZlLlxuICAgICAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgICAgICAgaWYgKGVkaXRMZW5ndGggPiBtYXhFZGl0TGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gY2FsbGJhY2soKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoIWV4ZWNFZGl0TGVuZ3RoKCkpIHtcbiAgICAgICAgICAgIGV4ZWMoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0sIDApO1xuICAgICAgfSgpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgd2hpbGUgKGVkaXRMZW5ndGggPD0gbWF4RWRpdExlbmd0aCkge1xuICAgICAgICBsZXQgcmV0ID0gZXhlY0VkaXRMZW5ndGgoKTtcbiAgICAgICAgaWYgKHJldCkge1xuICAgICAgICAgIHJldHVybiByZXQ7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH0sXG5cbiAgcHVzaENvbXBvbmVudChjb21wb25lbnRzLCBhZGRlZCwgcmVtb3ZlZCkge1xuICAgIGxldCBsYXN0ID0gY29tcG9uZW50c1tjb21wb25lbnRzLmxlbmd0aCAtIDFdO1xuICAgIGlmIChsYXN0ICYmIGxhc3QuYWRkZWQgPT09IGFkZGVkICYmIGxhc3QucmVtb3ZlZCA9PT0gcmVtb3ZlZCkge1xuICAgICAgLy8gV2UgbmVlZCB0byBjbG9uZSBoZXJlIGFzIHRoZSBjb21wb25lbnQgY2xvbmUgb3BlcmF0aW9uIGlzIGp1c3RcbiAgICAgIC8vIGFzIHNoYWxsb3cgYXJyYXkgY2xvbmVcbiAgICAgIGNvbXBvbmVudHNbY29tcG9uZW50cy5sZW5ndGggLSAxXSA9IHtjb3VudDogbGFzdC5jb3VudCArIDEsIGFkZGVkOiBhZGRlZCwgcmVtb3ZlZDogcmVtb3ZlZCB9O1xuICAgIH0gZWxzZSB7XG4gICAgICBjb21wb25lbnRzLnB1c2goe2NvdW50OiAxLCBhZGRlZDogYWRkZWQsIHJlbW92ZWQ6IHJlbW92ZWQgfSk7XG4gICAgfVxuICB9LFxuICBleHRyYWN0Q29tbW9uKGJhc2VQYXRoLCBuZXdTdHJpbmcsIG9sZFN0cmluZywgZGlhZ29uYWxQYXRoKSB7XG4gICAgbGV0IG5ld0xlbiA9IG5ld1N0cmluZy5sZW5ndGgsXG4gICAgICAgIG9sZExlbiA9IG9sZFN0cmluZy5sZW5ndGgsXG4gICAgICAgIG5ld1BvcyA9IGJhc2VQYXRoLm5ld1BvcyxcbiAgICAgICAgb2xkUG9zID0gbmV3UG9zIC0gZGlhZ29uYWxQYXRoLFxuXG4gICAgICAgIGNvbW1vbkNvdW50ID0gMDtcbiAgICB3aGlsZSAobmV3UG9zICsgMSA8IG5ld0xlbiAmJiBvbGRQb3MgKyAxIDwgb2xkTGVuICYmIHRoaXMuZXF1YWxzKG5ld1N0cmluZ1tuZXdQb3MgKyAxXSwgb2xkU3RyaW5nW29sZFBvcyArIDFdKSkge1xuICAgICAgbmV3UG9zKys7XG4gICAgICBvbGRQb3MrKztcbiAgICAgIGNvbW1vbkNvdW50Kys7XG4gICAgfVxuXG4gICAgaWYgKGNvbW1vbkNvdW50KSB7XG4gICAgICBiYXNlUGF0aC5jb21wb25lbnRzLnB1c2goe2NvdW50OiBjb21tb25Db3VudH0pO1xuICAgIH1cblxuICAgIGJhc2VQYXRoLm5ld1BvcyA9IG5ld1BvcztcbiAgICByZXR1cm4gb2xkUG9zO1xuICB9LFxuXG4gIGVxdWFscyhsZWZ0LCByaWdodCkge1xuICAgIHJldHVybiBsZWZ0ID09PSByaWdodDtcbiAgfSxcbiAgcmVtb3ZlRW1wdHkoYXJyYXkpIHtcbiAgICBsZXQgcmV0ID0gW107XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcnJheS5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGFycmF5W2ldKSB7XG4gICAgICAgIHJldC5wdXNoKGFycmF5W2ldKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJldDtcbiAgfSxcbiAgY2FzdElucHV0KHZhbHVlKSB7XG4gICAgcmV0dXJuIHZhbHVlO1xuICB9LFxuICB0b2tlbml6ZSh2YWx1ZSkge1xuICAgIHJldHVybiB2YWx1ZS5zcGxpdCgnJyk7XG4gIH0sXG4gIGpvaW4oY2hhcnMpIHtcbiAgICByZXR1cm4gY2hhcnMuam9pbignJyk7XG4gIH1cbn07XG5cbmZ1bmN0aW9uIGJ1aWxkVmFsdWVzKGRpZmYsIGNvbXBvbmVudHMsIG5ld1N0cmluZywgb2xkU3RyaW5nLCB1c2VMb25nZXN0VG9rZW4pIHtcbiAgbGV0IGNvbXBvbmVudFBvcyA9IDAsXG4gICAgICBjb21wb25lbnRMZW4gPSBjb21wb25lbnRzLmxlbmd0aCxcbiAgICAgIG5ld1BvcyA9IDAsXG4gICAgICBvbGRQb3MgPSAwO1xuXG4gIGZvciAoOyBjb21wb25lbnRQb3MgPCBjb21wb25lbnRMZW47IGNvbXBvbmVudFBvcysrKSB7XG4gICAgbGV0IGNvbXBvbmVudCA9IGNvbXBvbmVudHNbY29tcG9uZW50UG9zXTtcbiAgICBpZiAoIWNvbXBvbmVudC5yZW1vdmVkKSB7XG4gICAgICBpZiAoIWNvbXBvbmVudC5hZGRlZCAmJiB1c2VMb25nZXN0VG9rZW4pIHtcbiAgICAgICAgbGV0IHZhbHVlID0gbmV3U3RyaW5nLnNsaWNlKG5ld1BvcywgbmV3UG9zICsgY29tcG9uZW50LmNvdW50KTtcbiAgICAgICAgdmFsdWUgPSB2YWx1ZS5tYXAoZnVuY3Rpb24odmFsdWUsIGkpIHtcbiAgICAgICAgICBsZXQgb2xkVmFsdWUgPSBvbGRTdHJpbmdbb2xkUG9zICsgaV07XG4gICAgICAgICAgcmV0dXJuIG9sZFZhbHVlLmxlbmd0aCA+IHZhbHVlLmxlbmd0aCA/IG9sZFZhbHVlIDogdmFsdWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvbXBvbmVudC52YWx1ZSA9IGRpZmYuam9pbih2YWx1ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb21wb25lbnQudmFsdWUgPSBkaWZmLmpvaW4obmV3U3RyaW5nLnNsaWNlKG5ld1BvcywgbmV3UG9zICsgY29tcG9uZW50LmNvdW50KSk7XG4gICAgICB9XG4gICAgICBuZXdQb3MgKz0gY29tcG9uZW50LmNvdW50O1xuXG4gICAgICAvLyBDb21tb24gY2FzZVxuICAgICAgaWYgKCFjb21wb25lbnQuYWRkZWQpIHtcbiAgICAgICAgb2xkUG9zICs9IGNvbXBvbmVudC5jb3VudDtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgY29tcG9uZW50LnZhbHVlID0gZGlmZi5qb2luKG9sZFN0cmluZy5zbGljZShvbGRQb3MsIG9sZFBvcyArIGNvbXBvbmVudC5jb3VudCkpO1xuICAgICAgb2xkUG9zICs9IGNvbXBvbmVudC5jb3VudDtcblxuICAgICAgLy8gUmV2ZXJzZSBhZGQgYW5kIHJlbW92ZSBzbyByZW1vdmVzIGFyZSBvdXRwdXQgZmlyc3QgdG8gbWF0Y2ggY29tbW9uIGNvbnZlbnRpb25cbiAgICAgIC8vIFRoZSBkaWZmaW5nIGFsZ29yaXRobSBpcyB0aWVkIHRvIGFkZCB0aGVuIHJlbW92ZSBvdXRwdXQgYW5kIHRoaXMgaXMgdGhlIHNpbXBsZXN0XG4gICAgICAvLyByb3V0ZSB0byBnZXQgdGhlIGRlc2lyZWQgb3V0cHV0IHdpdGggbWluaW1hbCBvdmVyaGVhZC5cbiAgICAgIGlmIChjb21wb25lbnRQb3MgJiYgY29tcG9uZW50c1tjb21wb25lbnRQb3MgLSAxXS5hZGRlZCkge1xuICAgICAgICBsZXQgdG1wID0gY29tcG9uZW50c1tjb21wb25lbnRQb3MgLSAxXTtcbiAgICAgICAgY29tcG9uZW50c1tjb21wb25lbnRQb3MgLSAxXSA9IGNvbXBvbmVudHNbY29tcG9uZW50UG9zXTtcbiAgICAgICAgY29tcG9uZW50c1tjb21wb25lbnRQb3NdID0gdG1wO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIFNwZWNpYWwgY2FzZSBoYW5kbGUgZm9yIHdoZW4gb25lIHRlcm1pbmFsIGlzIGlnbm9yZWQuIEZvciB0aGlzIGNhc2Ugd2UgbWVyZ2UgdGhlXG4gIC8vIHRlcm1pbmFsIGludG8gdGhlIHByaW9yIHN0cmluZyBhbmQgZHJvcCB0aGUgY2hhbmdlLlxuICBsZXQgbGFzdENvbXBvbmVudCA9IGNvbXBvbmVudHNbY29tcG9uZW50TGVuIC0gMV07XG4gIGlmIChjb21wb25lbnRMZW4gPiAxXG4gICAgICAmJiAobGFzdENvbXBvbmVudC5hZGRlZCB8fCBsYXN0Q29tcG9uZW50LnJlbW92ZWQpXG4gICAgICAmJiBkaWZmLmVxdWFscygnJywgbGFzdENvbXBvbmVudC52YWx1ZSkpIHtcbiAgICBjb21wb25lbnRzW2NvbXBvbmVudExlbiAtIDJdLnZhbHVlICs9IGxhc3RDb21wb25lbnQudmFsdWU7XG4gICAgY29tcG9uZW50cy5wb3AoKTtcbiAgfVxuXG4gIHJldHVybiBjb21wb25lbnRzO1xufVxuXG5mdW5jdGlvbiBjbG9uZVBhdGgocGF0aCkge1xuICByZXR1cm4geyBuZXdQb3M6IHBhdGgubmV3UG9zLCBjb21wb25lbnRzOiBwYXRoLmNvbXBvbmVudHMuc2xpY2UoMCkgfTtcbn1cbiIsImltcG9ydCBEaWZmIGZyb20gJy4vYmFzZSc7XG5cbmV4cG9ydCBjb25zdCBjaGFyYWN0ZXJEaWZmID0gbmV3IERpZmYoKTtcbmV4cG9ydCBmdW5jdGlvbiBkaWZmQ2hhcnMob2xkU3RyLCBuZXdTdHIsIGNhbGxiYWNrKSB7IHJldHVybiBjaGFyYWN0ZXJEaWZmLmRpZmYob2xkU3RyLCBuZXdTdHIsIGNhbGxiYWNrKTsgfVxuIiwiaW1wb3J0IERpZmYgZnJvbSAnLi9iYXNlJztcblxuZXhwb3J0IGNvbnN0IGNzc0RpZmYgPSBuZXcgRGlmZigpO1xuY3NzRGlmZi50b2tlbml6ZSA9IGZ1bmN0aW9uKHZhbHVlKSB7XG4gIHJldHVybiB2YWx1ZS5zcGxpdCgvKFt7fTo7LF18XFxzKykvKTtcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBkaWZmQ3NzKG9sZFN0ciwgbmV3U3RyLCBjYWxsYmFjaykgeyByZXR1cm4gY3NzRGlmZi5kaWZmKG9sZFN0ciwgbmV3U3RyLCBjYWxsYmFjayk7IH1cbiIsImltcG9ydCBEaWZmIGZyb20gJy4vYmFzZSc7XG5pbXBvcnQge2xpbmVEaWZmfSBmcm9tICcuL2xpbmUnO1xuXG5jb25zdCBvYmplY3RQcm90b3R5cGVUb1N0cmluZyA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmc7XG5cblxuZXhwb3J0IGNvbnN0IGpzb25EaWZmID0gbmV3IERpZmYoKTtcbi8vIERpc2NyaW1pbmF0ZSBiZXR3ZWVuIHR3byBsaW5lcyBvZiBwcmV0dHktcHJpbnRlZCwgc2VyaWFsaXplZCBKU09OIHdoZXJlIG9uZSBvZiB0aGVtIGhhcyBhXG4vLyBkYW5nbGluZyBjb21tYSBhbmQgdGhlIG90aGVyIGRvZXNuJ3QuIFR1cm5zIG91dCBpbmNsdWRpbmcgdGhlIGRhbmdsaW5nIGNvbW1hIHlpZWxkcyB0aGUgbmljZXN0IG91dHB1dDpcbmpzb25EaWZmLnVzZUxvbmdlc3RUb2tlbiA9IHRydWU7XG5cbmpzb25EaWZmLnRva2VuaXplID0gbGluZURpZmYudG9rZW5pemU7XG5qc29uRGlmZi5jYXN0SW5wdXQgPSBmdW5jdGlvbih2YWx1ZSkge1xuICBjb25zdCB7dW5kZWZpbmVkUmVwbGFjZW1lbnR9ID0gdGhpcy5vcHRpb25zO1xuXG4gIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gdmFsdWUgOiBKU09OLnN0cmluZ2lmeShjYW5vbmljYWxpemUodmFsdWUpLCBmdW5jdGlvbihrLCB2KSB7XG4gICAgaWYgKHR5cGVvZiB2ID09PSAndW5kZWZpbmVkJykge1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZFJlcGxhY2VtZW50O1xuICAgIH1cblxuICAgIHJldHVybiB2O1xuICB9LCAnICAnKTtcbn07XG5qc29uRGlmZi5lcXVhbHMgPSBmdW5jdGlvbihsZWZ0LCByaWdodCkge1xuICByZXR1cm4gRGlmZi5wcm90b3R5cGUuZXF1YWxzKGxlZnQucmVwbGFjZSgvLChbXFxyXFxuXSkvZywgJyQxJyksIHJpZ2h0LnJlcGxhY2UoLywoW1xcclxcbl0pL2csICckMScpKTtcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBkaWZmSnNvbihvbGRPYmosIG5ld09iaiwgb3B0aW9ucykgeyByZXR1cm4ganNvbkRpZmYuZGlmZihvbGRPYmosIG5ld09iaiwgb3B0aW9ucyk7IH1cblxuLy8gVGhpcyBmdW5jdGlvbiBoYW5kbGVzIHRoZSBwcmVzZW5jZSBvZiBjaXJjdWxhciByZWZlcmVuY2VzIGJ5IGJhaWxpbmcgb3V0IHdoZW4gZW5jb3VudGVyaW5nIGFuXG4vLyBvYmplY3QgdGhhdCBpcyBhbHJlYWR5IG9uIHRoZSBcInN0YWNrXCIgb2YgaXRlbXMgYmVpbmcgcHJvY2Vzc2VkLlxuZXhwb3J0IGZ1bmN0aW9uIGNhbm9uaWNhbGl6ZShvYmosIHN0YWNrLCByZXBsYWNlbWVudFN0YWNrKSB7XG4gIHN0YWNrID0gc3RhY2sgfHwgW107XG4gIHJlcGxhY2VtZW50U3RhY2sgPSByZXBsYWNlbWVudFN0YWNrIHx8IFtdO1xuXG4gIGxldCBpO1xuXG4gIGZvciAoaSA9IDA7IGkgPCBzdGFjay5sZW5ndGg7IGkgKz0gMSkge1xuICAgIGlmIChzdGFja1tpXSA9PT0gb2JqKSB7XG4gICAgICByZXR1cm4gcmVwbGFjZW1lbnRTdGFja1tpXTtcbiAgICB9XG4gIH1cblxuICBsZXQgY2Fub25pY2FsaXplZE9iajtcblxuICBpZiAoJ1tvYmplY3QgQXJyYXldJyA9PT0gb2JqZWN0UHJvdG90eXBlVG9TdHJpbmcuY2FsbChvYmopKSB7XG4gICAgc3RhY2sucHVzaChvYmopO1xuICAgIGNhbm9uaWNhbGl6ZWRPYmogPSBuZXcgQXJyYXkob2JqLmxlbmd0aCk7XG4gICAgcmVwbGFjZW1lbnRTdGFjay5wdXNoKGNhbm9uaWNhbGl6ZWRPYmopO1xuICAgIGZvciAoaSA9IDA7IGkgPCBvYmoubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgIGNhbm9uaWNhbGl6ZWRPYmpbaV0gPSBjYW5vbmljYWxpemUob2JqW2ldLCBzdGFjaywgcmVwbGFjZW1lbnRTdGFjayk7XG4gICAgfVxuICAgIHN0YWNrLnBvcCgpO1xuICAgIHJlcGxhY2VtZW50U3RhY2sucG9wKCk7XG4gICAgcmV0dXJuIGNhbm9uaWNhbGl6ZWRPYmo7XG4gIH1cblxuICBpZiAob2JqICYmIG9iai50b0pTT04pIHtcbiAgICBvYmogPSBvYmoudG9KU09OKCk7XG4gIH1cblxuICBpZiAodHlwZW9mIG9iaiA9PT0gJ29iamVjdCcgJiYgb2JqICE9PSBudWxsKSB7XG4gICAgc3RhY2sucHVzaChvYmopO1xuICAgIGNhbm9uaWNhbGl6ZWRPYmogPSB7fTtcbiAgICByZXBsYWNlbWVudFN0YWNrLnB1c2goY2Fub25pY2FsaXplZE9iaik7XG4gICAgbGV0IHNvcnRlZEtleXMgPSBbXSxcbiAgICAgICAga2V5O1xuICAgIGZvciAoa2V5IGluIG9iaikge1xuICAgICAgLyogaXN0YW5idWwgaWdub3JlIGVsc2UgKi9cbiAgICAgIGlmIChvYmouaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgICBzb3J0ZWRLZXlzLnB1c2goa2V5KTtcbiAgICAgIH1cbiAgICB9XG4gICAgc29ydGVkS2V5cy5zb3J0KCk7XG4gICAgZm9yIChpID0gMDsgaSA8IHNvcnRlZEtleXMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICAgIGtleSA9IHNvcnRlZEtleXNbaV07XG4gICAgICBjYW5vbmljYWxpemVkT2JqW2tleV0gPSBjYW5vbmljYWxpemUob2JqW2tleV0sIHN0YWNrLCByZXBsYWNlbWVudFN0YWNrKTtcbiAgICB9XG4gICAgc3RhY2sucG9wKCk7XG4gICAgcmVwbGFjZW1lbnRTdGFjay5wb3AoKTtcbiAgfSBlbHNlIHtcbiAgICBjYW5vbmljYWxpemVkT2JqID0gb2JqO1xuICB9XG4gIHJldHVybiBjYW5vbmljYWxpemVkT2JqO1xufVxuIiwiaW1wb3J0IERpZmYgZnJvbSAnLi9iYXNlJztcbmltcG9ydCB7Z2VuZXJhdGVPcHRpb25zfSBmcm9tICcuLi91dGlsL3BhcmFtcyc7XG5cbmV4cG9ydCBjb25zdCBsaW5lRGlmZiA9IG5ldyBEaWZmKCk7XG5saW5lRGlmZi50b2tlbml6ZSA9IGZ1bmN0aW9uKHZhbHVlKSB7XG4gIGxldCByZXRMaW5lcyA9IFtdLFxuICAgICAgbGluZXNBbmROZXdsaW5lcyA9IHZhbHVlLnNwbGl0KC8oXFxufFxcclxcbikvKTtcblxuICAvLyBJZ25vcmUgdGhlIGZpbmFsIGVtcHR5IHRva2VuIHRoYXQgb2NjdXJzIGlmIHRoZSBzdHJpbmcgZW5kcyB3aXRoIGEgbmV3IGxpbmVcbiAgaWYgKCFsaW5lc0FuZE5ld2xpbmVzW2xpbmVzQW5kTmV3bGluZXMubGVuZ3RoIC0gMV0pIHtcbiAgICBsaW5lc0FuZE5ld2xpbmVzLnBvcCgpO1xuICB9XG5cbiAgLy8gTWVyZ2UgdGhlIGNvbnRlbnQgYW5kIGxpbmUgc2VwYXJhdG9ycyBpbnRvIHNpbmdsZSB0b2tlbnNcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBsaW5lc0FuZE5ld2xpbmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgbGV0IGxpbmUgPSBsaW5lc0FuZE5ld2xpbmVzW2ldO1xuXG4gICAgaWYgKGkgJSAyICYmICF0aGlzLm9wdGlvbnMubmV3bGluZUlzVG9rZW4pIHtcbiAgICAgIHJldExpbmVzW3JldExpbmVzLmxlbmd0aCAtIDFdICs9IGxpbmU7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuaWdub3JlV2hpdGVzcGFjZSkge1xuICAgICAgICBsaW5lID0gbGluZS50cmltKCk7XG4gICAgICB9XG4gICAgICByZXRMaW5lcy5wdXNoKGxpbmUpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiByZXRMaW5lcztcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBkaWZmTGluZXMob2xkU3RyLCBuZXdTdHIsIGNhbGxiYWNrKSB7IHJldHVybiBsaW5lRGlmZi5kaWZmKG9sZFN0ciwgbmV3U3RyLCBjYWxsYmFjayk7IH1cbmV4cG9ydCBmdW5jdGlvbiBkaWZmVHJpbW1lZExpbmVzKG9sZFN0ciwgbmV3U3RyLCBjYWxsYmFjaykge1xuICBsZXQgb3B0aW9ucyA9IGdlbmVyYXRlT3B0aW9ucyhjYWxsYmFjaywge2lnbm9yZVdoaXRlc3BhY2U6IHRydWV9KTtcbiAgcmV0dXJuIGxpbmVEaWZmLmRpZmYob2xkU3RyLCBuZXdTdHIsIG9wdGlvbnMpO1xufVxuIiwiaW1wb3J0IERpZmYgZnJvbSAnLi9iYXNlJztcblxuXG5leHBvcnQgY29uc3Qgc2VudGVuY2VEaWZmID0gbmV3IERpZmYoKTtcbnNlbnRlbmNlRGlmZi50b2tlbml6ZSA9IGZ1bmN0aW9uKHZhbHVlKSB7XG4gIHJldHVybiB2YWx1ZS5zcGxpdCgvKFxcUy4rP1suIT9dKSg/PVxccyt8JCkvKTtcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBkaWZmU2VudGVuY2VzKG9sZFN0ciwgbmV3U3RyLCBjYWxsYmFjaykgeyByZXR1cm4gc2VudGVuY2VEaWZmLmRpZmYob2xkU3RyLCBuZXdTdHIsIGNhbGxiYWNrKTsgfVxuIiwiaW1wb3J0IERpZmYgZnJvbSAnLi9iYXNlJztcbmltcG9ydCB7Z2VuZXJhdGVPcHRpb25zfSBmcm9tICcuLi91dGlsL3BhcmFtcyc7XG5cbi8vIEJhc2VkIG9uIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0xhdGluX3NjcmlwdF9pbl9Vbmljb2RlXG4vL1xuLy8gUmFuZ2VzIGFuZCBleGNlcHRpb25zOlxuLy8gTGF0aW4tMSBTdXBwbGVtZW50LCAwMDgw4oCTMDBGRlxuLy8gIC0gVSswMEQ3ICDDlyBNdWx0aXBsaWNhdGlvbiBzaWduXG4vLyAgLSBVKzAwRjcgIMO3IERpdmlzaW9uIHNpZ25cbi8vIExhdGluIEV4dGVuZGVkLUEsIDAxMDDigJMwMTdGXG4vLyBMYXRpbiBFeHRlbmRlZC1CLCAwMTgw4oCTMDI0RlxuLy8gSVBBIEV4dGVuc2lvbnMsIDAyNTDigJMwMkFGXG4vLyBTcGFjaW5nIE1vZGlmaWVyIExldHRlcnMsIDAyQjDigJMwMkZGXG4vLyAgLSBVKzAyQzcgIMuHICYjNzExOyAgQ2Fyb25cbi8vICAtIFUrMDJEOCAgy5ggJiM3Mjg7ICBCcmV2ZVxuLy8gIC0gVSswMkQ5ICDLmSAmIzcyOTsgIERvdCBBYm92ZVxuLy8gIC0gVSswMkRBICDLmiAmIzczMDsgIFJpbmcgQWJvdmVcbi8vICAtIFUrMDJEQiAgy5sgJiM3MzE7ICBPZ29uZWtcbi8vICAtIFUrMDJEQyAgy5wgJiM3MzI7ICBTbWFsbCBUaWxkZVxuLy8gIC0gVSswMkREICDLnSAmIzczMzsgIERvdWJsZSBBY3V0ZSBBY2NlbnRcbi8vIExhdGluIEV4dGVuZGVkIEFkZGl0aW9uYWwsIDFFMDDigJMxRUZGXG5jb25zdCBleHRlbmRlZFdvcmRDaGFycyA9IC9eW2EtekEtWlxcdXtDMH0tXFx1e0ZGfVxcdXtEOH0tXFx1e0Y2fVxcdXtGOH0tXFx1ezJDNn1cXHV7MkM4fS1cXHV7MkQ3fVxcdXsyREV9LVxcdXsyRkZ9XFx1ezFFMDB9LVxcdXsxRUZGfV0rJC91O1xuXG5jb25zdCByZVdoaXRlc3BhY2UgPSAvXFxTLztcblxuZXhwb3J0IGNvbnN0IHdvcmREaWZmID0gbmV3IERpZmYoKTtcbndvcmREaWZmLmVxdWFscyA9IGZ1bmN0aW9uKGxlZnQsIHJpZ2h0KSB7XG4gIHJldHVybiBsZWZ0ID09PSByaWdodCB8fCAodGhpcy5vcHRpb25zLmlnbm9yZVdoaXRlc3BhY2UgJiYgIXJlV2hpdGVzcGFjZS50ZXN0KGxlZnQpICYmICFyZVdoaXRlc3BhY2UudGVzdChyaWdodCkpO1xufTtcbndvcmREaWZmLnRva2VuaXplID0gZnVuY3Rpb24odmFsdWUpIHtcbiAgbGV0IHRva2VucyA9IHZhbHVlLnNwbGl0KC8oXFxzK3xcXGIpLyk7XG5cbiAgLy8gSm9pbiB0aGUgYm91bmRhcnkgc3BsaXRzIHRoYXQgd2UgZG8gbm90IGNvbnNpZGVyIHRvIGJlIGJvdW5kYXJpZXMuIFRoaXMgaXMgcHJpbWFyaWx5IHRoZSBleHRlbmRlZCBMYXRpbiBjaGFyYWN0ZXIgc2V0LlxuICBmb3IgKGxldCBpID0gMDsgaSA8IHRva2Vucy5sZW5ndGggLSAxOyBpKyspIHtcbiAgICAvLyBJZiB3ZSBoYXZlIGFuIGVtcHR5IHN0cmluZyBpbiB0aGUgbmV4dCBmaWVsZCBhbmQgd2UgaGF2ZSBvbmx5IHdvcmQgY2hhcnMgYmVmb3JlIGFuZCBhZnRlciwgbWVyZ2VcbiAgICBpZiAoIXRva2Vuc1tpICsgMV0gJiYgdG9rZW5zW2kgKyAyXVxuICAgICAgICAgICYmIGV4dGVuZGVkV29yZENoYXJzLnRlc3QodG9rZW5zW2ldKVxuICAgICAgICAgICYmIGV4dGVuZGVkV29yZENoYXJzLnRlc3QodG9rZW5zW2kgKyAyXSkpIHtcbiAgICAgIHRva2Vuc1tpXSArPSB0b2tlbnNbaSArIDJdO1xuICAgICAgdG9rZW5zLnNwbGljZShpICsgMSwgMik7XG4gICAgICBpLS07XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHRva2Vucztcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBkaWZmV29yZHMob2xkU3RyLCBuZXdTdHIsIGNhbGxiYWNrKSB7XG4gIGxldCBvcHRpb25zID0gZ2VuZXJhdGVPcHRpb25zKGNhbGxiYWNrLCB7aWdub3JlV2hpdGVzcGFjZTogdHJ1ZX0pO1xuICByZXR1cm4gd29yZERpZmYuZGlmZihvbGRTdHIsIG5ld1N0ciwgb3B0aW9ucyk7XG59XG5leHBvcnQgZnVuY3Rpb24gZGlmZldvcmRzV2l0aFNwYWNlKG9sZFN0ciwgbmV3U3RyLCBjYWxsYmFjaykge1xuICByZXR1cm4gd29yZERpZmYuZGlmZihvbGRTdHIsIG5ld1N0ciwgY2FsbGJhY2spO1xufVxuIiwiLyogU2VlIExJQ0VOU0UgZmlsZSBmb3IgdGVybXMgb2YgdXNlICovXG5cbi8qXG4gKiBUZXh0IGRpZmYgaW1wbGVtZW50YXRpb24uXG4gKlxuICogVGhpcyBsaWJyYXJ5IHN1cHBvcnRzIHRoZSBmb2xsb3dpbmcgQVBJUzpcbiAqIEpzRGlmZi5kaWZmQ2hhcnM6IENoYXJhY3RlciBieSBjaGFyYWN0ZXIgZGlmZlxuICogSnNEaWZmLmRpZmZXb3JkczogV29yZCAoYXMgZGVmaW5lZCBieSBcXGIgcmVnZXgpIGRpZmYgd2hpY2ggaWdub3JlcyB3aGl0ZXNwYWNlXG4gKiBKc0RpZmYuZGlmZkxpbmVzOiBMaW5lIGJhc2VkIGRpZmZcbiAqXG4gKiBKc0RpZmYuZGlmZkNzczogRGlmZiB0YXJnZXRlZCBhdCBDU1MgY29udGVudFxuICpcbiAqIFRoZXNlIG1ldGhvZHMgYXJlIGJhc2VkIG9uIHRoZSBpbXBsZW1lbnRhdGlvbiBwcm9wb3NlZCBpblxuICogXCJBbiBPKE5EKSBEaWZmZXJlbmNlIEFsZ29yaXRobSBhbmQgaXRzIFZhcmlhdGlvbnNcIiAoTXllcnMsIDE5ODYpLlxuICogaHR0cDovL2NpdGVzZWVyeC5pc3QucHN1LmVkdS92aWV3ZG9jL3N1bW1hcnk/ZG9pPTEwLjEuMS40LjY5MjdcbiAqL1xuaW1wb3J0IERpZmYgZnJvbSAnLi9kaWZmL2Jhc2UnO1xuaW1wb3J0IHtkaWZmQ2hhcnN9IGZyb20gJy4vZGlmZi9jaGFyYWN0ZXInO1xuaW1wb3J0IHtkaWZmV29yZHMsIGRpZmZXb3Jkc1dpdGhTcGFjZX0gZnJvbSAnLi9kaWZmL3dvcmQnO1xuaW1wb3J0IHtkaWZmTGluZXMsIGRpZmZUcmltbWVkTGluZXN9IGZyb20gJy4vZGlmZi9saW5lJztcbmltcG9ydCB7ZGlmZlNlbnRlbmNlc30gZnJvbSAnLi9kaWZmL3NlbnRlbmNlJztcblxuaW1wb3J0IHtkaWZmQ3NzfSBmcm9tICcuL2RpZmYvY3NzJztcbmltcG9ydCB7ZGlmZkpzb24sIGNhbm9uaWNhbGl6ZX0gZnJvbSAnLi9kaWZmL2pzb24nO1xuXG5pbXBvcnQge2RpZmZBcnJheXN9IGZyb20gJy4vZGlmZi9hcnJheSc7XG5cbmltcG9ydCB7YXBwbHlQYXRjaCwgYXBwbHlQYXRjaGVzfSBmcm9tICcuL3BhdGNoL2FwcGx5JztcbmltcG9ydCB7cGFyc2VQYXRjaH0gZnJvbSAnLi9wYXRjaC9wYXJzZSc7XG5pbXBvcnQge3N0cnVjdHVyZWRQYXRjaCwgY3JlYXRlVHdvRmlsZXNQYXRjaCwgY3JlYXRlUGF0Y2h9IGZyb20gJy4vcGF0Y2gvY3JlYXRlJztcblxuaW1wb3J0IHtjb252ZXJ0Q2hhbmdlc1RvRE1QfSBmcm9tICcuL2NvbnZlcnQvZG1wJztcbmltcG9ydCB7Y29udmVydENoYW5nZXNUb1hNTH0gZnJvbSAnLi9jb252ZXJ0L3htbCc7XG5cbmV4cG9ydCB7XG4gIERpZmYsXG5cbiAgZGlmZkNoYXJzLFxuICBkaWZmV29yZHMsXG4gIGRpZmZXb3Jkc1dpdGhTcGFjZSxcbiAgZGlmZkxpbmVzLFxuICBkaWZmVHJpbW1lZExpbmVzLFxuICBkaWZmU2VudGVuY2VzLFxuXG4gIGRpZmZDc3MsXG4gIGRpZmZKc29uLFxuXG4gIGRpZmZBcnJheXMsXG5cbiAgc3RydWN0dXJlZFBhdGNoLFxuICBjcmVhdGVUd29GaWxlc1BhdGNoLFxuICBjcmVhdGVQYXRjaCxcbiAgYXBwbHlQYXRjaCxcbiAgYXBwbHlQYXRjaGVzLFxuICBwYXJzZVBhdGNoLFxuICBjb252ZXJ0Q2hhbmdlc1RvRE1QLFxuICBjb252ZXJ0Q2hhbmdlc1RvWE1MLFxuICBjYW5vbmljYWxpemVcbn07XG4iLCJpbXBvcnQge3BhcnNlUGF0Y2h9IGZyb20gJy4vcGFyc2UnO1xuaW1wb3J0IGRpc3RhbmNlSXRlcmF0b3IgZnJvbSAnLi4vdXRpbC9kaXN0YW5jZS1pdGVyYXRvcic7XG5cbmV4cG9ydCBmdW5jdGlvbiBhcHBseVBhdGNoKHNvdXJjZSwgdW5pRGlmZiwgb3B0aW9ucyA9IHt9KSB7XG4gIGlmICh0eXBlb2YgdW5pRGlmZiA9PT0gJ3N0cmluZycpIHtcbiAgICB1bmlEaWZmID0gcGFyc2VQYXRjaCh1bmlEaWZmKTtcbiAgfVxuXG4gIGlmIChBcnJheS5pc0FycmF5KHVuaURpZmYpKSB7XG4gICAgaWYgKHVuaURpZmYubGVuZ3RoID4gMSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdhcHBseVBhdGNoIG9ubHkgd29ya3Mgd2l0aCBhIHNpbmdsZSBpbnB1dC4nKTtcbiAgICB9XG5cbiAgICB1bmlEaWZmID0gdW5pRGlmZlswXTtcbiAgfVxuXG4gIC8vIEFwcGx5IHRoZSBkaWZmIHRvIHRoZSBpbnB1dFxuICBsZXQgbGluZXMgPSBzb3VyY2Uuc3BsaXQoL1xcclxcbnxbXFxuXFx2XFxmXFxyXFx4ODVdLyksXG4gICAgICBkZWxpbWl0ZXJzID0gc291cmNlLm1hdGNoKC9cXHJcXG58W1xcblxcdlxcZlxcclxceDg1XS9nKSB8fCBbXSxcbiAgICAgIGh1bmtzID0gdW5pRGlmZi5odW5rcyxcblxuICAgICAgY29tcGFyZUxpbmUgPSBvcHRpb25zLmNvbXBhcmVMaW5lIHx8ICgobGluZU51bWJlciwgbGluZSwgb3BlcmF0aW9uLCBwYXRjaENvbnRlbnQpID0+IGxpbmUgPT09IHBhdGNoQ29udGVudCksXG4gICAgICBlcnJvckNvdW50ID0gMCxcbiAgICAgIGZ1enpGYWN0b3IgPSBvcHRpb25zLmZ1enpGYWN0b3IgfHwgMCxcbiAgICAgIG1pbkxpbmUgPSAwLFxuICAgICAgb2Zmc2V0ID0gMCxcblxuICAgICAgcmVtb3ZlRU9GTkwsXG4gICAgICBhZGRFT0ZOTDtcblxuICAvKipcbiAgICogQ2hlY2tzIGlmIHRoZSBodW5rIGV4YWN0bHkgZml0cyBvbiB0aGUgcHJvdmlkZWQgbG9jYXRpb25cbiAgICovXG4gIGZ1bmN0aW9uIGh1bmtGaXRzKGh1bmssIHRvUG9zKSB7XG4gICAgZm9yIChsZXQgaiA9IDA7IGogPCBodW5rLmxpbmVzLmxlbmd0aDsgaisrKSB7XG4gICAgICBsZXQgbGluZSA9IGh1bmsubGluZXNbal0sXG4gICAgICAgICAgb3BlcmF0aW9uID0gbGluZVswXSxcbiAgICAgICAgICBjb250ZW50ID0gbGluZS5zdWJzdHIoMSk7XG5cbiAgICAgIGlmIChvcGVyYXRpb24gPT09ICcgJyB8fCBvcGVyYXRpb24gPT09ICctJykge1xuICAgICAgICAvLyBDb250ZXh0IHNhbml0eSBjaGVja1xuICAgICAgICBpZiAoIWNvbXBhcmVMaW5lKHRvUG9zICsgMSwgbGluZXNbdG9Qb3NdLCBvcGVyYXRpb24sIGNvbnRlbnQpKSB7XG4gICAgICAgICAgZXJyb3JDb3VudCsrO1xuXG4gICAgICAgICAgaWYgKGVycm9yQ291bnQgPiBmdXp6RmFjdG9yKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHRvUG9zKys7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvLyBTZWFyY2ggYmVzdCBmaXQgb2Zmc2V0cyBmb3IgZWFjaCBodW5rIGJhc2VkIG9uIHRoZSBwcmV2aW91cyBvbmVzXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgaHVua3MubGVuZ3RoOyBpKyspIHtcbiAgICBsZXQgaHVuayA9IGh1bmtzW2ldLFxuICAgICAgICBtYXhMaW5lID0gbGluZXMubGVuZ3RoIC0gaHVuay5vbGRMaW5lcyxcbiAgICAgICAgbG9jYWxPZmZzZXQgPSAwLFxuICAgICAgICB0b1BvcyA9IG9mZnNldCArIGh1bmsub2xkU3RhcnQgLSAxO1xuXG4gICAgbGV0IGl0ZXJhdG9yID0gZGlzdGFuY2VJdGVyYXRvcih0b1BvcywgbWluTGluZSwgbWF4TGluZSk7XG5cbiAgICBmb3IgKDsgbG9jYWxPZmZzZXQgIT09IHVuZGVmaW5lZDsgbG9jYWxPZmZzZXQgPSBpdGVyYXRvcigpKSB7XG4gICAgICBpZiAoaHVua0ZpdHMoaHVuaywgdG9Qb3MgKyBsb2NhbE9mZnNldCkpIHtcbiAgICAgICAgaHVuay5vZmZzZXQgPSBvZmZzZXQgKz0gbG9jYWxPZmZzZXQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChsb2NhbE9mZnNldCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gU2V0IGxvd2VyIHRleHQgbGltaXQgdG8gZW5kIG9mIHRoZSBjdXJyZW50IGh1bmssIHNvIG5leHQgb25lcyBkb24ndCB0cnlcbiAgICAvLyB0byBmaXQgb3ZlciBhbHJlYWR5IHBhdGNoZWQgdGV4dFxuICAgIG1pbkxpbmUgPSBodW5rLm9mZnNldCArIGh1bmsub2xkU3RhcnQgKyBodW5rLm9sZExpbmVzO1xuICB9XG5cbiAgLy8gQXBwbHkgcGF0Y2ggaHVua3NcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBodW5rcy5sZW5ndGg7IGkrKykge1xuICAgIGxldCBodW5rID0gaHVua3NbaV0sXG4gICAgICAgIHRvUG9zID0gaHVuay5vZmZzZXQgKyBodW5rLm5ld1N0YXJ0IC0gMTtcbiAgICBpZiAoaHVuay5uZXdMaW5lcyA9PSAwKSB7IHRvUG9zKys7IH1cblxuICAgIGZvciAobGV0IGogPSAwOyBqIDwgaHVuay5saW5lcy5sZW5ndGg7IGorKykge1xuICAgICAgbGV0IGxpbmUgPSBodW5rLmxpbmVzW2pdLFxuICAgICAgICAgIG9wZXJhdGlvbiA9IGxpbmVbMF0sXG4gICAgICAgICAgY29udGVudCA9IGxpbmUuc3Vic3RyKDEpLFxuICAgICAgICAgIGRlbGltaXRlciA9IGh1bmsubGluZWRlbGltaXRlcnNbal07XG5cbiAgICAgIGlmIChvcGVyYXRpb24gPT09ICcgJykge1xuICAgICAgICB0b1BvcysrO1xuICAgICAgfSBlbHNlIGlmIChvcGVyYXRpb24gPT09ICctJykge1xuICAgICAgICBsaW5lcy5zcGxpY2UodG9Qb3MsIDEpO1xuICAgICAgICBkZWxpbWl0ZXJzLnNwbGljZSh0b1BvcywgMSk7XG4gICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgZWxzZSAqL1xuICAgICAgfSBlbHNlIGlmIChvcGVyYXRpb24gPT09ICcrJykge1xuICAgICAgICBsaW5lcy5zcGxpY2UodG9Qb3MsIDAsIGNvbnRlbnQpO1xuICAgICAgICBkZWxpbWl0ZXJzLnNwbGljZSh0b1BvcywgMCwgZGVsaW1pdGVyKTtcbiAgICAgICAgdG9Qb3MrKztcbiAgICAgIH0gZWxzZSBpZiAob3BlcmF0aW9uID09PSAnXFxcXCcpIHtcbiAgICAgICAgbGV0IHByZXZpb3VzT3BlcmF0aW9uID0gaHVuay5saW5lc1tqIC0gMV0gPyBodW5rLmxpbmVzW2ogLSAxXVswXSA6IG51bGw7XG4gICAgICAgIGlmIChwcmV2aW91c09wZXJhdGlvbiA9PT0gJysnKSB7XG4gICAgICAgICAgcmVtb3ZlRU9GTkwgPSB0cnVlO1xuICAgICAgICB9IGVsc2UgaWYgKHByZXZpb3VzT3BlcmF0aW9uID09PSAnLScpIHtcbiAgICAgICAgICBhZGRFT0ZOTCA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBIYW5kbGUgRU9GTkwgaW5zZXJ0aW9uL3JlbW92YWxcbiAgaWYgKHJlbW92ZUVPRk5MKSB7XG4gICAgd2hpbGUgKCFsaW5lc1tsaW5lcy5sZW5ndGggLSAxXSkge1xuICAgICAgbGluZXMucG9wKCk7XG4gICAgICBkZWxpbWl0ZXJzLnBvcCgpO1xuICAgIH1cbiAgfSBlbHNlIGlmIChhZGRFT0ZOTCkge1xuICAgIGxpbmVzLnB1c2goJycpO1xuICAgIGRlbGltaXRlcnMucHVzaCgnXFxuJyk7XG4gIH1cbiAgZm9yIChsZXQgX2sgPSAwOyBfayA8IGxpbmVzLmxlbmd0aCAtIDE7IF9rKyspIHtcbiAgICBsaW5lc1tfa10gPSBsaW5lc1tfa10gKyBkZWxpbWl0ZXJzW19rXTtcbiAgfVxuICByZXR1cm4gbGluZXMuam9pbignJyk7XG59XG5cbi8vIFdyYXBwZXIgdGhhdCBzdXBwb3J0cyBtdWx0aXBsZSBmaWxlIHBhdGNoZXMgdmlhIGNhbGxiYWNrcy5cbmV4cG9ydCBmdW5jdGlvbiBhcHBseVBhdGNoZXModW5pRGlmZiwgb3B0aW9ucykge1xuICBpZiAodHlwZW9mIHVuaURpZmYgPT09ICdzdHJpbmcnKSB7XG4gICAgdW5pRGlmZiA9IHBhcnNlUGF0Y2godW5pRGlmZik7XG4gIH1cblxuICBsZXQgY3VycmVudEluZGV4ID0gMDtcbiAgZnVuY3Rpb24gcHJvY2Vzc0luZGV4KCkge1xuICAgIGxldCBpbmRleCA9IHVuaURpZmZbY3VycmVudEluZGV4KytdO1xuICAgIGlmICghaW5kZXgpIHtcbiAgICAgIHJldHVybiBvcHRpb25zLmNvbXBsZXRlKCk7XG4gICAgfVxuXG4gICAgb3B0aW9ucy5sb2FkRmlsZShpbmRleCwgZnVuY3Rpb24oZXJyLCBkYXRhKSB7XG4gICAgICBpZiAoZXJyKSB7XG4gICAgICAgIHJldHVybiBvcHRpb25zLmNvbXBsZXRlKGVycik7XG4gICAgICB9XG5cbiAgICAgIGxldCB1cGRhdGVkQ29udGVudCA9IGFwcGx5UGF0Y2goZGF0YSwgaW5kZXgsIG9wdGlvbnMpO1xuICAgICAgb3B0aW9ucy5wYXRjaGVkKGluZGV4LCB1cGRhdGVkQ29udGVudCwgZnVuY3Rpb24oZXJyKSB7XG4gICAgICAgIGlmIChlcnIpIHtcbiAgICAgICAgICByZXR1cm4gb3B0aW9ucy5jb21wbGV0ZShlcnIpO1xuICAgICAgICB9XG5cbiAgICAgICAgcHJvY2Vzc0luZGV4KCk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfVxuICBwcm9jZXNzSW5kZXgoKTtcbn1cbiIsImltcG9ydCB7ZGlmZkxpbmVzfSBmcm9tICcuLi9kaWZmL2xpbmUnO1xuXG5leHBvcnQgZnVuY3Rpb24gc3RydWN0dXJlZFBhdGNoKG9sZEZpbGVOYW1lLCBuZXdGaWxlTmFtZSwgb2xkU3RyLCBuZXdTdHIsIG9sZEhlYWRlciwgbmV3SGVhZGVyLCBvcHRpb25zKSB7XG4gIGlmICghb3B0aW9ucykge1xuICAgIG9wdGlvbnMgPSB7fTtcbiAgfVxuICBpZiAodHlwZW9mIG9wdGlvbnMuY29udGV4dCA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBvcHRpb25zLmNvbnRleHQgPSA0O1xuICB9XG5cbiAgY29uc3QgZGlmZiA9IGRpZmZMaW5lcyhvbGRTdHIsIG5ld1N0ciwgb3B0aW9ucyk7XG4gIGRpZmYucHVzaCh7dmFsdWU6ICcnLCBsaW5lczogW119KTsgICAvLyBBcHBlbmQgYW4gZW1wdHkgdmFsdWUgdG8gbWFrZSBjbGVhbnVwIGVhc2llclxuXG4gIGZ1bmN0aW9uIGNvbnRleHRMaW5lcyhsaW5lcykge1xuICAgIHJldHVybiBsaW5lcy5tYXAoZnVuY3Rpb24oZW50cnkpIHsgcmV0dXJuICcgJyArIGVudHJ5OyB9KTtcbiAgfVxuXG4gIGxldCBodW5rcyA9IFtdO1xuICBsZXQgb2xkUmFuZ2VTdGFydCA9IDAsIG5ld1JhbmdlU3RhcnQgPSAwLCBjdXJSYW5nZSA9IFtdLFxuICAgICAgb2xkTGluZSA9IDEsIG5ld0xpbmUgPSAxO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGRpZmYubGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCBjdXJyZW50ID0gZGlmZltpXSxcbiAgICAgICAgICBsaW5lcyA9IGN1cnJlbnQubGluZXMgfHwgY3VycmVudC52YWx1ZS5yZXBsYWNlKC9cXG4kLywgJycpLnNwbGl0KCdcXG4nKTtcbiAgICBjdXJyZW50LmxpbmVzID0gbGluZXM7XG5cbiAgICBpZiAoY3VycmVudC5hZGRlZCB8fCBjdXJyZW50LnJlbW92ZWQpIHtcbiAgICAgIC8vIElmIHdlIGhhdmUgcHJldmlvdXMgY29udGV4dCwgc3RhcnQgd2l0aCB0aGF0XG4gICAgICBpZiAoIW9sZFJhbmdlU3RhcnQpIHtcbiAgICAgICAgY29uc3QgcHJldiA9IGRpZmZbaSAtIDFdO1xuICAgICAgICBvbGRSYW5nZVN0YXJ0ID0gb2xkTGluZTtcbiAgICAgICAgbmV3UmFuZ2VTdGFydCA9IG5ld0xpbmU7XG5cbiAgICAgICAgaWYgKHByZXYpIHtcbiAgICAgICAgICBjdXJSYW5nZSA9IG9wdGlvbnMuY29udGV4dCA+IDAgPyBjb250ZXh0TGluZXMocHJldi5saW5lcy5zbGljZSgtb3B0aW9ucy5jb250ZXh0KSkgOiBbXTtcbiAgICAgICAgICBvbGRSYW5nZVN0YXJ0IC09IGN1clJhbmdlLmxlbmd0aDtcbiAgICAgICAgICBuZXdSYW5nZVN0YXJ0IC09IGN1clJhbmdlLmxlbmd0aDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBPdXRwdXQgb3VyIGNoYW5nZXNcbiAgICAgIGN1clJhbmdlLnB1c2goLi4uIGxpbmVzLm1hcChmdW5jdGlvbihlbnRyeSkge1xuICAgICAgICByZXR1cm4gKGN1cnJlbnQuYWRkZWQgPyAnKycgOiAnLScpICsgZW50cnk7XG4gICAgICB9KSk7XG5cbiAgICAgIC8vIFRyYWNrIHRoZSB1cGRhdGVkIGZpbGUgcG9zaXRpb25cbiAgICAgIGlmIChjdXJyZW50LmFkZGVkKSB7XG4gICAgICAgIG5ld0xpbmUgKz0gbGluZXMubGVuZ3RoO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgb2xkTGluZSArPSBsaW5lcy5sZW5ndGg7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIElkZW50aWNhbCBjb250ZXh0IGxpbmVzLiBUcmFjayBsaW5lIGNoYW5nZXNcbiAgICAgIGlmIChvbGRSYW5nZVN0YXJ0KSB7XG4gICAgICAgIC8vIENsb3NlIG91dCBhbnkgY2hhbmdlcyB0aGF0IGhhdmUgYmVlbiBvdXRwdXQgKG9yIGpvaW4gb3ZlcmxhcHBpbmcpXG4gICAgICAgIGlmIChsaW5lcy5sZW5ndGggPD0gb3B0aW9ucy5jb250ZXh0ICogMiAmJiBpIDwgZGlmZi5sZW5ndGggLSAyKSB7XG4gICAgICAgICAgLy8gT3ZlcmxhcHBpbmdcbiAgICAgICAgICBjdXJSYW5nZS5wdXNoKC4uLiBjb250ZXh0TGluZXMobGluZXMpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBlbmQgdGhlIHJhbmdlIGFuZCBvdXRwdXRcbiAgICAgICAgICBsZXQgY29udGV4dFNpemUgPSBNYXRoLm1pbihsaW5lcy5sZW5ndGgsIG9wdGlvbnMuY29udGV4dCk7XG4gICAgICAgICAgY3VyUmFuZ2UucHVzaCguLi4gY29udGV4dExpbmVzKGxpbmVzLnNsaWNlKDAsIGNvbnRleHRTaXplKSkpO1xuXG4gICAgICAgICAgbGV0IGh1bmsgPSB7XG4gICAgICAgICAgICBvbGRTdGFydDogb2xkUmFuZ2VTdGFydCxcbiAgICAgICAgICAgIG9sZExpbmVzOiAob2xkTGluZSAtIG9sZFJhbmdlU3RhcnQgKyBjb250ZXh0U2l6ZSksXG4gICAgICAgICAgICBuZXdTdGFydDogbmV3UmFuZ2VTdGFydCxcbiAgICAgICAgICAgIG5ld0xpbmVzOiAobmV3TGluZSAtIG5ld1JhbmdlU3RhcnQgKyBjb250ZXh0U2l6ZSksXG4gICAgICAgICAgICBsaW5lczogY3VyUmFuZ2VcbiAgICAgICAgICB9O1xuICAgICAgICAgIGlmIChpID49IGRpZmYubGVuZ3RoIC0gMiAmJiBsaW5lcy5sZW5ndGggPD0gb3B0aW9ucy5jb250ZXh0KSB7XG4gICAgICAgICAgICAvLyBFT0YgaXMgaW5zaWRlIHRoaXMgaHVua1xuICAgICAgICAgICAgbGV0IG9sZEVPRk5ld2xpbmUgPSAoL1xcbiQvLnRlc3Qob2xkU3RyKSk7XG4gICAgICAgICAgICBsZXQgbmV3RU9GTmV3bGluZSA9ICgvXFxuJC8udGVzdChuZXdTdHIpKTtcbiAgICAgICAgICAgIGlmIChsaW5lcy5sZW5ndGggPT0gMCAmJiAhb2xkRU9GTmV3bGluZSkge1xuICAgICAgICAgICAgICAvLyBzcGVjaWFsIGNhc2U6IG9sZCBoYXMgbm8gZW9sIGFuZCBubyB0cmFpbGluZyBjb250ZXh0OyBuby1ubCBjYW4gZW5kIHVwIGJlZm9yZSBhZGRzXG4gICAgICAgICAgICAgIGN1clJhbmdlLnNwbGljZShodW5rLm9sZExpbmVzLCAwLCAnXFxcXCBObyBuZXdsaW5lIGF0IGVuZCBvZiBmaWxlJyk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCFvbGRFT0ZOZXdsaW5lIHx8ICFuZXdFT0ZOZXdsaW5lKSB7XG4gICAgICAgICAgICAgIGN1clJhbmdlLnB1c2goJ1xcXFwgTm8gbmV3bGluZSBhdCBlbmQgb2YgZmlsZScpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBodW5rcy5wdXNoKGh1bmspO1xuXG4gICAgICAgICAgb2xkUmFuZ2VTdGFydCA9IDA7XG4gICAgICAgICAgbmV3UmFuZ2VTdGFydCA9IDA7XG4gICAgICAgICAgY3VyUmFuZ2UgPSBbXTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgb2xkTGluZSArPSBsaW5lcy5sZW5ndGg7XG4gICAgICBuZXdMaW5lICs9IGxpbmVzLmxlbmd0aDtcbiAgICB9XG4gIH1cblxuICByZXR1cm4ge1xuICAgIG9sZEZpbGVOYW1lOiBvbGRGaWxlTmFtZSwgbmV3RmlsZU5hbWU6IG5ld0ZpbGVOYW1lLFxuICAgIG9sZEhlYWRlcjogb2xkSGVhZGVyLCBuZXdIZWFkZXI6IG5ld0hlYWRlcixcbiAgICBodW5rczogaHVua3NcbiAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVR3b0ZpbGVzUGF0Y2gob2xkRmlsZU5hbWUsIG5ld0ZpbGVOYW1lLCBvbGRTdHIsIG5ld1N0ciwgb2xkSGVhZGVyLCBuZXdIZWFkZXIsIG9wdGlvbnMpIHtcbiAgY29uc3QgZGlmZiA9IHN0cnVjdHVyZWRQYXRjaChvbGRGaWxlTmFtZSwgbmV3RmlsZU5hbWUsIG9sZFN0ciwgbmV3U3RyLCBvbGRIZWFkZXIsIG5ld0hlYWRlciwgb3B0aW9ucyk7XG5cbiAgY29uc3QgcmV0ID0gW107XG4gIGlmIChvbGRGaWxlTmFtZSA9PSBuZXdGaWxlTmFtZSkge1xuICAgIHJldC5wdXNoKCdJbmRleDogJyArIG9sZEZpbGVOYW1lKTtcbiAgfVxuICByZXQucHVzaCgnPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PScpO1xuICByZXQucHVzaCgnLS0tICcgKyBkaWZmLm9sZEZpbGVOYW1lICsgKHR5cGVvZiBkaWZmLm9sZEhlYWRlciA9PT0gJ3VuZGVmaW5lZCcgPyAnJyA6ICdcXHQnICsgZGlmZi5vbGRIZWFkZXIpKTtcbiAgcmV0LnB1c2goJysrKyAnICsgZGlmZi5uZXdGaWxlTmFtZSArICh0eXBlb2YgZGlmZi5uZXdIZWFkZXIgPT09ICd1bmRlZmluZWQnID8gJycgOiAnXFx0JyArIGRpZmYubmV3SGVhZGVyKSk7XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBkaWZmLmh1bmtzLmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3QgaHVuayA9IGRpZmYuaHVua3NbaV07XG4gICAgcmV0LnB1c2goXG4gICAgICAnQEAgLScgKyBodW5rLm9sZFN0YXJ0ICsgJywnICsgaHVuay5vbGRMaW5lc1xuICAgICAgKyAnICsnICsgaHVuay5uZXdTdGFydCArICcsJyArIGh1bmsubmV3TGluZXNcbiAgICAgICsgJyBAQCdcbiAgICApO1xuICAgIHJldC5wdXNoLmFwcGx5KHJldCwgaHVuay5saW5lcyk7XG4gIH1cblxuICByZXR1cm4gcmV0LmpvaW4oJ1xcbicpICsgJ1xcbic7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVQYXRjaChmaWxlTmFtZSwgb2xkU3RyLCBuZXdTdHIsIG9sZEhlYWRlciwgbmV3SGVhZGVyLCBvcHRpb25zKSB7XG4gIHJldHVybiBjcmVhdGVUd29GaWxlc1BhdGNoKGZpbGVOYW1lLCBmaWxlTmFtZSwgb2xkU3RyLCBuZXdTdHIsIG9sZEhlYWRlciwgbmV3SGVhZGVyLCBvcHRpb25zKTtcbn1cbiIsImV4cG9ydCBmdW5jdGlvbiBwYXJzZVBhdGNoKHVuaURpZmYsIG9wdGlvbnMgPSB7fSkge1xuICBsZXQgZGlmZnN0ciA9IHVuaURpZmYuc3BsaXQoL1xcclxcbnxbXFxuXFx2XFxmXFxyXFx4ODVdLyksXG4gICAgICBkZWxpbWl0ZXJzID0gdW5pRGlmZi5tYXRjaCgvXFxyXFxufFtcXG5cXHZcXGZcXHJcXHg4NV0vZykgfHwgW10sXG4gICAgICBsaXN0ID0gW10sXG4gICAgICBpID0gMDtcblxuICBmdW5jdGlvbiBwYXJzZUluZGV4KCkge1xuICAgIGxldCBpbmRleCA9IHt9O1xuICAgIGxpc3QucHVzaChpbmRleCk7XG5cbiAgICAvLyBQYXJzZSBkaWZmIG1ldGFkYXRhXG4gICAgd2hpbGUgKGkgPCBkaWZmc3RyLmxlbmd0aCkge1xuICAgICAgbGV0IGxpbmUgPSBkaWZmc3RyW2ldO1xuXG4gICAgICAvLyBGaWxlIGhlYWRlciBmb3VuZCwgZW5kIHBhcnNpbmcgZGlmZiBtZXRhZGF0YVxuICAgICAgaWYgKC9eKFxcLVxcLVxcLXxcXCtcXCtcXCt8QEApXFxzLy50ZXN0KGxpbmUpKSB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgICAvLyBEaWZmIGluZGV4XG4gICAgICBsZXQgaGVhZGVyID0gKC9eKD86SW5kZXg6fGRpZmYoPzogLXIgXFx3KykrKVxccysoLis/KVxccyokLykuZXhlYyhsaW5lKTtcbiAgICAgIGlmIChoZWFkZXIpIHtcbiAgICAgICAgaW5kZXguaW5kZXggPSBoZWFkZXJbMV07XG4gICAgICB9XG5cbiAgICAgIGkrKztcbiAgICB9XG5cbiAgICAvLyBQYXJzZSBmaWxlIGhlYWRlcnMgaWYgdGhleSBhcmUgZGVmaW5lZC4gVW5pZmllZCBkaWZmIHJlcXVpcmVzIHRoZW0sIGJ1dFxuICAgIC8vIHRoZXJlJ3Mgbm8gdGVjaG5pY2FsIGlzc3VlcyB0byBoYXZlIGFuIGlzb2xhdGVkIGh1bmsgd2l0aG91dCBmaWxlIGhlYWRlclxuICAgIHBhcnNlRmlsZUhlYWRlcihpbmRleCk7XG4gICAgcGFyc2VGaWxlSGVhZGVyKGluZGV4KTtcblxuICAgIC8vIFBhcnNlIGh1bmtzXG4gICAgaW5kZXguaHVua3MgPSBbXTtcblxuICAgIHdoaWxlIChpIDwgZGlmZnN0ci5sZW5ndGgpIHtcbiAgICAgIGxldCBsaW5lID0gZGlmZnN0cltpXTtcblxuICAgICAgaWYgKC9eKEluZGV4OnxkaWZmfFxcLVxcLVxcLXxcXCtcXCtcXCspXFxzLy50ZXN0KGxpbmUpKSB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfSBlbHNlIGlmICgvXkBALy50ZXN0KGxpbmUpKSB7XG4gICAgICAgIGluZGV4Lmh1bmtzLnB1c2gocGFyc2VIdW5rKCkpO1xuICAgICAgfSBlbHNlIGlmIChsaW5lICYmIG9wdGlvbnMuc3RyaWN0KSB7XG4gICAgICAgIC8vIElnbm9yZSB1bmV4cGVjdGVkIGNvbnRlbnQgdW5sZXNzIGluIHN0cmljdCBtb2RlXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVW5rbm93biBsaW5lICcgKyAoaSArIDEpICsgJyAnICsgSlNPTi5zdHJpbmdpZnkobGluZSkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaSsrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIFBhcnNlcyB0aGUgLS0tIGFuZCArKysgaGVhZGVycywgaWYgbm9uZSBhcmUgZm91bmQsIG5vIGxpbmVzXG4gIC8vIGFyZSBjb25zdW1lZC5cbiAgZnVuY3Rpb24gcGFyc2VGaWxlSGVhZGVyKGluZGV4KSB7XG4gICAgY29uc3QgaGVhZGVyUGF0dGVybiA9IC9eKC0tLXxcXCtcXCtcXCspXFxzKyhbXFxTIF0qKSg/OlxcdCguKj8pXFxzKik/JC87XG4gICAgY29uc3QgZmlsZUhlYWRlciA9IGhlYWRlclBhdHRlcm4uZXhlYyhkaWZmc3RyW2ldKTtcbiAgICBpZiAoZmlsZUhlYWRlcikge1xuICAgICAgbGV0IGtleVByZWZpeCA9IGZpbGVIZWFkZXJbMV0gPT09ICctLS0nID8gJ29sZCcgOiAnbmV3JztcbiAgICAgIGluZGV4W2tleVByZWZpeCArICdGaWxlTmFtZSddID0gZmlsZUhlYWRlclsyXTtcbiAgICAgIGluZGV4W2tleVByZWZpeCArICdIZWFkZXInXSA9IGZpbGVIZWFkZXJbM107XG5cbiAgICAgIGkrKztcbiAgICB9XG4gIH1cblxuICAvLyBQYXJzZXMgYSBodW5rXG4gIC8vIFRoaXMgYXNzdW1lcyB0aGF0IHdlIGFyZSBhdCB0aGUgc3RhcnQgb2YgYSBodW5rLlxuICBmdW5jdGlvbiBwYXJzZUh1bmsoKSB7XG4gICAgbGV0IGNodW5rSGVhZGVySW5kZXggPSBpLFxuICAgICAgICBjaHVua0hlYWRlckxpbmUgPSBkaWZmc3RyW2krK10sXG4gICAgICAgIGNodW5rSGVhZGVyID0gY2h1bmtIZWFkZXJMaW5lLnNwbGl0KC9AQCAtKFxcZCspKD86LChcXGQrKSk/IFxcKyhcXGQrKSg/OiwoXFxkKykpPyBAQC8pO1xuXG4gICAgbGV0IGh1bmsgPSB7XG4gICAgICBvbGRTdGFydDogK2NodW5rSGVhZGVyWzFdLFxuICAgICAgb2xkTGluZXM6ICtjaHVua0hlYWRlclsyXSB8fCAxLFxuICAgICAgbmV3U3RhcnQ6ICtjaHVua0hlYWRlclszXSxcbiAgICAgIG5ld0xpbmVzOiArY2h1bmtIZWFkZXJbNF0gfHwgMSxcbiAgICAgIGxpbmVzOiBbXSxcbiAgICAgIGxpbmVkZWxpbWl0ZXJzOiBbXVxuICAgIH07XG5cbiAgICBsZXQgYWRkQ291bnQgPSAwLFxuICAgICAgICByZW1vdmVDb3VudCA9IDA7XG4gICAgZm9yICg7IGkgPCBkaWZmc3RyLmxlbmd0aDsgaSsrKSB7XG4gICAgICAvLyBMaW5lcyBzdGFydGluZyB3aXRoICctLS0nIGNvdWxkIGJlIG1pc3Rha2VuIGZvciB0aGUgXCJyZW1vdmUgbGluZVwiIG9wZXJhdGlvblxuICAgICAgLy8gQnV0IHRoZXkgY291bGQgYmUgdGhlIGhlYWRlciBmb3IgdGhlIG5leHQgZmlsZS4gVGhlcmVmb3JlIHBydW5lIHN1Y2ggY2FzZXMgb3V0LlxuICAgICAgaWYgKGRpZmZzdHJbaV0uaW5kZXhPZignLS0tICcpID09PSAwXG4gICAgICAgICAgICAmJiAoaSArIDIgPCBkaWZmc3RyLmxlbmd0aClcbiAgICAgICAgICAgICYmIGRpZmZzdHJbaSArIDFdLmluZGV4T2YoJysrKyAnKSA9PT0gMFxuICAgICAgICAgICAgJiYgZGlmZnN0cltpICsgMl0uaW5kZXhPZignQEAnKSA9PT0gMCkge1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgbGV0IG9wZXJhdGlvbiA9IGRpZmZzdHJbaV1bMF07XG5cbiAgICAgIGlmIChvcGVyYXRpb24gPT09ICcrJyB8fCBvcGVyYXRpb24gPT09ICctJyB8fCBvcGVyYXRpb24gPT09ICcgJyB8fCBvcGVyYXRpb24gPT09ICdcXFxcJykge1xuICAgICAgICBodW5rLmxpbmVzLnB1c2goZGlmZnN0cltpXSk7XG4gICAgICAgIGh1bmsubGluZWRlbGltaXRlcnMucHVzaChkZWxpbWl0ZXJzW2ldIHx8ICdcXG4nKTtcblxuICAgICAgICBpZiAob3BlcmF0aW9uID09PSAnKycpIHtcbiAgICAgICAgICBhZGRDb3VudCsrO1xuICAgICAgICB9IGVsc2UgaWYgKG9wZXJhdGlvbiA9PT0gJy0nKSB7XG4gICAgICAgICAgcmVtb3ZlQ291bnQrKztcbiAgICAgICAgfSBlbHNlIGlmIChvcGVyYXRpb24gPT09ICcgJykge1xuICAgICAgICAgIGFkZENvdW50Kys7XG4gICAgICAgICAgcmVtb3ZlQ291bnQrKztcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gSGFuZGxlIHRoZSBlbXB0eSBibG9jayBjb3VudCBjYXNlXG4gICAgaWYgKCFhZGRDb3VudCAmJiBodW5rLm5ld0xpbmVzID09PSAxKSB7XG4gICAgICBodW5rLm5ld0xpbmVzID0gMDtcbiAgICB9XG4gICAgaWYgKCFyZW1vdmVDb3VudCAmJiBodW5rLm9sZExpbmVzID09PSAxKSB7XG4gICAgICBodW5rLm9sZExpbmVzID0gMDtcbiAgICB9XG5cbiAgICAvLyBQZXJmb3JtIG9wdGlvbmFsIHNhbml0eSBjaGVja2luZ1xuICAgIGlmIChvcHRpb25zLnN0cmljdCkge1xuICAgICAgaWYgKGFkZENvdW50ICE9PSBodW5rLm5ld0xpbmVzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignQWRkZWQgbGluZSBjb3VudCBkaWQgbm90IG1hdGNoIGZvciBodW5rIGF0IGxpbmUgJyArIChjaHVua0hlYWRlckluZGV4ICsgMSkpO1xuICAgICAgfVxuICAgICAgaWYgKHJlbW92ZUNvdW50ICE9PSBodW5rLm9sZExpbmVzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignUmVtb3ZlZCBsaW5lIGNvdW50IGRpZCBub3QgbWF0Y2ggZm9yIGh1bmsgYXQgbGluZSAnICsgKGNodW5rSGVhZGVySW5kZXggKyAxKSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGh1bms7XG4gIH1cblxuICB3aGlsZSAoaSA8IGRpZmZzdHIubGVuZ3RoKSB7XG4gICAgcGFyc2VJbmRleCgpO1xuICB9XG5cbiAgcmV0dXJuIGxpc3Q7XG59XG4iLCIvLyBJdGVyYXRvciB0aGF0IHRyYXZlcnNlcyBpbiB0aGUgcmFuZ2Ugb2YgW21pbiwgbWF4XSwgc3RlcHBpbmdcbi8vIGJ5IGRpc3RhbmNlIGZyb20gYSBnaXZlbiBzdGFydCBwb3NpdGlvbi4gSS5lLiBmb3IgWzAsIDRdLCB3aXRoXG4vLyBzdGFydCBvZiAyLCB0aGlzIHdpbGwgaXRlcmF0ZSAyLCAzLCAxLCA0LCAwLlxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24oc3RhcnQsIG1pbkxpbmUsIG1heExpbmUpIHtcbiAgbGV0IHdhbnRGb3J3YXJkID0gdHJ1ZSxcbiAgICAgIGJhY2t3YXJkRXhoYXVzdGVkID0gZmFsc2UsXG4gICAgICBmb3J3YXJkRXhoYXVzdGVkID0gZmFsc2UsXG4gICAgICBsb2NhbE9mZnNldCA9IDE7XG5cbiAgcmV0dXJuIGZ1bmN0aW9uIGl0ZXJhdG9yKCkge1xuICAgIGlmICh3YW50Rm9yd2FyZCAmJiAhZm9yd2FyZEV4aGF1c3RlZCkge1xuICAgICAgaWYgKGJhY2t3YXJkRXhoYXVzdGVkKSB7XG4gICAgICAgIGxvY2FsT2Zmc2V0Kys7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB3YW50Rm9yd2FyZCA9IGZhbHNlO1xuICAgICAgfVxuXG4gICAgICAvLyBDaGVjayBpZiB0cnlpbmcgdG8gZml0IGJleW9uZCB0ZXh0IGxlbmd0aCwgYW5kIGlmIG5vdCwgY2hlY2sgaXQgZml0c1xuICAgICAgLy8gYWZ0ZXIgb2Zmc2V0IGxvY2F0aW9uIChvciBkZXNpcmVkIGxvY2F0aW9uIG9uIGZpcnN0IGl0ZXJhdGlvbilcbiAgICAgIGlmIChzdGFydCArIGxvY2FsT2Zmc2V0IDw9IG1heExpbmUpIHtcbiAgICAgICAgcmV0dXJuIGxvY2FsT2Zmc2V0O1xuICAgICAgfVxuXG4gICAgICBmb3J3YXJkRXhoYXVzdGVkID0gdHJ1ZTtcbiAgICB9XG5cbiAgICBpZiAoIWJhY2t3YXJkRXhoYXVzdGVkKSB7XG4gICAgICBpZiAoIWZvcndhcmRFeGhhdXN0ZWQpIHtcbiAgICAgICAgd2FudEZvcndhcmQgPSB0cnVlO1xuICAgICAgfVxuXG4gICAgICAvLyBDaGVjayBpZiB0cnlpbmcgdG8gZml0IGJlZm9yZSB0ZXh0IGJlZ2lubmluZywgYW5kIGlmIG5vdCwgY2hlY2sgaXQgZml0c1xuICAgICAgLy8gYmVmb3JlIG9mZnNldCBsb2NhdGlvblxuICAgICAgaWYgKG1pbkxpbmUgPD0gc3RhcnQgLSBsb2NhbE9mZnNldCkge1xuICAgICAgICByZXR1cm4gLWxvY2FsT2Zmc2V0Kys7XG4gICAgICB9XG5cbiAgICAgIGJhY2t3YXJkRXhoYXVzdGVkID0gdHJ1ZTtcbiAgICAgIHJldHVybiBpdGVyYXRvcigpO1xuICAgIH1cblxuICAgIC8vIFdlIHRyaWVkIHRvIGZpdCBodW5rIGJlZm9yZSB0ZXh0IGJlZ2lubmluZyBhbmQgYmV5b25kIHRleHQgbGVuZ2h0LCB0aGVuXG4gICAgLy8gaHVuayBjYW4ndCBmaXQgb24gdGhlIHRleHQuIFJldHVybiB1bmRlZmluZWRcbiAgfTtcbn1cbiIsImV4cG9ydCBmdW5jdGlvbiBnZW5lcmF0ZU9wdGlvbnMob3B0aW9ucywgZGVmYXVsdHMpIHtcbiAgaWYgKHR5cGVvZiBvcHRpb25zID09PSAnZnVuY3Rpb24nKSB7XG4gICAgZGVmYXVsdHMuY2FsbGJhY2sgPSBvcHRpb25zO1xuICB9IGVsc2UgaWYgKG9wdGlvbnMpIHtcbiAgICBmb3IgKGxldCBuYW1lIGluIG9wdGlvbnMpIHtcbiAgICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBlbHNlICovXG4gICAgICBpZiAob3B0aW9ucy5oYXNPd25Qcm9wZXJ0eShuYW1lKSkge1xuICAgICAgICBkZWZhdWx0c1tuYW1lXSA9IG9wdGlvbnNbbmFtZV07XG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiBkZWZhdWx0cztcbn1cbiIsIigodHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIGRlZmluZS5hbWQgJiYgZnVuY3Rpb24gKG0pIHtcbiAgICBkZWZpbmUoXCJmb3JtYXRpb1wiLCBbXCJzYW1zYW1cIl0sIG0pO1xufSkgfHwgKHR5cGVvZiBtb2R1bGUgPT09IFwib2JqZWN0XCIgJiYgZnVuY3Rpb24gKG0pIHtcbiAgICBtb2R1bGUuZXhwb3J0cyA9IG0ocmVxdWlyZShcInNhbXNhbVwiKSk7XG59KSB8fCBmdW5jdGlvbiAobSkgeyB0aGlzLmZvcm1hdGlvID0gbSh0aGlzLnNhbXNhbSk7IH1cbikoZnVuY3Rpb24gKHNhbXNhbSkge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgdmFyIGZvcm1hdGlvID0ge1xuICAgICAgICBleGNsdWRlQ29uc3RydWN0b3JzOiBbXCJPYmplY3RcIiwgL14uJC9dLFxuICAgICAgICBxdW90ZVN0cmluZ3M6IHRydWUsXG4gICAgICAgIGxpbWl0Q2hpbGRyZW5Db3VudDogMFxuICAgIH07XG5cbiAgICB2YXIgaGFzT3duID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eTtcblxuICAgIHZhciBzcGVjaWFsT2JqZWN0cyA9IFtdO1xuICAgIGlmICh0eXBlb2YgZ2xvYmFsICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgIHNwZWNpYWxPYmplY3RzLnB1c2goeyBvYmplY3Q6IGdsb2JhbCwgdmFsdWU6IFwiW29iamVjdCBnbG9iYWxdXCIgfSk7XG4gICAgfVxuICAgIGlmICh0eXBlb2YgZG9jdW1lbnQgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgc3BlY2lhbE9iamVjdHMucHVzaCh7XG4gICAgICAgICAgICBvYmplY3Q6IGRvY3VtZW50LFxuICAgICAgICAgICAgdmFsdWU6IFwiW29iamVjdCBIVE1MRG9jdW1lbnRdXCJcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGlmICh0eXBlb2Ygd2luZG93ICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgIHNwZWNpYWxPYmplY3RzLnB1c2goeyBvYmplY3Q6IHdpbmRvdywgdmFsdWU6IFwiW29iamVjdCBXaW5kb3ddXCIgfSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZnVuY3Rpb25OYW1lKGZ1bmMpIHtcbiAgICAgICAgaWYgKCFmdW5jKSB7IHJldHVybiBcIlwiOyB9XG4gICAgICAgIGlmIChmdW5jLmRpc3BsYXlOYW1lKSB7IHJldHVybiBmdW5jLmRpc3BsYXlOYW1lOyB9XG4gICAgICAgIGlmIChmdW5jLm5hbWUpIHsgcmV0dXJuIGZ1bmMubmFtZTsgfVxuICAgICAgICB2YXIgbWF0Y2hlcyA9IGZ1bmMudG9TdHJpbmcoKS5tYXRjaCgvZnVuY3Rpb25cXHMrKFteXFwoXSspL20pO1xuICAgICAgICByZXR1cm4gKG1hdGNoZXMgJiYgbWF0Y2hlc1sxXSkgfHwgXCJcIjtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjb25zdHJ1Y3Rvck5hbWUoZiwgb2JqZWN0KSB7XG4gICAgICAgIHZhciBuYW1lID0gZnVuY3Rpb25OYW1lKG9iamVjdCAmJiBvYmplY3QuY29uc3RydWN0b3IpO1xuICAgICAgICB2YXIgZXhjbHVkZXMgPSBmLmV4Y2x1ZGVDb25zdHJ1Y3RvcnMgfHxcbiAgICAgICAgICAgICAgICBmb3JtYXRpby5leGNsdWRlQ29uc3RydWN0b3JzIHx8IFtdO1xuXG4gICAgICAgIHZhciBpLCBsO1xuICAgICAgICBmb3IgKGkgPSAwLCBsID0gZXhjbHVkZXMubGVuZ3RoOyBpIDwgbDsgKytpKSB7XG4gICAgICAgICAgICBpZiAodHlwZW9mIGV4Y2x1ZGVzW2ldID09PSBcInN0cmluZ1wiICYmIGV4Y2x1ZGVzW2ldID09PSBuYW1lKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFwiXCI7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGV4Y2x1ZGVzW2ldLnRlc3QgJiYgZXhjbHVkZXNbaV0udGVzdChuYW1lKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBcIlwiO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG5hbWU7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gaXNDaXJjdWxhcihvYmplY3QsIG9iamVjdHMpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBvYmplY3QgIT09IFwib2JqZWN0XCIpIHsgcmV0dXJuIGZhbHNlOyB9XG4gICAgICAgIHZhciBpLCBsO1xuICAgICAgICBmb3IgKGkgPSAwLCBsID0gb2JqZWN0cy5sZW5ndGg7IGkgPCBsOyArK2kpIHtcbiAgICAgICAgICAgIGlmIChvYmplY3RzW2ldID09PSBvYmplY3QpIHsgcmV0dXJuIHRydWU7IH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gYXNjaWkoZiwgb2JqZWN0LCBwcm9jZXNzZWQsIGluZGVudCkge1xuICAgICAgICBpZiAodHlwZW9mIG9iamVjdCA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgaWYgKG9iamVjdC5sZW5ndGggPT09IDApIHsgcmV0dXJuIFwiKGVtcHR5IHN0cmluZylcIjsgfVxuICAgICAgICAgICAgdmFyIHFzID0gZi5xdW90ZVN0cmluZ3M7XG4gICAgICAgICAgICB2YXIgcXVvdGUgPSB0eXBlb2YgcXMgIT09IFwiYm9vbGVhblwiIHx8IHFzO1xuICAgICAgICAgICAgcmV0dXJuIHByb2Nlc3NlZCB8fCBxdW90ZSA/ICdcIicgKyBvYmplY3QgKyAnXCInIDogb2JqZWN0O1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBvYmplY3QgPT09IFwiZnVuY3Rpb25cIiAmJiAhKG9iamVjdCBpbnN0YW5jZW9mIFJlZ0V4cCkpIHtcbiAgICAgICAgICAgIHJldHVybiBhc2NpaS5mdW5jKG9iamVjdCk7XG4gICAgICAgIH1cblxuICAgICAgICBwcm9jZXNzZWQgPSBwcm9jZXNzZWQgfHwgW107XG5cbiAgICAgICAgaWYgKGlzQ2lyY3VsYXIob2JqZWN0LCBwcm9jZXNzZWQpKSB7IHJldHVybiBcIltDaXJjdWxhcl1cIjsgfVxuXG4gICAgICAgIGlmIChPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwob2JqZWN0KSA9PT0gXCJbb2JqZWN0IEFycmF5XVwiKSB7XG4gICAgICAgICAgICByZXR1cm4gYXNjaWkuYXJyYXkuY2FsbChmLCBvYmplY3QsIHByb2Nlc3NlZCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIW9iamVjdCkgeyByZXR1cm4gU3RyaW5nKCgxL29iamVjdCkgPT09IC1JbmZpbml0eSA/IFwiLTBcIiA6IG9iamVjdCk7IH1cbiAgICAgICAgaWYgKHNhbXNhbS5pc0VsZW1lbnQob2JqZWN0KSkgeyByZXR1cm4gYXNjaWkuZWxlbWVudChvYmplY3QpOyB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBvYmplY3QudG9TdHJpbmcgPT09IFwiZnVuY3Rpb25cIiAmJlxuICAgICAgICAgICAgICAgIG9iamVjdC50b1N0cmluZyAhPT0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZykge1xuICAgICAgICAgICAgcmV0dXJuIG9iamVjdC50b1N0cmluZygpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGksIGw7XG4gICAgICAgIGZvciAoaSA9IDAsIGwgPSBzcGVjaWFsT2JqZWN0cy5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgICAgIGlmIChvYmplY3QgPT09IHNwZWNpYWxPYmplY3RzW2ldLm9iamVjdCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBzcGVjaWFsT2JqZWN0c1tpXS52YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgU2V0ICE9PSAndW5kZWZpbmVkJyAmJiBvYmplY3QgaW5zdGFuY2VvZiBTZXQpIHtcbiAgICAgICAgICAgIHJldHVybiBhc2NpaS5zZXQuY2FsbChmLCBvYmplY3QsIHByb2Nlc3NlZCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gYXNjaWkub2JqZWN0LmNhbGwoZiwgb2JqZWN0LCBwcm9jZXNzZWQsIGluZGVudCk7XG4gICAgfVxuXG4gICAgYXNjaWkuZnVuYyA9IGZ1bmN0aW9uIChmdW5jKSB7XG4gICAgICAgIHJldHVybiBcImZ1bmN0aW9uIFwiICsgZnVuY3Rpb25OYW1lKGZ1bmMpICsgXCIoKSB7fVwiO1xuICAgIH07XG5cbiAgICBmdW5jdGlvbiBkZWxpbWl0KHN0ciwgZGVsaW1pdGVycykge1xuICAgICAgICBkZWxpbWl0ZXJzID0gZGVsaW1pdGVycyB8fCBbXCJbXCIsIFwiXVwiXTtcbiAgICAgICAgcmV0dXJuIGRlbGltaXRlcnNbMF0gKyBzdHIgKyBkZWxpbWl0ZXJzWzFdO1xuICAgIH1cblxuICAgIGFzY2lpLmFycmF5ID0gZnVuY3Rpb24gKGFycmF5LCBwcm9jZXNzZWQsIGRlbGltaXRlcnMpIHtcbiAgICAgICAgcHJvY2Vzc2VkID0gcHJvY2Vzc2VkIHx8IFtdO1xuICAgICAgICBwcm9jZXNzZWQucHVzaChhcnJheSk7XG4gICAgICAgIHZhciBwaWVjZXMgPSBbXTtcbiAgICAgICAgdmFyIGksIGw7XG4gICAgICAgIGwgPSAodGhpcy5saW1pdENoaWxkcmVuQ291bnQgPiAwKSA/IFxuICAgICAgICAgICAgTWF0aC5taW4odGhpcy5saW1pdENoaWxkcmVuQ291bnQsIGFycmF5Lmxlbmd0aCkgOiBhcnJheS5sZW5ndGg7XG5cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGw7ICsraSkge1xuICAgICAgICAgICAgcGllY2VzLnB1c2goYXNjaWkodGhpcywgYXJyYXlbaV0sIHByb2Nlc3NlZCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGwgPCBhcnJheS5sZW5ndGgpIHtcbiAgICAgICAgICAgIHBpZWNlcy5wdXNoKFwiWy4uLiBcIiArIChhcnJheS5sZW5ndGggLSBsKSArIFwiIG1vcmUgZWxlbWVudHNdXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGRlbGltaXQocGllY2VzLmpvaW4oXCIsIFwiKSwgZGVsaW1pdGVycyk7XG4gICAgfTtcblxuICAgIGFzY2lpLnNldCA9IGZ1bmN0aW9uIChzZXQsIHByb2Nlc3NlZCkge1xuICAgICAgICByZXR1cm4gYXNjaWkuYXJyYXkuY2FsbCh0aGlzLCBBcnJheS5mcm9tKHNldCksIHByb2Nlc3NlZCwgWydTZXQgeycsICd9J10pO1xuICAgIH07XG5cbiAgICBhc2NpaS5vYmplY3QgPSBmdW5jdGlvbiAob2JqZWN0LCBwcm9jZXNzZWQsIGluZGVudCkge1xuICAgICAgICBwcm9jZXNzZWQgPSBwcm9jZXNzZWQgfHwgW107XG4gICAgICAgIHByb2Nlc3NlZC5wdXNoKG9iamVjdCk7XG4gICAgICAgIGluZGVudCA9IGluZGVudCB8fCAwO1xuICAgICAgICB2YXIgcGllY2VzID0gW10sIHByb3BlcnRpZXMgPSBzYW1zYW0ua2V5cyhvYmplY3QpLnNvcnQoKTtcbiAgICAgICAgdmFyIGxlbmd0aCA9IDM7XG4gICAgICAgIHZhciBwcm9wLCBzdHIsIG9iaiwgaSwgaywgbDtcbiAgICAgICAgbCA9ICh0aGlzLmxpbWl0Q2hpbGRyZW5Db3VudCA+IDApID8gXG4gICAgICAgICAgICBNYXRoLm1pbih0aGlzLmxpbWl0Q2hpbGRyZW5Db3VudCwgcHJvcGVydGllcy5sZW5ndGgpIDogcHJvcGVydGllcy5sZW5ndGg7XG5cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGw7ICsraSkge1xuICAgICAgICAgICAgcHJvcCA9IHByb3BlcnRpZXNbaV07XG4gICAgICAgICAgICBvYmogPSBvYmplY3RbcHJvcF07XG5cbiAgICAgICAgICAgIGlmIChpc0NpcmN1bGFyKG9iaiwgcHJvY2Vzc2VkKSkge1xuICAgICAgICAgICAgICAgIHN0ciA9IFwiW0NpcmN1bGFyXVwiO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzdHIgPSBhc2NpaSh0aGlzLCBvYmosIHByb2Nlc3NlZCwgaW5kZW50ICsgMik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHN0ciA9ICgvXFxzLy50ZXN0KHByb3ApID8gJ1wiJyArIHByb3AgKyAnXCInIDogcHJvcCkgKyBcIjogXCIgKyBzdHI7XG4gICAgICAgICAgICBsZW5ndGggKz0gc3RyLmxlbmd0aDtcbiAgICAgICAgICAgIHBpZWNlcy5wdXNoKHN0cik7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgY29ucyA9IGNvbnN0cnVjdG9yTmFtZSh0aGlzLCBvYmplY3QpO1xuICAgICAgICB2YXIgcHJlZml4ID0gY29ucyA/IFwiW1wiICsgY29ucyArIFwiXSBcIiA6IFwiXCI7XG4gICAgICAgIHZhciBpcyA9IFwiXCI7XG4gICAgICAgIGZvciAoaSA9IDAsIGsgPSBpbmRlbnQ7IGkgPCBrOyArK2kpIHsgaXMgKz0gXCIgXCI7IH1cblxuICAgICAgICBpZihsIDwgcHJvcGVydGllcy5sZW5ndGgpXG4gICAgICAgICAgICBwaWVjZXMucHVzaChcIlsuLi4gXCIgKyAocHJvcGVydGllcy5sZW5ndGggLSBsKSArIFwiIG1vcmUgZWxlbWVudHNdXCIpO1xuXG4gICAgICAgIGlmIChsZW5ndGggKyBpbmRlbnQgPiA4MCkge1xuICAgICAgICAgICAgcmV0dXJuIHByZWZpeCArIFwie1xcbiAgXCIgKyBpcyArIHBpZWNlcy5qb2luKFwiLFxcbiAgXCIgKyBpcykgKyBcIlxcblwiICtcbiAgICAgICAgICAgICAgICBpcyArIFwifVwiO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBwcmVmaXggKyBcInsgXCIgKyBwaWVjZXMuam9pbihcIiwgXCIpICsgXCIgfVwiO1xuICAgIH07XG5cbiAgICBhc2NpaS5lbGVtZW50ID0gZnVuY3Rpb24gKGVsZW1lbnQpIHtcbiAgICAgICAgdmFyIHRhZ05hbWUgPSBlbGVtZW50LnRhZ05hbWUudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgdmFyIGF0dHJzID0gZWxlbWVudC5hdHRyaWJ1dGVzLCBhdHRyLCBwYWlycyA9IFtdLCBhdHRyTmFtZSwgaSwgbCwgdmFsO1xuXG4gICAgICAgIGZvciAoaSA9IDAsIGwgPSBhdHRycy5sZW5ndGg7IGkgPCBsOyArK2kpIHtcbiAgICAgICAgICAgIGF0dHIgPSBhdHRycy5pdGVtKGkpO1xuICAgICAgICAgICAgYXR0ck5hbWUgPSBhdHRyLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkucmVwbGFjZShcImh0bWw6XCIsIFwiXCIpO1xuICAgICAgICAgICAgdmFsID0gYXR0ci5ub2RlVmFsdWU7XG4gICAgICAgICAgICBpZiAoYXR0ck5hbWUgIT09IFwiY29udGVudGVkaXRhYmxlXCIgfHwgdmFsICE9PSBcImluaGVyaXRcIikge1xuICAgICAgICAgICAgICAgIGlmICghIXZhbCkgeyBwYWlycy5wdXNoKGF0dHJOYW1lICsgXCI9XFxcIlwiICsgdmFsICsgXCJcXFwiXCIpOyB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgZm9ybWF0dGVkID0gXCI8XCIgKyB0YWdOYW1lICsgKHBhaXJzLmxlbmd0aCA+IDAgPyBcIiBcIiA6IFwiXCIpO1xuICAgICAgICAvLyBTVkcgZWxlbWVudHMgaGF2ZSB1bmRlZmluZWQgaW5uZXJIVE1MXG4gICAgICAgIHZhciBjb250ZW50ID0gZWxlbWVudC5pbm5lckhUTUwgfHwgJyc7XG5cbiAgICAgICAgaWYgKGNvbnRlbnQubGVuZ3RoID4gMjApIHtcbiAgICAgICAgICAgIGNvbnRlbnQgPSBjb250ZW50LnN1YnN0cigwLCAyMCkgKyBcIlsuLi5dXCI7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgcmVzID0gZm9ybWF0dGVkICsgcGFpcnMuam9pbihcIiBcIikgKyBcIj5cIiArIGNvbnRlbnQgK1xuICAgICAgICAgICAgICAgIFwiPC9cIiArIHRhZ05hbWUgKyBcIj5cIjtcblxuICAgICAgICByZXR1cm4gcmVzLnJlcGxhY2UoLyBjb250ZW50RWRpdGFibGU9XCJpbmhlcml0XCIvLCBcIlwiKTtcbiAgICB9O1xuXG4gICAgZnVuY3Rpb24gRm9ybWF0aW8ob3B0aW9ucykge1xuICAgICAgICBmb3IgKHZhciBvcHQgaW4gb3B0aW9ucykge1xuICAgICAgICAgICAgdGhpc1tvcHRdID0gb3B0aW9uc1tvcHRdO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgRm9ybWF0aW8ucHJvdG90eXBlID0ge1xuICAgICAgICBmdW5jdGlvbk5hbWU6IGZ1bmN0aW9uTmFtZSxcblxuICAgICAgICBjb25maWd1cmU6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IEZvcm1hdGlvKG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGNvbnN0cnVjdG9yTmFtZTogZnVuY3Rpb24gKG9iamVjdCkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbnN0cnVjdG9yTmFtZSh0aGlzLCBvYmplY3QpO1xuICAgICAgICB9LFxuXG4gICAgICAgIGFzY2lpOiBmdW5jdGlvbiAob2JqZWN0LCBwcm9jZXNzZWQsIGluZGVudCkge1xuICAgICAgICAgICAgcmV0dXJuIGFzY2lpKHRoaXMsIG9iamVjdCwgcHJvY2Vzc2VkLCBpbmRlbnQpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHJldHVybiBGb3JtYXRpby5wcm90b3R5cGU7XG59KTtcbiIsIm1vZHVsZS5leHBvcnRzID0gQXJyYXkuaXNBcnJheSB8fCBmdW5jdGlvbiAoYXJyKSB7XG4gIHJldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoYXJyKSA9PSAnW29iamVjdCBBcnJheV0nO1xufTtcbiIsIlwidXNlIHN0cmljdFwiO1xuXG52YXIgdXNlckFnZW50ID0gZ2xvYmFsLm5hdmlnYXRvciAmJiBnbG9iYWwubmF2aWdhdG9yLnVzZXJBZ2VudDtcbnZhciBpc1J1bm5pbmdJbklFID0gdXNlckFnZW50ICYmIHVzZXJBZ2VudC5pbmRleE9mKFwiTVNJRSBcIikgPiAtMTtcblxuLy8gTWFrZSBwcm9wZXJ0aWVzIHdyaXRhYmxlIGluIElFLCBhcyBwZXJcbi8vIGh0dHA6Ly93d3cuYWRlcXVhdGVseWdvb2QuY29tL1JlcGxhY2luZy1zZXRUaW1lb3V0LUdsb2JhbGx5Lmh0bWxcbmlmIChpc1J1bm5pbmdJbklFKSB7XG4gICAgZ2xvYmFsLnNldFRpbWVvdXQgPSBnbG9iYWwuc2V0VGltZW91dDtcbiAgICBnbG9iYWwuY2xlYXJUaW1lb3V0ID0gZ2xvYmFsLmNsZWFyVGltZW91dDtcbiAgICBnbG9iYWwuc2V0SW50ZXJ2YWwgPSBnbG9iYWwuc2V0SW50ZXJ2YWw7XG4gICAgZ2xvYmFsLmNsZWFySW50ZXJ2YWwgPSBnbG9iYWwuY2xlYXJJbnRlcnZhbDtcbiAgICBnbG9iYWwuRGF0ZSA9IGdsb2JhbC5EYXRlO1xufVxuXG4vLyBzZXRJbW1lZGlhdGUgaXMgbm90IGEgc3RhbmRhcmQgZnVuY3Rpb25cbi8vIGF2b2lkIGFkZGluZyB0aGUgcHJvcCB0byB0aGUgd2luZG93IG9iamVjdCBpZiBub3QgcHJlc2VudFxuaWYgKGdsb2JhbC5zZXRJbW1lZGlhdGUgIT09IHVuZGVmaW5lZCkge1xuICAgIGdsb2JhbC5zZXRJbW1lZGlhdGUgPSBnbG9iYWwuc2V0SW1tZWRpYXRlO1xuICAgIGdsb2JhbC5jbGVhckltbWVkaWF0ZSA9IGdsb2JhbC5jbGVhckltbWVkaWF0ZTtcbn1cblxuLy8gbm9kZSBleHBlY3RzIHNldFRpbWVvdXQvc2V0SW50ZXJ2YWwgdG8gcmV0dXJuIGEgZm4gb2JqZWN0IHcvIC5yZWYoKS8udW5yZWYoKVxuLy8gYnJvd3NlcnMsIGEgbnVtYmVyLlxuLy8gc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9jam9oYW5zZW4vU2lub24uSlMvcHVsbC80MzZcblxudmFyIE5PT1AgPSBmdW5jdGlvbiAoKSB7IHJldHVybiB1bmRlZmluZWQ7IH07XG52YXIgdGltZW91dFJlc3VsdCA9IHNldFRpbWVvdXQoTk9PUCwgMCk7XG52YXIgYWRkVGltZXJSZXR1cm5zT2JqZWN0ID0gdHlwZW9mIHRpbWVvdXRSZXN1bHQgPT09IFwib2JqZWN0XCI7XG52YXIgaHJ0aW1lUHJlc2VudCA9IChnbG9iYWwucHJvY2VzcyAmJiB0eXBlb2YgZ2xvYmFsLnByb2Nlc3MuaHJ0aW1lID09PSBcImZ1bmN0aW9uXCIpO1xuY2xlYXJUaW1lb3V0KHRpbWVvdXRSZXN1bHQpO1xuXG52YXIgTmF0aXZlRGF0ZSA9IERhdGU7XG52YXIgdW5pcXVlVGltZXJJZCA9IDE7XG5cbi8qKlxuICogUGFyc2Ugc3RyaW5ncyBsaWtlIFwiMDE6MTA6MDBcIiAobWVhbmluZyAxIGhvdXIsIDEwIG1pbnV0ZXMsIDAgc2Vjb25kcykgaW50b1xuICogbnVtYmVyIG9mIG1pbGxpc2Vjb25kcy4gVGhpcyBpcyB1c2VkIHRvIHN1cHBvcnQgaHVtYW4tcmVhZGFibGUgc3RyaW5ncyBwYXNzZWRcbiAqIHRvIGNsb2NrLnRpY2soKVxuICovXG5mdW5jdGlvbiBwYXJzZVRpbWUoc3RyKSB7XG4gICAgaWYgKCFzdHIpIHtcbiAgICAgICAgcmV0dXJuIDA7XG4gICAgfVxuXG4gICAgdmFyIHN0cmluZ3MgPSBzdHIuc3BsaXQoXCI6XCIpO1xuICAgIHZhciBsID0gc3RyaW5ncy5sZW5ndGg7XG4gICAgdmFyIGkgPSBsO1xuICAgIHZhciBtcyA9IDA7XG4gICAgdmFyIHBhcnNlZDtcblxuICAgIGlmIChsID4gMyB8fCAhL14oXFxkXFxkOil7MCwyfVxcZFxcZD8kLy50ZXN0KHN0cikpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwidGljayBvbmx5IHVuZGVyc3RhbmRzIG51bWJlcnMsICdtOnMnIGFuZCAnaDptOnMnLiBFYWNoIHBhcnQgbXVzdCBiZSB0d28gZGlnaXRzXCIpO1xuICAgIH1cblxuICAgIHdoaWxlIChpLS0pIHtcbiAgICAgICAgcGFyc2VkID0gcGFyc2VJbnQoc3RyaW5nc1tpXSwgMTApO1xuXG4gICAgICAgIGlmIChwYXJzZWQgPj0gNjApIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkludmFsaWQgdGltZSBcIiArIHN0cik7XG4gICAgICAgIH1cblxuICAgICAgICBtcyArPSBwYXJzZWQgKiBNYXRoLnBvdyg2MCwgKGwgLSBpIC0gMSkpO1xuICAgIH1cblxuICAgIHJldHVybiBtcyAqIDEwMDA7XG59XG5cbi8qKlxuICogRmxvb3IgZnVuY3Rpb24gdGhhdCBhbHNvIHdvcmtzIGZvciBuZWdhdGl2ZSBudW1iZXJzXG4gKi9cbmZ1bmN0aW9uIGZpeGVkRmxvb3Iobikge1xuICAgIHJldHVybiAobiA+PSAwID8gTWF0aC5mbG9vcihuKSA6IE1hdGguY2VpbChuKSk7XG59XG5cbi8qKlxuICogJSBvcGVyYXRvciB0aGF0IGFsc28gd29ya3MgZm9yIG5lZ2F0aXZlIG51bWJlcnNcbiAqL1xuZnVuY3Rpb24gZml4ZWRNb2R1bG8obiwgbSkge1xuICAgIHJldHVybiAoKG4gJSBtKSArIG0pICUgbTtcbn1cblxuLyoqXG4gKiBVc2VkIHRvIGdyb2sgdGhlIGBub3dgIHBhcmFtZXRlciB0byBjcmVhdGVDbG9jay5cbiAqL1xuZnVuY3Rpb24gZ2V0RXBvY2goZXBvY2gpIHtcbiAgICBpZiAoIWVwb2NoKSB7IHJldHVybiAwOyB9XG4gICAgaWYgKHR5cGVvZiBlcG9jaC5nZXRUaW1lID09PSBcImZ1bmN0aW9uXCIpIHsgcmV0dXJuIGVwb2NoLmdldFRpbWUoKTsgfVxuICAgIGlmICh0eXBlb2YgZXBvY2ggPT09IFwibnVtYmVyXCIpIHsgcmV0dXJuIGVwb2NoOyB9XG4gICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIm5vdyBzaG91bGQgYmUgbWlsbGlzZWNvbmRzIHNpbmNlIFVOSVggZXBvY2hcIik7XG59XG5cbmZ1bmN0aW9uIGluUmFuZ2UoZnJvbSwgdG8sIHRpbWVyKSB7XG4gICAgcmV0dXJuIHRpbWVyICYmIHRpbWVyLmNhbGxBdCA+PSBmcm9tICYmIHRpbWVyLmNhbGxBdCA8PSB0bztcbn1cblxuZnVuY3Rpb24gbWlycm9yRGF0ZVByb3BlcnRpZXModGFyZ2V0LCBzb3VyY2UpIHtcbiAgICB2YXIgcHJvcDtcbiAgICBmb3IgKHByb3AgaW4gc291cmNlKSB7XG4gICAgICAgIGlmIChzb3VyY2UuaGFzT3duUHJvcGVydHkocHJvcCkpIHtcbiAgICAgICAgICAgIHRhcmdldFtwcm9wXSA9IHNvdXJjZVtwcm9wXTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIHNldCBzcGVjaWFsIG5vdyBpbXBsZW1lbnRhdGlvblxuICAgIGlmIChzb3VyY2Uubm93KSB7XG4gICAgICAgIHRhcmdldC5ub3cgPSBmdW5jdGlvbiBub3coKSB7XG4gICAgICAgICAgICByZXR1cm4gdGFyZ2V0LmNsb2NrLm5vdztcbiAgICAgICAgfTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBkZWxldGUgdGFyZ2V0Lm5vdztcbiAgICB9XG5cbiAgICAvLyBzZXQgc3BlY2lhbCB0b1NvdXJjZSBpbXBsZW1lbnRhdGlvblxuICAgIGlmIChzb3VyY2UudG9Tb3VyY2UpIHtcbiAgICAgICAgdGFyZ2V0LnRvU291cmNlID0gZnVuY3Rpb24gdG9Tb3VyY2UoKSB7XG4gICAgICAgICAgICByZXR1cm4gc291cmNlLnRvU291cmNlKCk7XG4gICAgICAgIH07XG4gICAgfSBlbHNlIHtcbiAgICAgICAgZGVsZXRlIHRhcmdldC50b1NvdXJjZTtcbiAgICB9XG5cbiAgICAvLyBzZXQgc3BlY2lhbCB0b1N0cmluZyBpbXBsZW1lbnRhdGlvblxuICAgIHRhcmdldC50b1N0cmluZyA9IGZ1bmN0aW9uIHRvU3RyaW5nKCkge1xuICAgICAgICByZXR1cm4gc291cmNlLnRvU3RyaW5nKCk7XG4gICAgfTtcblxuICAgIHRhcmdldC5wcm90b3R5cGUgPSBzb3VyY2UucHJvdG90eXBlO1xuICAgIHRhcmdldC5wYXJzZSA9IHNvdXJjZS5wYXJzZTtcbiAgICB0YXJnZXQuVVRDID0gc291cmNlLlVUQztcbiAgICB0YXJnZXQucHJvdG90eXBlLnRvVVRDU3RyaW5nID0gc291cmNlLnByb3RvdHlwZS50b1VUQ1N0cmluZztcblxuICAgIHJldHVybiB0YXJnZXQ7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZURhdGUoKSB7XG4gICAgZnVuY3Rpb24gQ2xvY2tEYXRlKHllYXIsIG1vbnRoLCBkYXRlLCBob3VyLCBtaW51dGUsIHNlY29uZCwgbXMpIHtcbiAgICAgICAgLy8gRGVmZW5zaXZlIGFuZCB2ZXJib3NlIHRvIGF2b2lkIHBvdGVudGlhbCBoYXJtIGluIHBhc3NpbmdcbiAgICAgICAgLy8gZXhwbGljaXQgdW5kZWZpbmVkIHdoZW4gdXNlciBkb2VzIG5vdCBwYXNzIGFyZ3VtZW50XG4gICAgICAgIHN3aXRjaCAoYXJndW1lbnRzLmxlbmd0aCkge1xuICAgICAgICAgICAgY2FzZSAwOlxuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgTmF0aXZlRGF0ZShDbG9ja0RhdGUuY2xvY2subm93KTtcbiAgICAgICAgICAgIGNhc2UgMTpcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IE5hdGl2ZURhdGUoeWVhcik7XG4gICAgICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBOYXRpdmVEYXRlKHllYXIsIG1vbnRoKTtcbiAgICAgICAgICAgIGNhc2UgMzpcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IE5hdGl2ZURhdGUoeWVhciwgbW9udGgsIGRhdGUpO1xuICAgICAgICAgICAgY2FzZSA0OlxuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgTmF0aXZlRGF0ZSh5ZWFyLCBtb250aCwgZGF0ZSwgaG91cik7XG4gICAgICAgICAgICBjYXNlIDU6XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBOYXRpdmVEYXRlKHllYXIsIG1vbnRoLCBkYXRlLCBob3VyLCBtaW51dGUpO1xuICAgICAgICAgICAgY2FzZSA2OlxuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgTmF0aXZlRGF0ZSh5ZWFyLCBtb250aCwgZGF0ZSwgaG91ciwgbWludXRlLCBzZWNvbmQpO1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IE5hdGl2ZURhdGUoeWVhciwgbW9udGgsIGRhdGUsIGhvdXIsIG1pbnV0ZSwgc2Vjb25kLCBtcyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gbWlycm9yRGF0ZVByb3BlcnRpZXMoQ2xvY2tEYXRlLCBOYXRpdmVEYXRlKTtcbn1cblxuZnVuY3Rpb24gYWRkVGltZXIoY2xvY2ssIHRpbWVyKSB7XG4gICAgaWYgKHRpbWVyLmZ1bmMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYWxsYmFjayBtdXN0IGJlIHByb3ZpZGVkIHRvIHRpbWVyIGNhbGxzXCIpO1xuICAgIH1cblxuICAgIGlmICghY2xvY2sudGltZXJzKSB7XG4gICAgICAgIGNsb2NrLnRpbWVycyA9IHt9O1xuICAgIH1cblxuICAgIHRpbWVyLmlkID0gdW5pcXVlVGltZXJJZCsrO1xuICAgIHRpbWVyLmNyZWF0ZWRBdCA9IGNsb2NrLm5vdztcbiAgICB0aW1lci5jYWxsQXQgPSBjbG9jay5ub3cgKyAocGFyc2VJbnQodGltZXIuZGVsYXkpIHx8IChjbG9jay5kdXJpbmdUaWNrID8gMSA6IDApKTtcblxuICAgIGNsb2NrLnRpbWVyc1t0aW1lci5pZF0gPSB0aW1lcjtcblxuICAgIGlmIChhZGRUaW1lclJldHVybnNPYmplY3QpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGlkOiB0aW1lci5pZCxcbiAgICAgICAgICAgIHJlZjogTk9PUCxcbiAgICAgICAgICAgIHVucmVmOiBOT09QXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcmV0dXJuIHRpbWVyLmlkO1xufVxuXG5cbi8qIGVzbGludCBjb25zaXN0ZW50LXJldHVybjogXCJvZmZcIiAqL1xuZnVuY3Rpb24gY29tcGFyZVRpbWVycyhhLCBiKSB7XG4gICAgLy8gU29ydCBmaXJzdCBieSBhYnNvbHV0ZSB0aW1pbmdcbiAgICBpZiAoYS5jYWxsQXQgPCBiLmNhbGxBdCkge1xuICAgICAgICByZXR1cm4gLTE7XG4gICAgfVxuICAgIGlmIChhLmNhbGxBdCA+IGIuY2FsbEF0KSB7XG4gICAgICAgIHJldHVybiAxO1xuICAgIH1cblxuICAgIC8vIFNvcnQgbmV4dCBieSBpbW1lZGlhdGUsIGltbWVkaWF0ZSB0aW1lcnMgdGFrZSBwcmVjZWRlbmNlXG4gICAgaWYgKGEuaW1tZWRpYXRlICYmICFiLmltbWVkaWF0ZSkge1xuICAgICAgICByZXR1cm4gLTE7XG4gICAgfVxuICAgIGlmICghYS5pbW1lZGlhdGUgJiYgYi5pbW1lZGlhdGUpIHtcbiAgICAgICAgcmV0dXJuIDE7XG4gICAgfVxuXG4gICAgLy8gU29ydCBuZXh0IGJ5IGNyZWF0aW9uIHRpbWUsIGVhcmxpZXItY3JlYXRlZCB0aW1lcnMgdGFrZSBwcmVjZWRlbmNlXG4gICAgaWYgKGEuY3JlYXRlZEF0IDwgYi5jcmVhdGVkQXQpIHtcbiAgICAgICAgcmV0dXJuIC0xO1xuICAgIH1cbiAgICBpZiAoYS5jcmVhdGVkQXQgPiBiLmNyZWF0ZWRBdCkge1xuICAgICAgICByZXR1cm4gMTtcbiAgICB9XG5cbiAgICAvLyBTb3J0IG5leHQgYnkgaWQsIGxvd2VyLWlkIHRpbWVycyB0YWtlIHByZWNlZGVuY2VcbiAgICBpZiAoYS5pZCA8IGIuaWQpIHtcbiAgICAgICAgcmV0dXJuIC0xO1xuICAgIH1cbiAgICBpZiAoYS5pZCA+IGIuaWQpIHtcbiAgICAgICAgcmV0dXJuIDE7XG4gICAgfVxuXG4gICAgLy8gQXMgdGltZXIgaWRzIGFyZSB1bmlxdWUsIG5vIGZhbGxiYWNrIGAwYCBpcyBuZWNlc3Nhcnlcbn1cblxuZnVuY3Rpb24gZmlyc3RUaW1lckluUmFuZ2UoY2xvY2ssIGZyb20sIHRvKSB7XG4gICAgdmFyIHRpbWVycyA9IGNsb2NrLnRpbWVycztcbiAgICB2YXIgdGltZXIgPSBudWxsO1xuICAgIHZhciBpZCwgaXNJblJhbmdlO1xuXG4gICAgZm9yIChpZCBpbiB0aW1lcnMpIHtcbiAgICAgICAgaWYgKHRpbWVycy5oYXNPd25Qcm9wZXJ0eShpZCkpIHtcbiAgICAgICAgICAgIGlzSW5SYW5nZSA9IGluUmFuZ2UoZnJvbSwgdG8sIHRpbWVyc1tpZF0pO1xuXG4gICAgICAgICAgICBpZiAoaXNJblJhbmdlICYmICghdGltZXIgfHwgY29tcGFyZVRpbWVycyh0aW1lciwgdGltZXJzW2lkXSkgPT09IDEpKSB7XG4gICAgICAgICAgICAgICAgdGltZXIgPSB0aW1lcnNbaWRdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRpbWVyO1xufVxuXG5mdW5jdGlvbiBmaXJzdFRpbWVyKGNsb2NrKSB7XG4gICAgdmFyIHRpbWVycyA9IGNsb2NrLnRpbWVycztcbiAgICB2YXIgdGltZXIgPSBudWxsO1xuICAgIHZhciBpZDtcblxuICAgIGZvciAoaWQgaW4gdGltZXJzKSB7XG4gICAgICAgIGlmICh0aW1lcnMuaGFzT3duUHJvcGVydHkoaWQpKSB7XG4gICAgICAgICAgICBpZiAoIXRpbWVyIHx8IGNvbXBhcmVUaW1lcnModGltZXIsIHRpbWVyc1tpZF0pID09PSAxKSB7XG4gICAgICAgICAgICAgICAgdGltZXIgPSB0aW1lcnNbaWRdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRpbWVyO1xufVxuXG5mdW5jdGlvbiBsYXN0VGltZXIoY2xvY2spIHtcbiAgICB2YXIgdGltZXJzID0gY2xvY2sudGltZXJzO1xuICAgIHZhciB0aW1lciA9IG51bGw7XG4gICAgdmFyIGlkO1xuXG4gICAgZm9yIChpZCBpbiB0aW1lcnMpIHtcbiAgICAgICAgaWYgKHRpbWVycy5oYXNPd25Qcm9wZXJ0eShpZCkpIHtcbiAgICAgICAgICAgIGlmICghdGltZXIgfHwgY29tcGFyZVRpbWVycyh0aW1lciwgdGltZXJzW2lkXSkgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgdGltZXIgPSB0aW1lcnNbaWRdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRpbWVyO1xufVxuXG5mdW5jdGlvbiBjYWxsVGltZXIoY2xvY2ssIHRpbWVyKSB7XG4gICAgdmFyIGV4Y2VwdGlvbjtcblxuICAgIGlmICh0eXBlb2YgdGltZXIuaW50ZXJ2YWwgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgY2xvY2sudGltZXJzW3RpbWVyLmlkXS5jYWxsQXQgKz0gdGltZXIuaW50ZXJ2YWw7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgZGVsZXRlIGNsb2NrLnRpbWVyc1t0aW1lci5pZF07XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgICAgaWYgKHR5cGVvZiB0aW1lci5mdW5jID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgIHRpbWVyLmZ1bmMuYXBwbHkobnVsbCwgdGltZXIuYXJncyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvKiBlc2xpbnQgbm8tZXZhbDogXCJvZmZcIiAqL1xuICAgICAgICAgICAgZXZhbCh0aW1lci5mdW5jKTtcbiAgICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgZXhjZXB0aW9uID0gZTtcbiAgICB9XG5cbiAgICBpZiAoIWNsb2NrLnRpbWVyc1t0aW1lci5pZF0pIHtcbiAgICAgICAgaWYgKGV4Y2VwdGlvbikge1xuICAgICAgICAgICAgdGhyb3cgZXhjZXB0aW9uO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoZXhjZXB0aW9uKSB7XG4gICAgICAgIHRocm93IGV4Y2VwdGlvbjtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIHRpbWVyVHlwZSh0aW1lcikge1xuICAgIGlmICh0aW1lci5pbW1lZGlhdGUpIHtcbiAgICAgICAgcmV0dXJuIFwiSW1tZWRpYXRlXCI7XG4gICAgfVxuICAgIGlmICh0aW1lci5pbnRlcnZhbCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiBcIkludGVydmFsXCI7XG4gICAgfVxuICAgIHJldHVybiBcIlRpbWVvdXRcIjtcbn1cblxuZnVuY3Rpb24gY2xlYXJUaW1lcihjbG9jaywgdGltZXJJZCwgdHR5cGUpIHtcbiAgICBpZiAoIXRpbWVySWQpIHtcbiAgICAgICAgLy8gbnVsbCBhcHBlYXJzIHRvIGJlIGFsbG93ZWQgaW4gbW9zdCBicm93c2VycywgYW5kIGFwcGVhcnMgdG8gYmVcbiAgICAgICAgLy8gcmVsaWVkIHVwb24gYnkgc29tZSBsaWJyYXJpZXMsIGxpa2UgQm9vdHN0cmFwIGNhcm91c2VsXG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoIWNsb2NrLnRpbWVycykge1xuICAgICAgICBjbG9jay50aW1lcnMgPSBbXTtcbiAgICB9XG5cbiAgICAvLyBpbiBOb2RlLCB0aW1lcklkIGlzIGFuIG9iamVjdCB3aXRoIC5yZWYoKS8udW5yZWYoKSwgYW5kXG4gICAgLy8gaXRzIC5pZCBmaWVsZCBpcyB0aGUgYWN0dWFsIHRpbWVyIGlkLlxuICAgIGlmICh0eXBlb2YgdGltZXJJZCA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICB0aW1lcklkID0gdGltZXJJZC5pZDtcbiAgICB9XG5cbiAgICBpZiAoY2xvY2sudGltZXJzLmhhc093blByb3BlcnR5KHRpbWVySWQpKSB7XG4gICAgICAgIC8vIGNoZWNrIHRoYXQgdGhlIElEIG1hdGNoZXMgYSB0aW1lciBvZiB0aGUgY29ycmVjdCB0eXBlXG4gICAgICAgIHZhciB0aW1lciA9IGNsb2NrLnRpbWVyc1t0aW1lcklkXTtcbiAgICAgICAgaWYgKHRpbWVyVHlwZSh0aW1lcikgPT09IHR0eXBlKSB7XG4gICAgICAgICAgICBkZWxldGUgY2xvY2sudGltZXJzW3RpbWVySWRdO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ2Fubm90IGNsZWFyIHRpbWVyOiB0aW1lciBjcmVhdGVkIHdpdGggc2V0XCIgKyB0aW1lclR5cGUodGltZXIpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKyBcIigpIGJ1dCBjbGVhcmVkIHdpdGggY2xlYXJcIiArIHR0eXBlICsgXCIoKVwiKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuZnVuY3Rpb24gdW5pbnN0YWxsKGNsb2NrLCB0YXJnZXQpIHtcbiAgICB2YXIgbWV0aG9kLFxuICAgICAgICBpLFxuICAgICAgICBsO1xuICAgIHZhciBpbnN0YWxsZWRIclRpbWUgPSBcIl9ocnRpbWVcIjtcblxuICAgIGZvciAoaSA9IDAsIGwgPSBjbG9jay5tZXRob2RzLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgICBtZXRob2QgPSBjbG9jay5tZXRob2RzW2ldO1xuICAgICAgICBpZiAobWV0aG9kID09PSBcImhydGltZVwiICYmIHRhcmdldC5wcm9jZXNzKSB7XG4gICAgICAgICAgICB0YXJnZXQucHJvY2Vzcy5ocnRpbWUgPSBjbG9ja1tpbnN0YWxsZWRIclRpbWVdO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKHRhcmdldFttZXRob2RdICYmIHRhcmdldFttZXRob2RdLmhhZE93blByb3BlcnR5KSB7XG4gICAgICAgICAgICAgICAgdGFyZ2V0W21ldGhvZF0gPSBjbG9ja1tcIl9cIiArIG1ldGhvZF07XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB0YXJnZXRbbWV0aG9kXTtcbiAgICAgICAgICAgICAgICB9IGNhdGNoIChpZ25vcmUpIHsgLyogZXNsaW50IGVtcHR5LWJsb2NrOiBcIm9mZlwiICovIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIFByZXZlbnQgbXVsdGlwbGUgZXhlY3V0aW9ucyB3aGljaCB3aWxsIGNvbXBsZXRlbHkgcmVtb3ZlIHRoZXNlIHByb3BzXG4gICAgY2xvY2subWV0aG9kcyA9IFtdO1xufVxuXG5mdW5jdGlvbiBoaWphY2tNZXRob2QodGFyZ2V0LCBtZXRob2QsIGNsb2NrKSB7XG4gICAgdmFyIHByb3A7XG5cbiAgICBjbG9ja1ttZXRob2RdLmhhZE93blByb3BlcnR5ID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHRhcmdldCwgbWV0aG9kKTtcbiAgICBjbG9ja1tcIl9cIiArIG1ldGhvZF0gPSB0YXJnZXRbbWV0aG9kXTtcblxuICAgIGlmIChtZXRob2QgPT09IFwiRGF0ZVwiKSB7XG4gICAgICAgIHZhciBkYXRlID0gbWlycm9yRGF0ZVByb3BlcnRpZXMoY2xvY2tbbWV0aG9kXSwgdGFyZ2V0W21ldGhvZF0pO1xuICAgICAgICB0YXJnZXRbbWV0aG9kXSA9IGRhdGU7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGFyZ2V0W21ldGhvZF0gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gY2xvY2tbbWV0aG9kXS5hcHBseShjbG9jaywgYXJndW1lbnRzKTtcbiAgICAgICAgfTtcblxuICAgICAgICBmb3IgKHByb3AgaW4gY2xvY2tbbWV0aG9kXSkge1xuICAgICAgICAgICAgaWYgKGNsb2NrW21ldGhvZF0uaGFzT3duUHJvcGVydHkocHJvcCkpIHtcbiAgICAgICAgICAgICAgICB0YXJnZXRbbWV0aG9kXVtwcm9wXSA9IGNsb2NrW21ldGhvZF1bcHJvcF07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICB0YXJnZXRbbWV0aG9kXS5jbG9jayA9IGNsb2NrO1xufVxuXG52YXIgdGltZXJzID0ge1xuICAgIHNldFRpbWVvdXQ6IHNldFRpbWVvdXQsXG4gICAgY2xlYXJUaW1lb3V0OiBjbGVhclRpbWVvdXQsXG4gICAgc2V0SW1tZWRpYXRlOiBnbG9iYWwuc2V0SW1tZWRpYXRlLFxuICAgIGNsZWFySW1tZWRpYXRlOiBnbG9iYWwuY2xlYXJJbW1lZGlhdGUsXG4gICAgc2V0SW50ZXJ2YWw6IHNldEludGVydmFsLFxuICAgIGNsZWFySW50ZXJ2YWw6IGNsZWFySW50ZXJ2YWwsXG4gICAgRGF0ZTogRGF0ZVxufTtcblxuaWYgKGhydGltZVByZXNlbnQpIHtcbiAgICB0aW1lcnMuaHJ0aW1lID0gZ2xvYmFsLnByb2Nlc3MuaHJ0aW1lO1xufVxuXG52YXIga2V5cyA9IE9iamVjdC5rZXlzIHx8IGZ1bmN0aW9uIChvYmopIHtcbiAgICB2YXIga3MgPSBbXTtcbiAgICB2YXIga2V5O1xuXG4gICAgZm9yIChrZXkgaW4gb2JqKSB7XG4gICAgICAgIGlmIChvYmouaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgICAgICAga3MucHVzaChrZXkpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGtzO1xufTtcblxuZXhwb3J0cy50aW1lcnMgPSB0aW1lcnM7XG5cbmZ1bmN0aW9uIGNyZWF0ZUNsb2NrKG5vdywgbG9vcExpbWl0KSB7XG4gICAgbG9vcExpbWl0ID0gbG9vcExpbWl0IHx8IDEwMDA7XG5cbiAgICB2YXIgY2xvY2sgPSB7XG4gICAgICAgIG5vdzogZ2V0RXBvY2gobm93KSxcbiAgICAgICAgaHJOb3c6IDAsXG4gICAgICAgIHRpbWVvdXRzOiB7fSxcbiAgICAgICAgRGF0ZTogY3JlYXRlRGF0ZSgpLFxuICAgICAgICBsb29wTGltaXQ6IGxvb3BMaW1pdFxuICAgIH07XG5cbiAgICBjbG9jay5EYXRlLmNsb2NrID0gY2xvY2s7XG5cbiAgICBjbG9jay5zZXRUaW1lb3V0ID0gZnVuY3Rpb24gc2V0VGltZW91dChmdW5jLCB0aW1lb3V0KSB7XG4gICAgICAgIHJldHVybiBhZGRUaW1lcihjbG9jaywge1xuICAgICAgICAgICAgZnVuYzogZnVuYyxcbiAgICAgICAgICAgIGFyZ3M6IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMiksXG4gICAgICAgICAgICBkZWxheTogdGltZW91dFxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgY2xvY2suY2xlYXJUaW1lb3V0ID0gZnVuY3Rpb24gY2xlYXJUaW1lb3V0KHRpbWVySWQpIHtcbiAgICAgICAgcmV0dXJuIGNsZWFyVGltZXIoY2xvY2ssIHRpbWVySWQsIFwiVGltZW91dFwiKTtcbiAgICB9O1xuXG4gICAgY2xvY2suc2V0SW50ZXJ2YWwgPSBmdW5jdGlvbiBzZXRJbnRlcnZhbChmdW5jLCB0aW1lb3V0KSB7XG4gICAgICAgIHJldHVybiBhZGRUaW1lcihjbG9jaywge1xuICAgICAgICAgICAgZnVuYzogZnVuYyxcbiAgICAgICAgICAgIGFyZ3M6IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMiksXG4gICAgICAgICAgICBkZWxheTogdGltZW91dCxcbiAgICAgICAgICAgIGludGVydmFsOiB0aW1lb3V0XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICBjbG9jay5jbGVhckludGVydmFsID0gZnVuY3Rpb24gY2xlYXJJbnRlcnZhbCh0aW1lcklkKSB7XG4gICAgICAgIHJldHVybiBjbGVhclRpbWVyKGNsb2NrLCB0aW1lcklkLCBcIkludGVydmFsXCIpO1xuICAgIH07XG5cbiAgICBjbG9jay5zZXRJbW1lZGlhdGUgPSBmdW5jdGlvbiBzZXRJbW1lZGlhdGUoZnVuYykge1xuICAgICAgICByZXR1cm4gYWRkVGltZXIoY2xvY2ssIHtcbiAgICAgICAgICAgIGZ1bmM6IGZ1bmMsXG4gICAgICAgICAgICBhcmdzOiBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpLFxuICAgICAgICAgICAgaW1tZWRpYXRlOiB0cnVlXG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICBjbG9jay5jbGVhckltbWVkaWF0ZSA9IGZ1bmN0aW9uIGNsZWFySW1tZWRpYXRlKHRpbWVySWQpIHtcbiAgICAgICAgcmV0dXJuIGNsZWFyVGltZXIoY2xvY2ssIHRpbWVySWQsIFwiSW1tZWRpYXRlXCIpO1xuICAgIH07XG5cbiAgICBjbG9jay50aWNrID0gZnVuY3Rpb24gdGljayhtcykge1xuICAgICAgICBtcyA9IHR5cGVvZiBtcyA9PT0gXCJudW1iZXJcIiA/IG1zIDogcGFyc2VUaW1lKG1zKTtcbiAgICAgICAgdmFyIHRpY2tGcm9tID0gY2xvY2subm93O1xuICAgICAgICB2YXIgdGlja1RvID0gY2xvY2subm93ICsgbXM7XG4gICAgICAgIHZhciBwcmV2aW91cyA9IGNsb2NrLm5vdztcbiAgICAgICAgdmFyIHRpbWVyID0gZmlyc3RUaW1lckluUmFuZ2UoY2xvY2ssIHRpY2tGcm9tLCB0aWNrVG8pO1xuICAgICAgICB2YXIgb2xkTm93LCBmaXJzdEV4Y2VwdGlvbjtcblxuICAgICAgICBjbG9jay5kdXJpbmdUaWNrID0gdHJ1ZTtcblxuICAgICAgICBmdW5jdGlvbiB1cGRhdGVIclRpbWUobmV3Tm93KSB7XG4gICAgICAgICAgICBjbG9jay5ock5vdyArPSAobmV3Tm93IC0gY2xvY2subm93KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHdoaWxlICh0aW1lciAmJiB0aWNrRnJvbSA8PSB0aWNrVG8pIHtcbiAgICAgICAgICAgIGlmIChjbG9jay50aW1lcnNbdGltZXIuaWRdKSB7XG4gICAgICAgICAgICAgICAgdXBkYXRlSHJUaW1lKHRpbWVyLmNhbGxBdCk7XG4gICAgICAgICAgICAgICAgdGlja0Zyb20gPSB0aW1lci5jYWxsQXQ7XG4gICAgICAgICAgICAgICAgY2xvY2subm93ID0gdGltZXIuY2FsbEF0O1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIG9sZE5vdyA9IGNsb2NrLm5vdztcbiAgICAgICAgICAgICAgICAgICAgY2FsbFRpbWVyKGNsb2NrLCB0aW1lcik7XG4gICAgICAgICAgICAgICAgICAgIC8vIGNvbXBlbnNhdGUgZm9yIGFueSBzZXRTeXN0ZW1UaW1lKCkgY2FsbCBkdXJpbmcgdGltZXIgY2FsbGJhY2tcbiAgICAgICAgICAgICAgICAgICAgaWYgKG9sZE5vdyAhPT0gY2xvY2subm93KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aWNrRnJvbSArPSBjbG9jay5ub3cgLSBvbGROb3c7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aWNrVG8gKz0gY2xvY2subm93IC0gb2xkTm93O1xuICAgICAgICAgICAgICAgICAgICAgICAgcHJldmlvdXMgKz0gY2xvY2subm93IC0gb2xkTm93O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICBmaXJzdEV4Y2VwdGlvbiA9IGZpcnN0RXhjZXB0aW9uIHx8IGU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB0aW1lciA9IGZpcnN0VGltZXJJblJhbmdlKGNsb2NrLCBwcmV2aW91cywgdGlja1RvKTtcbiAgICAgICAgICAgIHByZXZpb3VzID0gdGlja0Zyb207XG4gICAgICAgIH1cblxuICAgICAgICBjbG9jay5kdXJpbmdUaWNrID0gZmFsc2U7XG4gICAgICAgIHVwZGF0ZUhyVGltZSh0aWNrVG8pO1xuICAgICAgICBjbG9jay5ub3cgPSB0aWNrVG87XG5cbiAgICAgICAgaWYgKGZpcnN0RXhjZXB0aW9uKSB7XG4gICAgICAgICAgICB0aHJvdyBmaXJzdEV4Y2VwdGlvbjtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBjbG9jay5ub3c7XG4gICAgfTtcblxuICAgIGNsb2NrLm5leHQgPSBmdW5jdGlvbiBuZXh0KCkge1xuICAgICAgICB2YXIgdGltZXIgPSBmaXJzdFRpbWVyKGNsb2NrKTtcbiAgICAgICAgaWYgKCF0aW1lcikge1xuICAgICAgICAgICAgcmV0dXJuIGNsb2NrLm5vdztcbiAgICAgICAgfVxuXG4gICAgICAgIGNsb2NrLmR1cmluZ1RpY2sgPSB0cnVlO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgY2xvY2subm93ID0gdGltZXIuY2FsbEF0O1xuICAgICAgICAgICAgY2FsbFRpbWVyKGNsb2NrLCB0aW1lcik7XG4gICAgICAgICAgICByZXR1cm4gY2xvY2subm93O1xuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgICAgY2xvY2suZHVyaW5nVGljayA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIGNsb2NrLnJ1bkFsbCA9IGZ1bmN0aW9uIHJ1bkFsbCgpIHtcbiAgICAgICAgdmFyIG51bVRpbWVycywgaTtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGNsb2NrLmxvb3BMaW1pdDsgaSsrKSB7XG4gICAgICAgICAgICBpZiAoIWNsb2NrLnRpbWVycykge1xuICAgICAgICAgICAgICAgIHJldHVybiBjbG9jay5ub3c7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG51bVRpbWVycyA9IE9iamVjdC5rZXlzKGNsb2NrLnRpbWVycykubGVuZ3RoO1xuICAgICAgICAgICAgaWYgKG51bVRpbWVycyA9PT0gMCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBjbG9jay5ub3c7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNsb2NrLm5leHQoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIkFib3J0aW5nIGFmdGVyIHJ1bm5pbmcgXCIgKyBjbG9jay5sb29wTGltaXQgKyBcIiB0aW1lcnMsIGFzc3VtaW5nIGFuIGluZmluaXRlIGxvb3AhXCIpO1xuICAgIH07XG5cbiAgICBjbG9jay5ydW5Ub0xhc3QgPSBmdW5jdGlvbiBydW5Ub0xhc3QoKSB7XG4gICAgICAgIHZhciB0aW1lciA9IGxhc3RUaW1lcihjbG9jayk7XG4gICAgICAgIGlmICghdGltZXIpIHtcbiAgICAgICAgICAgIHJldHVybiBjbG9jay5ub3c7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gY2xvY2sudGljayh0aW1lci5jYWxsQXQpO1xuICAgIH07XG5cbiAgICBjbG9jay5yZXNldCA9IGZ1bmN0aW9uIHJlc2V0KCkge1xuICAgICAgICBjbG9jay50aW1lcnMgPSB7fTtcbiAgICB9O1xuXG4gICAgY2xvY2suc2V0U3lzdGVtVGltZSA9IGZ1bmN0aW9uIHNldFN5c3RlbVRpbWUoc3lzdGVtVGltZSkge1xuICAgICAgICAvLyBkZXRlcm1pbmUgdGltZSBkaWZmZXJlbmNlXG4gICAgICAgIHZhciBuZXdOb3cgPSBnZXRFcG9jaChzeXN0ZW1UaW1lKTtcbiAgICAgICAgdmFyIGRpZmZlcmVuY2UgPSBuZXdOb3cgLSBjbG9jay5ub3c7XG4gICAgICAgIHZhciBpZCwgdGltZXI7XG5cbiAgICAgICAgLy8gdXBkYXRlICdzeXN0ZW0gY2xvY2snXG4gICAgICAgIGNsb2NrLm5vdyA9IG5ld05vdztcblxuICAgICAgICAvLyB1cGRhdGUgdGltZXJzIGFuZCBpbnRlcnZhbHMgdG8ga2VlcCB0aGVtIHN0YWJsZVxuICAgICAgICBmb3IgKGlkIGluIGNsb2NrLnRpbWVycykge1xuICAgICAgICAgICAgaWYgKGNsb2NrLnRpbWVycy5oYXNPd25Qcm9wZXJ0eShpZCkpIHtcbiAgICAgICAgICAgICAgICB0aW1lciA9IGNsb2NrLnRpbWVyc1tpZF07XG4gICAgICAgICAgICAgICAgdGltZXIuY3JlYXRlZEF0ICs9IGRpZmZlcmVuY2U7XG4gICAgICAgICAgICAgICAgdGltZXIuY2FsbEF0ICs9IGRpZmZlcmVuY2U7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgaWYgKGhydGltZVByZXNlbnQpIHtcbiAgICAgICAgY2xvY2suaHJ0aW1lID0gZnVuY3Rpb24gKHByZXYpIHtcbiAgICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KHByZXYpKSB7XG4gICAgICAgICAgICAgICAgdmFyIG9sZFNlY3MgPSAocHJldlswXSArIHByZXZbMV0gLyAxZTkpO1xuICAgICAgICAgICAgICAgIHZhciBuZXdTZWNzID0gKGNsb2NrLmhyTm93IC8gMTAwMCk7XG4gICAgICAgICAgICAgICAgdmFyIGRpZmZlcmVuY2UgPSAobmV3U2VjcyAtIG9sZFNlY3MpO1xuICAgICAgICAgICAgICAgIHZhciBzZWNzID0gZml4ZWRGbG9vcihkaWZmZXJlbmNlKTtcbiAgICAgICAgICAgICAgICB2YXIgbmFub3NlY3MgPSBmaXhlZE1vZHVsbyhkaWZmZXJlbmNlICogMWU5LCAxZTkpO1xuICAgICAgICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAgICAgICAgIHNlY3MsXG4gICAgICAgICAgICAgICAgICAgIG5hbm9zZWNzXG4gICAgICAgICAgICAgICAgXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAgICAgZml4ZWRGbG9vcihjbG9jay5ock5vdyAvIDEwMDApLFxuICAgICAgICAgICAgICAgIGZpeGVkTW9kdWxvKGNsb2NrLmhyTm93ICogMWU2LCAxZTkpXG4gICAgICAgICAgICBdO1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiBjbG9jaztcbn1cbmV4cG9ydHMuY3JlYXRlQ2xvY2sgPSBjcmVhdGVDbG9jaztcblxuZXhwb3J0cy5pbnN0YWxsID0gZnVuY3Rpb24gaW5zdGFsbCh0YXJnZXQsIG5vdywgdG9GYWtlLCBsb29wTGltaXQpIHtcbiAgICB2YXIgaSwgbDtcblxuICAgIGlmICh0YXJnZXQgaW5zdGFuY2VvZiBEYXRlKSB7XG4gICAgICAgIHRvRmFrZSA9IG5vdztcbiAgICAgICAgbm93ID0gdGFyZ2V0LmdldFRpbWUoKTtcbiAgICAgICAgdGFyZ2V0ID0gbnVsbDtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIHRhcmdldCA9PT0gXCJudW1iZXJcIikge1xuICAgICAgICB0b0Zha2UgPSBub3c7XG4gICAgICAgIG5vdyA9IHRhcmdldDtcbiAgICAgICAgdGFyZ2V0ID0gbnVsbDtcbiAgICB9XG5cbiAgICBpZiAoIXRhcmdldCkge1xuICAgICAgICB0YXJnZXQgPSBnbG9iYWw7XG4gICAgfVxuXG4gICAgdmFyIGNsb2NrID0gY3JlYXRlQ2xvY2sobm93LCBsb29wTGltaXQpO1xuXG4gICAgY2xvY2sudW5pbnN0YWxsID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB1bmluc3RhbGwoY2xvY2ssIHRhcmdldCk7XG4gICAgfTtcblxuICAgIGNsb2NrLm1ldGhvZHMgPSB0b0Zha2UgfHwgW107XG5cbiAgICBpZiAoY2xvY2subWV0aG9kcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgY2xvY2subWV0aG9kcyA9IGtleXModGltZXJzKTtcbiAgICB9XG5cbiAgICBmb3IgKGkgPSAwLCBsID0gY2xvY2subWV0aG9kcy5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgaWYgKGNsb2NrLm1ldGhvZHNbaV0gPT09IFwiaHJ0aW1lXCIpIHtcbiAgICAgICAgICAgIGlmICh0YXJnZXQucHJvY2VzcyAmJiB0eXBlb2YgdGFyZ2V0LnByb2Nlc3MuaHJ0aW1lID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICBoaWphY2tNZXRob2QodGFyZ2V0LnByb2Nlc3MsIGNsb2NrLm1ldGhvZHNbaV0sIGNsb2NrKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGhpamFja01ldGhvZCh0YXJnZXQsIGNsb2NrLm1ldGhvZHNbaV0sIGNsb2NrKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBjbG9jaztcbn07XG4iLCJ2YXIgaXNhcnJheSA9IHJlcXVpcmUoJ2lzYXJyYXknKVxuXG4vKipcbiAqIEV4cG9zZSBgcGF0aFRvUmVnZXhwYC5cbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBwYXRoVG9SZWdleHBcbm1vZHVsZS5leHBvcnRzLnBhcnNlID0gcGFyc2Vcbm1vZHVsZS5leHBvcnRzLmNvbXBpbGUgPSBjb21waWxlXG5tb2R1bGUuZXhwb3J0cy50b2tlbnNUb0Z1bmN0aW9uID0gdG9rZW5zVG9GdW5jdGlvblxubW9kdWxlLmV4cG9ydHMudG9rZW5zVG9SZWdFeHAgPSB0b2tlbnNUb1JlZ0V4cFxuXG4vKipcbiAqIFRoZSBtYWluIHBhdGggbWF0Y2hpbmcgcmVnZXhwIHV0aWxpdHkuXG4gKlxuICogQHR5cGUge1JlZ0V4cH1cbiAqL1xudmFyIFBBVEhfUkVHRVhQID0gbmV3IFJlZ0V4cChbXG4gIC8vIE1hdGNoIGVzY2FwZWQgY2hhcmFjdGVycyB0aGF0IHdvdWxkIG90aGVyd2lzZSBhcHBlYXIgaW4gZnV0dXJlIG1hdGNoZXMuXG4gIC8vIFRoaXMgYWxsb3dzIHRoZSB1c2VyIHRvIGVzY2FwZSBzcGVjaWFsIGNoYXJhY3RlcnMgdGhhdCB3b24ndCB0cmFuc2Zvcm0uXG4gICcoXFxcXFxcXFwuKScsXG4gIC8vIE1hdGNoIEV4cHJlc3Mtc3R5bGUgcGFyYW1ldGVycyBhbmQgdW4tbmFtZWQgcGFyYW1ldGVycyB3aXRoIGEgcHJlZml4XG4gIC8vIGFuZCBvcHRpb25hbCBzdWZmaXhlcy4gTWF0Y2hlcyBhcHBlYXIgYXM6XG4gIC8vXG4gIC8vIFwiLzp0ZXN0KFxcXFxkKyk/XCIgPT4gW1wiL1wiLCBcInRlc3RcIiwgXCJcXGQrXCIsIHVuZGVmaW5lZCwgXCI/XCIsIHVuZGVmaW5lZF1cbiAgLy8gXCIvcm91dGUoXFxcXGQrKVwiICA9PiBbdW5kZWZpbmVkLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgXCJcXGQrXCIsIHVuZGVmaW5lZCwgdW5kZWZpbmVkXVxuICAvLyBcIi8qXCIgICAgICAgICAgICA9PiBbXCIvXCIsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgXCIqXCJdXG4gICcoW1xcXFwvLl0pPyg/Oig/OlxcXFw6KFxcXFx3KykoPzpcXFxcKCgoPzpcXFxcXFxcXC58W15cXFxcXFxcXCgpXSkrKVxcXFwpKT98XFxcXCgoKD86XFxcXFxcXFwufFteXFxcXFxcXFwoKV0pKylcXFxcKSkoWysqP10pP3woXFxcXCopKSdcbl0uam9pbignfCcpLCAnZycpXG5cbi8qKlxuICogUGFyc2UgYSBzdHJpbmcgZm9yIHRoZSByYXcgdG9rZW5zLlxuICpcbiAqIEBwYXJhbSAge3N0cmluZ30gIHN0clxuICogQHBhcmFtICB7T2JqZWN0PX0gb3B0aW9uc1xuICogQHJldHVybiB7IUFycmF5fVxuICovXG5mdW5jdGlvbiBwYXJzZSAoc3RyLCBvcHRpb25zKSB7XG4gIHZhciB0b2tlbnMgPSBbXVxuICB2YXIga2V5ID0gMFxuICB2YXIgaW5kZXggPSAwXG4gIHZhciBwYXRoID0gJydcbiAgdmFyIGRlZmF1bHREZWxpbWl0ZXIgPSBvcHRpb25zICYmIG9wdGlvbnMuZGVsaW1pdGVyIHx8ICcvJ1xuICB2YXIgcmVzXG5cbiAgd2hpbGUgKChyZXMgPSBQQVRIX1JFR0VYUC5leGVjKHN0cikpICE9IG51bGwpIHtcbiAgICB2YXIgbSA9IHJlc1swXVxuICAgIHZhciBlc2NhcGVkID0gcmVzWzFdXG4gICAgdmFyIG9mZnNldCA9IHJlcy5pbmRleFxuICAgIHBhdGggKz0gc3RyLnNsaWNlKGluZGV4LCBvZmZzZXQpXG4gICAgaW5kZXggPSBvZmZzZXQgKyBtLmxlbmd0aFxuXG4gICAgLy8gSWdub3JlIGFscmVhZHkgZXNjYXBlZCBzZXF1ZW5jZXMuXG4gICAgaWYgKGVzY2FwZWQpIHtcbiAgICAgIHBhdGggKz0gZXNjYXBlZFsxXVxuICAgICAgY29udGludWVcbiAgICB9XG5cbiAgICB2YXIgbmV4dCA9IHN0cltpbmRleF1cbiAgICB2YXIgcHJlZml4ID0gcmVzWzJdXG4gICAgdmFyIG5hbWUgPSByZXNbM11cbiAgICB2YXIgY2FwdHVyZSA9IHJlc1s0XVxuICAgIHZhciBncm91cCA9IHJlc1s1XVxuICAgIHZhciBtb2RpZmllciA9IHJlc1s2XVxuICAgIHZhciBhc3RlcmlzayA9IHJlc1s3XVxuXG4gICAgLy8gUHVzaCB0aGUgY3VycmVudCBwYXRoIG9udG8gdGhlIHRva2Vucy5cbiAgICBpZiAocGF0aCkge1xuICAgICAgdG9rZW5zLnB1c2gocGF0aClcbiAgICAgIHBhdGggPSAnJ1xuICAgIH1cblxuICAgIHZhciBwYXJ0aWFsID0gcHJlZml4ICE9IG51bGwgJiYgbmV4dCAhPSBudWxsICYmIG5leHQgIT09IHByZWZpeFxuICAgIHZhciByZXBlYXQgPSBtb2RpZmllciA9PT0gJysnIHx8IG1vZGlmaWVyID09PSAnKidcbiAgICB2YXIgb3B0aW9uYWwgPSBtb2RpZmllciA9PT0gJz8nIHx8IG1vZGlmaWVyID09PSAnKidcbiAgICB2YXIgZGVsaW1pdGVyID0gcmVzWzJdIHx8IGRlZmF1bHREZWxpbWl0ZXJcbiAgICB2YXIgcGF0dGVybiA9IGNhcHR1cmUgfHwgZ3JvdXBcblxuICAgIHRva2Vucy5wdXNoKHtcbiAgICAgIG5hbWU6IG5hbWUgfHwga2V5KyssXG4gICAgICBwcmVmaXg6IHByZWZpeCB8fCAnJyxcbiAgICAgIGRlbGltaXRlcjogZGVsaW1pdGVyLFxuICAgICAgb3B0aW9uYWw6IG9wdGlvbmFsLFxuICAgICAgcmVwZWF0OiByZXBlYXQsXG4gICAgICBwYXJ0aWFsOiBwYXJ0aWFsLFxuICAgICAgYXN0ZXJpc2s6ICEhYXN0ZXJpc2ssXG4gICAgICBwYXR0ZXJuOiBwYXR0ZXJuID8gZXNjYXBlR3JvdXAocGF0dGVybikgOiAoYXN0ZXJpc2sgPyAnLionIDogJ1teJyArIGVzY2FwZVN0cmluZyhkZWxpbWl0ZXIpICsgJ10rPycpXG4gICAgfSlcbiAgfVxuXG4gIC8vIE1hdGNoIGFueSBjaGFyYWN0ZXJzIHN0aWxsIHJlbWFpbmluZy5cbiAgaWYgKGluZGV4IDwgc3RyLmxlbmd0aCkge1xuICAgIHBhdGggKz0gc3RyLnN1YnN0cihpbmRleClcbiAgfVxuXG4gIC8vIElmIHRoZSBwYXRoIGV4aXN0cywgcHVzaCBpdCBvbnRvIHRoZSBlbmQuXG4gIGlmIChwYXRoKSB7XG4gICAgdG9rZW5zLnB1c2gocGF0aClcbiAgfVxuXG4gIHJldHVybiB0b2tlbnNcbn1cblxuLyoqXG4gKiBDb21waWxlIGEgc3RyaW5nIHRvIGEgdGVtcGxhdGUgZnVuY3Rpb24gZm9yIHRoZSBwYXRoLlxuICpcbiAqIEBwYXJhbSAge3N0cmluZ30gICAgICAgICAgICAgc3RyXG4gKiBAcGFyYW0gIHtPYmplY3Q9fSAgICAgICAgICAgIG9wdGlvbnNcbiAqIEByZXR1cm4geyFmdW5jdGlvbihPYmplY3Q9LCBPYmplY3Q9KX1cbiAqL1xuZnVuY3Rpb24gY29tcGlsZSAoc3RyLCBvcHRpb25zKSB7XG4gIHJldHVybiB0b2tlbnNUb0Z1bmN0aW9uKHBhcnNlKHN0ciwgb3B0aW9ucykpXG59XG5cbi8qKlxuICogUHJldHRpZXIgZW5jb2Rpbmcgb2YgVVJJIHBhdGggc2VnbWVudHMuXG4gKlxuICogQHBhcmFtICB7c3RyaW5nfVxuICogQHJldHVybiB7c3RyaW5nfVxuICovXG5mdW5jdGlvbiBlbmNvZGVVUklDb21wb25lbnRQcmV0dHkgKHN0cikge1xuICByZXR1cm4gZW5jb2RlVVJJKHN0cikucmVwbGFjZSgvW1xcLz8jXS9nLCBmdW5jdGlvbiAoYykge1xuICAgIHJldHVybiAnJScgKyBjLmNoYXJDb2RlQXQoMCkudG9TdHJpbmcoMTYpLnRvVXBwZXJDYXNlKClcbiAgfSlcbn1cblxuLyoqXG4gKiBFbmNvZGUgdGhlIGFzdGVyaXNrIHBhcmFtZXRlci4gU2ltaWxhciB0byBgcHJldHR5YCwgYnV0IGFsbG93cyBzbGFzaGVzLlxuICpcbiAqIEBwYXJhbSAge3N0cmluZ31cbiAqIEByZXR1cm4ge3N0cmluZ31cbiAqL1xuZnVuY3Rpb24gZW5jb2RlQXN0ZXJpc2sgKHN0cikge1xuICByZXR1cm4gZW5jb2RlVVJJKHN0cikucmVwbGFjZSgvWz8jXS9nLCBmdW5jdGlvbiAoYykge1xuICAgIHJldHVybiAnJScgKyBjLmNoYXJDb2RlQXQoMCkudG9TdHJpbmcoMTYpLnRvVXBwZXJDYXNlKClcbiAgfSlcbn1cblxuLyoqXG4gKiBFeHBvc2UgYSBtZXRob2QgZm9yIHRyYW5zZm9ybWluZyB0b2tlbnMgaW50byB0aGUgcGF0aCBmdW5jdGlvbi5cbiAqL1xuZnVuY3Rpb24gdG9rZW5zVG9GdW5jdGlvbiAodG9rZW5zKSB7XG4gIC8vIENvbXBpbGUgYWxsIHRoZSB0b2tlbnMgaW50byByZWdleHBzLlxuICB2YXIgbWF0Y2hlcyA9IG5ldyBBcnJheSh0b2tlbnMubGVuZ3RoKVxuXG4gIC8vIENvbXBpbGUgYWxsIHRoZSBwYXR0ZXJucyBiZWZvcmUgY29tcGlsYXRpb24uXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgdG9rZW5zLmxlbmd0aDsgaSsrKSB7XG4gICAgaWYgKHR5cGVvZiB0b2tlbnNbaV0gPT09ICdvYmplY3QnKSB7XG4gICAgICBtYXRjaGVzW2ldID0gbmV3IFJlZ0V4cCgnXig/OicgKyB0b2tlbnNbaV0ucGF0dGVybiArICcpJCcpXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGZ1bmN0aW9uIChvYmosIG9wdHMpIHtcbiAgICB2YXIgcGF0aCA9ICcnXG4gICAgdmFyIGRhdGEgPSBvYmogfHwge31cbiAgICB2YXIgb3B0aW9ucyA9IG9wdHMgfHwge31cbiAgICB2YXIgZW5jb2RlID0gb3B0aW9ucy5wcmV0dHkgPyBlbmNvZGVVUklDb21wb25lbnRQcmV0dHkgOiBlbmNvZGVVUklDb21wb25lbnRcblxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdG9rZW5zLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgdG9rZW4gPSB0b2tlbnNbaV1cblxuICAgICAgaWYgKHR5cGVvZiB0b2tlbiA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgcGF0aCArPSB0b2tlblxuXG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIHZhciB2YWx1ZSA9IGRhdGFbdG9rZW4ubmFtZV1cbiAgICAgIHZhciBzZWdtZW50XG5cbiAgICAgIGlmICh2YWx1ZSA9PSBudWxsKSB7XG4gICAgICAgIGlmICh0b2tlbi5vcHRpb25hbCkge1xuICAgICAgICAgIC8vIFByZXBlbmQgcGFydGlhbCBzZWdtZW50IHByZWZpeGVzLlxuICAgICAgICAgIGlmICh0b2tlbi5wYXJ0aWFsKSB7XG4gICAgICAgICAgICBwYXRoICs9IHRva2VuLnByZWZpeFxuICAgICAgICAgIH1cblxuICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignRXhwZWN0ZWQgXCInICsgdG9rZW4ubmFtZSArICdcIiB0byBiZSBkZWZpbmVkJylcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoaXNhcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgaWYgKCF0b2tlbi5yZXBlYXQpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdFeHBlY3RlZCBcIicgKyB0b2tlbi5uYW1lICsgJ1wiIHRvIG5vdCByZXBlYXQsIGJ1dCByZWNlaXZlZCBgJyArIEpTT04uc3RyaW5naWZ5KHZhbHVlKSArICdgJylcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh2YWx1ZS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICBpZiAodG9rZW4ub3B0aW9uYWwpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlXG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0V4cGVjdGVkIFwiJyArIHRva2VuLm5hbWUgKyAnXCIgdG8gbm90IGJlIGVtcHR5JylcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHZhbHVlLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgc2VnbWVudCA9IGVuY29kZSh2YWx1ZVtqXSlcblxuICAgICAgICAgIGlmICghbWF0Y2hlc1tpXS50ZXN0KHNlZ21lbnQpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdFeHBlY3RlZCBhbGwgXCInICsgdG9rZW4ubmFtZSArICdcIiB0byBtYXRjaCBcIicgKyB0b2tlbi5wYXR0ZXJuICsgJ1wiLCBidXQgcmVjZWl2ZWQgYCcgKyBKU09OLnN0cmluZ2lmeShzZWdtZW50KSArICdgJylcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBwYXRoICs9IChqID09PSAwID8gdG9rZW4ucHJlZml4IDogdG9rZW4uZGVsaW1pdGVyKSArIHNlZ21lbnRcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIHNlZ21lbnQgPSB0b2tlbi5hc3RlcmlzayA/IGVuY29kZUFzdGVyaXNrKHZhbHVlKSA6IGVuY29kZSh2YWx1ZSlcblxuICAgICAgaWYgKCFtYXRjaGVzW2ldLnRlc3Qoc2VnbWVudCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcignRXhwZWN0ZWQgXCInICsgdG9rZW4ubmFtZSArICdcIiB0byBtYXRjaCBcIicgKyB0b2tlbi5wYXR0ZXJuICsgJ1wiLCBidXQgcmVjZWl2ZWQgXCInICsgc2VnbWVudCArICdcIicpXG4gICAgICB9XG5cbiAgICAgIHBhdGggKz0gdG9rZW4ucHJlZml4ICsgc2VnbWVudFxuICAgIH1cblxuICAgIHJldHVybiBwYXRoXG4gIH1cbn1cblxuLyoqXG4gKiBFc2NhcGUgYSByZWd1bGFyIGV4cHJlc3Npb24gc3RyaW5nLlxuICpcbiAqIEBwYXJhbSAge3N0cmluZ30gc3RyXG4gKiBAcmV0dXJuIHtzdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIGVzY2FwZVN0cmluZyAoc3RyKSB7XG4gIHJldHVybiBzdHIucmVwbGFjZSgvKFsuKyo/PV4hOiR7fSgpW1xcXXxcXC9cXFxcXSkvZywgJ1xcXFwkMScpXG59XG5cbi8qKlxuICogRXNjYXBlIHRoZSBjYXB0dXJpbmcgZ3JvdXAgYnkgZXNjYXBpbmcgc3BlY2lhbCBjaGFyYWN0ZXJzIGFuZCBtZWFuaW5nLlxuICpcbiAqIEBwYXJhbSAge3N0cmluZ30gZ3JvdXBcbiAqIEByZXR1cm4ge3N0cmluZ31cbiAqL1xuZnVuY3Rpb24gZXNjYXBlR3JvdXAgKGdyb3VwKSB7XG4gIHJldHVybiBncm91cC5yZXBsYWNlKC8oWz0hOiRcXC8oKV0pL2csICdcXFxcJDEnKVxufVxuXG4vKipcbiAqIEF0dGFjaCB0aGUga2V5cyBhcyBhIHByb3BlcnR5IG9mIHRoZSByZWdleHAuXG4gKlxuICogQHBhcmFtICB7IVJlZ0V4cH0gcmVcbiAqIEBwYXJhbSAge0FycmF5fSAgIGtleXNcbiAqIEByZXR1cm4geyFSZWdFeHB9XG4gKi9cbmZ1bmN0aW9uIGF0dGFjaEtleXMgKHJlLCBrZXlzKSB7XG4gIHJlLmtleXMgPSBrZXlzXG4gIHJldHVybiByZVxufVxuXG4vKipcbiAqIEdldCB0aGUgZmxhZ3MgZm9yIGEgcmVnZXhwIGZyb20gdGhlIG9wdGlvbnMuXG4gKlxuICogQHBhcmFtICB7T2JqZWN0fSBvcHRpb25zXG4gKiBAcmV0dXJuIHtzdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIGZsYWdzIChvcHRpb25zKSB7XG4gIHJldHVybiBvcHRpb25zLnNlbnNpdGl2ZSA/ICcnIDogJ2knXG59XG5cbi8qKlxuICogUHVsbCBvdXQga2V5cyBmcm9tIGEgcmVnZXhwLlxuICpcbiAqIEBwYXJhbSAgeyFSZWdFeHB9IHBhdGhcbiAqIEBwYXJhbSAgeyFBcnJheX0gIGtleXNcbiAqIEByZXR1cm4geyFSZWdFeHB9XG4gKi9cbmZ1bmN0aW9uIHJlZ2V4cFRvUmVnZXhwIChwYXRoLCBrZXlzKSB7XG4gIC8vIFVzZSBhIG5lZ2F0aXZlIGxvb2thaGVhZCB0byBtYXRjaCBvbmx5IGNhcHR1cmluZyBncm91cHMuXG4gIHZhciBncm91cHMgPSBwYXRoLnNvdXJjZS5tYXRjaCgvXFwoKD8hXFw/KS9nKVxuXG4gIGlmIChncm91cHMpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGdyb3Vwcy5sZW5ndGg7IGkrKykge1xuICAgICAga2V5cy5wdXNoKHtcbiAgICAgICAgbmFtZTogaSxcbiAgICAgICAgcHJlZml4OiBudWxsLFxuICAgICAgICBkZWxpbWl0ZXI6IG51bGwsXG4gICAgICAgIG9wdGlvbmFsOiBmYWxzZSxcbiAgICAgICAgcmVwZWF0OiBmYWxzZSxcbiAgICAgICAgcGFydGlhbDogZmFsc2UsXG4gICAgICAgIGFzdGVyaXNrOiBmYWxzZSxcbiAgICAgICAgcGF0dGVybjogbnVsbFxuICAgICAgfSlcbiAgICB9XG4gIH1cblxuICByZXR1cm4gYXR0YWNoS2V5cyhwYXRoLCBrZXlzKVxufVxuXG4vKipcbiAqIFRyYW5zZm9ybSBhbiBhcnJheSBpbnRvIGEgcmVnZXhwLlxuICpcbiAqIEBwYXJhbSAgeyFBcnJheX0gIHBhdGhcbiAqIEBwYXJhbSAge0FycmF5fSAgIGtleXNcbiAqIEBwYXJhbSAgeyFPYmplY3R9IG9wdGlvbnNcbiAqIEByZXR1cm4geyFSZWdFeHB9XG4gKi9cbmZ1bmN0aW9uIGFycmF5VG9SZWdleHAgKHBhdGgsIGtleXMsIG9wdGlvbnMpIHtcbiAgdmFyIHBhcnRzID0gW11cblxuICBmb3IgKHZhciBpID0gMDsgaSA8IHBhdGgubGVuZ3RoOyBpKyspIHtcbiAgICBwYXJ0cy5wdXNoKHBhdGhUb1JlZ2V4cChwYXRoW2ldLCBrZXlzLCBvcHRpb25zKS5zb3VyY2UpXG4gIH1cblxuICB2YXIgcmVnZXhwID0gbmV3IFJlZ0V4cCgnKD86JyArIHBhcnRzLmpvaW4oJ3wnKSArICcpJywgZmxhZ3Mob3B0aW9ucykpXG5cbiAgcmV0dXJuIGF0dGFjaEtleXMocmVnZXhwLCBrZXlzKVxufVxuXG4vKipcbiAqIENyZWF0ZSBhIHBhdGggcmVnZXhwIGZyb20gc3RyaW5nIGlucHV0LlxuICpcbiAqIEBwYXJhbSAge3N0cmluZ30gIHBhdGhcbiAqIEBwYXJhbSAgeyFBcnJheX0gIGtleXNcbiAqIEBwYXJhbSAgeyFPYmplY3R9IG9wdGlvbnNcbiAqIEByZXR1cm4geyFSZWdFeHB9XG4gKi9cbmZ1bmN0aW9uIHN0cmluZ1RvUmVnZXhwIChwYXRoLCBrZXlzLCBvcHRpb25zKSB7XG4gIHJldHVybiB0b2tlbnNUb1JlZ0V4cChwYXJzZShwYXRoLCBvcHRpb25zKSwga2V5cywgb3B0aW9ucylcbn1cblxuLyoqXG4gKiBFeHBvc2UgYSBmdW5jdGlvbiBmb3IgdGFraW5nIHRva2VucyBhbmQgcmV0dXJuaW5nIGEgUmVnRXhwLlxuICpcbiAqIEBwYXJhbSAgeyFBcnJheX0gICAgICAgICAgdG9rZW5zXG4gKiBAcGFyYW0gIHsoQXJyYXl8T2JqZWN0KT19IGtleXNcbiAqIEBwYXJhbSAge09iamVjdD19ICAgICAgICAgb3B0aW9uc1xuICogQHJldHVybiB7IVJlZ0V4cH1cbiAqL1xuZnVuY3Rpb24gdG9rZW5zVG9SZWdFeHAgKHRva2Vucywga2V5cywgb3B0aW9ucykge1xuICBpZiAoIWlzYXJyYXkoa2V5cykpIHtcbiAgICBvcHRpb25zID0gLyoqIEB0eXBlIHshT2JqZWN0fSAqLyAoa2V5cyB8fCBvcHRpb25zKVxuICAgIGtleXMgPSBbXVxuICB9XG5cbiAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge31cblxuICB2YXIgc3RyaWN0ID0gb3B0aW9ucy5zdHJpY3RcbiAgdmFyIGVuZCA9IG9wdGlvbnMuZW5kICE9PSBmYWxzZVxuICB2YXIgcm91dGUgPSAnJ1xuXG4gIC8vIEl0ZXJhdGUgb3ZlciB0aGUgdG9rZW5zIGFuZCBjcmVhdGUgb3VyIHJlZ2V4cCBzdHJpbmcuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgdG9rZW5zLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIHRva2VuID0gdG9rZW5zW2ldXG5cbiAgICBpZiAodHlwZW9mIHRva2VuID09PSAnc3RyaW5nJykge1xuICAgICAgcm91dGUgKz0gZXNjYXBlU3RyaW5nKHRva2VuKVxuICAgIH0gZWxzZSB7XG4gICAgICB2YXIgcHJlZml4ID0gZXNjYXBlU3RyaW5nKHRva2VuLnByZWZpeClcbiAgICAgIHZhciBjYXB0dXJlID0gJyg/OicgKyB0b2tlbi5wYXR0ZXJuICsgJyknXG5cbiAgICAgIGtleXMucHVzaCh0b2tlbilcblxuICAgICAgaWYgKHRva2VuLnJlcGVhdCkge1xuICAgICAgICBjYXB0dXJlICs9ICcoPzonICsgcHJlZml4ICsgY2FwdHVyZSArICcpKidcbiAgICAgIH1cblxuICAgICAgaWYgKHRva2VuLm9wdGlvbmFsKSB7XG4gICAgICAgIGlmICghdG9rZW4ucGFydGlhbCkge1xuICAgICAgICAgIGNhcHR1cmUgPSAnKD86JyArIHByZWZpeCArICcoJyArIGNhcHR1cmUgKyAnKSk/J1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNhcHR1cmUgPSBwcmVmaXggKyAnKCcgKyBjYXB0dXJlICsgJyk/J1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjYXB0dXJlID0gcHJlZml4ICsgJygnICsgY2FwdHVyZSArICcpJ1xuICAgICAgfVxuXG4gICAgICByb3V0ZSArPSBjYXB0dXJlXG4gICAgfVxuICB9XG5cbiAgdmFyIGRlbGltaXRlciA9IGVzY2FwZVN0cmluZyhvcHRpb25zLmRlbGltaXRlciB8fCAnLycpXG4gIHZhciBlbmRzV2l0aERlbGltaXRlciA9IHJvdXRlLnNsaWNlKC1kZWxpbWl0ZXIubGVuZ3RoKSA9PT0gZGVsaW1pdGVyXG5cbiAgLy8gSW4gbm9uLXN0cmljdCBtb2RlIHdlIGFsbG93IGEgc2xhc2ggYXQgdGhlIGVuZCBvZiBtYXRjaC4gSWYgdGhlIHBhdGggdG9cbiAgLy8gbWF0Y2ggYWxyZWFkeSBlbmRzIHdpdGggYSBzbGFzaCwgd2UgcmVtb3ZlIGl0IGZvciBjb25zaXN0ZW5jeS4gVGhlIHNsYXNoXG4gIC8vIGlzIHZhbGlkIGF0IHRoZSBlbmQgb2YgYSBwYXRoIG1hdGNoLCBub3QgaW4gdGhlIG1pZGRsZS4gVGhpcyBpcyBpbXBvcnRhbnRcbiAgLy8gaW4gbm9uLWVuZGluZyBtb2RlLCB3aGVyZSBcIi90ZXN0L1wiIHNob3VsZG4ndCBtYXRjaCBcIi90ZXN0Ly9yb3V0ZVwiLlxuICBpZiAoIXN0cmljdCkge1xuICAgIHJvdXRlID0gKGVuZHNXaXRoRGVsaW1pdGVyID8gcm91dGUuc2xpY2UoMCwgLWRlbGltaXRlci5sZW5ndGgpIDogcm91dGUpICsgJyg/OicgKyBkZWxpbWl0ZXIgKyAnKD89JCkpPydcbiAgfVxuXG4gIGlmIChlbmQpIHtcbiAgICByb3V0ZSArPSAnJCdcbiAgfSBlbHNlIHtcbiAgICAvLyBJbiBub24tZW5kaW5nIG1vZGUsIHdlIG5lZWQgdGhlIGNhcHR1cmluZyBncm91cHMgdG8gbWF0Y2ggYXMgbXVjaCBhc1xuICAgIC8vIHBvc3NpYmxlIGJ5IHVzaW5nIGEgcG9zaXRpdmUgbG9va2FoZWFkIHRvIHRoZSBlbmQgb3IgbmV4dCBwYXRoIHNlZ21lbnQuXG4gICAgcm91dGUgKz0gc3RyaWN0ICYmIGVuZHNXaXRoRGVsaW1pdGVyID8gJycgOiAnKD89JyArIGRlbGltaXRlciArICd8JCknXG4gIH1cblxuICByZXR1cm4gYXR0YWNoS2V5cyhuZXcgUmVnRXhwKCdeJyArIHJvdXRlLCBmbGFncyhvcHRpb25zKSksIGtleXMpXG59XG5cbi8qKlxuICogTm9ybWFsaXplIHRoZSBnaXZlbiBwYXRoIHN0cmluZywgcmV0dXJuaW5nIGEgcmVndWxhciBleHByZXNzaW9uLlxuICpcbiAqIEFuIGVtcHR5IGFycmF5IGNhbiBiZSBwYXNzZWQgaW4gZm9yIHRoZSBrZXlzLCB3aGljaCB3aWxsIGhvbGQgdGhlXG4gKiBwbGFjZWhvbGRlciBrZXkgZGVzY3JpcHRpb25zLiBGb3IgZXhhbXBsZSwgdXNpbmcgYC91c2VyLzppZGAsIGBrZXlzYCB3aWxsXG4gKiBjb250YWluIGBbeyBuYW1lOiAnaWQnLCBkZWxpbWl0ZXI6ICcvJywgb3B0aW9uYWw6IGZhbHNlLCByZXBlYXQ6IGZhbHNlIH1dYC5cbiAqXG4gKiBAcGFyYW0gIHsoc3RyaW5nfFJlZ0V4cHxBcnJheSl9IHBhdGhcbiAqIEBwYXJhbSAgeyhBcnJheXxPYmplY3QpPX0gICAgICAga2V5c1xuICogQHBhcmFtICB7T2JqZWN0PX0gICAgICAgICAgICAgICBvcHRpb25zXG4gKiBAcmV0dXJuIHshUmVnRXhwfVxuICovXG5mdW5jdGlvbiBwYXRoVG9SZWdleHAgKHBhdGgsIGtleXMsIG9wdGlvbnMpIHtcbiAgaWYgKCFpc2FycmF5KGtleXMpKSB7XG4gICAgb3B0aW9ucyA9IC8qKiBAdHlwZSB7IU9iamVjdH0gKi8gKGtleXMgfHwgb3B0aW9ucylcbiAgICBrZXlzID0gW11cbiAgfVxuXG4gIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9XG5cbiAgaWYgKHBhdGggaW5zdGFuY2VvZiBSZWdFeHApIHtcbiAgICByZXR1cm4gcmVnZXhwVG9SZWdleHAocGF0aCwgLyoqIEB0eXBlIHshQXJyYXl9ICovIChrZXlzKSlcbiAgfVxuXG4gIGlmIChpc2FycmF5KHBhdGgpKSB7XG4gICAgcmV0dXJuIGFycmF5VG9SZWdleHAoLyoqIEB0eXBlIHshQXJyYXl9ICovIChwYXRoKSwgLyoqIEB0eXBlIHshQXJyYXl9ICovIChrZXlzKSwgb3B0aW9ucylcbiAgfVxuXG4gIHJldHVybiBzdHJpbmdUb1JlZ2V4cCgvKiogQHR5cGUge3N0cmluZ30gKi8gKHBhdGgpLCAvKiogQHR5cGUgeyFBcnJheX0gKi8gKGtleXMpLCBvcHRpb25zKVxufVxuIiwiLy8gc2hpbSBmb3IgdXNpbmcgcHJvY2VzcyBpbiBicm93c2VyXG52YXIgcHJvY2VzcyA9IG1vZHVsZS5leHBvcnRzID0ge307XG5cbi8vIGNhY2hlZCBmcm9tIHdoYXRldmVyIGdsb2JhbCBpcyBwcmVzZW50IHNvIHRoYXQgdGVzdCBydW5uZXJzIHRoYXQgc3R1YiBpdFxuLy8gZG9uJ3QgYnJlYWsgdGhpbmdzLiAgQnV0IHdlIG5lZWQgdG8gd3JhcCBpdCBpbiBhIHRyeSBjYXRjaCBpbiBjYXNlIGl0IGlzXG4vLyB3cmFwcGVkIGluIHN0cmljdCBtb2RlIGNvZGUgd2hpY2ggZG9lc24ndCBkZWZpbmUgYW55IGdsb2JhbHMuICBJdCdzIGluc2lkZSBhXG4vLyBmdW5jdGlvbiBiZWNhdXNlIHRyeS9jYXRjaGVzIGRlb3B0aW1pemUgaW4gY2VydGFpbiBlbmdpbmVzLlxuXG52YXIgY2FjaGVkU2V0VGltZW91dDtcbnZhciBjYWNoZWRDbGVhclRpbWVvdXQ7XG5cbmZ1bmN0aW9uIGRlZmF1bHRTZXRUaW1vdXQoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdzZXRUaW1lb3V0IGhhcyBub3QgYmVlbiBkZWZpbmVkJyk7XG59XG5mdW5jdGlvbiBkZWZhdWx0Q2xlYXJUaW1lb3V0ICgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2NsZWFyVGltZW91dCBoYXMgbm90IGJlZW4gZGVmaW5lZCcpO1xufVxuKGZ1bmN0aW9uICgpIHtcbiAgICB0cnkge1xuICAgICAgICBpZiAodHlwZW9mIHNldFRpbWVvdXQgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIGNhY2hlZFNldFRpbWVvdXQgPSBzZXRUaW1lb3V0O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY2FjaGVkU2V0VGltZW91dCA9IGRlZmF1bHRTZXRUaW1vdXQ7XG4gICAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNhY2hlZFNldFRpbWVvdXQgPSBkZWZhdWx0U2V0VGltb3V0O1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgICBpZiAodHlwZW9mIGNsZWFyVGltZW91dCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgY2FjaGVkQ2xlYXJUaW1lb3V0ID0gY2xlYXJUaW1lb3V0O1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY2FjaGVkQ2xlYXJUaW1lb3V0ID0gZGVmYXVsdENsZWFyVGltZW91dDtcbiAgICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY2FjaGVkQ2xlYXJUaW1lb3V0ID0gZGVmYXVsdENsZWFyVGltZW91dDtcbiAgICB9XG59ICgpKVxuZnVuY3Rpb24gcnVuVGltZW91dChmdW4pIHtcbiAgICBpZiAoY2FjaGVkU2V0VGltZW91dCA9PT0gc2V0VGltZW91dCkge1xuICAgICAgICAvL25vcm1hbCBlbnZpcm9tZW50cyBpbiBzYW5lIHNpdHVhdGlvbnNcbiAgICAgICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuLCAwKTtcbiAgICB9XG4gICAgLy8gaWYgc2V0VGltZW91dCB3YXNuJ3QgYXZhaWxhYmxlIGJ1dCB3YXMgbGF0dGVyIGRlZmluZWRcbiAgICBpZiAoKGNhY2hlZFNldFRpbWVvdXQgPT09IGRlZmF1bHRTZXRUaW1vdXQgfHwgIWNhY2hlZFNldFRpbWVvdXQpICYmIHNldFRpbWVvdXQpIHtcbiAgICAgICAgY2FjaGVkU2V0VGltZW91dCA9IHNldFRpbWVvdXQ7XG4gICAgICAgIHJldHVybiBzZXRUaW1lb3V0KGZ1biwgMCk7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICAgIC8vIHdoZW4gd2hlbiBzb21lYm9keSBoYXMgc2NyZXdlZCB3aXRoIHNldFRpbWVvdXQgYnV0IG5vIEkuRS4gbWFkZG5lc3NcbiAgICAgICAgcmV0dXJuIGNhY2hlZFNldFRpbWVvdXQoZnVuLCAwKTtcbiAgICB9IGNhdGNoKGUpe1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgLy8gV2hlbiB3ZSBhcmUgaW4gSS5FLiBidXQgdGhlIHNjcmlwdCBoYXMgYmVlbiBldmFsZWQgc28gSS5FLiBkb2Vzbid0IHRydXN0IHRoZSBnbG9iYWwgb2JqZWN0IHdoZW4gY2FsbGVkIG5vcm1hbGx5XG4gICAgICAgICAgICByZXR1cm4gY2FjaGVkU2V0VGltZW91dC5jYWxsKG51bGwsIGZ1biwgMCk7XG4gICAgICAgIH0gY2F0Y2goZSl7XG4gICAgICAgICAgICAvLyBzYW1lIGFzIGFib3ZlIGJ1dCB3aGVuIGl0J3MgYSB2ZXJzaW9uIG9mIEkuRS4gdGhhdCBtdXN0IGhhdmUgdGhlIGdsb2JhbCBvYmplY3QgZm9yICd0aGlzJywgaG9wZnVsbHkgb3VyIGNvbnRleHQgY29ycmVjdCBvdGhlcndpc2UgaXQgd2lsbCB0aHJvdyBhIGdsb2JhbCBlcnJvclxuICAgICAgICAgICAgcmV0dXJuIGNhY2hlZFNldFRpbWVvdXQuY2FsbCh0aGlzLCBmdW4sIDApO1xuICAgICAgICB9XG4gICAgfVxuXG5cbn1cbmZ1bmN0aW9uIHJ1bkNsZWFyVGltZW91dChtYXJrZXIpIHtcbiAgICBpZiAoY2FjaGVkQ2xlYXJUaW1lb3V0ID09PSBjbGVhclRpbWVvdXQpIHtcbiAgICAgICAgLy9ub3JtYWwgZW52aXJvbWVudHMgaW4gc2FuZSBzaXR1YXRpb25zXG4gICAgICAgIHJldHVybiBjbGVhclRpbWVvdXQobWFya2VyKTtcbiAgICB9XG4gICAgLy8gaWYgY2xlYXJUaW1lb3V0IHdhc24ndCBhdmFpbGFibGUgYnV0IHdhcyBsYXR0ZXIgZGVmaW5lZFxuICAgIGlmICgoY2FjaGVkQ2xlYXJUaW1lb3V0ID09PSBkZWZhdWx0Q2xlYXJUaW1lb3V0IHx8ICFjYWNoZWRDbGVhclRpbWVvdXQpICYmIGNsZWFyVGltZW91dCkge1xuICAgICAgICBjYWNoZWRDbGVhclRpbWVvdXQgPSBjbGVhclRpbWVvdXQ7XG4gICAgICAgIHJldHVybiBjbGVhclRpbWVvdXQobWFya2VyKTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgICAgLy8gd2hlbiB3aGVuIHNvbWVib2R5IGhhcyBzY3Jld2VkIHdpdGggc2V0VGltZW91dCBidXQgbm8gSS5FLiBtYWRkbmVzc1xuICAgICAgICByZXR1cm4gY2FjaGVkQ2xlYXJUaW1lb3V0KG1hcmtlcik7XG4gICAgfSBjYXRjaCAoZSl7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICAvLyBXaGVuIHdlIGFyZSBpbiBJLkUuIGJ1dCB0aGUgc2NyaXB0IGhhcyBiZWVuIGV2YWxlZCBzbyBJLkUuIGRvZXNuJ3QgIHRydXN0IHRoZSBnbG9iYWwgb2JqZWN0IHdoZW4gY2FsbGVkIG5vcm1hbGx5XG4gICAgICAgICAgICByZXR1cm4gY2FjaGVkQ2xlYXJUaW1lb3V0LmNhbGwobnVsbCwgbWFya2VyKTtcbiAgICAgICAgfSBjYXRjaCAoZSl7XG4gICAgICAgICAgICAvLyBzYW1lIGFzIGFib3ZlIGJ1dCB3aGVuIGl0J3MgYSB2ZXJzaW9uIG9mIEkuRS4gdGhhdCBtdXN0IGhhdmUgdGhlIGdsb2JhbCBvYmplY3QgZm9yICd0aGlzJywgaG9wZnVsbHkgb3VyIGNvbnRleHQgY29ycmVjdCBvdGhlcndpc2UgaXQgd2lsbCB0aHJvdyBhIGdsb2JhbCBlcnJvci5cbiAgICAgICAgICAgIC8vIFNvbWUgdmVyc2lvbnMgb2YgSS5FLiBoYXZlIGRpZmZlcmVudCBydWxlcyBmb3IgY2xlYXJUaW1lb3V0IHZzIHNldFRpbWVvdXRcbiAgICAgICAgICAgIHJldHVybiBjYWNoZWRDbGVhclRpbWVvdXQuY2FsbCh0aGlzLCBtYXJrZXIpO1xuICAgICAgICB9XG4gICAgfVxuXG5cblxufVxudmFyIHF1ZXVlID0gW107XG52YXIgZHJhaW5pbmcgPSBmYWxzZTtcbnZhciBjdXJyZW50UXVldWU7XG52YXIgcXVldWVJbmRleCA9IC0xO1xuXG5mdW5jdGlvbiBjbGVhblVwTmV4dFRpY2soKSB7XG4gICAgaWYgKCFkcmFpbmluZyB8fCAhY3VycmVudFF1ZXVlKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgZHJhaW5pbmcgPSBmYWxzZTtcbiAgICBpZiAoY3VycmVudFF1ZXVlLmxlbmd0aCkge1xuICAgICAgICBxdWV1ZSA9IGN1cnJlbnRRdWV1ZS5jb25jYXQocXVldWUpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHF1ZXVlSW5kZXggPSAtMTtcbiAgICB9XG4gICAgaWYgKHF1ZXVlLmxlbmd0aCkge1xuICAgICAgICBkcmFpblF1ZXVlKCk7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBkcmFpblF1ZXVlKCkge1xuICAgIGlmIChkcmFpbmluZykge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIHZhciB0aW1lb3V0ID0gcnVuVGltZW91dChjbGVhblVwTmV4dFRpY2spO1xuICAgIGRyYWluaW5nID0gdHJ1ZTtcblxuICAgIHZhciBsZW4gPSBxdWV1ZS5sZW5ndGg7XG4gICAgd2hpbGUobGVuKSB7XG4gICAgICAgIGN1cnJlbnRRdWV1ZSA9IHF1ZXVlO1xuICAgICAgICBxdWV1ZSA9IFtdO1xuICAgICAgICB3aGlsZSAoKytxdWV1ZUluZGV4IDwgbGVuKSB7XG4gICAgICAgICAgICBpZiAoY3VycmVudFF1ZXVlKSB7XG4gICAgICAgICAgICAgICAgY3VycmVudFF1ZXVlW3F1ZXVlSW5kZXhdLnJ1bigpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHF1ZXVlSW5kZXggPSAtMTtcbiAgICAgICAgbGVuID0gcXVldWUubGVuZ3RoO1xuICAgIH1cbiAgICBjdXJyZW50UXVldWUgPSBudWxsO1xuICAgIGRyYWluaW5nID0gZmFsc2U7XG4gICAgcnVuQ2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xufVxuXG5wcm9jZXNzLm5leHRUaWNrID0gZnVuY3Rpb24gKGZ1bikge1xuICAgIHZhciBhcmdzID0gbmV3IEFycmF5KGFyZ3VtZW50cy5sZW5ndGggLSAxKTtcbiAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDE7IGkgPCBhcmd1bWVudHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGFyZ3NbaSAtIDFdID0gYXJndW1lbnRzW2ldO1xuICAgICAgICB9XG4gICAgfVxuICAgIHF1ZXVlLnB1c2gobmV3IEl0ZW0oZnVuLCBhcmdzKSk7XG4gICAgaWYgKHF1ZXVlLmxlbmd0aCA9PT0gMSAmJiAhZHJhaW5pbmcpIHtcbiAgICAgICAgcnVuVGltZW91dChkcmFpblF1ZXVlKTtcbiAgICB9XG59O1xuXG4vLyB2OCBsaWtlcyBwcmVkaWN0aWJsZSBvYmplY3RzXG5mdW5jdGlvbiBJdGVtKGZ1biwgYXJyYXkpIHtcbiAgICB0aGlzLmZ1biA9IGZ1bjtcbiAgICB0aGlzLmFycmF5ID0gYXJyYXk7XG59XG5JdGVtLnByb3RvdHlwZS5ydW4gPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5mdW4uYXBwbHkobnVsbCwgdGhpcy5hcnJheSk7XG59O1xucHJvY2Vzcy50aXRsZSA9ICdicm93c2VyJztcbnByb2Nlc3MuYnJvd3NlciA9IHRydWU7XG5wcm9jZXNzLmVudiA9IHt9O1xucHJvY2Vzcy5hcmd2ID0gW107XG5wcm9jZXNzLnZlcnNpb24gPSAnJzsgLy8gZW1wdHkgc3RyaW5nIHRvIGF2b2lkIHJlZ2V4cCBpc3N1ZXNcbnByb2Nlc3MudmVyc2lvbnMgPSB7fTtcblxuZnVuY3Rpb24gbm9vcCgpIHt9XG5cbnByb2Nlc3Mub24gPSBub29wO1xucHJvY2Vzcy5hZGRMaXN0ZW5lciA9IG5vb3A7XG5wcm9jZXNzLm9uY2UgPSBub29wO1xucHJvY2Vzcy5vZmYgPSBub29wO1xucHJvY2Vzcy5yZW1vdmVMaXN0ZW5lciA9IG5vb3A7XG5wcm9jZXNzLnJlbW92ZUFsbExpc3RlbmVycyA9IG5vb3A7XG5wcm9jZXNzLmVtaXQgPSBub29wO1xuXG5wcm9jZXNzLmJpbmRpbmcgPSBmdW5jdGlvbiAobmFtZSkge1xuICAgIHRocm93IG5ldyBFcnJvcigncHJvY2Vzcy5iaW5kaW5nIGlzIG5vdCBzdXBwb3J0ZWQnKTtcbn07XG5cbnByb2Nlc3MuY3dkID0gZnVuY3Rpb24gKCkgeyByZXR1cm4gJy8nIH07XG5wcm9jZXNzLmNoZGlyID0gZnVuY3Rpb24gKGRpcikge1xuICAgIHRocm93IG5ldyBFcnJvcigncHJvY2Vzcy5jaGRpciBpcyBub3Qgc3VwcG9ydGVkJyk7XG59O1xucHJvY2Vzcy51bWFzayA9IGZ1bmN0aW9uKCkgeyByZXR1cm4gMDsgfTtcbiIsIigodHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIGRlZmluZS5hbWQgJiYgZnVuY3Rpb24gKG0pIHsgZGVmaW5lKFwic2Ftc2FtXCIsIG0pOyB9KSB8fFxuICh0eXBlb2YgbW9kdWxlID09PSBcIm9iamVjdFwiICYmXG4gICAgICBmdW5jdGlvbiAobSkgeyBtb2R1bGUuZXhwb3J0cyA9IG0oKTsgfSkgfHwgLy8gTm9kZVxuIGZ1bmN0aW9uIChtKSB7IHRoaXMuc2Ftc2FtID0gbSgpOyB9IC8vIEJyb3dzZXIgZ2xvYmFsc1xuKShmdW5jdGlvbiAoKSB7XG4gICAgdmFyIG8gPSBPYmplY3QucHJvdG90eXBlO1xuICAgIHZhciBkaXYgPSB0eXBlb2YgZG9jdW1lbnQgIT09IFwidW5kZWZpbmVkXCIgJiYgZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKTtcblxuICAgIGZ1bmN0aW9uIGlzTmFOKHZhbHVlKSB7XG4gICAgICAgIC8vIFVubGlrZSBnbG9iYWwgaXNOYU4sIHRoaXMgYXZvaWRzIHR5cGUgY29lcmNpb25cbiAgICAgICAgLy8gdHlwZW9mIGNoZWNrIGF2b2lkcyBJRSBob3N0IG9iamVjdCBpc3N1ZXMsIGhhdCB0aXAgdG9cbiAgICAgICAgLy8gbG9kYXNoXG4gICAgICAgIHZhciB2YWwgPSB2YWx1ZTsgLy8gSnNMaW50IHRoaW5rcyB2YWx1ZSAhPT0gdmFsdWUgaXMgXCJ3ZWlyZFwiXG4gICAgICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT09IFwibnVtYmVyXCIgJiYgdmFsdWUgIT09IHZhbDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBnZXRDbGFzcyh2YWx1ZSkge1xuICAgICAgICAvLyBSZXR1cm5zIHRoZSBpbnRlcm5hbCBbW0NsYXNzXV0gYnkgY2FsbGluZyBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nXG4gICAgICAgIC8vIHdpdGggdGhlIHByb3ZpZGVkIHZhbHVlIGFzIHRoaXMuIFJldHVybiB2YWx1ZSBpcyBhIHN0cmluZywgbmFtaW5nIHRoZVxuICAgICAgICAvLyBpbnRlcm5hbCBjbGFzcywgZS5nLiBcIkFycmF5XCJcbiAgICAgICAgcmV0dXJuIG8udG9TdHJpbmcuY2FsbCh2YWx1ZSkuc3BsaXQoL1sgXFxdXS8pWzFdO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBuYW1lIHNhbXNhbS5pc0FyZ3VtZW50c1xuICAgICAqIEBwYXJhbSBPYmplY3Qgb2JqZWN0XG4gICAgICpcbiAgICAgKiBSZXR1cm5zIGBgdHJ1ZWBgIGlmIGBgb2JqZWN0YGAgaXMgYW4gYGBhcmd1bWVudHNgYCBvYmplY3QsXG4gICAgICogYGBmYWxzZWBgIG90aGVyd2lzZS5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpc0FyZ3VtZW50cyhvYmplY3QpIHtcbiAgICAgICAgaWYgKGdldENsYXNzKG9iamVjdCkgPT09ICdBcmd1bWVudHMnKSB7IHJldHVybiB0cnVlOyB9XG4gICAgICAgIGlmICh0eXBlb2Ygb2JqZWN0ICE9PSBcIm9iamVjdFwiIHx8IHR5cGVvZiBvYmplY3QubGVuZ3RoICE9PSBcIm51bWJlclwiIHx8XG4gICAgICAgICAgICAgICAgZ2V0Q2xhc3Mob2JqZWN0KSA9PT0gXCJBcnJheVwiKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHR5cGVvZiBvYmplY3QuY2FsbGVlID09IFwiZnVuY3Rpb25cIikgeyByZXR1cm4gdHJ1ZTsgfVxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgb2JqZWN0W29iamVjdC5sZW5ndGhdID0gNjtcbiAgICAgICAgICAgIGRlbGV0ZSBvYmplY3Rbb2JqZWN0Lmxlbmd0aF07XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAbmFtZSBzYW1zYW0uaXNFbGVtZW50XG4gICAgICogQHBhcmFtIE9iamVjdCBvYmplY3RcbiAgICAgKlxuICAgICAqIFJldHVybnMgYGB0cnVlYGAgaWYgYGBvYmplY3RgYCBpcyBhIERPTSBlbGVtZW50IG5vZGUuIFVubGlrZVxuICAgICAqIFVuZGVyc2NvcmUuanMvbG9kYXNoLCB0aGlzIGZ1bmN0aW9uIHdpbGwgcmV0dXJuIGBgZmFsc2VgYCBpZiBgYG9iamVjdGBgXG4gICAgICogaXMgYW4gKmVsZW1lbnQtbGlrZSogb2JqZWN0LCBpLmUuIGEgcmVndWxhciBvYmplY3Qgd2l0aCBhIGBgbm9kZVR5cGVgYFxuICAgICAqIHByb3BlcnR5IHRoYXQgaG9sZHMgdGhlIHZhbHVlIGBgMWBgLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGlzRWxlbWVudChvYmplY3QpIHtcbiAgICAgICAgaWYgKCFvYmplY3QgfHwgb2JqZWN0Lm5vZGVUeXBlICE9PSAxIHx8ICFkaXYpIHsgcmV0dXJuIGZhbHNlOyB9XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBvYmplY3QuYXBwZW5kQ2hpbGQoZGl2KTtcbiAgICAgICAgICAgIG9iamVjdC5yZW1vdmVDaGlsZChkaXYpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQG5hbWUgc2Ftc2FtLmtleXNcbiAgICAgKiBAcGFyYW0gT2JqZWN0IG9iamVjdFxuICAgICAqXG4gICAgICogUmV0dXJuIGFuIGFycmF5IG9mIG93biBwcm9wZXJ0eSBuYW1lcy5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBrZXlzKG9iamVjdCkge1xuICAgICAgICB2YXIga3MgPSBbXSwgcHJvcDtcbiAgICAgICAgZm9yIChwcm9wIGluIG9iamVjdCkge1xuICAgICAgICAgICAgaWYgKG8uaGFzT3duUHJvcGVydHkuY2FsbChvYmplY3QsIHByb3ApKSB7IGtzLnB1c2gocHJvcCk7IH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ga3M7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQG5hbWUgc2Ftc2FtLmlzRGF0ZVxuICAgICAqIEBwYXJhbSBPYmplY3QgdmFsdWVcbiAgICAgKlxuICAgICAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgb2JqZWN0IGlzIGEgYGBEYXRlYGAsIG9yICpkYXRlLWxpa2UqLiBEdWNrIHR5cGluZ1xuICAgICAqIG9mIGRhdGUgb2JqZWN0cyB3b3JrIGJ5IGNoZWNraW5nIHRoYXQgdGhlIG9iamVjdCBoYXMgYSBgYGdldFRpbWVgYFxuICAgICAqIGZ1bmN0aW9uIHdob3NlIHJldHVybiB2YWx1ZSBlcXVhbHMgdGhlIHJldHVybiB2YWx1ZSBmcm9tIHRoZSBvYmplY3Qnc1xuICAgICAqIGBgdmFsdWVPZmBgLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGlzRGF0ZSh2YWx1ZSkge1xuICAgICAgICByZXR1cm4gdHlwZW9mIHZhbHVlLmdldFRpbWUgPT0gXCJmdW5jdGlvblwiICYmXG4gICAgICAgICAgICB2YWx1ZS5nZXRUaW1lKCkgPT0gdmFsdWUudmFsdWVPZigpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBuYW1lIHNhbXNhbS5pc05lZ1plcm9cbiAgICAgKiBAcGFyYW0gT2JqZWN0IHZhbHVlXG4gICAgICpcbiAgICAgKiBSZXR1cm5zIGBgdHJ1ZWBgIGlmIGBgdmFsdWVgYCBpcyBgYC0wYGAuXG4gICAgICovXG4gICAgZnVuY3Rpb24gaXNOZWdaZXJvKHZhbHVlKSB7XG4gICAgICAgIHJldHVybiB2YWx1ZSA9PT0gMCAmJiAxIC8gdmFsdWUgPT09IC1JbmZpbml0eTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAbmFtZSBzYW1zYW0uZXF1YWxcbiAgICAgKiBAcGFyYW0gT2JqZWN0IG9iajFcbiAgICAgKiBAcGFyYW0gT2JqZWN0IG9iajJcbiAgICAgKlxuICAgICAqIFJldHVybnMgYGB0cnVlYGAgaWYgdHdvIG9iamVjdHMgYXJlIHN0cmljdGx5IGVxdWFsLiBDb21wYXJlZCB0b1xuICAgICAqIGBgPT09YGAgdGhlcmUgYXJlIHR3byBleGNlcHRpb25zOlxuICAgICAqXG4gICAgICogICAtIE5hTiBpcyBjb25zaWRlcmVkIGVxdWFsIHRvIE5hTlxuICAgICAqICAgLSAtMCBhbmQgKzAgYXJlIG5vdCBjb25zaWRlcmVkIGVxdWFsXG4gICAgICovXG4gICAgZnVuY3Rpb24gaWRlbnRpY2FsKG9iajEsIG9iajIpIHtcbiAgICAgICAgaWYgKG9iajEgPT09IG9iajIgfHwgKGlzTmFOKG9iajEpICYmIGlzTmFOKG9iajIpKSkge1xuICAgICAgICAgICAgcmV0dXJuIG9iajEgIT09IDAgfHwgaXNOZWdaZXJvKG9iajEpID09PSBpc05lZ1plcm8ob2JqMik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBpc1NldCh2YWwpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBTZXQgIT09ICd1bmRlZmluZWQnICYmIHZhbCBpbnN0YW5jZW9mIFNldCkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBpc1N1YnNldChzMSwgczIsIGNvbXBhcmUpIHtcbiAgICAgICAgdmFyIHZhbHVlczEgPSBBcnJheS5mcm9tKHMxKTtcbiAgICAgICAgdmFyIHZhbHVlczIgPSBBcnJheS5mcm9tKHMyKTtcblxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHZhbHVlczEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIHZhciBpbmNsdWRlcyA9IGZhbHNlO1xuXG4gICAgICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHZhbHVlczIubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgICAgICBpZiAoY29tcGFyZSh2YWx1ZXMyW2pdLCB2YWx1ZXMxW2ldKSkge1xuICAgICAgICAgICAgICAgICAgICBpbmNsdWRlcyA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCFpbmNsdWRlcykge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBuYW1lIHNhbXNhbS5kZWVwRXF1YWxcbiAgICAgKiBAcGFyYW0gT2JqZWN0IG9iajFcbiAgICAgKiBAcGFyYW0gT2JqZWN0IG9iajJcbiAgICAgKlxuICAgICAqIERlZXAgZXF1YWwgY29tcGFyaXNvbi4gVHdvIHZhbHVlcyBhcmUgXCJkZWVwIGVxdWFsXCIgaWY6XG4gICAgICpcbiAgICAgKiAgIC0gVGhleSBhcmUgZXF1YWwsIGFjY29yZGluZyB0byBzYW1zYW0uaWRlbnRpY2FsXG4gICAgICogICAtIFRoZXkgYXJlIGJvdGggZGF0ZSBvYmplY3RzIHJlcHJlc2VudGluZyB0aGUgc2FtZSB0aW1lXG4gICAgICogICAtIFRoZXkgYXJlIGJvdGggYXJyYXlzIGNvbnRhaW5pbmcgZWxlbWVudHMgdGhhdCBhcmUgYWxsIGRlZXBFcXVhbFxuICAgICAqICAgLSBUaGV5IGFyZSBvYmplY3RzIHdpdGggdGhlIHNhbWUgc2V0IG9mIHByb3BlcnRpZXMsIGFuZCBlYWNoIHByb3BlcnR5XG4gICAgICogICAgIGluIGBgb2JqMWBgIGlzIGRlZXBFcXVhbCB0byB0aGUgY29ycmVzcG9uZGluZyBwcm9wZXJ0eSBpbiBgYG9iajJgYFxuICAgICAqXG4gICAgICogU3VwcG9ydHMgY3ljbGljIG9iamVjdHMuXG4gICAgICovXG4gICAgZnVuY3Rpb24gZGVlcEVxdWFsQ3ljbGljKG9iajEsIG9iajIpIHtcblxuICAgICAgICAvLyB1c2VkIGZvciBjeWNsaWMgY29tcGFyaXNvblxuICAgICAgICAvLyBjb250YWluIGFscmVhZHkgdmlzaXRlZCBvYmplY3RzXG4gICAgICAgIHZhciBvYmplY3RzMSA9IFtdLFxuICAgICAgICAgICAgb2JqZWN0czIgPSBbXSxcbiAgICAgICAgLy8gY29udGFpbiBwYXRoZXMgKHBvc2l0aW9uIGluIHRoZSBvYmplY3Qgc3RydWN0dXJlKVxuICAgICAgICAvLyBvZiB0aGUgYWxyZWFkeSB2aXNpdGVkIG9iamVjdHNcbiAgICAgICAgLy8gaW5kZXhlcyBzYW1lIGFzIGluIG9iamVjdHMgYXJyYXlzXG4gICAgICAgICAgICBwYXRoczEgPSBbXSxcbiAgICAgICAgICAgIHBhdGhzMiA9IFtdLFxuICAgICAgICAvLyBjb250YWlucyBjb21iaW5hdGlvbnMgb2YgYWxyZWFkeSBjb21wYXJlZCBvYmplY3RzXG4gICAgICAgIC8vIGluIHRoZSBtYW5uZXI6IHsgXCIkMVsncmVmJ10kMlsncmVmJ11cIjogdHJ1ZSB9XG4gICAgICAgICAgICBjb21wYXJlZCA9IHt9O1xuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiB1c2VkIHRvIGNoZWNrLCBpZiB0aGUgdmFsdWUgb2YgYSBwcm9wZXJ0eSBpcyBhbiBvYmplY3RcbiAgICAgICAgICogKGN5Y2xpYyBsb2dpYyBpcyBvbmx5IG5lZWRlZCBmb3Igb2JqZWN0cylcbiAgICAgICAgICogb25seSBuZWVkZWQgZm9yIGN5Y2xpYyBsb2dpY1xuICAgICAgICAgKi9cbiAgICAgICAgZnVuY3Rpb24gaXNPYmplY3QodmFsdWUpIHtcblxuICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgdmFsdWUgIT09IG51bGwgJiZcbiAgICAgICAgICAgICAgICAgICAgISh2YWx1ZSBpbnN0YW5jZW9mIEJvb2xlYW4pICYmXG4gICAgICAgICAgICAgICAgICAgICEodmFsdWUgaW5zdGFuY2VvZiBEYXRlKSAgICAmJlxuICAgICAgICAgICAgICAgICAgICAhKHZhbHVlIGluc3RhbmNlb2YgTnVtYmVyKSAgJiZcbiAgICAgICAgICAgICAgICAgICAgISh2YWx1ZSBpbnN0YW5jZW9mIFJlZ0V4cCkgICYmXG4gICAgICAgICAgICAgICAgICAgICEodmFsdWUgaW5zdGFuY2VvZiBTdHJpbmcpKSB7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgLyoqXG4gICAgICAgICAqIHJldHVybnMgdGhlIGluZGV4IG9mIHRoZSBnaXZlbiBvYmplY3QgaW4gdGhlXG4gICAgICAgICAqIGdpdmVuIG9iamVjdHMgYXJyYXksIC0xIGlmIG5vdCBjb250YWluZWRcbiAgICAgICAgICogb25seSBuZWVkZWQgZm9yIGN5Y2xpYyBsb2dpY1xuICAgICAgICAgKi9cbiAgICAgICAgZnVuY3Rpb24gZ2V0SW5kZXgob2JqZWN0cywgb2JqKSB7XG5cbiAgICAgICAgICAgIHZhciBpO1xuICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IG9iamVjdHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBpZiAob2JqZWN0c1tpXSA9PT0gb2JqKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG9lcyB0aGUgcmVjdXJzaW9uIGZvciB0aGUgZGVlcCBlcXVhbCBjaGVja1xuICAgICAgICByZXR1cm4gKGZ1bmN0aW9uIGRlZXBFcXVhbChvYmoxLCBvYmoyLCBwYXRoMSwgcGF0aDIpIHtcbiAgICAgICAgICAgIHZhciB0eXBlMSA9IHR5cGVvZiBvYmoxO1xuICAgICAgICAgICAgdmFyIHR5cGUyID0gdHlwZW9mIG9iajI7XG5cbiAgICAgICAgICAgIC8vID09IG51bGwgYWxzbyBtYXRjaGVzIHVuZGVmaW5lZFxuICAgICAgICAgICAgaWYgKG9iajEgPT09IG9iajIgfHxcbiAgICAgICAgICAgICAgICAgICAgaXNOYU4ob2JqMSkgfHwgaXNOYU4ob2JqMikgfHxcbiAgICAgICAgICAgICAgICAgICAgb2JqMSA9PSBudWxsIHx8IG9iajIgPT0gbnVsbCB8fFxuICAgICAgICAgICAgICAgICAgICB0eXBlMSAhPT0gXCJvYmplY3RcIiB8fCB0eXBlMiAhPT0gXCJvYmplY3RcIikge1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIGlkZW50aWNhbChvYmoxLCBvYmoyKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gRWxlbWVudHMgYXJlIG9ubHkgZXF1YWwgaWYgaWRlbnRpY2FsKGV4cGVjdGVkLCBhY3R1YWwpXG4gICAgICAgICAgICBpZiAoaXNFbGVtZW50KG9iajEpIHx8IGlzRWxlbWVudChvYmoyKSkgeyByZXR1cm4gZmFsc2U7IH1cblxuICAgICAgICAgICAgdmFyIGlzRGF0ZTEgPSBpc0RhdGUob2JqMSksIGlzRGF0ZTIgPSBpc0RhdGUob2JqMik7XG4gICAgICAgICAgICBpZiAoaXNEYXRlMSB8fCBpc0RhdGUyKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFpc0RhdGUxIHx8ICFpc0RhdGUyIHx8IG9iajEuZ2V0VGltZSgpICE9PSBvYmoyLmdldFRpbWUoKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAob2JqMSBpbnN0YW5jZW9mIFJlZ0V4cCAmJiBvYmoyIGluc3RhbmNlb2YgUmVnRXhwKSB7XG4gICAgICAgICAgICAgICAgaWYgKG9iajEudG9TdHJpbmcoKSAhPT0gb2JqMi50b1N0cmluZygpKSB7IHJldHVybiBmYWxzZTsgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgY2xhc3MxID0gZ2V0Q2xhc3Mob2JqMSk7XG4gICAgICAgICAgICB2YXIgY2xhc3MyID0gZ2V0Q2xhc3Mob2JqMik7XG4gICAgICAgICAgICB2YXIga2V5czEgPSBrZXlzKG9iajEpO1xuICAgICAgICAgICAgdmFyIGtleXMyID0ga2V5cyhvYmoyKTtcblxuICAgICAgICAgICAgaWYgKGlzQXJndW1lbnRzKG9iajEpIHx8IGlzQXJndW1lbnRzKG9iajIpKSB7XG4gICAgICAgICAgICAgICAgaWYgKG9iajEubGVuZ3RoICE9PSBvYmoyLmxlbmd0aCkgeyByZXR1cm4gZmFsc2U7IH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGUxICE9PSB0eXBlMiB8fCBjbGFzczEgIT09IGNsYXNzMiB8fFxuICAgICAgICAgICAgICAgICAgICAgICAga2V5czEubGVuZ3RoICE9PSBrZXlzMi5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGlzU2V0KG9iajEpIHx8IGlzU2V0KG9iajIpKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFpc1NldChvYmoxKSB8fCAhaXNTZXQob2JqMikgfHwgb2JqMS5zaXplICE9PSBvYmoyLnNpemUpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBpc1N1YnNldChvYmoxLCBvYmoyLCBkZWVwRXF1YWwpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIga2V5LCBpLCBsLFxuICAgICAgICAgICAgICAgIC8vIGZvbGxvd2luZyB2YXJzIGFyZSB1c2VkIGZvciB0aGUgY3ljbGljIGxvZ2ljXG4gICAgICAgICAgICAgICAgdmFsdWUxLCB2YWx1ZTIsXG4gICAgICAgICAgICAgICAgaXNPYmplY3QxLCBpc09iamVjdDIsXG4gICAgICAgICAgICAgICAgaW5kZXgxLCBpbmRleDIsXG4gICAgICAgICAgICAgICAgbmV3UGF0aDEsIG5ld1BhdGgyO1xuXG4gICAgICAgICAgICBmb3IgKGkgPSAwLCBsID0ga2V5czEubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgICAgICAgICAga2V5ID0ga2V5czFbaV07XG4gICAgICAgICAgICAgICAgaWYgKCFvLmhhc093blByb3BlcnR5LmNhbGwob2JqMiwga2V5KSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gU3RhcnQgb2YgdGhlIGN5Y2xpYyBsb2dpY1xuXG4gICAgICAgICAgICAgICAgdmFsdWUxID0gb2JqMVtrZXldO1xuICAgICAgICAgICAgICAgIHZhbHVlMiA9IG9iajJba2V5XTtcblxuICAgICAgICAgICAgICAgIGlzT2JqZWN0MSA9IGlzT2JqZWN0KHZhbHVlMSk7XG4gICAgICAgICAgICAgICAgaXNPYmplY3QyID0gaXNPYmplY3QodmFsdWUyKTtcblxuICAgICAgICAgICAgICAgIC8vIGRldGVybWluZSwgaWYgdGhlIG9iamVjdHMgd2VyZSBhbHJlYWR5IHZpc2l0ZWRcbiAgICAgICAgICAgICAgICAvLyAoaXQncyBmYXN0ZXIgdG8gY2hlY2sgZm9yIGlzT2JqZWN0IGZpcnN0LCB0aGFuIHRvXG4gICAgICAgICAgICAgICAgLy8gZ2V0IC0xIGZyb20gZ2V0SW5kZXggZm9yIG5vbiBvYmplY3RzKVxuICAgICAgICAgICAgICAgIGluZGV4MSA9IGlzT2JqZWN0MSA/IGdldEluZGV4KG9iamVjdHMxLCB2YWx1ZTEpIDogLTE7XG4gICAgICAgICAgICAgICAgaW5kZXgyID0gaXNPYmplY3QyID8gZ2V0SW5kZXgob2JqZWN0czIsIHZhbHVlMikgOiAtMTtcblxuICAgICAgICAgICAgICAgIC8vIGRldGVybWluZSB0aGUgbmV3IHBhdGhlcyBvZiB0aGUgb2JqZWN0c1xuICAgICAgICAgICAgICAgIC8vIC0gZm9yIG5vbiBjeWNsaWMgb2JqZWN0cyB0aGUgY3VycmVudCBwYXRoIHdpbGwgYmUgZXh0ZW5kZWRcbiAgICAgICAgICAgICAgICAvLyAgIGJ5IGN1cnJlbnQgcHJvcGVydHkgbmFtZVxuICAgICAgICAgICAgICAgIC8vIC0gZm9yIGN5Y2xpYyBvYmplY3RzIHRoZSBzdG9yZWQgcGF0aCBpcyB0YWtlblxuICAgICAgICAgICAgICAgIG5ld1BhdGgxID0gaW5kZXgxICE9PSAtMVxuICAgICAgICAgICAgICAgICAgICA/IHBhdGhzMVtpbmRleDFdXG4gICAgICAgICAgICAgICAgICAgIDogcGF0aDEgKyAnWycgKyBKU09OLnN0cmluZ2lmeShrZXkpICsgJ10nO1xuICAgICAgICAgICAgICAgIG5ld1BhdGgyID0gaW5kZXgyICE9PSAtMVxuICAgICAgICAgICAgICAgICAgICA/IHBhdGhzMltpbmRleDJdXG4gICAgICAgICAgICAgICAgICAgIDogcGF0aDIgKyAnWycgKyBKU09OLnN0cmluZ2lmeShrZXkpICsgJ10nO1xuXG4gICAgICAgICAgICAgICAgLy8gc3RvcCByZWN1cnNpb24gaWYgY3VycmVudCBvYmplY3RzIGFyZSBhbHJlYWR5IGNvbXBhcmVkXG4gICAgICAgICAgICAgICAgaWYgKGNvbXBhcmVkW25ld1BhdGgxICsgbmV3UGF0aDJdKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIHJlbWVtYmVyIHRoZSBjdXJyZW50IG9iamVjdHMgYW5kIHRoZWlyIHBhdGhlc1xuICAgICAgICAgICAgICAgIGlmIChpbmRleDEgPT09IC0xICYmIGlzT2JqZWN0MSkge1xuICAgICAgICAgICAgICAgICAgICBvYmplY3RzMS5wdXNoKHZhbHVlMSk7XG4gICAgICAgICAgICAgICAgICAgIHBhdGhzMS5wdXNoKG5ld1BhdGgxKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKGluZGV4MiA9PT0gLTEgJiYgaXNPYmplY3QyKSB7XG4gICAgICAgICAgICAgICAgICAgIG9iamVjdHMyLnB1c2godmFsdWUyKTtcbiAgICAgICAgICAgICAgICAgICAgcGF0aHMyLnB1c2gobmV3UGF0aDIpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIHJlbWVtYmVyIHRoYXQgdGhlIGN1cnJlbnQgb2JqZWN0cyBhcmUgYWxyZWFkeSBjb21wYXJlZFxuICAgICAgICAgICAgICAgIGlmIChpc09iamVjdDEgJiYgaXNPYmplY3QyKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbXBhcmVkW25ld1BhdGgxICsgbmV3UGF0aDJdID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBFbmQgb2YgY3ljbGljIGxvZ2ljXG5cbiAgICAgICAgICAgICAgICAvLyBuZWl0aGVyIHZhbHVlMSBub3IgdmFsdWUyIGlzIGEgY3ljbGVcbiAgICAgICAgICAgICAgICAvLyBjb250aW51ZSB3aXRoIG5leHQgbGV2ZWxcbiAgICAgICAgICAgICAgICBpZiAoIWRlZXBFcXVhbCh2YWx1ZTEsIHZhbHVlMiwgbmV3UGF0aDEsIG5ld1BhdGgyKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcblxuICAgICAgICB9KG9iajEsIG9iajIsICckMScsICckMicpKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBhcnJheUNvbnRhaW5zKGFycmF5LCBzdWJzZXQsIGNvbXBhcmUpIHtcbiAgICAgICAgaWYgKHN1YnNldC5sZW5ndGggPT09IDApIHsgcmV0dXJuIHRydWU7IH1cbiAgICAgICAgdmFyIGksIGwsIGosIGs7XG4gICAgICAgIGZvciAoaSA9IDAsIGwgPSBhcnJheS5sZW5ndGg7IGkgPCBsOyArK2kpIHtcbiAgICAgICAgICAgIGlmIChjb21wYXJlKGFycmF5W2ldLCBzdWJzZXRbMF0pKSB7XG4gICAgICAgICAgICAgICAgZm9yIChqID0gMCwgayA9IHN1YnNldC5sZW5ndGg7IGogPCBrOyArK2opIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKChpICsgaikgPj0gbCkgeyByZXR1cm4gZmFsc2U7IH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKCFjb21wYXJlKGFycmF5W2kgKyBqXSwgc3Vic2V0W2pdKSkgeyByZXR1cm4gZmFsc2U7IH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBuYW1lIHNhbXNhbS5tYXRjaFxuICAgICAqIEBwYXJhbSBPYmplY3Qgb2JqZWN0XG4gICAgICogQHBhcmFtIE9iamVjdCBtYXRjaGVyXG4gICAgICpcbiAgICAgKiBDb21wYXJlIGFyYml0cmFyeSB2YWx1ZSBgYG9iamVjdGBgIHdpdGggbWF0Y2hlci5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBtYXRjaChvYmplY3QsIG1hdGNoZXIpIHtcbiAgICAgICAgaWYgKG1hdGNoZXIgJiYgdHlwZW9mIG1hdGNoZXIudGVzdCA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICByZXR1cm4gbWF0Y2hlci50ZXN0KG9iamVjdCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIG1hdGNoZXIgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgcmV0dXJuIG1hdGNoZXIob2JqZWN0KSA9PT0gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgbWF0Y2hlciA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgbWF0Y2hlciA9IG1hdGNoZXIudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgICAgIHZhciBub3ROdWxsID0gdHlwZW9mIG9iamVjdCA9PT0gXCJzdHJpbmdcIiB8fCAhIW9iamVjdDtcbiAgICAgICAgICAgIHJldHVybiBub3ROdWxsICYmXG4gICAgICAgICAgICAgICAgKFN0cmluZyhvYmplY3QpKS50b0xvd2VyQ2FzZSgpLmluZGV4T2YobWF0Y2hlcikgPj0gMDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgbWF0Y2hlciA9PT0gXCJudW1iZXJcIikge1xuICAgICAgICAgICAgcmV0dXJuIG1hdGNoZXIgPT09IG9iamVjdDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgbWF0Y2hlciA9PT0gXCJib29sZWFuXCIpIHtcbiAgICAgICAgICAgIHJldHVybiBtYXRjaGVyID09PSBvYmplY3Q7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mKG1hdGNoZXIpID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgICByZXR1cm4gdHlwZW9mKG9iamVjdCkgPT09IFwidW5kZWZpbmVkXCI7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAobWF0Y2hlciA9PT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIG9iamVjdCA9PT0gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChpc1NldChvYmplY3QpKSB7XG4gICAgICAgICAgICByZXR1cm4gaXNTdWJzZXQobWF0Y2hlciwgb2JqZWN0LCBtYXRjaCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoZ2V0Q2xhc3Mob2JqZWN0KSA9PT0gXCJBcnJheVwiICYmIGdldENsYXNzKG1hdGNoZXIpID09PSBcIkFycmF5XCIpIHtcbiAgICAgICAgICAgIHJldHVybiBhcnJheUNvbnRhaW5zKG9iamVjdCwgbWF0Y2hlciwgbWF0Y2gpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKG1hdGNoZXIgJiYgdHlwZW9mIG1hdGNoZXIgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgICAgIGlmIChtYXRjaGVyID09PSBvYmplY3QpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBwcm9wO1xuICAgICAgICAgICAgZm9yIChwcm9wIGluIG1hdGNoZXIpIHtcbiAgICAgICAgICAgICAgICB2YXIgdmFsdWUgPSBvYmplY3RbcHJvcF07XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJ1bmRlZmluZWRcIiAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgdHlwZW9mIG9iamVjdC5nZXRBdHRyaWJ1dGUgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IG9iamVjdC5nZXRBdHRyaWJ1dGUocHJvcCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChtYXRjaGVyW3Byb3BdID09PSBudWxsIHx8IHR5cGVvZiBtYXRjaGVyW3Byb3BdID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgICAgICAgICBpZiAodmFsdWUgIT09IG1hdGNoZXJbcHJvcF0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodHlwZW9mICB2YWx1ZSA9PT0gXCJ1bmRlZmluZWRcIiB8fCAhbWF0Y2godmFsdWUsIG1hdGNoZXJbcHJvcF0pKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIk1hdGNoZXIgd2FzIG5vdCBhIHN0cmluZywgYSBudW1iZXIsIGEgXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgXCJmdW5jdGlvbiwgYSBib29sZWFuIG9yIGFuIG9iamVjdFwiKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgICBpc0FyZ3VtZW50czogaXNBcmd1bWVudHMsXG4gICAgICAgIGlzRWxlbWVudDogaXNFbGVtZW50LFxuICAgICAgICBpc0RhdGU6IGlzRGF0ZSxcbiAgICAgICAgaXNOZWdaZXJvOiBpc05lZ1plcm8sXG4gICAgICAgIGlkZW50aWNhbDogaWRlbnRpY2FsLFxuICAgICAgICBkZWVwRXF1YWw6IGRlZXBFcXVhbEN5Y2xpYyxcbiAgICAgICAgbWF0Y2g6IG1hdGNoLFxuICAgICAgICBrZXlzOiBrZXlzXG4gICAgfTtcbn0pO1xuIiwiLy8gVGhpcyBpcyBmcmVlIGFuZCB1bmVuY3VtYmVyZWQgc29mdHdhcmUgcmVsZWFzZWQgaW50byB0aGUgcHVibGljIGRvbWFpbi5cbi8vIFNlZSBMSUNFTlNFLm1kIGZvciBtb3JlIGluZm9ybWF0aW9uLlxuXG52YXIgZW5jb2RpbmcgPSByZXF1aXJlKFwiLi9saWIvZW5jb2RpbmcuanNcIik7XG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBUZXh0RW5jb2RlcjogZW5jb2RpbmcuVGV4dEVuY29kZXIsXG4gIFRleHREZWNvZGVyOiBlbmNvZGluZy5UZXh0RGVjb2Rlcixcbn07XG4iLCIoZnVuY3Rpb24oZ2xvYmFsKSB7XG4gICd1c2Ugc3RyaWN0JztcblxuICBpZiAodHlwZW9mIG1vZHVsZSAhPT0gXCJ1bmRlZmluZWRcIiAmJiBtb2R1bGUuZXhwb3J0cykge1xuICAgIG1vZHVsZS5leHBvcnRzID0gZ2xvYmFsO1xuICB9XG5cbiAgZ2xvYmFsW1wiZW5jb2RpbmctaW5kZXhlc1wiXSA9XG57XG4gIFwiYmlnNVwiOltudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCwxNzM5MiwxOTUwNiwxNzkyMywxNzgzMCwxNzc4NCwxNjAzNTksMTk4MzEsMTc4NDMsMTYyOTkzLDE5NjgyLDE2MzAxMywxNTI1MywxODIzMCwxODI0NCwxOTUyNywxOTUyMCwxNDgxNTksMTQ0OTE5LDE2MDU5NCwxNTkzNzEsMTU5OTU0LDE5NTQzLDE3Mjg4MSwxODI1NSwxNzg4MiwxOTU4OSwxNjI5MjQsMTk3MTksMTkxMDgsMTgwODEsMTU4NDk5LDI5MjIxLDE1NDE5NiwxMzc4MjcsMTQ2OTUwLDE0NzI5NywyNjE4OSwyMjI2NyxudWxsLDMyMTQ5LDIyODEzLDE2Njg0MSwxNTg2MCwzODcwOCwxNjI3OTksMjM1MTUsMTM4NTkwLDIzMjA0LDEzODYxLDE3MTY5NiwyMzI0OSwyMzQ3OSwyMzgwNCwyNjQ3OCwzNDE5NSwxNzAzMDksMjk3OTMsMjk4NTMsMTQ0NTMsMTM4NTc5LDE0NTA1NCwxNTU2ODEsMTYxMDgsMTUzODIyLDE1MDkzLDMxNDg0LDQwODU1LDE0NzgwOSwxNjYxNTcsMTQzODUwLDEzMzc3MCwxNDM5NjYsMTcxNjIsMzM5MjQsNDA4NTQsMzc5MzUsMTg3MzYsMzQzMjMsMjI2NzgsMzg3MzAsMzc0MDAsMzExODQsMzEyODIsMjYyMDgsMjcxNzcsMzQ5NzMsMjk3NzIsMzE2ODUsMjY0OTgsMzEyNzYsMjEwNzEsMzY5MzQsMTM1NDIsMjk2MzYsMTU1MDY1LDI5ODk0LDQwOTAzLDIyNDUxLDE4NzM1LDIxNTgwLDE2Njg5LDE0NTAzOCwyMjU1MiwzMTM0NiwxNjI2NjEsMzU3MjcsMTgwOTQsMTU5MzY4LDE2NzY5LDE1NTAzMywzMTY2MiwxNDA0NzYsNDA5MDQsMTQwNDgxLDE0MDQ4OSwxNDA0OTIsNDA5MDUsMzQwNTIsMTQ0ODI3LDE2NTY0LDQwOTA2LDE3NjMzLDE3NTYxNSwyNTI4MSwyODc4Miw0MDkwNyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDEyNzM2LDEyNzM3LDEyNzM4LDEyNzM5LDEyNzQwLDEzMTM0MCwxMjc0MSwxMzEyODEsMTMxMjc3LDEyNzQyLDEyNzQzLDEzMTI3NSwxMzkyNDAsMTI3NDQsMTMxMjc0LDEyNzQ1LDEyNzQ2LDEyNzQ3LDEyNzQ4LDEzMTM0MiwxMjc0OSwxMjc1MCwyNTYsMTkzLDQ2MSwxOTIsMjc0LDIwMSwyODIsMjAwLDMzMiwyMTEsNDY1LDIxMCxudWxsLDc4NzAsbnVsbCw3ODcyLDIwMiwyNTcsMjI1LDQ2MiwyMjQsNTkzLDI3NSwyMzMsMjgzLDIzMiwyOTksMjM3LDQ2NCwyMzYsMzMzLDI0Myw0NjYsMjQyLDM2MywyNTAsNDY4LDI0OSw0NzAsNDcyLDQ3NCw0NzYsMjUyLG51bGwsNzg3MSxudWxsLDc4NzMsMjM0LDYwOSw5MTc4LDkxNzksbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsMTcyOTY5LDEzNTQ5MyxudWxsLDI1ODY2LG51bGwsbnVsbCwyMDAyOSwyODM4MSw0MDI3MCwzNzM0MyxudWxsLG51bGwsMTYxNTg5LDI1NzQ1LDIwMjUwLDIwMjY0LDIwMzkyLDIwODIyLDIwODUyLDIwODkyLDIwOTY0LDIxMTUzLDIxMTYwLDIxMzA3LDIxMzI2LDIxNDU3LDIxNDY0LDIyMjQyLDIyNzY4LDIyNzg4LDIyNzkxLDIyODM0LDIyODM2LDIzMzk4LDIzNDU0LDIzNDU1LDIzNzA2LDI0MTk4LDI0NjM1LDI1OTkzLDI2NjIyLDI2NjI4LDI2NzI1LDI3OTgyLDI4ODYwLDMwMDA1LDMyNDIwLDMyNDI4LDMyNDQyLDMyNDU1LDMyNDYzLDMyNDc5LDMyNTE4LDMyNTY3LDMzNDAyLDMzNDg3LDMzNjQ3LDM1MjcwLDM1Nzc0LDM1ODEwLDM2NzEwLDM2NzExLDM2NzE4LDI5NzEzLDMxOTk2LDMyMjA1LDI2OTUwLDMxNDMzLDIxMDMxLG51bGwsbnVsbCxudWxsLG51bGwsMzcyNjAsMzA5MDQsMzcyMTQsMzI5NTYsbnVsbCwzNjEwNywzMzAxNCwxMzM2MDcsbnVsbCxudWxsLDMyOTI3LDQwNjQ3LDE5NjYxLDQwMzkzLDQwNDYwLDE5NTE4LDE3MTUxMCwxNTk3NTgsNDA0NTgsMTcyMzM5LDEzNzYxLG51bGwsMjgzMTQsMzMzNDIsMjk5NzcsbnVsbCwxODcwNSwzOTUzMiwzOTU2Nyw0MDg1NywzMTExMSwxNjQ5NzIsMTM4Njk4LDEzMjU2MCwxNDIwNTQsMjAwMDQsMjAwOTcsMjAwOTYsMjAxMDMsMjAxNTksMjAyMDMsMjAyNzksMTMzODgsMjA0MTMsMTU5NDQsMjA0ODMsMjA2MTYsMTM0MzcsMTM0NTksMTM0NzcsMjA4NzAsMjI3ODksMjA5NTUsMjA5ODgsMjA5OTcsMjAxMDUsMjExMTMsMjExMzYsMjEyODcsMTM3NjcsMjE0MTcsMTM2NDksMjE0MjQsMTM2NTEsMjE0NDIsMjE1MzksMTM2NzcsMTM2ODIsMTM5NTMsMjE2NTEsMjE2NjcsMjE2ODQsMjE2ODksMjE3MTIsMjE3NDMsMjE3ODQsMjE3OTUsMjE4MDAsMTM3MjAsMjE4MjMsMTM3MzMsMTM3NTksMjE5NzUsMTM3NjUsMTYzMjA0LDIxNzk3LG51bGwsMTM0MjEwLDEzNDQyMSwxNTE4NTEsMjE5MDQsMTQyNTM0LDE0ODI4LDEzMTkwNSwzNjQyMiwxNTA5NjgsMTY5MTg5LDE2NDY3LDE2NDAzMCwzMDU4NiwxNDIzOTIsMTQ5MDAsMTgzODksMTY0MTg5LDE1ODE5NCwxNTEwMTgsMjU4MjEsMTM0NTI0LDEzNTA5MiwxMzQzNTcsMTM1NDEyLDI1NzQxLDM2NDc4LDEzNDgwNiwxMzQxNTUsMTM1MDEyLDE0MjUwNSwxNjQ0MzgsMTQ4NjkxLG51bGwsMTM0NDcwLDE3MDU3MywxNjQwNzMsMTg0MjAsMTUxMjA3LDE0MjUzMCwzOTYwMiwxNDk1MSwxNjk0NjAsMTYzNjUsMTM1NzQsMTUyMjYzLDE2OTk0MCwxNjE5OTIsMTQyNjYwLDQwMzAyLDM4OTMzLG51bGwsMTczNjksMTU1ODEzLDI1NzgwLDIxNzMxLDE0MjY2OCwxNDIyODIsMTM1Mjg3LDE0ODQzLDEzNTI3OSwxNTc0MDIsMTU3NDYyLDE2MjIwOCwyNTgzNCwxNTE2MzQsMTM0MjExLDM2NDU2LDEzOTY4MSwxNjY3MzIsMTMyOTEzLG51bGwsMTg0NDMsMTMxNDk3LDE2Mzc4LDIyNjQzLDE0MjczMyxudWxsLDE0ODkzNiwxMzIzNDgsMTU1Nzk5LDEzNDk4OCwxMzQ1NTAsMjE4ODEsMTY1NzEsMTczMzgsbnVsbCwxOTEyNCwxNDE5MjYsMTM1MzI1LDMzMTk0LDM5MTU3LDEzNDU1NiwyNTQ2NSwxNDg0NiwxNDExNzMsMzYyODgsMjIxNzcsMjU3MjQsMTU5MzksbnVsbCwxNzM1NjksMTM0NjY1LDE0MjAzMSwxNDI1MzcsbnVsbCwxMzUzNjgsMTQ1ODU4LDE0NzM4LDE0ODU0LDE2NDUwNywxMzY4OCwxNTUyMDksMTM5NDYzLDIyMDk4LDEzNDk2MSwxNDI1MTQsMTY5NzYwLDEzNTAwLDI3NzA5LDE1MTA5OSxudWxsLG51bGwsMTYxMTQwLDE0Mjk4NywxMzk3ODQsMTczNjU5LDE2NzExNywxMzQ3NzgsMTM0MTk2LDE1NzcyNCwzMjY1OSwxMzUzNzUsMTQxMzE1LDE0MTYyNSwxMzgxOSwxNTIwMzUsMTM0Nzk2LDEzNTA1MywxMzQ4MjYsMTYyNzUsMTM0OTYwLDEzNDQ3MSwxMzU1MDMsMTM0NzMyLG51bGwsMTM0ODI3LDEzNDA1NywxMzQ0NzIsMTM1MzYwLDEzNTQ4NSwxNjM3NywxNDA5NTAsMjU2NTAsMTM1MDg1LDE0NDM3MiwxNjEzMzcsMTQyMjg2LDEzNDUyNiwxMzQ1MjcsMTQyNDE3LDE0MjQyMSwxNDg3MiwxMzQ4MDgsMTM1MzY3LDEzNDk1OCwxNzM2MTgsMTU4NTQ0LDE2NzEyMiwxNjczMjEsMTY3MTE0LDM4MzE0LDIxNzA4LDMzNDc2LDIxOTQ1LG51bGwsMTcxNzE1LDM5OTc0LDM5NjA2LDE2MTYzMCwxNDI4MzAsMjg5OTIsMzMxMzMsMzMwMDQsMjM1ODAsMTU3MDQyLDMzMDc2LDE0MjMxLDIxMzQzLDE2NDAyOSwzNzMwMiwxMzQ5MDYsMTM0NjcxLDEzNDc3NSwxMzQ5MDcsMTM3ODksMTUxMDE5LDEzODMzLDEzNDM1OCwyMjE5MSwxNDEyMzcsMTM1MzY5LDEzNDY3MiwxMzQ3NzYsMTM1Mjg4LDEzNTQ5NiwxNjQzNTksMTM2Mjc3LDEzNDc3NywxNTExMjAsMTQyNzU2LDIzMTI0LDEzNTE5NywxMzUxOTgsMTM1NDEzLDEzNTQxNCwyMjQyOCwxMzQ2NzMsMTYxNDI4LDE2NDU1NywxMzUwOTMsMTM0Nzc5LDE1MTkzNCwxNDA4MywxMzUwOTQsMTM1NTUyLDE1MjI4MCwxNzI3MzMsMTQ5OTc4LDEzNzI3NCwxNDc4MzEsMTY0NDc2LDIyNjgxLDIxMDk2LDEzODUwLDE1MzQwNSwzMTY2NiwyMzQwMCwxODQzMiwxOTI0NCw0MDc0MywxODkxOSwzOTk2NywzOTgyMSwxNTQ0ODQsMTQzNjc3LDIyMDExLDEzODEwLDIyMTUzLDIwMDA4LDIyNzg2LDEzODE3NywxOTQ2ODAsMzg3MzcsMTMxMjA2LDIwMDU5LDIwMTU1LDEzNjMwLDIzNTg3LDI0NDAxLDI0NTE2LDE0NTg2LDI1MTY0LDI1OTA5LDI3NTE0LDI3NzAxLDI3NzA2LDI4NzgwLDI5MjI3LDIwMDEyLDI5MzU3LDE0OTczNywzMjU5NCwzMTAzNSwzMTk5MywzMjU5NSwxNTYyNjYsMTM1MDUsbnVsbCwxNTY0OTEsMzI3NzAsMzI4OTYsMTU3MjAyLDE1ODAzMywyMTM0MSwzNDkxNiwzNTI2NSwxNjE5NzAsMzU3NDQsMzYxMjUsMzgwMjEsMzgyNjQsMzgyNzEsMzgzNzYsMTY3NDM5LDM4ODg2LDM5MDI5LDM5MTE4LDM5MTM0LDM5MjY3LDE3MDAwMCw0MDA2MCw0MDQ3OSw0MDY0NCwyNzUwMyw2Mzc1MSwyMDAyMywxMzEyMDcsMzg0MjksMjUxNDMsMzgwNTAsbnVsbCwyMDUzOSwyODE1OCwxNzExMjMsNDA4NzAsMTU4MTcsMzQ5NTksMTQ3NzkwLDI4NzkxLDIzNzk3LDE5MjMyLDE1MjAxMywxMzY1NywxNTQ5MjgsMjQ4NjYsMTY2NDUwLDM2Nzc1LDM3MzY2LDI5MDczLDI2MzkzLDI5NjI2LDE0NDAwMSwxNzIyOTUsMTU0OTksMTM3NjAwLDE5MjE2LDMwOTQ4LDI5Njk4LDIwOTEwLDE2NTY0NywxNjM5MywyNzIzNSwxNzI3MzAsMTY5MzEsMzQzMTksMTMzNzQzLDMxMjc0LDE3MDMxMSwxNjY2MzQsMzg3NDEsMjg3NDksMjEyODQsMTM5MzkwLDM3ODc2LDMwNDI1LDE2NjM3MSw0MDg3MSwzMDY4NSwyMDEzMSwyMDQ2NCwyMDY2OCwyMDAxNSwyMDI0Nyw0MDg3MiwyMTU1NiwzMjEzOSwyMjY3NCwyMjczNiwxMzg2NzgsMjQyMTAsMjQyMTcsMjQ1MTQsMTQxMDc0LDI1OTk1LDE0NDM3NywyNjkwNSwyNzIwMywxNDY1MzEsMjc5MDMsbnVsbCwyOTE4NCwxNDg3NDEsMjk1ODAsMTYwOTEsMTUwMDM1LDIzMzE3LDI5ODgxLDM1NzE1LDE1NDc4OCwxNTMyMzcsMzEzNzksMzE3MjQsMzE5MzksMzIzNjQsMzM1MjgsMzQxOTksNDA4NzMsMzQ5NjAsNDA4NzQsMzY1MzcsNDA4NzUsMzY4MTUsMzQxNDMsMzkzOTIsMzc0MDksNDA4NzYsMTY3MzUzLDEzNjI1NSwxNjQ5NywxNzA1OCwyMzA2NixudWxsLG51bGwsbnVsbCwzOTAxNiwyNjQ3NSwxNzAxNCwyMjMzMyxudWxsLDM0MjYyLDE0OTg4MywzMzQ3MSwxNjAwMTMsMTk1ODUsMTU5MDkyLDIzOTMxLDE1ODQ4NSwxNTk2NzgsNDA4NzcsNDA4NzgsMjM0NDYsNDA4NzksMjYzNDMsMzIzNDcsMjgyNDcsMzExNzgsMTU3NTIsMTc2MDMsMTQzOTU4LDE0MTIwNiwxNzMwNiwxNzcxOCxudWxsLDIzNzY1LDE0NjIwMiwzNTU3NywyMzY3MiwxNTYzNCwxNDQ3MjEsMjM5MjgsNDA4ODIsMjkwMTUsMTc3NTIsMTQ3NjkyLDEzODc4NywxOTU3NSwxNDcxMiwxMzM4NiwxMzE0OTIsMTU4Nzg1LDM1NTMyLDIwNDA0LDEzMTY0MSwyMjk3NSwzMzEzMiwzODk5OCwxNzAyMzQsMjQzNzksMTM0MDQ3LG51bGwsMTM5NzEzLDE2NjI1MywxNjY0MiwxODEwNywxNjgwNTcsMTYxMzUsNDA4ODMsMTcyNDY5LDE2NjMyLDE0Mjk0LDE4MTY3LDE1ODc5MCwxNjc2NCwxNjU1NTQsMTYwNzY3LDE3NzczLDE0NTQ4LDE1MjczMCwxNzc2MSwxNzY5MSwxOTg0OSwxOTU3OSwxOTgzMCwxNzg5OCwxNjMyOCwxNTAyODcsMTM5MjEsMTc2MzAsMTc1OTcsMTY4NzcsMjM4NzAsMjM4ODAsMjM4OTQsMTU4NjgsMTQzNTEsMjM5NzIsMjM5OTMsMTQzNjgsMTQzOTIsMjQxMzAsMjQyNTMsMjQzNTcsMjQ0NTEsMTQ2MDAsMTQ2MTIsMTQ2NTUsMTQ2NjksMjQ3OTEsMjQ4OTMsMjM3ODEsMTQ3MjksMjUwMTUsMjUwMTcsMjUwMzksMTQ3NzYsMjUxMzIsMjUyMzIsMjUzMTcsMjUzNjgsMTQ4NDAsMjIxOTMsMTQ4NTEsMjU1NzAsMjU1OTUsMjU2MDcsMjU2OTAsMTQ5MjMsMjU3OTIsMjM4MjksMjIwNDksNDA4NjMsMTQ5OTksMjU5OTAsMTUwMzcsMjYxMTEsMjYxOTUsMTUwOTAsMjYyNTgsMTUxMzgsMjYzOTAsMTUxNzAsMjY1MzIsMjY2MjQsMTUxOTIsMjY2OTgsMjY3NTYsMTUyMTgsMTUyMTcsMTUyMjcsMjY4ODksMjY5NDcsMjkyNzYsMjY5ODAsMjcwMzksMjcwMTMsMTUyOTIsMjcwOTQsMTUzMjUsMjcyMzcsMjcyNTIsMjcyNDksMjcyNjYsMTUzNDAsMjcyODksMTUzNDYsMjczMDcsMjczMTcsMjczNDgsMjczODIsMjc1MjEsMjc1ODUsMjc2MjYsMjc3NjUsMjc4MTgsMTU1NjMsMjc5MDYsMjc5MTAsMjc5NDIsMjgwMzMsMTU1OTksMjgwNjgsMjgwODEsMjgxODEsMjgxODQsMjgyMDEsMjgyOTQsMTY2MzM2LDI4MzQ3LDI4Mzg2LDI4Mzc4LDQwODMxLDI4MzkyLDI4MzkzLDI4NDUyLDI4NDY4LDE1Njg2LDE0NzI2NSwyODU0NSwyODYwNiwxNTcyMiwxNTczMywyOTExMSwyMzcwNSwxNTc1NCwyODcxNiwxNTc2MSwyODc1MiwyODc1NiwyODc4MywyODc5OSwyODgwOSwxMzE4NzcsMTczNDUsMTM4MDksMTM0ODcyLDE0NzE1OSwyMjQ2MiwxNTk0NDMsMjg5OTAsMTUzNTY4LDEzOTAyLDI3MDQyLDE2Njg4OSwyMzQxMiwzMTMwNSwxNTM4MjUsMTY5MTc3LDMxMzMzLDMxMzU3LDE1NDAyOCwzMTQxOSwzMTQwOCwzMTQyNiwzMTQyNywyOTEzNywxNTY4MTMsMTY4NDIsMzE0NTAsMzE0NTMsMzE0NjYsMTY4NzksMjE2ODIsMTU0NjI1LDMxNDk5LDMxNTczLDMxNTI5LDE1MjMzNCwxNTQ4NzgsMzE2NTAsMzE1OTksMzM2OTIsMTU0NTQ4LDE1ODg0NywzMTY5NiwzMzgyNSwzMTYzNCwzMTY3MiwxNTQ5MTIsMTU3ODksMTU0NzI1LDMzOTM4LDMxNzM4LDMxNzUwLDMxNzk3LDE1NDgxNywzMTgxMiwzMTg3NSwxNDk2MzQsMzE5MTAsMjYyMzcsMTQ4ODU2LDMxOTQ1LDMxOTQzLDMxOTc0LDMxODYwLDMxOTg3LDMxOTg5LDMxOTUwLDMyMzU5LDE3NjkzLDE1OTMwMCwzMjA5MywxNTk0NDYsMjk4MzcsMzIxMzcsMzIxNzEsMjg5ODEsMzIxNzksMzIyMTAsMTQ3NTQzLDE1NTY4OSwzMjIyOCwxNTYzNSwzMjI0NSwxMzcyMDksMzIyMjksMTY0NzE3LDMyMjg1LDE1NTkzNywxNTU5OTQsMzIzNjYsMzI0MDIsMTcxOTUsMzc5OTYsMzIyOTUsMzI1NzYsMzI1NzcsMzI1ODMsMzEwMzAsMTU2MzY4LDM5MzkzLDMyNjYzLDE1NjQ5NywzMjY3NSwxMzY4MDEsMTMxMTc2LDE3NzU2LDE0NTI1NCwxNzY2NywxNjQ2NjYsMzI3NjIsMTU2ODA5LDMyNzczLDMyNzc2LDMyNzk3LDMyODA4LDMyODE1LDE3MjE2NywxNTg5MTUsMzI4MjcsMzI4MjgsMzI4NjUsMTQxMDc2LDE4ODI1LDE1NzIyMiwxNDY5MTUsMTU3NDE2LDI2NDA1LDMyOTM1LDE2NjQ3MiwzMzAzMSwzMzA1MCwyMjcwNCwxNDEwNDYsMjc3NzUsMTU2ODI0LDE1MTQ4MCwyNTgzMSwxMzYzMzAsMzMzMDQsMTM3MzEwLDI3MjE5LDE1MDExNywxNTAxNjUsMTc1MzAsMzMzMjEsMTMzOTAxLDE1ODI5MCwxNDY4MTQsMjA0NzMsMTM2NDQ1LDM0MDE4LDMzNjM0LDE1ODQ3NCwxNDk5MjcsMTQ0Njg4LDEzNzA3NSwxNDY5MzYsMzM0NTAsMjY5MDcsMTk0OTY0LDE2ODU5LDM0MTIzLDMzNDg4LDMzNTYyLDEzNDY3OCwxMzcxNDAsMTQwMTcsMTQzNzQxLDE0NDczMCwzMzQwMywzMzUwNiwzMzU2MCwxNDcwODMsMTU5MTM5LDE1ODQ2OSwxNTg2MTUsMTQ0ODQ2LDE1ODA3LDMzNTY1LDIxOTk2LDMzNjY5LDE3Njc1LDE1OTE0MSwzMzcwOCwzMzcyOSwzMzc0NywxMzQzOCwxNTk0NDQsMjcyMjMsMzQxMzgsMTM0NjIsMTU5Mjk4LDE0MzA4NywzMzg4MCwxNTQ1OTYsMzM5MDUsMTU4MjcsMTc2MzYsMjczMDMsMzM4NjYsMTQ2NjEzLDMxMDY0LDMzOTYwLDE1ODYxNCwxNTkzNTEsMTU5Mjk5LDM0MDE0LDMzODA3LDMzNjgxLDE3NTY4LDMzOTM5LDM0MDIwLDE1NDc2OSwxNjk2MCwxNTQ4MTYsMTc3MzEsMzQxMDAsMjMyODIsMTU5Mzg1LDE3NzAzLDM0MTYzLDE3Njg2LDI2NTU5LDM0MzI2LDE2NTQxMywxNjU0MzUsMzQyNDEsMTU5ODgwLDM0MzA2LDEzNjU3OCwxNTk5NDksMTk0OTk0LDE3NzcwLDM0MzQ0LDEzODk2LDEzNzM3OCwyMTQ5NSwxNjA2NjYsMzQ0MzAsMzQ2NzMsMTcyMjgwLDM0Nzk4LDE0MjM3NSwzNDczNywzNDc3OCwzNDgzMSwyMjExMywzNDQxMiwyNjcxMCwxNzkzNSwzNDg4NSwzNDg4NiwxNjEyNDgsMTQ2ODczLDE2MTI1MiwzNDkxMCwzNDk3MiwxODAxMSwzNDk5NiwzNDk5NywyNTUzNywzNTAxMywzMDU4MywxNjE1NTEsMzUyMDcsMzUyMTAsMzUyMzgsMzUyNDEsMzUyMzksMzUyNjAsMTY2NDM3LDM1MzAzLDE2MjA4NCwxNjI0OTMsMzU0ODQsMzA2MTEsMzczNzQsMzU0NzIsMTYyMzkzLDMxNDY1LDE2MjYxOCwxNDczNDMsMTgxOTUsMTYyNjE2LDI5MDUyLDM1NTk2LDM1NjE1LDE1MjYyNCwxNTI5MzMsMzU2NDcsMzU2NjAsMzU2NjEsMzU0OTcsMTUwMTM4LDM1NzI4LDM1NzM5LDM1NTAzLDEzNjkyNywxNzk0MSwzNDg5NSwzNTk5NSwxNjMxNTYsMTYzMjE1LDE5NTAyOCwxNDExNywxNjMxNTUsMzYwNTQsMTYzMjI0LDE2MzI2MSwzNjExNCwzNjA5OSwxMzc0ODgsMzYwNTksMjg3NjQsMzYxMTMsMTUwNzI5LDE2MDgwLDM2MjE1LDM2MjY1LDE2Mzg0MiwxMzUxODgsMTQ5ODk4LDE1MjI4LDE2NDI4NCwxNjAwMTIsMzE0NjMsMzY1MjUsMzY1MzQsMzY1NDcsMzc1ODgsMzY2MzMsMzY2NTMsMTY0NzA5LDE2NDg4MiwzNjc3MywzNzYzNSwxNzI3MDMsMTMzNzEyLDM2Nzg3LDE4NzMwLDE2NjM2NiwxNjUxODEsMTQ2ODc1LDI0MzEyLDE0Mzk3MCwzNjg1NywxNzIwNTIsMTY1NTY0LDE2NTEyMSwxNDAwNjksMTQ3MjAsMTU5NDQ3LDM2OTE5LDE2NTE4MCwxNjI0OTQsMzY5NjEsMTY1MjI4LDE2NTM4NywzNzAzMiwxNjU2NTEsMzcwNjAsMTY1NjA2LDM3MDM4LDM3MTE3LDM3MjIzLDE1MDg4LDM3Mjg5LDM3MzE2LDMxOTE2LDE2NjE5NSwxMzg4ODksMzczOTAsMjc4MDcsMzc0NDEsMzc0NzQsMTUzMDE3LDM3NTYxLDE2NjU5OCwxNDY1ODcsMTY2NjY4LDE1MzA1MSwxMzQ0NDksMzc2NzYsMzc3MzksMTY2NjI1LDE2Njg5MSwyODgxNSwyMzIzNSwxNjY2MjYsMTY2NjI5LDE4Nzg5LDM3NDQ0LDE2Njg5MiwxNjY5NjksMTY2OTExLDM3NzQ3LDM3OTc5LDM2NTQwLDM4Mjc3LDM4MzEwLDM3OTI2LDM4MzA0LDI4NjYyLDE3MDgxLDE0MDkyMiwxNjU1OTIsMTM1ODA0LDE0Njk5MCwxODkxMSwyNzY3NiwzODUyMywzODU1MCwxNjc0OCwzODU2MywxNTk0NDUsMjUwNTAsMzg1ODIsMzA5NjUsMTY2NjI0LDM4NTg5LDIxNDUyLDE4ODQ5LDE1ODkwNCwxMzE3MDAsMTU2Njg4LDE2ODExMSwxNjgxNjUsMTUwMjI1LDEzNzQ5MywxNDQxMzgsMzg3MDUsMzQzNzAsMzg3MTAsMTg5NTksMTc3MjUsMTc3OTcsMTUwMjQ5LDI4Nzg5LDIzMzYxLDM4NjgzLDM4NzQ4LDE2ODQwNSwzODc0MywyMzM3MCwxNjg0MjcsMzg3NTEsMzc5MjUsMjA2ODgsMTQzNTQzLDE0MzU0OCwzODc5MywzODgxNSwzODgzMywzODg0NiwzODg0OCwzODg2NiwzODg4MCwxNTI2ODQsMzg4OTQsMjk3MjQsMTY5MDExLDM4OTExLDM4OTAxLDE2ODk4OSwxNjIxNzAsMTkxNTMsMzg5NjQsMzg5NjMsMzg5ODcsMzkwMTQsMTUxMTgsMTYwMTE3LDE1Njk3LDEzMjY1NiwxNDc4MDQsMTUzMzUwLDM5MTE0LDM5MDk1LDM5MTEyLDM5MTExLDE5MTk5LDE1OTAxNSwxMzY5MTUsMjE5MzYsMzkxMzcsMzkxNDIsMzkxNDgsMzc3NTIsMzkyMjUsMTUwMDU3LDE5MzE0LDE3MDA3MSwxNzAyNDUsMzk0MTMsMzk0MzYsMzk0ODMsMzk0NDAsMzk1MTIsMTUzMzgxLDE0MDIwLDE2ODExMywxNzA5NjUsMzk2NDgsMzk2NTAsMTcwNzU3LDM5NjY4LDE5NDcwLDM5NzAwLDM5NzI1LDE2NTM3NiwyMDUzMiwzOTczMiwxNTgxMjAsMTQ1MzEsMTQzNDg1LDM5NzYwLDM5NzQ0LDE3MTMyNiwyMzEwOSwxMzczMTUsMzk4MjIsMTQ4MDQzLDM5OTM4LDM5OTM1LDM5OTQ4LDE3MTYyNCw0MDQwNCwxNzE5NTksMTcyNDM0LDE3MjQ1OSwxNzIyNTcsMTcyMzIzLDE3MjUxMSw0MDMxOCw0MDMyMywxNzIzNDAsNDA0NjIsMjY3NjAsNDAzODgsMTM5NjExLDE3MjQzNSwxNzI1NzYsMTM3NTMxLDE3MjU5NSw0MDI0OSwxNzIyMTcsMTcyNzI0LDQwNTkyLDQwNTk3LDQwNjA2LDQwNjEwLDE5NzY0LDQwNjE4LDQwNjIzLDE0ODMyNCw0MDY0MSwxNTIwMCwxNDgyMSwxNTY0NSwyMDI3NCwxNDI3MCwxNjY5NTUsNDA3MDYsNDA3MTIsMTkzNTAsMzc5MjQsMTU5MTM4LDQwNzI3LDQwNzI2LDQwNzYxLDIyMTc1LDIyMTU0LDQwNzczLDM5MzUyLDE2ODA3NSwzODg5OCwzMzkxOSw0MDgwMiw0MDgwOSwzMTQ1Miw0MDg0NiwyOTIwNiwxOTM5MCwxNDk4NzcsMTQ5OTQ3LDI5MDQ3LDE1MDAwOCwxNDgyOTYsMTUwMDk3LDI5NTk4LDE2Njg3NCwxMzc0NjYsMzExMzUsMTY2MjcwLDE2NzQ3OCwzNzczNywzNzg3NSwxNjY0NjgsMzc2MTIsMzc3NjEsMzc4MzUsMTY2MjUyLDE0ODY2NSwyOTIwNywxNjEwNywzMDU3OCwzMTI5OSwyODg4MCwxNDg1OTUsMTQ4NDcyLDI5MDU0LDEzNzE5OSwyODgzNSwxMzc0MDYsMTQ0NzkzLDE2MDcxLDEzNzM0OSwxNTI2MjMsMTM3MjA4LDE0MTE0LDEzNjk1NSwxMzcyNzMsMTQwNDksMTM3MDc2LDEzNzQyNSwxNTU0NjcsMTQxMTUsMTM2ODk2LDIyMzYzLDE1MDA1MywxMzYxOTAsMTM1ODQ4LDEzNjEzNCwxMzYzNzQsMzQwNTEsMTQ1MDYyLDM0MDUxLDMzODc3LDE0OTkwOCwxNjAxMDEsMTQ2OTkzLDE1MjkyNCwxNDcxOTUsMTU5ODI2LDE3NjUyLDE0NTEzNCwxNzAzOTcsMTU5NTI2LDI2NjE3LDE0MTMxLDE1MzgxLDE1ODQ3LDIyNjM2LDEzNzUwNiwyNjY0MCwxNjQ3MSwxNDUyMTUsMTQ3NjgxLDE0NzU5NSwxNDc3MjcsMTU4NzUzLDIxNzA3LDIyMTc0LDE1NzM2MSwyMjE2MiwxMzUxMzUsMTM0MDU2LDEzNDY2OSwzNzgzMCwxNjY2NzUsMzc3ODgsMjAyMTYsMjA3NzksMTQzNjEsMTQ4NTM0LDIwMTU2LDEzMjE5NywxMzE5NjcsMjAyOTksMjAzNjIsMTUzMTY5LDIzMTQ0LDEzMTQ5OSwxMzIwNDMsMTQ3NDUsMTMxODUwLDEzMjExNiwxMzM2NSwyMDI2NSwxMzE3NzYsMTY3NjAzLDEzMTcwMSwzNTU0NiwxMzE1OTYsMjAxMjAsMjA2ODUsMjA3NDksMjAzODYsMjAyMjcsMTUwMDMwLDE0NzA4MiwyMDI5MCwyMDUyNiwyMDU4OCwyMDYwOSwyMDQyOCwyMDQ1MywyMDU2OCwyMDczMiwyMDgyNSwyMDgyNywyMDgyOSwyMDgzMCwyODI3OCwxNDQ3ODksMTQ3MDAxLDE0NzEzNSwyODAxOCwxMzczNDgsMTQ3MDgxLDIwOTA0LDIwOTMxLDEzMjU3NiwxNzYyOSwxMzIyNTksMTMyMjQyLDEzMjI0MSwzNjIxOCwxNjY1NTYsMTMyODc4LDIxMDgxLDIxMTU2LDEzMzIzNSwyMTIxNywzNzc0MiwxODA0MiwyOTA2OCwxNDgzNjQsMTM0MTc2LDE0OTkzMiwxMzUzOTYsMjcwODksMTM0Njg1LDI5ODE3LDE2MDk0LDI5ODQ5LDI5NzE2LDI5NzgyLDI5NTkyLDE5MzQyLDE1MDIwNCwxNDc1OTcsMjE0NTYsMTM3MDAsMjkxOTksMTQ3NjU3LDIxOTQwLDEzMTkwOSwyMTcwOSwxMzQwODYsMjIzMDEsMzc0NjksMzg2NDQsMzc3MzQsMjI0OTMsMjI0MTMsMjIzOTksMTM4ODYsMjI3MzEsMjMxOTMsMTY2NDcwLDEzNjk1NCwxMzcwNzEsMTM2OTc2LDIzMDg0LDIyOTY4LDM3NTE5LDIzMTY2LDIzMjQ3LDIzMDU4LDE1MzkyNiwxMzc3MTUsMTM3MzEzLDE0ODExNywxNDA2OSwyNzkwOSwyOTc2MywyMzA3MywxNTUyNjcsMjMxNjksMTY2ODcxLDEzMjExNSwzNzg1NiwyOTgzNiwxMzU5MzksMjg5MzMsMTg4MDIsMzc4OTYsMTY2Mzk1LDM3ODIxLDE0MjQwLDIzNTgyLDIzNzEwLDI0MTU4LDI0MTM2LDEzNzYyMiwxMzc1OTYsMTQ2MTU4LDI0MjY5LDIzMzc1LDEzNzQ3NSwxMzc0NzYsMTQwODEsMTM3Mzc2LDE0MDQ1LDEzNjk1OCwxNDAzNSwzMzA2NiwxNjY0NzEsMTM4NjgyLDE0NDQ5OCwxNjYzMTIsMjQzMzIsMjQzMzQsMTM3NTExLDEzNzEzMSwyMzE0NywxMzcwMTksMjMzNjQsMzQzMjQsMTYxMjc3LDM0OTEyLDI0NzAyLDE0MTQwOCwxNDA4NDMsMjQ1MzksMTYwNTYsMTQwNzE5LDE0MDczNCwxNjgwNzIsMTU5NjAzLDI1MDI0LDEzMTEzNCwxMzExNDIsMTQwODI3LDI0OTg1LDI0OTg0LDI0NjkzLDE0MjQ5MSwxNDI1OTksMTQ5MjA0LDE2ODI2OSwyNTcxMywxNDkwOTMsMTQyMTg2LDE0ODg5LDE0MjExNCwxNDQ0NjQsMTcwMjE4LDE0Mjk2OCwyNTM5OSwxNzMxNDcsMjU3ODIsMjUzOTMsMjU1NTMsMTQ5OTg3LDE0MjY5NSwyNTI1MiwxNDI0OTcsMjU2NTksMjU5NjMsMjY5OTQsMTUzNDgsMTQzNTAyLDE0NDA0NSwxNDk4OTcsMTQ0MDQzLDIxNzczLDE0NDA5NiwxMzc0MzMsMTY5MDIzLDI2MzE4LDE0NDAwOSwxNDM3OTUsMTUwNzIsMTY3ODQsMTUyOTY0LDE2NjY5MCwxNTI5NzUsMTM2OTU2LDE1MjkyMywxNTI2MTMsMzA5NTgsMTQzNjE5LDEzNzI1OCwxNDM5MjQsMTM0MTIsMTQzODg3LDE0Mzc0NiwxNDgxNjksMjYyNTQsMTU5MDEyLDI2MjE5LDE5MzQ3LDI2MTYwLDE2MTkwNCwxMzg3MzEsMjYyMTEsMTQ0MDgyLDE0NDA5NywyNjE0MiwxNTM3MTQsMTQ1NDUsMTQ1NDY2LDE0NTM0MCwxNTI1NywxNDUzMTQsMTQ0MzgyLDI5OTA0LDE1MjU0LDI2NTExLDE0OTAzNCwyNjgwNiwyNjY1NCwxNTMwMCwyNzMyNiwxNDQzNSwxNDUzNjUsMTQ4NjE1LDI3MTg3LDI3MjE4LDI3MzM3LDI3Mzk3LDEzNzQ5MCwyNTg3MywyNjc3NiwyNzIxMiwxNTMxOSwyNzI1OCwyNzQ3OSwxNDczOTIsMTQ2NTg2LDM3NzkyLDM3NjE4LDE2Njg5MCwxNjY2MDMsMzc1MTMsMTYzODcwLDE2NjM2NCwzNzk5MSwyODA2OSwyODQyNywxNDk5OTYsMjgwMDcsMTQ3MzI3LDE1NzU5LDI4MTY0LDE0NzUxNiwyMzEwMSwyODE3MCwyMjU5OSwyNzk0MCwzMDc4NiwyODk4NywxNDgyNTAsMTQ4MDg2LDI4OTEzLDI5MjY0LDI5MzE5LDI5MzMyLDE0OTM5MSwxNDkyODUsMjA4NTcsMTUwMTgwLDEzMjU4NywyOTgxOCwxNDcxOTIsMTQ0OTkxLDE1MDA5MCwxNDk3ODMsMTU1NjE3LDE2MTM0LDE2MDQ5LDE1MDIzOSwxNjY5NDcsMTQ3MjUzLDI0NzQzLDE2MTE1LDI5OTAwLDI5NzU2LDM3NzY3LDI5NzUxLDE3NTY3LDE1OTIxMCwxNzc0NSwzMDA4MywxNjIyNywxNTA3NDUsMTUwNzkwLDE2MjE2LDMwMDM3LDMwMzIzLDE3MzUxMCwxNTEyOSwyOTgwMCwxNjY2MDQsMTQ5OTMxLDE0OTkwMiwxNTA5OSwxNTgyMSwxNTAwOTQsMTYxMjcsMTQ5OTU3LDE0OTc0NywzNzM3MCwyMjMyMiwzNzY5OCwxNjY2MjcsMTM3MzE2LDIwNzAzLDE1MjA5NywxNTIwMzksMzA1ODQsMTQzOTIyLDMwNDc4LDMwNDc5LDMwNTg3LDE0OTE0MywxNDUyODEsMTQ5NDIsMTQ5NzQ0LDI5NzUyLDI5ODUxLDE2MDYzLDE1MDIwMiwxNTAyMTUsMTY1ODQsMTUwMTY2LDE1NjA3OCwzNzYzOSwxNTI5NjEsMzA3NTAsMzA4NjEsMzA4NTYsMzA5MzAsMjk2NDgsMzEwNjUsMTYxNjAxLDE1MzMxNSwxNjY1NCwzMTEzMSwzMzk0MiwzMTE0MSwyNzE4MSwxNDcxOTQsMzEyOTAsMzEyMjAsMTY3NTAsMTM2OTM0LDE2NjkwLDM3NDI5LDMxMjE3LDEzNDQ3NiwxNDk5MDAsMTMxNzM3LDE0Njg3NCwxMzcwNzAsMTM3MTksMjE4NjcsMTM2ODAsMTM5OTQsMTMxNTQwLDEzNDE1NywzMTQ1OCwyMzEyOSwxNDEwNDUsMTU0Mjg3LDE1NDI2OCwyMzA1MywxMzE2NzUsMzA5NjAsMjMwODIsMTU0NTY2LDMxNDg2LDE2ODg5LDMxODM3LDMxODUzLDE2OTEzLDE1NDU0NywxNTUzMjQsMTU1MzAyLDMxOTQ5LDE1MDAwOSwxMzcxMzYsMzE4ODYsMzE4NjgsMzE5MTgsMjczMTQsMzIyMjAsMzIyNjMsMzIyMTEsMzI1OTAsMTU2MjU3LDE1NTk5NiwxNjI2MzIsMzIxNTEsMTU1MjY2LDE3MDAyLDE1ODU4MSwxMzMzOTgsMjY1ODIsMTMxMTUwLDE0NDg0NywyMjQ2OCwxNTY2OTAsMTU2NjY0LDE0OTg1OCwzMjczMywzMTUyNywxMzMxNjQsMTU0MzQ1LDE1NDk0NywzMTUwMCwxNTUxNTAsMzkzOTgsMzQzNzMsMzk1MjMsMjcxNjQsMTQ0NDQ3LDE0ODE4LDE1MDAwNywxNTcxMDEsMzk0NTUsMTU3MDg4LDMzOTIwLDE2MDAzOSwxNTg5MjksMTc2NDIsMzMwNzksMTc0MTAsMzI5NjYsMzMwMzMsMzMwOTAsMTU3NjIwLDM5MTA3LDE1ODI3NCwzMzM3OCwzMzM4MSwxNTgyODksMzM4NzUsMTU5MTQzLDM0MzIwLDE2MDI4MywyMzE3NCwxNjc2NywxMzcyODAsMjMzMzksMTM3Mzc3LDIzMjY4LDEzNzQzMiwzNDQ2NCwxOTUwMDQsMTQ2ODMxLDM0ODYxLDE2MDgwMiwyMzA0MiwzNDkyNiwyMDI5MywzNDk1MSwzNTAwNywzNTA0NiwzNTE3MywzNTE0OSwxNTMyMTksMzUxNTYsMTYxNjY5LDE2MTY2OCwxNjY5MDEsMTY2ODczLDE2NjgxMiwxNjYzOTMsMTYwNDUsMzM5NTUsMTgxNjUsMTgxMjcsMTQzMjIsMzUzODksMzUzNTYsMTY5MDMyLDI0Mzk3LDM3NDE5LDE0ODEwMCwyNjA2OCwyODk2OSwyODg2OCwxMzcyODUsNDAzMDEsMzU5OTksMzYwNzMsMTYzMjkyLDIyOTM4LDMwNjU5LDIzMDI0LDE3MjYyLDE0MDM2LDM2Mzk0LDM2NTE5LDE1MDUzNywzNjY1NiwzNjY4MiwxNzE0MCwyNzczNiwyODYwMywxNDAwNjUsMTg1ODcsMjg1MzcsMjgyOTksMTM3MTc4LDM5OTEzLDE0MDA1LDE0OTgwNywzNzA1MSwzNzAxNSwyMTg3MywxODY5NCwzNzMwNywzNzg5MiwxNjY0NzUsMTY0ODIsMTY2NjUyLDM3OTI3LDE2Njk0MSwxNjY5NzEsMzQwMjEsMzUzNzEsMzgyOTcsMzgzMTEsMzgyOTUsMzgyOTQsMTY3MjIwLDI5NzY1LDE2MDY2LDE0OTc1OSwxNTAwODIsMTQ4NDU4LDE2MTAzLDE0MzkwOSwzODU0MywxNjc2NTUsMTY3NTI2LDE2NzUyNSwxNjA3NiwxNDk5OTcsMTUwMTM2LDE0NzQzOCwyOTcxNCwyOTgwMywxNjEyNCwzODcyMSwxNjgxMTIsMjY2OTUsMTg5NzMsMTY4MDgzLDE1MzU2NywzODc0OSwzNzczNiwxNjYyODEsMTY2OTUwLDE2NjcwMywxNTY2MDYsMzc1NjIsMjMzMTMsMzU2ODksMTg3NDgsMjk2ODksMTQ3OTk1LDM4ODExLDM4NzY5LDM5MjI0LDEzNDk1MCwyNDAwMSwxNjY4NTMsMTUwMTk0LDM4OTQzLDE2OTE3OCwzNzYyMiwxNjk0MzEsMzczNDksMTc2MDAsMTY2NzM2LDE1MDExOSwxNjY3NTYsMzkxMzIsMTY2NDY5LDE2MTI4LDM3NDE4LDE4NzI1LDMzODEyLDM5MjI3LDM5MjQ1LDE2MjU2NiwxNTg2OSwzOTMyMywxOTMxMSwzOTMzOCwzOTUxNiwxNjY3NTcsMTUzODAwLDI3Mjc5LDM5NDU3LDIzMjk0LDM5NDcxLDE3MDIyNSwxOTM0NCwxNzAzMTIsMzkzNTYsMTkzODksMTkzNTEsMzc3NTcsMjI2NDIsMTM1OTM4LDIyNTYyLDE0OTk0NCwxMzY0MjQsMzA3ODgsMTQxMDg3LDE0Njg3MiwyNjgyMSwxNTc0MSwzNzk3NiwxNDYzMSwyNDkxMiwxNDExODUsMTQxNjc1LDI0ODM5LDQwMDE1LDQwMDE5LDQwMDU5LDM5OTg5LDM5OTUyLDM5ODA3LDM5ODg3LDE3MTU2NSwzOTgzOSwxNzI1MzMsMTcyMjg2LDQwMjI1LDE5NjMwLDE0NzcxNiw0MDQ3MiwxOTYzMiw0MDIwNCwxNzI0NjgsMTcyMjY5LDE3MjI3NSwxNzAyODcsNDAzNTcsMzM5ODEsMTU5MjUwLDE1OTcxMSwxNTg1OTQsMzQzMDAsMTc3MTUsMTU5MTQwLDE1OTM2NCwxNTkyMTYsMzM4MjQsMzQyODYsMTU5MjMyLDE0NTM2NywxNTU3NDgsMzEyMDIsMTQ0Nzk2LDE0NDk2MCwxODczMywxNDk5ODIsMTU3MTQsMzc4NTEsMzc1NjYsMzc3MDQsMTMxNzc1LDMwOTA1LDM3NDk1LDM3OTY1LDIwNDUyLDEzMzc2LDM2OTY0LDE1MjkyNSwzMDc4MSwzMDgwNCwzMDkwMiwzMDc5NSwxMzcwNDcsMTQzODE3LDE0OTgyNSwxMzk3OCwyMDMzOCwyODYzNCwyODYzMywyODcwMiwyODcwMiwyMTUyNCwxNDc4OTMsMjI0NTksMjI3NzEsMjI0MTAsNDAyMTQsMjI0ODcsMjg5ODAsMTM0ODcsMTQ3ODg0LDI5MTYzLDE1ODc4NCwxNTE0NDcsMjMzMzYsMTM3MTQxLDE2NjQ3MywyNDg0NCwyMzI0NiwyMzA1MSwxNzA4NCwxNDg2MTYsMTQxMjQsMTkzMjMsMTY2Mzk2LDM3ODE5LDM3ODE2LDEzNzQzMCwxMzQ5NDEsMzM5MDYsMTU4OTEyLDEzNjIxMSwxNDgyMTgsMTQyMzc0LDE0ODQxNywyMjkzMiwxNDY4NzEsMTU3NTA1LDMyMTY4LDE1NTk5NSwxNTU4MTIsMTQ5OTQ1LDE0OTg5OSwxNjYzOTQsMzc2MDUsMjk2NjYsMTYxMDUsMjk4NzYsMTY2NzU1LDEzNzM3NSwxNjA5NywxNTAxOTUsMjczNTIsMjk2ODMsMjk2OTEsMTYwODYsMTUwMDc4LDE1MDE2NCwxMzcxNzcsMTUwMTE4LDEzMjAwNywxMzYyMjgsMTQ5OTg5LDI5NzY4LDE0OTc4MiwyODgzNywxNDk4NzgsMzc1MDgsMjk2NzAsMzc3MjcsMTMyMzUwLDM3NjgxLDE2NjYwNiwxNjY0MjIsMzc3NjYsMTY2ODg3LDE1MzA0NSwxODc0MSwxNjY1MzAsMjkwMzUsMTQ5ODI3LDEzNDM5OSwyMjE4MCwxMzI2MzQsMTM0MTIzLDEzNDMyOCwyMTc2MiwzMTE3MiwxMzcyMTAsMzIyNTQsMTM2ODk4LDE1MDA5NiwxMzcyOTgsMTc3MTAsMzc4ODksMTQwOTAsMTY2NTkyLDE0OTkzMywyMjk2MCwxMzc0MDcsMTM3MzQ3LDE2MDkwMCwyMzIwMSwxNDA1MCwxNDY3NzksMTQwMDAsMzc0NzEsMjMxNjEsMTY2NTI5LDEzNzMxNCwzNzc0OCwxNTU2NSwxMzM4MTIsMTkwOTQsMTQ3MzAsMjA3MjQsMTU3MjEsMTU2OTIsMTM2MDkyLDI5MDQ1LDE3MTQ3LDE2NDM3NiwyODE3NSwxNjgxNjQsMTc2NDMsMjc5OTEsMTYzNDA3LDI4Nzc1LDI3ODIzLDE1NTc0LDE0NzQzNywxNDY5ODksMjgxNjIsMjg0MjgsMTU3MjcsMTMyMDg1LDMwMDMzLDE0MDEyLDEzNTEyLDE4MDQ4LDE2MDkwLDE4NTQ1LDIyOTgwLDM3NDg2LDE4NzUwLDM2NjczLDE2Njk0MCwxNTg2NTYsMjI1NDYsMjI0NzIsMTQwMzgsMTM2Mjc0LDI4OTI2LDE0ODMyMiwxNTAxMjksMTQzMzMxLDEzNTg1NiwxNDAyMjEsMjY4MDksMjY5ODMsMTM2MDg4LDE0NDYxMywxNjI4MDQsMTQ1MTE5LDE2NjUzMSwxNDUzNjYsMTQ0Mzc4LDE1MDY4NywyNzE2MiwxNDUwNjksMTU4OTAzLDMzODU0LDE3NjMxLDE3NjE0LDE1OTAxNCwxNTkwNTcsMTU4ODUwLDE1OTcxMCwyODQzOSwxNjAwMDksMzM1OTcsMTM3MDE4LDMzNzczLDE1ODg0OCwxNTk4MjcsMTM3MTc5LDIyOTIxLDIzMTcwLDEzNzEzOSwyMzEzNywyMzE1MywxMzc0NzcsMTQ3OTY0LDE0MTI1LDIzMDIzLDEzNzAyMCwxNDAyMywyOTA3MCwzNzc3NiwyNjI2NiwxNDgxMzMsMjMxNTAsMjMwODMsMTQ4MTE1LDI3MTc5LDE0NzE5MywxNjE1OTAsMTQ4NTcxLDE0ODE3MCwyODk1NywxNDgwNTcsMTY2MzY5LDIwNDAwLDE1OTAxNiwyMzc0NiwxNDg2ODYsMTYzNDA1LDE0ODQxMywyNzE0OCwxNDgwNTQsMTM1OTQwLDI4ODM4LDI4OTc5LDE0ODQ1NywxNTc4MSwyNzg3MSwxOTQ1OTcsMTUwMDk1LDMyMzU3LDIzMDE5LDIzODU1LDE1ODU5LDI0NDEyLDE1MDEwOSwxMzcxODMsMzIxNjQsMzM4MzAsMjE2MzcsMTQ2MTcwLDE0NDEyOCwxMzE2MDQsMjIzOTgsMTMzMzMzLDEzMjYzMywxNjM1NywxMzkxNjYsMTcyNzI2LDI4Njc1LDE2ODI4MywyMzkyMCwyOTU4MywzMTk1NSwxNjY0ODksMTY4OTkyLDIwNDI0LDMyNzQzLDI5Mzg5LDI5NDU2LDE2MjU0OCwyOTQ5NiwyOTQ5NywxNTMzMzQsMjk1MDUsMjk1MTIsMTYwNDEsMTYyNTg0LDM2OTcyLDI5MTczLDE0OTc0NiwyOTY2NSwzMzI3MCwxNjA3NCwzMDQ3NiwxNjA4MSwyNzgxMCwyMjI2OSwyOTcyMSwyOTcyNiwyOTcyNywxNjA5OCwxNjExMiwxNjExNiwxNjEyMiwyOTkwNywxNjE0MiwxNjIxMSwzMDAxOCwzMDA2MSwzMDA2NiwzMDA5MywxNjI1MiwzMDE1MiwzMDE3MiwxNjMyMCwzMDI4NSwxNjM0MywzMDMyNCwxNjM0OCwzMDMzMCwxNTEzODgsMjkwNjQsMjIwNTEsMzUyMDAsMjI2MzMsMTY0MTMsMzA1MzEsMTY0NDEsMjY0NjUsMTY0NTMsMTM3ODcsMzA2MTYsMTY0OTAsMTY0OTUsMjM2NDYsMzA2NTQsMzA2NjcsMjI3NzAsMzA3NDQsMjg4NTcsMzA3NDgsMTY1NTIsMzA3NzcsMzA3OTEsMzA4MDEsMzA4MjIsMzM4NjQsMTUyODg1LDMxMDI3LDI2NjI3LDMxMDI2LDE2NjQzLDE2NjQ5LDMxMTIxLDMxMTI5LDM2Nzk1LDMxMjM4LDM2Nzk2LDE2NzQzLDMxMzc3LDE2ODE4LDMxNDIwLDMzNDAxLDE2ODM2LDMxNDM5LDMxNDUxLDE2ODQ3LDIwMDAxLDMxNTg2LDMxNTk2LDMxNjExLDMxNzYyLDMxNzcxLDE2OTkyLDE3MDE4LDMxODY3LDMxOTAwLDE3MDM2LDMxOTI4LDE3MDQ0LDMxOTgxLDM2NzU1LDI4ODY0LDEzNDM1MSwzMjIwNywzMjIxMiwzMjIwOCwzMjI1MywzMjY4NiwzMjY5MiwyOTM0MywxNzMwMywzMjgwMCwzMjgwNSwzMTU0NSwzMjgxNCwzMjgxNywzMjg1MiwxNTgyMCwyMjQ1MiwyODgzMiwzMjk1MSwzMzAwMSwxNzM4OSwzMzAzNiwyOTQ4MiwzMzAzOCwzMzA0MiwzMDA0OCwzMzA0NCwxNzQwOSwxNTE2MSwzMzExMCwzMzExMywzMzExNCwxNzQyNywyMjU4NiwzMzE0OCwzMzE1NiwxNzQ0NSwzMzE3MSwxNzQ1MywzMzE4OSwyMjUxMSwzMzIxNywzMzI1MiwzMzM2NCwxNzU1MSwzMzQ0NiwzMzM5OCwzMzQ4MiwzMzQ5NiwzMzUzNSwxNzU4NCwzMzYyMywzODUwNSwyNzAxOCwzMzc5NywyODkxNywzMzg5MiwyNDgwMywzMzkyOCwxNzY2OCwzMzk4MiwzNDAxNywzNDA0MCwzNDA2NCwzNDEwNCwzNDEzMCwxNzcyMywzNDE1OSwzNDE2MCwzNDI3MiwxNzc4MywzNDQxOCwzNDQ1MCwzNDQ4MiwzNDU0MywzODQ2OSwzNDY5OSwxNzkyNiwxNzk0MywzNDk5MCwzNTA3MSwzNTEwOCwzNTE0MywzNTIxNywxNjIxNTEsMzUzNjksMzUzODQsMzU0NzYsMzU1MDgsMzU5MjEsMzYwNTIsMzYwODIsMzYxMjQsMTgzMjgsMjI2MjMsMzYyOTEsMTg0MTMsMjAyMDYsMzY0MTAsMjE5NzYsMjIzNTYsMzY0NjUsMjIwMDUsMzY1MjgsMTg0ODcsMzY1NTgsMzY1NzgsMzY1ODAsMzY1ODksMzY1OTQsMzY3OTEsMzY4MDEsMzY4MTAsMzY4MTIsMzY5MTUsMzkzNjQsMTg2MDUsMzkxMzYsMzczOTUsMTg3MTgsMzc0MTYsMzc0NjQsMzc0ODMsMzc1NTMsMzc1NTAsMzc1NjcsMzc2MDMsMzc2MTEsMzc2MTksMzc2MjAsMzc2MjksMzc2OTksMzc3NjQsMzc4MDUsMTg3NTcsMTg3NjksNDA2MzksMzc5MTEsMjEyNDksMzc5MTcsMzc5MzMsMzc5NTAsMTg3OTQsMzc5NzIsMzgwMDksMzgxODksMzgzMDYsMTg4NTUsMzgzODgsMzg0NTEsMTg5MTcsMjY1MjgsMTg5ODAsMzg3MjAsMTg5OTcsMzg4MzQsMzg4NTAsMjIxMDAsMTkxNzIsMjQ4MDgsMzkwOTcsMTkyMjUsMzkxNTMsMjI1OTYsMzkxODIsMzkxOTMsMjA5MTYsMzkxOTYsMzkyMjMsMzkyMzQsMzkyNjEsMzkyNjYsMTkzMTIsMzkzNjUsMTkzNTcsMzk0ODQsMzk2OTUsMzEzNjMsMzk3ODUsMzk4MDksMzk5MDEsMzk5MjEsMzk5MjQsMTk1NjUsMzk5NjgsMTQxOTEsMTM4MTc4LDQwMjY1LDM5OTk0LDQwNzAyLDIyMDk2LDQwMzM5LDQwMzgxLDQwMzg0LDQwNDQ0LDM4MTM0LDM2NzkwLDQwNTcxLDQwNjIwLDQwNjI1LDQwNjM3LDQwNjQ2LDM4MTA4LDQwNjc0LDQwNjg5LDQwNjk2LDMxNDMyLDQwNzcyLDEzMTIyMCwxMzE3NjcsMTMyMDAwLDI2OTA2LDM4MDgzLDIyOTU2LDEzMjMxMSwyMjU5MiwzODA4MSwxNDI2NSwxMzI1NjUsMTMyNjI5LDEzMjcyNiwxMzY4OTAsMjIzNTksMjkwNDMsMTMzODI2LDEzMzgzNywxMzQwNzksMjE2MTAsMTk0NjE5LDEzNDA5MSwyMTY2MiwxMzQxMzksMTM0MjAzLDEzNDIyNywxMzQyNDUsMTM0MjY4LDI0ODA3LDEzNDI4NSwyMjEzOCwxMzQzMjUsMTM0MzY1LDEzNDM4MSwxMzQ1MTEsMTM0NTc4LDEzNDYwMCwyNjk2NSwzOTk4MywzNDcyNSwxMzQ2NjAsMTM0NjcwLDEzNDg3MSwxMzUwNTYsMTM0OTU3LDEzNDc3MSwyMzU4NCwxMzUxMDAsMjQwNzUsMTM1MjYwLDEzNTI0NywxMzUyODYsMjYzOTgsMTM1MjkxLDEzNTMwNCwxMzUzMTgsMTM4OTUsMTM1MzU5LDEzNTM3OSwxMzU0NzEsMTM1NDgzLDIxMzQ4LDMzOTY1LDEzNTkwNywxMzYwNTMsMTM1OTkwLDM1NzEzLDEzNjU2NywxMzY3MjksMTM3MTU1LDEzNzE1OSwyMDA4OCwyODg1OSwxMzcyNjEsMTM3NTc4LDEzNzc3MywxMzc3OTcsMTM4MjgyLDEzODM1MiwxMzg0MTIsMTM4OTUyLDI1MjgzLDEzODk2NSwxMzkwMjksMjkwODAsMjY3MDksMTM5MzMzLDI3MTEzLDE0MDI0LDEzOTkwMCwxNDAyNDcsMTQwMjgyLDE0MTA5OCwxNDE0MjUsMTQxNjQ3LDMzNTMzLDE0MTY3MSwxNDE3MTUsMTQyMDM3LDM1MjM3LDE0MjA1NiwzNjc2OCwxNDIwOTQsMzg4NDAsMTQyMTQzLDM4OTgzLDM5NjEzLDE0MjQxMixudWxsLDE0MjQ3MiwxNDI1MTksMTU0NjAwLDE0MjYwMCwxNDI2MTAsMTQyNzc1LDE0Mjc0MSwxNDI5MTQsMTQzMjIwLDE0MzMwOCwxNDM0MTEsMTQzNDYyLDE0NDE1OSwxNDQzNTAsMjQ0OTcsMjYxODQsMjYzMDMsMTYyNDI1LDE0NDc0MywxNDQ4ODMsMjkxODUsMTQ5OTQ2LDMwNjc5LDE0NDkyMiwxNDUxNzQsMzIzOTEsMTMxOTEwLDIyNzA5LDI2MzgyLDI2OTA0LDE0NjA4NywxNjEzNjcsMTU1NjE4LDE0Njk2MSwxNDcxMjksMTYxMjc4LDEzOTQxOCwxODY0MCwxOTEyOCwxNDc3MzcsMTY2NTU0LDE0ODIwNiwxNDgyMzcsMTQ3NTE1LDE0ODI3NiwxNDgzNzQsMTUwMDg1LDEzMjU1NCwyMDk0NiwxMzI2MjUsMjI5NDMsMTM4OTIwLDE1Mjk0LDE0NjY4NywxNDg0ODQsMTQ4Njk0LDIyNDA4LDE0OTEwOCwxNDc0NywxNDkyOTUsMTY1MzUyLDE3MDQ0MSwxNDE3OCwxMzk3MTUsMzU2NzgsMTY2NzM0LDM5MzgyLDE0OTUyMiwxNDk3NTUsMTUwMDM3LDI5MTkzLDE1MDIwOCwxMzQyNjQsMjI4ODUsMTUxMjA1LDE1MTQzMCwxMzI5ODUsMzY1NzAsMTUxNTk2LDIxMTM1LDIyMzM1LDI5MDQxLDE1MjIxNywxNTI2MDEsMTQ3Mjc0LDE1MDE4MywyMTk0OCwxNTI2NDYsMTUyNjg2LDE1ODU0NiwzNzMzMiwxMzQyNywxNTI4OTUsMTYxMzMwLDE1MjkyNiwxODIwMCwxNTI5MzAsMTUyOTM0LDE1MzU0MywxNDk4MjMsMTUzNjkzLDIwNTgyLDEzNTYzLDE0NDMzMiwyNDc5OCwxNTM4NTksMTgzMDAsMTY2MjE2LDE1NDI4NiwxNTQ1MDUsMTU0NjMwLDEzODY0MCwyMjQzMywyOTAwOSwyODU5OCwxNTU5MDYsMTYyODM0LDM2OTUwLDE1NjA4MiwxNTE0NTAsMzU2ODIsMTU2Njc0LDE1Njc0NiwyMzg5OSwxNTg3MTEsMzY2NjIsMTU2ODA0LDEzNzUwMCwzNTU2MiwxNTAwMDYsMTU2ODA4LDE0NzQzOSwxNTY5NDYsMTkzOTIsMTU3MTE5LDE1NzM2NSwxNDEwODMsMzc5ODksMTUzNTY5LDI0OTgxLDIzMDc5LDE5NDc2NSwyMDQxMSwyMjIwMSwxNDg3NjksMTU3NDM2LDIwMDc0LDE0OTgxMiwzODQ4NiwyODA0NywxNTg5MDksMTM4NDgsMzUxOTEsMTU3NTkzLDE1NzgwNiwxNTY2ODksMTU3NzkwLDI5MTUxLDE1Nzg5NSwzMTU1NCwxNjgxMjgsMTMzNjQ5LDE1Nzk5MCwzNzEyNCwxNTgwMDksMzEzMDEsNDA0MzIsMTU4MjAyLDM5NDYyLDE1ODI1MywxMzkxOSwxNTY3NzcsMTMxMTA1LDMxMTA3LDE1ODI2MCwxNTg1NTUsMjM4NTIsMTQ0NjY1LDMzNzQzLDE1ODYyMSwxODEyOCwxNTg4ODQsMzAwMTEsMzQ5MTcsMTU5MTUwLDIyNzEwLDE0MTA4LDE0MDY4NSwxNTk4MTksMTYwMjA1LDE1NDQ0LDE2MDM4NCwxNjAzODksMzc1MDUsMTM5NjQyLDE2MDM5NSwzNzY4MCwxNjA0ODYsMTQ5OTY4LDI3NzA1LDM4MDQ3LDE2MDg0OCwxMzQ5MDQsMzQ4NTUsMzUwNjEsMTQxNjA2LDE2NDk3OSwxMzcxMzcsMjgzNDQsMTUwMDU4LDEzNzI0OCwxNDc1NiwxNDAwOSwyMzU2OCwzMTIwMywxNzcyNywyNjI5NCwxNzExODEsMTcwMTQ4LDM1MTM5LDE2MTc0MCwxNjE4ODAsMjIyMzAsMTY2MDcsMTM2NzE0LDE0NzUzLDE0NTE5OSwxNjQwNzIsMTM2MTMzLDI5MTAxLDMzNjM4LDE2MjI2OSwxNjgzNjAsMjMxNDMsMTk2MzksMTU5OTE5LDE2NjMxNSwxNjIzMDEsMTYyMzE0LDE2MjU3MSwxNjMxNzQsMTQ3ODM0LDMxNTU1LDMxMTAyLDE2Mzg0OSwyODU5NywxNzI3NjcsMjcxMzksMTY0NjMyLDIxNDEwLDE1OTIzOSwzNzgyMywyNjY3OCwzODc0OSwxNjQyMDcsMTYzODc1LDE1ODEzMywxMzYxNzMsMTQzOTE5LDE2MzkxMiwyMzk0MSwxNjY5NjAsMTYzOTcxLDIyMjkzLDM4OTQ3LDE2NjIxNywyMzk3OSwxNDk4OTYsMjYwNDYsMjcwOTMsMjE0NTgsMTUwMTgxLDE0NzMyOSwxNTM3NywyNjQyMiwxNjM5ODQsMTY0MDg0LDE2NDE0MiwxMzkxNjksMTY0MTc1LDE2NDIzMywxNjQyNzEsMTY0Mzc4LDE2NDYxNCwxNjQ2NTUsMTY0NzQ2LDEzNzcwLDE2NDk2OCwxNjU1NDYsMTg2ODIsMjU1NzQsMTY2MjMwLDMwNzI4LDM3NDYxLDE2NjMyOCwxNzM5NCwxNjYzNzUsMTczNzUsMTY2Mzc2LDE2NjcyNiwxNjY4NjgsMjMwMzIsMTY2OTIxLDM2NjE5LDE2Nzg3NywxNjgxNzIsMzE1NjksMTY4MjA4LDE2ODI1MiwxNTg2MywxNjgyODYsMTUwMjE4LDM2ODE2LDI5MzI3LDIyMTU1LDE2OTE5MSwxNjk0NDksMTY5MzkyLDE2OTQwMCwxNjk3NzgsMTcwMTkzLDE3MDMxMywxNzAzNDYsMTcwNDM1LDE3MDUzNiwxNzA3NjYsMTcxMzU0LDE3MTQxOSwzMjQxNSwxNzE3NjgsMTcxODExLDE5NjIwLDM4MjE1LDE3MjY5MSwyOTA5MCwxNzI3OTksMTk4NTcsMzY4ODIsMTczNTE1LDE5ODY4LDEzNDMwMCwzNjc5OCwyMTk1MywzNjc5NCwxNDA0NjQsMzY3OTMsMTUwMTYzLDE3NjczLDMyMzgzLDI4NTAyLDI3MzEzLDIwMjAyLDEzNTQwLDE2NjcwMCwxNjE5NDksMTQxMzgsMzY0ODAsMTM3MjA1LDE2Mzg3NiwxNjY3NjQsMTY2ODA5LDE2MjM2NiwxNTczNTksMTU4NTEsMTYxMzY1LDE0NjYxNSwxNTMxNDEsMTUzOTQyLDIwMTIyLDE1NTI2NSwxNTYyNDgsMjIyMDcsMTM0NzY1LDM2MzY2LDIzNDA1LDE0NzA4MCwxNTA2ODYsMjU1NjYsMjUyOTYsMTM3MjA2LDEzNzMzOSwyNTkwNCwyMjA2MSwxNTQ2OTgsMjE1MzAsMTUyMzM3LDE1ODE0LDE3MTQxNiwxOTU4MSwyMjA1MCwyMjA0NiwzMjU4NSwxNTUzNTIsMjI5MDEsMTQ2NzUyLDM0NjcyLDE5OTk2LDEzNTE0NiwxMzQ0NzMsMTQ1MDgyLDMzMDQ3LDQwMjg2LDM2MTIwLDMwMjY3LDQwMDA1LDMwMjg2LDMwNjQ5LDM3NzAxLDIxNTU0LDMzMDk2LDMzNTI3LDIyMDUzLDMzMDc0LDMzODE2LDMyOTU3LDIxOTk0LDMxMDc0LDIyMDgzLDIxNTI2LDEzNDgxMywxMzc3NCwyMjAyMSwyMjAwMSwyNjM1MywxNjQ1NzgsMTM4NjksMzAwMDQsMjIwMDAsMjE5NDYsMjE2NTUsMjE4NzQsMTM0MjA5LDEzNDI5NCwyNDI3MiwxNTE4ODAsMTM0Nzc0LDE0MjQzNCwxMzQ4MTgsNDA2MTksMzIwOTAsMjE5ODIsMTM1Mjg1LDI1MjQ1LDM4NzY1LDIxNjUyLDM2MDQ1LDI5MTc0LDM3MjM4LDI1NTk2LDI1NTI5LDI1NTk4LDIxODY1LDE0MjE0Nyw0MDA1MCwxNDMwMjcsMjA4OTAsMTM1MzUsMTM0NTY3LDIwOTAzLDIxNTgxLDIxNzkwLDIxNzc5LDMwMzEwLDM2Mzk3LDE1NzgzNCwzMDEyOSwzMjk1MCwzNDgyMCwzNDY5NCwzNTAxNSwzMzIwNiwzMzgyMCwxMzUzNjEsMTc2NDQsMjk0NDQsMTQ5MjU0LDIzNDQwLDMzNTQ3LDE1Nzg0MywyMjEzOSwxNDEwNDQsMTYzMTE5LDE0Nzg3NSwxNjMxODcsMTU5NDQwLDE2MDQzOCwzNzIzMiwxMzU2NDEsMzczODQsMTQ2Njg0LDE3MzczNywxMzQ4MjgsMTM0OTA1LDI5Mjg2LDEzODQwMiwxODI1NCwxNTE0OTAsMTYzODMzLDEzNTE0NywxNjYzNCw0MDAyOSwyNTg4NywxNDI3NTIsMTg2NzUsMTQ5NDcyLDE3MTM4OCwxMzUxNDgsMTM0NjY2LDI0Njc0LDE2MTE4NywxMzUxNDksbnVsbCwxNTU3MjAsMTM1NTU5LDI5MDkxLDMyMzk4LDQwMjcyLDE5OTk0LDE5OTcyLDEzNjg3LDIzMzA5LDI3ODI2LDIxMzUxLDEzOTk2LDE0ODEyLDIxMzczLDEzOTg5LDE0OTAxNiwyMjY4MiwxNTAzODIsMzMzMjUsMjE1NzksMjI0NDIsMTU0MjYxLDEzMzQ5NyxudWxsLDE0OTMwLDE0MDM4OSwyOTU1NiwxNzE2OTIsMTk3MjEsMzk5MTcsMTQ2Njg2LDE3MTgyNCwxOTU0NywxNTE0NjUsMTY5Mzc0LDE3MTk5OCwzMzg4NCwxNDY4NzAsMTYwNDM0LDE1NzYxOSwxNDUxODQsMjUzOTAsMzIwMzcsMTQ3MTkxLDE0Njk4OCwxNDg5MCwzNjg3MiwyMTE5NiwxNTk4OCwxMzk0NiwxNzg5NywxMzIyMzgsMzAyNzIsMjMyODAsMTM0ODM4LDMwODQyLDE2MzYzMCwyMjY5NSwxNjU3NSwyMjE0MCwzOTgxOSwyMzkyNCwzMDI5MiwxNzMxMDgsNDA1ODEsMTk2ODEsMzAyMDEsMTQzMzEsMjQ4NTcsMTQzNTc4LDE0ODQ2NixudWxsLDIyMTA5LDEzNTg0OSwyMjQzOSwxNDk4NTksMTcxNTI2LDIxMDQ0LDE1OTkxOCwxMzc0MSwyNzcyMiw0MDMxNiwzMTgzMCwzOTczNywyMjQ5NCwxMzcwNjgsMjM2MzUsMjU4MTEsMTY5MTY4LDE1NjQ2OSwxNjAxMDAsMzQ0NzcsMTM0NDQwLDE1OTAxMCwxNTAyNDIsMTM0NTEzLG51bGwsMjA5OTAsMTM5MDIzLDIzOTUwLDM4NjU5LDEzODcwNSw0MDU3NywzNjk0MCwzMTUxOSwzOTY4MiwyMzc2MSwzMTY1MSwyNTE5MiwyNTM5NywzOTY3OSwzMTY5NSwzOTcyMiwzMTg3MCwzOTcyNiwzMTgxMCwzMTg3OCwzOTk1NywzMTc0MCwzOTY4OSw0MDcyNywzOTk2MywxNDk4MjIsNDA3OTQsMjE4NzUsMjM0OTEsMjA0NzcsNDA2MDAsMjA0NjYsMjEwODgsMTU4NzgsMjEyMDEsMjIzNzUsMjA1NjYsMjI5NjcsMjQwODIsMzg4NTYsNDAzNjMsMzY3MDAsMjE2MDksMzg4MzYsMzkyMzIsMzg4NDIsMjEyOTIsMjQ4ODAsMjY5MjQsMjE0NjYsMzk5NDYsNDAxOTQsMTk1MTUsMzg0NjUsMjcwMDgsMjA2NDYsMzAwMjIsMTM3MDY5LDM5Mzg2LDIxMTA3LG51bGwsMzcyMDksMzg1MjksMzcyMTIsbnVsbCwzNzIwMSwxNjc1NzUsMjU0NzEsMTU5MDExLDI3MzM4LDIyMDMzLDM3MjYyLDMwMDc0LDI1MjIxLDEzMjA5MiwyOTUxOSwzMTg1NiwxNTQ2NTcsMTQ2Njg1LG51bGwsMTQ5Nzg1LDMwNDIyLDM5ODM3LDIwMDEwLDEzNDM1NiwzMzcyNiwzNDg4MixudWxsLDIzNjI2LDI3MDcyLDIwNzE3LDIyMzk0LDIxMDIzLDI0MDUzLDIwMTc0LDI3Njk3LDEzMTU3MCwyMDI4MSwyMTY2MCwyMTcyMiwyMTE0NiwzNjIyNiwxMzgyMiwyNDMzMiwxMzgxMSxudWxsLDI3NDc0LDM3MjQ0LDQwODY5LDM5ODMxLDM4OTU4LDM5MDkyLDM5NjEwLDQwNjE2LDQwNTgwLDI5MDUwLDMxNTA4LG51bGwsMjc2NDIsMzQ4NDAsMzI2MzIsbnVsbCwyMjA0OCwxNzM2NDIsMzY0NzEsNDA3ODcsbnVsbCwzNjMwOCwzNjQzMSw0MDQ3NiwzNjM1MywyNTIxOCwxNjQ3MzMsMzYzOTIsMzY0NjksMzE0NDMsMTUwMTM1LDMxMjk0LDMwOTM2LDI3ODgyLDM1NDMxLDMwMjE1LDE2NjQ5MCw0MDc0MiwyNzg1NCwzNDc3NCwzMDE0NywxNzI3MjIsMzA4MDMsMTk0NjI0LDM2MTA4LDI5NDEwLDI5NTUzLDM1NjI5LDI5NDQyLDI5OTM3LDM2MDc1LDE1MDIwMywzNDM1MSwyNDUwNiwzNDk3NiwxNzU5MSxudWxsLDEzNzI3NSwxNTkyMzcsbnVsbCwzNTQ1NCwxNDA1NzEsbnVsbCwyNDgyOSwzMDMxMSwzOTYzOSw0MDI2MCwzNzc0MiwzOTgyMywzNDgwNSxudWxsLDM0ODMxLDM2MDg3LDI5NDg0LDM4Njg5LDM5ODU2LDEzNzgyLDI5MzYyLDE5NDYzLDMxODI1LDM5MjQyLDE1NTk5MywyNDkyMSwxOTQ2MCw0MDU5OCwyNDk1NyxudWxsLDIyMzY3LDI0OTQzLDI1MjU0LDI1MTQ1LDI1Mjk0LDE0OTQwLDI1MDU4LDIxNDE4LDE0NDM3MywyNTQ0NCwyNjYyNiwxMzc3OCwyMzg5NSwxNjY4NTAsMzY4MjYsMTY3NDgxLG51bGwsMjA2OTcsMTM4NTY2LDMwOTgyLDIxMjk4LDM4NDU2LDEzNDk3MSwxNjQ4NSxudWxsLDMwNzE4LG51bGwsMzE5MzgsMTU1NDE4LDMxOTYyLDMxMjc3LDMyODcwLDMyODY3LDMyMDc3LDI5OTU3LDI5OTM4LDM1MjIwLDMzMzA2LDI2MzgwLDMyODY2LDE2MDkwMiwzMjg1OSwyOTkzNiwzMzAyNywzMDUwMCwzNTIwOSwxNTc2NDQsMzAwMzUsMTU5NDQxLDM0NzI5LDM0NzY2LDMzMjI0LDM0NzAwLDM1NDAxLDM2MDEzLDM1NjUxLDMwNTA3LDI5OTQ0LDM0MDEwLDEzODc3LDI3MDU4LDM2MjYyLG51bGwsMzUyNDEsMjk4MDAsMjgwODksMzQ3NTMsMTQ3NDczLDI5OTI3LDE1ODM1LDI5MDQ2LDI0NzQwLDI0OTg4LDE1NTY5LDI5MDI2LDI0Njk1LG51bGwsMzI2MjUsMTY2NzAxLDI5MjY0LDI0ODA5LDE5MzI2LDIxMDI0LDE1Mzg0LDE0NjYzMSwxNTUzNTEsMTYxMzY2LDE1Mjg4MSwxMzc1NDAsMTM1OTM0LDE3MDI0MywxNTkxOTYsMTU5OTE3LDIzNzQ1LDE1NjA3NywxNjY0MTUsMTQ1MDE1LDEzMTMxMCwxNTc3NjYsMTUxMzEwLDE3NzYyLDIzMzI3LDE1NjQ5Miw0MDc4NCw0MDYxNCwxNTYyNjcsMTIyODgsNjUyOTIsMTIyODksMTIyOTAsNjUyOTQsODIzMSw2NTMwNyw2NTMwNiw2NTMxMSw2NTI4MSw2NTA3Miw4MjMwLDgyMjksNjUxMDQsNjUxMDUsNjUxMDYsMTgzLDY1MTA4LDY1MTA5LDY1MTEwLDY1MTExLDY1MzcyLDgyMTEsNjUwNzMsODIxMiw2NTA3NSw5NTg4LDY1MDc2LDY1MTAzLDY1Mjg4LDY1Mjg5LDY1MDc3LDY1MDc4LDY1MzcxLDY1MzczLDY1MDc5LDY1MDgwLDEyMzA4LDEyMzA5LDY1MDgxLDY1MDgyLDEyMzA0LDEyMzA1LDY1MDgzLDY1MDg0LDEyMjk4LDEyMjk5LDY1MDg1LDY1MDg2LDEyMjk2LDEyMjk3LDY1MDg3LDY1MDg4LDEyMzAwLDEyMzAxLDY1MDg5LDY1MDkwLDEyMzAyLDEyMzAzLDY1MDkxLDY1MDkyLDY1MTEzLDY1MTE0LDY1MTE1LDY1MTE2LDY1MTE3LDY1MTE4LDgyMTYsODIxNyw4MjIwLDgyMjEsMTIzMTcsMTIzMTgsODI0NSw4MjQyLDY1MjgzLDY1Mjg2LDY1MjkwLDgyNTEsMTY3LDEyMjkxLDk2NzUsOTY3OSw5NjUxLDk2NTAsOTY3OCw5NzM0LDk3MzMsOTY3MSw5NjcwLDk2MzMsOTYzMiw5NjYxLDk2NjAsMTI5NjMsODQ1MywxNzUsNjU1MDcsNjUzNDMsNzE3LDY1MDk3LDY1MDk4LDY1MTAxLDY1MTAyLDY1MDk5LDY1MTAwLDY1MTE5LDY1MTIwLDY1MTIxLDY1MjkxLDY1MjkzLDIxNSwyNDcsMTc3LDg3MzAsNjUzMDgsNjUzMTAsNjUzMDksODgwNiw4ODA3LDg4MDAsODczNCw4Nzg2LDg4MDEsNjUxMjIsNjUxMjMsNjUxMjQsNjUxMjUsNjUxMjYsNjUzNzQsODc0NSw4NzQ2LDg4NjksODczNiw4NzM1LDg4OTUsMTMyNjYsMTMyNjUsODc0Nyw4NzUwLDg3NTcsODc1Niw5NzkyLDk3OTQsODg1Myw4ODU3LDg1OTMsODU5NSw4NTkyLDg1OTQsODU5OCw4NTk5LDg2MDEsODYwMCw4NzQxLDg3MzksNjUyOTUsNjUzNDAsODcyNSw2NTEyOCw2NTI4NCw2NTUwOSwxMjMwNiw2NTUwNCw2NTUwNSw2NTI4NSw2NTMxMiw4NDUxLDg0NTcsNjUxMjksNjUxMzAsNjUxMzEsMTMyNjksMTMyMTIsMTMyMTMsMTMyMTQsMTMyNjIsMTMyMTcsMTMxOTgsMTMxOTksMTMyNTIsMTc2LDIwODI1LDIwODI3LDIwODMwLDIwODI5LDIwODMzLDIwODM1LDIxOTkxLDI5OTI5LDMxOTUwLDk2MDEsOTYwMiw5NjAzLDk2MDQsOTYwNSw5NjA2LDk2MDcsOTYwOCw5NjE1LDk2MTQsOTYxMyw5NjEyLDk2MTEsOTYxMCw5NjA5LDk1MzIsOTUyNCw5NTE2LDk1MDgsOTUwMCw5NjIwLDk0NzIsOTQ3NCw5NjIxLDk0ODQsOTQ4OCw5NDkyLDk0OTYsOTU4MSw5NTgyLDk1ODQsOTU4Myw5NTUyLDk1NjYsOTU3OCw5NTY5LDk2OTgsOTY5OSw5NzAxLDk3MDAsOTU4NSw5NTg2LDk1ODcsNjUyOTYsNjUyOTcsNjUyOTgsNjUyOTksNjUzMDAsNjUzMDEsNjUzMDIsNjUzMDMsNjUzMDQsNjUzMDUsODU0NCw4NTQ1LDg1NDYsODU0Nyw4NTQ4LDg1NDksODU1MCw4NTUxLDg1NTIsODU1MywxMjMyMSwxMjMyMiwxMjMyMywxMjMyNCwxMjMyNSwxMjMyNiwxMjMyNywxMjMyOCwxMjMyOSwyMTMxMywyMTMxNiwyMTMxNyw2NTMxMyw2NTMxNCw2NTMxNSw2NTMxNiw2NTMxNyw2NTMxOCw2NTMxOSw2NTMyMCw2NTMyMSw2NTMyMiw2NTMyMyw2NTMyNCw2NTMyNSw2NTMyNiw2NTMyNyw2NTMyOCw2NTMyOSw2NTMzMCw2NTMzMSw2NTMzMiw2NTMzMyw2NTMzNCw2NTMzNSw2NTMzNiw2NTMzNyw2NTMzOCw2NTM0NSw2NTM0Niw2NTM0Nyw2NTM0OCw2NTM0OSw2NTM1MCw2NTM1MSw2NTM1Miw2NTM1Myw2NTM1NCw2NTM1NSw2NTM1Niw2NTM1Nyw2NTM1OCw2NTM1OSw2NTM2MCw2NTM2MSw2NTM2Miw2NTM2Myw2NTM2NCw2NTM2NSw2NTM2Niw2NTM2Nyw2NTM2OCw2NTM2OSw2NTM3MCw5MTMsOTE0LDkxNSw5MTYsOTE3LDkxOCw5MTksOTIwLDkyMSw5MjIsOTIzLDkyNCw5MjUsOTI2LDkyNyw5MjgsOTI5LDkzMSw5MzIsOTMzLDkzNCw5MzUsOTM2LDkzNyw5NDUsOTQ2LDk0Nyw5NDgsOTQ5LDk1MCw5NTEsOTUyLDk1Myw5NTQsOTU1LDk1Niw5NTcsOTU4LDk1OSw5NjAsOTYxLDk2Myw5NjQsOTY1LDk2Niw5NjcsOTY4LDk2OSwxMjU0OSwxMjU1MCwxMjU1MSwxMjU1MiwxMjU1MywxMjU1NCwxMjU1NSwxMjU1NiwxMjU1NywxMjU1OCwxMjU1OSwxMjU2MCwxMjU2MSwxMjU2MiwxMjU2MywxMjU2NCwxMjU2NSwxMjU2NiwxMjU2NywxMjU2OCwxMjU2OSwxMjU3MCwxMjU3MSwxMjU3MiwxMjU3MywxMjU3NCwxMjU3NSwxMjU3NiwxMjU3NywxMjU3OCwxMjU3OSwxMjU4MCwxMjU4MSwxMjU4MiwxMjU4MywxMjU4NCwxMjU4NSw3MjksNzEzLDcxNCw3MTEsNzE1LDkyMTYsOTIxNyw5MjE4LDkyMTksOTIyMCw5MjIxLDkyMjIsOTIyMyw5MjI0LDkyMjUsOTIyNiw5MjI3LDkyMjgsOTIyOSw5MjMwLDkyMzEsOTIzMiw5MjMzLDkyMzQsOTIzNSw5MjM2LDkyMzcsOTIzOCw5MjM5LDkyNDAsOTI0MSw5MjQyLDkyNDMsOTI0NCw5MjQ1LDkyNDYsOTI0Nyw5MjQ5LDgzNjQsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDE5OTY4LDIwMDU3LDE5OTY5LDE5OTcxLDIwMDM1LDIwMDYxLDIwMTAyLDIwMTA4LDIwMTU0LDIwNzk5LDIwODM3LDIwODQzLDIwOTYwLDIwOTkyLDIwOTkzLDIxMTQ3LDIxMjY5LDIxMzEzLDIxMzQwLDIxNDQ4LDE5OTc3LDE5OTc5LDE5OTc2LDE5OTc4LDIwMDExLDIwMDI0LDIwOTYxLDIwMDM3LDIwMDQwLDIwMDYzLDIwMDYyLDIwMTEwLDIwMTI5LDIwODAwLDIwOTk1LDIxMjQyLDIxMzE1LDIxNDQ5LDIxNDc1LDIyMzAzLDIyNzYzLDIyODA1LDIyODIzLDIyODk5LDIzMzc2LDIzMzc3LDIzMzc5LDIzNTQ0LDIzNTY3LDIzNTg2LDIzNjA4LDIzNjY1LDI0MDI5LDI0MDM3LDI0MDQ5LDI0MDUwLDI0MDUxLDI0MDYyLDI0MTc4LDI0MzE4LDI0MzMxLDI0MzM5LDI1MTY1LDE5OTg1LDE5OTg0LDE5OTgxLDIwMDEzLDIwMDE2LDIwMDI1LDIwMDQzLDIzNjA5LDIwMTA0LDIwMTEzLDIwMTE3LDIwMTE0LDIwMTE2LDIwMTMwLDIwMTYxLDIwMTYwLDIwMTYzLDIwMTY2LDIwMTY3LDIwMTczLDIwMTcwLDIwMTcxLDIwMTY0LDIwODAzLDIwODAxLDIwODM5LDIwODQ1LDIwODQ2LDIwODQ0LDIwODg3LDIwOTgyLDIwOTk4LDIwOTk5LDIxMDAwLDIxMjQzLDIxMjQ2LDIxMjQ3LDIxMjcwLDIxMzA1LDIxMzIwLDIxMzE5LDIxMzE3LDIxMzQyLDIxMzgwLDIxNDUxLDIxNDUwLDIxNDUzLDIyNzY0LDIyODI1LDIyODI3LDIyODI2LDIyODI5LDIzMzgwLDIzNTY5LDIzNTg4LDIzNjEwLDIzNjYzLDI0MDUyLDI0MTg3LDI0MzE5LDI0MzQwLDI0MzQxLDI0NTE1LDI1MDk2LDI1MTQyLDI1MTYzLDI1MTY2LDI1OTAzLDI1OTkxLDI2MDA3LDI2MDIwLDI2MDQxLDI2MDg1LDI2MzUyLDI2Mzc2LDI2NDA4LDI3NDI0LDI3NDkwLDI3NTEzLDI3NTk1LDI3NjA0LDI3NjExLDI3NjYzLDI3NzAwLDI4Nzc5LDI5MjI2LDI5MjM4LDI5MjQzLDI5MjU1LDI5MjczLDI5Mjc1LDI5MzU2LDI5NTc5LDE5OTkzLDE5OTkwLDE5OTg5LDE5OTg4LDE5OTkyLDIwMDI3LDIwMDQ1LDIwMDQ3LDIwMDQ2LDIwMTk3LDIwMTg0LDIwMTgwLDIwMTgxLDIwMTgyLDIwMTgzLDIwMTk1LDIwMTk2LDIwMTg1LDIwMTkwLDIwODA1LDIwODA0LDIwODczLDIwODc0LDIwOTA4LDIwOTg1LDIwOTg2LDIwOTg0LDIxMDAyLDIxMTUyLDIxMTUxLDIxMjUzLDIxMjU0LDIxMjcxLDIxMjc3LDIwMTkxLDIxMzIyLDIxMzIxLDIxMzQ1LDIxMzQ0LDIxMzU5LDIxMzU4LDIxNDM1LDIxNDg3LDIxNDc2LDIxNDkxLDIxNDg0LDIxNDg2LDIxNDgxLDIxNDgwLDIxNTAwLDIxNDk2LDIxNDkzLDIxNDgzLDIxNDc4LDIxNDgyLDIxNDkwLDIxNDg5LDIxNDg4LDIxNDc3LDIxNDg1LDIxNDk5LDIyMjM1LDIyMjM0LDIyODA2LDIyODMwLDIyODMzLDIyOTAwLDIyOTAyLDIzMzgxLDIzNDI3LDIzNjEyLDI0MDQwLDI0MDM5LDI0MDM4LDI0MDY2LDI0MDY3LDI0MTc5LDI0MTg4LDI0MzIxLDI0MzQ0LDI0MzQzLDI0NTE3LDI1MDk4LDI1MTcxLDI1MTcyLDI1MTcwLDI1MTY5LDI2MDIxLDI2MDg2LDI2NDE0LDI2NDEyLDI2NDEwLDI2NDExLDI2NDEzLDI3NDkxLDI3NTk3LDI3NjY1LDI3NjY0LDI3NzA0LDI3NzEzLDI3NzEyLDI3NzEwLDI5MzU5LDI5NTcyLDI5NTc3LDI5OTE2LDI5OTI2LDI5OTc2LDI5OTgzLDI5OTkyLDI5OTkzLDMwMDAwLDMwMDAxLDMwMDAyLDMwMDAzLDMwMDkxLDMwMzMzLDMwMzgyLDMwMzk5LDMwNDQ2LDMwNjgzLDMwNjkwLDMwNzA3LDMxMDM0LDMxMTY2LDMxMzQ4LDMxNDM1LDE5OTk4LDE5OTk5LDIwMDUwLDIwMDUxLDIwMDczLDIwMTIxLDIwMTMyLDIwMTM0LDIwMTMzLDIwMjIzLDIwMjMzLDIwMjQ5LDIwMjM0LDIwMjQ1LDIwMjM3LDIwMjQwLDIwMjQxLDIwMjM5LDIwMjEwLDIwMjE0LDIwMjE5LDIwMjA4LDIwMjExLDIwMjIxLDIwMjI1LDIwMjM1LDIwODA5LDIwODA3LDIwODA2LDIwODA4LDIwODQwLDIwODQ5LDIwODc3LDIwOTEyLDIxMDE1LDIxMDA5LDIxMDEwLDIxMDA2LDIxMDE0LDIxMTU1LDIxMjU2LDIxMjgxLDIxMjgwLDIxMzYwLDIxMzYxLDIxNTEzLDIxNTE5LDIxNTE2LDIxNTE0LDIxNTIwLDIxNTA1LDIxNTE1LDIxNTA4LDIxNTIxLDIxNTE3LDIxNTEyLDIxNTA3LDIxNTE4LDIxNTEwLDIxNTIyLDIyMjQwLDIyMjM4LDIyMjM3LDIyMzIzLDIyMzIwLDIyMzEyLDIyMzE3LDIyMzE2LDIyMzE5LDIyMzEzLDIyODA5LDIyODEwLDIyODM5LDIyODQwLDIyOTE2LDIyOTA0LDIyOTE1LDIyOTA5LDIyOTA1LDIyOTE0LDIyOTEzLDIzMzgzLDIzMzg0LDIzNDMxLDIzNDMyLDIzNDI5LDIzNDMzLDIzNTQ2LDIzNTc0LDIzNjczLDI0MDMwLDI0MDcwLDI0MTgyLDI0MTgwLDI0MzM1LDI0MzQ3LDI0NTM3LDI0NTM0LDI1MTAyLDI1MTAwLDI1MTAxLDI1MTA0LDI1MTg3LDI1MTc5LDI1MTc2LDI1OTEwLDI2MDg5LDI2MDg4LDI2MDkyLDI2MDkzLDI2MzU0LDI2MzU1LDI2Mzc3LDI2NDI5LDI2NDIwLDI2NDE3LDI2NDIxLDI3NDI1LDI3NDkyLDI3NTE1LDI3NjcwLDI3NzQxLDI3NzM1LDI3NzM3LDI3NzQzLDI3NzQ0LDI3NzI4LDI3NzMzLDI3NzQ1LDI3NzM5LDI3NzI1LDI3NzI2LDI4Nzg0LDI5Mjc5LDI5Mjc3LDMwMzM0LDMxNDgxLDMxODU5LDMxOTkyLDMyNTY2LDMyNjUwLDMyNzAxLDMyNzY5LDMyNzcxLDMyNzgwLDMyNzg2LDMyODE5LDMyODk1LDMyOTA1LDMyOTA3LDMyOTA4LDMzMjUxLDMzMjU4LDMzMjY3LDMzMjc2LDMzMjkyLDMzMzA3LDMzMzExLDMzMzkwLDMzMzk0LDMzNDA2LDM0NDExLDM0ODgwLDM0ODkyLDM0OTE1LDM1MTk5LDM4NDMzLDIwMDE4LDIwMTM2LDIwMzAxLDIwMzAzLDIwMjk1LDIwMzExLDIwMzE4LDIwMjc2LDIwMzE1LDIwMzA5LDIwMjcyLDIwMzA0LDIwMzA1LDIwMjg1LDIwMjgyLDIwMjgwLDIwMjkxLDIwMzA4LDIwMjg0LDIwMjk0LDIwMzIzLDIwMzE2LDIwMzIwLDIwMjcxLDIwMzAyLDIwMjc4LDIwMzEzLDIwMzE3LDIwMjk2LDIwMzE0LDIwODEyLDIwODExLDIwODEzLDIwODUzLDIwOTE4LDIwOTE5LDIxMDI5LDIxMDI4LDIxMDMzLDIxMDM0LDIxMDMyLDIxMTYzLDIxMTYxLDIxMTYyLDIxMTY0LDIxMjgzLDIxMzYzLDIxMzY1LDIxNTMzLDIxNTQ5LDIxNTM0LDIxNTY2LDIxNTQyLDIxNTgyLDIxNTQzLDIxNTc0LDIxNTcxLDIxNTU1LDIxNTc2LDIxNTcwLDIxNTMxLDIxNTQ1LDIxNTc4LDIxNTYxLDIxNTYzLDIxNTYwLDIxNTUwLDIxNTU3LDIxNTU4LDIxNTM2LDIxNTY0LDIxNTY4LDIxNTUzLDIxNTQ3LDIxNTM1LDIxNTQ4LDIyMjUwLDIyMjU2LDIyMjQ0LDIyMjUxLDIyMzQ2LDIyMzUzLDIyMzM2LDIyMzQ5LDIyMzQzLDIyMzUwLDIyMzM0LDIyMzUyLDIyMzUxLDIyMzMxLDIyNzY3LDIyODQ2LDIyOTQxLDIyOTMwLDIyOTUyLDIyOTQyLDIyOTQ3LDIyOTM3LDIyOTM0LDIyOTI1LDIyOTQ4LDIyOTMxLDIyOTIyLDIyOTQ5LDIzMzg5LDIzMzg4LDIzMzg2LDIzMzg3LDIzNDM2LDIzNDM1LDIzNDM5LDIzNTk2LDIzNjE2LDIzNjE3LDIzNjE1LDIzNjE0LDIzNjk2LDIzNjk3LDIzNzAwLDIzNjkyLDI0MDQzLDI0MDc2LDI0MjA3LDI0MTk5LDI0MjAyLDI0MzExLDI0MzI0LDI0MzUxLDI0NDIwLDI0NDE4LDI0NDM5LDI0NDQxLDI0NTM2LDI0NTI0LDI0NTM1LDI0NTI1LDI0NTYxLDI0NTU1LDI0NTY4LDI0NTU0LDI1MTA2LDI1MTA1LDI1MjIwLDI1MjM5LDI1MjM4LDI1MjE2LDI1MjA2LDI1MjI1LDI1MTk3LDI1MjI2LDI1MjEyLDI1MjE0LDI1MjA5LDI1MjAzLDI1MjM0LDI1MTk5LDI1MjQwLDI1MTk4LDI1MjM3LDI1MjM1LDI1MjMzLDI1MjIyLDI1OTEzLDI1OTE1LDI1OTEyLDI2MDk3LDI2MzU2LDI2NDYzLDI2NDQ2LDI2NDQ3LDI2NDQ4LDI2NDQ5LDI2NDYwLDI2NDU0LDI2NDYyLDI2NDQxLDI2NDM4LDI2NDY0LDI2NDUxLDI2NDU1LDI3NDkzLDI3NTk5LDI3NzE0LDI3NzQyLDI3ODAxLDI3Nzc3LDI3Nzg0LDI3Nzg1LDI3NzgxLDI3ODAzLDI3NzU0LDI3NzcwLDI3NzkyLDI3NzYwLDI3Nzg4LDI3NzUyLDI3Nzk4LDI3Nzk0LDI3NzczLDI3Nzc5LDI3NzYyLDI3Nzc0LDI3NzY0LDI3NzgyLDI3NzY2LDI3Nzg5LDI3Nzk2LDI3ODAwLDI3Nzc4LDI4NzkwLDI4Nzk2LDI4Nzk3LDI4NzkyLDI5MjgyLDI5MjgxLDI5MjgwLDI5MzgwLDI5Mzc4LDI5NTkwLDI5OTk2LDI5OTk1LDMwMDA3LDMwMDA4LDMwMzM4LDMwNDQ3LDMwNjkxLDMxMTY5LDMxMTY4LDMxMTY3LDMxMzUwLDMxOTk1LDMyNTk3LDMyOTE4LDMyOTE1LDMyOTI1LDMyOTIwLDMyOTIzLDMyOTIyLDMyOTQ2LDMzMzkxLDMzNDI2LDMzNDE5LDMzNDIxLDM1MjExLDM1MjgyLDM1MzI4LDM1ODk1LDM1OTEwLDM1OTI1LDM1OTk3LDM2MTk2LDM2MjA4LDM2Mjc1LDM2NTIzLDM2NTU0LDM2NzYzLDM2Nzg0LDM2ODAyLDM2ODA2LDM2ODA1LDM2ODA0LDI0MDMzLDM3MDA5LDM3MDI2LDM3MDM0LDM3MDMwLDM3MDI3LDM3MTkzLDM3MzE4LDM3MzI0LDM4NDUwLDM4NDQ2LDM4NDQ5LDM4NDQyLDM4NDQ0LDIwMDA2LDIwMDU0LDIwMDgzLDIwMTA3LDIwMTIzLDIwMTI2LDIwMTM5LDIwMTQwLDIwMzM1LDIwMzgxLDIwMzY1LDIwMzM5LDIwMzUxLDIwMzMyLDIwMzc5LDIwMzYzLDIwMzU4LDIwMzU1LDIwMzM2LDIwMzQxLDIwMzYwLDIwMzI5LDIwMzQ3LDIwMzc0LDIwMzUwLDIwMzY3LDIwMzY5LDIwMzQ2LDIwODIwLDIwODE4LDIwODIxLDIwODQxLDIwODU1LDIwODU0LDIwODU2LDIwOTI1LDIwOTg5LDIxMDUxLDIxMDQ4LDIxMDQ3LDIxMDUwLDIxMDQwLDIxMDM4LDIxMDQ2LDIxMDU3LDIxMTgyLDIxMTc5LDIxMzMwLDIxMzMyLDIxMzMxLDIxMzI5LDIxMzUwLDIxMzY3LDIxMzY4LDIxMzY5LDIxNDYyLDIxNDYwLDIxNDYzLDIxNjE5LDIxNjIxLDIxNjU0LDIxNjI0LDIxNjUzLDIxNjMyLDIxNjI3LDIxNjIzLDIxNjM2LDIxNjUwLDIxNjM4LDIxNjI4LDIxNjQ4LDIxNjE3LDIxNjIyLDIxNjQ0LDIxNjU4LDIxNjAyLDIxNjA4LDIxNjQzLDIxNjI5LDIxNjQ2LDIyMjY2LDIyNDAzLDIyMzkxLDIyMzc4LDIyMzc3LDIyMzY5LDIyMzc0LDIyMzcyLDIyMzk2LDIyODEyLDIyODU3LDIyODU1LDIyODU2LDIyODUyLDIyODY4LDIyOTc0LDIyOTcxLDIyOTk2LDIyOTY5LDIyOTU4LDIyOTkzLDIyOTgyLDIyOTkyLDIyOTg5LDIyOTg3LDIyOTk1LDIyOTg2LDIyOTU5LDIyOTYzLDIyOTk0LDIyOTgxLDIzMzkxLDIzMzk2LDIzMzk1LDIzNDQ3LDIzNDUwLDIzNDQ4LDIzNDUyLDIzNDQ5LDIzNDUxLDIzNTc4LDIzNjI0LDIzNjIxLDIzNjIyLDIzNzM1LDIzNzEzLDIzNzM2LDIzNzIxLDIzNzIzLDIzNzI5LDIzNzMxLDI0MDg4LDI0MDkwLDI0MDg2LDI0MDg1LDI0MDkxLDI0MDgxLDI0MTg0LDI0MjE4LDI0MjE1LDI0MjIwLDI0MjEzLDI0MjE0LDI0MzEwLDI0MzU4LDI0MzU5LDI0MzYxLDI0NDQ4LDI0NDQ5LDI0NDQ3LDI0NDQ0LDI0NTQxLDI0NTQ0LDI0NTczLDI0NTY1LDI0NTc1LDI0NTkxLDI0NTk2LDI0NjIzLDI0NjI5LDI0NTk4LDI0NjE4LDI0NTk3LDI0NjA5LDI0NjE1LDI0NjE3LDI0NjE5LDI0NjAzLDI1MTEwLDI1MTA5LDI1MTUxLDI1MTUwLDI1MTUyLDI1MjE1LDI1Mjg5LDI1MjkyLDI1Mjg0LDI1Mjc5LDI1MjgyLDI1MjczLDI1Mjk4LDI1MzA3LDI1MjU5LDI1Mjk5LDI1MzAwLDI1MjkxLDI1Mjg4LDI1MjU2LDI1Mjc3LDI1Mjc2LDI1Mjk2LDI1MzA1LDI1Mjg3LDI1MjkzLDI1MjY5LDI1MzA2LDI1MjY1LDI1MzA0LDI1MzAyLDI1MzAzLDI1Mjg2LDI1MjYwLDI1Mjk0LDI1OTE4LDI2MDIzLDI2MDQ0LDI2MTA2LDI2MTMyLDI2MTMxLDI2MTI0LDI2MTE4LDI2MTE0LDI2MTI2LDI2MTEyLDI2MTI3LDI2MTMzLDI2MTIyLDI2MTE5LDI2MzgxLDI2Mzc5LDI2NDc3LDI2NTA3LDI2NTE3LDI2NDgxLDI2NTI0LDI2NDgzLDI2NDg3LDI2NTAzLDI2NTI1LDI2NTE5LDI2NDc5LDI2NDgwLDI2NDk1LDI2NTA1LDI2NDk0LDI2NTEyLDI2NDg1LDI2NTIyLDI2NTE1LDI2NDkyLDI2NDc0LDI2NDgyLDI3NDI3LDI3NDk0LDI3NDk1LDI3NTE5LDI3NjY3LDI3Njc1LDI3ODc1LDI3ODgwLDI3ODkxLDI3ODI1LDI3ODUyLDI3ODc3LDI3ODI3LDI3ODM3LDI3ODM4LDI3ODM2LDI3ODc0LDI3ODE5LDI3ODYxLDI3ODU5LDI3ODMyLDI3ODQ0LDI3ODMzLDI3ODQxLDI3ODIyLDI3ODYzLDI3ODQ1LDI3ODg5LDI3ODM5LDI3ODM1LDI3ODczLDI3ODY3LDI3ODUwLDI3ODIwLDI3ODg3LDI3ODY4LDI3ODYyLDI3ODcyLDI4ODIxLDI4ODE0LDI4ODE4LDI4ODEwLDI4ODI1LDI5MjI4LDI5MjI5LDI5MjQwLDI5MjU2LDI5Mjg3LDI5Mjg5LDI5Mzc2LDI5MzkwLDI5NDAxLDI5Mzk5LDI5MzkyLDI5NjA5LDI5NjA4LDI5NTk5LDI5NjExLDI5NjA1LDMwMDEzLDMwMTA5LDMwMTA1LDMwMTA2LDMwMzQwLDMwNDAyLDMwNDUwLDMwNDUyLDMwNjkzLDMwNzE3LDMxMDM4LDMxMDQwLDMxMDQxLDMxMTc3LDMxMTc2LDMxMzU0LDMxMzUzLDMxNDgyLDMxOTk4LDMyNTk2LDMyNjUyLDMyNjUxLDMyNzczLDMyOTU0LDMyOTMzLDMyOTMwLDMyOTQ1LDMyOTI5LDMyOTM5LDMyOTM3LDMyOTQ4LDMyOTM4LDMyOTQzLDMzMjUzLDMzMjc4LDMzMjkzLDMzNDU5LDMzNDM3LDMzNDMzLDMzNDUzLDMzNDY5LDMzNDM5LDMzNDY1LDMzNDU3LDMzNDUyLDMzNDQ1LDMzNDU1LDMzNDY0LDMzNDQzLDMzNDU2LDMzNDcwLDMzNDYzLDM0MzgyLDM0NDE3LDIxMDIxLDM0OTIwLDM2NTU1LDM2ODE0LDM2ODIwLDM2ODE3LDM3MDQ1LDM3MDQ4LDM3MDQxLDM3MDQ2LDM3MzE5LDM3MzI5LDM4MjYzLDM4MjcyLDM4NDI4LDM4NDY0LDM4NDYzLDM4NDU5LDM4NDY4LDM4NDY2LDM4NTg1LDM4NjMyLDM4NzM4LDM4NzUwLDIwMTI3LDIwMTQxLDIwMTQyLDIwNDQ5LDIwNDA1LDIwMzk5LDIwNDE1LDIwNDQ4LDIwNDMzLDIwNDMxLDIwNDQ1LDIwNDE5LDIwNDA2LDIwNDQwLDIwNDQ3LDIwNDI2LDIwNDM5LDIwMzk4LDIwNDMyLDIwNDIwLDIwNDE4LDIwNDQyLDIwNDMwLDIwNDQ2LDIwNDA3LDIwODIzLDIwODgyLDIwODgxLDIwODk2LDIxMDcwLDIxMDU5LDIxMDY2LDIxMDY5LDIxMDY4LDIxMDY3LDIxMDYzLDIxMTkxLDIxMTkzLDIxMTg3LDIxMTg1LDIxMjYxLDIxMzM1LDIxMzcxLDIxNDAyLDIxNDY3LDIxNjc2LDIxNjk2LDIxNjcyLDIxNzEwLDIxNzA1LDIxNjg4LDIxNjcwLDIxNjgzLDIxNzAzLDIxNjk4LDIxNjkzLDIxNjc0LDIxNjk3LDIxNzAwLDIxNzA0LDIxNjc5LDIxNjc1LDIxNjgxLDIxNjkxLDIxNjczLDIxNjcxLDIxNjk1LDIyMjcxLDIyNDAyLDIyNDExLDIyNDMyLDIyNDM1LDIyNDM0LDIyNDc4LDIyNDQ2LDIyNDE5LDIyODY5LDIyODY1LDIyODYzLDIyODYyLDIyODY0LDIzMDA0LDIzMDAwLDIzMDM5LDIzMDExLDIzMDE2LDIzMDQzLDIzMDEzLDIzMDE4LDIzMDAyLDIzMDE0LDIzMDQxLDIzMDM1LDIzNDAxLDIzNDU5LDIzNDYyLDIzNDYwLDIzNDU4LDIzNDYxLDIzNTUzLDIzNjMwLDIzNjMxLDIzNjI5LDIzNjI3LDIzNzY5LDIzNzYyLDI0MDU1LDI0MDkzLDI0MTAxLDI0MDk1LDI0MTg5LDI0MjI0LDI0MjMwLDI0MzE0LDI0MzI4LDI0MzY1LDI0NDIxLDI0NDU2LDI0NDUzLDI0NDU4LDI0NDU5LDI0NDU1LDI0NDYwLDI0NDU3LDI0NTk0LDI0NjA1LDI0NjA4LDI0NjEzLDI0NTkwLDI0NjE2LDI0NjUzLDI0Njg4LDI0NjgwLDI0Njc0LDI0NjQ2LDI0NjQzLDI0Njg0LDI0NjgzLDI0NjgyLDI0Njc2LDI1MTUzLDI1MzA4LDI1MzY2LDI1MzUzLDI1MzQwLDI1MzI1LDI1MzQ1LDI1MzI2LDI1MzQxLDI1MzUxLDI1MzI5LDI1MzM1LDI1MzI3LDI1MzI0LDI1MzQyLDI1MzMyLDI1MzYxLDI1MzQ2LDI1OTE5LDI1OTI1LDI2MDI3LDI2MDQ1LDI2MDgyLDI2MTQ5LDI2MTU3LDI2MTQ0LDI2MTUxLDI2MTU5LDI2MTQzLDI2MTUyLDI2MTYxLDI2MTQ4LDI2MzU5LDI2NjIzLDI2NTc5LDI2NjA5LDI2NTgwLDI2NTc2LDI2NjA0LDI2NTUwLDI2NTQzLDI2NjEzLDI2NjAxLDI2NjA3LDI2NTY0LDI2NTc3LDI2NTQ4LDI2NTg2LDI2NTk3LDI2NTUyLDI2NTc1LDI2NTkwLDI2NjExLDI2NTQ0LDI2NTg1LDI2NTk0LDI2NTg5LDI2NTc4LDI3NDk4LDI3NTIzLDI3NTI2LDI3NTczLDI3NjAyLDI3NjA3LDI3Njc5LDI3ODQ5LDI3OTE1LDI3OTU0LDI3OTQ2LDI3OTY5LDI3OTQxLDI3OTE2LDI3OTUzLDI3OTM0LDI3OTI3LDI3OTYzLDI3OTY1LDI3OTY2LDI3OTU4LDI3OTMxLDI3ODkzLDI3OTYxLDI3OTQzLDI3OTYwLDI3OTQ1LDI3OTUwLDI3OTU3LDI3OTE4LDI3OTQ3LDI4ODQzLDI4ODU4LDI4ODUxLDI4ODQ0LDI4ODQ3LDI4ODQ1LDI4ODU2LDI4ODQ2LDI4ODM2LDI5MjMyLDI5Mjk4LDI5Mjk1LDI5MzAwLDI5NDE3LDI5NDA4LDI5NDA5LDI5NjIzLDI5NjQyLDI5NjI3LDI5NjE4LDI5NjQ1LDI5NjMyLDI5NjE5LDI5OTc4LDI5OTk3LDMwMDMxLDMwMDI4LDMwMDMwLDMwMDI3LDMwMTIzLDMwMTE2LDMwMTE3LDMwMTE0LDMwMTE1LDMwMzI4LDMwMzQyLDMwMzQzLDMwMzQ0LDMwNDA4LDMwNDA2LDMwNDAzLDMwNDA1LDMwNDY1LDMwNDU3LDMwNDU2LDMwNDczLDMwNDc1LDMwNDYyLDMwNDYwLDMwNDcxLDMwNjg0LDMwNzIyLDMwNzQwLDMwNzMyLDMwNzMzLDMxMDQ2LDMxMDQ5LDMxMDQ4LDMxMDQ3LDMxMTYxLDMxMTYyLDMxMTg1LDMxMTg2LDMxMTc5LDMxMzU5LDMxMzYxLDMxNDg3LDMxNDg1LDMxODY5LDMyMDAyLDMyMDA1LDMyMDAwLDMyMDA5LDMyMDA3LDMyMDA0LDMyMDA2LDMyNTY4LDMyNjU0LDMyNzAzLDMyNzcyLDMyNzg0LDMyNzgxLDMyNzg1LDMyODIyLDMyOTgyLDMyOTk3LDMyOTg2LDMyOTYzLDMyOTY0LDMyOTcyLDMyOTkzLDMyOTg3LDMyOTc0LDMyOTkwLDMyOTk2LDMyOTg5LDMzMjY4LDMzMzE0LDMzNTExLDMzNTM5LDMzNTQxLDMzNTA3LDMzNDk5LDMzNTEwLDMzNTQwLDMzNTA5LDMzNTM4LDMzNTQ1LDMzNDkwLDMzNDk1LDMzNTIxLDMzNTM3LDMzNTAwLDMzNDkyLDMzNDg5LDMzNTAyLDMzNDkxLDMzNTAzLDMzNTE5LDMzNTQyLDM0Mzg0LDM0NDI1LDM0NDI3LDM0NDI2LDM0ODkzLDM0OTIzLDM1MjAxLDM1Mjg0LDM1MzM2LDM1MzMwLDM1MzMxLDM1OTk4LDM2MDAwLDM2MjEyLDM2MjExLDM2Mjc2LDM2NTU3LDM2NTU2LDM2ODQ4LDM2ODM4LDM2ODM0LDM2ODQyLDM2ODM3LDM2ODQ1LDM2ODQzLDM2ODM2LDM2ODQwLDM3MDY2LDM3MDcwLDM3MDU3LDM3MDU5LDM3MTk1LDM3MTk0LDM3MzI1LDM4Mjc0LDM4NDgwLDM4NDc1LDM4NDc2LDM4NDc3LDM4NzU0LDM4NzYxLDM4ODU5LDM4ODkzLDM4ODk5LDM4OTEzLDM5MDgwLDM5MTMxLDM5MTM1LDM5MzE4LDM5MzIxLDIwMDU2LDIwMTQ3LDIwNDkyLDIwNDkzLDIwNTE1LDIwNDYzLDIwNTE4LDIwNTE3LDIwNDcyLDIwNTIxLDIwNTAyLDIwNDg2LDIwNTQwLDIwNTExLDIwNTA2LDIwNDk4LDIwNDk3LDIwNDc0LDIwNDgwLDIwNTAwLDIwNTIwLDIwNDY1LDIwNTEzLDIwNDkxLDIwNTA1LDIwNTA0LDIwNDY3LDIwNDYyLDIwNTI1LDIwNTIyLDIwNDc4LDIwNTIzLDIwNDg5LDIwODYwLDIwOTAwLDIwOTAxLDIwODk4LDIwOTQxLDIwOTQwLDIwOTM0LDIwOTM5LDIxMDc4LDIxMDg0LDIxMDc2LDIxMDgzLDIxMDg1LDIxMjkwLDIxMzc1LDIxNDA3LDIxNDA1LDIxNDcxLDIxNzM2LDIxNzc2LDIxNzYxLDIxODE1LDIxNzU2LDIxNzMzLDIxNzQ2LDIxNzY2LDIxNzU0LDIxNzgwLDIxNzM3LDIxNzQxLDIxNzI5LDIxNzY5LDIxNzQyLDIxNzM4LDIxNzM0LDIxNzk5LDIxNzY3LDIxNzU3LDIxNzc1LDIyMjc1LDIyMjc2LDIyNDY2LDIyNDg0LDIyNDc1LDIyNDY3LDIyNTM3LDIyNzk5LDIyODcxLDIyODcyLDIyODc0LDIzMDU3LDIzMDY0LDIzMDY4LDIzMDcxLDIzMDY3LDIzMDU5LDIzMDIwLDIzMDcyLDIzMDc1LDIzMDgxLDIzMDc3LDIzMDUyLDIzMDQ5LDIzNDAzLDIzNjQwLDIzNDcyLDIzNDc1LDIzNDc4LDIzNDc2LDIzNDcwLDIzNDc3LDIzNDgxLDIzNDgwLDIzNTU2LDIzNjMzLDIzNjM3LDIzNjMyLDIzNzg5LDIzODA1LDIzODAzLDIzNzg2LDIzNzg0LDIzNzkyLDIzNzk4LDIzODA5LDIzNzk2LDI0MDQ2LDI0MTA5LDI0MTA3LDI0MjM1LDI0MjM3LDI0MjMxLDI0MzY5LDI0NDY2LDI0NDY1LDI0NDY0LDI0NjY1LDI0Njc1LDI0Njc3LDI0NjU2LDI0NjYxLDI0Njg1LDI0NjgxLDI0Njg3LDI0NzA4LDI0NzM1LDI0NzMwLDI0NzE3LDI0NzI0LDI0NzE2LDI0NzA5LDI0NzI2LDI1MTU5LDI1MzMxLDI1MzUyLDI1MzQzLDI1NDIyLDI1NDA2LDI1MzkxLDI1NDI5LDI1NDEwLDI1NDE0LDI1NDIzLDI1NDE3LDI1NDAyLDI1NDI0LDI1NDA1LDI1Mzg2LDI1Mzg3LDI1Mzg0LDI1NDIxLDI1NDIwLDI1OTI4LDI1OTI5LDI2MDA5LDI2MDQ5LDI2MDUzLDI2MTc4LDI2MTg1LDI2MTkxLDI2MTc5LDI2MTk0LDI2MTg4LDI2MTgxLDI2MTc3LDI2MzYwLDI2Mzg4LDI2Mzg5LDI2MzkxLDI2NjU3LDI2NjgwLDI2Njk2LDI2Njk0LDI2NzA3LDI2NjgxLDI2NjkwLDI2NzA4LDI2NjY1LDI2ODAzLDI2NjQ3LDI2NzAwLDI2NzA1LDI2Njg1LDI2NjEyLDI2NzA0LDI2Njg4LDI2Njg0LDI2NjkxLDI2NjY2LDI2NjkzLDI2NjQzLDI2NjQ4LDI2Njg5LDI3NTMwLDI3NTI5LDI3NTc1LDI3NjgzLDI3Njg3LDI3Njg4LDI3Njg2LDI3Njg0LDI3ODg4LDI4MDEwLDI4MDUzLDI4MDQwLDI4MDM5LDI4MDA2LDI4MDI0LDI4MDIzLDI3OTkzLDI4MDUxLDI4MDEyLDI4MDQxLDI4MDE0LDI3OTk0LDI4MDIwLDI4MDA5LDI4MDQ0LDI4MDQyLDI4MDI1LDI4MDM3LDI4MDA1LDI4MDUyLDI4ODc0LDI4ODg4LDI4OTAwLDI4ODg5LDI4ODcyLDI4ODc5LDI5MjQxLDI5MzA1LDI5NDM2LDI5NDMzLDI5NDM3LDI5NDMyLDI5NDMxLDI5NTc0LDI5Njc3LDI5NzA1LDI5Njc4LDI5NjY0LDI5Njc0LDI5NjYyLDMwMDM2LDMwMDQ1LDMwMDQ0LDMwMDQyLDMwMDQxLDMwMTQyLDMwMTQ5LDMwMTUxLDMwMTMwLDMwMTMxLDMwMTQxLDMwMTQwLDMwMTM3LDMwMTQ2LDMwMTM2LDMwMzQ3LDMwMzg0LDMwNDEwLDMwNDEzLDMwNDE0LDMwNTA1LDMwNDk1LDMwNDk2LDMwNTA0LDMwNjk3LDMwNzY4LDMwNzU5LDMwNzc2LDMwNzQ5LDMwNzcyLDMwNzc1LDMwNzU3LDMwNzY1LDMwNzUyLDMwNzUxLDMwNzcwLDMxMDYxLDMxMDU2LDMxMDcyLDMxMDcxLDMxMDYyLDMxMDcwLDMxMDY5LDMxMDYzLDMxMDY2LDMxMjA0LDMxMjAzLDMxMjA3LDMxMTk5LDMxMjA2LDMxMjA5LDMxMTkyLDMxMzY0LDMxMzY4LDMxNDQ5LDMxNDk0LDMxNTA1LDMxODgxLDMyMDMzLDMyMDIzLDMyMDExLDMyMDEwLDMyMDMyLDMyMDM0LDMyMDIwLDMyMDE2LDMyMDIxLDMyMDI2LDMyMDI4LDMyMDEzLDMyMDI1LDMyMDI3LDMyNTcwLDMyNjA3LDMyNjYwLDMyNzA5LDMyNzA1LDMyNzc0LDMyNzkyLDMyNzg5LDMyNzkzLDMyNzkxLDMyODI5LDMyODMxLDMzMDA5LDMzMDI2LDMzMDA4LDMzMDI5LDMzMDA1LDMzMDEyLDMzMDMwLDMzMDE2LDMzMDExLDMzMDMyLDMzMDIxLDMzMDM0LDMzMDIwLDMzMDA3LDMzMjYxLDMzMjYwLDMzMjgwLDMzMjk2LDMzMzIyLDMzMzIzLDMzMzIwLDMzMzI0LDMzNDY3LDMzNTc5LDMzNjE4LDMzNjIwLDMzNjEwLDMzNTkyLDMzNjE2LDMzNjA5LDMzNTg5LDMzNTg4LDMzNjE1LDMzNTg2LDMzNTkzLDMzNTkwLDMzNTU5LDMzNjAwLDMzNTg1LDMzNTc2LDMzNjAzLDM0Mzg4LDM0NDQyLDM0NDc0LDM0NDUxLDM0NDY4LDM0NDczLDM0NDQ0LDM0NDY3LDM0NDYwLDM0OTI4LDM0OTM1LDM0OTQ1LDM0OTQ2LDM0OTQxLDM0OTM3LDM1MzUyLDM1MzQ0LDM1MzQyLDM1MzQwLDM1MzQ5LDM1MzM4LDM1MzUxLDM1MzQ3LDM1MzUwLDM1MzQzLDM1MzQ1LDM1OTEyLDM1OTYyLDM1OTYxLDM2MDAxLDM2MDAyLDM2MjE1LDM2NTI0LDM2NTYyLDM2NTY0LDM2NTU5LDM2Nzg1LDM2ODY1LDM2ODcwLDM2ODU1LDM2ODY0LDM2ODU4LDM2ODUyLDM2ODY3LDM2ODYxLDM2ODY5LDM2ODU2LDM3MDEzLDM3MDg5LDM3MDg1LDM3MDkwLDM3MjAyLDM3MTk3LDM3MTk2LDM3MzM2LDM3MzQxLDM3MzM1LDM3MzQwLDM3MzM3LDM4Mjc1LDM4NDk4LDM4NDk5LDM4NDk3LDM4NDkxLDM4NDkzLDM4NTAwLDM4NDg4LDM4NDk0LDM4NTg3LDM5MTM4LDM5MzQwLDM5NTkyLDM5NjQwLDM5NzE3LDM5NzMwLDM5NzQwLDIwMDk0LDIwNjAyLDIwNjA1LDIwNTcyLDIwNTUxLDIwNTQ3LDIwNTU2LDIwNTcwLDIwNTUzLDIwNTgxLDIwNTk4LDIwNTU4LDIwNTY1LDIwNTk3LDIwNTk2LDIwNTk5LDIwNTU5LDIwNDk1LDIwNTkxLDIwNTg5LDIwODI4LDIwODg1LDIwOTc2LDIxMDk4LDIxMTAzLDIxMjAyLDIxMjA5LDIxMjA4LDIxMjA1LDIxMjY0LDIxMjYzLDIxMjczLDIxMzExLDIxMzEyLDIxMzEwLDIxNDQzLDI2MzY0LDIxODMwLDIxODY2LDIxODYyLDIxODI4LDIxODU0LDIxODU3LDIxODI3LDIxODM0LDIxODA5LDIxODQ2LDIxODM5LDIxODQ1LDIxODA3LDIxODYwLDIxODE2LDIxODA2LDIxODUyLDIxODA0LDIxODU5LDIxODExLDIxODI1LDIxODQ3LDIyMjgwLDIyMjgzLDIyMjgxLDIyNDk1LDIyNTMzLDIyNTM4LDIyNTM0LDIyNDk2LDIyNTAwLDIyNTIyLDIyNTMwLDIyNTgxLDIyNTE5LDIyNTIxLDIyODE2LDIyODgyLDIzMDk0LDIzMTA1LDIzMTEzLDIzMTQyLDIzMTQ2LDIzMTA0LDIzMTAwLDIzMTM4LDIzMTMwLDIzMTEwLDIzMTE0LDIzNDA4LDIzNDk1LDIzNDkzLDIzNDkyLDIzNDkwLDIzNDg3LDIzNDk0LDIzNTYxLDIzNTYwLDIzNTU5LDIzNjQ4LDIzNjQ0LDIzNjQ1LDIzODE1LDIzODE0LDIzODIyLDIzODM1LDIzODMwLDIzODQyLDIzODI1LDIzODQ5LDIzODI4LDIzODMzLDIzODQ0LDIzODQ3LDIzODMxLDI0MDM0LDI0MTIwLDI0MTE4LDI0MTE1LDI0MTE5LDI0MjQ3LDI0MjQ4LDI0MjQ2LDI0MjQ1LDI0MjU0LDI0MzczLDI0Mzc1LDI0NDA3LDI0NDI4LDI0NDI1LDI0NDI3LDI0NDcxLDI0NDczLDI0NDc4LDI0NDcyLDI0NDgxLDI0NDgwLDI0NDc2LDI0NzAzLDI0NzM5LDI0NzEzLDI0NzM2LDI0NzQ0LDI0Nzc5LDI0NzU2LDI0ODA2LDI0NzY1LDI0NzczLDI0NzYzLDI0NzU3LDI0Nzk2LDI0NzY0LDI0NzkyLDI0Nzg5LDI0Nzc0LDI0Nzk5LDI0NzYwLDI0Nzk0LDI0Nzc1LDI1MTE0LDI1MTE1LDI1MTYwLDI1NTA0LDI1NTExLDI1NDU4LDI1NDk0LDI1NTA2LDI1NTA5LDI1NDYzLDI1NDQ3LDI1NDk2LDI1NTE0LDI1NDU3LDI1NTEzLDI1NDgxLDI1NDc1LDI1NDk5LDI1NDUxLDI1NTEyLDI1NDc2LDI1NDgwLDI1NDk3LDI1NTA1LDI1NTE2LDI1NDkwLDI1NDg3LDI1NDcyLDI1NDY3LDI1NDQ5LDI1NDQ4LDI1NDY2LDI1OTQ5LDI1OTQyLDI1OTM3LDI1OTQ1LDI1OTQzLDIxODU1LDI1OTM1LDI1OTQ0LDI1OTQxLDI1OTQwLDI2MDEyLDI2MDExLDI2MDI4LDI2MDYzLDI2MDU5LDI2MDYwLDI2MDYyLDI2MjA1LDI2MjAyLDI2MjEyLDI2MjE2LDI2MjE0LDI2MjA2LDI2MzYxLDIxMjA3LDI2Mzk1LDI2NzUzLDI2Nzk5LDI2Nzg2LDI2NzcxLDI2ODA1LDI2NzUxLDI2NzQyLDI2ODAxLDI2NzkxLDI2Nzc1LDI2ODAwLDI2NzU1LDI2ODIwLDI2Nzk3LDI2NzU4LDI2NzU3LDI2NzcyLDI2NzgxLDI2NzkyLDI2NzgzLDI2Nzg1LDI2NzU0LDI3NDQyLDI3NTc4LDI3NjI3LDI3NjI4LDI3NjkxLDI4MDQ2LDI4MDkyLDI4MTQ3LDI4MTIxLDI4MDgyLDI4MTI5LDI4MTA4LDI4MTMyLDI4MTU1LDI4MTU0LDI4MTY1LDI4MTAzLDI4MTA3LDI4MDc5LDI4MTEzLDI4MDc4LDI4MTI2LDI4MTUzLDI4MDg4LDI4MTUxLDI4MTQ5LDI4MTAxLDI4MTE0LDI4MTg2LDI4MDg1LDI4MTIyLDI4MTM5LDI4MTIwLDI4MTM4LDI4MTQ1LDI4MTQyLDI4MTM2LDI4MTAyLDI4MTAwLDI4MDc0LDI4MTQwLDI4MDk1LDI4MTM0LDI4OTIxLDI4OTM3LDI4OTM4LDI4OTI1LDI4OTExLDI5MjQ1LDI5MzA5LDI5MzEzLDI5NDY4LDI5NDY3LDI5NDYyLDI5NDU5LDI5NDY1LDI5NTc1LDI5NzAxLDI5NzA2LDI5Njk5LDI5NzAyLDI5Njk0LDI5NzA5LDI5OTIwLDI5OTQyLDI5OTQzLDI5OTgwLDI5OTg2LDMwMDUzLDMwMDU0LDMwMDUwLDMwMDY0LDMwMDk1LDMwMTY0LDMwMTY1LDMwMTMzLDMwMTU0LDMwMTU3LDMwMzUwLDMwNDIwLDMwNDE4LDMwNDI3LDMwNTE5LDMwNTI2LDMwNTI0LDMwNTE4LDMwNTIwLDMwNTIyLDMwODI3LDMwNzg3LDMwNzk4LDMxMDc3LDMxMDgwLDMxMDg1LDMxMjI3LDMxMzc4LDMxMzgxLDMxNTIwLDMxNTI4LDMxNTE1LDMxNTMyLDMxNTI2LDMxNTEzLDMxNTE4LDMxNTM0LDMxODkwLDMxODk1LDMxODkzLDMyMDcwLDMyMDY3LDMyMTEzLDMyMDQ2LDMyMDU3LDMyMDYwLDMyMDY0LDMyMDQ4LDMyMDUxLDMyMDY4LDMyMDQ3LDMyMDY2LDMyMDUwLDMyMDQ5LDMyNTczLDMyNjcwLDMyNjY2LDMyNzE2LDMyNzE4LDMyNzIyLDMyNzk2LDMyODQyLDMyODM4LDMzMDcxLDMzMDQ2LDMzMDU5LDMzMDY3LDMzMDY1LDMzMDcyLDMzMDYwLDMzMjgyLDMzMzMzLDMzMzM1LDMzMzM0LDMzMzM3LDMzNjc4LDMzNjk0LDMzNjg4LDMzNjU2LDMzNjk4LDMzNjg2LDMzNzI1LDMzNzA3LDMzNjgyLDMzNjc0LDMzNjgzLDMzNjczLDMzNjk2LDMzNjU1LDMzNjU5LDMzNjYwLDMzNjcwLDMzNzAzLDM0Mzg5LDI0NDI2LDM0NTAzLDM0NDk2LDM0NDg2LDM0NTAwLDM0NDg1LDM0NTAyLDM0NTA3LDM0NDgxLDM0NDc5LDM0NTA1LDM0ODk5LDM0OTc0LDM0OTUyLDM0OTg3LDM0OTYyLDM0OTY2LDM0OTU3LDM0OTU1LDM1MjE5LDM1MjE1LDM1MzcwLDM1MzU3LDM1MzYzLDM1MzY1LDM1Mzc3LDM1MzczLDM1MzU5LDM1MzU1LDM1MzYyLDM1OTEzLDM1OTMwLDM2MDA5LDM2MDEyLDM2MDExLDM2MDA4LDM2MDEwLDM2MDA3LDM2MTk5LDM2MTk4LDM2Mjg2LDM2MjgyLDM2NTcxLDM2NTc1LDM2ODg5LDM2ODc3LDM2ODkwLDM2ODg3LDM2ODk5LDM2ODk1LDM2ODkzLDM2ODgwLDM2ODg1LDM2ODk0LDM2ODk2LDM2ODc5LDM2ODk4LDM2ODg2LDM2ODkxLDM2ODg0LDM3MDk2LDM3MTAxLDM3MTE3LDM3MjA3LDM3MzI2LDM3MzY1LDM3MzUwLDM3MzQ3LDM3MzUxLDM3MzU3LDM3MzUzLDM4MjgxLDM4NTA2LDM4NTE3LDM4NTE1LDM4NTIwLDM4NTEyLDM4NTE2LDM4NTE4LDM4NTE5LDM4NTA4LDM4NTkyLDM4NjM0LDM4NjMzLDMxNDU2LDMxNDU1LDM4OTE0LDM4OTE1LDM5NzcwLDQwMTY1LDQwNTY1LDQwNTc1LDQwNjEzLDQwNjM1LDIwNjQyLDIwNjIxLDIwNjEzLDIwNjMzLDIwNjI1LDIwNjA4LDIwNjMwLDIwNjMyLDIwNjM0LDI2MzY4LDIwOTc3LDIxMTA2LDIxMTA4LDIxMTA5LDIxMDk3LDIxMjE0LDIxMjEzLDIxMjExLDIxMzM4LDIxNDEzLDIxODgzLDIxODg4LDIxOTI3LDIxODg0LDIxODk4LDIxOTE3LDIxOTEyLDIxODkwLDIxOTE2LDIxOTMwLDIxOTA4LDIxODk1LDIxODk5LDIxODkxLDIxOTM5LDIxOTM0LDIxOTE5LDIxODIyLDIxOTM4LDIxOTE0LDIxOTQ3LDIxOTMyLDIxOTM3LDIxODg2LDIxODk3LDIxOTMxLDIxOTEzLDIyMjg1LDIyNTc1LDIyNTcwLDIyNTgwLDIyNTY0LDIyNTc2LDIyNTc3LDIyNTYxLDIyNTU3LDIyNTYwLDIyNzc3LDIyNzc4LDIyODgwLDIzMTU5LDIzMTk0LDIzMTY3LDIzMTg2LDIzMTk1LDIzMjA3LDIzNDExLDIzNDA5LDIzNTA2LDIzNTAwLDIzNTA3LDIzNTA0LDIzNTYyLDIzNTYzLDIzNjAxLDIzODg0LDIzODg4LDIzODYwLDIzODc5LDI0MDYxLDI0MTMzLDI0MTI1LDI0MTI4LDI0MTMxLDI0MTkwLDI0MjY2LDI0MjU3LDI0MjU4LDI0MjYwLDI0MzgwLDI0NDI5LDI0NDg5LDI0NDkwLDI0NDg4LDI0Nzg1LDI0ODAxLDI0NzU0LDI0NzU4LDI0ODAwLDI0ODYwLDI0ODY3LDI0ODI2LDI0ODUzLDI0ODE2LDI0ODI3LDI0ODIwLDI0OTM2LDI0ODE3LDI0ODQ2LDI0ODIyLDI0ODQxLDI0ODMyLDI0ODUwLDI1MTE5LDI1MTYxLDI1NTA3LDI1NDg0LDI1NTUxLDI1NTM2LDI1NTc3LDI1NTQ1LDI1NTQyLDI1NTQ5LDI1NTU0LDI1NTcxLDI1NTUyLDI1NTY5LDI1NTU4LDI1NTgxLDI1NTgyLDI1NDYyLDI1NTg4LDI1NTc4LDI1NTYzLDI1NjgyLDI1NTYyLDI1NTkzLDI1OTUwLDI1OTU4LDI1OTU0LDI1OTU1LDI2MDAxLDI2MDAwLDI2MDMxLDI2MjIyLDI2MjI0LDI2MjI4LDI2MjMwLDI2MjIzLDI2MjU3LDI2MjM0LDI2MjM4LDI2MjMxLDI2MzY2LDI2MzY3LDI2Mzk5LDI2Mzk3LDI2ODc0LDI2ODM3LDI2ODQ4LDI2ODQwLDI2ODM5LDI2ODg1LDI2ODQ3LDI2ODY5LDI2ODYyLDI2ODU1LDI2ODczLDI2ODM0LDI2ODY2LDI2ODUxLDI2ODI3LDI2ODI5LDI2ODkzLDI2ODk4LDI2ODk0LDI2ODI1LDI2ODQyLDI2OTkwLDI2ODc1LDI3NDU0LDI3NDUwLDI3NDUzLDI3NTQ0LDI3NTQyLDI3NTgwLDI3NjMxLDI3Njk0LDI3Njk1LDI3NjkyLDI4MjA3LDI4MjE2LDI4MjQ0LDI4MTkzLDI4MjEwLDI4MjYzLDI4MjM0LDI4MTkyLDI4MTk3LDI4MTk1LDI4MTg3LDI4MjUxLDI4MjQ4LDI4MTk2LDI4MjQ2LDI4MjcwLDI4MjA1LDI4MTk4LDI4MjcxLDI4MjEyLDI4MjM3LDI4MjE4LDI4MjA0LDI4MjI3LDI4MTg5LDI4MjIyLDI4MzYzLDI4Mjk3LDI4MTg1LDI4MjM4LDI4MjU5LDI4MjI4LDI4Mjc0LDI4MjY1LDI4MjU1LDI4OTUzLDI4OTU0LDI4OTY2LDI4OTc2LDI4OTYxLDI4OTgyLDI5MDM4LDI4OTU2LDI5MjYwLDI5MzE2LDI5MzEyLDI5NDk0LDI5NDc3LDI5NDkyLDI5NDgxLDI5NzU0LDI5NzM4LDI5NzQ3LDI5NzMwLDI5NzMzLDI5NzQ5LDI5NzUwLDI5NzQ4LDI5NzQzLDI5NzIzLDI5NzM0LDI5NzM2LDI5OTg5LDI5OTkwLDMwMDU5LDMwMDU4LDMwMTc4LDMwMTcxLDMwMTc5LDMwMTY5LDMwMTY4LDMwMTc0LDMwMTc2LDMwMzMxLDMwMzMyLDMwMzU4LDMwMzU1LDMwMzg4LDMwNDI4LDMwNTQzLDMwNzAxLDMwODEzLDMwODI4LDMwODMxLDMxMjQ1LDMxMjQwLDMxMjQzLDMxMjM3LDMxMjMyLDMxMzg0LDMxMzgzLDMxMzgyLDMxNDYxLDMxNDU5LDMxNTYxLDMxNTc0LDMxNTU4LDMxNTY4LDMxNTcwLDMxNTcyLDMxNTY1LDMxNTYzLDMxNTY3LDMxNTY5LDMxOTAzLDMxOTA5LDMyMDk0LDMyMDgwLDMyMTA0LDMyMDg1LDMyMDQzLDMyMTEwLDMyMTE0LDMyMDk3LDMyMTAyLDMyMDk4LDMyMTEyLDMyMTE1LDIxODkyLDMyNzI0LDMyNzI1LDMyNzc5LDMyODUwLDMyOTAxLDMzMTA5LDMzMTA4LDMzMDk5LDMzMTA1LDMzMTAyLDMzMDgxLDMzMDk0LDMzMDg2LDMzMTAwLDMzMTA3LDMzMTQwLDMzMjk4LDMzMzA4LDMzNzY5LDMzNzk1LDMzNzg0LDMzODA1LDMzNzYwLDMzNzMzLDMzODAzLDMzNzI5LDMzNzc1LDMzNzc3LDMzNzgwLDMzODc5LDMzODAyLDMzNzc2LDMzODA0LDMzNzQwLDMzNzg5LDMzNzc4LDMzNzM4LDMzODQ4LDMzODA2LDMzNzk2LDMzNzU2LDMzNzk5LDMzNzQ4LDMzNzU5LDM0Mzk1LDM0NTI3LDM0NTIxLDM0NTQxLDM0NTE2LDM0NTIzLDM0NTMyLDM0NTEyLDM0NTI2LDM0OTAzLDM1MDA5LDM1MDEwLDM0OTkzLDM1MjAzLDM1MjIyLDM1Mzg3LDM1NDI0LDM1NDEzLDM1NDIyLDM1Mzg4LDM1MzkzLDM1NDEyLDM1NDE5LDM1NDA4LDM1Mzk4LDM1MzgwLDM1Mzg2LDM1MzgyLDM1NDE0LDM1OTM3LDM1OTcwLDM2MDE1LDM2MDI4LDM2MDE5LDM2MDI5LDM2MDMzLDM2MDI3LDM2MDMyLDM2MDIwLDM2MDIzLDM2MDIyLDM2MDMxLDM2MDI0LDM2MjM0LDM2MjI5LDM2MjI1LDM2MzAyLDM2MzE3LDM2Mjk5LDM2MzE0LDM2MzA1LDM2MzAwLDM2MzE1LDM2Mjk0LDM2NjAzLDM2NjAwLDM2NjA0LDM2NzY0LDM2OTEwLDM2OTE3LDM2OTEzLDM2OTIwLDM2OTE0LDM2OTE4LDM3MTIyLDM3MTA5LDM3MTI5LDM3MTE4LDM3MjE5LDM3MjIxLDM3MzI3LDM3Mzk2LDM3Mzk3LDM3NDExLDM3Mzg1LDM3NDA2LDM3Mzg5LDM3MzkyLDM3MzgzLDM3MzkzLDM4MjkyLDM4Mjg3LDM4MjgzLDM4Mjg5LDM4MjkxLDM4MjkwLDM4Mjg2LDM4NTM4LDM4NTQyLDM4NTM5LDM4NTI1LDM4NTMzLDM4NTM0LDM4NTQxLDM4NTE0LDM4NTMyLDM4NTkzLDM4NTk3LDM4NTk2LDM4NTk4LDM4NTk5LDM4NjM5LDM4NjQyLDM4ODYwLDM4OTE3LDM4OTE4LDM4OTIwLDM5MTQzLDM5MTQ2LDM5MTUxLDM5MTQ1LDM5MTU0LDM5MTQ5LDM5MzQyLDM5MzQxLDQwNjQzLDQwNjUzLDQwNjU3LDIwMDk4LDIwNjUzLDIwNjYxLDIwNjU4LDIwNjU5LDIwNjc3LDIwNjcwLDIwNjUyLDIwNjYzLDIwNjY3LDIwNjU1LDIwNjc5LDIxMTE5LDIxMTExLDIxMTE3LDIxMjE1LDIxMjIyLDIxMjIwLDIxMjE4LDIxMjE5LDIxMjk1LDIxOTgzLDIxOTkyLDIxOTcxLDIxOTkwLDIxOTY2LDIxOTgwLDIxOTU5LDIxOTY5LDIxOTg3LDIxOTg4LDIxOTk5LDIxOTc4LDIxOTg1LDIxOTU3LDIxOTU4LDIxOTg5LDIxOTYxLDIyMjkwLDIyMjkxLDIyNjIyLDIyNjA5LDIyNjE2LDIyNjE1LDIyNjE4LDIyNjEyLDIyNjM1LDIyNjA0LDIyNjM3LDIyNjAyLDIyNjI2LDIyNjEwLDIyNjAzLDIyODg3LDIzMjMzLDIzMjQxLDIzMjQ0LDIzMjMwLDIzMjI5LDIzMjI4LDIzMjE5LDIzMjM0LDIzMjE4LDIzOTEzLDIzOTE5LDI0MTQwLDI0MTg1LDI0MjY1LDI0MjY0LDI0MzM4LDI0NDA5LDI0NDkyLDI0NDk0LDI0ODU4LDI0ODQ3LDI0OTA0LDI0ODYzLDI0ODE5LDI0ODU5LDI0ODI1LDI0ODMzLDI0ODQwLDI0OTEwLDI0OTA4LDI0OTAwLDI0OTA5LDI0ODk0LDI0ODg0LDI0ODcxLDI0ODQ1LDI0ODM4LDI0ODg3LDI1MTIxLDI1MTIyLDI1NjE5LDI1NjYyLDI1NjMwLDI1NjQyLDI1NjQ1LDI1NjYxLDI1NjQ0LDI1NjE1LDI1NjI4LDI1NjIwLDI1NjEzLDI1NjU0LDI1NjIyLDI1NjIzLDI1NjA2LDI1OTY0LDI2MDE1LDI2MDMyLDI2MjYzLDI2MjQ5LDI2MjQ3LDI2MjQ4LDI2MjYyLDI2MjQ0LDI2MjY0LDI2MjUzLDI2MzcxLDI3MDI4LDI2OTg5LDI2OTcwLDI2OTk5LDI2OTc2LDI2OTY0LDI2OTk3LDI2OTI4LDI3MDEwLDI2OTU0LDI2OTg0LDI2OTg3LDI2OTc0LDI2OTYzLDI3MDAxLDI3MDE0LDI2OTczLDI2OTc5LDI2OTcxLDI3NDYzLDI3NTA2LDI3NTg0LDI3NTgzLDI3NjAzLDI3NjQ1LDI4MzIyLDI4MzM1LDI4MzcxLDI4MzQyLDI4MzU0LDI4MzA0LDI4MzE3LDI4MzU5LDI4MzU3LDI4MzI1LDI4MzEyLDI4MzQ4LDI4MzQ2LDI4MzMxLDI4MzY5LDI4MzEwLDI4MzE2LDI4MzU2LDI4MzcyLDI4MzMwLDI4MzI3LDI4MzQwLDI5MDA2LDI5MDE3LDI5MDMzLDI5MDI4LDI5MDAxLDI5MDMxLDI5MDIwLDI5MDM2LDI5MDMwLDI5MDA0LDI5MDI5LDI5MDIyLDI4OTk4LDI5MDMyLDI5MDE0LDI5MjQyLDI5MjY2LDI5NDk1LDI5NTA5LDI5NTAzLDI5NTAyLDI5ODA3LDI5Nzg2LDI5NzgxLDI5NzkxLDI5NzkwLDI5NzYxLDI5NzU5LDI5Nzg1LDI5Nzg3LDI5Nzg4LDMwMDcwLDMwMDcyLDMwMjA4LDMwMTkyLDMwMjA5LDMwMTk0LDMwMTkzLDMwMjAyLDMwMjA3LDMwMTk2LDMwMTk1LDMwNDMwLDMwNDMxLDMwNTU1LDMwNTcxLDMwNTY2LDMwNTU4LDMwNTYzLDMwNTg1LDMwNTcwLDMwNTcyLDMwNTU2LDMwNTY1LDMwNTY4LDMwNTYyLDMwNzAyLDMwODYyLDMwODk2LDMwODcxLDMwODcyLDMwODYwLDMwODU3LDMwODQ0LDMwODY1LDMwODY3LDMwODQ3LDMxMDk4LDMxMTAzLDMxMTA1LDMzODM2LDMxMTY1LDMxMjYwLDMxMjU4LDMxMjY0LDMxMjUyLDMxMjYzLDMxMjYyLDMxMzkxLDMxMzkyLDMxNjA3LDMxNjgwLDMxNTg0LDMxNTk4LDMxNTkxLDMxOTIxLDMxOTIzLDMxOTI1LDMyMTQ3LDMyMTIxLDMyMTQ1LDMyMTI5LDMyMTQzLDMyMDkxLDMyNjIyLDMyNjE3LDMyNjE4LDMyNjI2LDMyNjgxLDMyNjgwLDMyNjc2LDMyODU0LDMyODU2LDMyOTAyLDMyOTAwLDMzMTM3LDMzMTM2LDMzMTQ0LDMzMTI1LDMzMTM0LDMzMTM5LDMzMTMxLDMzMTQ1LDMzMTQ2LDMzMTI2LDMzMjg1LDMzMzUxLDMzOTIyLDMzOTExLDMzODUzLDMzODQxLDMzOTA5LDMzODk0LDMzODk5LDMzODY1LDMzOTAwLDMzODgzLDMzODUyLDMzODQ1LDMzODg5LDMzODkxLDMzODk3LDMzOTAxLDMzODYyLDM0Mzk4LDM0Mzk2LDM0Mzk5LDM0NTUzLDM0NTc5LDM0NTY4LDM0NTY3LDM0NTYwLDM0NTU4LDM0NTU1LDM0NTYyLDM0NTYzLDM0NTY2LDM0NTcwLDM0OTA1LDM1MDM5LDM1MDI4LDM1MDMzLDM1MDM2LDM1MDMyLDM1MDM3LDM1MDQxLDM1MDE4LDM1MDI5LDM1MDI2LDM1MjI4LDM1Mjk5LDM1NDM1LDM1NDQyLDM1NDQzLDM1NDMwLDM1NDMzLDM1NDQwLDM1NDYzLDM1NDUyLDM1NDI3LDM1NDg4LDM1NDQxLDM1NDYxLDM1NDM3LDM1NDI2LDM1NDM4LDM1NDM2LDM1NDQ5LDM1NDUxLDM1MzkwLDM1NDMyLDM1OTM4LDM1OTc4LDM1OTc3LDM2MDQyLDM2MDM5LDM2MDQwLDM2MDM2LDM2MDE4LDM2MDM1LDM2MDM0LDM2MDM3LDM2MzIxLDM2MzE5LDM2MzI4LDM2MzM1LDM2MzM5LDM2MzQ2LDM2MzMwLDM2MzI0LDM2MzI2LDM2NTMwLDM2NjExLDM2NjE3LDM2NjA2LDM2NjE4LDM2NzY3LDM2Nzg2LDM2OTM5LDM2OTM4LDM2OTQ3LDM2OTMwLDM2OTQ4LDM2OTI0LDM2OTQ5LDM2OTQ0LDM2OTM1LDM2OTQzLDM2OTQyLDM2OTQxLDM2OTQ1LDM2OTI2LDM2OTI5LDM3MTM4LDM3MTQzLDM3MjI4LDM3MjI2LDM3MjI1LDM3MzIxLDM3NDMxLDM3NDYzLDM3NDMyLDM3NDM3LDM3NDQwLDM3NDM4LDM3NDY3LDM3NDUxLDM3NDc2LDM3NDU3LDM3NDI4LDM3NDQ5LDM3NDUzLDM3NDQ1LDM3NDMzLDM3NDM5LDM3NDY2LDM4Mjk2LDM4NTUyLDM4NTQ4LDM4NTQ5LDM4NjA1LDM4NjAzLDM4NjAxLDM4NjAyLDM4NjQ3LDM4NjUxLDM4NjQ5LDM4NjQ2LDM4NzQyLDM4NzcyLDM4Nzc0LDM4OTI4LDM4OTI5LDM4OTMxLDM4OTIyLDM4OTMwLDM4OTI0LDM5MTY0LDM5MTU2LDM5MTY1LDM5MTY2LDM5MzQ3LDM5MzQ1LDM5MzQ4LDM5NjQ5LDQwMTY5LDQwNTc4LDQwNzE4LDQwNzIzLDQwNzM2LDIwNzExLDIwNzE4LDIwNzA5LDIwNjk0LDIwNzE3LDIwNjk4LDIwNjkzLDIwNjg3LDIwNjg5LDIwNzIxLDIwNjg2LDIwNzEzLDIwODM0LDIwOTc5LDIxMTIzLDIxMTIyLDIxMjk3LDIxNDIxLDIyMDE0LDIyMDE2LDIyMDQzLDIyMDM5LDIyMDEzLDIyMDM2LDIyMDIyLDIyMDI1LDIyMDI5LDIyMDMwLDIyMDA3LDIyMDM4LDIyMDQ3LDIyMDI0LDIyMDMyLDIyMDA2LDIyMjk2LDIyMjk0LDIyNjQ1LDIyNjU0LDIyNjU5LDIyNjc1LDIyNjY2LDIyNjQ5LDIyNjYxLDIyNjUzLDIyNzgxLDIyODIxLDIyODE4LDIyODIwLDIyODkwLDIyODg5LDIzMjY1LDIzMjcwLDIzMjczLDIzMjU1LDIzMjU0LDIzMjU2LDIzMjY3LDIzNDEzLDIzNTE4LDIzNTI3LDIzNTIxLDIzNTI1LDIzNTI2LDIzNTI4LDIzNTIyLDIzNTI0LDIzNTE5LDIzNTY1LDIzNjUwLDIzOTQwLDIzOTQzLDI0MTU1LDI0MTYzLDI0MTQ5LDI0MTUxLDI0MTQ4LDI0Mjc1LDI0Mjc4LDI0MzMwLDI0MzkwLDI0NDMyLDI0NTA1LDI0OTAzLDI0ODk1LDI0OTA3LDI0OTUxLDI0OTMwLDI0OTMxLDI0OTI3LDI0OTIyLDI0OTIwLDI0OTQ5LDI1MTMwLDI1NzM1LDI1Njg4LDI1Njg0LDI1NzY0LDI1NzIwLDI1Njk1LDI1NzIyLDI1NjgxLDI1NzAzLDI1NjUyLDI1NzA5LDI1NzIzLDI1OTcwLDI2MDE3LDI2MDcxLDI2MDcwLDI2Mjc0LDI2MjgwLDI2MjY5LDI3MDM2LDI3MDQ4LDI3MDI5LDI3MDczLDI3MDU0LDI3MDkxLDI3MDgzLDI3MDM1LDI3MDYzLDI3MDY3LDI3MDUxLDI3MDYwLDI3MDg4LDI3MDg1LDI3MDUzLDI3MDg0LDI3MDQ2LDI3MDc1LDI3MDQzLDI3NDY1LDI3NDY4LDI3Njk5LDI4NDY3LDI4NDM2LDI4NDE0LDI4NDM1LDI4NDA0LDI4NDU3LDI4NDc4LDI4NDQ4LDI4NDYwLDI4NDMxLDI4NDE4LDI4NDUwLDI4NDE1LDI4Mzk5LDI4NDIyLDI4NDY1LDI4NDcyLDI4NDY2LDI4NDUxLDI4NDM3LDI4NDU5LDI4NDYzLDI4NTUyLDI4NDU4LDI4Mzk2LDI4NDE3LDI4NDAyLDI4MzY0LDI4NDA3LDI5MDc2LDI5MDgxLDI5MDUzLDI5MDY2LDI5MDYwLDI5MDc0LDI5MjQ2LDI5MzMwLDI5MzM0LDI5NTA4LDI5NTIwLDI5Nzk2LDI5Nzk1LDI5ODAyLDI5ODA4LDI5ODA1LDI5OTU2LDMwMDk3LDMwMjQ3LDMwMjIxLDMwMjE5LDMwMjE3LDMwMjI3LDMwNDMzLDMwNDM1LDMwNTk2LDMwNTg5LDMwNTkxLDMwNTYxLDMwOTEzLDMwODc5LDMwODg3LDMwODk5LDMwODg5LDMwODgzLDMxMTE4LDMxMTE5LDMxMTE3LDMxMjc4LDMxMjgxLDMxNDAyLDMxNDAxLDMxNDY5LDMxNDcxLDMxNjQ5LDMxNjM3LDMxNjI3LDMxNjA1LDMxNjM5LDMxNjQ1LDMxNjM2LDMxNjMxLDMxNjcyLDMxNjIzLDMxNjIwLDMxOTI5LDMxOTMzLDMxOTM0LDMyMTg3LDMyMTc2LDMyMTU2LDMyMTg5LDMyMTkwLDMyMTYwLDMyMjAyLDMyMTgwLDMyMTc4LDMyMTc3LDMyMTg2LDMyMTYyLDMyMTkxLDMyMTgxLDMyMTg0LDMyMTczLDMyMjEwLDMyMTk5LDMyMTcyLDMyNjI0LDMyNzM2LDMyNzM3LDMyNzM1LDMyODYyLDMyODU4LDMyOTAzLDMzMTA0LDMzMTUyLDMzMTY3LDMzMTYwLDMzMTYyLDMzMTUxLDMzMTU0LDMzMjU1LDMzMjc0LDMzMjg3LDMzMzAwLDMzMzEwLDMzMzU1LDMzOTkzLDMzOTgzLDMzOTkwLDMzOTg4LDMzOTQ1LDMzOTUwLDMzOTcwLDMzOTQ4LDMzOTk1LDMzOTc2LDMzOTg0LDM0MDAzLDMzOTM2LDMzOTgwLDM0MDAxLDMzOTk0LDM0NjIzLDM0NTg4LDM0NjE5LDM0NTk0LDM0NTk3LDM0NjEyLDM0NTg0LDM0NjQ1LDM0NjE1LDM0NjAxLDM1MDU5LDM1MDc0LDM1MDYwLDM1MDY1LDM1MDY0LDM1MDY5LDM1MDQ4LDM1MDk4LDM1MDU1LDM1NDk0LDM1NDY4LDM1NDg2LDM1NDkxLDM1NDY5LDM1NDg5LDM1NDc1LDM1NDkyLDM1NDk4LDM1NDkzLDM1NDk2LDM1NDgwLDM1NDczLDM1NDgyLDM1NDk1LDM1OTQ2LDM1OTgxLDM1OTgwLDM2MDUxLDM2MDQ5LDM2MDUwLDM2MjAzLDM2MjQ5LDM2MjQ1LDM2MzQ4LDM2NjI4LDM2NjI2LDM2NjI5LDM2NjI3LDM2NzcxLDM2OTYwLDM2OTUyLDM2OTU2LDM2OTYzLDM2OTUzLDM2OTU4LDM2OTYyLDM2OTU3LDM2OTU1LDM3MTQ1LDM3MTQ0LDM3MTUwLDM3MjM3LDM3MjQwLDM3MjM5LDM3MjM2LDM3NDk2LDM3NTA0LDM3NTA5LDM3NTI4LDM3NTI2LDM3NDk5LDM3NTIzLDM3NTMyLDM3NTQ0LDM3NTAwLDM3NTIxLDM4MzA1LDM4MzEyLDM4MzEzLDM4MzA3LDM4MzA5LDM4MzA4LDM4NTUzLDM4NTU2LDM4NTU1LDM4NjA0LDM4NjEwLDM4NjU2LDM4NzgwLDM4Nzg5LDM4OTAyLDM4OTM1LDM4OTM2LDM5MDg3LDM5MDg5LDM5MTcxLDM5MTczLDM5MTgwLDM5MTc3LDM5MzYxLDM5NTk5LDM5NjAwLDM5NjU0LDM5NzQ1LDM5NzQ2LDQwMTgwLDQwMTgyLDQwMTc5LDQwNjM2LDQwNzYzLDQwNzc4LDIwNzQwLDIwNzM2LDIwNzMxLDIwNzI1LDIwNzI5LDIwNzM4LDIwNzQ0LDIwNzQ1LDIwNzQxLDIwOTU2LDIxMTI3LDIxMTI4LDIxMTI5LDIxMTMzLDIxMTMwLDIxMjMyLDIxNDI2LDIyMDYyLDIyMDc1LDIyMDczLDIyMDY2LDIyMDc5LDIyMDY4LDIyMDU3LDIyMDk5LDIyMDk0LDIyMTAzLDIyMTMyLDIyMDcwLDIyMDYzLDIyMDY0LDIyNjU2LDIyNjg3LDIyNjg2LDIyNzA3LDIyNjg0LDIyNzAyLDIyNjk3LDIyNjk0LDIyODkzLDIzMzA1LDIzMjkxLDIzMzA3LDIzMjg1LDIzMzA4LDIzMzA0LDIzNTM0LDIzNTMyLDIzNTI5LDIzNTMxLDIzNjUyLDIzNjUzLDIzOTY1LDIzOTU2LDI0MTYyLDI0MTU5LDI0MTYxLDI0MjkwLDI0MjgyLDI0Mjg3LDI0Mjg1LDI0MjkxLDI0Mjg4LDI0MzkyLDI0NDMzLDI0NTAzLDI0NTAxLDI0OTUwLDI0OTM1LDI0OTQyLDI0OTI1LDI0OTE3LDI0OTYyLDI0OTU2LDI0OTQ0LDI0OTM5LDI0OTU4LDI0OTk5LDI0OTc2LDI1MDAzLDI0OTc0LDI1MDA0LDI0OTg2LDI0OTk2LDI0OTgwLDI1MDA2LDI1MTM0LDI1NzA1LDI1NzExLDI1NzIxLDI1NzU4LDI1Nzc4LDI1NzM2LDI1NzQ0LDI1Nzc2LDI1NzY1LDI1NzQ3LDI1NzQ5LDI1NzY5LDI1NzQ2LDI1Nzc0LDI1NzczLDI1NzcxLDI1NzU0LDI1NzcyLDI1NzUzLDI1NzYyLDI1Nzc5LDI1OTczLDI1OTc1LDI1OTc2LDI2Mjg2LDI2MjgzLDI2MjkyLDI2Mjg5LDI3MTcxLDI3MTY3LDI3MTEyLDI3MTM3LDI3MTY2LDI3MTYxLDI3MTMzLDI3MTY5LDI3MTU1LDI3MTQ2LDI3MTIzLDI3MTM4LDI3MTQxLDI3MTE3LDI3MTUzLDI3NDcyLDI3NDcwLDI3NTU2LDI3NTg5LDI3NTkwLDI4NDc5LDI4NTQwLDI4NTQ4LDI4NDk3LDI4NTE4LDI4NTAwLDI4NTUwLDI4NTI1LDI4NTA3LDI4NTM2LDI4NTI2LDI4NTU4LDI4NTM4LDI4NTI4LDI4NTE2LDI4NTY3LDI4NTA0LDI4MzczLDI4NTI3LDI4NTEyLDI4NTExLDI5MDg3LDI5MTAwLDI5MTA1LDI5MDk2LDI5MjcwLDI5MzM5LDI5NTE4LDI5NTI3LDI5ODAxLDI5ODM1LDI5ODI3LDI5ODIyLDI5ODI0LDMwMDc5LDMwMjQwLDMwMjQ5LDMwMjM5LDMwMjQ0LDMwMjQ2LDMwMjQxLDMwMjQyLDMwMzYyLDMwMzk0LDMwNDM2LDMwNjA2LDMwNTk5LDMwNjA0LDMwNjA5LDMwNjAzLDMwOTIzLDMwOTE3LDMwOTA2LDMwOTIyLDMwOTEwLDMwOTMzLDMwOTA4LDMwOTI4LDMxMjk1LDMxMjkyLDMxMjk2LDMxMjkzLDMxMjg3LDMxMjkxLDMxNDA3LDMxNDA2LDMxNjYxLDMxNjY1LDMxNjg0LDMxNjY4LDMxNjg2LDMxNjg3LDMxNjgxLDMxNjQ4LDMxNjkyLDMxOTQ2LDMyMjI0LDMyMjQ0LDMyMjM5LDMyMjUxLDMyMjE2LDMyMjM2LDMyMjIxLDMyMjMyLDMyMjI3LDMyMjE4LDMyMjIyLDMyMjMzLDMyMTU4LDMyMjE3LDMyMjQyLDMyMjQ5LDMyNjI5LDMyNjMxLDMyNjg3LDMyNzQ1LDMyODA2LDMzMTc5LDMzMTgwLDMzMTgxLDMzMTg0LDMzMTc4LDMzMTc2LDM0MDcxLDM0MTA5LDM0MDc0LDM0MDMwLDM0MDkyLDM0MDkzLDM0MDY3LDM0MDY1LDM0MDgzLDM0MDgxLDM0MDY4LDM0MDI4LDM0MDg1LDM0MDQ3LDM0MDU0LDM0NjkwLDM0Njc2LDM0Njc4LDM0NjU2LDM0NjYyLDM0NjgwLDM0NjY0LDM0NjQ5LDM0NjQ3LDM0NjM2LDM0NjQzLDM0OTA3LDM0OTA5LDM1MDg4LDM1MDc5LDM1MDkwLDM1MDkxLDM1MDkzLDM1MDgyLDM1NTE2LDM1NTM4LDM1NTI3LDM1NTI0LDM1NDc3LDM1NTMxLDM1NTc2LDM1NTA2LDM1NTI5LDM1NTIyLDM1NTE5LDM1NTA0LDM1NTQyLDM1NTMzLDM1NTEwLDM1NTEzLDM1NTQ3LDM1OTE2LDM1OTE4LDM1OTQ4LDM2MDY0LDM2MDYyLDM2MDcwLDM2MDY4LDM2MDc2LDM2MDc3LDM2MDY2LDM2MDY3LDM2MDYwLDM2MDc0LDM2MDY1LDM2MjA1LDM2MjU1LDM2MjU5LDM2Mzk1LDM2MzY4LDM2MzgxLDM2Mzg2LDM2MzY3LDM2MzkzLDM2MzgzLDM2Mzg1LDM2MzgyLDM2NTM4LDM2NjM3LDM2NjM1LDM2NjM5LDM2NjQ5LDM2NjQ2LDM2NjUwLDM2NjM2LDM2NjM4LDM2NjQ1LDM2OTY5LDM2OTc0LDM2OTY4LDM2OTczLDM2OTgzLDM3MTY4LDM3MTY1LDM3MTU5LDM3MTY5LDM3MjU1LDM3MjU3LDM3MjU5LDM3MjUxLDM3NTczLDM3NTYzLDM3NTU5LDM3NjEwLDM3NTQ4LDM3NjA0LDM3NTY5LDM3NTU1LDM3NTY0LDM3NTg2LDM3NTc1LDM3NjE2LDM3NTU0LDM4MzE3LDM4MzIxLDM4NjYwLDM4NjYyLDM4NjYzLDM4NjY1LDM4NzUyLDM4Nzk3LDM4Nzk1LDM4Nzk5LDM4OTQ1LDM4OTU1LDM4OTQwLDM5MDkxLDM5MTc4LDM5MTg3LDM5MTg2LDM5MTkyLDM5Mzg5LDM5Mzc2LDM5MzkxLDM5Mzg3LDM5Mzc3LDM5MzgxLDM5Mzc4LDM5Mzg1LDM5NjA3LDM5NjYyLDM5NjYzLDM5NzE5LDM5NzQ5LDM5NzQ4LDM5Nzk5LDM5NzkxLDQwMTk4LDQwMjAxLDQwMTk1LDQwNjE3LDQwNjM4LDQwNjU0LDIyNjk2LDQwNzg2LDIwNzU0LDIwNzYwLDIwNzU2LDIwNzUyLDIwNzU3LDIwODY0LDIwOTA2LDIwOTU3LDIxMTM3LDIxMTM5LDIxMjM1LDIyMTA1LDIyMTIzLDIyMTM3LDIyMTIxLDIyMTE2LDIyMTM2LDIyMTIyLDIyMTIwLDIyMTE3LDIyMTI5LDIyMTI3LDIyMTI0LDIyMTE0LDIyMTM0LDIyNzIxLDIyNzE4LDIyNzI3LDIyNzI1LDIyODk0LDIzMzI1LDIzMzQ4LDIzNDE2LDIzNTM2LDIzNTY2LDI0Mzk0LDI1MDEwLDI0OTc3LDI1MDAxLDI0OTcwLDI1MDM3LDI1MDE0LDI1MDIyLDI1MDM0LDI1MDMyLDI1MTM2LDI1Nzk3LDI1NzkzLDI1ODAzLDI1Nzg3LDI1Nzg4LDI1ODE4LDI1Nzk2LDI1Nzk5LDI1Nzk0LDI1ODA1LDI1NzkxLDI1ODEwLDI1ODEyLDI1NzkwLDI1OTcyLDI2MzEwLDI2MzEzLDI2Mjk3LDI2MzA4LDI2MzExLDI2Mjk2LDI3MTk3LDI3MTkyLDI3MTk0LDI3MjI1LDI3MjQzLDI3MjI0LDI3MTkzLDI3MjA0LDI3MjM0LDI3MjMzLDI3MjExLDI3MjA3LDI3MTg5LDI3MjMxLDI3MjA4LDI3NDgxLDI3NTExLDI3NjUzLDI4NjEwLDI4NTkzLDI4NTc3LDI4NjExLDI4NTgwLDI4NjA5LDI4NTgzLDI4NTk1LDI4NjA4LDI4NjAxLDI4NTk4LDI4NTgyLDI4NTc2LDI4NTk2LDI5MTE4LDI5MTI5LDI5MTM2LDI5MTM4LDI5MTI4LDI5MTQxLDI5MTEzLDI5MTM0LDI5MTQ1LDI5MTQ4LDI5MTIzLDI5MTI0LDI5NTQ0LDI5ODUyLDI5ODU5LDI5ODQ4LDI5ODU1LDI5ODU0LDI5OTIyLDI5OTY0LDI5OTY1LDMwMjYwLDMwMjY0LDMwMjY2LDMwNDM5LDMwNDM3LDMwNjI0LDMwNjIyLDMwNjIzLDMwNjI5LDMwOTUyLDMwOTM4LDMwOTU2LDMwOTUxLDMxMTQyLDMxMzA5LDMxMzEwLDMxMzAyLDMxMzA4LDMxMzA3LDMxNDE4LDMxNzA1LDMxNzYxLDMxNjg5LDMxNzE2LDMxNzA3LDMxNzEzLDMxNzIxLDMxNzE4LDMxOTU3LDMxOTU4LDMyMjY2LDMyMjczLDMyMjY0LDMyMjgzLDMyMjkxLDMyMjg2LDMyMjg1LDMyMjY1LDMyMjcyLDMyNjMzLDMyNjkwLDMyNzUyLDMyNzUzLDMyNzUwLDMyODA4LDMzMjAzLDMzMTkzLDMzMTkyLDMzMjc1LDMzMjg4LDMzMzY4LDMzMzY5LDM0MTIyLDM0MTM3LDM0MTIwLDM0MTUyLDM0MTUzLDM0MTE1LDM0MTIxLDM0MTU3LDM0MTU0LDM0MTQyLDM0NjkxLDM0NzE5LDM0NzE4LDM0NzIyLDM0NzAxLDM0OTEzLDM1MTE0LDM1MTIyLDM1MTA5LDM1MTE1LDM1MTA1LDM1MjQyLDM1MjM4LDM1NTU4LDM1NTc4LDM1NTYzLDM1NTY5LDM1NTg0LDM1NTQ4LDM1NTU5LDM1NTY2LDM1NTgyLDM1NTg1LDM1NTg2LDM1NTc1LDM1NTY1LDM1NTcxLDM1NTc0LDM1NTgwLDM1OTQ3LDM1OTQ5LDM1OTg3LDM2MDg0LDM2NDIwLDM2NDAxLDM2NDA0LDM2NDE4LDM2NDA5LDM2NDA1LDM2NjY3LDM2NjU1LDM2NjY0LDM2NjU5LDM2Nzc2LDM2Nzc0LDM2OTgxLDM2OTgwLDM2OTg0LDM2OTc4LDM2OTg4LDM2OTg2LDM3MTcyLDM3MjY2LDM3NjY0LDM3Njg2LDM3NjI0LDM3NjgzLDM3Njc5LDM3NjY2LDM3NjI4LDM3Njc1LDM3NjM2LDM3NjU4LDM3NjQ4LDM3NjcwLDM3NjY1LDM3NjUzLDM3Njc4LDM3NjU3LDM4MzMxLDM4NTY3LDM4NTY4LDM4NTcwLDM4NjEzLDM4NjcwLDM4NjczLDM4Njc4LDM4NjY5LDM4Njc1LDM4NjcxLDM4NzQ3LDM4NzQ4LDM4NzU4LDM4ODA4LDM4OTYwLDM4OTY4LDM4OTcxLDM4OTY3LDM4OTU3LDM4OTY5LDM4OTQ4LDM5MTg0LDM5MjA4LDM5MTk4LDM5MTk1LDM5MjAxLDM5MTk0LDM5NDA1LDM5Mzk0LDM5NDA5LDM5NjA4LDM5NjEyLDM5Njc1LDM5NjYxLDM5NzIwLDM5ODI1LDQwMjEzLDQwMjI3LDQwMjMwLDQwMjMyLDQwMjEwLDQwMjE5LDQwNjY0LDQwNjYwLDQwODQ1LDQwODYwLDIwNzc4LDIwNzY3LDIwNzY5LDIwNzg2LDIxMjM3LDIyMTU4LDIyMTQ0LDIyMTYwLDIyMTQ5LDIyMTUxLDIyMTU5LDIyNzQxLDIyNzM5LDIyNzM3LDIyNzM0LDIzMzQ0LDIzMzM4LDIzMzMyLDIzNDE4LDIzNjA3LDIzNjU2LDIzOTk2LDIzOTk0LDIzOTk3LDIzOTkyLDI0MTcxLDI0Mzk2LDI0NTA5LDI1MDMzLDI1MDI2LDI1MDMxLDI1MDYyLDI1MDM1LDI1MTM4LDI1MTQwLDI1ODA2LDI1ODAyLDI1ODE2LDI1ODI0LDI1ODQwLDI1ODMwLDI1ODM2LDI1ODQxLDI1ODI2LDI1ODM3LDI1OTg2LDI1OTg3LDI2MzI5LDI2MzI2LDI3MjY0LDI3Mjg0LDI3MjY4LDI3Mjk4LDI3MjkyLDI3MzU1LDI3Mjk5LDI3MjYyLDI3Mjg3LDI3MjgwLDI3Mjk2LDI3NDg0LDI3NTY2LDI3NjEwLDI3NjU2LDI4NjMyLDI4NjU3LDI4NjM5LDI4NjQwLDI4NjM1LDI4NjQ0LDI4NjUxLDI4NjU1LDI4NTQ0LDI4NjUyLDI4NjQxLDI4NjQ5LDI4NjI5LDI4NjU0LDI4NjU2LDI5MTU5LDI5MTUxLDI5MTY2LDI5MTU4LDI5MTU3LDI5MTY1LDI5MTY0LDI5MTcyLDI5MTUyLDI5MjM3LDI5MjU0LDI5NTUyLDI5NTU0LDI5ODY1LDI5ODcyLDI5ODYyLDI5ODY0LDMwMjc4LDMwMjc0LDMwMjg0LDMwNDQyLDMwNjQzLDMwNjM0LDMwNjQwLDMwNjM2LDMwNjMxLDMwNjM3LDMwNzAzLDMwOTY3LDMwOTcwLDMwOTY0LDMwOTU5LDMwOTc3LDMxMTQzLDMxMTQ2LDMxMzE5LDMxNDIzLDMxNzUxLDMxNzU3LDMxNzQyLDMxNzM1LDMxNzU2LDMxNzEyLDMxOTY4LDMxOTY0LDMxOTY2LDMxOTcwLDMxOTY3LDMxOTYxLDMxOTY1LDMyMzAyLDMyMzE4LDMyMzI2LDMyMzExLDMyMzA2LDMyMzIzLDMyMjk5LDMyMzE3LDMyMzA1LDMyMzI1LDMyMzIxLDMyMzA4LDMyMzEzLDMyMzI4LDMyMzA5LDMyMzE5LDMyMzAzLDMyNTgwLDMyNzU1LDMyNzY0LDMyODgxLDMyODgyLDMyODgwLDMyODc5LDMyODgzLDMzMjIyLDMzMjE5LDMzMjEwLDMzMjE4LDMzMjE2LDMzMjE1LDMzMjEzLDMzMjI1LDMzMjE0LDMzMjU2LDMzMjg5LDMzMzkzLDM0MjE4LDM0MTgwLDM0MTc0LDM0MjA0LDM0MTkzLDM0MTk2LDM0MjIzLDM0MjAzLDM0MTgzLDM0MjE2LDM0MTg2LDM0NDA3LDM0NzUyLDM0NzY5LDM0NzM5LDM0NzcwLDM0NzU4LDM0NzMxLDM0NzQ3LDM0NzQ2LDM0NzYwLDM0NzYzLDM1MTMxLDM1MTI2LDM1MTQwLDM1MTI4LDM1MTMzLDM1MjQ0LDM1NTk4LDM1NjA3LDM1NjA5LDM1NjExLDM1NTk0LDM1NjE2LDM1NjEzLDM1NTg4LDM1NjAwLDM1OTA1LDM1OTAzLDM1OTU1LDM2MDkwLDM2MDkzLDM2MDkyLDM2MDg4LDM2MDkxLDM2MjY0LDM2NDI1LDM2NDI3LDM2NDI0LDM2NDI2LDM2Njc2LDM2NjcwLDM2Njc0LDM2Njc3LDM2NjcxLDM2OTkxLDM2OTg5LDM2OTk2LDM2OTkzLDM2OTk0LDM2OTkyLDM3MTc3LDM3MjgzLDM3Mjc4LDM3Mjc2LDM3NzA5LDM3NzYyLDM3NjcyLDM3NzQ5LDM3NzA2LDM3NzMzLDM3NzA3LDM3NjU2LDM3NzU4LDM3NzQwLDM3NzIzLDM3NzQ0LDM3NzIyLDM3NzE2LDM4MzQ2LDM4MzQ3LDM4MzQ4LDM4MzQ0LDM4MzQyLDM4NTc3LDM4NTg0LDM4NjE0LDM4Njg0LDM4Njg2LDM4ODE2LDM4ODY3LDM4OTgyLDM5MDk0LDM5MjIxLDM5NDI1LDM5NDIzLDM5ODU0LDM5ODUxLDM5ODUwLDM5ODUzLDQwMjUxLDQwMjU1LDQwNTg3LDQwNjU1LDQwNjcwLDQwNjY4LDQwNjY5LDQwNjY3LDQwNzY2LDQwNzc5LDIxNDc0LDIyMTY1LDIyMTkwLDIyNzQ1LDIyNzQ0LDIzMzUyLDI0NDEzLDI1MDU5LDI1MTM5LDI1ODQ0LDI1ODQyLDI1ODU0LDI1ODYyLDI1ODUwLDI1ODUxLDI1ODQ3LDI2MDM5LDI2MzMyLDI2NDA2LDI3MzE1LDI3MzA4LDI3MzMxLDI3MzIzLDI3MzIwLDI3MzMwLDI3MzEwLDI3MzExLDI3NDg3LDI3NTEyLDI3NTY3LDI4NjgxLDI4NjgzLDI4NjcwLDI4Njc4LDI4NjY2LDI4Njg5LDI4Njg3LDI5MTc5LDI5MTgwLDI5MTgyLDI5MTc2LDI5NTU5LDI5NTU3LDI5ODYzLDI5ODg3LDI5OTczLDMwMjk0LDMwMjk2LDMwMjkwLDMwNjUzLDMwNjU1LDMwNjUxLDMwNjUyLDMwOTkwLDMxMTUwLDMxMzI5LDMxMzMwLDMxMzI4LDMxNDI4LDMxNDI5LDMxNzg3LDMxNzgzLDMxNzg2LDMxNzc0LDMxNzc5LDMxNzc3LDMxOTc1LDMyMzQwLDMyMzQxLDMyMzUwLDMyMzQ2LDMyMzUzLDMyMzM4LDMyMzQ1LDMyNTg0LDMyNzYxLDMyNzYzLDMyODg3LDMyODg2LDMzMjI5LDMzMjMxLDMzMjkwLDM0MjU1LDM0MjE3LDM0MjUzLDM0MjU2LDM0MjQ5LDM0MjI0LDM0MjM0LDM0MjMzLDM0MjE0LDM0Nzk5LDM0Nzk2LDM0ODAyLDM0Nzg0LDM1MjA2LDM1MjUwLDM1MzE2LDM1NjI0LDM1NjQxLDM1NjI4LDM1NjI3LDM1OTIwLDM2MTAxLDM2NDQxLDM2NDUxLDM2NDU0LDM2NDUyLDM2NDQ3LDM2NDM3LDM2NTQ0LDM2NjgxLDM2Njg1LDM2OTk5LDM2OTk1LDM3MDAwLDM3MjkxLDM3MjkyLDM3MzI4LDM3NzgwLDM3NzcwLDM3NzgyLDM3Nzk0LDM3ODExLDM3ODA2LDM3ODA0LDM3ODA4LDM3Nzg0LDM3Nzg2LDM3NzgzLDM4MzU2LDM4MzU4LDM4MzUyLDM4MzU3LDM4NjI2LDM4NjIwLDM4NjE3LDM4NjE5LDM4NjIyLDM4NjkyLDM4ODE5LDM4ODIyLDM4ODI5LDM4OTA1LDM4OTg5LDM4OTkxLDM4OTg4LDM4OTkwLDM4OTk1LDM5MDk4LDM5MjMwLDM5MjMxLDM5MjI5LDM5MjE0LDM5MzMzLDM5NDM4LDM5NjE3LDM5NjgzLDM5Njg2LDM5NzU5LDM5NzU4LDM5NzU3LDM5ODgyLDM5ODgxLDM5OTMzLDM5ODgwLDM5ODcyLDQwMjczLDQwMjg1LDQwMjg4LDQwNjcyLDQwNzI1LDQwNzQ4LDIwNzg3LDIyMTgxLDIyNzUwLDIyNzUxLDIyNzU0LDIzNTQxLDQwODQ4LDI0MzAwLDI1MDc0LDI1MDc5LDI1MDc4LDI1MDc3LDI1ODU2LDI1ODcxLDI2MzM2LDI2MzMzLDI3MzY1LDI3MzU3LDI3MzU0LDI3MzQ3LDI4Njk5LDI4NzAzLDI4NzEyLDI4Njk4LDI4NzAxLDI4NjkzLDI4Njk2LDI5MTkwLDI5MTk3LDI5MjcyLDI5MzQ2LDI5NTYwLDI5NTYyLDI5ODg1LDI5ODk4LDI5OTIzLDMwMDg3LDMwMDg2LDMwMzAzLDMwMzA1LDMwNjYzLDMxMDAxLDMxMTUzLDMxMzM5LDMxMzM3LDMxODA2LDMxODA3LDMxODAwLDMxODA1LDMxNzk5LDMxODA4LDMyMzYzLDMyMzY1LDMyMzc3LDMyMzYxLDMyMzYyLDMyNjQ1LDMyMzcxLDMyNjk0LDMyNjk3LDMyNjk2LDMzMjQwLDM0MjgxLDM0MjY5LDM0MjgyLDM0MjYxLDM0Mjc2LDM0Mjc3LDM0Mjk1LDM0ODExLDM0ODIxLDM0ODI5LDM0ODA5LDM0ODE0LDM1MTY4LDM1MTY3LDM1MTU4LDM1MTY2LDM1NjQ5LDM1Njc2LDM1NjcyLDM1NjU3LDM1Njc0LDM1NjYyLDM1NjYzLDM1NjU0LDM1NjczLDM2MTA0LDM2MTA2LDM2NDc2LDM2NDY2LDM2NDg3LDM2NDcwLDM2NDYwLDM2NDc0LDM2NDY4LDM2NjkyLDM2Njg2LDM2NzgxLDM3MDAyLDM3MDAzLDM3Mjk3LDM3Mjk0LDM3ODU3LDM3ODQxLDM3ODU1LDM3ODI3LDM3ODMyLDM3ODUyLDM3ODUzLDM3ODQ2LDM3ODU4LDM3ODM3LDM3ODQ4LDM3ODYwLDM3ODQ3LDM3ODY0LDM4MzY0LDM4NTgwLDM4NjI3LDM4Njk4LDM4Njk1LDM4NzUzLDM4ODc2LDM4OTA3LDM5MDA2LDM5MDAwLDM5MDAzLDM5MTAwLDM5MjM3LDM5MjQxLDM5NDQ2LDM5NDQ5LDM5NjkzLDM5OTEyLDM5OTExLDM5ODk0LDM5ODk5LDQwMzI5LDQwMjg5LDQwMzA2LDQwMjk4LDQwMzAwLDQwNTk0LDQwNTk5LDQwNTk1LDQwNjI4LDIxMjQwLDIyMTg0LDIyMTk5LDIyMTk4LDIyMTk2LDIyMjA0LDIyNzU2LDIzMzYwLDIzMzYzLDIzNDIxLDIzNTQyLDI0MDA5LDI1MDgwLDI1MDgyLDI1ODgwLDI1ODc2LDI1ODgxLDI2MzQyLDI2NDA3LDI3MzcyLDI4NzM0LDI4NzIwLDI4NzIyLDI5MjAwLDI5NTYzLDI5OTAzLDMwMzA2LDMwMzA5LDMxMDE0LDMxMDE4LDMxMDIwLDMxMDE5LDMxNDMxLDMxNDc4LDMxODIwLDMxODExLDMxODIxLDMxOTgzLDMxOTg0LDM2NzgyLDMyMzgxLDMyMzgwLDMyMzg2LDMyNTg4LDMyNzY4LDMzMjQyLDMzMzgyLDM0Mjk5LDM0Mjk3LDM0MzIxLDM0Mjk4LDM0MzEwLDM0MzE1LDM0MzExLDM0MzE0LDM0ODM2LDM0ODM3LDM1MTcyLDM1MjU4LDM1MzIwLDM1Njk2LDM1NjkyLDM1Njg2LDM1Njk1LDM1Njc5LDM1NjkxLDM2MTExLDM2MTA5LDM2NDg5LDM2NDgxLDM2NDg1LDM2NDgyLDM3MzAwLDM3MzIzLDM3OTEyLDM3ODkxLDM3ODg1LDM4MzY5LDM4NzA0LDM5MTA4LDM5MjUwLDM5MjQ5LDM5MzM2LDM5NDY3LDM5NDcyLDM5NDc5LDM5NDc3LDM5OTU1LDM5OTQ5LDQwNTY5LDQwNjI5LDQwNjgwLDQwNzUxLDQwNzk5LDQwODAzLDQwODAxLDIwNzkxLDIwNzkyLDIyMjA5LDIyMjA4LDIyMjEwLDIyODA0LDIzNjYwLDI0MDEzLDI1MDg0LDI1MDg2LDI1ODg1LDI1ODg0LDI2MDA1LDI2MzQ1LDI3Mzg3LDI3Mzk2LDI3Mzg2LDI3NTcwLDI4NzQ4LDI5MjExLDI5MzUxLDI5OTEwLDI5OTA4LDMwMzEzLDMwNjc1LDMxODI0LDMyMzk5LDMyMzk2LDMyNzAwLDM0MzI3LDM0MzQ5LDM0MzMwLDM0ODUxLDM0ODUwLDM0ODQ5LDM0ODQ3LDM1MTc4LDM1MTgwLDM1MjYxLDM1NzAwLDM1NzAzLDM1NzA5LDM2MTE1LDM2NDkwLDM2NDkzLDM2NDkxLDM2NzAzLDM2NzgzLDM3MzA2LDM3OTM0LDM3OTM5LDM3OTQxLDM3OTQ2LDM3OTQ0LDM3OTM4LDM3OTMxLDM4MzcwLDM4NzEyLDM4NzEzLDM4NzA2LDM4OTExLDM5MDE1LDM5MDEzLDM5MjU1LDM5NDkzLDM5NDkxLDM5NDg4LDM5NDg2LDM5NjMxLDM5NzY0LDM5NzYxLDM5OTgxLDM5OTczLDQwMzY3LDQwMzcyLDQwMzg2LDQwMzc2LDQwNjA1LDQwNjg3LDQwNzI5LDQwNzk2LDQwODA2LDQwODA3LDIwNzk2LDIwNzk1LDIyMjE2LDIyMjE4LDIyMjE3LDIzNDIzLDI0MDIwLDI0MDE4LDI0Mzk4LDI1MDg3LDI1ODkyLDI3NDAyLDI3NDg5LDI4NzUzLDI4NzYwLDI5NTY4LDI5OTI0LDMwMDkwLDMwMzE4LDMwMzE2LDMxMTU1LDMxODQwLDMxODM5LDMyODk0LDMyODkzLDMzMjQ3LDM1MTg2LDM1MTgzLDM1MzI0LDM1NzEyLDM2MTE4LDM2MTE5LDM2NDk3LDM2NDk5LDM2NzA1LDM3MTkyLDM3OTU2LDM3OTY5LDM3OTcwLDM4NzE3LDM4NzE4LDM4ODUxLDM4ODQ5LDM5MDE5LDM5MjUzLDM5NTA5LDM5NTAxLDM5NjM0LDM5NzA2LDQwMDA5LDM5OTg1LDM5OTk4LDM5OTk1LDQwNDAzLDQwNDA3LDQwNzU2LDQwODEyLDQwODEwLDQwODUyLDIyMjIwLDI0MDIyLDI1MDg4LDI1ODkxLDI1ODk5LDI1ODk4LDI2MzQ4LDI3NDA4LDI5OTE0LDMxNDM0LDMxODQ0LDMxODQzLDMxODQ1LDMyNDAzLDMyNDA2LDMyNDA0LDMzMjUwLDM0MzYwLDM0MzY3LDM0ODY1LDM1NzIyLDM3MDA4LDM3MDA3LDM3OTg3LDM3OTg0LDM3OTg4LDM4NzYwLDM5MDIzLDM5MjYwLDM5NTE0LDM5NTE1LDM5NTExLDM5NjM1LDM5NjM2LDM5NjMzLDQwMDIwLDQwMDIzLDQwMDIyLDQwNDIxLDQwNjA3LDQwNjkyLDIyMjI1LDIyNzYxLDI1OTAwLDI4NzY2LDMwMzIxLDMwMzIyLDMwNjc5LDMyNTkyLDMyNjQ4LDM0ODcwLDM0ODczLDM0OTE0LDM1NzMxLDM1NzMwLDM1NzM0LDMzMzk5LDM2MTIzLDM3MzEyLDM3OTk0LDM4NzIyLDM4NzI4LDM4NzI0LDM4ODU0LDM5MDI0LDM5NTE5LDM5NzE0LDM5NzY4LDQwMDMxLDQwNDQxLDQwNDQyLDQwNTcyLDQwNTczLDQwNzExLDQwODIzLDQwODE4LDI0MzA3LDI3NDE0LDI4NzcxLDMxODUyLDMxODU0LDM0ODc1LDM1MjY0LDM2NTEzLDM3MzEzLDM4MDAyLDM4MDAwLDM5MDI1LDM5MjYyLDM5NjM4LDM5NzE1LDQwNjUyLDI4NzcyLDMwNjgyLDM1NzM4LDM4MDA3LDM4ODU3LDM5NTIyLDM5NTI1LDMyNDEyLDM1NzQwLDM2NTIyLDM3MzE3LDM4MDEzLDM4MDE0LDM4MDEyLDQwMDU1LDQwMDU2LDQwNjk1LDM1OTI0LDM4MDE1LDQwNDc0LDI5MjI0LDM5NTMwLDM5NzI5LDQwNDc1LDQwNDc4LDMxODU4LDkzMTIsOTMxMyw5MzE0LDkzMTUsOTMxNiw5MzE3LDkzMTgsOTMxOSw5MzIwLDkzMjEsOTMzMiw5MzMzLDkzMzQsOTMzNSw5MzM2LDkzMzcsOTMzOCw5MzM5LDkzNDAsOTM0MSw4NTYwLDg1NjEsODU2Miw4NTYzLDg1NjQsODU2NSw4NTY2LDg1NjcsODU2OCw4NTY5LDIwMDIyLDIwMDMxLDIwMTAxLDIwMTI4LDIwODY2LDIwODg2LDIwOTA3LDIxMjQxLDIxMzA0LDIxMzUzLDIxNDMwLDIyNzk0LDIzNDI0LDI0MDI3LDEyMDgzLDI0MTkxLDI0MzA4LDI0NDAwLDI0NDE3LDI1OTA4LDI2MDgwLDMwMDk4LDMwMzI2LDM2Nzg5LDM4NTgyLDE2OCw3MTAsMTI1NDEsMTI1NDIsMTI0NDUsMTI0NDYsMTIyOTEsMjAxODksMTIyOTMsMTIyOTQsMTIyOTUsMTI1NDAsNjUzMzksNjUzNDEsMTAwNDUsMTIzNTMsMTIzNTQsMTIzNTUsMTIzNTYsMTIzNTcsMTIzNTgsMTIzNTksMTIzNjAsMTIzNjEsMTIzNjIsMTIzNjMsMTIzNjQsMTIzNjUsMTIzNjYsMTIzNjcsMTIzNjgsMTIzNjksMTIzNzAsMTIzNzEsMTIzNzIsMTIzNzMsMTIzNzQsMTIzNzUsMTIzNzYsMTIzNzcsMTIzNzgsMTIzNzksMTIzODAsMTIzODEsMTIzODIsMTIzODMsMTIzODQsMTIzODUsMTIzODYsMTIzODcsMTIzODgsMTIzODksMTIzOTAsMTIzOTEsMTIzOTIsMTIzOTMsMTIzOTQsMTIzOTUsMTIzOTYsMTIzOTcsMTIzOTgsMTIzOTksMTI0MDAsMTI0MDEsMTI0MDIsMTI0MDMsMTI0MDQsMTI0MDUsMTI0MDYsMTI0MDcsMTI0MDgsMTI0MDksMTI0MTAsMTI0MTEsMTI0MTIsMTI0MTMsMTI0MTQsMTI0MTUsMTI0MTYsMTI0MTcsMTI0MTgsMTI0MTksMTI0MjAsMTI0MjEsMTI0MjIsMTI0MjMsMTI0MjQsMTI0MjUsMTI0MjYsMTI0MjcsMTI0MjgsMTI0MjksMTI0MzAsMTI0MzEsMTI0MzIsMTI0MzMsMTI0MzQsMTI0MzUsMTI0NDksMTI0NTAsMTI0NTEsMTI0NTIsMTI0NTMsMTI0NTQsMTI0NTUsMTI0NTYsMTI0NTcsMTI0NTgsMTI0NTksMTI0NjAsMTI0NjEsMTI0NjIsMTI0NjMsMTI0NjQsMTI0NjUsMTI0NjYsMTI0NjcsMTI0NjgsMTI0NjksMTI0NzAsMTI0NzEsMTI0NzIsMTI0NzMsMTI0NzQsMTI0NzUsMTI0NzYsMTI0NzcsMTI0NzgsMTI0NzksMTI0ODAsMTI0ODEsMTI0ODIsMTI0ODMsMTI0ODQsMTI0ODUsMTI0ODYsMTI0ODcsMTI0ODgsMTI0ODksMTI0OTAsMTI0OTEsMTI0OTIsMTI0OTMsMTI0OTQsMTI0OTUsMTI0OTYsMTI0OTcsMTI0OTgsMTI0OTksMTI1MDAsMTI1MDEsMTI1MDIsMTI1MDMsMTI1MDQsMTI1MDUsMTI1MDYsMTI1MDcsMTI1MDgsMTI1MDksMTI1MTAsMTI1MTEsMTI1MTIsMTI1MTMsMTI1MTQsMTI1MTUsMTI1MTYsMTI1MTcsMTI1MTgsMTI1MTksMTI1MjAsMTI1MjEsMTI1MjIsMTI1MjMsMTI1MjQsMTI1MjUsMTI1MjYsMTI1MjcsMTI1MjgsMTI1MjksMTI1MzAsMTI1MzEsMTI1MzIsMTI1MzMsMTI1MzQsMTA0MCwxMDQxLDEwNDIsMTA0MywxMDQ0LDEwNDUsMTAyNSwxMDQ2LDEwNDcsMTA0OCwxMDQ5LDEwNTAsMTA1MSwxMDUyLDEwNTMsMTA1NCwxMDU1LDEwNTYsMTA1NywxMDU4LDEwNTksMTA2MCwxMDYxLDEwNjIsMTA2MywxMDY0LDEwNjUsMTA2NiwxMDY3LDEwNjgsMTA2OSwxMDcwLDEwNzEsMTA3MiwxMDczLDEwNzQsMTA3NSwxMDc2LDEwNzcsMTEwNSwxMDc4LDEwNzksMTA4MCwxMDgxLDEwODIsMTA4MywxMDg0LDEwODUsMTA4NiwxMDg3LDEwODgsMTA4OSwxMDkwLDEwOTEsMTA5MiwxMDkzLDEwOTQsMTA5NSwxMDk2LDEwOTcsMTA5OCwxMDk5LDExMDAsMTEwMSwxMTAyLDExMDMsODY3OSw4NjMyLDg2MzMsMTI3NTEsMTMxMjc2LDIwMDU4LDEzMTIxMCwyMDk5NCwxNzU1Myw0MDg4MCwyMDg3Miw0MDg4MSwxNjEyODcsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw2NTUwNiw2NTUwOCw2NTI4Nyw2NTI4MiwxMjg0OSw4NDcwLDg0ODEsMTI0NDMsMTI0NDQsMTE5MDQsMTE5MDgsMTE5MTAsMTE5MTEsMTE5MTIsMTE5MTQsMTE5MTYsMTE5MTcsMTE5MjUsMTE5MzIsMTE5MzMsMTE5NDEsMTE5NDMsMTE5NDYsMTE5NDgsMTE5NTAsMTE5NTgsMTE5NjQsMTE5NjYsMTE5NzQsMTE5NzgsMTE5ODAsMTE5ODEsMTE5ODMsMTE5OTAsMTE5OTEsMTE5OTgsMTIwMDMsbnVsbCxudWxsLG51bGwsNjQzLDU5Miw2MDMsNTk2LDYyOSwzMzksMjQ4LDMzMSw2NTAsNjE4LDIwMDM0LDIwMDYwLDIwOTgxLDIxMjc0LDIxMzc4LDE5OTc1LDE5OTgwLDIwMDM5LDIwMTA5LDIyMjMxLDY0MDEyLDIzNjYyLDI0NDM1LDE5OTgzLDIwODcxLDE5OTgyLDIwMDE0LDIwMTE1LDIwMTYyLDIwMTY5LDIwMTY4LDIwODg4LDIxMjQ0LDIxMzU2LDIxNDMzLDIyMzA0LDIyNzg3LDIyODI4LDIzNTY4LDI0MDYzLDI2MDgxLDI3NTcxLDI3NTk2LDI3NjY4LDI5MjQ3LDIwMDE3LDIwMDI4LDIwMjAwLDIwMTg4LDIwMjAxLDIwMTkzLDIwMTg5LDIwMTg2LDIxMDA0LDIxMjc2LDIxMzI0LDIyMzA2LDIyMzA3LDIyODA3LDIyODMxLDIzNDI1LDIzNDI4LDIzNTcwLDIzNjExLDIzNjY4LDIzNjY3LDI0MDY4LDI0MTkyLDI0MTk0LDI0NTIxLDI1MDk3LDI1MTY4LDI3NjY5LDI3NzAyLDI3NzE1LDI3NzExLDI3NzA3LDI5MzU4LDI5MzYwLDI5NTc4LDMxMTYwLDMyOTA2LDM4NDMwLDIwMjM4LDIwMjQ4LDIwMjY4LDIwMjEzLDIwMjQ0LDIwMjA5LDIwMjI0LDIwMjE1LDIwMjMyLDIwMjUzLDIwMjI2LDIwMjI5LDIwMjU4LDIwMjQzLDIwMjI4LDIwMjEyLDIwMjQyLDIwOTEzLDIxMDExLDIxMDAxLDIxMDA4LDIxMTU4LDIxMjgyLDIxMjc5LDIxMzI1LDIxMzg2LDIxNTExLDIyMjQxLDIyMjM5LDIyMzE4LDIyMzE0LDIyMzI0LDIyODQ0LDIyOTEyLDIyOTA4LDIyOTE3LDIyOTA3LDIyOTEwLDIyOTAzLDIyOTExLDIzMzgyLDIzNTczLDIzNTg5LDIzNjc2LDIzNjc0LDIzNjc1LDIzNjc4LDI0MDMxLDI0MTgxLDI0MTk2LDI0MzIyLDI0MzQ2LDI0NDM2LDI0NTMzLDI0NTMyLDI0NTI3LDI1MTgwLDI1MTgyLDI1MTg4LDI1MTg1LDI1MTkwLDI1MTg2LDI1MTc3LDI1MTg0LDI1MTc4LDI1MTg5LDI2MDk1LDI2MDk0LDI2NDMwLDI2NDI1LDI2NDI0LDI2NDI3LDI2NDI2LDI2NDMxLDI2NDI4LDI2NDE5LDI3NjcyLDI3NzE4LDI3NzMwLDI3NzQwLDI3NzI3LDI3NzIyLDI3NzMyLDI3NzIzLDI3NzI0LDI4Nzg1LDI5Mjc4LDI5MzY0LDI5MzY1LDI5NTgyLDI5OTk0LDMwMzM1LDMxMzQ5LDMyNTkzLDMzNDAwLDMzNDA0LDMzNDA4LDMzNDA1LDMzNDA3LDM0MzgxLDM1MTk4LDM3MDE3LDM3MDE1LDM3MDE2LDM3MDE5LDM3MDEyLDM4NDM0LDM4NDM2LDM4NDMyLDM4NDM1LDIwMzEwLDIwMjgzLDIwMzIyLDIwMjk3LDIwMzA3LDIwMzI0LDIwMjg2LDIwMzI3LDIwMzA2LDIwMzE5LDIwMjg5LDIwMzEyLDIwMjY5LDIwMjc1LDIwMjg3LDIwMzIxLDIwODc5LDIwOTIxLDIxMDIwLDIxMDIyLDIxMDI1LDIxMTY1LDIxMTY2LDIxMjU3LDIxMzQ3LDIxMzYyLDIxMzkwLDIxMzkxLDIxNTUyLDIxNTU5LDIxNTQ2LDIxNTg4LDIxNTczLDIxNTI5LDIxNTMyLDIxNTQxLDIxNTI4LDIxNTY1LDIxNTgzLDIxNTY5LDIxNTQ0LDIxNTQwLDIxNTc1LDIyMjU0LDIyMjQ3LDIyMjQ1LDIyMzM3LDIyMzQxLDIyMzQ4LDIyMzQ1LDIyMzQ3LDIyMzU0LDIyNzkwLDIyODQ4LDIyOTUwLDIyOTM2LDIyOTQ0LDIyOTM1LDIyOTI2LDIyOTQ2LDIyOTI4LDIyOTI3LDIyOTUxLDIyOTQ1LDIzNDM4LDIzNDQyLDIzNTkyLDIzNTk0LDIzNjkzLDIzNjk1LDIzNjg4LDIzNjkxLDIzNjg5LDIzNjk4LDIzNjkwLDIzNjg2LDIzNjk5LDIzNzAxLDI0MDMyLDI0MDc0LDI0MDc4LDI0MjAzLDI0MjAxLDI0MjA0LDI0MjAwLDI0MjA1LDI0MzI1LDI0MzQ5LDI0NDQwLDI0NDM4LDI0NTMwLDI0NTI5LDI0NTI4LDI0NTU3LDI0NTUyLDI0NTU4LDI0NTYzLDI0NTQ1LDI0NTQ4LDI0NTQ3LDI0NTcwLDI0NTU5LDI0NTY3LDI0NTcxLDI0NTc2LDI0NTY0LDI1MTQ2LDI1MjE5LDI1MjI4LDI1MjMwLDI1MjMxLDI1MjM2LDI1MjIzLDI1MjAxLDI1MjExLDI1MjEwLDI1MjAwLDI1MjE3LDI1MjI0LDI1MjA3LDI1MjEzLDI1MjAyLDI1MjA0LDI1OTExLDI2MDk2LDI2MTAwLDI2MDk5LDI2MDk4LDI2MTAxLDI2NDM3LDI2NDM5LDI2NDU3LDI2NDUzLDI2NDQ0LDI2NDQwLDI2NDYxLDI2NDQ1LDI2NDU4LDI2NDQzLDI3NjAwLDI3NjczLDI3Njc0LDI3NzY4LDI3NzUxLDI3NzU1LDI3NzgwLDI3Nzg3LDI3NzkxLDI3NzYxLDI3NzU5LDI3NzUzLDI3ODAyLDI3NzU3LDI3NzgzLDI3Nzk3LDI3ODA0LDI3NzUwLDI3NzYzLDI3NzQ5LDI3NzcxLDI3NzkwLDI4Nzg4LDI4Nzk0LDI5MjgzLDI5Mzc1LDI5MzczLDI5Mzc5LDI5MzgyLDI5Mzc3LDI5MzcwLDI5MzgxLDI5NTg5LDI5NTkxLDI5NTg3LDI5NTg4LDI5NTg2LDMwMDEwLDMwMDA5LDMwMTAwLDMwMTAxLDMwMzM3LDMxMDM3LDMyODIwLDMyOTE3LDMyOTIxLDMyOTEyLDMyOTE0LDMyOTI0LDMzNDI0LDMzNDIzLDMzNDEzLDMzNDIyLDMzNDI1LDMzNDI3LDMzNDE4LDMzNDExLDMzNDEyLDM1OTYwLDM2ODA5LDM2Nzk5LDM3MDIzLDM3MDI1LDM3MDI5LDM3MDIyLDM3MDMxLDM3MDI0LDM4NDQ4LDM4NDQwLDM4NDQ3LDM4NDQ1LDIwMDE5LDIwMzc2LDIwMzQ4LDIwMzU3LDIwMzQ5LDIwMzUyLDIwMzU5LDIwMzQyLDIwMzQwLDIwMzYxLDIwMzU2LDIwMzQzLDIwMzAwLDIwMzc1LDIwMzMwLDIwMzc4LDIwMzQ1LDIwMzUzLDIwMzQ0LDIwMzY4LDIwMzgwLDIwMzcyLDIwMzgyLDIwMzcwLDIwMzU0LDIwMzczLDIwMzMxLDIwMzM0LDIwODk0LDIwOTI0LDIwOTI2LDIxMDQ1LDIxMDQyLDIxMDQzLDIxMDYyLDIxMDQxLDIxMTgwLDIxMjU4LDIxMjU5LDIxMzA4LDIxMzk0LDIxMzk2LDIxNjM5LDIxNjMxLDIxNjMzLDIxNjQ5LDIxNjM0LDIxNjQwLDIxNjExLDIxNjI2LDIxNjMwLDIxNjA1LDIxNjEyLDIxNjIwLDIxNjA2LDIxNjQ1LDIxNjE1LDIxNjAxLDIxNjAwLDIxNjU2LDIxNjAzLDIxNjA3LDIxNjA0LDIyMjYzLDIyMjY1LDIyMzgzLDIyMzg2LDIyMzgxLDIyMzc5LDIyMzg1LDIyMzg0LDIyMzkwLDIyNDAwLDIyMzg5LDIyMzk1LDIyMzg3LDIyMzg4LDIyMzcwLDIyMzc2LDIyMzk3LDIyNzk2LDIyODUzLDIyOTY1LDIyOTcwLDIyOTkxLDIyOTkwLDIyOTYyLDIyOTg4LDIyOTc3LDIyOTY2LDIyOTcyLDIyOTc5LDIyOTk4LDIyOTYxLDIyOTczLDIyOTc2LDIyOTg0LDIyOTY0LDIyOTgzLDIzMzk0LDIzMzk3LDIzNDQzLDIzNDQ1LDIzNjIwLDIzNjIzLDIzNzI2LDIzNzE2LDIzNzEyLDIzNzMzLDIzNzI3LDIzNzIwLDIzNzI0LDIzNzExLDIzNzE1LDIzNzI1LDIzNzE0LDIzNzIyLDIzNzE5LDIzNzA5LDIzNzE3LDIzNzM0LDIzNzI4LDIzNzE4LDI0MDg3LDI0MDg0LDI0MDg5LDI0MzYwLDI0MzU0LDI0MzU1LDI0MzU2LDI0NDA0LDI0NDUwLDI0NDQ2LDI0NDQ1LDI0NTQyLDI0NTQ5LDI0NjIxLDI0NjE0LDI0NjAxLDI0NjI2LDI0NTg3LDI0NjI4LDI0NTg2LDI0NTk5LDI0NjI3LDI0NjAyLDI0NjA2LDI0NjIwLDI0NjEwLDI0NTg5LDI0NTkyLDI0NjIyLDI0NTk1LDI0NTkzLDI0NTg4LDI0NTg1LDI0NjA0LDI1MTA4LDI1MTQ5LDI1MjYxLDI1MjY4LDI1Mjk3LDI1Mjc4LDI1MjU4LDI1MjcwLDI1MjkwLDI1MjYyLDI1MjY3LDI1MjYzLDI1Mjc1LDI1MjU3LDI1MjY0LDI1MjcyLDI1OTE3LDI2MDI0LDI2MDQzLDI2MTIxLDI2MTA4LDI2MTE2LDI2MTMwLDI2MTIwLDI2MTA3LDI2MTE1LDI2MTIzLDI2MTI1LDI2MTE3LDI2MTA5LDI2MTI5LDI2MTI4LDI2MzU4LDI2Mzc4LDI2NTAxLDI2NDc2LDI2NTEwLDI2NTE0LDI2NDg2LDI2NDkxLDI2NTIwLDI2NTAyLDI2NTAwLDI2NDg0LDI2NTA5LDI2NTA4LDI2NDkwLDI2NTI3LDI2NTEzLDI2NTIxLDI2NDk5LDI2NDkzLDI2NDk3LDI2NDg4LDI2NDg5LDI2NTE2LDI3NDI5LDI3NTIwLDI3NTE4LDI3NjE0LDI3Njc3LDI3Nzk1LDI3ODg0LDI3ODgzLDI3ODg2LDI3ODY1LDI3ODMwLDI3ODYwLDI3ODIxLDI3ODc5LDI3ODMxLDI3ODU2LDI3ODQyLDI3ODM0LDI3ODQzLDI3ODQ2LDI3ODg1LDI3ODkwLDI3ODU4LDI3ODY5LDI3ODI4LDI3Nzg2LDI3ODA1LDI3Nzc2LDI3ODcwLDI3ODQwLDI3OTUyLDI3ODUzLDI3ODQ3LDI3ODI0LDI3ODk3LDI3ODU1LDI3ODgxLDI3ODU3LDI4ODIwLDI4ODI0LDI4ODA1LDI4ODE5LDI4ODA2LDI4ODA0LDI4ODE3LDI4ODIyLDI4ODAyLDI4ODI2LDI4ODAzLDI5MjkwLDI5Mzk4LDI5Mzg3LDI5NDAwLDI5Mzg1LDI5NDA0LDI5Mzk0LDI5Mzk2LDI5NDAyLDI5Mzg4LDI5MzkzLDI5NjA0LDI5NjAxLDI5NjEzLDI5NjA2LDI5NjAyLDI5NjAwLDI5NjEyLDI5NTk3LDI5OTE3LDI5OTI4LDMwMDE1LDMwMDE2LDMwMDE0LDMwMDkyLDMwMTA0LDMwMzgzLDMwNDUxLDMwNDQ5LDMwNDQ4LDMwNDUzLDMwNzEyLDMwNzE2LDMwNzEzLDMwNzE1LDMwNzE0LDMwNzExLDMxMDQyLDMxMDM5LDMxMTczLDMxMzUyLDMxMzU1LDMxNDgzLDMxODYxLDMxOTk3LDMyODIxLDMyOTExLDMyOTQyLDMyOTMxLDMyOTUyLDMyOTQ5LDMyOTQxLDMzMzEyLDMzNDQwLDMzNDcyLDMzNDUxLDMzNDM0LDMzNDMyLDMzNDM1LDMzNDYxLDMzNDQ3LDMzNDU0LDMzNDY4LDMzNDM4LDMzNDY2LDMzNDYwLDMzNDQ4LDMzNDQxLDMzNDQ5LDMzNDc0LDMzNDQ0LDMzNDc1LDMzNDYyLDMzNDQyLDM0NDE2LDM0NDE1LDM0NDEzLDM0NDE0LDM1OTI2LDM2ODE4LDM2ODExLDM2ODE5LDM2ODEzLDM2ODIyLDM2ODIxLDM2ODIzLDM3MDQyLDM3MDQ0LDM3MDM5LDM3MDQzLDM3MDQwLDM4NDU3LDM4NDYxLDM4NDYwLDM4NDU4LDM4NDY3LDIwNDI5LDIwNDIxLDIwNDM1LDIwNDAyLDIwNDI1LDIwNDI3LDIwNDE3LDIwNDM2LDIwNDQ0LDIwNDQxLDIwNDExLDIwNDAzLDIwNDQzLDIwNDIzLDIwNDM4LDIwNDEwLDIwNDE2LDIwNDA5LDIwNDYwLDIxMDYwLDIxMDY1LDIxMTg0LDIxMTg2LDIxMzA5LDIxMzcyLDIxMzk5LDIxMzk4LDIxNDAxLDIxNDAwLDIxNjkwLDIxNjY1LDIxNjc3LDIxNjY5LDIxNzExLDIxNjk5LDMzNTQ5LDIxNjg3LDIxNjc4LDIxNzE4LDIxNjg2LDIxNzAxLDIxNzAyLDIxNjY0LDIxNjE2LDIxNjkyLDIxNjY2LDIxNjk0LDIxNjE4LDIxNzI2LDIxNjgwLDIyNDUzLDIyNDMwLDIyNDMxLDIyNDM2LDIyNDEyLDIyNDIzLDIyNDI5LDIyNDI3LDIyNDIwLDIyNDI0LDIyNDE1LDIyNDI1LDIyNDM3LDIyNDI2LDIyNDIxLDIyNzcyLDIyNzk3LDIyODY3LDIzMDA5LDIzMDA2LDIzMDIyLDIzMDQwLDIzMDI1LDIzMDA1LDIzMDM0LDIzMDM3LDIzMDM2LDIzMDMwLDIzMDEyLDIzMDI2LDIzMDMxLDIzMDAzLDIzMDE3LDIzMDI3LDIzMDI5LDIzMDA4LDIzMDM4LDIzMDI4LDIzMDIxLDIzNDY0LDIzNjI4LDIzNzYwLDIzNzY4LDIzNzU2LDIzNzY3LDIzNzU1LDIzNzcxLDIzNzc0LDIzNzcwLDIzNzUzLDIzNzUxLDIzNzU0LDIzNzY2LDIzNzYzLDIzNzY0LDIzNzU5LDIzNzUyLDIzNzUwLDIzNzU4LDIzNzc1LDIzODAwLDI0MDU3LDI0MDk3LDI0MDk4LDI0MDk5LDI0MDk2LDI0MTAwLDI0MjQwLDI0MjI4LDI0MjI2LDI0MjE5LDI0MjI3LDI0MjI5LDI0MzI3LDI0MzY2LDI0NDA2LDI0NDU0LDI0NjMxLDI0NjMzLDI0NjYwLDI0NjkwLDI0NjcwLDI0NjQ1LDI0NjU5LDI0NjQ3LDI0NjQ5LDI0NjY3LDI0NjUyLDI0NjQwLDI0NjQyLDI0NjcxLDI0NjEyLDI0NjQ0LDI0NjY0LDI0Njc4LDI0Njg2LDI1MTU0LDI1MTU1LDI1Mjk1LDI1MzU3LDI1MzU1LDI1MzMzLDI1MzU4LDI1MzQ3LDI1MzIzLDI1MzM3LDI1MzU5LDI1MzU2LDI1MzM2LDI1MzM0LDI1MzQ0LDI1MzYzLDI1MzY0LDI1MzM4LDI1MzY1LDI1MzM5LDI1MzI4LDI1OTIxLDI1OTIzLDI2MDI2LDI2MDQ3LDI2MTY2LDI2MTQ1LDI2MTYyLDI2MTY1LDI2MTQwLDI2MTUwLDI2MTQ2LDI2MTYzLDI2MTU1LDI2MTcwLDI2MTQxLDI2MTY0LDI2MTY5LDI2MTU4LDI2MzgzLDI2Mzg0LDI2NTYxLDI2NjEwLDI2NTY4LDI2NTU0LDI2NTg4LDI2NTU1LDI2NjE2LDI2NTg0LDI2NTYwLDI2NTUxLDI2NTY1LDI2NjAzLDI2NTk2LDI2NTkxLDI2NTQ5LDI2NTczLDI2NTQ3LDI2NjE1LDI2NjE0LDI2NjA2LDI2NTk1LDI2NTYyLDI2NTUzLDI2NTc0LDI2NTk5LDI2NjA4LDI2NTQ2LDI2NjIwLDI2NTY2LDI2NjA1LDI2NTcyLDI2NTQyLDI2NTk4LDI2NTg3LDI2NjE4LDI2NTY5LDI2NTcwLDI2NTYzLDI2NjAyLDI2NTcxLDI3NDMyLDI3NTIyLDI3NTI0LDI3NTc0LDI3NjA2LDI3NjA4LDI3NjE2LDI3NjgwLDI3NjgxLDI3OTQ0LDI3OTU2LDI3OTQ5LDI3OTM1LDI3OTY0LDI3OTY3LDI3OTIyLDI3OTE0LDI3ODY2LDI3OTU1LDI3OTA4LDI3OTI5LDI3OTYyLDI3OTMwLDI3OTIxLDI3OTA0LDI3OTMzLDI3OTcwLDI3OTA1LDI3OTI4LDI3OTU5LDI3OTA3LDI3OTE5LDI3OTY4LDI3OTExLDI3OTM2LDI3OTQ4LDI3OTEyLDI3OTM4LDI3OTEzLDI3OTIwLDI4ODU1LDI4ODMxLDI4ODYyLDI4ODQ5LDI4ODQ4LDI4ODMzLDI4ODUyLDI4ODUzLDI4ODQxLDI5MjQ5LDI5MjU3LDI5MjU4LDI5MjkyLDI5Mjk2LDI5Mjk5LDI5Mjk0LDI5Mzg2LDI5NDEyLDI5NDE2LDI5NDE5LDI5NDA3LDI5NDE4LDI5NDE0LDI5NDExLDI5NTczLDI5NjQ0LDI5NjM0LDI5NjQwLDI5NjM3LDI5NjI1LDI5NjIyLDI5NjIxLDI5NjIwLDI5Njc1LDI5NjMxLDI5NjM5LDI5NjMwLDI5NjM1LDI5NjM4LDI5NjI0LDI5NjQzLDI5OTMyLDI5OTM0LDI5OTk4LDMwMDIzLDMwMDI0LDMwMTE5LDMwMTIyLDMwMzI5LDMwNDA0LDMwNDcyLDMwNDY3LDMwNDY4LDMwNDY5LDMwNDc0LDMwNDU1LDMwNDU5LDMwNDU4LDMwNjk1LDMwNjk2LDMwNzI2LDMwNzM3LDMwNzM4LDMwNzI1LDMwNzM2LDMwNzM1LDMwNzM0LDMwNzI5LDMwNzIzLDMwNzM5LDMxMDUwLDMxMDUyLDMxMDUxLDMxMDQ1LDMxMDQ0LDMxMTg5LDMxMTgxLDMxMTgzLDMxMTkwLDMxMTgyLDMxMzYwLDMxMzU4LDMxNDQxLDMxNDg4LDMxNDg5LDMxODY2LDMxODY0LDMxODY1LDMxODcxLDMxODcyLDMxODczLDMyMDAzLDMyMDA4LDMyMDAxLDMyNjAwLDMyNjU3LDMyNjUzLDMyNzAyLDMyNzc1LDMyNzgyLDMyNzgzLDMyNzg4LDMyODIzLDMyOTg0LDMyOTY3LDMyOTkyLDMyOTc3LDMyOTY4LDMyOTYyLDMyOTc2LDMyOTY1LDMyOTk1LDMyOTg1LDMyOTg4LDMyOTcwLDMyOTgxLDMyOTY5LDMyOTc1LDMyOTgzLDMyOTk4LDMyOTczLDMzMjc5LDMzMzEzLDMzNDI4LDMzNDk3LDMzNTM0LDMzNTI5LDMzNTQzLDMzNTEyLDMzNTM2LDMzNDkzLDMzNTk0LDMzNTE1LDMzNDk0LDMzNTI0LDMzNTE2LDMzNTA1LDMzNTIyLDMzNTI1LDMzNTQ4LDMzNTMxLDMzNTI2LDMzNTIwLDMzNTE0LDMzNTA4LDMzNTA0LDMzNTMwLDMzNTIzLDMzNTE3LDM0NDIzLDM0NDIwLDM0NDI4LDM0NDE5LDM0ODgxLDM0ODk0LDM0OTE5LDM0OTIyLDM0OTIxLDM1MjgzLDM1MzMyLDM1MzM1LDM2MjEwLDM2ODM1LDM2ODMzLDM2ODQ2LDM2ODMyLDM3MTA1LDM3MDUzLDM3MDU1LDM3MDc3LDM3MDYxLDM3MDU0LDM3MDYzLDM3MDY3LDM3MDY0LDM3MzMyLDM3MzMxLDM4NDg0LDM4NDc5LDM4NDgxLDM4NDgzLDM4NDc0LDM4NDc4LDIwNTEwLDIwNDg1LDIwNDg3LDIwNDk5LDIwNTE0LDIwNTI4LDIwNTA3LDIwNDY5LDIwNDY4LDIwNTMxLDIwNTM1LDIwNTI0LDIwNDcwLDIwNDcxLDIwNTAzLDIwNTA4LDIwNTEyLDIwNTE5LDIwNTMzLDIwNTI3LDIwNTI5LDIwNDk0LDIwODI2LDIwODg0LDIwODgzLDIwOTM4LDIwOTMyLDIwOTMzLDIwOTM2LDIwOTQyLDIxMDg5LDIxMDgyLDIxMDc0LDIxMDg2LDIxMDg3LDIxMDc3LDIxMDkwLDIxMTk3LDIxMjYyLDIxNDA2LDIxNzk4LDIxNzMwLDIxNzgzLDIxNzc4LDIxNzM1LDIxNzQ3LDIxNzMyLDIxNzg2LDIxNzU5LDIxNzY0LDIxNzY4LDIxNzM5LDIxNzc3LDIxNzY1LDIxNzQ1LDIxNzcwLDIxNzU1LDIxNzUxLDIxNzUyLDIxNzI4LDIxNzc0LDIxNzYzLDIxNzcxLDIyMjczLDIyMjc0LDIyNDc2LDIyNTc4LDIyNDg1LDIyNDgyLDIyNDU4LDIyNDcwLDIyNDYxLDIyNDYwLDIyNDU2LDIyNDU0LDIyNDYzLDIyNDcxLDIyNDgwLDIyNDU3LDIyNDY1LDIyNzk4LDIyODU4LDIzMDY1LDIzMDYyLDIzMDg1LDIzMDg2LDIzMDYxLDIzMDU1LDIzMDYzLDIzMDUwLDIzMDcwLDIzMDkxLDIzNDA0LDIzNDYzLDIzNDY5LDIzNDY4LDIzNTU1LDIzNjM4LDIzNjM2LDIzNzg4LDIzODA3LDIzNzkwLDIzNzkzLDIzNzk5LDIzODA4LDIzODAxLDI0MTA1LDI0MTA0LDI0MjMyLDI0MjM4LDI0MjM0LDI0MjM2LDI0MzcxLDI0MzY4LDI0NDIzLDI0NjY5LDI0NjY2LDI0Njc5LDI0NjQxLDI0NzM4LDI0NzEyLDI0NzA0LDI0NzIyLDI0NzA1LDI0NzMzLDI0NzA3LDI0NzI1LDI0NzMxLDI0NzI3LDI0NzExLDI0NzMyLDI0NzE4LDI1MTEzLDI1MTU4LDI1MzMwLDI1MzYwLDI1NDMwLDI1Mzg4LDI1NDEyLDI1NDEzLDI1Mzk4LDI1NDExLDI1NTcyLDI1NDAxLDI1NDE5LDI1NDE4LDI1NDA0LDI1Mzg1LDI1NDA5LDI1Mzk2LDI1NDMyLDI1NDI4LDI1NDMzLDI1Mzg5LDI1NDE1LDI1Mzk1LDI1NDM0LDI1NDI1LDI1NDAwLDI1NDMxLDI1NDA4LDI1NDE2LDI1OTMwLDI1OTI2LDI2MDU0LDI2MDUxLDI2MDUyLDI2MDUwLDI2MTg2LDI2MjA3LDI2MTgzLDI2MTkzLDI2Mzg2LDI2Mzg3LDI2NjU1LDI2NjUwLDI2Njk3LDI2Njc0LDI2Njc1LDI2NjgzLDI2Njk5LDI2NzAzLDI2NjQ2LDI2NjczLDI2NjUyLDI2Njc3LDI2NjY3LDI2NjY5LDI2NjcxLDI2NzAyLDI2NjkyLDI2Njc2LDI2NjUzLDI2NjQyLDI2NjQ0LDI2NjYyLDI2NjY0LDI2NjcwLDI2NzAxLDI2NjgyLDI2NjYxLDI2NjU2LDI3NDM2LDI3NDM5LDI3NDM3LDI3NDQxLDI3NDQ0LDI3NTAxLDMyODk4LDI3NTI4LDI3NjIyLDI3NjIwLDI3NjI0LDI3NjE5LDI3NjE4LDI3NjIzLDI3Njg1LDI4MDI2LDI4MDAzLDI4MDA0LDI4MDIyLDI3OTE3LDI4MDAxLDI4MDUwLDI3OTkyLDI4MDAyLDI4MDEzLDI4MDE1LDI4MDQ5LDI4MDQ1LDI4MTQzLDI4MDMxLDI4MDM4LDI3OTk4LDI4MDA3LDI4MDAwLDI4MDU1LDI4MDE2LDI4MDI4LDI3OTk5LDI4MDM0LDI4MDU2LDI3OTUxLDI4MDA4LDI4MDQzLDI4MDMwLDI4MDMyLDI4MDM2LDI3OTI2LDI4MDM1LDI4MDI3LDI4MDI5LDI4MDIxLDI4MDQ4LDI4ODkyLDI4ODgzLDI4ODgxLDI4ODkzLDI4ODc1LDMyNTY5LDI4ODk4LDI4ODg3LDI4ODgyLDI4ODk0LDI4ODk2LDI4ODg0LDI4ODc3LDI4ODY5LDI4ODcwLDI4ODcxLDI4ODkwLDI4ODc4LDI4ODk3LDI5MjUwLDI5MzA0LDI5MzAzLDI5MzAyLDI5NDQwLDI5NDM0LDI5NDI4LDI5NDM4LDI5NDMwLDI5NDI3LDI5NDM1LDI5NDQxLDI5NjUxLDI5NjU3LDI5NjY5LDI5NjU0LDI5NjI4LDI5NjcxLDI5NjY3LDI5NjczLDI5NjYwLDI5NjUwLDI5NjU5LDI5NjUyLDI5NjYxLDI5NjU4LDI5NjU1LDI5NjU2LDI5NjcyLDI5OTE4LDI5OTE5LDI5OTQwLDI5OTQxLDI5OTg1LDMwMDQzLDMwMDQ3LDMwMTI4LDMwMTQ1LDMwMTM5LDMwMTQ4LDMwMTQ0LDMwMTQzLDMwMTM0LDMwMTM4LDMwMzQ2LDMwNDA5LDMwNDkzLDMwNDkxLDMwNDgwLDMwNDgzLDMwNDgyLDMwNDk5LDMwNDgxLDMwNDg1LDMwNDg5LDMwNDkwLDMwNDk4LDMwNTAzLDMwNzU1LDMwNzY0LDMwNzU0LDMwNzczLDMwNzY3LDMwNzYwLDMwNzY2LDMwNzYzLDMwNzUzLDMwNzYxLDMwNzcxLDMwNzYyLDMwNzY5LDMxMDYwLDMxMDY3LDMxMDU1LDMxMDY4LDMxMDU5LDMxMDU4LDMxMDU3LDMxMjExLDMxMjEyLDMxMjAwLDMxMjE0LDMxMjEzLDMxMjEwLDMxMTk2LDMxMTk4LDMxMTk3LDMxMzY2LDMxMzY5LDMxMzY1LDMxMzcxLDMxMzcyLDMxMzcwLDMxMzY3LDMxNDQ4LDMxNTA0LDMxNDkyLDMxNTA3LDMxNDkzLDMxNTAzLDMxNDk2LDMxNDk4LDMxNTAyLDMxNDk3LDMxNTA2LDMxODc2LDMxODg5LDMxODgyLDMxODg0LDMxODgwLDMxODg1LDMxODc3LDMyMDMwLDMyMDI5LDMyMDE3LDMyMDE0LDMyMDI0LDMyMDIyLDMyMDE5LDMyMDMxLDMyMDE4LDMyMDE1LDMyMDEyLDMyNjA0LDMyNjA5LDMyNjA2LDMyNjA4LDMyNjA1LDMyNjAzLDMyNjYyLDMyNjU4LDMyNzA3LDMyNzA2LDMyNzA0LDMyNzkwLDMyODMwLDMyODI1LDMzMDE4LDMzMDEwLDMzMDE3LDMzMDEzLDMzMDI1LDMzMDE5LDMzMDI0LDMzMjgxLDMzMzI3LDMzMzE3LDMzNTg3LDMzNTgxLDMzNjA0LDMzNTYxLDMzNjE3LDMzNTczLDMzNjIyLDMzNTk5LDMzNjAxLDMzNTc0LDMzNTY0LDMzNTcwLDMzNjAyLDMzNjE0LDMzNTYzLDMzNTc4LDMzNTQ0LDMzNTk2LDMzNjEzLDMzNTU4LDMzNTcyLDMzNTY4LDMzNTkxLDMzNTgzLDMzNTc3LDMzNjA3LDMzNjA1LDMzNjEyLDMzNjE5LDMzNTY2LDMzNTgwLDMzNjExLDMzNTc1LDMzNjA4LDM0Mzg3LDM0Mzg2LDM0NDY2LDM0NDcyLDM0NDU0LDM0NDQ1LDM0NDQ5LDM0NDYyLDM0NDM5LDM0NDU1LDM0NDM4LDM0NDQzLDM0NDU4LDM0NDM3LDM0NDY5LDM0NDU3LDM0NDY1LDM0NDcxLDM0NDUzLDM0NDU2LDM0NDQ2LDM0NDYxLDM0NDQ4LDM0NDUyLDM0ODgzLDM0ODg0LDM0OTI1LDM0OTMzLDM0OTM0LDM0OTMwLDM0OTQ0LDM0OTI5LDM0OTQzLDM0OTI3LDM0OTQ3LDM0OTQyLDM0OTMyLDM0OTQwLDM1MzQ2LDM1OTExLDM1OTI3LDM1OTYzLDM2MDA0LDM2MDAzLDM2MjE0LDM2MjE2LDM2Mjc3LDM2Mjc5LDM2Mjc4LDM2NTYxLDM2NTYzLDM2ODYyLDM2ODUzLDM2ODY2LDM2ODYzLDM2ODU5LDM2ODY4LDM2ODYwLDM2ODU0LDM3MDc4LDM3MDg4LDM3MDgxLDM3MDgyLDM3MDkxLDM3MDg3LDM3MDkzLDM3MDgwLDM3MDgzLDM3MDc5LDM3MDg0LDM3MDkyLDM3MjAwLDM3MTk4LDM3MTk5LDM3MzMzLDM3MzQ2LDM3MzM4LDM4NDkyLDM4NDk1LDM4NTg4LDM5MTM5LDM5NjQ3LDM5NzI3LDIwMDk1LDIwNTkyLDIwNTg2LDIwNTc3LDIwNTc0LDIwNTc2LDIwNTYzLDIwNTU1LDIwNTczLDIwNTk0LDIwNTUyLDIwNTU3LDIwNTQ1LDIwNTcxLDIwNTU0LDIwNTc4LDIwNTAxLDIwNTQ5LDIwNTc1LDIwNTg1LDIwNTg3LDIwNTc5LDIwNTgwLDIwNTUwLDIwNTQ0LDIwNTkwLDIwNTk1LDIwNTY3LDIwNTYxLDIwOTQ0LDIxMDk5LDIxMTAxLDIxMTAwLDIxMTAyLDIxMjA2LDIxMjAzLDIxMjkzLDIxNDA0LDIxODc3LDIxODc4LDIxODIwLDIxODM3LDIxODQwLDIxODEyLDIxODAyLDIxODQxLDIxODU4LDIxODE0LDIxODEzLDIxODA4LDIxODQyLDIxODI5LDIxNzcyLDIxODEwLDIxODYxLDIxODM4LDIxODE3LDIxODMyLDIxODA1LDIxODE5LDIxODI0LDIxODM1LDIyMjgyLDIyMjc5LDIyNTIzLDIyNTQ4LDIyNDk4LDIyNTE4LDIyNDkyLDIyNTE2LDIyNTI4LDIyNTA5LDIyNTI1LDIyNTM2LDIyNTIwLDIyNTM5LDIyNTE1LDIyNDc5LDIyNTM1LDIyNTEwLDIyNDk5LDIyNTE0LDIyNTAxLDIyNTA4LDIyNDk3LDIyNTQyLDIyNTI0LDIyNTQ0LDIyNTAzLDIyNTI5LDIyNTQwLDIyNTEzLDIyNTA1LDIyNTEyLDIyNTQxLDIyNTMyLDIyODc2LDIzMTM2LDIzMTI4LDIzMTI1LDIzMTQzLDIzMTM0LDIzMDk2LDIzMDkzLDIzMTQ5LDIzMTIwLDIzMTM1LDIzMTQxLDIzMTQ4LDIzMTIzLDIzMTQwLDIzMTI3LDIzMTA3LDIzMTMzLDIzMTIyLDIzMTA4LDIzMTMxLDIzMTEyLDIzMTgyLDIzMTAyLDIzMTE3LDIzMDk3LDIzMTE2LDIzMTUyLDIzMTQ1LDIzMTExLDIzMTIxLDIzMTI2LDIzMTA2LDIzMTMyLDIzNDEwLDIzNDA2LDIzNDg5LDIzNDg4LDIzNjQxLDIzODM4LDIzODE5LDIzODM3LDIzODM0LDIzODQwLDIzODIwLDIzODQ4LDIzODIxLDIzODQ2LDIzODQ1LDIzODIzLDIzODU2LDIzODI2LDIzODQzLDIzODM5LDIzODU0LDI0MTI2LDI0MTE2LDI0MjQxLDI0MjQ0LDI0MjQ5LDI0MjQyLDI0MjQzLDI0Mzc0LDI0Mzc2LDI0NDc1LDI0NDcwLDI0NDc5LDI0NzE0LDI0NzIwLDI0NzEwLDI0NzY2LDI0NzUyLDI0NzYyLDI0Nzg3LDI0Nzg4LDI0NzgzLDI0ODA0LDI0NzkzLDI0Nzk3LDI0Nzc2LDI0NzUzLDI0Nzk1LDI0NzU5LDI0Nzc4LDI0NzY3LDI0NzcxLDI0NzgxLDI0NzY4LDI1Mzk0LDI1NDQ1LDI1NDgyLDI1NDc0LDI1NDY5LDI1NTMzLDI1NTAyLDI1NTE3LDI1NTAxLDI1NDk1LDI1NTE1LDI1NDg2LDI1NDU1LDI1NDc5LDI1NDg4LDI1NDU0LDI1NTE5LDI1NDYxLDI1NTAwLDI1NDUzLDI1NTE4LDI1NDY4LDI1NTA4LDI1NDAzLDI1NTAzLDI1NDY0LDI1NDc3LDI1NDczLDI1NDg5LDI1NDg1LDI1NDU2LDI1OTM5LDI2MDYxLDI2MjEzLDI2MjA5LDI2MjAzLDI2MjAxLDI2MjA0LDI2MjEwLDI2MzkyLDI2NzQ1LDI2NzU5LDI2NzY4LDI2NzgwLDI2NzMzLDI2NzM0LDI2Nzk4LDI2Nzk1LDI2OTY2LDI2NzM1LDI2Nzg3LDI2Nzk2LDI2NzkzLDI2NzQxLDI2NzQwLDI2ODAyLDI2NzY3LDI2NzQzLDI2NzcwLDI2NzQ4LDI2NzMxLDI2NzM4LDI2Nzk0LDI2NzUyLDI2NzM3LDI2NzUwLDI2Nzc5LDI2Nzc0LDI2NzYzLDI2Nzg0LDI2NzYxLDI2Nzg4LDI2NzQ0LDI2NzQ3LDI2NzY5LDI2NzY0LDI2NzYyLDI2NzQ5LDI3NDQ2LDI3NDQzLDI3NDQ3LDI3NDQ4LDI3NTM3LDI3NTM1LDI3NTMzLDI3NTM0LDI3NTMyLDI3NjkwLDI4MDk2LDI4MDc1LDI4MDg0LDI4MDgzLDI4Mjc2LDI4MDc2LDI4MTM3LDI4MTMwLDI4MDg3LDI4MTUwLDI4MTE2LDI4MTYwLDI4MTA0LDI4MTI4LDI4MTI3LDI4MTE4LDI4MDk0LDI4MTMzLDI4MTI0LDI4MTI1LDI4MTIzLDI4MTQ4LDI4MTA2LDI4MDkzLDI4MTQxLDI4MTQ0LDI4MDkwLDI4MTE3LDI4MDk4LDI4MTExLDI4MTA1LDI4MTEyLDI4MTQ2LDI4MTE1LDI4MTU3LDI4MTE5LDI4MTA5LDI4MTMxLDI4MDkxLDI4OTIyLDI4OTQxLDI4OTE5LDI4OTUxLDI4OTE2LDI4OTQwLDI4OTEyLDI4OTMyLDI4OTE1LDI4OTQ0LDI4OTI0LDI4OTI3LDI4OTM0LDI4OTQ3LDI4OTI4LDI4OTIwLDI4OTE4LDI4OTM5LDI4OTMwLDI4OTQyLDI5MzEwLDI5MzA3LDI5MzA4LDI5MzExLDI5NDY5LDI5NDYzLDI5NDQ3LDI5NDU3LDI5NDY0LDI5NDUwLDI5NDQ4LDI5NDM5LDI5NDU1LDI5NDcwLDI5NTc2LDI5Njg2LDI5Njg4LDI5Njg1LDI5NzAwLDI5Njk3LDI5NjkzLDI5NzAzLDI5Njk2LDI5NjkwLDI5NjkyLDI5Njk1LDI5NzA4LDI5NzA3LDI5Njg0LDI5NzA0LDMwMDUyLDMwMDUxLDMwMTU4LDMwMTYyLDMwMTU5LDMwMTU1LDMwMTU2LDMwMTYxLDMwMTYwLDMwMzUxLDMwMzQ1LDMwNDE5LDMwNTIxLDMwNTExLDMwNTA5LDMwNTEzLDMwNTE0LDMwNTE2LDMwNTE1LDMwNTI1LDMwNTAxLDMwNTIzLDMwNTE3LDMwNzkyLDMwODAyLDMwNzkzLDMwNzk3LDMwNzk0LDMwNzk2LDMwNzU4LDMwNzg5LDMwODAwLDMxMDc2LDMxMDc5LDMxMDgxLDMxMDgyLDMxMDc1LDMxMDgzLDMxMDczLDMxMTYzLDMxMjI2LDMxMjI0LDMxMjIyLDMxMjIzLDMxMzc1LDMxMzgwLDMxMzc2LDMxNTQxLDMxNTU5LDMxNTQwLDMxNTI1LDMxNTM2LDMxNTIyLDMxNTI0LDMxNTM5LDMxNTEyLDMxNTMwLDMxNTE3LDMxNTM3LDMxNTMxLDMxNTMzLDMxNTM1LDMxNTM4LDMxNTQ0LDMxNTE0LDMxNTIzLDMxODkyLDMxODk2LDMxODk0LDMxOTA3LDMyMDUzLDMyMDYxLDMyMDU2LDMyMDU0LDMyMDU4LDMyMDY5LDMyMDQ0LDMyMDQxLDMyMDY1LDMyMDcxLDMyMDYyLDMyMDYzLDMyMDc0LDMyMDU5LDMyMDQwLDMyNjExLDMyNjYxLDMyNjY4LDMyNjY5LDMyNjY3LDMyNzE0LDMyNzE1LDMyNzE3LDMyNzIwLDMyNzIxLDMyNzExLDMyNzE5LDMyNzEzLDMyNzk5LDMyNzk4LDMyNzk1LDMyODM5LDMyODM1LDMyODQwLDMzMDQ4LDMzMDYxLDMzMDQ5LDMzMDUxLDMzMDY5LDMzMDU1LDMzMDY4LDMzMDU0LDMzMDU3LDMzMDQ1LDMzMDYzLDMzMDUzLDMzMDU4LDMzMjk3LDMzMzM2LDMzMzMxLDMzMzM4LDMzMzMyLDMzMzMwLDMzMzk2LDMzNjgwLDMzNjk5LDMzNzA0LDMzNjc3LDMzNjU4LDMzNjUxLDMzNzAwLDMzNjUyLDMzNjc5LDMzNjY1LDMzNjg1LDMzNjg5LDMzNjUzLDMzNjg0LDMzNzA1LDMzNjYxLDMzNjY3LDMzNjc2LDMzNjkzLDMzNjkxLDMzNzA2LDMzNjc1LDMzNjYyLDMzNzAxLDMzNzExLDMzNjcyLDMzNjg3LDMzNzEyLDMzNjYzLDMzNzAyLDMzNjcxLDMzNzEwLDMzNjU0LDMzNjkwLDM0MzkzLDM0MzkwLDM0NDk1LDM0NDg3LDM0NDk4LDM0NDk3LDM0NTAxLDM0NDkwLDM0NDgwLDM0NTA0LDM0NDg5LDM0NDgzLDM0NDg4LDM0NTA4LDM0NDg0LDM0NDkxLDM0NDkyLDM0NDk5LDM0NDkzLDM0NDk0LDM0ODk4LDM0OTUzLDM0OTY1LDM0OTg0LDM0OTc4LDM0OTg2LDM0OTcwLDM0OTYxLDM0OTc3LDM0OTc1LDM0OTY4LDM0OTgzLDM0OTY5LDM0OTcxLDM0OTY3LDM0OTgwLDM0OTg4LDM0OTU2LDM0OTYzLDM0OTU4LDM1MjAyLDM1Mjg2LDM1Mjg5LDM1Mjg1LDM1Mzc2LDM1MzY3LDM1MzcyLDM1MzU4LDM1ODk3LDM1ODk5LDM1OTMyLDM1OTMzLDM1OTY1LDM2MDA1LDM2MjIxLDM2MjE5LDM2MjE3LDM2Mjg0LDM2MjkwLDM2MjgxLDM2Mjg3LDM2Mjg5LDM2NTY4LDM2NTc0LDM2NTczLDM2NTcyLDM2NTY3LDM2NTc2LDM2NTc3LDM2OTAwLDM2ODc1LDM2ODgxLDM2ODkyLDM2ODc2LDM2ODk3LDM3MTAzLDM3MDk4LDM3MTA0LDM3MTA4LDM3MTA2LDM3MTA3LDM3MDc2LDM3MDk5LDM3MTAwLDM3MDk3LDM3MjA2LDM3MjA4LDM3MjEwLDM3MjAzLDM3MjA1LDM3MzU2LDM3MzY0LDM3MzYxLDM3MzYzLDM3MzY4LDM3MzQ4LDM3MzY5LDM3MzU0LDM3MzU1LDM3MzY3LDM3MzUyLDM3MzU4LDM4MjY2LDM4Mjc4LDM4MjgwLDM4NTI0LDM4NTA5LDM4NTA3LDM4NTEzLDM4NTExLDM4NTkxLDM4NzYyLDM4OTE2LDM5MTQxLDM5MzE5LDIwNjM1LDIwNjI5LDIwNjI4LDIwNjM4LDIwNjE5LDIwNjQzLDIwNjExLDIwNjIwLDIwNjIyLDIwNjM3LDIwNTg0LDIwNjM2LDIwNjI2LDIwNjEwLDIwNjE1LDIwODMxLDIwOTQ4LDIxMjY2LDIxMjY1LDIxNDEyLDIxNDE1LDIxOTA1LDIxOTI4LDIxOTI1LDIxOTMzLDIxODc5LDIyMDg1LDIxOTIyLDIxOTA3LDIxODk2LDIxOTAzLDIxOTQxLDIxODg5LDIxOTIzLDIxOTA2LDIxOTI0LDIxODg1LDIxOTAwLDIxOTI2LDIxODg3LDIxOTA5LDIxOTIxLDIxOTAyLDIyMjg0LDIyNTY5LDIyNTgzLDIyNTUzLDIyNTU4LDIyNTY3LDIyNTYzLDIyNTY4LDIyNTE3LDIyNjAwLDIyNTY1LDIyNTU2LDIyNTU1LDIyNTc5LDIyNTkxLDIyNTgyLDIyNTc0LDIyNTg1LDIyNTg0LDIyNTczLDIyNTcyLDIyNTg3LDIyODgxLDIzMjE1LDIzMTg4LDIzMTk5LDIzMTYyLDIzMjAyLDIzMTk4LDIzMTYwLDIzMjA2LDIzMTY0LDIzMjA1LDIzMjEyLDIzMTg5LDIzMjE0LDIzMDk1LDIzMTcyLDIzMTc4LDIzMTkxLDIzMTcxLDIzMTc5LDIzMjA5LDIzMTYzLDIzMTY1LDIzMTgwLDIzMTk2LDIzMTgzLDIzMTg3LDIzMTk3LDIzNTMwLDIzNTAxLDIzNDk5LDIzNTA4LDIzNTA1LDIzNDk4LDIzNTAyLDIzNTY0LDIzNjAwLDIzODYzLDIzODc1LDIzOTE1LDIzODczLDIzODgzLDIzODcxLDIzODYxLDIzODg5LDIzODg2LDIzODkzLDIzODU5LDIzODY2LDIzODkwLDIzODY5LDIzODU3LDIzODk3LDIzODc0LDIzODY1LDIzODgxLDIzODY0LDIzODY4LDIzODU4LDIzODYyLDIzODcyLDIzODc3LDI0MTMyLDI0MTI5LDI0NDA4LDI0NDg2LDI0NDg1LDI0NDkxLDI0Nzc3LDI0NzYxLDI0NzgwLDI0ODAyLDI0NzgyLDI0NzcyLDI0ODUyLDI0ODE4LDI0ODQyLDI0ODU0LDI0ODM3LDI0ODIxLDI0ODUxLDI0ODI0LDI0ODI4LDI0ODMwLDI0NzY5LDI0ODM1LDI0ODU2LDI0ODYxLDI0ODQ4LDI0ODMxLDI0ODM2LDI0ODQzLDI1MTYyLDI1NDkyLDI1NTIxLDI1NTIwLDI1NTUwLDI1NTczLDI1NTc2LDI1NTgzLDI1NTM5LDI1NzU3LDI1NTg3LDI1NTQ2LDI1NTY4LDI1NTkwLDI1NTU3LDI1NTg2LDI1NTg5LDI1Njk3LDI1NTY3LDI1NTM0LDI1NTY1LDI1NTY0LDI1NTQwLDI1NTYwLDI1NTU1LDI1NTM4LDI1NTQzLDI1NTQ4LDI1NTQ3LDI1NTQ0LDI1NTg0LDI1NTU5LDI1NTYxLDI1OTA2LDI1OTU5LDI1OTYyLDI1OTU2LDI1OTQ4LDI1OTYwLDI1OTU3LDI1OTk2LDI2MDEzLDI2MDE0LDI2MDMwLDI2MDY0LDI2MDY2LDI2MjM2LDI2MjIwLDI2MjM1LDI2MjQwLDI2MjI1LDI2MjMzLDI2MjE4LDI2MjI2LDI2MzY5LDI2ODkyLDI2ODM1LDI2ODg0LDI2ODQ0LDI2OTIyLDI2ODYwLDI2ODU4LDI2ODY1LDI2ODk1LDI2ODM4LDI2ODcxLDI2ODU5LDI2ODUyLDI2ODcwLDI2ODk5LDI2ODk2LDI2ODY3LDI2ODQ5LDI2ODg3LDI2ODI4LDI2ODg4LDI2OTkyLDI2ODA0LDI2ODk3LDI2ODYzLDI2ODIyLDI2OTAwLDI2ODcyLDI2ODMyLDI2ODc3LDI2ODc2LDI2ODU2LDI2ODkxLDI2ODkwLDI2OTAzLDI2ODMwLDI2ODI0LDI2ODQ1LDI2ODQ2LDI2ODU0LDI2ODY4LDI2ODMzLDI2ODg2LDI2ODM2LDI2ODU3LDI2OTAxLDI2OTE3LDI2ODIzLDI3NDQ5LDI3NDUxLDI3NDU1LDI3NDUyLDI3NTQwLDI3NTQzLDI3NTQ1LDI3NTQxLDI3NTgxLDI3NjMyLDI3NjM0LDI3NjM1LDI3Njk2LDI4MTU2LDI4MjMwLDI4MjMxLDI4MTkxLDI4MjMzLDI4Mjk2LDI4MjIwLDI4MjIxLDI4MjI5LDI4MjU4LDI4MjAzLDI4MjIzLDI4MjI1LDI4MjUzLDI4Mjc1LDI4MTg4LDI4MjExLDI4MjM1LDI4MjI0LDI4MjQxLDI4MjE5LDI4MTYzLDI4MjA2LDI4MjU0LDI4MjY0LDI4MjUyLDI4MjU3LDI4MjA5LDI4MjAwLDI4MjU2LDI4MjczLDI4MjY3LDI4MjE3LDI4MTk0LDI4MjA4LDI4MjQzLDI4MjYxLDI4MTk5LDI4MjgwLDI4MjYwLDI4Mjc5LDI4MjQ1LDI4MjgxLDI4MjQyLDI4MjYyLDI4MjEzLDI4MjE0LDI4MjUwLDI4OTYwLDI4OTU4LDI4OTc1LDI4OTIzLDI4OTc0LDI4OTc3LDI4OTYzLDI4OTY1LDI4OTYyLDI4OTc4LDI4OTU5LDI4OTY4LDI4OTg2LDI4OTU1LDI5MjU5LDI5Mjc0LDI5MzIwLDI5MzIxLDI5MzE4LDI5MzE3LDI5MzIzLDI5NDU4LDI5NDUxLDI5NDg4LDI5NDc0LDI5NDg5LDI5NDkxLDI5NDc5LDI5NDkwLDI5NDg1LDI5NDc4LDI5NDc1LDI5NDkzLDI5NDUyLDI5NzQyLDI5NzQwLDI5NzQ0LDI5NzM5LDI5NzE4LDI5NzIyLDI5NzI5LDI5NzQxLDI5NzQ1LDI5NzMyLDI5NzMxLDI5NzI1LDI5NzM3LDI5NzI4LDI5NzQ2LDI5OTQ3LDI5OTk5LDMwMDYzLDMwMDYwLDMwMTgzLDMwMTcwLDMwMTc3LDMwMTgyLDMwMTczLDMwMTc1LDMwMTgwLDMwMTY3LDMwMzU3LDMwMzU0LDMwNDI2LDMwNTM0LDMwNTM1LDMwNTMyLDMwNTQxLDMwNTMzLDMwNTM4LDMwNTQyLDMwNTM5LDMwNTQwLDMwNjg2LDMwNzAwLDMwODE2LDMwODIwLDMwODIxLDMwODEyLDMwODI5LDMwODMzLDMwODI2LDMwODMwLDMwODMyLDMwODI1LDMwODI0LDMwODE0LDMwODE4LDMxMDkyLDMxMDkxLDMxMDkwLDMxMDg4LDMxMjM0LDMxMjQyLDMxMjM1LDMxMjQ0LDMxMjM2LDMxMzg1LDMxNDYyLDMxNDYwLDMxNTYyLDMxNTQ3LDMxNTU2LDMxNTYwLDMxNTY0LDMxNTY2LDMxNTUyLDMxNTc2LDMxNTU3LDMxOTA2LDMxOTAyLDMxOTEyLDMxOTA1LDMyMDg4LDMyMTExLDMyMDk5LDMyMDgzLDMyMDg2LDMyMTAzLDMyMTA2LDMyMDc5LDMyMTA5LDMyMDkyLDMyMTA3LDMyMDgyLDMyMDg0LDMyMTA1LDMyMDgxLDMyMDk1LDMyMDc4LDMyNTc0LDMyNTc1LDMyNjEzLDMyNjE0LDMyNjc0LDMyNjcyLDMyNjczLDMyNzI3LDMyODQ5LDMyODQ3LDMyODQ4LDMzMDIyLDMyOTgwLDMzMDkxLDMzMDk4LDMzMTA2LDMzMTAzLDMzMDk1LDMzMDg1LDMzMTAxLDMzMDgyLDMzMjU0LDMzMjYyLDMzMjcxLDMzMjcyLDMzMjczLDMzMjg0LDMzMzQwLDMzMzQxLDMzMzQzLDMzMzk3LDMzNTk1LDMzNzQzLDMzNzg1LDMzODI3LDMzNzI4LDMzNzY4LDMzODEwLDMzNzY3LDMzNzY0LDMzNzg4LDMzNzgyLDMzODA4LDMzNzM0LDMzNzM2LDMzNzcxLDMzNzYzLDMzNzI3LDMzNzkzLDMzNzU3LDMzNzY1LDMzNzUyLDMzNzkxLDMzNzYxLDMzNzM5LDMzNzQyLDMzNzUwLDMzNzgxLDMzNzM3LDMzODAxLDMzODA3LDMzNzU4LDMzODA5LDMzNzk4LDMzNzMwLDMzNzc5LDMzNzQ5LDMzNzg2LDMzNzM1LDMzNzQ1LDMzNzcwLDMzODExLDMzNzMxLDMzNzcyLDMzNzc0LDMzNzMyLDMzNzg3LDMzNzUxLDMzNzYyLDMzODE5LDMzNzU1LDMzNzkwLDM0NTIwLDM0NTMwLDM0NTM0LDM0NTE1LDM0NTMxLDM0NTIyLDM0NTM4LDM0NTI1LDM0NTM5LDM0NTI0LDM0NTQwLDM0NTM3LDM0NTE5LDM0NTM2LDM0NTEzLDM0ODg4LDM0OTAyLDM0OTAxLDM1MDAyLDM1MDMxLDM1MDAxLDM1MDAwLDM1MDA4LDM1MDA2LDM0OTk4LDM1MDA0LDM0OTk5LDM1MDA1LDM0OTk0LDM1MDczLDM1MDE3LDM1MjIxLDM1MjI0LDM1MjIzLDM1MjkzLDM1MjkwLDM1MjkxLDM1NDA2LDM1NDA1LDM1Mzg1LDM1NDE3LDM1MzkyLDM1NDE1LDM1NDE2LDM1Mzk2LDM1Mzk3LDM1NDEwLDM1NDAwLDM1NDA5LDM1NDAyLDM1NDA0LDM1NDA3LDM1OTM1LDM1OTY5LDM1OTY4LDM2MDI2LDM2MDMwLDM2MDE2LDM2MDI1LDM2MDIxLDM2MjI4LDM2MjI0LDM2MjMzLDM2MzEyLDM2MzA3LDM2MzAxLDM2Mjk1LDM2MzEwLDM2MzE2LDM2MzAzLDM2MzA5LDM2MzEzLDM2Mjk2LDM2MzExLDM2MjkzLDM2NTkxLDM2NTk5LDM2NjAyLDM2NjAxLDM2NTgyLDM2NTkwLDM2NTgxLDM2NTk3LDM2NTgzLDM2NTg0LDM2NTk4LDM2NTg3LDM2NTkzLDM2NTg4LDM2NTk2LDM2NTg1LDM2OTA5LDM2OTE2LDM2OTExLDM3MTI2LDM3MTY0LDM3MTI0LDM3MTE5LDM3MTE2LDM3MTI4LDM3MTEzLDM3MTE1LDM3MTIxLDM3MTIwLDM3MTI3LDM3MTI1LDM3MTIzLDM3MjE3LDM3MjIwLDM3MjE1LDM3MjE4LDM3MjE2LDM3Mzc3LDM3Mzg2LDM3NDEzLDM3Mzc5LDM3NDAyLDM3NDE0LDM3MzkxLDM3Mzg4LDM3Mzc2LDM3Mzk0LDM3Mzc1LDM3MzczLDM3MzgyLDM3MzgwLDM3NDE1LDM3Mzc4LDM3NDA0LDM3NDEyLDM3NDAxLDM3Mzk5LDM3MzgxLDM3Mzk4LDM4MjY3LDM4Mjg1LDM4Mjg0LDM4Mjg4LDM4NTM1LDM4NTI2LDM4NTM2LDM4NTM3LDM4NTMxLDM4NTI4LDM4NTk0LDM4NjAwLDM4NTk1LDM4NjQxLDM4NjQwLDM4NzY0LDM4NzY4LDM4NzY2LDM4OTE5LDM5MDgxLDM5MTQ3LDQwMTY2LDQwNjk3LDIwMDk5LDIwMTAwLDIwMTUwLDIwNjY5LDIwNjcxLDIwNjc4LDIwNjU0LDIwNjc2LDIwNjgyLDIwNjYwLDIwNjgwLDIwNjc0LDIwNjU2LDIwNjczLDIwNjY2LDIwNjU3LDIwNjgzLDIwNjgxLDIwNjYyLDIwNjY0LDIwOTUxLDIxMTE0LDIxMTEyLDIxMTE1LDIxMTE2LDIxOTU1LDIxOTc5LDIxOTY0LDIxOTY4LDIxOTYzLDIxOTYyLDIxOTgxLDIxOTUyLDIxOTcyLDIxOTU2LDIxOTkzLDIxOTUxLDIxOTcwLDIxOTAxLDIxOTY3LDIxOTczLDIxOTg2LDIxOTc0LDIxOTYwLDIyMDAyLDIxOTY1LDIxOTc3LDIxOTU0LDIyMjkyLDIyNjExLDIyNjMyLDIyNjI4LDIyNjA3LDIyNjA1LDIyNjAxLDIyNjM5LDIyNjEzLDIyNjA2LDIyNjIxLDIyNjE3LDIyNjI5LDIyNjE5LDIyNTg5LDIyNjI3LDIyNjQxLDIyNzgwLDIzMjM5LDIzMjM2LDIzMjQzLDIzMjI2LDIzMjI0LDIzMjE3LDIzMjIxLDIzMjE2LDIzMjMxLDIzMjQwLDIzMjI3LDIzMjM4LDIzMjIzLDIzMjMyLDIzMjQyLDIzMjIwLDIzMjIyLDIzMjQ1LDIzMjI1LDIzMTg0LDIzNTEwLDIzNTEyLDIzNTEzLDIzNTgzLDIzNjAzLDIzOTIxLDIzOTA3LDIzODgyLDIzOTA5LDIzOTIyLDIzOTE2LDIzOTAyLDIzOTEyLDIzOTExLDIzOTA2LDI0MDQ4LDI0MTQzLDI0MTQyLDI0MTM4LDI0MTQxLDI0MTM5LDI0MjYxLDI0MjY4LDI0MjYyLDI0MjY3LDI0MjYzLDI0Mzg0LDI0NDk1LDI0NDkzLDI0ODIzLDI0OTA1LDI0OTA2LDI0ODc1LDI0OTAxLDI0ODg2LDI0ODgyLDI0ODc4LDI0OTAyLDI0ODc5LDI0OTExLDI0ODczLDI0ODk2LDI1MTIwLDM3MjI0LDI1MTIzLDI1MTI1LDI1MTI0LDI1NTQxLDI1NTg1LDI1NTc5LDI1NjE2LDI1NjE4LDI1NjA5LDI1NjMyLDI1NjM2LDI1NjUxLDI1NjY3LDI1NjMxLDI1NjIxLDI1NjI0LDI1NjU3LDI1NjU1LDI1NjM0LDI1NjM1LDI1NjEyLDI1NjM4LDI1NjQ4LDI1NjQwLDI1NjY1LDI1NjUzLDI1NjQ3LDI1NjEwLDI1NjI2LDI1NjY0LDI1NjM3LDI1NjM5LDI1NjExLDI1NTc1LDI1NjI3LDI1NjQ2LDI1NjMzLDI1NjE0LDI1OTY3LDI2MDAyLDI2MDY3LDI2MjQ2LDI2MjUyLDI2MjYxLDI2MjU2LDI2MjUxLDI2MjUwLDI2MjY1LDI2MjYwLDI2MjMyLDI2NDAwLDI2OTgyLDI2OTc1LDI2OTM2LDI2OTU4LDI2OTc4LDI2OTkzLDI2OTQzLDI2OTQ5LDI2OTg2LDI2OTM3LDI2OTQ2LDI2OTY3LDI2OTY5LDI3MDAyLDI2OTUyLDI2OTUzLDI2OTMzLDI2OTg4LDI2OTMxLDI2OTQxLDI2OTgxLDI2ODY0LDI3MDAwLDI2OTMyLDI2OTg1LDI2OTQ0LDI2OTkxLDI2OTQ4LDI2OTk4LDI2OTY4LDI2OTQ1LDI2OTk2LDI2OTU2LDI2OTM5LDI2OTU1LDI2OTM1LDI2OTcyLDI2OTU5LDI2OTYxLDI2OTMwLDI2OTYyLDI2OTI3LDI3MDAzLDI2OTQwLDI3NDYyLDI3NDYxLDI3NDU5LDI3NDU4LDI3NDY0LDI3NDU3LDI3NTQ3LDY0MDEzLDI3NjQzLDI3NjQ0LDI3NjQxLDI3NjM5LDI3NjQwLDI4MzE1LDI4Mzc0LDI4MzYwLDI4MzAzLDI4MzUyLDI4MzE5LDI4MzA3LDI4MzA4LDI4MzIwLDI4MzM3LDI4MzQ1LDI4MzU4LDI4MzcwLDI4MzQ5LDI4MzUzLDI4MzE4LDI4MzYxLDI4MzQzLDI4MzM2LDI4MzY1LDI4MzI2LDI4MzY3LDI4MzM4LDI4MzUwLDI4MzU1LDI4MzgwLDI4Mzc2LDI4MzEzLDI4MzA2LDI4MzAyLDI4MzAxLDI4MzI0LDI4MzIxLDI4MzUxLDI4MzM5LDI4MzY4LDI4MzYyLDI4MzExLDI4MzM0LDI4MzIzLDI4OTk5LDI5MDEyLDI5MDEwLDI5MDI3LDI5MDI0LDI4OTkzLDI5MDIxLDI5MDI2LDI5MDQyLDI5MDQ4LDI5MDM0LDI5MDI1LDI4OTk0LDI5MDE2LDI4OTk1LDI5MDAzLDI5MDQwLDI5MDIzLDI5MDA4LDI5MDExLDI4OTk2LDI5MDA1LDI5MDE4LDI5MjYzLDI5MzI1LDI5MzI0LDI5MzI5LDI5MzI4LDI5MzI2LDI5NTAwLDI5NTA2LDI5NDk5LDI5NDk4LDI5NTA0LDI5NTE0LDI5NTEzLDI5NzY0LDI5NzcwLDI5NzcxLDI5Nzc4LDI5Nzc3LDI5NzgzLDI5NzYwLDI5Nzc1LDI5Nzc2LDI5Nzc0LDI5NzYyLDI5NzY2LDI5NzczLDI5NzgwLDI5OTIxLDI5OTUxLDI5OTUwLDI5OTQ5LDI5OTgxLDMwMDczLDMwMDcxLDI3MDExLDMwMTkxLDMwMjIzLDMwMjExLDMwMTk5LDMwMjA2LDMwMjA0LDMwMjAxLDMwMjAwLDMwMjI0LDMwMjAzLDMwMTk4LDMwMTg5LDMwMTk3LDMwMjA1LDMwMzYxLDMwMzg5LDMwNDI5LDMwNTQ5LDMwNTU5LDMwNTYwLDMwNTQ2LDMwNTUwLDMwNTU0LDMwNTY5LDMwNTY3LDMwNTQ4LDMwNTUzLDMwNTczLDMwNjg4LDMwODU1LDMwODc0LDMwODY4LDMwODYzLDMwODUyLDMwODY5LDMwODUzLDMwODU0LDMwODgxLDMwODUxLDMwODQxLDMwODczLDMwODQ4LDMwODcwLDMwODQzLDMxMTAwLDMxMTA2LDMxMTAxLDMxMDk3LDMxMjQ5LDMxMjU2LDMxMjU3LDMxMjUwLDMxMjU1LDMxMjUzLDMxMjY2LDMxMjUxLDMxMjU5LDMxMjQ4LDMxMzk1LDMxMzk0LDMxMzkwLDMxNDY3LDMxNTkwLDMxNTg4LDMxNTk3LDMxNjA0LDMxNTkzLDMxNjAyLDMxNTg5LDMxNjAzLDMxNjAxLDMxNjAwLDMxNTg1LDMxNjA4LDMxNjA2LDMxNTg3LDMxOTIyLDMxOTI0LDMxOTE5LDMyMTM2LDMyMTM0LDMyMTI4LDMyMTQxLDMyMTI3LDMyMTMzLDMyMTIyLDMyMTQyLDMyMTIzLDMyMTMxLDMyMTI0LDMyMTQwLDMyMTQ4LDMyMTMyLDMyMTI1LDMyMTQ2LDMyNjIxLDMyNjE5LDMyNjE1LDMyNjE2LDMyNjIwLDMyNjc4LDMyNjc3LDMyNjc5LDMyNzMxLDMyNzMyLDMyODAxLDMzMTI0LDMzMTIwLDMzMTQzLDMzMTE2LDMzMTI5LDMzMTE1LDMzMTIyLDMzMTM4LDI2NDAxLDMzMTE4LDMzMTQyLDMzMTI3LDMzMTM1LDMzMDkyLDMzMTIxLDMzMzA5LDMzMzUzLDMzMzQ4LDMzMzQ0LDMzMzQ2LDMzMzQ5LDM0MDMzLDMzODU1LDMzODc4LDMzOTEwLDMzOTEzLDMzOTM1LDMzOTMzLDMzODkzLDMzODczLDMzODU2LDMzOTI2LDMzODk1LDMzODQwLDMzODY5LDMzOTE3LDMzODgyLDMzODgxLDMzOTA4LDMzOTA3LDMzODg1LDM0MDU1LDMzODg2LDMzODQ3LDMzODUwLDMzODQ0LDMzOTE0LDMzODU5LDMzOTEyLDMzODQyLDMzODYxLDMzODMzLDMzNzUzLDMzODY3LDMzODM5LDMzODU4LDMzODM3LDMzODg3LDMzOTA0LDMzODQ5LDMzODcwLDMzODY4LDMzODc0LDMzOTAzLDMzOTg5LDMzOTM0LDMzODUxLDMzODYzLDMzODQ2LDMzODQzLDMzODk2LDMzOTE4LDMzODYwLDMzODM1LDMzODg4LDMzODc2LDMzOTAyLDMzODcyLDM0NTcxLDM0NTY0LDM0NTUxLDM0NTcyLDM0NTU0LDM0NTE4LDM0NTQ5LDM0NjM3LDM0NTUyLDM0NTc0LDM0NTY5LDM0NTYxLDM0NTUwLDM0NTczLDM0NTY1LDM1MDMwLDM1MDE5LDM1MDIxLDM1MDIyLDM1MDM4LDM1MDM1LDM1MDM0LDM1MDIwLDM1MDI0LDM1MjA1LDM1MjI3LDM1Mjk1LDM1MzAxLDM1MzAwLDM1Mjk3LDM1Mjk2LDM1Mjk4LDM1MjkyLDM1MzAyLDM1NDQ2LDM1NDYyLDM1NDU1LDM1NDI1LDM1MzkxLDM1NDQ3LDM1NDU4LDM1NDYwLDM1NDQ1LDM1NDU5LDM1NDU3LDM1NDQ0LDM1NDUwLDM1OTAwLDM1OTE1LDM1OTE0LDM1OTQxLDM1OTQwLDM1OTQyLDM1OTc0LDM1OTcyLDM1OTczLDM2MDQ0LDM2MjAwLDM2MjAxLDM2MjQxLDM2MjM2LDM2MjM4LDM2MjM5LDM2MjM3LDM2MjQzLDM2MjQ0LDM2MjQwLDM2MjQyLDM2MzM2LDM2MzIwLDM2MzMyLDM2MzM3LDM2MzM0LDM2MzA0LDM2MzI5LDM2MzIzLDM2MzIyLDM2MzI3LDM2MzM4LDM2MzMxLDM2MzQwLDM2NjE0LDM2NjA3LDM2NjA5LDM2NjA4LDM2NjEzLDM2NjE1LDM2NjE2LDM2NjEwLDM2NjE5LDM2OTQ2LDM2OTI3LDM2OTMyLDM2OTM3LDM2OTI1LDM3MTM2LDM3MTMzLDM3MTM1LDM3MTM3LDM3MTQyLDM3MTQwLDM3MTMxLDM3MTM0LDM3MjMwLDM3MjMxLDM3NDQ4LDM3NDU4LDM3NDI0LDM3NDM0LDM3NDc4LDM3NDI3LDM3NDc3LDM3NDcwLDM3NTA3LDM3NDIyLDM3NDUwLDM3NDQ2LDM3NDg1LDM3NDg0LDM3NDU1LDM3NDcyLDM3NDc5LDM3NDg3LDM3NDMwLDM3NDczLDM3NDg4LDM3NDI1LDM3NDYwLDM3NDc1LDM3NDU2LDM3NDkwLDM3NDU0LDM3NDU5LDM3NDUyLDM3NDYyLDM3NDI2LDM4MzAzLDM4MzAwLDM4MzAyLDM4Mjk5LDM4NTQ2LDM4NTQ3LDM4NTQ1LDM4NTUxLDM4NjA2LDM4NjUwLDM4NjUzLDM4NjQ4LDM4NjQ1LDM4NzcxLDM4Nzc1LDM4Nzc2LDM4NzcwLDM4OTI3LDM4OTI1LDM4OTI2LDM5MDg0LDM5MTU4LDM5MTYxLDM5MzQzLDM5MzQ2LDM5MzQ0LDM5MzQ5LDM5NTk3LDM5NTk1LDM5NzcxLDQwMTcwLDQwMTczLDQwMTY3LDQwNTc2LDQwNzAxLDIwNzEwLDIwNjkyLDIwNjk1LDIwNzEyLDIwNzIzLDIwNjk5LDIwNzE0LDIwNzAxLDIwNzA4LDIwNjkxLDIwNzE2LDIwNzIwLDIwNzE5LDIwNzA3LDIwNzA0LDIwOTUyLDIxMTIwLDIxMTIxLDIxMjI1LDIxMjI3LDIxMjk2LDIxNDIwLDIyMDU1LDIyMDM3LDIyMDI4LDIyMDM0LDIyMDEyLDIyMDMxLDIyMDQ0LDIyMDE3LDIyMDM1LDIyMDE4LDIyMDEwLDIyMDQ1LDIyMDIwLDIyMDE1LDIyMDA5LDIyNjY1LDIyNjUyLDIyNjcyLDIyNjgwLDIyNjYyLDIyNjU3LDIyNjU1LDIyNjQ0LDIyNjY3LDIyNjUwLDIyNjYzLDIyNjczLDIyNjcwLDIyNjQ2LDIyNjU4LDIyNjY0LDIyNjUxLDIyNjc2LDIyNjcxLDIyNzgyLDIyODkxLDIzMjYwLDIzMjc4LDIzMjY5LDIzMjUzLDIzMjc0LDIzMjU4LDIzMjc3LDIzMjc1LDIzMjgzLDIzMjY2LDIzMjY0LDIzMjU5LDIzMjc2LDIzMjYyLDIzMjYxLDIzMjU3LDIzMjcyLDIzMjYzLDIzNDE1LDIzNTIwLDIzNTIzLDIzNjUxLDIzOTM4LDIzOTM2LDIzOTMzLDIzOTQyLDIzOTMwLDIzOTM3LDIzOTI3LDIzOTQ2LDIzOTQ1LDIzOTQ0LDIzOTM0LDIzOTMyLDIzOTQ5LDIzOTI5LDIzOTM1LDI0MTUyLDI0MTUzLDI0MTQ3LDI0MjgwLDI0MjczLDI0Mjc5LDI0MjcwLDI0Mjg0LDI0Mjc3LDI0MjgxLDI0Mjc0LDI0Mjc2LDI0Mzg4LDI0Mzg3LDI0NDMxLDI0NTAyLDI0ODc2LDI0ODcyLDI0ODk3LDI0OTI2LDI0OTQ1LDI0OTQ3LDI0OTE0LDI0OTE1LDI0OTQ2LDI0OTQwLDI0OTYwLDI0OTQ4LDI0OTE2LDI0OTU0LDI0OTIzLDI0OTMzLDI0ODkxLDI0OTM4LDI0OTI5LDI0OTE4LDI1MTI5LDI1MTI3LDI1MTMxLDI1NjQzLDI1Njc3LDI1NjkxLDI1NjkzLDI1NzE2LDI1NzE4LDI1NzE0LDI1NzE1LDI1NzI1LDI1NzE3LDI1NzAyLDI1NzY2LDI1Njc4LDI1NzMwLDI1Njk0LDI1NjkyLDI1Njc1LDI1NjgzLDI1Njk2LDI1NjgwLDI1NzI3LDI1NjYzLDI1NzA4LDI1NzA3LDI1Njg5LDI1NzAxLDI1NzE5LDI1OTcxLDI2MDE2LDI2MjczLDI2MjcyLDI2MjcxLDI2MzczLDI2MzcyLDI2NDAyLDI3MDU3LDI3MDYyLDI3MDgxLDI3MDQwLDI3MDg2LDI3MDMwLDI3MDU2LDI3MDUyLDI3MDY4LDI3MDI1LDI3MDMzLDI3MDIyLDI3MDQ3LDI3MDIxLDI3MDQ5LDI3MDcwLDI3MDU1LDI3MDcxLDI3MDc2LDI3MDY5LDI3MDQ0LDI3MDkyLDI3MDY1LDI3MDgyLDI3MDM0LDI3MDg3LDI3MDU5LDI3MDI3LDI3MDUwLDI3MDQxLDI3MDM4LDI3MDk3LDI3MDMxLDI3MDI0LDI3MDc0LDI3MDYxLDI3MDQ1LDI3MDc4LDI3NDY2LDI3NDY5LDI3NDY3LDI3NTUwLDI3NTUxLDI3NTUyLDI3NTg3LDI3NTg4LDI3NjQ2LDI4MzY2LDI4NDA1LDI4NDAxLDI4NDE5LDI4NDUzLDI4NDA4LDI4NDcxLDI4NDExLDI4NDYyLDI4NDI1LDI4NDk0LDI4NDQxLDI4NDQyLDI4NDU1LDI4NDQwLDI4NDc1LDI4NDM0LDI4Mzk3LDI4NDI2LDI4NDcwLDI4NTMxLDI4NDA5LDI4Mzk4LDI4NDYxLDI4NDgwLDI4NDY0LDI4NDc2LDI4NDY5LDI4Mzk1LDI4NDIzLDI4NDMwLDI4NDgzLDI4NDIxLDI4NDEzLDI4NDA2LDI4NDczLDI4NDQ0LDI4NDEyLDI4NDc0LDI4NDQ3LDI4NDI5LDI4NDQ2LDI4NDI0LDI4NDQ5LDI5MDYzLDI5MDcyLDI5MDY1LDI5MDU2LDI5MDYxLDI5MDU4LDI5MDcxLDI5MDUxLDI5MDYyLDI5MDU3LDI5MDc5LDI5MjUyLDI5MjY3LDI5MzM1LDI5MzMzLDI5MzMxLDI5NTA3LDI5NTE3LDI5NTIxLDI5NTE2LDI5Nzk0LDI5ODExLDI5ODA5LDI5ODEzLDI5ODEwLDI5Nzk5LDI5ODA2LDI5OTUyLDI5OTU0LDI5OTU1LDMwMDc3LDMwMDk2LDMwMjMwLDMwMjE2LDMwMjIwLDMwMjI5LDMwMjI1LDMwMjE4LDMwMjI4LDMwMzkyLDMwNTkzLDMwNTg4LDMwNTk3LDMwNTk0LDMwNTc0LDMwNTkyLDMwNTc1LDMwNTkwLDMwNTk1LDMwODk4LDMwODkwLDMwOTAwLDMwODkzLDMwODg4LDMwODQ2LDMwODkxLDMwODc4LDMwODg1LDMwODgwLDMwODkyLDMwODgyLDMwODg0LDMxMTI4LDMxMTE0LDMxMTE1LDMxMTI2LDMxMTI1LDMxMTI0LDMxMTIzLDMxMTI3LDMxMTEyLDMxMTIyLDMxMTIwLDMxMjc1LDMxMzA2LDMxMjgwLDMxMjc5LDMxMjcyLDMxMjcwLDMxNDAwLDMxNDAzLDMxNDA0LDMxNDcwLDMxNjI0LDMxNjQ0LDMxNjI2LDMxNjMzLDMxNjMyLDMxNjM4LDMxNjI5LDMxNjI4LDMxNjQzLDMxNjMwLDMxNjIxLDMxNjQwLDIxMTI0LDMxNjQxLDMxNjUyLDMxNjE4LDMxOTMxLDMxOTM1LDMxOTMyLDMxOTMwLDMyMTY3LDMyMTgzLDMyMTk0LDMyMTYzLDMyMTcwLDMyMTkzLDMyMTkyLDMyMTk3LDMyMTU3LDMyMjA2LDMyMTk2LDMyMTk4LDMyMjAzLDMyMjA0LDMyMTc1LDMyMTg1LDMyMTUwLDMyMTg4LDMyMTU5LDMyMTY2LDMyMTc0LDMyMTY5LDMyMTYxLDMyMjAxLDMyNjI3LDMyNzM4LDMyNzM5LDMyNzQxLDMyNzM0LDMyODA0LDMyODYxLDMyODYwLDMzMTYxLDMzMTU4LDMzMTU1LDMzMTU5LDMzMTY1LDMzMTY0LDMzMTYzLDMzMzAxLDMzOTQzLDMzOTU2LDMzOTUzLDMzOTUxLDMzOTc4LDMzOTk4LDMzOTg2LDMzOTY0LDMzOTY2LDMzOTYzLDMzOTc3LDMzOTcyLDMzOTg1LDMzOTk3LDMzOTYyLDMzOTQ2LDMzOTY5LDM0MDAwLDMzOTQ5LDMzOTU5LDMzOTc5LDMzOTU0LDMzOTQwLDMzOTkxLDMzOTk2LDMzOTQ3LDMzOTYxLDMzOTY3LDMzOTYwLDM0MDA2LDMzOTQ0LDMzOTc0LDMzOTk5LDMzOTUyLDM0MDA3LDM0MDA0LDM0MDAyLDM0MDExLDMzOTY4LDMzOTM3LDM0NDAxLDM0NjExLDM0NTk1LDM0NjAwLDM0NjY3LDM0NjI0LDM0NjA2LDM0NTkwLDM0NTkzLDM0NTg1LDM0NTg3LDM0NjI3LDM0NjA0LDM0NjI1LDM0NjIyLDM0NjMwLDM0NTkyLDM0NjEwLDM0NjAyLDM0NjA1LDM0NjIwLDM0NTc4LDM0NjE4LDM0NjA5LDM0NjEzLDM0NjI2LDM0NTk4LDM0NTk5LDM0NjE2LDM0NTk2LDM0NTg2LDM0NjA4LDM0NTc3LDM1MDYzLDM1MDQ3LDM1MDU3LDM1MDU4LDM1MDY2LDM1MDcwLDM1MDU0LDM1MDY4LDM1MDYyLDM1MDY3LDM1MDU2LDM1MDUyLDM1MDUxLDM1MjI5LDM1MjMzLDM1MjMxLDM1MjMwLDM1MzA1LDM1MzA3LDM1MzA0LDM1NDk5LDM1NDgxLDM1NDY3LDM1NDc0LDM1NDcxLDM1NDc4LDM1OTAxLDM1OTQ0LDM1OTQ1LDM2MDUzLDM2MDQ3LDM2MDU1LDM2MjQ2LDM2MzYxLDM2MzU0LDM2MzUxLDM2MzY1LDM2MzQ5LDM2MzYyLDM2MzU1LDM2MzU5LDM2MzU4LDM2MzU3LDM2MzUwLDM2MzUyLDM2MzU2LDM2NjI0LDM2NjI1LDM2NjIyLDM2NjIxLDM3MTU1LDM3MTQ4LDM3MTUyLDM3MTU0LDM3MTUxLDM3MTQ5LDM3MTQ2LDM3MTU2LDM3MTUzLDM3MTQ3LDM3MjQyLDM3MjM0LDM3MjQxLDM3MjM1LDM3NTQxLDM3NTQwLDM3NDk0LDM3NTMxLDM3NDk4LDM3NTM2LDM3NTI0LDM3NTQ2LDM3NTE3LDM3NTQyLDM3NTMwLDM3NTQ3LDM3NDk3LDM3NTI3LDM3NTAzLDM3NTM5LDM3NjE0LDM3NTE4LDM3NTA2LDM3NTI1LDM3NTM4LDM3NTAxLDM3NTEyLDM3NTM3LDM3NTE0LDM3NTEwLDM3NTE2LDM3NTI5LDM3NTQzLDM3NTAyLDM3NTExLDM3NTQ1LDM3NTMzLDM3NTE1LDM3NDIxLDM4NTU4LDM4NTYxLDM4NjU1LDM4NzQ0LDM4NzgxLDM4Nzc4LDM4NzgyLDM4Nzg3LDM4Nzg0LDM4Nzg2LDM4Nzc5LDM4Nzg4LDM4Nzg1LDM4NzgzLDM4ODYyLDM4ODYxLDM4OTM0LDM5MDg1LDM5MDg2LDM5MTcwLDM5MTY4LDM5MTc1LDM5MzI1LDM5MzI0LDM5MzYzLDM5MzUzLDM5MzU1LDM5MzU0LDM5MzYyLDM5MzU3LDM5MzY3LDM5NjAxLDM5NjUxLDM5NjU1LDM5NzQyLDM5NzQzLDM5Nzc2LDM5Nzc3LDM5Nzc1LDQwMTc3LDQwMTc4LDQwMTgxLDQwNjE1LDIwNzM1LDIwNzM5LDIwNzg0LDIwNzI4LDIwNzQyLDIwNzQzLDIwNzI2LDIwNzM0LDIwNzQ3LDIwNzQ4LDIwNzMzLDIwNzQ2LDIxMTMxLDIxMTMyLDIxMjMzLDIxMjMxLDIyMDg4LDIyMDgyLDIyMDkyLDIyMDY5LDIyMDgxLDIyMDkwLDIyMDg5LDIyMDg2LDIyMTA0LDIyMTA2LDIyMDgwLDIyMDY3LDIyMDc3LDIyMDYwLDIyMDc4LDIyMDcyLDIyMDU4LDIyMDc0LDIyMjk4LDIyNjk5LDIyNjg1LDIyNzA1LDIyNjg4LDIyNjkxLDIyNzAzLDIyNzAwLDIyNjkzLDIyNjg5LDIyNzgzLDIzMjk1LDIzMjg0LDIzMjkzLDIzMjg3LDIzMjg2LDIzMjk5LDIzMjg4LDIzMjk4LDIzMjg5LDIzMjk3LDIzMzAzLDIzMzAxLDIzMzExLDIzNjU1LDIzOTYxLDIzOTU5LDIzOTY3LDIzOTU0LDIzOTcwLDIzOTU1LDIzOTU3LDIzOTY4LDIzOTY0LDIzOTY5LDIzOTYyLDIzOTY2LDI0MTY5LDI0MTU3LDI0MTYwLDI0MTU2LDMyMjQzLDI0MjgzLDI0Mjg2LDI0Mjg5LDI0MzkzLDI0NDk4LDI0OTcxLDI0OTYzLDI0OTUzLDI1MDA5LDI1MDA4LDI0OTk0LDI0OTY5LDI0OTg3LDI0OTc5LDI1MDA3LDI1MDA1LDI0OTkxLDI0OTc4LDI1MDAyLDI0OTkzLDI0OTczLDI0OTM0LDI1MDExLDI1MTMzLDI1NzEwLDI1NzEyLDI1NzUwLDI1NzYwLDI1NzMzLDI1NzUxLDI1NzU2LDI1NzQzLDI1NzM5LDI1NzM4LDI1NzQwLDI1NzYzLDI1NzU5LDI1NzA0LDI1Nzc3LDI1NzUyLDI1OTc0LDI1OTc4LDI1OTc3LDI1OTc5LDI2MDM0LDI2MDM1LDI2MjkzLDI2Mjg4LDI2MjgxLDI2MjkwLDI2Mjk1LDI2MjgyLDI2Mjg3LDI3MTM2LDI3MTQyLDI3MTU5LDI3MTA5LDI3MTI4LDI3MTU3LDI3MTIxLDI3MTA4LDI3MTY4LDI3MTM1LDI3MTE2LDI3MTA2LDI3MTYzLDI3MTY1LDI3MTM0LDI3MTc1LDI3MTIyLDI3MTE4LDI3MTU2LDI3MTI3LDI3MTExLDI3MjAwLDI3MTQ0LDI3MTEwLDI3MTMxLDI3MTQ5LDI3MTMyLDI3MTE1LDI3MTQ1LDI3MTQwLDI3MTYwLDI3MTczLDI3MTUxLDI3MTI2LDI3MTc0LDI3MTQzLDI3MTI0LDI3MTU4LDI3NDczLDI3NTU3LDI3NTU1LDI3NTU0LDI3NTU4LDI3NjQ5LDI3NjQ4LDI3NjQ3LDI3NjUwLDI4NDgxLDI4NDU0LDI4NTQyLDI4NTUxLDI4NjE0LDI4NTYyLDI4NTU3LDI4NTUzLDI4NTU2LDI4NTE0LDI4NDk1LDI4NTQ5LDI4NTA2LDI4NTY2LDI4NTM0LDI4NTI0LDI4NTQ2LDI4NTAxLDI4NTMwLDI4NDk4LDI4NDk2LDI4NTAzLDI4NTY0LDI4NTYzLDI4NTA5LDI4NDE2LDI4NTEzLDI4NTIzLDI4NTQxLDI4NTE5LDI4NTYwLDI4NDk5LDI4NTU1LDI4NTIxLDI4NTQzLDI4NTY1LDI4NTE1LDI4NTM1LDI4NTIyLDI4NTM5LDI5MTA2LDI5MTAzLDI5MDgzLDI5MTA0LDI5MDg4LDI5MDgyLDI5MDk3LDI5MTA5LDI5MDg1LDI5MDkzLDI5MDg2LDI5MDkyLDI5MDg5LDI5MDk4LDI5MDg0LDI5MDk1LDI5MTA3LDI5MzM2LDI5MzM4LDI5NTI4LDI5NTIyLDI5NTM0LDI5NTM1LDI5NTM2LDI5NTMzLDI5NTMxLDI5NTM3LDI5NTMwLDI5NTI5LDI5NTM4LDI5ODMxLDI5ODMzLDI5ODM0LDI5ODMwLDI5ODI1LDI5ODIxLDI5ODI5LDI5ODMyLDI5ODIwLDI5ODE3LDI5OTYwLDI5OTU5LDMwMDc4LDMwMjQ1LDMwMjM4LDMwMjMzLDMwMjM3LDMwMjM2LDMwMjQzLDMwMjM0LDMwMjQ4LDMwMjM1LDMwMzY0LDMwMzY1LDMwMzY2LDMwMzYzLDMwNjA1LDMwNjA3LDMwNjAxLDMwNjAwLDMwOTI1LDMwOTA3LDMwOTI3LDMwOTI0LDMwOTI5LDMwOTI2LDMwOTMyLDMwOTIwLDMwOTE1LDMwOTE2LDMwOTIxLDMxMTMwLDMxMTM3LDMxMTM2LDMxMTMyLDMxMTM4LDMxMTMxLDI3NTEwLDMxMjg5LDMxNDEwLDMxNDEyLDMxNDExLDMxNjcxLDMxNjkxLDMxNjc4LDMxNjYwLDMxNjk0LDMxNjYzLDMxNjczLDMxNjkwLDMxNjY5LDMxOTQxLDMxOTQ0LDMxOTQ4LDMxOTQ3LDMyMjQ3LDMyMjE5LDMyMjM0LDMyMjMxLDMyMjE1LDMyMjI1LDMyMjU5LDMyMjUwLDMyMjMwLDMyMjQ2LDMyMjQxLDMyMjQwLDMyMjM4LDMyMjIzLDMyNjMwLDMyNjg0LDMyNjg4LDMyNjg1LDMyNzQ5LDMyNzQ3LDMyNzQ2LDMyNzQ4LDMyNzQyLDMyNzQ0LDMyODY4LDMyODcxLDMzMTg3LDMzMTgzLDMzMTgyLDMzMTczLDMzMTg2LDMzMTc3LDMzMTc1LDMzMzAyLDMzMzU5LDMzMzYzLDMzMzYyLDMzMzYwLDMzMzU4LDMzMzYxLDM0MDg0LDM0MTA3LDM0MDYzLDM0MDQ4LDM0MDg5LDM0MDYyLDM0MDU3LDM0MDYxLDM0MDc5LDM0MDU4LDM0MDg3LDM0MDc2LDM0MDQzLDM0MDkxLDM0MDQyLDM0MDU2LDM0MDYwLDM0MDM2LDM0MDkwLDM0MDM0LDM0MDY5LDM0MDM5LDM0MDI3LDM0MDM1LDM0MDQ0LDM0MDY2LDM0MDI2LDM0MDI1LDM0MDcwLDM0MDQ2LDM0MDg4LDM0MDc3LDM0MDk0LDM0MDUwLDM0MDQ1LDM0MDc4LDM0MDM4LDM0MDk3LDM0MDg2LDM0MDIzLDM0MDI0LDM0MDMyLDM0MDMxLDM0MDQxLDM0MDcyLDM0MDgwLDM0MDk2LDM0MDU5LDM0MDczLDM0MDk1LDM0NDAyLDM0NjQ2LDM0NjU5LDM0NjYwLDM0Njc5LDM0Nzg1LDM0Njc1LDM0NjQ4LDM0NjQ0LDM0NjUxLDM0NjQyLDM0NjU3LDM0NjUwLDM0NjQxLDM0NjU0LDM0NjY5LDM0NjY2LDM0NjQwLDM0NjM4LDM0NjU1LDM0NjUzLDM0NjcxLDM0NjY4LDM0NjgyLDM0NjcwLDM0NjUyLDM0NjYxLDM0NjM5LDM0NjgzLDM0Njc3LDM0NjU4LDM0NjYzLDM0NjY1LDM0OTA2LDM1MDc3LDM1MDg0LDM1MDkyLDM1MDgzLDM1MDk1LDM1MDk2LDM1MDk3LDM1MDc4LDM1MDk0LDM1MDg5LDM1MDg2LDM1MDgxLDM1MjM0LDM1MjM2LDM1MjM1LDM1MzA5LDM1MzEyLDM1MzA4LDM1NTM1LDM1NTI2LDM1NTEyLDM1NTM5LDM1NTM3LDM1NTQwLDM1NTQxLDM1NTE1LDM1NTQzLDM1NTE4LDM1NTIwLDM1NTI1LDM1NTQ0LDM1NTIzLDM1NTE0LDM1NTE3LDM1NTQ1LDM1OTAyLDM1OTE3LDM1OTgzLDM2MDY5LDM2MDYzLDM2MDU3LDM2MDcyLDM2MDU4LDM2MDYxLDM2MDcxLDM2MjU2LDM2MjUyLDM2MjU3LDM2MjUxLDM2Mzg0LDM2Mzg3LDM2Mzg5LDM2Mzg4LDM2Mzk4LDM2MzczLDM2Mzc5LDM2Mzc0LDM2MzY5LDM2Mzc3LDM2MzkwLDM2MzkxLDM2MzcyLDM2MzcwLDM2Mzc2LDM2MzcxLDM2MzgwLDM2Mzc1LDM2Mzc4LDM2NjUyLDM2NjQ0LDM2NjMyLDM2NjM0LDM2NjQwLDM2NjQzLDM2NjMwLDM2NjMxLDM2OTc5LDM2OTc2LDM2OTc1LDM2OTY3LDM2OTcxLDM3MTY3LDM3MTYzLDM3MTYxLDM3MTYyLDM3MTcwLDM3MTU4LDM3MTY2LDM3MjUzLDM3MjU0LDM3MjU4LDM3MjQ5LDM3MjUwLDM3MjUyLDM3MjQ4LDM3NTg0LDM3NTcxLDM3NTcyLDM3NTY4LDM3NTkzLDM3NTU4LDM3NTgzLDM3NjE3LDM3NTk5LDM3NTkyLDM3NjA5LDM3NTkxLDM3NTk3LDM3NTgwLDM3NjE1LDM3NTcwLDM3NjA4LDM3NTc4LDM3NTc2LDM3NTgyLDM3NjA2LDM3NTgxLDM3NTg5LDM3NTc3LDM3NjAwLDM3NTk4LDM3NjA3LDM3NTg1LDM3NTg3LDM3NTU3LDM3NjAxLDM3NTc0LDM3NTU2LDM4MjY4LDM4MzE2LDM4MzE1LDM4MzE4LDM4MzIwLDM4NTY0LDM4NTYyLDM4NjExLDM4NjYxLDM4NjY0LDM4NjU4LDM4NzQ2LDM4Nzk0LDM4Nzk4LDM4NzkyLDM4ODY0LDM4ODYzLDM4OTQyLDM4OTQxLDM4OTUwLDM4OTUzLDM4OTUyLDM4OTQ0LDM4OTM5LDM4OTUxLDM5MDkwLDM5MTc2LDM5MTYyLDM5MTg1LDM5MTg4LDM5MTkwLDM5MTkxLDM5MTg5LDM5Mzg4LDM5MzczLDM5Mzc1LDM5Mzc5LDM5MzgwLDM5Mzc0LDM5MzY5LDM5MzgyLDM5Mzg0LDM5MzcxLDM5MzgzLDM5MzcyLDM5NjAzLDM5NjYwLDM5NjU5LDM5NjY3LDM5NjY2LDM5NjY1LDM5NzUwLDM5NzQ3LDM5NzgzLDM5Nzk2LDM5NzkzLDM5NzgyLDM5Nzk4LDM5Nzk3LDM5NzkyLDM5Nzg0LDM5NzgwLDM5Nzg4LDQwMTg4LDQwMTg2LDQwMTg5LDQwMTkxLDQwMTgzLDQwMTk5LDQwMTkyLDQwMTg1LDQwMTg3LDQwMjAwLDQwMTk3LDQwMTk2LDQwNTc5LDQwNjU5LDQwNzE5LDQwNzIwLDIwNzY0LDIwNzU1LDIwNzU5LDIwNzYyLDIwNzUzLDIwOTU4LDIxMzAwLDIxNDczLDIyMTI4LDIyMTEyLDIyMTI2LDIyMTMxLDIyMTE4LDIyMTE1LDIyMTI1LDIyMTMwLDIyMTEwLDIyMTM1LDIyMzAwLDIyMjk5LDIyNzI4LDIyNzE3LDIyNzI5LDIyNzE5LDIyNzE0LDIyNzIyLDIyNzE2LDIyNzI2LDIzMzE5LDIzMzIxLDIzMzIzLDIzMzI5LDIzMzE2LDIzMzE1LDIzMzEyLDIzMzE4LDIzMzM2LDIzMzIyLDIzMzI4LDIzMzI2LDIzNTM1LDIzOTgwLDIzOTg1LDIzOTc3LDIzOTc1LDIzOTg5LDIzOTg0LDIzOTgyLDIzOTc4LDIzOTc2LDIzOTg2LDIzOTgxLDIzOTgzLDIzOTg4LDI0MTY3LDI0MTY4LDI0MTY2LDI0MTc1LDI0Mjk3LDI0Mjk1LDI0Mjk0LDI0Mjk2LDI0MjkzLDI0Mzk1LDI0NTA4LDI0OTg5LDI1MDAwLDI0OTgyLDI1MDI5LDI1MDEyLDI1MDMwLDI1MDI1LDI1MDM2LDI1MDE4LDI1MDIzLDI1MDE2LDI0OTcyLDI1ODE1LDI1ODE0LDI1ODA4LDI1ODA3LDI1ODAxLDI1Nzg5LDI1NzM3LDI1Nzk1LDI1ODE5LDI1ODQzLDI1ODE3LDI1OTA3LDI1OTgzLDI1OTgwLDI2MDE4LDI2MzEyLDI2MzAyLDI2MzA0LDI2MzE0LDI2MzE1LDI2MzE5LDI2MzAxLDI2Mjk5LDI2Mjk4LDI2MzE2LDI2NDAzLDI3MTg4LDI3MjM4LDI3MjA5LDI3MjM5LDI3MTg2LDI3MjQwLDI3MTk4LDI3MjI5LDI3MjQ1LDI3MjU0LDI3MjI3LDI3MjE3LDI3MTc2LDI3MjI2LDI3MTk1LDI3MTk5LDI3MjAxLDI3MjQyLDI3MjM2LDI3MjE2LDI3MjE1LDI3MjIwLDI3MjQ3LDI3MjQxLDI3MjMyLDI3MTk2LDI3MjMwLDI3MjIyLDI3MjIxLDI3MjEzLDI3MjE0LDI3MjA2LDI3NDc3LDI3NDc2LDI3NDc4LDI3NTU5LDI3NTYyLDI3NTYzLDI3NTkyLDI3NTkxLDI3NjUyLDI3NjUxLDI3NjU0LDI4NTg5LDI4NjE5LDI4NTc5LDI4NjE1LDI4NjA0LDI4NjIyLDI4NjE2LDI4NTEwLDI4NjEyLDI4NjA1LDI4NTc0LDI4NjE4LDI4NTg0LDI4Njc2LDI4NTgxLDI4NTkwLDI4NjAyLDI4NTg4LDI4NTg2LDI4NjIzLDI4NjA3LDI4NjAwLDI4NTc4LDI4NjE3LDI4NTg3LDI4NjIxLDI4NTkxLDI4NTk0LDI4NTkyLDI5MTI1LDI5MTIyLDI5MTE5LDI5MTEyLDI5MTQyLDI5MTIwLDI5MTIxLDI5MTMxLDI5MTQwLDI5MTMwLDI5MTI3LDI5MTM1LDI5MTE3LDI5MTQ0LDI5MTE2LDI5MTI2LDI5MTQ2LDI5MTQ3LDI5MzQxLDI5MzQyLDI5NTQ1LDI5NTQyLDI5NTQzLDI5NTQ4LDI5NTQxLDI5NTQ3LDI5NTQ2LDI5ODIzLDI5ODUwLDI5ODU2LDI5ODQ0LDI5ODQyLDI5ODQ1LDI5ODU3LDI5OTYzLDMwMDgwLDMwMjU1LDMwMjUzLDMwMjU3LDMwMjY5LDMwMjU5LDMwMjY4LDMwMjYxLDMwMjU4LDMwMjU2LDMwMzk1LDMwNDM4LDMwNjE4LDMwNjIxLDMwNjI1LDMwNjIwLDMwNjE5LDMwNjI2LDMwNjI3LDMwNjEzLDMwNjE3LDMwNjE1LDMwOTQxLDMwOTUzLDMwOTQ5LDMwOTU0LDMwOTQyLDMwOTQ3LDMwOTM5LDMwOTQ1LDMwOTQ2LDMwOTU3LDMwOTQzLDMwOTQ0LDMxMTQwLDMxMzAwLDMxMzA0LDMxMzAzLDMxNDE0LDMxNDE2LDMxNDEzLDMxNDA5LDMxNDE1LDMxNzEwLDMxNzE1LDMxNzE5LDMxNzA5LDMxNzAxLDMxNzE3LDMxNzA2LDMxNzIwLDMxNzM3LDMxNzAwLDMxNzIyLDMxNzE0LDMxNzA4LDMxNzIzLDMxNzA0LDMxNzExLDMxOTU0LDMxOTU2LDMxOTU5LDMxOTUyLDMxOTUzLDMyMjc0LDMyMjg5LDMyMjc5LDMyMjY4LDMyMjg3LDMyMjg4LDMyMjc1LDMyMjcwLDMyMjg0LDMyMjc3LDMyMjgyLDMyMjkwLDMyMjY3LDMyMjcxLDMyMjc4LDMyMjY5LDMyMjc2LDMyMjkzLDMyMjkyLDMyNTc5LDMyNjM1LDMyNjM2LDMyNjM0LDMyNjg5LDMyNzUxLDMyODEwLDMyODA5LDMyODc2LDMzMjAxLDMzMTkwLDMzMTk4LDMzMjA5LDMzMjA1LDMzMTk1LDMzMjAwLDMzMTk2LDMzMjA0LDMzMjAyLDMzMjA3LDMzMTkxLDMzMjY2LDMzMzY1LDMzMzY2LDMzMzY3LDM0MTM0LDM0MTE3LDM0MTU1LDM0MTI1LDM0MTMxLDM0MTQ1LDM0MTM2LDM0MTEyLDM0MTE4LDM0MTQ4LDM0MTEzLDM0MTQ2LDM0MTE2LDM0MTI5LDM0MTE5LDM0MTQ3LDM0MTEwLDM0MTM5LDM0MTYxLDM0MTI2LDM0MTU4LDM0MTY1LDM0MTMzLDM0MTUxLDM0MTQ0LDM0MTg4LDM0MTUwLDM0MTQxLDM0MTMyLDM0MTQ5LDM0MTU2LDM0NDAzLDM0NDA1LDM0NDA0LDM0NzE1LDM0NzAzLDM0NzExLDM0NzA3LDM0NzA2LDM0Njk2LDM0Njg5LDM0NzEwLDM0NzEyLDM0NjgxLDM0Njk1LDM0NzIzLDM0NjkzLDM0NzA0LDM0NzA1LDM0NzE3LDM0NjkyLDM0NzA4LDM0NzE2LDM0NzE0LDM0Njk3LDM1MTAyLDM1MTEwLDM1MTIwLDM1MTE3LDM1MTE4LDM1MTExLDM1MTIxLDM1MTA2LDM1MTEzLDM1MTA3LDM1MTE5LDM1MTE2LDM1MTAzLDM1MzEzLDM1NTUyLDM1NTU0LDM1NTcwLDM1NTcyLDM1NTczLDM1NTQ5LDM1NjA0LDM1NTU2LDM1NTUxLDM1NTY4LDM1NTI4LDM1NTUwLDM1NTUzLDM1NTYwLDM1NTgzLDM1NTY3LDM1NTc5LDM1OTg1LDM1OTg2LDM1OTg0LDM2MDg1LDM2MDc4LDM2MDgxLDM2MDgwLDM2MDgzLDM2MjA0LDM2MjA2LDM2MjYxLDM2MjYzLDM2NDAzLDM2NDE0LDM2NDA4LDM2NDE2LDM2NDIxLDM2NDA2LDM2NDEyLDM2NDEzLDM2NDE3LDM2NDAwLDM2NDE1LDM2NTQxLDM2NjYyLDM2NjU0LDM2NjYxLDM2NjU4LDM2NjY1LDM2NjYzLDM2NjYwLDM2OTgyLDM2OTg1LDM2OTg3LDM2OTk4LDM3MTE0LDM3MTcxLDM3MTczLDM3MTc0LDM3MjY3LDM3MjY0LDM3MjY1LDM3MjYxLDM3MjYzLDM3NjcxLDM3NjYyLDM3NjQwLDM3NjYzLDM3NjM4LDM3NjQ3LDM3NzU0LDM3Njg4LDM3NjkyLDM3NjU5LDM3NjY3LDM3NjUwLDM3NjMzLDM3NzAyLDM3Njc3LDM3NjQ2LDM3NjQ1LDM3NTc5LDM3NjYxLDM3NjI2LDM3NjY5LDM3NjUxLDM3NjI1LDM3NjIzLDM3Njg0LDM3NjM0LDM3NjY4LDM3NjMxLDM3NjczLDM3Njg5LDM3Njg1LDM3Njc0LDM3NjUyLDM3NjQ0LDM3NjQzLDM3NjMwLDM3NjQxLDM3NjMyLDM3NjI3LDM3NjU0LDM4MzMyLDM4MzQ5LDM4MzM0LDM4MzI5LDM4MzMwLDM4MzI2LDM4MzM1LDM4MzI1LDM4MzMzLDM4NTY5LDM4NjEyLDM4NjY3LDM4Njc0LDM4NjcyLDM4ODA5LDM4ODA3LDM4ODA0LDM4ODk2LDM4OTA0LDM4OTY1LDM4OTU5LDM4OTYyLDM5MjA0LDM5MTk5LDM5MjA3LDM5MjA5LDM5MzI2LDM5NDA2LDM5NDA0LDM5Mzk3LDM5Mzk2LDM5NDA4LDM5Mzk1LDM5NDAyLDM5NDAxLDM5Mzk5LDM5NjA5LDM5NjE1LDM5NjA0LDM5NjExLDM5NjcwLDM5Njc0LDM5NjczLDM5NjcxLDM5NzMxLDM5ODA4LDM5ODEzLDM5ODE1LDM5ODA0LDM5ODA2LDM5ODAzLDM5ODEwLDM5ODI3LDM5ODI2LDM5ODI0LDM5ODAyLDM5ODI5LDM5ODA1LDM5ODE2LDQwMjI5LDQwMjE1LDQwMjI0LDQwMjIyLDQwMjEyLDQwMjMzLDQwMjIxLDQwMjE2LDQwMjI2LDQwMjA4LDQwMjE3LDQwMjIzLDQwNTg0LDQwNTgyLDQwNTgzLDQwNjIyLDQwNjIxLDQwNjYxLDQwNjYyLDQwNjk4LDQwNzIyLDQwNzY1LDIwNzc0LDIwNzczLDIwNzcwLDIwNzcyLDIwNzY4LDIwNzc3LDIxMjM2LDIyMTYzLDIyMTU2LDIyMTU3LDIyMTUwLDIyMTQ4LDIyMTQ3LDIyMTQyLDIyMTQ2LDIyMTQzLDIyMTQ1LDIyNzQyLDIyNzQwLDIyNzM1LDIyNzM4LDIzMzQxLDIzMzMzLDIzMzQ2LDIzMzMxLDIzMzQwLDIzMzM1LDIzMzM0LDIzMzQzLDIzMzQyLDIzNDE5LDIzNTM3LDIzNTM4LDIzOTkxLDI0MTcyLDI0MTcwLDI0NTEwLDI0NTA3LDI1MDI3LDI1MDEzLDI1MDIwLDI1MDYzLDI1MDU2LDI1MDYxLDI1MDYwLDI1MDY0LDI1MDU0LDI1ODM5LDI1ODMzLDI1ODI3LDI1ODM1LDI1ODI4LDI1ODMyLDI1OTg1LDI1OTg0LDI2MDM4LDI2MDc0LDI2MzIyLDI3Mjc3LDI3Mjg2LDI3MjY1LDI3MzAxLDI3MjczLDI3Mjk1LDI3MjkxLDI3Mjk3LDI3Mjk0LDI3MjcxLDI3MjgzLDI3Mjc4LDI3Mjg1LDI3MjY3LDI3MzA0LDI3MzAwLDI3MjgxLDI3MjYzLDI3MzAyLDI3MjkwLDI3MjY5LDI3Mjc2LDI3MjgyLDI3NDgzLDI3NTY1LDI3NjU3LDI4NjIwLDI4NTg1LDI4NjYwLDI4NjI4LDI4NjQzLDI4NjM2LDI4NjUzLDI4NjQ3LDI4NjQ2LDI4NjM4LDI4NjU4LDI4NjM3LDI4NjQyLDI4NjQ4LDI5MTUzLDI5MTY5LDI5MTYwLDI5MTcwLDI5MTU2LDI5MTY4LDI5MTU0LDI5NTU1LDI5NTUwLDI5NTUxLDI5ODQ3LDI5ODc0LDI5ODY3LDI5ODQwLDI5ODY2LDI5ODY5LDI5ODczLDI5ODYxLDI5ODcxLDI5OTY4LDI5OTY5LDI5OTcwLDI5OTY3LDMwMDg0LDMwMjc1LDMwMjgwLDMwMjgxLDMwMjc5LDMwMzcyLDMwNDQxLDMwNjQ1LDMwNjM1LDMwNjQyLDMwNjQ3LDMwNjQ2LDMwNjQ0LDMwNjQxLDMwNjMyLDMwNzA0LDMwOTYzLDMwOTczLDMwOTc4LDMwOTcxLDMwOTcyLDMwOTYyLDMwOTgxLDMwOTY5LDMwOTc0LDMwOTgwLDMxMTQ3LDMxMTQ0LDMxMzI0LDMxMzIzLDMxMzE4LDMxMzIwLDMxMzE2LDMxMzIyLDMxNDIyLDMxNDI0LDMxNDI1LDMxNzQ5LDMxNzU5LDMxNzMwLDMxNzQ0LDMxNzQzLDMxNzM5LDMxNzU4LDMxNzMyLDMxNzU1LDMxNzMxLDMxNzQ2LDMxNzUzLDMxNzQ3LDMxNzQ1LDMxNzM2LDMxNzQxLDMxNzUwLDMxNzI4LDMxNzI5LDMxNzYwLDMxNzU0LDMxOTc2LDMyMzAxLDMyMzE2LDMyMzIyLDMyMzA3LDM4OTg0LDMyMzEyLDMyMjk4LDMyMzI5LDMyMzIwLDMyMzI3LDMyMjk3LDMyMzMyLDMyMzA0LDMyMzE1LDMyMzEwLDMyMzI0LDMyMzE0LDMyNTgxLDMyNjM5LDMyNjM4LDMyNjM3LDMyNzU2LDMyNzU0LDMyODEyLDMzMjExLDMzMjIwLDMzMjI4LDMzMjI2LDMzMjIxLDMzMjIzLDMzMjEyLDMzMjU3LDMzMzcxLDMzMzcwLDMzMzcyLDM0MTc5LDM0MTc2LDM0MTkxLDM0MjE1LDM0MTk3LDM0MjA4LDM0MTg3LDM0MjExLDM0MTcxLDM0MjEyLDM0MjAyLDM0MjA2LDM0MTY3LDM0MTcyLDM0MTg1LDM0MjA5LDM0MTcwLDM0MTY4LDM0MTM1LDM0MTkwLDM0MTk4LDM0MTgyLDM0MTg5LDM0MjAxLDM0MjA1LDM0MTc3LDM0MjEwLDM0MTc4LDM0MTg0LDM0MTgxLDM0MTY5LDM0MTY2LDM0MjAwLDM0MTkyLDM0MjA3LDM0NDA4LDM0NzUwLDM0NzMwLDM0NzMzLDM0NzU3LDM0NzM2LDM0NzMyLDM0NzQ1LDM0NzQxLDM0NzQ4LDM0NzM0LDM0NzYxLDM0NzU1LDM0NzU0LDM0NzY0LDM0NzQzLDM0NzM1LDM0NzU2LDM0NzYyLDM0NzQwLDM0NzQyLDM0NzUxLDM0NzQ0LDM0NzQ5LDM0NzgyLDM0NzM4LDM1MTI1LDM1MTIzLDM1MTMyLDM1MTM0LDM1MTM3LDM1MTU0LDM1MTI3LDM1MTM4LDM1MjQ1LDM1MjQ3LDM1MjQ2LDM1MzE0LDM1MzE1LDM1NjE0LDM1NjA4LDM1NjA2LDM1NjAxLDM1NTg5LDM1NTk1LDM1NjE4LDM1NTk5LDM1NjAyLDM1NjA1LDM1NTkxLDM1NTk3LDM1NTkyLDM1NTkwLDM1NjEyLDM1NjAzLDM1NjEwLDM1OTE5LDM1OTUyLDM1OTU0LDM1OTUzLDM1OTUxLDM1OTg5LDM1OTg4LDM2MDg5LDM2MjA3LDM2NDMwLDM2NDI5LDM2NDM1LDM2NDMyLDM2NDI4LDM2NDIzLDM2Njc1LDM2NjcyLDM2OTk3LDM2OTkwLDM3MTc2LDM3Mjc0LDM3MjgyLDM3Mjc1LDM3MjczLDM3Mjc5LDM3MjgxLDM3Mjc3LDM3MjgwLDM3NzkzLDM3NzYzLDM3ODA3LDM3NzMyLDM3NzE4LDM3NzAzLDM3NzU2LDM3NzIwLDM3NzI0LDM3NzUwLDM3NzA1LDM3NzEyLDM3NzEzLDM3NzI4LDM3NzQxLDM3Nzc1LDM3NzA4LDM3NzM4LDM3NzUzLDM3NzE5LDM3NzE3LDM3NzE0LDM3NzExLDM3NzQ1LDM3NzUxLDM3NzU1LDM3NzI5LDM3NzI2LDM3NzMxLDM3NzM1LDM3NzYwLDM3NzEwLDM3NzIxLDM4MzQzLDM4MzM2LDM4MzQ1LDM4MzM5LDM4MzQxLDM4MzI3LDM4NTc0LDM4NTc2LDM4NTcyLDM4Njg4LDM4Njg3LDM4NjgwLDM4Njg1LDM4NjgxLDM4ODEwLDM4ODE3LDM4ODEyLDM4ODE0LDM4ODEzLDM4ODY5LDM4ODY4LDM4ODk3LDM4OTc3LDM4OTgwLDM4OTg2LDM4OTg1LDM4OTgxLDM4OTc5LDM5MjA1LDM5MjExLDM5MjEyLDM5MjEwLDM5MjE5LDM5MjE4LDM5MjE1LDM5MjEzLDM5MjE3LDM5MjE2LDM5MzIwLDM5MzMxLDM5MzI5LDM5NDI2LDM5NDE4LDM5NDEyLDM5NDE1LDM5NDE3LDM5NDE2LDM5NDE0LDM5NDE5LDM5NDIxLDM5NDIyLDM5NDIwLDM5NDI3LDM5NjE0LDM5Njc4LDM5Njc3LDM5NjgxLDM5Njc2LDM5NzUyLDM5ODM0LDM5ODQ4LDM5ODM4LDM5ODM1LDM5ODQ2LDM5ODQxLDM5ODQ1LDM5ODQ0LDM5ODE0LDM5ODQyLDM5ODQwLDM5ODU1LDQwMjQzLDQwMjU3LDQwMjk1LDQwMjQ2LDQwMjM4LDQwMjM5LDQwMjQxLDQwMjQ4LDQwMjQwLDQwMjYxLDQwMjU4LDQwMjU5LDQwMjU0LDQwMjQ3LDQwMjU2LDQwMjUzLDMyNzU3LDQwMjM3LDQwNTg2LDQwNTg1LDQwNTg5LDQwNjI0LDQwNjQ4LDQwNjY2LDQwNjk5LDQwNzAzLDQwNzQwLDQwNzM5LDQwNzM4LDQwNzg4LDQwODY0LDIwNzg1LDIwNzgxLDIwNzgyLDIyMTY4LDIyMTcyLDIyMTY3LDIyMTcwLDIyMTczLDIyMTY5LDIyODk2LDIzMzU2LDIzNjU3LDIzNjU4LDI0MDAwLDI0MTczLDI0MTc0LDI1MDQ4LDI1MDU1LDI1MDY5LDI1MDcwLDI1MDczLDI1MDY2LDI1MDcyLDI1MDY3LDI1MDQ2LDI1MDY1LDI1ODU1LDI1ODYwLDI1ODUzLDI1ODQ4LDI1ODU3LDI1ODU5LDI1ODUyLDI2MDA0LDI2MDc1LDI2MzMwLDI2MzMxLDI2MzI4LDI3MzMzLDI3MzIxLDI3MzI1LDI3MzYxLDI3MzM0LDI3MzIyLDI3MzE4LDI3MzE5LDI3MzM1LDI3MzE2LDI3MzA5LDI3NDg2LDI3NTkzLDI3NjU5LDI4Njc5LDI4Njg0LDI4Njg1LDI4NjczLDI4Njc3LDI4NjkyLDI4Njg2LDI4NjcxLDI4NjcyLDI4NjY3LDI4NzEwLDI4NjY4LDI4NjYzLDI4NjgyLDI5MTg1LDI5MTgzLDI5MTc3LDI5MTg3LDI5MTgxLDI5NTU4LDI5ODgwLDI5ODg4LDI5ODc3LDI5ODg5LDI5ODg2LDI5ODc4LDI5ODgzLDI5ODkwLDI5OTcyLDI5OTcxLDMwMzAwLDMwMzA4LDMwMjk3LDMwMjg4LDMwMjkxLDMwMjk1LDMwMjk4LDMwMzc0LDMwMzk3LDMwNDQ0LDMwNjU4LDMwNjUwLDMwOTc1LDMwOTg4LDMwOTk1LDMwOTk2LDMwOTg1LDMwOTkyLDMwOTk0LDMwOTkzLDMxMTQ5LDMxMTQ4LDMxMzI3LDMxNzcyLDMxNzg1LDMxNzY5LDMxNzc2LDMxNzc1LDMxNzg5LDMxNzczLDMxNzgyLDMxNzg0LDMxNzc4LDMxNzgxLDMxNzkyLDMyMzQ4LDMyMzM2LDMyMzQyLDMyMzU1LDMyMzQ0LDMyMzU0LDMyMzUxLDMyMzM3LDMyMzUyLDMyMzQzLDMyMzM5LDMyNjkzLDMyNjkxLDMyNzU5LDMyNzYwLDMyODg1LDMzMjMzLDMzMjM0LDMzMjMyLDMzMzc1LDMzMzc0LDM0MjI4LDM0MjQ2LDM0MjQwLDM0MjQzLDM0MjQyLDM0MjI3LDM0MjI5LDM0MjM3LDM0MjQ3LDM0MjQ0LDM0MjM5LDM0MjUxLDM0MjU0LDM0MjQ4LDM0MjQ1LDM0MjI1LDM0MjMwLDM0MjU4LDM0MzQwLDM0MjMyLDM0MjMxLDM0MjM4LDM0NDA5LDM0NzkxLDM0NzkwLDM0Nzg2LDM0Nzc5LDM0Nzk1LDM0Nzk0LDM0Nzg5LDM0NzgzLDM0ODAzLDM0Nzg4LDM0NzcyLDM0NzgwLDM0NzcxLDM0Nzk3LDM0Nzc2LDM0Nzg3LDM0NzI0LDM0Nzc1LDM0Nzc3LDM0ODE3LDM0ODA0LDM0NzkyLDM0NzgxLDM1MTU1LDM1MTQ3LDM1MTUxLDM1MTQ4LDM1MTQyLDM1MTUyLDM1MTUzLDM1MTQ1LDM1NjI2LDM1NjIzLDM1NjE5LDM1NjM1LDM1NjMyLDM1NjM3LDM1NjU1LDM1NjMxLDM1NjQ0LDM1NjQ2LDM1NjMzLDM1NjIxLDM1NjM5LDM1NjIyLDM1NjM4LDM1NjMwLDM1NjIwLDM1NjQzLDM1NjQ1LDM1NjQyLDM1OTA2LDM1OTU3LDM1OTkzLDM1OTkyLDM1OTkxLDM2MDk0LDM2MTAwLDM2MDk4LDM2MDk2LDM2NDQ0LDM2NDUwLDM2NDQ4LDM2NDM5LDM2NDM4LDM2NDQ2LDM2NDUzLDM2NDU1LDM2NDQzLDM2NDQyLDM2NDQ5LDM2NDQ1LDM2NDU3LDM2NDM2LDM2Njc4LDM2Njc5LDM2NjgwLDM2NjgzLDM3MTYwLDM3MTc4LDM3MTc5LDM3MTgyLDM3Mjg4LDM3Mjg1LDM3Mjg3LDM3Mjk1LDM3MjkwLDM3ODEzLDM3NzcyLDM3Nzc4LDM3ODE1LDM3Nzg3LDM3Nzg5LDM3NzY5LDM3Nzk5LDM3Nzc0LDM3ODAyLDM3NzkwLDM3Nzk4LDM3NzgxLDM3NzY4LDM3Nzg1LDM3NzkxLDM3NzczLDM3ODA5LDM3Nzc3LDM3ODEwLDM3Nzk2LDM3ODAwLDM3ODEyLDM3Nzk1LDM3Nzk3LDM4MzU0LDM4MzU1LDM4MzUzLDM4NTc5LDM4NjE1LDM4NjE4LDI0MDAyLDM4NjIzLDM4NjE2LDM4NjIxLDM4NjkxLDM4NjkwLDM4NjkzLDM4ODI4LDM4ODMwLDM4ODI0LDM4ODI3LDM4ODIwLDM4ODI2LDM4ODE4LDM4ODIxLDM4ODcxLDM4ODczLDM4ODcwLDM4ODcyLDM4OTA2LDM4OTkyLDM4OTkzLDM4OTk0LDM5MDk2LDM5MjMzLDM5MjI4LDM5MjI2LDM5NDM5LDM5NDM1LDM5NDMzLDM5NDM3LDM5NDI4LDM5NDQxLDM5NDM0LDM5NDI5LDM5NDMxLDM5NDMwLDM5NjE2LDM5NjQ0LDM5Njg4LDM5Njg0LDM5Njg1LDM5NzIxLDM5NzMzLDM5NzU0LDM5NzU2LDM5NzU1LDM5ODc5LDM5ODc4LDM5ODc1LDM5ODcxLDM5ODczLDM5ODYxLDM5ODY0LDM5ODkxLDM5ODYyLDM5ODc2LDM5ODY1LDM5ODY5LDQwMjg0LDQwMjc1LDQwMjcxLDQwMjY2LDQwMjgzLDQwMjY3LDQwMjgxLDQwMjc4LDQwMjY4LDQwMjc5LDQwMjc0LDQwMjc2LDQwMjg3LDQwMjgwLDQwMjgyLDQwNTkwLDQwNTg4LDQwNjcxLDQwNzA1LDQwNzA0LDQwNzI2LDQwNzQxLDQwNzQ3LDQwNzQ2LDQwNzQ1LDQwNzQ0LDQwNzgwLDQwNzg5LDIwNzg4LDIwNzg5LDIxMTQyLDIxMjM5LDIxNDI4LDIyMTg3LDIyMTg5LDIyMTgyLDIyMTgzLDIyMTg2LDIyMTg4LDIyNzQ2LDIyNzQ5LDIyNzQ3LDIyODAyLDIzMzU3LDIzMzU4LDIzMzU5LDI0MDAzLDI0MTc2LDI0NTExLDI1MDgzLDI1ODYzLDI1ODcyLDI1ODY5LDI1ODY1LDI1ODY4LDI1ODcwLDI1OTg4LDI2MDc4LDI2MDc3LDI2MzM0LDI3MzY3LDI3MzYwLDI3MzQwLDI3MzQ1LDI3MzUzLDI3MzM5LDI3MzU5LDI3MzU2LDI3MzQ0LDI3MzcxLDI3MzQzLDI3MzQxLDI3MzU4LDI3NDg4LDI3NTY4LDI3NjYwLDI4Njk3LDI4NzExLDI4NzA0LDI4Njk0LDI4NzE1LDI4NzA1LDI4NzA2LDI4NzA3LDI4NzEzLDI4Njk1LDI4NzA4LDI4NzAwLDI4NzE0LDI5MTk2LDI5MTk0LDI5MTkxLDI5MTg2LDI5MTg5LDI5MzQ5LDI5MzUwLDI5MzQ4LDI5MzQ3LDI5MzQ1LDI5ODk5LDI5ODkzLDI5ODc5LDI5ODkxLDI5OTc0LDMwMzA0LDMwNjY1LDMwNjY2LDMwNjYwLDMwNzA1LDMxMDA1LDMxMDAzLDMxMDA5LDMxMDA0LDMwOTk5LDMxMDA2LDMxMTUyLDMxMzM1LDMxMzM2LDMxNzk1LDMxODA0LDMxODAxLDMxNzg4LDMxODAzLDMxOTgwLDMxOTc4LDMyMzc0LDMyMzczLDMyMzc2LDMyMzY4LDMyMzc1LDMyMzY3LDMyMzc4LDMyMzcwLDMyMzcyLDMyMzYwLDMyNTg3LDMyNTg2LDMyNjQzLDMyNjQ2LDMyNjk1LDMyNzY1LDMyNzY2LDMyODg4LDMzMjM5LDMzMjM3LDMzMzgwLDMzMzc3LDMzMzc5LDM0MjgzLDM0Mjg5LDM0Mjg1LDM0MjY1LDM0MjczLDM0MjgwLDM0MjY2LDM0MjYzLDM0Mjg0LDM0MjkwLDM0Mjk2LDM0MjY0LDM0MjcxLDM0Mjc1LDM0MjY4LDM0MjU3LDM0Mjg4LDM0Mjc4LDM0Mjg3LDM0MjcwLDM0Mjc0LDM0ODE2LDM0ODEwLDM0ODE5LDM0ODA2LDM0ODA3LDM0ODI1LDM0ODI4LDM0ODI3LDM0ODIyLDM0ODEyLDM0ODI0LDM0ODE1LDM0ODI2LDM0ODE4LDM1MTcwLDM1MTYyLDM1MTYzLDM1MTU5LDM1MTY5LDM1MTY0LDM1MTYwLDM1MTY1LDM1MTYxLDM1MjA4LDM1MjU1LDM1MjU0LDM1MzE4LDM1NjY0LDM1NjU2LDM1NjU4LDM1NjQ4LDM1NjY3LDM1NjcwLDM1NjY4LDM1NjU5LDM1NjY5LDM1NjY1LDM1NjUwLDM1NjY2LDM1NjcxLDM1OTA3LDM1OTU5LDM1OTU4LDM1OTk0LDM2MTAyLDM2MTAzLDM2MTA1LDM2MjY4LDM2MjY2LDM2MjY5LDM2MjY3LDM2NDYxLDM2NDcyLDM2NDY3LDM2NDU4LDM2NDYzLDM2NDc1LDM2NTQ2LDM2NjkwLDM2Njg5LDM2Njg3LDM2Njg4LDM2NjkxLDM2Nzg4LDM3MTg0LDM3MTgzLDM3Mjk2LDM3MjkzLDM3ODU0LDM3ODMxLDM3ODM5LDM3ODI2LDM3ODUwLDM3ODQwLDM3ODgxLDM3ODY4LDM3ODM2LDM3ODQ5LDM3ODAxLDM3ODYyLDM3ODM0LDM3ODQ0LDM3ODcwLDM3ODU5LDM3ODQ1LDM3ODI4LDM3ODM4LDM3ODI0LDM3ODQyLDM3ODYzLDM4MjY5LDM4MzYyLDM4MzYzLDM4NjI1LDM4Njk3LDM4Njk5LDM4NzAwLDM4Njk2LDM4Njk0LDM4ODM1LDM4ODM5LDM4ODM4LDM4ODc3LDM4ODc4LDM4ODc5LDM5MDA0LDM5MDAxLDM5MDA1LDM4OTk5LDM5MTAzLDM5MTAxLDM5MDk5LDM5MTAyLDM5MjQwLDM5MjM5LDM5MjM1LDM5MzM0LDM5MzM1LDM5NDUwLDM5NDQ1LDM5NDYxLDM5NDUzLDM5NDYwLDM5NDUxLDM5NDU4LDM5NDU2LDM5NDYzLDM5NDU5LDM5NDU0LDM5NDUyLDM5NDQ0LDM5NjE4LDM5NjkxLDM5NjkwLDM5Njk0LDM5NjkyLDM5NzM1LDM5OTE0LDM5OTE1LDM5OTA0LDM5OTAyLDM5OTA4LDM5OTEwLDM5OTA2LDM5OTIwLDM5ODkyLDM5ODk1LDM5OTE2LDM5OTAwLDM5ODk3LDM5OTA5LDM5ODkzLDM5OTA1LDM5ODk4LDQwMzExLDQwMzIxLDQwMzMwLDQwMzI0LDQwMzI4LDQwMzA1LDQwMzIwLDQwMzEyLDQwMzI2LDQwMzMxLDQwMzMyLDQwMzE3LDQwMjk5LDQwMzA4LDQwMzA5LDQwMzA0LDQwMjk3LDQwMzI1LDQwMzA3LDQwMzE1LDQwMzIyLDQwMzAzLDQwMzEzLDQwMzE5LDQwMzI3LDQwMjk2LDQwNTk2LDQwNTkzLDQwNjQwLDQwNzAwLDQwNzQ5LDQwNzY4LDQwNzY5LDQwNzgxLDQwNzkwLDQwNzkxLDQwNzkyLDIxMzAzLDIyMTk0LDIyMTk3LDIyMTk1LDIyNzU1LDIzMzY1LDI0MDA2LDI0MDA3LDI0MzAyLDI0MzAzLDI0NTEyLDI0NTEzLDI1MDgxLDI1ODc5LDI1ODc4LDI1ODc3LDI1ODc1LDI2MDc5LDI2MzQ0LDI2MzM5LDI2MzQwLDI3Mzc5LDI3Mzc2LDI3MzcwLDI3MzY4LDI3Mzg1LDI3Mzc3LDI3Mzc0LDI3Mzc1LDI4NzMyLDI4NzI1LDI4NzE5LDI4NzI3LDI4NzI0LDI4NzIxLDI4NzM4LDI4NzI4LDI4NzM1LDI4NzMwLDI4NzI5LDI4NzM2LDI4NzMxLDI4NzIzLDI4NzM3LDI5MjAzLDI5MjA0LDI5MzUyLDI5NTY1LDI5NTY0LDI5ODgyLDMwMzc5LDMwMzc4LDMwMzk4LDMwNDQ1LDMwNjY4LDMwNjcwLDMwNjcxLDMwNjY5LDMwNzA2LDMxMDEzLDMxMDExLDMxMDE1LDMxMDE2LDMxMDEyLDMxMDE3LDMxMTU0LDMxMzQyLDMxMzQwLDMxMzQxLDMxNDc5LDMxODE3LDMxODE2LDMxODE4LDMxODE1LDMxODEzLDMxOTgyLDMyMzc5LDMyMzgyLDMyMzg1LDMyMzg0LDMyNjk4LDMyNzY3LDMyODg5LDMzMjQzLDMzMjQxLDMzMjkxLDMzMzg0LDMzMzg1LDM0MzM4LDM0MzAzLDM0MzA1LDM0MzAyLDM0MzMxLDM0MzA0LDM0Mjk0LDM0MzA4LDM0MzEzLDM0MzA5LDM0MzE2LDM0MzAxLDM0ODQxLDM0ODMyLDM0ODMzLDM0ODM5LDM0ODM1LDM0ODM4LDM1MTcxLDM1MTc0LDM1MjU3LDM1MzE5LDM1NjgwLDM1NjkwLDM1Njc3LDM1Njg4LDM1NjgzLDM1Njg1LDM1Njg3LDM1NjkzLDM2MjcwLDM2NDg2LDM2NDg4LDM2NDg0LDM2Njk3LDM2Njk0LDM2Njk1LDM2NjkzLDM2Njk2LDM2Njk4LDM3MDA1LDM3MTg3LDM3MTg1LDM3MzAzLDM3MzAxLDM3Mjk4LDM3Mjk5LDM3ODk5LDM3OTA3LDM3ODgzLDM3OTIwLDM3OTAzLDM3OTA4LDM3ODg2LDM3OTA5LDM3OTA0LDM3OTI4LDM3OTEzLDM3OTAxLDM3ODc3LDM3ODg4LDM3ODc5LDM3ODk1LDM3OTAyLDM3OTEwLDM3OTA2LDM3ODgyLDM3ODk3LDM3ODgwLDM3ODk4LDM3ODg3LDM3ODg0LDM3OTAwLDM3ODc4LDM3OTA1LDM3ODk0LDM4MzY2LDM4MzY4LDM4MzY3LDM4NzAyLDM4NzAzLDM4ODQxLDM4ODQzLDM4OTA5LDM4OTEwLDM5MDA4LDM5MDEwLDM5MDExLDM5MDA3LDM5MTA1LDM5MTA2LDM5MjQ4LDM5MjQ2LDM5MjU3LDM5MjQ0LDM5MjQzLDM5MjUxLDM5NDc0LDM5NDc2LDM5NDczLDM5NDY4LDM5NDY2LDM5NDc4LDM5NDY1LDM5NDcwLDM5NDgwLDM5NDY5LDM5NjIzLDM5NjI2LDM5NjIyLDM5Njk2LDM5Njk4LDM5Njk3LDM5OTQ3LDM5OTQ0LDM5OTI3LDM5OTQxLDM5OTU0LDM5OTI4LDQwMDAwLDM5OTQzLDM5OTUwLDM5OTQyLDM5OTU5LDM5OTU2LDM5OTQ1LDQwMzUxLDQwMzQ1LDQwMzU2LDQwMzQ5LDQwMzM4LDQwMzQ0LDQwMzM2LDQwMzQ3LDQwMzUyLDQwMzQwLDQwMzQ4LDQwMzYyLDQwMzQzLDQwMzUzLDQwMzQ2LDQwMzU0LDQwMzYwLDQwMzUwLDQwMzU1LDQwMzgzLDQwMzYxLDQwMzQyLDQwMzU4LDQwMzU5LDQwNjAxLDQwNjAzLDQwNjAyLDQwNjc3LDQwNjc2LDQwNjc5LDQwNjc4LDQwNzUyLDQwNzUwLDQwNzk1LDQwODAwLDQwNzk4LDQwNzk3LDQwNzkzLDQwODQ5LDIwNzk0LDIwNzkzLDIxMTQ0LDIxMTQzLDIyMjExLDIyMjA1LDIyMjA2LDIzMzY4LDIzMzY3LDI0MDExLDI0MDE1LDI0MzA1LDI1MDg1LDI1ODgzLDI3Mzk0LDI3Mzg4LDI3Mzk1LDI3Mzg0LDI3MzkyLDI4NzM5LDI4NzQwLDI4NzQ2LDI4NzQ0LDI4NzQ1LDI4NzQxLDI4NzQyLDI5MjEzLDI5MjEwLDI5MjA5LDI5NTY2LDI5OTc1LDMwMzE0LDMwNjcyLDMxMDIxLDMxMDI1LDMxMDIzLDMxODI4LDMxODI3LDMxOTg2LDMyMzk0LDMyMzkxLDMyMzkyLDMyMzk1LDMyMzkwLDMyMzk3LDMyNTg5LDMyNjk5LDMyODE2LDMzMjQ1LDM0MzI4LDM0MzQ2LDM0MzQyLDM0MzM1LDM0MzM5LDM0MzMyLDM0MzI5LDM0MzQzLDM0MzUwLDM0MzM3LDM0MzM2LDM0MzQ1LDM0MzM0LDM0MzQxLDM0ODU3LDM0ODQ1LDM0ODQzLDM0ODQ4LDM0ODUyLDM0ODQ0LDM0ODU5LDM0ODkwLDM1MTgxLDM1MTc3LDM1MTgyLDM1MTc5LDM1MzIyLDM1NzA1LDM1NzA0LDM1NjUzLDM1NzA2LDM1NzA3LDM2MTEyLDM2MTE2LDM2MjcxLDM2NDk0LDM2NDkyLDM2NzAyLDM2Njk5LDM2NzAxLDM3MTkwLDM3MTg4LDM3MTg5LDM3MzA1LDM3OTUxLDM3OTQ3LDM3OTQyLDM3OTI5LDM3OTQ5LDM3OTQ4LDM3OTM2LDM3OTQ1LDM3OTMwLDM3OTQzLDM3OTMyLDM3OTUyLDM3OTM3LDM4MzczLDM4MzcyLDM4MzcxLDM4NzA5LDM4NzE0LDM4ODQ3LDM4ODgxLDM5MDEyLDM5MTEzLDM5MTEwLDM5MTA0LDM5MjU2LDM5MjU0LDM5NDgxLDM5NDg1LDM5NDk0LDM5NDkyLDM5NDkwLDM5NDg5LDM5NDgyLDM5NDg3LDM5NjI5LDM5NzAxLDM5NzAzLDM5NzA0LDM5NzAyLDM5NzM4LDM5NzYyLDM5OTc5LDM5OTY1LDM5OTY0LDM5OTgwLDM5OTcxLDM5OTc2LDM5OTc3LDM5OTcyLDM5OTY5LDQwMzc1LDQwMzc0LDQwMzgwLDQwMzg1LDQwMzkxLDQwMzk0LDQwMzk5LDQwMzgyLDQwMzg5LDQwMzg3LDQwMzc5LDQwMzczLDQwMzk4LDQwMzc3LDQwMzc4LDQwMzY0LDQwMzkyLDQwMzY5LDQwMzY1LDQwMzk2LDQwMzcxLDQwMzk3LDQwMzcwLDQwNTcwLDQwNjA0LDQwNjgzLDQwNjg2LDQwNjg1LDQwNzMxLDQwNzI4LDQwNzMwLDQwNzUzLDQwNzgyLDQwODA1LDQwODA0LDQwODUwLDIwMTUzLDIyMjE0LDIyMjEzLDIyMjE5LDIyODk3LDIzMzcxLDIzMzcyLDI0MDIxLDI0MDE3LDI0MzA2LDI1ODg5LDI1ODg4LDI1ODk0LDI1ODkwLDI3NDAzLDI3NDAwLDI3NDAxLDI3NjYxLDI4NzU3LDI4NzU4LDI4NzU5LDI4NzU0LDI5MjE0LDI5MjE1LDI5MzUzLDI5NTY3LDI5OTEyLDI5OTA5LDI5OTEzLDI5OTExLDMwMzE3LDMwMzgxLDMxMDI5LDMxMTU2LDMxMzQ0LDMxMzQ1LDMxODMxLDMxODM2LDMxODMzLDMxODM1LDMxODM0LDMxOTg4LDMxOTg1LDMyNDAxLDMyNTkxLDMyNjQ3LDMzMjQ2LDMzMzg3LDM0MzU2LDM0MzU3LDM0MzU1LDM0MzQ4LDM0MzU0LDM0MzU4LDM0ODYwLDM0ODU2LDM0ODU0LDM0ODU4LDM0ODUzLDM1MTg1LDM1MjYzLDM1MjYyLDM1MzIzLDM1NzEwLDM1NzE2LDM1NzE0LDM1NzE4LDM1NzE3LDM1NzExLDM2MTE3LDM2NTAxLDM2NTAwLDM2NTA2LDM2NDk4LDM2NDk2LDM2NTAyLDM2NTAzLDM2NzA0LDM2NzA2LDM3MTkxLDM3OTY0LDM3OTY4LDM3OTYyLDM3OTYzLDM3OTY3LDM3OTU5LDM3OTU3LDM3OTYwLDM3OTYxLDM3OTU4LDM4NzE5LDM4ODgzLDM5MDE4LDM5MDE3LDM5MTE1LDM5MjUyLDM5MjU5LDM5NTAyLDM5NTA3LDM5NTA4LDM5NTAwLDM5NTAzLDM5NDk2LDM5NDk4LDM5NDk3LDM5NTA2LDM5NTA0LDM5NjMyLDM5NzA1LDM5NzIzLDM5NzM5LDM5NzY2LDM5NzY1LDQwMDA2LDQwMDA4LDM5OTk5LDQwMDA0LDM5OTkzLDM5OTg3LDQwMDAxLDM5OTk2LDM5OTkxLDM5OTg4LDM5OTg2LDM5OTk3LDM5OTkwLDQwNDExLDQwNDAyLDQwNDE0LDQwNDEwLDQwMzk1LDQwNDAwLDQwNDEyLDQwNDAxLDQwNDE1LDQwNDI1LDQwNDA5LDQwNDA4LDQwNDA2LDQwNDM3LDQwNDA1LDQwNDEzLDQwNjMwLDQwNjg4LDQwNzU3LDQwNzU1LDQwNzU0LDQwNzcwLDQwODExLDQwODUzLDQwODY2LDIwNzk3LDIxMTQ1LDIyNzYwLDIyNzU5LDIyODk4LDIzMzczLDI0MDI0LDM0ODYzLDI0Mzk5LDI1MDg5LDI1MDkxLDI1MDkyLDI1ODk3LDI1ODkzLDI2MDA2LDI2MzQ3LDI3NDA5LDI3NDEwLDI3NDA3LDI3NTk0LDI4NzYzLDI4NzYyLDI5MjE4LDI5NTcwLDI5NTY5LDI5NTcxLDMwMzIwLDMwNjc2LDMxODQ3LDMxODQ2LDMyNDA1LDMzMzg4LDM0MzYyLDM0MzY4LDM0MzYxLDM0MzY0LDM0MzUzLDM0MzYzLDM0MzY2LDM0ODY0LDM0ODY2LDM0ODYyLDM0ODY3LDM1MTkwLDM1MTg4LDM1MTg3LDM1MzI2LDM1NzI0LDM1NzI2LDM1NzIzLDM1NzIwLDM1OTA5LDM2MTIxLDM2NTA0LDM2NzA4LDM2NzA3LDM3MzA4LDM3OTg2LDM3OTczLDM3OTgxLDM3OTc1LDM3OTgyLDM4ODUyLDM4ODUzLDM4OTEyLDM5NTEwLDM5NTEzLDM5NzEwLDM5NzExLDM5NzEyLDQwMDE4LDQwMDI0LDQwMDE2LDQwMDEwLDQwMDEzLDQwMDExLDQwMDIxLDQwMDI1LDQwMDEyLDQwMDE0LDQwNDQzLDQwNDM5LDQwNDMxLDQwNDE5LDQwNDI3LDQwNDQwLDQwNDIwLDQwNDM4LDQwNDE3LDQwNDMwLDQwNDIyLDQwNDM0LDQwNDMyLDQwNDE4LDQwNDI4LDQwNDM2LDQwNDM1LDQwNDI0LDQwNDI5LDQwNjQyLDQwNjU2LDQwNjkwLDQwNjkxLDQwNzEwLDQwNzMyLDQwNzYwLDQwNzU5LDQwNzU4LDQwNzcxLDQwNzgzLDQwODE3LDQwODE2LDQwODE0LDQwODE1LDIyMjI3LDIyMjIxLDIzMzc0LDIzNjYxLDI1OTAxLDI2MzQ5LDI2MzUwLDI3NDExLDI4NzY3LDI4NzY5LDI4NzY1LDI4NzY4LDI5MjE5LDI5OTE1LDI5OTI1LDMwNjc3LDMxMDMyLDMxMTU5LDMxMTU4LDMxODUwLDMyNDA3LDMyNjQ5LDMzMzg5LDM0MzcxLDM0ODcyLDM0ODcxLDM0ODY5LDM0ODkxLDM1NzMyLDM1NzMzLDM2NTEwLDM2NTExLDM2NTEyLDM2NTA5LDM3MzEwLDM3MzA5LDM3MzE0LDM3OTk1LDM3OTkyLDM3OTkzLDM4NjI5LDM4NzI2LDM4NzIzLDM4NzI3LDM4ODU1LDM4ODg1LDM5NTE4LDM5NjM3LDM5NzY5LDQwMDM1LDQwMDM5LDQwMDM4LDQwMDM0LDQwMDMwLDQwMDMyLDQwNDUwLDQwNDQ2LDQwNDU1LDQwNDUxLDQwNDU0LDQwNDUzLDQwNDQ4LDQwNDQ5LDQwNDU3LDQwNDQ3LDQwNDQ1LDQwNDUyLDQwNjA4LDQwNzM0LDQwNzc0LDQwODIwLDQwODIxLDQwODIyLDIyMjI4LDI1OTAyLDI2MDQwLDI3NDE2LDI3NDE3LDI3NDE1LDI3NDE4LDI4NzcwLDI5MjIyLDI5MzU0LDMwNjgwLDMwNjgxLDMxMDMzLDMxODQ5LDMxODUxLDMxOTkwLDMyNDEwLDMyNDA4LDMyNDExLDMyNDA5LDMzMjQ4LDMzMjQ5LDM0Mzc0LDM0Mzc1LDM0Mzc2LDM1MTkzLDM1MTk0LDM1MTk2LDM1MTk1LDM1MzI3LDM1NzM2LDM1NzM3LDM2NTE3LDM2NTE2LDM2NTE1LDM3OTk4LDM3OTk3LDM3OTk5LDM4MDAxLDM4MDAzLDM4NzI5LDM5MDI2LDM5MjYzLDQwMDQwLDQwMDQ2LDQwMDQ1LDQwNDU5LDQwNDYxLDQwNDY0LDQwNDYzLDQwNDY2LDQwNDY1LDQwNjA5LDQwNjkzLDQwNzEzLDQwNzc1LDQwODI0LDQwODI3LDQwODI2LDQwODI1LDIyMzAyLDI4Nzc0LDMxODU1LDM0ODc2LDM2Mjc0LDM2NTE4LDM3MzE1LDM4MDA0LDM4MDA4LDM4MDA2LDM4MDA1LDM5NTIwLDQwMDUyLDQwMDUxLDQwMDQ5LDQwMDUzLDQwNDY4LDQwNDY3LDQwNjk0LDQwNzE0LDQwODY4LDI4Nzc2LDI4NzczLDMxOTkxLDM0NDEwLDM0ODc4LDM0ODc3LDM0ODc5LDM1NzQyLDM1OTk2LDM2NTIxLDM2NTUzLDM4NzMxLDM5MDI3LDM5MDI4LDM5MTE2LDM5MjY1LDM5MzM5LDM5NTI0LDM5NTI2LDM5NTI3LDM5NzE2LDQwNDY5LDQwNDcxLDQwNzc2LDI1MDk1LDI3NDIyLDI5MjIzLDM0MzgwLDM2NTIwLDM4MDE4LDM4MDE2LDM4MDE3LDM5NTI5LDM5NTI4LDM5NzI2LDQwNDczLDI5MjI1LDM0Mzc5LDM1NzQzLDM4MDE5LDQwMDU3LDQwNjMxLDMwMzI1LDM5NTMxLDQwMDU4LDQwNDc3LDI4Nzc3LDI4Nzc4LDQwNjEyLDQwODMwLDQwNzc3LDQwODU2LDMwODQ5LDM3NTYxLDM1MDIzLDIyNzE1LDI0NjU4LDMxOTExLDIzMjkwLDk1NTYsOTU3NCw5NTU5LDk1NjgsOTU4MCw5NTcxLDk1NjIsOTU3Nyw5NTY1LDk1NTQsOTU3Miw5NTU3LDk1NjYsOTU3OCw5NTY5LDk1NjAsOTU3NSw5NTYzLDk1NTUsOTU3Myw5NTU4LDk1NjcsOTU3OSw5NTcwLDk1NjEsOTU3Niw5NTY0LDk1NTMsOTU1Miw5NTgxLDk1ODIsOTU4NCw5NTgzLDY1NTE3LDEzMjQyMywzNzU5NSwxMzI1NzUsMTQ3Mzk3LDM0MTI0LDE3MDc3LDI5Njc5LDIwOTE3LDEzODk3LDE0OTgyNiwxNjYzNzIsMzc3MDAsMTM3NjkxLDMzNTE4LDE0NjYzMiwzMDc4MCwyNjQzNiwyNTMxMSwxNDk4MTEsMTY2MzE0LDEzMTc0NCwxNTg2NDMsMTM1OTQxLDIwMzk1LDE0MDUyNSwyMDQ4OCwxNTkwMTcsMTYyNDM2LDE0NDg5NiwxNTAxOTMsMTQwNTYzLDIwNTIxLDEzMTk2NiwyNDQ4NCwxMzE5NjgsMTMxOTExLDI4Mzc5LDEzMjEyNywyMDYwNSwyMDczNywxMzQzNCwyMDc1MCwzOTAyMCwxNDE0NywzMzgxNCwxNDk5MjQsMTMyMjMxLDIwODMyLDE0NDMwOCwyMDg0MiwxMzQxNDMsMTM5NTE2LDEzMTgxMywxNDA1OTIsMTMyNDk0LDE0MzkyMywxMzc2MDMsMjM0MjYsMzQ2ODUsMTMyNTMxLDE0NjU4NSwyMDkxNCwyMDkyMCw0MDI0NCwyMDkzNywyMDk0MywyMDk0NSwxNTU4MCwyMDk0NywxNTAxODIsMjA5MTUsMjA5NjIsMjEzMTQsMjA5NzMsMzM3NDEsMjY5NDIsMTQ1MTk3LDI0NDQzLDIxMDAzLDIxMDMwLDIxMDUyLDIxMTczLDIxMDc5LDIxMTQwLDIxMTc3LDIxMTg5LDMxNzY1LDM0MTE0LDIxMjE2LDM0MzE3LDE1ODQ4MywyMTI1MywxNjY2MjIsMjE4MzMsMjgzNzcsMTQ3MzI4LDEzMzQ2MCwxNDc0MzYsMjEyOTksMjEzMTYsMTM0MTE0LDI3ODUxLDEzNjk5OCwyNjY1MSwyOTY1MywyNDY1MCwxNjA0MiwxNDU0MCwxMzY5MzYsMjkxNDksMTc1NzAsMjEzNTcsMjEzNjQsMTY1NTQ3LDIxMzc0LDIxMzc1LDEzNjU5OCwxMzY3MjMsMzA2OTQsMjEzOTUsMTY2NTU1LDIxNDA4LDIxNDE5LDIxNDIyLDI5NjA3LDE1MzQ1OCwxNjIxNywyOTU5NiwyMTQ0MSwyMTQ0NSwyNzcyMSwyMDA0MSwyMjUyNiwyMTQ2NSwxNTAxOSwxMzQwMzEsMjE0NzIsMTQ3NDM1LDE0Mjc1NSwyMTQ5NCwxMzQyNjMsMjE1MjMsMjg3OTMsMjE4MDMsMjYxOTksMjc5OTUsMjE2MTMsMTU4NTQ3LDEzNDUxNiwyMTg1MywyMTY0NywyMTY2OCwxODM0MiwxMzY5NzMsMTM0ODc3LDE1Nzk2LDEzNDQ3NywxNjYzMzIsMTQwOTUyLDIxODMxLDE5NjkzLDIxNTUxLDI5NzE5LDIxODk0LDIxOTI5LDIyMDIxLDEzNzQzMSwxNDc1MTQsMTc3NDYsMTQ4NTMzLDI2MjkxLDEzNTM0OCwyMjA3MSwyNjMxNywxNDQwMTAsMjYyNzYsMjYyODUsMjIwOTMsMjIwOTUsMzA5NjEsMjIyNTcsMzg3OTEsMjE1MDIsMjIyNzIsMjIyNTUsMjIyNTMsMTY2NzU4LDEzODU5LDEzNTc1OSwyMjM0MiwxNDc4NzcsMjc3NTgsMjg4MTEsMjIzMzgsMTQwMDEsMTU4ODQ2LDIyNTAyLDEzNjIxNCwyMjUzMSwxMzYyNzYsMTQ4MzIzLDIyNTY2LDE1MDUxNywyMjYyMCwyMjY5OCwxMzY2NSwyMjc1MiwyMjc0OCwxMzU3NDAsMjI3NzksMjM1NTEsMjIzMzksMTcyMzY4LDE0ODA4OCwzNzg0MywxMzcyOSwyMjgxNSwyNjc5MCwxNDAxOSwyODI0OSwxMzY3NjYsMjMwNzYsMjE4NDMsMTM2ODUwLDM0MDUzLDIyOTg1LDEzNDQ3OCwxNTg4NDksMTU5MDE4LDEzNzE4MCwyMzAwMSwxMzcyMTEsMTM3MTM4LDE1OTE0MiwyODAxNywxMzcyNTYsMTM2OTE3LDIzMDMzLDE1OTMwMSwyMzIxMSwyMzEzOSwxNDA1NCwxNDk5MjksMjMxNTksMTQwODgsMjMxOTAsMjk3OTcsMjMyNTEsMTU5NjQ5LDE0MDYyOCwxNTc0OSwxMzc0ODksMTQxMzAsMTM2ODg4LDI0MTk1LDIxMjAwLDIzNDE0LDI1OTkyLDIzNDIwLDE2MjMxOCwxNjM4OCwxODUyNSwxMzE1ODgsMjM1MDksMjQ5MjgsMTM3NzgwLDE1NDA2MCwxMzI1MTcsMjM1MzksMjM0NTMsMTk3MjgsMjM1NTcsMTM4MDUyLDIzNTcxLDI5NjQ2LDIzNTcyLDEzODQwNSwxNTg1MDQsMjM2MjUsMTg2NTMsMjM2ODUsMjM3ODUsMjM3OTEsMjM5NDcsMTM4NzQ1LDEzODgwNywyMzgyNCwyMzgzMiwyMzg3OCwxMzg5MTYsMjM3MzgsMjQwMjMsMzM1MzIsMTQzODEsMTQ5NzYxLDEzOTMzNywxMzk2MzUsMzM0MTUsMTQzOTAsMTUyOTgsMjQxMTAsMjcyNzQsMjQxODEsMjQxODYsMTQ4NjY4LDEzNDM1NSwyMTQxNCwyMDE1MSwyNDI3MiwyMTQxNiwxMzcwNzMsMjQwNzMsMjQzMDgsMTY0OTk0LDI0MzEzLDI0MzE1LDE0NDk2LDI0MzE2LDI2Njg2LDM3OTE1LDI0MzMzLDEzMTUyMSwxOTQ3MDgsMTUwNzAsMTg2MDYsMTM1OTk0LDI0Mzc4LDE1NzgzMiwxNDAyNDAsMjQ0MDgsMTQwNDAxLDI0NDE5LDM4ODQ1LDE1OTM0MiwyNDQzNCwzNzY5NiwxNjY0NTQsMjQ0ODcsMjM5OTAsMTU3MTEsMTUyMTQ0LDEzOTExNCwxNTk5OTIsMTQwOTA0LDM3MzM0LDEzMTc0MiwxNjY0NDEsMjQ2MjUsMjYyNDUsMTM3MzM1LDE0NjkxLDE1ODE1LDEzODgxLDIyNDE2LDE0MTIzNiwzMTA4OSwxNTkzNiwyNDczNCwyNDc0MCwyNDc1NSwxNDk4OTAsMTQ5OTAzLDE2MjM4NywyOTg2MCwyMDcwNSwyMzIwMCwyNDkzMiwzMzgyOCwyNDg5OCwxOTQ3MjYsMTU5NDQyLDI0OTYxLDIwOTgwLDEzMjY5NCwyNDk2NywyMzQ2NiwxNDczODMsMTQxNDA3LDI1MDQzLDE2NjgxMywxNzAzMzMsMjUwNDAsMTQ2NDIsMTQxNjk2LDE0MTUwNSwyNDYxMSwyNDkyNCwyNTg4NiwyNTQ4MywxMzEzNTIsMjUyODUsMTM3MDcyLDI1MzAxLDE0Mjg2MSwyNTQ1MiwxNDk5ODMsMTQ4NzEsMjU2NTYsMjU1OTIsMTM2MDc4LDEzNzIxMiwyNTc0NCwyODU1NCwxNDI5MDIsMzg5MzIsMTQ3NTk2LDE1MzM3MywyNTgyNSwyNTgyOSwzODAxMSwxNDk1MCwyNTY1OCwxNDkzNSwyNTkzMywyODQzOCwxNTAwNTYsMTUwMDUxLDI1OTg5LDI1OTY1LDI1OTUxLDE0MzQ4NiwyNjAzNywxNDk4MjQsMTkyNTUsMjYwNjUsMTY2MDAsMTM3MjU3LDI2MDgwLDI2MDgzLDI0NTQzLDE0NDM4NCwyNjEzNiwxNDM4NjMsMTQzODY0LDI2MTgwLDE0Mzc4MCwxNDM3ODEsMjYxODcsMTM0NzczLDI2MjE1LDE1MjAzOCwyNjIyNywyNjIyOCwxMzg4MTMsMTQzOTIxLDE2NTM2NCwxNDM4MTYsMTUyMzM5LDMwNjYxLDE0MTU1OSwzOTMzMiwyNjM3MCwxNDgzODAsMTUwMDQ5LDE1MTQ3LDI3MTMwLDE0NTM0NiwyNjQ2MiwyNjQ3MSwyNjQ2NiwxNDc5MTcsMTY4MTczLDI2NTgzLDE3NjQxLDI2NjU4LDI4MjQwLDM3NDM2LDI2NjI1LDE0NDM1OCwxNTkxMzYsMjY3MTcsMTQ0NDk1LDI3MTA1LDI3MTQ3LDE2NjYyMywyNjk5NSwyNjgxOSwxNDQ4NDUsMjY4ODEsMjY4ODAsMTU2NjYsMTQ4NDksMTQ0OTU2LDE1MjMyLDI2NTQwLDI2OTc3LDE2NjQ3NCwxNzE0OCwyNjkzNCwyNzAzMiwxNTI2NSwxMzIwNDEsMzM2MzUsMjA2MjQsMjcxMjksMTQ0OTg1LDEzOTU2MiwyNzIwNSwxNDUxNTUsMjcyOTMsMTUzNDcsMjY1NDUsMjczMzYsMTY4MzQ4LDE1MzczLDI3NDIxLDEzMzQxMSwyNDc5OCwyNzQ0NSwyNzUwOCwxNDEyNjEsMjgzNDEsMTQ2MTM5LDEzMjAyMSwxMzc1NjAsMTQxNDQsMjE1MzcsMTQ2MjY2LDI3NjE3LDE0NzE5NiwyNzYxMiwyNzcwMywxNDA0MjcsMTQ5NzQ1LDE1ODU0NSwyNzczOCwzMzMxOCwyNzc2OSwxNDY4NzYsMTc2MDUsMTQ2ODc3LDE0Nzg3NiwxNDk3NzIsMTQ5NzYwLDE0NjYzMywxNDA1MywxNTU5NSwxMzQ0NTAsMzk4MTEsMTQzODY1LDE0MDQzMywzMjY1NSwyNjY3OSwxNTkwMTMsMTU5MTM3LDE1OTIxMSwyODA1NCwyNzk5NiwyODI4NCwyODQyMCwxNDk4ODcsMTQ3NTg5LDE1OTM0NiwzNDA5OSwxNTk2MDQsMjA5MzUsMjc4MDQsMjgxODksMzM4MzgsMTY2Njg5LDI4MjA3LDE0Njk5MSwyOTc3OSwxNDczMzAsMzExODAsMjgyMzksMjMxODUsMTQzNDM1LDI4NjY0LDE0MDkzLDI4NTczLDE0Njk5MiwyODQxMCwxMzYzNDMsMTQ3NTE3LDE3NzQ5LDM3ODcyLDI4NDg0LDI4NTA4LDE1Njk0LDI4NTMyLDE2ODMwNCwxNTY3NSwyODU3NSwxNDc3ODAsMjg2MjcsMTQ3NjAxLDE0Nzc5NywxNDc1MTMsMTQ3NDQwLDE0NzM4MCwxNDc3NzUsMjA5NTksMTQ3Nzk4LDE0Nzc5OSwxNDc3NzYsMTU2MTI1LDI4NzQ3LDI4Nzk4LDI4ODM5LDI4ODAxLDI4ODc2LDI4ODg1LDI4ODg2LDI4ODk1LDE2NjQ0LDE1ODQ4LDI5MTA4LDI5MDc4LDE0ODA4NywyODk3MSwyODk5NywyMzE3NiwyOTAwMiwyOTAzOCwyMzcwOCwxNDgzMjUsMjkwMDcsMzc3MzAsMTQ4MTYxLDI4OTcyLDE0ODU3MCwxNTAwNTUsMTUwMDUwLDI5MTE0LDE2Njg4OCwyODg2MSwyOTE5OCwzNzk1NCwyOTIwNSwyMjgwMSwzNzk1NSwyOTIyMCwzNzY5NywxNTMwOTMsMjkyMzAsMjkyNDgsMTQ5ODc2LDI2ODEzLDI5MjY5LDI5MjcxLDE1OTU3LDE0MzQyOCwyNjYzNywyODQ3NywyOTMxNCwyOTQ4MiwyOTQ4MywxNDk1MzksMTY1OTMxLDE4NjY5LDE2NTg5MiwyOTQ4MCwyOTQ4NiwyOTY0NywyOTYxMCwxMzQyMDIsMTU4MjU0LDI5NjQxLDI5NzY5LDE0NzkzOCwxMzY5MzUsMTUwMDUyLDI2MTQ3LDE0MDIxLDE0OTk0MywxNDk5MDEsMTUwMDExLDI5Njg3LDI5NzE3LDI2ODgzLDE1MDA1NCwyOTc1MywxMzI1NDcsMTYwODcsMjk3ODgsMTQxNDg1LDI5NzkyLDE2NzYwMiwyOTc2NywyOTY2OCwyOTgxNCwzMzcyMSwyOTgwNCwxNDEyOCwyOTgxMiwzNzg3MywyNzE4MCwyOTgyNiwxODc3MSwxNTAxNTYsMTQ3ODA3LDE1MDEzNywxNjY3OTksMjMzNjYsMTY2OTE1LDEzNzM3NCwyOTg5NiwxMzc2MDgsMjk5NjYsMjk5MjksMjk5ODIsMTY3NjQxLDEzNzgwMywyMzUxMSwxNjc1OTYsMzc3NjUsMzAwMjksMzAwMjYsMzAwNTUsMzAwNjIsMTUxNDI2LDE2MTMyLDE1MDgwMywzMDA5NCwyOTc4OSwzMDExMCwzMDEzMiwzMDIxMCwzMDI1MiwzMDI4OSwzMDI4NywzMDMxOSwzMDMyNiwxNTY2NjEsMzAzNTIsMzMyNjMsMTQzMjgsMTU3OTY5LDE1Nzk2NiwzMDM2OSwzMDM3MywzMDM5MSwzMDQxMiwxNTk2NDcsMzM4OTAsMTUxNzA5LDE1MTkzMywxMzg3ODAsMzA0OTQsMzA1MDIsMzA1MjgsMjU3NzUsMTUyMDk2LDMwNTUyLDE0NDA0NCwzMDYzOSwxNjYyNDQsMTY2MjQ4LDEzNjg5NywzMDcwOCwzMDcyOSwxMzYwNTQsMTUwMDM0LDI2ODI2LDMwODk1LDMwOTE5LDMwOTMxLDM4NTY1LDMxMDIyLDE1MzA1NiwzMDkzNSwzMTAyOCwzMDg5NywxNjEyOTIsMzY3OTIsMzQ5NDgsMTY2Njk5LDE1NTc3OSwxNDA4MjgsMzExMTAsMzUwNzIsMjY4ODIsMzExMDQsMTUzNjg3LDMxMTMzLDE2MjYxNywzMTAzNiwzMTE0NSwyODIwMiwxNjAwMzgsMTYwNDAsMzExNzQsMTY4MjA1LDMxMTg4XSxcbiAgXCJldWMta3JcIjpbNDQwMzQsNDQwMzUsNDQwMzcsNDQwMzgsNDQwNDMsNDQwNDQsNDQwNDUsNDQwNDYsNDQwNDcsNDQwNTYsNDQwNjIsNDQwNjMsNDQwNjUsNDQwNjYsNDQwNjcsNDQwNjksNDQwNzAsNDQwNzEsNDQwNzIsNDQwNzMsNDQwNzQsNDQwNzUsNDQwNzgsNDQwODIsNDQwODMsNDQwODQsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDQwODUsNDQwODYsNDQwODcsNDQwOTAsNDQwOTEsNDQwOTMsNDQwOTQsNDQwOTUsNDQwOTcsNDQwOTgsNDQwOTksNDQxMDAsNDQxMDEsNDQxMDIsNDQxMDMsNDQxMDQsNDQxMDUsNDQxMDYsNDQxMDgsNDQxMTAsNDQxMTEsNDQxMTIsNDQxMTMsNDQxMTQsNDQxMTUsNDQxMTcsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDQxMTgsNDQxMTksNDQxMjEsNDQxMjIsNDQxMjMsNDQxMjUsNDQxMjYsNDQxMjcsNDQxMjgsNDQxMjksNDQxMzAsNDQxMzEsNDQxMzIsNDQxMzMsNDQxMzQsNDQxMzUsNDQxMzYsNDQxMzcsNDQxMzgsNDQxMzksNDQxNDAsNDQxNDEsNDQxNDIsNDQxNDMsNDQxNDYsNDQxNDcsNDQxNDksNDQxNTAsNDQxNTMsNDQxNTUsNDQxNTYsNDQxNTcsNDQxNTgsNDQxNTksNDQxNjIsNDQxNjcsNDQxNjgsNDQxNzMsNDQxNzQsNDQxNzUsNDQxNzcsNDQxNzgsNDQxNzksNDQxODEsNDQxODIsNDQxODMsNDQxODQsNDQxODUsNDQxODYsNDQxODcsNDQxOTAsNDQxOTQsNDQxOTUsNDQxOTYsNDQxOTcsNDQxOTgsNDQxOTksNDQyMDMsNDQyMDUsNDQyMDYsNDQyMDksNDQyMTAsNDQyMTEsNDQyMTIsNDQyMTMsNDQyMTQsNDQyMTUsNDQyMTgsNDQyMjIsNDQyMjMsNDQyMjQsNDQyMjYsNDQyMjcsNDQyMjksNDQyMzAsNDQyMzEsNDQyMzMsNDQyMzQsNDQyMzUsNDQyMzcsNDQyMzgsNDQyMzksNDQyNDAsNDQyNDEsNDQyNDIsNDQyNDMsNDQyNDQsNDQyNDYsNDQyNDgsNDQyNDksNDQyNTAsNDQyNTEsNDQyNTIsNDQyNTMsNDQyNTQsNDQyNTUsNDQyNTgsNDQyNTksNDQyNjEsNDQyNjIsNDQyNjUsNDQyNjcsNDQyNjksNDQyNzAsNDQyNzQsNDQyNzYsNDQyNzksNDQyODAsNDQyODEsNDQyODIsNDQyODMsNDQyODYsNDQyODcsNDQyODksNDQyOTAsNDQyOTEsNDQyOTMsNDQyOTUsNDQyOTYsNDQyOTcsNDQyOTgsNDQyOTksNDQzMDIsNDQzMDQsNDQzMDYsNDQzMDcsNDQzMDgsNDQzMDksNDQzMTAsNDQzMTEsNDQzMTMsNDQzMTQsNDQzMTUsNDQzMTcsNDQzMTgsNDQzMTksNDQzMjEsNDQzMjIsNDQzMjMsNDQzMjQsNDQzMjUsNDQzMjYsNDQzMjcsNDQzMjgsNDQzMzAsNDQzMzEsNDQzMzQsNDQzMzUsNDQzMzYsNDQzMzcsNDQzMzgsNDQzMzksbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDQzNDIsNDQzNDMsNDQzNDUsNDQzNDYsNDQzNDcsNDQzNDksNDQzNTAsNDQzNTEsNDQzNTIsNDQzNTMsNDQzNTQsNDQzNTUsNDQzNTgsNDQzNjAsNDQzNjIsNDQzNjMsNDQzNjQsNDQzNjUsNDQzNjYsNDQzNjcsNDQzNjksNDQzNzAsNDQzNzEsNDQzNzMsNDQzNzQsNDQzNzUsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDQzNzcsNDQzNzgsNDQzNzksNDQzODAsNDQzODEsNDQzODIsNDQzODMsNDQzODQsNDQzODYsNDQzODgsNDQzODksNDQzOTAsNDQzOTEsNDQzOTIsNDQzOTMsNDQzOTQsNDQzOTUsNDQzOTgsNDQzOTksNDQ0MDEsNDQ0MDIsNDQ0MDcsNDQ0MDgsNDQ0MDksNDQ0MTAsNDQ0MTQsNDQ0MTYsNDQ0MTksNDQ0MjAsNDQ0MjEsNDQ0MjIsNDQ0MjMsNDQ0MjYsNDQ0MjcsNDQ0MjksNDQ0MzAsNDQ0MzEsNDQ0MzMsNDQ0MzQsNDQ0MzUsNDQ0MzYsNDQ0MzcsNDQ0MzgsNDQ0MzksNDQ0NDAsNDQ0NDEsNDQ0NDIsNDQ0NDMsNDQ0NDYsNDQ0NDcsNDQ0NDgsNDQ0NDksNDQ0NTAsNDQ0NTEsNDQ0NTMsNDQ0NTQsNDQ0NTUsNDQ0NTYsNDQ0NTcsNDQ0NTgsNDQ0NTksNDQ0NjAsNDQ0NjEsNDQ0NjIsNDQ0NjMsNDQ0NjQsNDQ0NjUsNDQ0NjYsNDQ0NjcsNDQ0NjgsNDQ0NjksNDQ0NzAsNDQ0NzIsNDQ0NzMsNDQ0NzQsNDQ0NzUsNDQ0NzYsNDQ0NzcsNDQ0NzgsNDQ0NzksNDQ0ODIsNDQ0ODMsNDQ0ODUsNDQ0ODYsNDQ0ODcsNDQ0ODksNDQ0OTAsNDQ0OTEsNDQ0OTIsNDQ0OTMsNDQ0OTQsNDQ0OTUsNDQ0OTgsNDQ1MDAsNDQ1MDEsNDQ1MDIsNDQ1MDMsNDQ1MDQsNDQ1MDUsNDQ1MDYsNDQ1MDcsNDQ1MDksNDQ1MTAsNDQ1MTEsNDQ1MTMsNDQ1MTQsNDQ1MTUsNDQ1MTcsNDQ1MTgsNDQ1MTksNDQ1MjAsNDQ1MjEsNDQ1MjIsNDQ1MjMsNDQ1MjQsNDQ1MjUsNDQ1MjYsNDQ1MjcsNDQ1MjgsNDQ1MjksNDQ1MzAsNDQ1MzEsNDQ1MzIsNDQ1MzMsNDQ1MzQsNDQ1MzUsNDQ1MzgsNDQ1MzksNDQ1NDEsNDQ1NDIsNDQ1NDYsNDQ1NDcsNDQ1NDgsNDQ1NDksNDQ1NTAsNDQ1NTEsNDQ1NTQsNDQ1NTYsNDQ1NTgsNDQ1NTksNDQ1NjAsNDQ1NjEsNDQ1NjIsNDQ1NjMsNDQ1NjUsNDQ1NjYsNDQ1NjcsNDQ1NjgsNDQ1NjksNDQ1NzAsNDQ1NzEsNDQ1NzIsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDQ1NzMsNDQ1NzQsNDQ1NzUsNDQ1NzYsNDQ1NzcsNDQ1NzgsNDQ1NzksNDQ1ODAsNDQ1ODEsNDQ1ODIsNDQ1ODMsNDQ1ODQsNDQ1ODUsNDQ1ODYsNDQ1ODcsNDQ1ODgsNDQ1ODksNDQ1OTAsNDQ1OTEsNDQ1OTQsNDQ1OTUsNDQ1OTcsNDQ1OTgsNDQ2MDEsNDQ2MDMsNDQ2MDQsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDQ2MDUsNDQ2MDYsNDQ2MDcsNDQ2MTAsNDQ2MTIsNDQ2MTUsNDQ2MTYsNDQ2MTcsNDQ2MTksNDQ2MjMsNDQ2MjUsNDQ2MjYsNDQ2MjcsNDQ2MjksNDQ2MzEsNDQ2MzIsNDQ2MzMsNDQ2MzQsNDQ2MzUsNDQ2MzgsNDQ2NDIsNDQ2NDMsNDQ2NDQsNDQ2NDYsNDQ2NDcsNDQ2NTAsNDQ2NTEsNDQ2NTMsNDQ2NTQsNDQ2NTUsNDQ2NTcsNDQ2NTgsNDQ2NTksNDQ2NjAsNDQ2NjEsNDQ2NjIsNDQ2NjMsNDQ2NjYsNDQ2NzAsNDQ2NzEsNDQ2NzIsNDQ2NzMsNDQ2NzQsNDQ2NzUsNDQ2NzgsNDQ2NzksNDQ2ODAsNDQ2ODEsNDQ2ODIsNDQ2ODMsNDQ2ODUsNDQ2ODYsNDQ2ODcsNDQ2ODgsNDQ2ODksNDQ2OTAsNDQ2OTEsNDQ2OTIsNDQ2OTMsNDQ2OTQsNDQ2OTUsNDQ2OTYsNDQ2OTcsNDQ2OTgsNDQ2OTksNDQ3MDAsNDQ3MDEsNDQ3MDIsNDQ3MDMsNDQ3MDQsNDQ3MDUsNDQ3MDYsNDQ3MDcsNDQ3MDgsNDQ3MDksNDQ3MTAsNDQ3MTEsNDQ3MTIsNDQ3MTMsNDQ3MTQsNDQ3MTUsNDQ3MTYsNDQ3MTcsNDQ3MTgsNDQ3MTksNDQ3MjAsNDQ3MjEsNDQ3MjIsNDQ3MjMsNDQ3MjQsNDQ3MjUsNDQ3MjYsNDQ3MjcsNDQ3MjgsNDQ3MjksNDQ3MzAsNDQ3MzEsNDQ3MzUsNDQ3MzcsNDQ3MzgsNDQ3MzksNDQ3NDEsNDQ3NDIsNDQ3NDMsNDQ3NDQsNDQ3NDUsNDQ3NDYsNDQ3NDcsNDQ3NTAsNDQ3NTQsNDQ3NTUsNDQ3NTYsNDQ3NTcsNDQ3NTgsNDQ3NTksNDQ3NjIsNDQ3NjMsNDQ3NjUsNDQ3NjYsNDQ3NjcsNDQ3NjgsNDQ3NjksNDQ3NzAsNDQ3NzEsNDQ3NzIsNDQ3NzMsNDQ3NzQsNDQ3NzUsNDQ3NzcsNDQ3NzgsNDQ3ODAsNDQ3ODIsNDQ3ODMsNDQ3ODQsNDQ3ODUsNDQ3ODYsNDQ3ODcsNDQ3ODksNDQ3OTAsNDQ3OTEsNDQ3OTMsNDQ3OTQsNDQ3OTUsNDQ3OTcsNDQ3OTgsNDQ3OTksNDQ4MDAsNDQ4MDEsNDQ4MDIsNDQ4MDMsNDQ4MDQsNDQ4MDUsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDQ4MDYsNDQ4MDksNDQ4MTAsNDQ4MTEsNDQ4MTIsNDQ4MTQsNDQ4MTUsNDQ4MTcsNDQ4MTgsNDQ4MTksNDQ4MjAsNDQ4MjEsNDQ4MjIsNDQ4MjMsNDQ4MjQsNDQ4MjUsNDQ4MjYsNDQ4MjcsNDQ4MjgsNDQ4MjksNDQ4MzAsNDQ4MzEsNDQ4MzIsNDQ4MzMsNDQ4MzQsNDQ4MzUsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDQ4MzYsNDQ4MzcsNDQ4MzgsNDQ4MzksNDQ4NDAsNDQ4NDEsNDQ4NDIsNDQ4NDMsNDQ4NDYsNDQ4NDcsNDQ4NDksNDQ4NTEsNDQ4NTMsNDQ4NTQsNDQ4NTUsNDQ4NTYsNDQ4NTcsNDQ4NTgsNDQ4NTksNDQ4NjIsNDQ4NjQsNDQ4NjgsNDQ4NjksNDQ4NzAsNDQ4NzEsNDQ4NzQsNDQ4NzUsNDQ4NzYsNDQ4NzcsNDQ4NzgsNDQ4NzksNDQ4ODEsNDQ4ODIsNDQ4ODMsNDQ4ODQsNDQ4ODUsNDQ4ODYsNDQ4ODcsNDQ4ODgsNDQ4ODksNDQ4OTAsNDQ4OTEsNDQ4OTQsNDQ4OTUsNDQ4OTYsNDQ4OTcsNDQ4OTgsNDQ4OTksNDQ5MDIsNDQ5MDMsNDQ5MDQsNDQ5MDUsNDQ5MDYsNDQ5MDcsNDQ5MDgsNDQ5MDksNDQ5MTAsNDQ5MTEsNDQ5MTIsNDQ5MTMsNDQ5MTQsNDQ5MTUsNDQ5MTYsNDQ5MTcsNDQ5MTgsNDQ5MTksNDQ5MjAsNDQ5MjIsNDQ5MjMsNDQ5MjQsNDQ5MjUsNDQ5MjYsNDQ5MjcsNDQ5MjksNDQ5MzAsNDQ5MzEsNDQ5MzMsNDQ5MzQsNDQ5MzUsNDQ5MzcsNDQ5MzgsNDQ5MzksNDQ5NDAsNDQ5NDEsNDQ5NDIsNDQ5NDMsNDQ5NDYsNDQ5NDcsNDQ5NDgsNDQ5NTAsNDQ5NTEsNDQ5NTIsNDQ5NTMsNDQ5NTQsNDQ5NTUsNDQ5NTcsNDQ5NTgsNDQ5NTksNDQ5NjAsNDQ5NjEsNDQ5NjIsNDQ5NjMsNDQ5NjQsNDQ5NjUsNDQ5NjYsNDQ5NjcsNDQ5NjgsNDQ5NjksNDQ5NzAsNDQ5NzEsNDQ5NzIsNDQ5NzMsNDQ5NzQsNDQ5NzUsNDQ5NzYsNDQ5NzcsNDQ5NzgsNDQ5NzksNDQ5ODAsNDQ5ODEsNDQ5ODIsNDQ5ODMsNDQ5ODYsNDQ5ODcsNDQ5ODksNDQ5OTAsNDQ5OTEsNDQ5OTMsNDQ5OTQsNDQ5OTUsNDQ5OTYsNDQ5OTcsNDQ5OTgsNDUwMDIsNDUwMDQsNDUwMDcsNDUwMDgsNDUwMDksNDUwMTAsNDUwMTEsNDUwMTMsNDUwMTQsNDUwMTUsNDUwMTYsNDUwMTcsNDUwMTgsNDUwMTksNDUwMjEsNDUwMjIsNDUwMjMsNDUwMjQsNDUwMjUsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDUwMjYsNDUwMjcsNDUwMjgsNDUwMjksNDUwMzAsNDUwMzEsNDUwMzQsNDUwMzUsNDUwMzYsNDUwMzcsNDUwMzgsNDUwMzksNDUwNDIsNDUwNDMsNDUwNDUsNDUwNDYsNDUwNDcsNDUwNDksNDUwNTAsNDUwNTEsNDUwNTIsNDUwNTMsNDUwNTQsNDUwNTUsNDUwNTgsNDUwNTksbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDUwNjEsNDUwNjIsNDUwNjMsNDUwNjQsNDUwNjUsNDUwNjYsNDUwNjcsNDUwNjksNDUwNzAsNDUwNzEsNDUwNzMsNDUwNzQsNDUwNzUsNDUwNzcsNDUwNzgsNDUwNzksNDUwODAsNDUwODEsNDUwODIsNDUwODMsNDUwODYsNDUwODcsNDUwODgsNDUwODksNDUwOTAsNDUwOTEsNDUwOTIsNDUwOTMsNDUwOTQsNDUwOTUsNDUwOTcsNDUwOTgsNDUwOTksNDUxMDAsNDUxMDEsNDUxMDIsNDUxMDMsNDUxMDQsNDUxMDUsNDUxMDYsNDUxMDcsNDUxMDgsNDUxMDksNDUxMTAsNDUxMTEsNDUxMTIsNDUxMTMsNDUxMTQsNDUxMTUsNDUxMTYsNDUxMTcsNDUxMTgsNDUxMTksNDUxMjAsNDUxMjEsNDUxMjIsNDUxMjMsNDUxMjYsNDUxMjcsNDUxMjksNDUxMzEsNDUxMzMsNDUxMzUsNDUxMzYsNDUxMzcsNDUxMzgsNDUxNDIsNDUxNDQsNDUxNDYsNDUxNDcsNDUxNDgsNDUxNTAsNDUxNTEsNDUxNTIsNDUxNTMsNDUxNTQsNDUxNTUsNDUxNTYsNDUxNTcsNDUxNTgsNDUxNTksNDUxNjAsNDUxNjEsNDUxNjIsNDUxNjMsNDUxNjQsNDUxNjUsNDUxNjYsNDUxNjcsNDUxNjgsNDUxNjksNDUxNzAsNDUxNzEsNDUxNzIsNDUxNzMsNDUxNzQsNDUxNzUsNDUxNzYsNDUxNzcsNDUxNzgsNDUxNzksNDUxODIsNDUxODMsNDUxODUsNDUxODYsNDUxODcsNDUxODksNDUxOTAsNDUxOTEsNDUxOTIsNDUxOTMsNDUxOTQsNDUxOTUsNDUxOTgsNDUyMDAsNDUyMDIsNDUyMDMsNDUyMDQsNDUyMDUsNDUyMDYsNDUyMDcsNDUyMTEsNDUyMTMsNDUyMTQsNDUyMTksNDUyMjAsNDUyMjEsNDUyMjIsNDUyMjMsNDUyMjYsNDUyMzIsNDUyMzQsNDUyMzgsNDUyMzksNDUyNDEsNDUyNDIsNDUyNDMsNDUyNDUsNDUyNDYsNDUyNDcsNDUyNDgsNDUyNDksNDUyNTAsNDUyNTEsNDUyNTQsNDUyNTgsNDUyNTksNDUyNjAsNDUyNjEsNDUyNjIsNDUyNjMsNDUyNjYsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDUyNjcsNDUyNjksNDUyNzAsNDUyNzEsNDUyNzMsNDUyNzQsNDUyNzUsNDUyNzYsNDUyNzcsNDUyNzgsNDUyNzksNDUyODEsNDUyODIsNDUyODMsNDUyODQsNDUyODYsNDUyODcsNDUyODgsNDUyODksNDUyOTAsNDUyOTEsNDUyOTIsNDUyOTMsNDUyOTQsNDUyOTUsNDUyOTYsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDUyOTcsNDUyOTgsNDUyOTksNDUzMDAsNDUzMDEsNDUzMDIsNDUzMDMsNDUzMDQsNDUzMDUsNDUzMDYsNDUzMDcsNDUzMDgsNDUzMDksNDUzMTAsNDUzMTEsNDUzMTIsNDUzMTMsNDUzMTQsNDUzMTUsNDUzMTYsNDUzMTcsNDUzMTgsNDUzMTksNDUzMjIsNDUzMjUsNDUzMjYsNDUzMjcsNDUzMjksNDUzMzIsNDUzMzMsNDUzMzQsNDUzMzUsNDUzMzgsNDUzNDIsNDUzNDMsNDUzNDQsNDUzNDUsNDUzNDYsNDUzNTAsNDUzNTEsNDUzNTMsNDUzNTQsNDUzNTUsNDUzNTcsNDUzNTgsNDUzNTksNDUzNjAsNDUzNjEsNDUzNjIsNDUzNjMsNDUzNjYsNDUzNzAsNDUzNzEsNDUzNzIsNDUzNzMsNDUzNzQsNDUzNzUsNDUzNzgsNDUzNzksNDUzODEsNDUzODIsNDUzODMsNDUzODUsNDUzODYsNDUzODcsNDUzODgsNDUzODksNDUzOTAsNDUzOTEsNDUzOTQsNDUzOTUsNDUzOTgsNDUzOTksNDU0MDEsNDU0MDIsNDU0MDMsNDU0MDUsNDU0MDYsNDU0MDcsNDU0MDksNDU0MTAsNDU0MTEsNDU0MTIsNDU0MTMsNDU0MTQsNDU0MTUsNDU0MTYsNDU0MTcsNDU0MTgsNDU0MTksNDU0MjAsNDU0MjEsNDU0MjIsNDU0MjMsNDU0MjQsNDU0MjUsNDU0MjYsNDU0MjcsNDU0MjgsNDU0MjksNDU0MzAsNDU0MzEsNDU0MzQsNDU0MzUsNDU0MzcsNDU0MzgsNDU0MzksNDU0NDEsNDU0NDMsNDU0NDQsNDU0NDUsNDU0NDYsNDU0NDcsNDU0NTAsNDU0NTIsNDU0NTQsNDU0NTUsNDU0NTYsNDU0NTcsNDU0NjEsNDU0NjIsNDU0NjMsNDU0NjUsNDU0NjYsNDU0NjcsNDU0NjksNDU0NzAsNDU0NzEsNDU0NzIsNDU0NzMsNDU0NzQsNDU0NzUsNDU0NzYsNDU0NzcsNDU0NzgsNDU0NzksNDU0ODEsNDU0ODIsNDU0ODMsNDU0ODQsNDU0ODUsNDU0ODYsNDU0ODcsNDU0ODgsNDU0ODksNDU0OTAsNDU0OTEsNDU0OTIsNDU0OTMsNDU0OTQsNDU0OTUsNDU0OTYsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDU0OTcsNDU0OTgsNDU0OTksNDU1MDAsNDU1MDEsNDU1MDIsNDU1MDMsNDU1MDQsNDU1MDUsNDU1MDYsNDU1MDcsNDU1MDgsNDU1MDksNDU1MTAsNDU1MTEsNDU1MTIsNDU1MTMsNDU1MTQsNDU1MTUsNDU1MTcsNDU1MTgsNDU1MTksNDU1MjEsNDU1MjIsNDU1MjMsNDU1MjUsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDU1MjYsNDU1MjcsNDU1MjgsNDU1MjksNDU1MzAsNDU1MzEsNDU1MzQsNDU1MzYsNDU1MzcsNDU1MzgsNDU1MzksNDU1NDAsNDU1NDEsNDU1NDIsNDU1NDMsNDU1NDYsNDU1NDcsNDU1NDksNDU1NTAsNDU1NTEsNDU1NTMsNDU1NTQsNDU1NTUsNDU1NTYsNDU1NTcsNDU1NTgsNDU1NTksNDU1NjAsNDU1NjIsNDU1NjQsNDU1NjYsNDU1NjcsNDU1NjgsNDU1NjksNDU1NzAsNDU1NzEsNDU1NzQsNDU1NzUsNDU1NzcsNDU1NzgsNDU1ODEsNDU1ODIsNDU1ODMsNDU1ODQsNDU1ODUsNDU1ODYsNDU1ODcsNDU1OTAsNDU1OTIsNDU1OTQsNDU1OTUsNDU1OTYsNDU1OTcsNDU1OTgsNDU1OTksNDU2MDEsNDU2MDIsNDU2MDMsNDU2MDQsNDU2MDUsNDU2MDYsNDU2MDcsNDU2MDgsNDU2MDksNDU2MTAsNDU2MTEsNDU2MTIsNDU2MTMsNDU2MTQsNDU2MTUsNDU2MTYsNDU2MTcsNDU2MTgsNDU2MTksNDU2MjEsNDU2MjIsNDU2MjMsNDU2MjQsNDU2MjUsNDU2MjYsNDU2MjcsNDU2MjksNDU2MzAsNDU2MzEsNDU2MzIsNDU2MzMsNDU2MzQsNDU2MzUsNDU2MzYsNDU2MzcsNDU2MzgsNDU2MzksNDU2NDAsNDU2NDEsNDU2NDIsNDU2NDMsNDU2NDQsNDU2NDUsNDU2NDYsNDU2NDcsNDU2NDgsNDU2NDksNDU2NTAsNDU2NTEsNDU2NTIsNDU2NTMsNDU2NTQsNDU2NTUsNDU2NTcsNDU2NTgsNDU2NTksNDU2NjEsNDU2NjIsNDU2NjMsNDU2NjUsNDU2NjYsNDU2NjcsNDU2NjgsNDU2NjksNDU2NzAsNDU2NzEsNDU2NzQsNDU2NzUsNDU2NzYsNDU2NzcsNDU2NzgsNDU2NzksNDU2ODAsNDU2ODEsNDU2ODIsNDU2ODMsNDU2ODYsNDU2ODcsNDU2ODgsNDU2ODksNDU2OTAsNDU2OTEsNDU2OTMsNDU2OTQsNDU2OTUsNDU2OTYsNDU2OTcsNDU2OTgsNDU2OTksNDU3MDIsNDU3MDMsNDU3MDQsNDU3MDYsNDU3MDcsNDU3MDgsNDU3MDksNDU3MTAsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDU3MTEsNDU3MTQsNDU3MTUsNDU3MTcsNDU3MTgsNDU3MTksNDU3MjMsNDU3MjQsNDU3MjUsNDU3MjYsNDU3MjcsNDU3MzAsNDU3MzIsNDU3MzUsNDU3MzYsNDU3MzcsNDU3MzksNDU3NDEsNDU3NDIsNDU3NDMsNDU3NDUsNDU3NDYsNDU3NDcsNDU3NDksNDU3NTAsNDU3NTEsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDU3NTIsNDU3NTMsNDU3NTQsNDU3NTUsNDU3NTYsNDU3NTcsNDU3NTgsNDU3NTksNDU3NjAsNDU3NjEsNDU3NjIsNDU3NjMsNDU3NjQsNDU3NjUsNDU3NjYsNDU3NjcsNDU3NzAsNDU3NzEsNDU3NzMsNDU3NzQsNDU3NzUsNDU3NzcsNDU3NzksNDU3ODAsNDU3ODEsNDU3ODIsNDU3ODMsNDU3ODYsNDU3ODgsNDU3OTAsNDU3OTEsNDU3OTIsNDU3OTMsNDU3OTUsNDU3OTksNDU4MDEsNDU4MDIsNDU4MDgsNDU4MDksNDU4MTAsNDU4MTQsNDU4MjAsNDU4MjEsNDU4MjIsNDU4MjYsNDU4MjcsNDU4MjksNDU4MzAsNDU4MzEsNDU4MzMsNDU4MzQsNDU4MzUsNDU4MzYsNDU4MzcsNDU4MzgsNDU4MzksNDU4NDIsNDU4NDYsNDU4NDcsNDU4NDgsNDU4NDksNDU4NTAsNDU4NTEsNDU4NTMsNDU4NTQsNDU4NTUsNDU4NTYsNDU4NTcsNDU4NTgsNDU4NTksNDU4NjAsNDU4NjEsNDU4NjIsNDU4NjMsNDU4NjQsNDU4NjUsNDU4NjYsNDU4NjcsNDU4NjgsNDU4NjksNDU4NzAsNDU4NzEsNDU4NzIsNDU4NzMsNDU4NzQsNDU4NzUsNDU4NzYsNDU4NzcsNDU4NzgsNDU4NzksNDU4ODAsNDU4ODEsNDU4ODIsNDU4ODMsNDU4ODQsNDU4ODUsNDU4ODYsNDU4ODcsNDU4ODgsNDU4ODksNDU4OTAsNDU4OTEsNDU4OTIsNDU4OTMsNDU4OTQsNDU4OTUsNDU4OTYsNDU4OTcsNDU4OTgsNDU4OTksNDU5MDAsNDU5MDEsNDU5MDIsNDU5MDMsNDU5MDQsNDU5MDUsNDU5MDYsNDU5MDcsNDU5MTEsNDU5MTMsNDU5MTQsNDU5MTcsNDU5MjAsNDU5MjEsNDU5MjIsNDU5MjMsNDU5MjYsNDU5MjgsNDU5MzAsNDU5MzIsNDU5MzMsNDU5MzUsNDU5MzgsNDU5MzksNDU5NDEsNDU5NDIsNDU5NDMsNDU5NDUsNDU5NDYsNDU5NDcsNDU5NDgsNDU5NDksNDU5NTAsNDU5NTEsNDU5NTQsNDU5NTgsNDU5NTksNDU5NjAsNDU5NjEsNDU5NjIsNDU5NjMsNDU5NjUsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDU5NjYsNDU5NjcsNDU5NjksNDU5NzAsNDU5NzEsNDU5NzMsNDU5NzQsNDU5NzUsNDU5NzYsNDU5NzcsNDU5NzgsNDU5NzksNDU5ODAsNDU5ODEsNDU5ODIsNDU5ODMsNDU5ODYsNDU5ODcsNDU5ODgsNDU5ODksNDU5OTAsNDU5OTEsNDU5OTMsNDU5OTQsNDU5OTUsNDU5OTcsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDU5OTgsNDU5OTksNDYwMDAsNDYwMDEsNDYwMDIsNDYwMDMsNDYwMDQsNDYwMDUsNDYwMDYsNDYwMDcsNDYwMDgsNDYwMDksNDYwMTAsNDYwMTEsNDYwMTIsNDYwMTMsNDYwMTQsNDYwMTUsNDYwMTYsNDYwMTcsNDYwMTgsNDYwMTksNDYwMjIsNDYwMjMsNDYwMjUsNDYwMjYsNDYwMjksNDYwMzEsNDYwMzMsNDYwMzQsNDYwMzUsNDYwMzgsNDYwNDAsNDYwNDIsNDYwNDQsNDYwNDYsNDYwNDcsNDYwNDksNDYwNTAsNDYwNTEsNDYwNTMsNDYwNTQsNDYwNTUsNDYwNTcsNDYwNTgsNDYwNTksNDYwNjAsNDYwNjEsNDYwNjIsNDYwNjMsNDYwNjQsNDYwNjUsNDYwNjYsNDYwNjcsNDYwNjgsNDYwNjksNDYwNzAsNDYwNzEsNDYwNzIsNDYwNzMsNDYwNzQsNDYwNzUsNDYwNzcsNDYwNzgsNDYwNzksNDYwODAsNDYwODEsNDYwODIsNDYwODMsNDYwODQsNDYwODUsNDYwODYsNDYwODcsNDYwODgsNDYwODksNDYwOTAsNDYwOTEsNDYwOTIsNDYwOTMsNDYwOTQsNDYwOTUsNDYwOTcsNDYwOTgsNDYwOTksNDYxMDAsNDYxMDEsNDYxMDIsNDYxMDMsNDYxMDUsNDYxMDYsNDYxMDcsNDYxMDksNDYxMTAsNDYxMTEsNDYxMTMsNDYxMTQsNDYxMTUsNDYxMTYsNDYxMTcsNDYxMTgsNDYxMTksNDYxMjIsNDYxMjQsNDYxMjUsNDYxMjYsNDYxMjcsNDYxMjgsNDYxMjksNDYxMzAsNDYxMzEsNDYxMzMsNDYxMzQsNDYxMzUsNDYxMzYsNDYxMzcsNDYxMzgsNDYxMzksNDYxNDAsNDYxNDEsNDYxNDIsNDYxNDMsNDYxNDQsNDYxNDUsNDYxNDYsNDYxNDcsNDYxNDgsNDYxNDksNDYxNTAsNDYxNTEsNDYxNTIsNDYxNTMsNDYxNTQsNDYxNTUsNDYxNTYsNDYxNTcsNDYxNTgsNDYxNTksNDYxNjIsNDYxNjMsNDYxNjUsNDYxNjYsNDYxNjcsNDYxNjksNDYxNzAsNDYxNzEsNDYxNzIsNDYxNzMsNDYxNzQsNDYxNzUsNDYxNzgsNDYxODAsNDYxODIsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDYxODMsNDYxODQsNDYxODUsNDYxODYsNDYxODcsNDYxODksNDYxOTAsNDYxOTEsNDYxOTIsNDYxOTMsNDYxOTQsNDYxOTUsNDYxOTYsNDYxOTcsNDYxOTgsNDYxOTksNDYyMDAsNDYyMDEsNDYyMDIsNDYyMDMsNDYyMDQsNDYyMDUsNDYyMDYsNDYyMDcsNDYyMDksNDYyMTAsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDYyMTEsNDYyMTIsNDYyMTMsNDYyMTQsNDYyMTUsNDYyMTcsNDYyMTgsNDYyMTksNDYyMjAsNDYyMjEsNDYyMjIsNDYyMjMsNDYyMjQsNDYyMjUsNDYyMjYsNDYyMjcsNDYyMjgsNDYyMjksNDYyMzAsNDYyMzEsNDYyMzIsNDYyMzMsNDYyMzQsNDYyMzUsNDYyMzYsNDYyMzgsNDYyMzksNDYyNDAsNDYyNDEsNDYyNDIsNDYyNDMsNDYyNDUsNDYyNDYsNDYyNDcsNDYyNDksNDYyNTAsNDYyNTEsNDYyNTMsNDYyNTQsNDYyNTUsNDYyNTYsNDYyNTcsNDYyNTgsNDYyNTksNDYyNjAsNDYyNjIsNDYyNjQsNDYyNjYsNDYyNjcsNDYyNjgsNDYyNjksNDYyNzAsNDYyNzEsNDYyNzMsNDYyNzQsNDYyNzUsNDYyNzcsNDYyNzgsNDYyNzksNDYyODEsNDYyODIsNDYyODMsNDYyODQsNDYyODUsNDYyODYsNDYyODcsNDYyODksNDYyOTAsNDYyOTEsNDYyOTIsNDYyOTQsNDYyOTUsNDYyOTYsNDYyOTcsNDYyOTgsNDYyOTksNDYzMDIsNDYzMDMsNDYzMDUsNDYzMDYsNDYzMDksNDYzMTEsNDYzMTIsNDYzMTMsNDYzMTQsNDYzMTUsNDYzMTgsNDYzMjAsNDYzMjIsNDYzMjMsNDYzMjQsNDYzMjUsNDYzMjYsNDYzMjcsNDYzMjksNDYzMzAsNDYzMzEsNDYzMzIsNDYzMzMsNDYzMzQsNDYzMzUsNDYzMzYsNDYzMzcsNDYzMzgsNDYzMzksNDYzNDAsNDYzNDEsNDYzNDIsNDYzNDMsNDYzNDQsNDYzNDUsNDYzNDYsNDYzNDcsNDYzNDgsNDYzNDksNDYzNTAsNDYzNTEsNDYzNTIsNDYzNTMsNDYzNTQsNDYzNTUsNDYzNTgsNDYzNTksNDYzNjEsNDYzNjIsNDYzNjUsNDYzNjYsNDYzNjcsNDYzNjgsNDYzNjksNDYzNzAsNDYzNzEsNDYzNzQsNDYzNzksNDYzODAsNDYzODEsNDYzODIsNDYzODMsNDYzODYsNDYzODcsNDYzODksNDYzOTAsNDYzOTEsNDYzOTMsNDYzOTQsNDYzOTUsNDYzOTYsNDYzOTcsNDYzOTgsNDYzOTksNDY0MDIsNDY0MDYsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDY0MDcsNDY0MDgsNDY0MDksNDY0MTAsNDY0MTQsNDY0MTUsNDY0MTcsNDY0MTgsNDY0MTksNDY0MjEsNDY0MjIsNDY0MjMsNDY0MjQsNDY0MjUsNDY0MjYsNDY0MjcsNDY0MzAsNDY0MzQsNDY0MzUsNDY0MzYsNDY0MzcsNDY0MzgsNDY0MzksNDY0NDAsNDY0NDEsNDY0NDIsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDY0NDMsNDY0NDQsNDY0NDUsNDY0NDYsNDY0NDcsNDY0NDgsNDY0NDksNDY0NTAsNDY0NTEsNDY0NTIsNDY0NTMsNDY0NTQsNDY0NTUsNDY0NTYsNDY0NTcsNDY0NTgsNDY0NTksNDY0NjAsNDY0NjEsNDY0NjIsNDY0NjMsNDY0NjQsNDY0NjUsNDY0NjYsNDY0NjcsNDY0NjgsNDY0NjksNDY0NzAsNDY0NzEsNDY0NzIsNDY0NzMsNDY0NzQsNDY0NzUsNDY0NzYsNDY0NzcsNDY0NzgsNDY0NzksNDY0ODAsNDY0ODEsNDY0ODIsNDY0ODMsNDY0ODQsNDY0ODUsNDY0ODYsNDY0ODcsNDY0ODgsNDY0ODksNDY0OTAsNDY0OTEsNDY0OTIsNDY0OTMsNDY0OTQsNDY0OTUsNDY0OTgsNDY0OTksNDY1MDEsNDY1MDIsNDY1MDMsNDY1MDUsNDY1MDgsNDY1MDksNDY1MTAsNDY1MTEsNDY1MTQsNDY1MTgsNDY1MTksNDY1MjAsNDY1MjEsNDY1MjIsNDY1MjYsNDY1MjcsNDY1MjksNDY1MzAsNDY1MzEsNDY1MzMsNDY1MzQsNDY1MzUsNDY1MzYsNDY1MzcsNDY1MzgsNDY1MzksNDY1NDIsNDY1NDYsNDY1NDcsNDY1NDgsNDY1NDksNDY1NTAsNDY1NTEsNDY1NTMsNDY1NTQsNDY1NTUsNDY1NTYsNDY1NTcsNDY1NTgsNDY1NTksNDY1NjAsNDY1NjEsNDY1NjIsNDY1NjMsNDY1NjQsNDY1NjUsNDY1NjYsNDY1NjcsNDY1NjgsNDY1NjksNDY1NzAsNDY1NzEsNDY1NzMsNDY1NzQsNDY1NzUsNDY1NzYsNDY1NzcsNDY1NzgsNDY1NzksNDY1ODAsNDY1ODEsNDY1ODIsNDY1ODMsNDY1ODQsNDY1ODUsNDY1ODYsNDY1ODcsNDY1ODgsNDY1ODksNDY1OTAsNDY1OTEsNDY1OTIsNDY1OTMsNDY1OTQsNDY1OTUsNDY1OTYsNDY1OTcsNDY1OTgsNDY1OTksNDY2MDAsNDY2MDEsNDY2MDIsNDY2MDMsNDY2MDQsNDY2MDUsNDY2MDYsNDY2MDcsNDY2MTAsNDY2MTEsNDY2MTMsNDY2MTQsNDY2MTUsNDY2MTcsNDY2MTgsNDY2MTksNDY2MjAsNDY2MjEsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDY2MjIsNDY2MjMsNDY2MjQsNDY2MjUsNDY2MjYsNDY2MjcsNDY2MjgsNDY2MzAsNDY2MzEsNDY2MzIsNDY2MzMsNDY2MzQsNDY2MzUsNDY2MzcsNDY2MzgsNDY2MzksNDY2NDAsNDY2NDEsNDY2NDIsNDY2NDMsNDY2NDUsNDY2NDYsNDY2NDcsNDY2NDgsNDY2NDksNDY2NTAsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDY2NTEsNDY2NTIsNDY2NTMsNDY2NTQsNDY2NTUsNDY2NTYsNDY2NTcsNDY2NTgsNDY2NTksNDY2NjAsNDY2NjEsNDY2NjIsNDY2NjMsNDY2NjUsNDY2NjYsNDY2NjcsNDY2NjgsNDY2NjksNDY2NzAsNDY2NzEsNDY2NzIsNDY2NzMsNDY2NzQsNDY2NzUsNDY2NzYsNDY2NzcsNDY2NzgsNDY2NzksNDY2ODAsNDY2ODEsNDY2ODIsNDY2ODMsNDY2ODQsNDY2ODUsNDY2ODYsNDY2ODcsNDY2ODgsNDY2ODksNDY2OTAsNDY2OTEsNDY2OTMsNDY2OTQsNDY2OTUsNDY2OTcsNDY2OTgsNDY2OTksNDY3MDAsNDY3MDEsNDY3MDIsNDY3MDMsNDY3MDQsNDY3MDUsNDY3MDYsNDY3MDcsNDY3MDgsNDY3MDksNDY3MTAsNDY3MTEsNDY3MTIsNDY3MTMsNDY3MTQsNDY3MTUsNDY3MTYsNDY3MTcsNDY3MTgsNDY3MTksNDY3MjAsNDY3MjEsNDY3MjIsNDY3MjMsNDY3MjQsNDY3MjUsNDY3MjYsNDY3MjcsNDY3MjgsNDY3MjksNDY3MzAsNDY3MzEsNDY3MzIsNDY3MzMsNDY3MzQsNDY3MzUsNDY3MzYsNDY3MzcsNDY3MzgsNDY3MzksNDY3NDAsNDY3NDEsNDY3NDIsNDY3NDMsNDY3NDQsNDY3NDUsNDY3NDYsNDY3NDcsNDY3NTAsNDY3NTEsNDY3NTMsNDY3NTQsNDY3NTUsNDY3NTcsNDY3NTgsNDY3NTksNDY3NjAsNDY3NjEsNDY3NjIsNDY3NjUsNDY3NjYsNDY3NjcsNDY3NjgsNDY3NzAsNDY3NzEsNDY3NzIsNDY3NzMsNDY3NzQsNDY3NzUsNDY3NzYsNDY3NzcsNDY3NzgsNDY3NzksNDY3ODAsNDY3ODEsNDY3ODIsNDY3ODMsNDY3ODQsNDY3ODUsNDY3ODYsNDY3ODcsNDY3ODgsNDY3ODksNDY3OTAsNDY3OTEsNDY3OTIsNDY3OTMsNDY3OTQsNDY3OTUsNDY3OTYsNDY3OTcsNDY3OTgsNDY3OTksNDY4MDAsNDY4MDEsNDY4MDIsNDY4MDMsNDY4MDUsNDY4MDYsNDY4MDcsNDY4MDgsNDY4MDksNDY4MTAsNDY4MTEsNDY4MTIsNDY4MTMsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDY4MTQsNDY4MTUsNDY4MTYsNDY4MTcsNDY4MTgsNDY4MTksNDY4MjAsNDY4MjEsNDY4MjIsNDY4MjMsNDY4MjQsNDY4MjUsNDY4MjYsNDY4MjcsNDY4MjgsNDY4MjksNDY4MzAsNDY4MzEsNDY4MzMsNDY4MzQsNDY4MzUsNDY4MzcsNDY4MzgsNDY4MzksNDY4NDEsNDY4NDIsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDY4NDMsNDY4NDQsNDY4NDUsNDY4NDYsNDY4NDcsNDY4NTAsNDY4NTEsNDY4NTIsNDY4NTQsNDY4NTUsNDY4NTYsNDY4NTcsNDY4NTgsNDY4NTksNDY4NjAsNDY4NjEsNDY4NjIsNDY4NjMsNDY4NjQsNDY4NjUsNDY4NjYsNDY4NjcsNDY4NjgsNDY4NjksNDY4NzAsNDY4NzEsNDY4NzIsNDY4NzMsNDY4NzQsNDY4NzUsNDY4NzYsNDY4NzcsNDY4NzgsNDY4NzksNDY4ODAsNDY4ODEsNDY4ODIsNDY4ODMsNDY4ODQsNDY4ODUsNDY4ODYsNDY4ODcsNDY4OTAsNDY4OTEsNDY4OTMsNDY4OTQsNDY4OTcsNDY4OTgsNDY4OTksNDY5MDAsNDY5MDEsNDY5MDIsNDY5MDMsNDY5MDYsNDY5MDgsNDY5MDksNDY5MTAsNDY5MTEsNDY5MTIsNDY5MTMsNDY5MTQsNDY5MTUsNDY5MTcsNDY5MTgsNDY5MTksNDY5MjEsNDY5MjIsNDY5MjMsNDY5MjUsNDY5MjYsNDY5MjcsNDY5MjgsNDY5MjksNDY5MzAsNDY5MzEsNDY5MzQsNDY5MzUsNDY5MzYsNDY5MzcsNDY5MzgsNDY5MzksNDY5NDAsNDY5NDEsNDY5NDIsNDY5NDMsNDY5NDUsNDY5NDYsNDY5NDcsNDY5NDksNDY5NTAsNDY5NTEsNDY5NTMsNDY5NTQsNDY5NTUsNDY5NTYsNDY5NTcsNDY5NTgsNDY5NTksNDY5NjIsNDY5NjQsNDY5NjYsNDY5NjcsNDY5NjgsNDY5NjksNDY5NzAsNDY5NzEsNDY5NzQsNDY5NzUsNDY5NzcsNDY5NzgsNDY5NzksNDY5ODEsNDY5ODIsNDY5ODMsNDY5ODQsNDY5ODUsNDY5ODYsNDY5ODcsNDY5OTAsNDY5OTUsNDY5OTYsNDY5OTcsNDcwMDIsNDcwMDMsNDcwMDUsNDcwMDYsNDcwMDcsNDcwMDksNDcwMTAsNDcwMTEsNDcwMTIsNDcwMTMsNDcwMTQsNDcwMTUsNDcwMTgsNDcwMjIsNDcwMjMsNDcwMjQsNDcwMjUsNDcwMjYsNDcwMjcsNDcwMzAsNDcwMzEsNDcwMzMsNDcwMzQsNDcwMzUsNDcwMzYsNDcwMzcsNDcwMzgsNDcwMzksNDcwNDAsNDcwNDEsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDcwNDIsNDcwNDMsNDcwNDQsNDcwNDUsNDcwNDYsNDcwNDgsNDcwNTAsNDcwNTEsNDcwNTIsNDcwNTMsNDcwNTQsNDcwNTUsNDcwNTYsNDcwNTcsNDcwNTgsNDcwNTksNDcwNjAsNDcwNjEsNDcwNjIsNDcwNjMsNDcwNjQsNDcwNjUsNDcwNjYsNDcwNjcsNDcwNjgsNDcwNjksbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDcwNzAsNDcwNzEsNDcwNzIsNDcwNzMsNDcwNzQsNDcwNzUsNDcwNzYsNDcwNzcsNDcwNzgsNDcwNzksNDcwODAsNDcwODEsNDcwODIsNDcwODMsNDcwODYsNDcwODcsNDcwODksNDcwOTAsNDcwOTEsNDcwOTMsNDcwOTQsNDcwOTUsNDcwOTYsNDcwOTcsNDcwOTgsNDcwOTksNDcxMDIsNDcxMDYsNDcxMDcsNDcxMDgsNDcxMDksNDcxMTAsNDcxMTQsNDcxMTUsNDcxMTcsNDcxMTgsNDcxMTksNDcxMjEsNDcxMjIsNDcxMjMsNDcxMjQsNDcxMjUsNDcxMjYsNDcxMjcsNDcxMzAsNDcxMzIsNDcxMzQsNDcxMzUsNDcxMzYsNDcxMzcsNDcxMzgsNDcxMzksNDcxNDIsNDcxNDMsNDcxNDUsNDcxNDYsNDcxNDcsNDcxNDksNDcxNTAsNDcxNTEsNDcxNTIsNDcxNTMsNDcxNTQsNDcxNTUsNDcxNTgsNDcxNjIsNDcxNjMsNDcxNjQsNDcxNjUsNDcxNjYsNDcxNjcsNDcxNjksNDcxNzAsNDcxNzEsNDcxNzMsNDcxNzQsNDcxNzUsNDcxNzYsNDcxNzcsNDcxNzgsNDcxNzksNDcxODAsNDcxODEsNDcxODIsNDcxODMsNDcxODQsNDcxODYsNDcxODgsNDcxODksNDcxOTAsNDcxOTEsNDcxOTIsNDcxOTMsNDcxOTQsNDcxOTUsNDcxOTgsNDcxOTksNDcyMDEsNDcyMDIsNDcyMDMsNDcyMDUsNDcyMDYsNDcyMDcsNDcyMDgsNDcyMDksNDcyMTAsNDcyMTEsNDcyMTQsNDcyMTYsNDcyMTgsNDcyMTksNDcyMjAsNDcyMjEsNDcyMjIsNDcyMjMsNDcyMjUsNDcyMjYsNDcyMjcsNDcyMjksNDcyMzAsNDcyMzEsNDcyMzIsNDcyMzMsNDcyMzQsNDcyMzUsNDcyMzYsNDcyMzcsNDcyMzgsNDcyMzksNDcyNDAsNDcyNDEsNDcyNDIsNDcyNDMsNDcyNDQsNDcyNDYsNDcyNDcsNDcyNDgsNDcyNDksNDcyNTAsNDcyNTEsNDcyNTIsNDcyNTMsNDcyNTQsNDcyNTUsNDcyNTYsNDcyNTcsNDcyNTgsNDcyNTksNDcyNjAsNDcyNjEsNDcyNjIsNDcyNjMsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDcyNjQsNDcyNjUsNDcyNjYsNDcyNjcsNDcyNjgsNDcyNjksNDcyNzAsNDcyNzEsNDcyNzMsNDcyNzQsNDcyNzUsNDcyNzYsNDcyNzcsNDcyNzgsNDcyNzksNDcyODEsNDcyODIsNDcyODMsNDcyODUsNDcyODYsNDcyODcsNDcyODksNDcyOTAsNDcyOTEsNDcyOTIsNDcyOTMsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDcyOTQsNDcyOTUsNDcyOTgsNDczMDAsNDczMDIsNDczMDMsNDczMDQsNDczMDUsNDczMDYsNDczMDcsNDczMDksNDczMTAsNDczMTEsNDczMTMsNDczMTQsNDczMTUsNDczMTcsNDczMTgsNDczMTksNDczMjAsNDczMjEsNDczMjIsNDczMjMsNDczMjQsNDczMjYsNDczMjgsNDczMzAsNDczMzEsNDczMzIsNDczMzMsNDczMzQsNDczMzUsNDczMzgsNDczMzksNDczNDEsNDczNDIsNDczNDMsNDczNDUsNDczNDYsNDczNDcsNDczNDgsNDczNDksNDczNTAsNDczNTEsNDczNTQsNDczNTYsNDczNTgsNDczNTksNDczNjAsNDczNjEsNDczNjIsNDczNjMsNDczNjUsNDczNjYsNDczNjcsNDczNjgsNDczNjksNDczNzAsNDczNzEsNDczNzIsNDczNzMsNDczNzQsNDczNzUsNDczNzYsNDczNzcsNDczNzgsNDczNzksNDczODAsNDczODEsNDczODIsNDczODMsNDczODUsNDczODYsNDczODcsNDczODgsNDczODksNDczOTAsNDczOTEsNDczOTMsNDczOTQsNDczOTUsNDczOTYsNDczOTcsNDczOTgsNDczOTksNDc0MDAsNDc0MDEsNDc0MDIsNDc0MDMsNDc0MDQsNDc0MDUsNDc0MDYsNDc0MDcsNDc0MDgsNDc0MDksNDc0MTAsNDc0MTEsNDc0MTIsNDc0MTMsNDc0MTQsNDc0MTUsNDc0MTYsNDc0MTcsNDc0MTgsNDc0MTksNDc0MjIsNDc0MjMsNDc0MjUsNDc0MjYsNDc0MjcsNDc0MjksNDc0MzAsNDc0MzEsNDc0MzIsNDc0MzMsNDc0MzQsNDc0MzUsNDc0MzcsNDc0MzgsNDc0NDAsNDc0NDIsNDc0NDMsNDc0NDQsNDc0NDUsNDc0NDYsNDc0NDcsNDc0NTAsNDc0NTEsNDc0NTMsNDc0NTQsNDc0NTUsNDc0NTcsNDc0NTgsNDc0NTksNDc0NjAsNDc0NjEsNDc0NjIsNDc0NjMsNDc0NjYsNDc0NjgsNDc0NzAsNDc0NzEsNDc0NzIsNDc0NzMsNDc0NzQsNDc0NzUsNDc0NzgsNDc0NzksNDc0ODEsNDc0ODIsNDc0ODMsNDc0ODUsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDc0ODYsNDc0ODcsNDc0ODgsNDc0ODksNDc0OTAsNDc0OTEsNDc0OTQsNDc0OTYsNDc0OTksNDc1MDAsNDc1MDMsNDc1MDQsNDc1MDUsNDc1MDYsNDc1MDcsNDc1MDgsNDc1MDksNDc1MTAsNDc1MTEsNDc1MTIsNDc1MTMsNDc1MTQsNDc1MTUsNDc1MTYsNDc1MTcsNDc1MTgsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDc1MTksNDc1MjAsNDc1MjEsNDc1MjIsNDc1MjMsNDc1MjQsNDc1MjUsNDc1MjYsNDc1MjcsNDc1MjgsNDc1MjksNDc1MzAsNDc1MzEsNDc1MzQsNDc1MzUsNDc1MzcsNDc1MzgsNDc1MzksNDc1NDEsNDc1NDIsNDc1NDMsNDc1NDQsNDc1NDUsNDc1NDYsNDc1NDcsNDc1NTAsNDc1NTIsNDc1NTQsNDc1NTUsNDc1NTYsNDc1NTcsNDc1NTgsNDc1NTksNDc1NjIsNDc1NjMsNDc1NjUsNDc1NzEsNDc1NzIsNDc1NzMsNDc1NzQsNDc1NzUsNDc1NzgsNDc1ODAsNDc1ODMsNDc1ODQsNDc1ODYsNDc1OTAsNDc1OTEsNDc1OTMsNDc1OTQsNDc1OTUsNDc1OTcsNDc1OTgsNDc1OTksNDc2MDAsNDc2MDEsNDc2MDIsNDc2MDMsNDc2MDYsNDc2MTEsNDc2MTIsNDc2MTMsNDc2MTQsNDc2MTUsNDc2MTgsNDc2MTksNDc2MjAsNDc2MjEsNDc2MjIsNDc2MjMsNDc2MjUsNDc2MjYsNDc2MjcsNDc2MjgsNDc2MjksNDc2MzAsNDc2MzEsNDc2MzIsNDc2MzMsNDc2MzQsNDc2MzUsNDc2MzYsNDc2MzgsNDc2MzksNDc2NDAsNDc2NDEsNDc2NDIsNDc2NDMsNDc2NDQsNDc2NDUsNDc2NDYsNDc2NDcsNDc2NDgsNDc2NDksNDc2NTAsNDc2NTEsNDc2NTIsNDc2NTMsNDc2NTQsNDc2NTUsNDc2NTYsNDc2NTcsNDc2NTgsNDc2NTksNDc2NjAsNDc2NjEsNDc2NjIsNDc2NjMsNDc2NjQsNDc2NjUsNDc2NjYsNDc2NjcsNDc2NjgsNDc2NjksNDc2NzAsNDc2NzEsNDc2NzQsNDc2NzUsNDc2NzcsNDc2NzgsNDc2NzksNDc2ODEsNDc2ODMsNDc2ODQsNDc2ODUsNDc2ODYsNDc2ODcsNDc2OTAsNDc2OTIsNDc2OTUsNDc2OTYsNDc2OTcsNDc2OTgsNDc3MDIsNDc3MDMsNDc3MDUsNDc3MDYsNDc3MDcsNDc3MDksNDc3MTAsNDc3MTEsNDc3MTIsNDc3MTMsNDc3MTQsNDc3MTUsNDc3MTgsNDc3MjIsNDc3MjMsNDc3MjQsNDc3MjUsNDc3MjYsNDc3MjcsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDc3MzAsNDc3MzEsNDc3MzMsNDc3MzQsNDc3MzUsNDc3MzcsNDc3MzgsNDc3MzksNDc3NDAsNDc3NDEsNDc3NDIsNDc3NDMsNDc3NDQsNDc3NDUsNDc3NDYsNDc3NTAsNDc3NTIsNDc3NTMsNDc3NTQsNDc3NTUsNDc3NTcsNDc3NTgsNDc3NTksNDc3NjAsNDc3NjEsNDc3NjIsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDc3NjMsNDc3NjQsNDc3NjUsNDc3NjYsNDc3NjcsNDc3NjgsNDc3NjksNDc3NzAsNDc3NzEsNDc3NzIsNDc3NzMsNDc3NzQsNDc3NzUsNDc3NzYsNDc3NzcsNDc3NzgsNDc3NzksNDc3ODAsNDc3ODEsNDc3ODIsNDc3ODMsNDc3ODYsNDc3ODksNDc3OTAsNDc3OTEsNDc3OTMsNDc3OTUsNDc3OTYsNDc3OTcsNDc3OTgsNDc3OTksNDc4MDIsNDc4MDQsNDc4MDYsNDc4MDcsNDc4MDgsNDc4MDksNDc4MTAsNDc4MTEsNDc4MTMsNDc4MTQsNDc4MTUsNDc4MTcsNDc4MTgsNDc4MTksNDc4MjAsNDc4MjEsNDc4MjIsNDc4MjMsNDc4MjQsNDc4MjUsNDc4MjYsNDc4MjcsNDc4MjgsNDc4MjksNDc4MzAsNDc4MzEsNDc4MzQsNDc4MzUsNDc4MzYsNDc4MzcsNDc4MzgsNDc4MzksNDc4NDAsNDc4NDEsNDc4NDIsNDc4NDMsNDc4NDQsNDc4NDUsNDc4NDYsNDc4NDcsNDc4NDgsNDc4NDksNDc4NTAsNDc4NTEsNDc4NTIsNDc4NTMsNDc4NTQsNDc4NTUsNDc4NTYsNDc4NTcsNDc4NTgsNDc4NTksNDc4NjAsNDc4NjEsNDc4NjIsNDc4NjMsNDc4NjQsNDc4NjUsNDc4NjYsNDc4NjcsNDc4NjksNDc4NzAsNDc4NzEsNDc4NzMsNDc4NzQsNDc4NzUsNDc4NzcsNDc4NzgsNDc4NzksNDc4ODAsNDc4ODEsNDc4ODIsNDc4ODMsNDc4ODQsNDc4ODYsNDc4ODgsNDc4OTAsNDc4OTEsNDc4OTIsNDc4OTMsNDc4OTQsNDc4OTUsNDc4OTcsNDc4OTgsNDc4OTksNDc5MDEsNDc5MDIsNDc5MDMsNDc5MDUsNDc5MDYsNDc5MDcsNDc5MDgsNDc5MDksNDc5MTAsNDc5MTEsNDc5MTIsNDc5MTQsNDc5MTYsNDc5MTcsNDc5MTgsNDc5MTksNDc5MjAsNDc5MjEsNDc5MjIsNDc5MjMsNDc5MjcsNDc5MjksNDc5MzAsNDc5MzUsNDc5MzYsNDc5MzcsNDc5MzgsNDc5MzksNDc5NDIsNDc5NDQsNDc5NDYsNDc5NDcsNDc5NDgsNDc5NTAsNDc5NTMsNDc5NTQsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDc5NTUsNDc5NTcsNDc5NTgsNDc5NTksNDc5NjEsNDc5NjIsNDc5NjMsNDc5NjQsNDc5NjUsNDc5NjYsNDc5NjcsNDc5NjgsNDc5NzAsNDc5NzIsNDc5NzMsNDc5NzQsNDc5NzUsNDc5NzYsNDc5NzcsNDc5NzgsNDc5NzksNDc5ODEsNDc5ODIsNDc5ODMsNDc5ODQsNDc5ODUsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDc5ODYsNDc5ODcsNDc5ODgsNDc5ODksNDc5OTAsNDc5OTEsNDc5OTIsNDc5OTMsNDc5OTQsNDc5OTUsNDc5OTYsNDc5OTcsNDc5OTgsNDc5OTksNDgwMDAsNDgwMDEsNDgwMDIsNDgwMDMsNDgwMDQsNDgwMDUsNDgwMDYsNDgwMDcsNDgwMDksNDgwMTAsNDgwMTEsNDgwMTMsNDgwMTQsNDgwMTUsNDgwMTcsNDgwMTgsNDgwMTksNDgwMjAsNDgwMjEsNDgwMjIsNDgwMjMsNDgwMjQsNDgwMjUsNDgwMjYsNDgwMjcsNDgwMjgsNDgwMjksNDgwMzAsNDgwMzEsNDgwMzIsNDgwMzMsNDgwMzQsNDgwMzUsNDgwMzcsNDgwMzgsNDgwMzksNDgwNDEsNDgwNDIsNDgwNDMsNDgwNDUsNDgwNDYsNDgwNDcsNDgwNDgsNDgwNDksNDgwNTAsNDgwNTEsNDgwNTMsNDgwNTQsNDgwNTYsNDgwNTcsNDgwNTgsNDgwNTksNDgwNjAsNDgwNjEsNDgwNjIsNDgwNjMsNDgwNjUsNDgwNjYsNDgwNjcsNDgwNjksNDgwNzAsNDgwNzEsNDgwNzMsNDgwNzQsNDgwNzUsNDgwNzYsNDgwNzcsNDgwNzgsNDgwNzksNDgwODEsNDgwODIsNDgwODQsNDgwODUsNDgwODYsNDgwODcsNDgwODgsNDgwODksNDgwOTAsNDgwOTEsNDgwOTIsNDgwOTMsNDgwOTQsNDgwOTUsNDgwOTYsNDgwOTcsNDgwOTgsNDgwOTksNDgxMDAsNDgxMDEsNDgxMDIsNDgxMDMsNDgxMDQsNDgxMDUsNDgxMDYsNDgxMDcsNDgxMDgsNDgxMDksNDgxMTAsNDgxMTEsNDgxMTIsNDgxMTMsNDgxMTQsNDgxMTUsNDgxMTYsNDgxMTcsNDgxMTgsNDgxMTksNDgxMjIsNDgxMjMsNDgxMjUsNDgxMjYsNDgxMjksNDgxMzEsNDgxMzIsNDgxMzMsNDgxMzQsNDgxMzUsNDgxMzgsNDgxNDIsNDgxNDQsNDgxNDYsNDgxNDcsNDgxNTMsNDgxNTQsNDgxNjAsNDgxNjEsNDgxNjIsNDgxNjMsNDgxNjYsNDgxNjgsNDgxNzAsNDgxNzEsNDgxNzIsNDgxNzQsNDgxNzUsNDgxNzgsNDgxNzksNDgxODEsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDgxODIsNDgxODMsNDgxODUsNDgxODYsNDgxODcsNDgxODgsNDgxODksNDgxOTAsNDgxOTEsNDgxOTQsNDgxOTgsNDgxOTksNDgyMDAsNDgyMDIsNDgyMDMsNDgyMDYsNDgyMDcsNDgyMDksNDgyMTAsNDgyMTEsNDgyMTIsNDgyMTMsNDgyMTQsNDgyMTUsNDgyMTYsNDgyMTcsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDgyMTgsNDgyMTksNDgyMjAsNDgyMjIsNDgyMjMsNDgyMjQsNDgyMjUsNDgyMjYsNDgyMjcsNDgyMjgsNDgyMjksNDgyMzAsNDgyMzEsNDgyMzIsNDgyMzMsNDgyMzQsNDgyMzUsNDgyMzYsNDgyMzcsNDgyMzgsNDgyMzksNDgyNDAsNDgyNDEsNDgyNDIsNDgyNDMsNDgyNDQsNDgyNDUsNDgyNDYsNDgyNDcsNDgyNDgsNDgyNDksNDgyNTAsNDgyNTEsNDgyNTIsNDgyNTMsNDgyNTQsNDgyNTUsNDgyNTYsNDgyNTcsNDgyNTgsNDgyNTksNDgyNjIsNDgyNjMsNDgyNjUsNDgyNjYsNDgyNjksNDgyNzEsNDgyNzIsNDgyNzMsNDgyNzQsNDgyNzUsNDgyNzgsNDgyODAsNDgyODMsNDgyODQsNDgyODUsNDgyODYsNDgyODcsNDgyOTAsNDgyOTEsNDgyOTMsNDgyOTQsNDgyOTcsNDgyOTgsNDgyOTksNDgzMDAsNDgzMDEsNDgzMDIsNDgzMDMsNDgzMDYsNDgzMTAsNDgzMTEsNDgzMTIsNDgzMTMsNDgzMTQsNDgzMTUsNDgzMTgsNDgzMTksNDgzMjEsNDgzMjIsNDgzMjMsNDgzMjUsNDgzMjYsNDgzMjcsNDgzMjgsNDgzMjksNDgzMzAsNDgzMzEsNDgzMzIsNDgzMzQsNDgzMzgsNDgzMzksNDgzNDAsNDgzNDIsNDgzNDMsNDgzNDUsNDgzNDYsNDgzNDcsNDgzNDksNDgzNTAsNDgzNTEsNDgzNTIsNDgzNTMsNDgzNTQsNDgzNTUsNDgzNTYsNDgzNTcsNDgzNTgsNDgzNTksNDgzNjAsNDgzNjEsNDgzNjIsNDgzNjMsNDgzNjQsNDgzNjUsNDgzNjYsNDgzNjcsNDgzNjgsNDgzNjksNDgzNzAsNDgzNzEsNDgzNzUsNDgzNzcsNDgzNzgsNDgzNzksNDgzODEsNDgzODIsNDgzODMsNDgzODQsNDgzODUsNDgzODYsNDgzODcsNDgzOTAsNDgzOTIsNDgzOTQsNDgzOTUsNDgzOTYsNDgzOTcsNDgzOTgsNDgzOTksNDg0MDEsNDg0MDIsNDg0MDMsNDg0MDUsNDg0MDYsNDg0MDcsNDg0MDgsNDg0MDksNDg0MTAsNDg0MTEsNDg0MTIsNDg0MTMsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDg0MTQsNDg0MTUsNDg0MTYsNDg0MTcsNDg0MTgsNDg0MTksNDg0MjEsNDg0MjIsNDg0MjMsNDg0MjQsNDg0MjUsNDg0MjYsNDg0MjcsNDg0MjksNDg0MzAsNDg0MzEsNDg0MzIsNDg0MzMsNDg0MzQsNDg0MzUsNDg0MzYsNDg0MzcsNDg0MzgsNDg0MzksNDg0NDAsNDg0NDEsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDg0NDIsNDg0NDMsNDg0NDQsNDg0NDUsNDg0NDYsNDg0NDcsNDg0NDksNDg0NTAsNDg0NTEsNDg0NTIsNDg0NTMsNDg0NTQsNDg0NTUsNDg0NTgsNDg0NTksNDg0NjEsNDg0NjIsNDg0NjMsNDg0NjUsNDg0NjYsNDg0NjcsNDg0NjgsNDg0NjksNDg0NzAsNDg0NzEsNDg0NzQsNDg0NzUsNDg0NzYsNDg0NzcsNDg0NzgsNDg0NzksNDg0ODAsNDg0ODEsNDg0ODIsNDg0ODMsNDg0ODUsNDg0ODYsNDg0ODcsNDg0ODksNDg0OTAsNDg0OTEsNDg0OTIsNDg0OTMsNDg0OTQsNDg0OTUsNDg0OTYsNDg0OTcsNDg0OTgsNDg0OTksNDg1MDAsNDg1MDEsNDg1MDIsNDg1MDMsNDg1MDQsNDg1MDUsNDg1MDYsNDg1MDcsNDg1MDgsNDg1MDksNDg1MTAsNDg1MTEsNDg1MTQsNDg1MTUsNDg1MTcsNDg1MTgsNDg1MjMsNDg1MjQsNDg1MjUsNDg1MjYsNDg1MjcsNDg1MzAsNDg1MzIsNDg1MzQsNDg1MzUsNDg1MzYsNDg1MzksNDg1NDEsNDg1NDIsNDg1NDMsNDg1NDQsNDg1NDUsNDg1NDYsNDg1NDcsNDg1NDksNDg1NTAsNDg1NTEsNDg1NTIsNDg1NTMsNDg1NTQsNDg1NTUsNDg1NTYsNDg1NTcsNDg1NTgsNDg1NTksNDg1NjEsNDg1NjIsNDg1NjMsNDg1NjQsNDg1NjUsNDg1NjYsNDg1NjcsNDg1NjksNDg1NzAsNDg1NzEsNDg1NzIsNDg1NzMsNDg1NzQsNDg1NzUsNDg1NzYsNDg1NzcsNDg1NzgsNDg1NzksNDg1ODAsNDg1ODEsNDg1ODIsNDg1ODMsNDg1ODQsNDg1ODUsNDg1ODYsNDg1ODcsNDg1ODgsNDg1ODksNDg1OTAsNDg1OTEsNDg1OTIsNDg1OTMsNDg1OTQsNDg1OTUsNDg1OTgsNDg1OTksNDg2MDEsNDg2MDIsNDg2MDMsNDg2MDUsNDg2MDYsNDg2MDcsNDg2MDgsNDg2MDksNDg2MTAsNDg2MTEsNDg2MTIsNDg2MTMsNDg2MTQsNDg2MTUsNDg2MTYsNDg2MTgsNDg2MTksNDg2MjAsNDg2MjEsNDg2MjIsNDg2MjMsNDg2MjUsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDg2MjYsNDg2MjcsNDg2MjksNDg2MzAsNDg2MzEsNDg2MzMsNDg2MzQsNDg2MzUsNDg2MzYsNDg2MzcsNDg2MzgsNDg2MzksNDg2NDEsNDg2NDIsNDg2NDQsNDg2NDYsNDg2NDcsNDg2NDgsNDg2NDksNDg2NTAsNDg2NTEsNDg2NTQsNDg2NTUsNDg2NTcsNDg2NTgsNDg2NTksbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDg2NjEsNDg2NjIsNDg2NjMsNDg2NjQsNDg2NjUsNDg2NjYsNDg2NjcsNDg2NzAsNDg2NzIsNDg2NzMsNDg2NzQsNDg2NzUsNDg2NzYsNDg2NzcsNDg2NzgsNDg2NzksNDg2ODAsNDg2ODEsNDg2ODIsNDg2ODMsNDg2ODQsNDg2ODUsNDg2ODYsNDg2ODcsNDg2ODgsNDg2ODksNDg2OTAsNDg2OTEsNDg2OTIsNDg2OTMsNDg2OTQsNDg2OTUsNDg2OTYsNDg2OTcsNDg2OTgsNDg2OTksNDg3MDAsNDg3MDEsNDg3MDIsNDg3MDMsNDg3MDQsNDg3MDUsNDg3MDYsNDg3MDcsNDg3MTAsNDg3MTEsNDg3MTMsNDg3MTQsNDg3MTUsNDg3MTcsNDg3MTksNDg3MjAsNDg3MjEsNDg3MjIsNDg3MjMsNDg3MjYsNDg3MjgsNDg3MzIsNDg3MzMsNDg3MzQsNDg3MzUsNDg3MzgsNDg3MzksNDg3NDEsNDg3NDIsNDg3NDMsNDg3NDUsNDg3NDcsNDg3NDgsNDg3NDksNDg3NTAsNDg3NTEsNDg3NTQsNDg3NTgsNDg3NTksNDg3NjAsNDg3NjEsNDg3NjIsNDg3NjYsNDg3NjcsNDg3NjksNDg3NzAsNDg3NzEsNDg3NzMsNDg3NzQsNDg3NzUsNDg3NzYsNDg3NzcsNDg3NzgsNDg3NzksNDg3ODIsNDg3ODYsNDg3ODcsNDg3ODgsNDg3ODksNDg3OTAsNDg3OTEsNDg3OTQsNDg3OTUsNDg3OTYsNDg3OTcsNDg3OTgsNDg3OTksNDg4MDAsNDg4MDEsNDg4MDIsNDg4MDMsNDg4MDQsNDg4MDUsNDg4MDYsNDg4MDcsNDg4MDksNDg4MTAsNDg4MTEsNDg4MTIsNDg4MTMsNDg4MTQsNDg4MTUsNDg4MTYsNDg4MTcsNDg4MTgsNDg4MTksNDg4MjAsNDg4MjEsNDg4MjIsNDg4MjMsNDg4MjQsNDg4MjUsNDg4MjYsNDg4MjcsNDg4MjgsNDg4MjksNDg4MzAsNDg4MzEsNDg4MzIsNDg4MzMsNDg4MzQsNDg4MzUsNDg4MzYsNDg4MzcsNDg4MzgsNDg4MzksNDg4NDAsNDg4NDEsNDg4NDIsNDg4NDMsNDg4NDQsNDg4NDUsNDg4NDYsNDg4NDcsNDg4NTAsNDg4NTEsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDg4NTMsNDg4NTQsNDg4NTcsNDg4NTgsNDg4NTksNDg4NjAsNDg4NjEsNDg4NjIsNDg4NjMsNDg4NjUsNDg4NjYsNDg4NzAsNDg4NzEsNDg4NzIsNDg4NzMsNDg4NzQsNDg4NzUsNDg4NzcsNDg4NzgsNDg4NzksNDg4ODAsNDg4ODEsNDg4ODIsNDg4ODMsNDg4ODQsNDg4ODUsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDg4ODYsNDg4ODcsNDg4ODgsNDg4ODksNDg4OTAsNDg4OTEsNDg4OTIsNDg4OTMsNDg4OTQsNDg4OTUsNDg4OTYsNDg4OTgsNDg4OTksNDg5MDAsNDg5MDEsNDg5MDIsNDg5MDMsNDg5MDYsNDg5MDcsNDg5MDgsNDg5MDksNDg5MTAsNDg5MTEsNDg5MTIsNDg5MTMsNDg5MTQsNDg5MTUsNDg5MTYsNDg5MTcsNDg5MTgsNDg5MTksNDg5MjIsNDg5MjYsNDg5MjcsNDg5MjgsNDg5MjksNDg5MzAsNDg5MzEsNDg5MzIsNDg5MzMsNDg5MzQsNDg5MzUsNDg5MzYsNDg5MzcsNDg5MzgsNDg5MzksNDg5NDAsNDg5NDEsNDg5NDIsNDg5NDMsNDg5NDQsNDg5NDUsNDg5NDYsNDg5NDcsNDg5NDgsNDg5NDksNDg5NTAsNDg5NTEsNDg5NTIsNDg5NTMsNDg5NTQsNDg5NTUsNDg5NTYsNDg5NTcsNDg5NTgsNDg5NTksNDg5NjIsNDg5NjMsNDg5NjUsNDg5NjYsNDg5NjcsNDg5NjksNDg5NzAsNDg5NzEsNDg5NzIsNDg5NzMsNDg5NzQsNDg5NzUsNDg5NzgsNDg5NzksNDg5ODAsNDg5ODIsNDg5ODMsNDg5ODQsNDg5ODUsNDg5ODYsNDg5ODcsNDg5ODgsNDg5ODksNDg5OTAsNDg5OTEsNDg5OTIsNDg5OTMsNDg5OTQsNDg5OTUsNDg5OTYsNDg5OTcsNDg5OTgsNDg5OTksNDkwMDAsNDkwMDEsNDkwMDIsNDkwMDMsNDkwMDQsNDkwMDUsNDkwMDYsNDkwMDcsNDkwMDgsNDkwMDksNDkwMTAsNDkwMTEsNDkwMTIsNDkwMTMsNDkwMTQsNDkwMTUsNDkwMTYsNDkwMTcsNDkwMTgsNDkwMTksNDkwMjAsNDkwMjEsNDkwMjIsNDkwMjMsNDkwMjQsNDkwMjUsNDkwMjYsNDkwMjcsNDkwMjgsNDkwMjksNDkwMzAsNDkwMzEsNDkwMzIsNDkwMzMsNDkwMzQsNDkwMzUsNDkwMzYsNDkwMzcsNDkwMzgsNDkwMzksNDkwNDAsNDkwNDEsNDkwNDIsNDkwNDMsNDkwNDUsNDkwNDYsNDkwNDcsNDkwNDgsNDkwNDksNDkwNTAsNDkwNTEsNDkwNTIsNDkwNTMsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDkwNTQsNDkwNTUsNDkwNTYsNDkwNTcsNDkwNTgsNDkwNTksNDkwNjAsNDkwNjEsNDkwNjIsNDkwNjMsNDkwNjQsNDkwNjUsNDkwNjYsNDkwNjcsNDkwNjgsNDkwNjksNDkwNzAsNDkwNzEsNDkwNzMsNDkwNzQsNDkwNzUsNDkwNzYsNDkwNzcsNDkwNzgsNDkwNzksNDkwODAsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDkwODEsNDkwODIsNDkwODMsNDkwODQsNDkwODUsNDkwODYsNDkwODcsNDkwODgsNDkwODksNDkwOTAsNDkwOTEsNDkwOTIsNDkwOTQsNDkwOTUsNDkwOTYsNDkwOTcsNDkwOTgsNDkwOTksNDkxMDIsNDkxMDMsNDkxMDUsNDkxMDYsNDkxMDcsNDkxMDksNDkxMTAsNDkxMTEsNDkxMTIsNDkxMTMsNDkxMTQsNDkxMTUsNDkxMTcsNDkxMTgsNDkxMjAsNDkxMjIsNDkxMjMsNDkxMjQsNDkxMjUsNDkxMjYsNDkxMjcsNDkxMjgsNDkxMjksNDkxMzAsNDkxMzEsNDkxMzIsNDkxMzMsNDkxMzQsNDkxMzUsNDkxMzYsNDkxMzcsNDkxMzgsNDkxMzksNDkxNDAsNDkxNDEsNDkxNDIsNDkxNDMsNDkxNDQsNDkxNDUsNDkxNDYsNDkxNDcsNDkxNDgsNDkxNDksNDkxNTAsNDkxNTEsNDkxNTIsNDkxNTMsNDkxNTQsNDkxNTUsNDkxNTYsNDkxNTcsNDkxNTgsNDkxNTksNDkxNjAsNDkxNjEsNDkxNjIsNDkxNjMsNDkxNjQsNDkxNjUsNDkxNjYsNDkxNjcsNDkxNjgsNDkxNjksNDkxNzAsNDkxNzEsNDkxNzIsNDkxNzMsNDkxNzQsNDkxNzUsNDkxNzYsNDkxNzcsNDkxNzgsNDkxNzksNDkxODAsNDkxODEsNDkxODIsNDkxODMsNDkxODQsNDkxODUsNDkxODYsNDkxODcsNDkxODgsNDkxODksNDkxOTAsNDkxOTEsNDkxOTIsNDkxOTMsNDkxOTQsNDkxOTUsNDkxOTYsNDkxOTcsNDkxOTgsNDkxOTksNDkyMDAsNDkyMDEsNDkyMDIsNDkyMDMsNDkyMDQsNDkyMDUsNDkyMDYsNDkyMDcsNDkyMDgsNDkyMDksNDkyMTAsNDkyMTEsNDkyMTMsNDkyMTQsNDkyMTUsNDkyMTYsNDkyMTcsNDkyMTgsNDkyMTksNDkyMjAsNDkyMjEsNDkyMjIsNDkyMjMsNDkyMjQsNDkyMjUsNDkyMjYsNDkyMjcsNDkyMjgsNDkyMjksNDkyMzAsNDkyMzEsNDkyMzIsNDkyMzQsNDkyMzUsNDkyMzYsNDkyMzcsNDkyMzgsNDkyMzksNDkyNDEsNDkyNDIsNDkyNDMsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDkyNDUsNDkyNDYsNDkyNDcsNDkyNDksNDkyNTAsNDkyNTEsNDkyNTIsNDkyNTMsNDkyNTQsNDkyNTUsNDkyNTgsNDkyNTksNDkyNjAsNDkyNjEsNDkyNjIsNDkyNjMsNDkyNjQsNDkyNjUsNDkyNjYsNDkyNjcsNDkyNjgsNDkyNjksNDkyNzAsNDkyNzEsNDkyNzIsNDkyNzMsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDkyNzQsNDkyNzUsNDkyNzYsNDkyNzcsNDkyNzgsNDkyNzksNDkyODAsNDkyODEsNDkyODIsNDkyODMsNDkyODQsNDkyODUsNDkyODYsNDkyODcsNDkyODgsNDkyODksNDkyOTAsNDkyOTEsNDkyOTIsNDkyOTMsNDkyOTQsNDkyOTUsNDkyOTgsNDkyOTksNDkzMDEsNDkzMDIsNDkzMDMsNDkzMDUsNDkzMDYsNDkzMDcsNDkzMDgsNDkzMDksNDkzMTAsNDkzMTEsNDkzMTQsNDkzMTYsNDkzMTgsNDkzMTksNDkzMjAsNDkzMjEsNDkzMjIsNDkzMjMsNDkzMjYsNDkzMjksNDkzMzAsNDkzMzUsNDkzMzYsNDkzMzcsNDkzMzgsNDkzMzksNDkzNDIsNDkzNDYsNDkzNDcsNDkzNDgsNDkzNTAsNDkzNTEsNDkzNTQsNDkzNTUsNDkzNTcsNDkzNTgsNDkzNTksNDkzNjEsNDkzNjIsNDkzNjMsNDkzNjQsNDkzNjUsNDkzNjYsNDkzNjcsNDkzNzAsNDkzNzQsNDkzNzUsNDkzNzYsNDkzNzcsNDkzNzgsNDkzNzksNDkzODIsNDkzODMsNDkzODUsNDkzODYsNDkzODcsNDkzODksNDkzOTAsNDkzOTEsNDkzOTIsNDkzOTMsNDkzOTQsNDkzOTUsNDkzOTgsNDk0MDAsNDk0MDIsNDk0MDMsNDk0MDQsNDk0MDUsNDk0MDYsNDk0MDcsNDk0MDksNDk0MTAsNDk0MTEsNDk0MTMsNDk0MTQsNDk0MTUsNDk0MTcsNDk0MTgsNDk0MTksNDk0MjAsNDk0MjEsNDk0MjIsNDk0MjMsNDk0MjUsNDk0MjYsNDk0MjcsNDk0MjgsNDk0MzAsNDk0MzEsNDk0MzIsNDk0MzMsNDk0MzQsNDk0MzUsNDk0NDEsNDk0NDIsNDk0NDUsNDk0NDgsNDk0NDksNDk0NTAsNDk0NTEsNDk0NTQsNDk0NTgsNDk0NTksNDk0NjAsNDk0NjEsNDk0NjMsNDk0NjYsNDk0NjcsNDk0NjksNDk0NzAsNDk0NzEsNDk0NzMsNDk0NzQsNDk0NzUsNDk0NzYsNDk0NzcsNDk0NzgsNDk0NzksNDk0ODIsNDk0ODYsNDk0ODcsNDk0ODgsNDk0ODksNDk0OTAsNDk0OTEsNDk0OTQsNDk0OTUsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDk0OTcsNDk0OTgsNDk0OTksNDk1MDEsNDk1MDIsNDk1MDMsNDk1MDQsNDk1MDUsNDk1MDYsNDk1MDcsNDk1MTAsNDk1MTQsNDk1MTUsNDk1MTYsNDk1MTcsNDk1MTgsNDk1MTksNDk1MjEsNDk1MjIsNDk1MjMsNDk1MjUsNDk1MjYsNDk1MjcsNDk1MjksNDk1MzAsNDk1MzEsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDk1MzIsNDk1MzMsNDk1MzQsNDk1MzUsNDk1MzYsNDk1MzcsNDk1MzgsNDk1MzksNDk1NDAsNDk1NDIsNDk1NDMsNDk1NDQsNDk1NDUsNDk1NDYsNDk1NDcsNDk1NTEsNDk1NTMsNDk1NTQsNDk1NTUsNDk1NTcsNDk1NTksNDk1NjAsNDk1NjEsNDk1NjIsNDk1NjMsNDk1NjYsNDk1NjgsNDk1NzAsNDk1NzEsNDk1NzIsNDk1NzQsNDk1NzUsNDk1NzgsNDk1NzksNDk1ODEsNDk1ODIsNDk1ODMsNDk1ODUsNDk1ODYsNDk1ODcsNDk1ODgsNDk1ODksNDk1OTAsNDk1OTEsNDk1OTIsNDk1OTMsNDk1OTQsNDk1OTUsNDk1OTYsNDk1OTgsNDk1OTksNDk2MDAsNDk2MDEsNDk2MDIsNDk2MDMsNDk2MDUsNDk2MDYsNDk2MDcsNDk2MDksNDk2MTAsNDk2MTEsNDk2MTMsNDk2MTQsNDk2MTUsNDk2MTYsNDk2MTcsNDk2MTgsNDk2MTksNDk2MjEsNDk2MjIsNDk2MjUsNDk2MjYsNDk2MjcsNDk2MjgsNDk2MjksNDk2MzAsNDk2MzEsNDk2MzMsNDk2MzQsNDk2MzUsNDk2MzcsNDk2MzgsNDk2MzksNDk2NDEsNDk2NDIsNDk2NDMsNDk2NDQsNDk2NDUsNDk2NDYsNDk2NDcsNDk2NTAsNDk2NTIsNDk2NTMsNDk2NTQsNDk2NTUsNDk2NTYsNDk2NTcsNDk2NTgsNDk2NTksNDk2NjIsNDk2NjMsNDk2NjUsNDk2NjYsNDk2NjcsNDk2NjksNDk2NzAsNDk2NzEsNDk2NzIsNDk2NzMsNDk2NzQsNDk2NzUsNDk2NzgsNDk2ODAsNDk2ODIsNDk2ODMsNDk2ODQsNDk2ODUsNDk2ODYsNDk2ODcsNDk2OTAsNDk2OTEsNDk2OTMsNDk2OTQsNDk2OTcsNDk2OTgsNDk2OTksNDk3MDAsNDk3MDEsNDk3MDIsNDk3MDMsNDk3MDYsNDk3MDgsNDk3MTAsNDk3MTIsNDk3MTUsNDk3MTcsNDk3MTgsNDk3MTksNDk3MjAsNDk3MjEsNDk3MjIsNDk3MjMsNDk3MjQsNDk3MjUsNDk3MjYsNDk3MjcsNDk3MjgsNDk3MjksNDk3MzAsNDk3MzEsNDk3MzIsNDk3MzMsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDk3MzQsNDk3MzUsNDk3MzcsNDk3MzgsNDk3MzksNDk3NDAsNDk3NDEsNDk3NDIsNDk3NDMsNDk3NDYsNDk3NDcsNDk3NDksNDk3NTAsNDk3NTEsNDk3NTMsNDk3NTQsNDk3NTUsNDk3NTYsNDk3NTcsNDk3NTgsNDk3NTksNDk3NjEsNDk3NjIsNDk3NjMsNDk3NjQsNDk3NjYsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDk3NjcsNDk3NjgsNDk3NjksNDk3NzAsNDk3NzEsNDk3NzQsNDk3NzUsNDk3NzcsNDk3NzgsNDk3NzksNDk3ODEsNDk3ODIsNDk3ODMsNDk3ODQsNDk3ODUsNDk3ODYsNDk3ODcsNDk3OTAsNDk3OTIsNDk3OTQsNDk3OTUsNDk3OTYsNDk3OTcsNDk3OTgsNDk3OTksNDk4MDIsNDk4MDMsNDk4MDQsNDk4MDUsNDk4MDYsNDk4MDcsNDk4MDksNDk4MTAsNDk4MTEsNDk4MTIsNDk4MTMsNDk4MTQsNDk4MTUsNDk4MTcsNDk4MTgsNDk4MjAsNDk4MjIsNDk4MjMsNDk4MjQsNDk4MjUsNDk4MjYsNDk4MjcsNDk4MzAsNDk4MzEsNDk4MzMsNDk4MzQsNDk4MzUsNDk4MzgsNDk4MzksNDk4NDAsNDk4NDEsNDk4NDIsNDk4NDMsNDk4NDYsNDk4NDgsNDk4NTAsNDk4NTEsNDk4NTIsNDk4NTMsNDk4NTQsNDk4NTUsNDk4NTYsNDk4NTcsNDk4NTgsNDk4NTksNDk4NjAsNDk4NjEsNDk4NjIsNDk4NjMsNDk4NjQsNDk4NjUsNDk4NjYsNDk4NjcsNDk4NjgsNDk4NjksNDk4NzAsNDk4NzEsNDk4NzIsNDk4NzMsNDk4NzQsNDk4NzUsNDk4NzYsNDk4NzcsNDk4NzgsNDk4NzksNDk4ODAsNDk4ODEsNDk4ODIsNDk4ODMsNDk4ODYsNDk4ODcsNDk4ODksNDk4OTAsNDk4OTMsNDk4OTQsNDk4OTUsNDk4OTYsNDk4OTcsNDk4OTgsNDk5MDIsNDk5MDQsNDk5MDYsNDk5MDcsNDk5MDgsNDk5MDksNDk5MTEsNDk5MTQsNDk5MTcsNDk5MTgsNDk5MTksNDk5MjEsNDk5MjIsNDk5MjMsNDk5MjQsNDk5MjUsNDk5MjYsNDk5MjcsNDk5MzAsNDk5MzEsNDk5MzQsNDk5MzUsNDk5MzYsNDk5MzcsNDk5MzgsNDk5NDIsNDk5NDMsNDk5NDUsNDk5NDYsNDk5NDcsNDk5NDksNDk5NTAsNDk5NTEsNDk5NTIsNDk5NTMsNDk5NTQsNDk5NTUsNDk5NTgsNDk5NTksNDk5NjIsNDk5NjMsNDk5NjQsNDk5NjUsNDk5NjYsNDk5NjcsNDk5NjgsNDk5NjksNDk5NzAsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDk5NzEsNDk5NzIsNDk5NzMsNDk5NzQsNDk5NzUsNDk5NzYsNDk5NzcsNDk5NzgsNDk5NzksNDk5ODAsNDk5ODEsNDk5ODIsNDk5ODMsNDk5ODQsNDk5ODUsNDk5ODYsNDk5ODcsNDk5ODgsNDk5OTAsNDk5OTEsNDk5OTIsNDk5OTMsNDk5OTQsNDk5OTUsNDk5OTYsNDk5OTcsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNDk5OTgsNDk5OTksNTAwMDAsNTAwMDEsNTAwMDIsNTAwMDMsNTAwMDQsNTAwMDUsNTAwMDYsNTAwMDcsNTAwMDgsNTAwMDksNTAwMTAsNTAwMTEsNTAwMTIsNTAwMTMsNTAwMTQsNTAwMTUsNTAwMTYsNTAwMTcsNTAwMTgsNTAwMTksNTAwMjAsNTAwMjEsNTAwMjIsNTAwMjMsNTAwMjYsNTAwMjcsNTAwMjksNTAwMzAsNTAwMzEsNTAwMzMsNTAwMzUsNTAwMzYsNTAwMzcsNTAwMzgsNTAwMzksNTAwNDIsNTAwNDMsNTAwNDYsNTAwNDcsNTAwNDgsNTAwNDksNTAwNTAsNTAwNTEsNTAwNTMsNTAwNTQsNTAwNTUsNTAwNTcsNTAwNTgsNTAwNTksNTAwNjEsNTAwNjIsNTAwNjMsNTAwNjQsNTAwNjUsNTAwNjYsNTAwNjcsNTAwNjgsNTAwNjksNTAwNzAsNTAwNzEsNTAwNzIsNTAwNzMsNTAwNzQsNTAwNzUsNTAwNzYsNTAwNzcsNTAwNzgsNTAwNzksNTAwODAsNTAwODEsNTAwODIsNTAwODMsNTAwODQsNTAwODUsNTAwODYsNTAwODcsNTAwODgsNTAwODksNTAwOTAsNTAwOTEsNTAwOTIsNTAwOTMsNTAwOTQsNTAwOTUsNTAwOTYsNTAwOTcsNTAwOTgsNTAwOTksNTAxMDAsNTAxMDEsNTAxMDIsNTAxMDMsNTAxMDQsNTAxMDUsNTAxMDYsNTAxMDcsNTAxMDgsNTAxMDksNTAxMTAsNTAxMTEsNTAxMTMsNTAxMTQsNTAxMTUsNTAxMTYsNTAxMTcsNTAxMTgsNTAxMTksNTAxMjAsNTAxMjEsNTAxMjIsNTAxMjMsNTAxMjQsNTAxMjUsNTAxMjYsNTAxMjcsNTAxMjgsNTAxMjksNTAxMzAsNTAxMzEsNTAxMzIsNTAxMzMsNTAxMzQsNTAxMzUsNTAxMzgsNTAxMzksNTAxNDEsNTAxNDIsNTAxNDUsNTAxNDcsNTAxNDgsNTAxNDksNTAxNTAsNTAxNTEsNTAxNTQsNTAxNTUsNTAxNTYsNTAxNTgsNTAxNTksNTAxNjAsNTAxNjEsNTAxNjIsNTAxNjMsNTAxNjYsNTAxNjcsNTAxNjksNTAxNzAsNTAxNzEsNTAxNzIsNTAxNzMsNTAxNzQsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTAxNzUsNTAxNzYsNTAxNzcsNTAxNzgsNTAxNzksNTAxODAsNTAxODEsNTAxODIsNTAxODMsNTAxODUsNTAxODYsNTAxODcsNTAxODgsNTAxODksNTAxOTAsNTAxOTEsNTAxOTMsNTAxOTQsNTAxOTUsNTAxOTYsNTAxOTcsNTAxOTgsNTAxOTksNTAyMDAsNTAyMDEsNTAyMDIsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTAyMDMsNTAyMDQsNTAyMDUsNTAyMDYsNTAyMDcsNTAyMDgsNTAyMDksNTAyMTAsNTAyMTEsNTAyMTMsNTAyMTQsNTAyMTUsNTAyMTYsNTAyMTcsNTAyMTgsNTAyMTksNTAyMjEsNTAyMjIsNTAyMjMsNTAyMjUsNTAyMjYsNTAyMjcsNTAyMjksNTAyMzAsNTAyMzEsNTAyMzIsNTAyMzMsNTAyMzQsNTAyMzUsNTAyMzgsNTAyMzksNTAyNDAsNTAyNDEsNTAyNDIsNTAyNDMsNTAyNDQsNTAyNDUsNTAyNDYsNTAyNDcsNTAyNDksNTAyNTAsNTAyNTEsNTAyNTIsNTAyNTMsNTAyNTQsNTAyNTUsNTAyNTYsNTAyNTcsNTAyNTgsNTAyNTksNTAyNjAsNTAyNjEsNTAyNjIsNTAyNjMsNTAyNjQsNTAyNjUsNTAyNjYsNTAyNjcsNTAyNjgsNTAyNjksNTAyNzAsNTAyNzEsNTAyNzIsNTAyNzMsNTAyNzQsNTAyNzUsNTAyNzgsNTAyNzksNTAyODEsNTAyODIsNTAyODMsNTAyODUsNTAyODYsNTAyODcsNTAyODgsNTAyODksNTAyOTAsNTAyOTEsNTAyOTQsNTAyOTUsNTAyOTYsNTAyOTgsNTAyOTksNTAzMDAsNTAzMDEsNTAzMDIsNTAzMDMsNTAzMDUsNTAzMDYsNTAzMDcsNTAzMDgsNTAzMDksNTAzMTAsNTAzMTEsNTAzMTIsNTAzMTMsNTAzMTQsNTAzMTUsNTAzMTYsNTAzMTcsNTAzMTgsNTAzMTksNTAzMjAsNTAzMjEsNTAzMjIsNTAzMjMsNTAzMjUsNTAzMjYsNTAzMjcsNTAzMjgsNTAzMjksNTAzMzAsNTAzMzEsNTAzMzMsNTAzMzQsNTAzMzUsNTAzMzYsNTAzMzcsNTAzMzgsNTAzMzksNTAzNDAsNTAzNDEsNTAzNDIsNTAzNDMsNTAzNDQsNTAzNDUsNTAzNDYsNTAzNDcsNTAzNDgsNTAzNDksNTAzNTAsNTAzNTEsNTAzNTIsNTAzNTMsNTAzNTQsNTAzNTUsNTAzNTYsNTAzNTcsNTAzNTgsNTAzNTksNTAzNjEsNTAzNjIsNTAzNjMsNTAzNjUsNTAzNjYsNTAzNjcsNTAzNjgsNTAzNjksNTAzNzAsNTAzNzEsNTAzNzIsNTAzNzMsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTAzNzQsNTAzNzUsNTAzNzYsNTAzNzcsNTAzNzgsNTAzNzksNTAzODAsNTAzODEsNTAzODIsNTAzODMsNTAzODQsNTAzODUsNTAzODYsNTAzODcsNTAzODgsNTAzODksNTAzOTAsNTAzOTEsNTAzOTIsNTAzOTMsNTAzOTQsNTAzOTUsNTAzOTYsNTAzOTcsNTAzOTgsNTAzOTksbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTA0MDAsNTA0MDEsNTA0MDIsNTA0MDMsNTA0MDQsNTA0MDUsNTA0MDYsNTA0MDcsNTA0MDgsNTA0MTAsNTA0MTEsNTA0MTIsNTA0MTMsNTA0MTQsNTA0MTUsNTA0MTgsNTA0MTksNTA0MjEsNTA0MjIsNTA0MjMsNTA0MjUsNTA0MjcsNTA0MjgsNTA0MjksNTA0MzAsNTA0MzQsNTA0MzUsNTA0MzYsNTA0MzcsNTA0MzgsNTA0MzksNTA0NDAsNTA0NDEsNTA0NDIsNTA0NDMsNTA0NDUsNTA0NDYsNTA0NDcsNTA0NDksNTA0NTAsNTA0NTEsNTA0NTMsNTA0NTQsNTA0NTUsNTA0NTYsNTA0NTcsNTA0NTgsNTA0NTksNTA0NjEsNTA0NjIsNTA0NjMsNTA0NjQsNTA0NjUsNTA0NjYsNTA0NjcsNTA0NjgsNTA0NjksNTA0NzAsNTA0NzEsNTA0NzQsNTA0NzUsNTA0NzcsNTA0NzgsNTA0NzksNTA0ODEsNTA0ODIsNTA0ODMsNTA0ODQsNTA0ODUsNTA0ODYsNTA0ODcsNTA0OTAsNTA0OTIsNTA0OTQsNTA0OTUsNTA0OTYsNTA0OTcsNTA0OTgsNTA0OTksNTA1MDIsNTA1MDMsNTA1MDcsNTA1MTEsNTA1MTIsNTA1MTMsNTA1MTQsNTA1MTgsNTA1MjIsNTA1MjMsNTA1MjQsNTA1MjcsNTA1MzAsNTA1MzEsNTA1MzMsNTA1MzQsNTA1MzUsNTA1MzcsNTA1MzgsNTA1MzksNTA1NDAsNTA1NDEsNTA1NDIsNTA1NDMsNTA1NDYsNTA1NTAsNTA1NTEsNTA1NTIsNTA1NTMsNTA1NTQsNTA1NTUsNTA1NTgsNTA1NTksNTA1NjEsNTA1NjIsNTA1NjMsNTA1NjUsNTA1NjYsNTA1NjgsNTA1NjksNTA1NzAsNTA1NzEsNTA1NzQsNTA1NzYsNTA1NzgsNTA1NzksNTA1ODAsNTA1ODIsNTA1ODUsNTA1ODYsNTA1ODcsNTA1ODksNTA1OTAsNTA1OTEsNTA1OTMsNTA1OTQsNTA1OTUsNTA1OTYsNTA1OTcsNTA1OTgsNTA1OTksNTA2MDAsNTA2MDIsNTA2MDMsNTA2MDQsNTA2MDUsNTA2MDYsNTA2MDcsNTA2MDgsNTA2MDksNTA2MTAsNTA2MTEsNTA2MTQsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTA2MTUsNTA2MTgsNTA2MjMsNTA2MjQsNTA2MjUsNTA2MjYsNTA2MjcsNTA2MzUsNTA2MzcsNTA2MzksNTA2NDIsNTA2NDMsNTA2NDUsNTA2NDYsNTA2NDcsNTA2NDksNTA2NTAsNTA2NTEsNTA2NTIsNTA2NTMsNTA2NTQsNTA2NTUsNTA2NTgsNTA2NjAsNTA2NjIsNTA2NjMsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTA2NjQsNTA2NjUsNTA2NjYsNTA2NjcsNTA2NzEsNTA2NzMsNTA2NzQsNTA2NzUsNTA2NzcsNTA2ODAsNTA2ODEsNTA2ODIsNTA2ODMsNTA2OTAsNTA2OTEsNTA2OTIsNTA2OTcsNTA2OTgsNTA2OTksNTA3MDEsNTA3MDIsNTA3MDMsNTA3MDUsNTA3MDYsNTA3MDcsNTA3MDgsNTA3MDksNTA3MTAsNTA3MTEsNTA3MTQsNTA3MTcsNTA3MTgsNTA3MTksNTA3MjAsNTA3MjEsNTA3MjIsNTA3MjMsNTA3MjYsNTA3MjcsNTA3MjksNTA3MzAsNTA3MzEsNTA3MzUsNTA3MzcsNTA3MzgsNTA3NDIsNTA3NDQsNTA3NDYsNTA3NDgsNTA3NDksNTA3NTAsNTA3NTEsNTA3NTQsNTA3NTUsNTA3NTcsNTA3NTgsNTA3NTksNTA3NjEsNTA3NjIsNTA3NjMsNTA3NjQsNTA3NjUsNTA3NjYsNTA3NjcsNTA3NzAsNTA3NzQsNTA3NzUsNTA3NzYsNTA3NzcsNTA3NzgsNTA3NzksNTA3ODIsNTA3ODMsNTA3ODUsNTA3ODYsNTA3ODcsNTA3ODgsNTA3ODksNTA3OTAsNTA3OTEsNTA3OTIsNTA3OTMsNTA3OTQsNTA3OTUsNTA3OTcsNTA3OTgsNTA4MDAsNTA4MDIsNTA4MDMsNTA4MDQsNTA4MDUsNTA4MDYsNTA4MDcsNTA4MTAsNTA4MTEsNTA4MTMsNTA4MTQsNTA4MTUsNTA4MTcsNTA4MTgsNTA4MTksNTA4MjAsNTA4MjEsNTA4MjIsNTA4MjMsNTA4MjYsNTA4MjgsNTA4MzAsNTA4MzEsNTA4MzIsNTA4MzMsNTA4MzQsNTA4MzUsNTA4MzgsNTA4MzksNTA4NDEsNTA4NDIsNTA4NDMsNTA4NDUsNTA4NDYsNTA4NDcsNTA4NDgsNTA4NDksNTA4NTAsNTA4NTEsNTA4NTQsNTA4NTYsNTA4NTgsNTA4NTksNTA4NjAsNTA4NjEsNTA4NjIsNTA4NjMsNTA4NjYsNTA4NjcsNTA4NjksNTA4NzAsNTA4NzEsNTA4NzUsNTA4NzYsNTA4NzcsNTA4NzgsNTA4NzksNTA4ODIsNTA4ODQsNTA4ODYsNTA4ODcsNTA4ODgsNTA4ODksNTA4OTAsNTA4OTEsNTA4OTQsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTA4OTUsNTA4OTcsNTA4OTgsNTA4OTksNTA5MDEsNTA5MDIsNTA5MDMsNTA5MDQsNTA5MDUsNTA5MDYsNTA5MDcsNTA5MTAsNTA5MTEsNTA5MTQsNTA5MTUsNTA5MTYsNTA5MTcsNTA5MTgsNTA5MTksNTA5MjIsNTA5MjMsNTA5MjUsNTA5MjYsNTA5MjcsNTA5MjksNTA5MzAsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTA5MzEsNTA5MzIsNTA5MzMsNTA5MzQsNTA5MzUsNTA5MzgsNTA5MzksNTA5NDAsNTA5NDIsNTA5NDMsNTA5NDQsNTA5NDUsNTA5NDYsNTA5NDcsNTA5NTAsNTA5NTEsNTA5NTMsNTA5NTQsNTA5NTUsNTA5NTcsNTA5NTgsNTA5NTksNTA5NjAsNTA5NjEsNTA5NjIsNTA5NjMsNTA5NjYsNTA5NjgsNTA5NzAsNTA5NzEsNTA5NzIsNTA5NzMsNTA5NzQsNTA5NzUsNTA5NzgsNTA5NzksNTA5ODEsNTA5ODIsNTA5ODMsNTA5ODUsNTA5ODYsNTA5ODcsNTA5ODgsNTA5ODksNTA5OTAsNTA5OTEsNTA5OTQsNTA5OTYsNTA5OTgsNTEwMDAsNTEwMDEsNTEwMDIsNTEwMDMsNTEwMDYsNTEwMDcsNTEwMDksNTEwMTAsNTEwMTEsNTEwMTMsNTEwMTQsNTEwMTUsNTEwMTYsNTEwMTcsNTEwMTksNTEwMjIsNTEwMjQsNTEwMzMsNTEwMzQsNTEwMzUsNTEwMzcsNTEwMzgsNTEwMzksNTEwNDEsNTEwNDIsNTEwNDMsNTEwNDQsNTEwNDUsNTEwNDYsNTEwNDcsNTEwNDksNTEwNTAsNTEwNTIsNTEwNTMsNTEwNTQsNTEwNTUsNTEwNTYsNTEwNTcsNTEwNTgsNTEwNTksNTEwNjIsNTEwNjMsNTEwNjUsNTEwNjYsNTEwNjcsNTEwNzEsNTEwNzIsNTEwNzMsNTEwNzQsNTEwNzgsNTEwODMsNTEwODQsNTEwODUsNTEwODcsNTEwOTAsNTEwOTEsNTEwOTMsNTEwOTcsNTEwOTksNTExMDAsNTExMDEsNTExMDIsNTExMDMsNTExMDYsNTExMTEsNTExMTIsNTExMTMsNTExMTQsNTExMTUsNTExMTgsNTExMTksNTExMjEsNTExMjIsNTExMjMsNTExMjUsNTExMjYsNTExMjcsNTExMjgsNTExMjksNTExMzAsNTExMzEsNTExMzQsNTExMzgsNTExMzksNTExNDAsNTExNDEsNTExNDIsNTExNDMsNTExNDYsNTExNDcsNTExNDksNTExNTEsNTExNTMsNTExNTQsNTExNTUsNTExNTYsNTExNTcsNTExNTgsNTExNTksNTExNjEsNTExNjIsNTExNjMsNTExNjQsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTExNjYsNTExNjcsNTExNjgsNTExNjksNTExNzAsNTExNzEsNTExNzMsNTExNzQsNTExNzUsNTExNzcsNTExNzgsNTExNzksNTExODEsNTExODIsNTExODMsNTExODQsNTExODUsNTExODYsNTExODcsNTExODgsNTExODksNTExOTAsNTExOTEsNTExOTIsNTExOTMsNTExOTQsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTExOTUsNTExOTYsNTExOTcsNTExOTgsNTExOTksNTEyMDIsNTEyMDMsNTEyMDUsNTEyMDYsNTEyMDcsNTEyMDksNTEyMTEsNTEyMTIsNTEyMTMsNTEyMTQsNTEyMTUsNTEyMTgsNTEyMjAsNTEyMjMsNTEyMjQsNTEyMjUsNTEyMjYsNTEyMjcsNTEyMzAsNTEyMzEsNTEyMzMsNTEyMzQsNTEyMzUsNTEyMzcsNTEyMzgsNTEyMzksNTEyNDAsNTEyNDEsNTEyNDIsNTEyNDMsNTEyNDYsNTEyNDgsNTEyNTAsNTEyNTEsNTEyNTIsNTEyNTMsNTEyNTQsNTEyNTUsNTEyNTcsNTEyNTgsNTEyNTksNTEyNjEsNTEyNjIsNTEyNjMsNTEyNjUsNTEyNjYsNTEyNjcsNTEyNjgsNTEyNjksNTEyNzAsNTEyNzEsNTEyNzQsNTEyNzUsNTEyNzgsNTEyNzksNTEyODAsNTEyODEsNTEyODIsNTEyODMsNTEyODUsNTEyODYsNTEyODcsNTEyODgsNTEyODksNTEyOTAsNTEyOTEsNTEyOTIsNTEyOTMsNTEyOTQsNTEyOTUsNTEyOTYsNTEyOTcsNTEyOTgsNTEyOTksNTEzMDAsNTEzMDEsNTEzMDIsNTEzMDMsNTEzMDQsNTEzMDUsNTEzMDYsNTEzMDcsNTEzMDgsNTEzMDksNTEzMTAsNTEzMTEsNTEzMTQsNTEzMTUsNTEzMTcsNTEzMTgsNTEzMTksNTEzMjEsNTEzMjMsNTEzMjQsNTEzMjUsNTEzMjYsNTEzMjcsNTEzMzAsNTEzMzIsNTEzMzYsNTEzMzcsNTEzMzgsNTEzNDIsNTEzNDMsNTEzNDQsNTEzNDUsNTEzNDYsNTEzNDcsNTEzNDksNTEzNTAsNTEzNTEsNTEzNTIsNTEzNTMsNTEzNTQsNTEzNTUsNTEzNTYsNTEzNTgsNTEzNjAsNTEzNjIsNTEzNjMsNTEzNjQsNTEzNjUsNTEzNjYsNTEzNjcsNTEzNjksNTEzNzAsNTEzNzEsNTEzNzIsNTEzNzMsNTEzNzQsNTEzNzUsNTEzNzYsNTEzNzcsNTEzNzgsNTEzNzksNTEzODAsNTEzODEsNTEzODIsNTEzODMsNTEzODQsNTEzODUsNTEzODYsNTEzODcsNTEzOTAsNTEzOTEsNTEzOTIsNTEzOTMsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTEzOTQsNTEzOTUsNTEzOTcsNTEzOTgsNTEzOTksNTE0MDEsNTE0MDIsNTE0MDMsNTE0MDUsNTE0MDYsNTE0MDcsNTE0MDgsNTE0MDksNTE0MTAsNTE0MTEsNTE0MTQsNTE0MTYsNTE0MTgsNTE0MTksNTE0MjAsNTE0MjEsNTE0MjIsNTE0MjMsNTE0MjYsNTE0MjcsNTE0MjksbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTE0MzAsNTE0MzEsNTE0MzIsNTE0MzMsNTE0MzQsNTE0MzUsNTE0MzYsNTE0MzcsNTE0MzgsNTE0MzksNTE0NDAsNTE0NDEsNTE0NDIsNTE0NDMsNTE0NDQsNTE0NDYsNTE0NDcsNTE0NDgsNTE0NDksNTE0NTAsNTE0NTEsNTE0NTQsNTE0NTUsNTE0NTcsNTE0NTgsNTE0NTksNTE0NjMsNTE0NjQsNTE0NjUsNTE0NjYsNTE0NjcsNTE0NzAsMTIyODgsMTIyODksMTIyOTAsMTgzLDgyMjksODIzMCwxNjgsMTIyOTEsMTczLDgyMTMsODc0MSw2NTM0MCw4NzY0LDgyMTYsODIxNyw4MjIwLDgyMjEsMTIzMDgsMTIzMDksMTIyOTYsMTIyOTcsMTIyOTgsMTIyOTksMTIzMDAsMTIzMDEsMTIzMDIsMTIzMDMsMTIzMDQsMTIzMDUsMTc3LDIxNSwyNDcsODgwMCw4ODA0LDg4MDUsODczNCw4NzU2LDE3Niw4MjQyLDgyNDMsODQ1MSw4NDkxLDY1NTA0LDY1NTA1LDY1NTA5LDk3OTQsOTc5Miw4NzM2LDg4NjksODk3OCw4NzA2LDg3MTEsODgwMSw4Nzg2LDE2Nyw4MjUxLDk3MzQsOTczMyw5Njc1LDk2NzksOTY3OCw5NjcxLDk2NzAsOTYzMyw5NjMyLDk2NTEsOTY1MCw5NjYxLDk2NjAsODU5NCw4NTkyLDg1OTMsODU5NSw4NTk2LDEyMzA3LDg4MTAsODgxMSw4NzMwLDg3NjUsODczMyw4NzU3LDg3NDcsODc0OCw4NzEyLDg3MTUsODgzOCw4ODM5LDg4MzQsODgzNSw4NzQ2LDg3NDUsODc0Myw4NzQ0LDY1NTA2LDUxNDcyLDUxNDc0LDUxNDc1LDUxNDc2LDUxNDc3LDUxNDc4LDUxNDc5LDUxNDgxLDUxNDgyLDUxNDgzLDUxNDg0LDUxNDg1LDUxNDg2LDUxNDg3LDUxNDg4LDUxNDg5LDUxNDkwLDUxNDkxLDUxNDkyLDUxNDkzLDUxNDk0LDUxNDk1LDUxNDk2LDUxNDk3LDUxNDk4LDUxNDk5LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDUxNTAxLDUxNTAyLDUxNTAzLDUxNTA0LDUxNTA1LDUxNTA2LDUxNTA3LDUxNTA5LDUxNTEwLDUxNTExLDUxNTEyLDUxNTEzLDUxNTE0LDUxNTE1LDUxNTE2LDUxNTE3LDUxNTE4LDUxNTE5LDUxNTIwLDUxNTIxLDUxNTIyLDUxNTIzLDUxNTI0LDUxNTI1LDUxNTI2LDUxNTI3LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDUxNTI4LDUxNTI5LDUxNTMwLDUxNTMxLDUxNTMyLDUxNTMzLDUxNTM0LDUxNTM1LDUxNTM4LDUxNTM5LDUxNTQxLDUxNTQyLDUxNTQzLDUxNTQ1LDUxNTQ2LDUxNTQ3LDUxNTQ4LDUxNTQ5LDUxNTUwLDUxNTUxLDUxNTU0LDUxNTU2LDUxNTU3LDUxNTU4LDUxNTU5LDUxNTYwLDUxNTYxLDUxNTYyLDUxNTYzLDUxNTY1LDUxNTY2LDUxNTY3LDg2NTgsODY2MCw4NzA0LDg3MDcsMTgwLDY1Mzc0LDcxMSw3MjgsNzMzLDczMCw3MjksMTg0LDczMSwxNjEsMTkxLDcyMCw4NzUwLDg3MjEsODcxOSwxNjQsODQ1Nyw4MjQwLDk2NjUsOTY2NCw5NjU1LDk2NTQsOTgyOCw5ODI0LDk4MjUsOTgyOSw5ODMxLDk4MjcsODg1Nyw5NjcyLDk2MzUsOTY4MCw5NjgxLDk2MTgsOTYzNiw5NjM3LDk2NDAsOTYzOSw5NjM4LDk2NDEsOTgzMiw5NzQzLDk3NDIsOTc1Niw5NzU4LDE4Miw4MjI0LDgyMjUsODU5Nyw4NTk5LDg2MDEsODU5OCw4NjAwLDk4MzcsOTgzMyw5ODM0LDk4MzYsMTI5MjcsMTI4MjgsODQ3MCwxMzI1NSw4NDgyLDEzMjUwLDEzMjcyLDg0ODEsODM2NCwxNzQsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDUxNTY5LDUxNTcwLDUxNTcxLDUxNTczLDUxNTc0LDUxNTc1LDUxNTc2LDUxNTc3LDUxNTc4LDUxNTc5LDUxNTgxLDUxNTgyLDUxNTgzLDUxNTg0LDUxNTg1LDUxNTg2LDUxNTg3LDUxNTg4LDUxNTg5LDUxNTkwLDUxNTkxLDUxNTk0LDUxNTk1LDUxNTk3LDUxNTk4LDUxNTk5LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDUxNjAxLDUxNjAyLDUxNjAzLDUxNjA0LDUxNjA1LDUxNjA2LDUxNjA3LDUxNjEwLDUxNjEyLDUxNjE0LDUxNjE1LDUxNjE2LDUxNjE3LDUxNjE4LDUxNjE5LDUxNjIwLDUxNjIxLDUxNjIyLDUxNjIzLDUxNjI0LDUxNjI1LDUxNjI2LDUxNjI3LDUxNjI4LDUxNjI5LDUxNjMwLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDUxNjMxLDUxNjMyLDUxNjMzLDUxNjM0LDUxNjM1LDUxNjM2LDUxNjM3LDUxNjM4LDUxNjM5LDUxNjQwLDUxNjQxLDUxNjQyLDUxNjQzLDUxNjQ0LDUxNjQ1LDUxNjQ2LDUxNjQ3LDUxNjUwLDUxNjUxLDUxNjUzLDUxNjU0LDUxNjU3LDUxNjU5LDUxNjYwLDUxNjYxLDUxNjYyLDUxNjYzLDUxNjY2LDUxNjY4LDUxNjcxLDUxNjcyLDUxNjc1LDY1MjgxLDY1MjgyLDY1MjgzLDY1Mjg0LDY1Mjg1LDY1Mjg2LDY1Mjg3LDY1Mjg4LDY1Mjg5LDY1MjkwLDY1MjkxLDY1MjkyLDY1MjkzLDY1Mjk0LDY1Mjk1LDY1Mjk2LDY1Mjk3LDY1Mjk4LDY1Mjk5LDY1MzAwLDY1MzAxLDY1MzAyLDY1MzAzLDY1MzA0LDY1MzA1LDY1MzA2LDY1MzA3LDY1MzA4LDY1MzA5LDY1MzEwLDY1MzExLDY1MzEyLDY1MzEzLDY1MzE0LDY1MzE1LDY1MzE2LDY1MzE3LDY1MzE4LDY1MzE5LDY1MzIwLDY1MzIxLDY1MzIyLDY1MzIzLDY1MzI0LDY1MzI1LDY1MzI2LDY1MzI3LDY1MzI4LDY1MzI5LDY1MzMwLDY1MzMxLDY1MzMyLDY1MzMzLDY1MzM0LDY1MzM1LDY1MzM2LDY1MzM3LDY1MzM4LDY1MzM5LDY1NTEwLDY1MzQxLDY1MzQyLDY1MzQzLDY1MzQ0LDY1MzQ1LDY1MzQ2LDY1MzQ3LDY1MzQ4LDY1MzQ5LDY1MzUwLDY1MzUxLDY1MzUyLDY1MzUzLDY1MzU0LDY1MzU1LDY1MzU2LDY1MzU3LDY1MzU4LDY1MzU5LDY1MzYwLDY1MzYxLDY1MzYyLDY1MzYzLDY1MzY0LDY1MzY1LDY1MzY2LDY1MzY3LDY1MzY4LDY1MzY5LDY1MzcwLDY1MzcxLDY1MzcyLDY1MzczLDY1NTA3LDUxNjc4LDUxNjc5LDUxNjgxLDUxNjgzLDUxNjg1LDUxNjg2LDUxNjg4LDUxNjg5LDUxNjkwLDUxNjkxLDUxNjk0LDUxNjk4LDUxNjk5LDUxNzAwLDUxNzAxLDUxNzAyLDUxNzAzLDUxNzA2LDUxNzA3LDUxNzA5LDUxNzEwLDUxNzExLDUxNzEzLDUxNzE0LDUxNzE1LDUxNzE2LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDUxNzE3LDUxNzE4LDUxNzE5LDUxNzIyLDUxNzI2LDUxNzI3LDUxNzI4LDUxNzI5LDUxNzMwLDUxNzMxLDUxNzMzLDUxNzM0LDUxNzM1LDUxNzM3LDUxNzM4LDUxNzM5LDUxNzQwLDUxNzQxLDUxNzQyLDUxNzQzLDUxNzQ0LDUxNzQ1LDUxNzQ2LDUxNzQ3LDUxNzQ4LDUxNzQ5LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDUxNzUwLDUxNzUxLDUxNzUyLDUxNzU0LDUxNzU1LDUxNzU2LDUxNzU3LDUxNzU4LDUxNzU5LDUxNzYwLDUxNzYxLDUxNzYyLDUxNzYzLDUxNzY0LDUxNzY1LDUxNzY2LDUxNzY3LDUxNzY4LDUxNzY5LDUxNzcwLDUxNzcxLDUxNzcyLDUxNzczLDUxNzc0LDUxNzc1LDUxNzc2LDUxNzc3LDUxNzc4LDUxNzc5LDUxNzgwLDUxNzgxLDUxNzgyLDEyNTkzLDEyNTk0LDEyNTk1LDEyNTk2LDEyNTk3LDEyNTk4LDEyNTk5LDEyNjAwLDEyNjAxLDEyNjAyLDEyNjAzLDEyNjA0LDEyNjA1LDEyNjA2LDEyNjA3LDEyNjA4LDEyNjA5LDEyNjEwLDEyNjExLDEyNjEyLDEyNjEzLDEyNjE0LDEyNjE1LDEyNjE2LDEyNjE3LDEyNjE4LDEyNjE5LDEyNjIwLDEyNjIxLDEyNjIyLDEyNjIzLDEyNjI0LDEyNjI1LDEyNjI2LDEyNjI3LDEyNjI4LDEyNjI5LDEyNjMwLDEyNjMxLDEyNjMyLDEyNjMzLDEyNjM0LDEyNjM1LDEyNjM2LDEyNjM3LDEyNjM4LDEyNjM5LDEyNjQwLDEyNjQxLDEyNjQyLDEyNjQzLDEyNjQ0LDEyNjQ1LDEyNjQ2LDEyNjQ3LDEyNjQ4LDEyNjQ5LDEyNjUwLDEyNjUxLDEyNjUyLDEyNjUzLDEyNjU0LDEyNjU1LDEyNjU2LDEyNjU3LDEyNjU4LDEyNjU5LDEyNjYwLDEyNjYxLDEyNjYyLDEyNjYzLDEyNjY0LDEyNjY1LDEyNjY2LDEyNjY3LDEyNjY4LDEyNjY5LDEyNjcwLDEyNjcxLDEyNjcyLDEyNjczLDEyNjc0LDEyNjc1LDEyNjc2LDEyNjc3LDEyNjc4LDEyNjc5LDEyNjgwLDEyNjgxLDEyNjgyLDEyNjgzLDEyNjg0LDEyNjg1LDEyNjg2LDUxNzgzLDUxNzg0LDUxNzg1LDUxNzg2LDUxNzg3LDUxNzkwLDUxNzkxLDUxNzkzLDUxNzk0LDUxNzk1LDUxNzk3LDUxNzk4LDUxNzk5LDUxODAwLDUxODAxLDUxODAyLDUxODAzLDUxODA2LDUxODEwLDUxODExLDUxODEyLDUxODEzLDUxODE0LDUxODE1LDUxODE3LDUxODE4LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDUxODE5LDUxODIwLDUxODIxLDUxODIyLDUxODIzLDUxODI0LDUxODI1LDUxODI2LDUxODI3LDUxODI4LDUxODI5LDUxODMwLDUxODMxLDUxODMyLDUxODMzLDUxODM0LDUxODM1LDUxODM2LDUxODM4LDUxODM5LDUxODQwLDUxODQxLDUxODQyLDUxODQzLDUxODQ1LDUxODQ2LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDUxODQ3LDUxODQ4LDUxODQ5LDUxODUwLDUxODUxLDUxODUyLDUxODUzLDUxODU0LDUxODU1LDUxODU2LDUxODU3LDUxODU4LDUxODU5LDUxODYwLDUxODYxLDUxODYyLDUxODYzLDUxODY1LDUxODY2LDUxODY3LDUxODY4LDUxODY5LDUxODcwLDUxODcxLDUxODcyLDUxODczLDUxODc0LDUxODc1LDUxODc2LDUxODc3LDUxODc4LDUxODc5LDg1NjAsODU2MSw4NTYyLDg1NjMsODU2NCw4NTY1LDg1NjYsODU2Nyw4NTY4LDg1NjksbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDg1NDQsODU0NSw4NTQ2LDg1NDcsODU0OCw4NTQ5LDg1NTAsODU1MSw4NTUyLDg1NTMsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw5MTMsOTE0LDkxNSw5MTYsOTE3LDkxOCw5MTksOTIwLDkyMSw5MjIsOTIzLDkyNCw5MjUsOTI2LDkyNyw5MjgsOTI5LDkzMSw5MzIsOTMzLDkzNCw5MzUsOTM2LDkzNyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsOTQ1LDk0Niw5NDcsOTQ4LDk0OSw5NTAsOTUxLDk1Miw5NTMsOTU0LDk1NSw5NTYsOTU3LDk1OCw5NTksOTYwLDk2MSw5NjMsOTY0LDk2NSw5NjYsOTY3LDk2OCw5NjksbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTE4ODAsNTE4ODEsNTE4ODIsNTE4ODMsNTE4ODQsNTE4ODUsNTE4ODYsNTE4ODcsNTE4ODgsNTE4ODksNTE4OTAsNTE4OTEsNTE4OTIsNTE4OTMsNTE4OTQsNTE4OTUsNTE4OTYsNTE4OTcsNTE4OTgsNTE4OTksNTE5MDIsNTE5MDMsNTE5MDUsNTE5MDYsNTE5MDcsNTE5MDksbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTE5MTAsNTE5MTEsNTE5MTIsNTE5MTMsNTE5MTQsNTE5MTUsNTE5MTgsNTE5MjAsNTE5MjIsNTE5MjQsNTE5MjUsNTE5MjYsNTE5MjcsNTE5MzAsNTE5MzEsNTE5MzIsNTE5MzMsNTE5MzQsNTE5MzUsNTE5MzcsNTE5MzgsNTE5MzksNTE5NDAsNTE5NDEsNTE5NDIsNTE5NDMsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTE5NDQsNTE5NDUsNTE5NDYsNTE5NDcsNTE5NDksNTE5NTAsNTE5NTEsNTE5NTIsNTE5NTMsNTE5NTQsNTE5NTUsNTE5NTcsNTE5NTgsNTE5NTksNTE5NjAsNTE5NjEsNTE5NjIsNTE5NjMsNTE5NjQsNTE5NjUsNTE5NjYsNTE5NjcsNTE5NjgsNTE5NjksNTE5NzAsNTE5NzEsNTE5NzIsNTE5NzMsNTE5NzQsNTE5NzUsNTE5NzcsNTE5NzgsOTQ3Miw5NDc0LDk0ODQsOTQ4OCw5NDk2LDk0OTIsOTUwMCw5NTE2LDk1MDgsOTUyNCw5NTMyLDk0NzMsOTQ3NSw5NDg3LDk0OTEsOTQ5OSw5NDk1LDk1MDcsOTUyMyw5NTE1LDk1MzEsOTU0Nyw5NTA0LDk1MTksOTUxMiw5NTI3LDk1MzUsOTUwMSw5NTIwLDk1MDksOTUyOCw5NTM4LDk0OTAsOTQ4OSw5NDk4LDk0OTcsOTQ5NCw5NDkzLDk0ODYsOTQ4NSw5NTAyLDk1MDMsOTUwNSw5NTA2LDk1MTAsOTUxMSw5NTEzLDk1MTQsOTUxNyw5NTE4LDk1MjEsOTUyMiw5NTI1LDk1MjYsOTUyOSw5NTMwLDk1MzMsOTUzNCw5NTM2LDk1MzcsOTUzOSw5NTQwLDk1NDEsOTU0Miw5NTQzLDk1NDQsOTU0NSw5NTQ2LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MTk3OSw1MTk4MCw1MTk4MSw1MTk4Miw1MTk4Myw1MTk4NSw1MTk4Niw1MTk4Nyw1MTk4OSw1MTk5MCw1MTk5MSw1MTk5Myw1MTk5NCw1MTk5NSw1MTk5Niw1MTk5Nyw1MTk5OCw1MTk5OSw1MjAwMiw1MjAwMyw1MjAwNCw1MjAwNSw1MjAwNiw1MjAwNyw1MjAwOCw1MjAwOSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MjAxMCw1MjAxMSw1MjAxMiw1MjAxMyw1MjAxNCw1MjAxNSw1MjAxNiw1MjAxNyw1MjAxOCw1MjAxOSw1MjAyMCw1MjAyMSw1MjAyMiw1MjAyMyw1MjAyNCw1MjAyNSw1MjAyNiw1MjAyNyw1MjAyOCw1MjAyOSw1MjAzMCw1MjAzMSw1MjAzMiw1MjAzNCw1MjAzNSw1MjAzNixudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MjAzNyw1MjAzOCw1MjAzOSw1MjA0Miw1MjA0Myw1MjA0NSw1MjA0Niw1MjA0Nyw1MjA0OSw1MjA1MCw1MjA1MSw1MjA1Miw1MjA1Myw1MjA1NCw1MjA1NSw1MjA1OCw1MjA1OSw1MjA2MCw1MjA2Miw1MjA2Myw1MjA2NCw1MjA2NSw1MjA2Niw1MjA2Nyw1MjA2OSw1MjA3MCw1MjA3MSw1MjA3Miw1MjA3Myw1MjA3NCw1MjA3NSw1MjA3NiwxMzIwNSwxMzIwNiwxMzIwNyw4NDY3LDEzMjA4LDEzMjUyLDEzMjE5LDEzMjIwLDEzMjIxLDEzMjIyLDEzMjA5LDEzMjEwLDEzMjExLDEzMjEyLDEzMjEzLDEzMjE0LDEzMjE1LDEzMjE2LDEzMjE3LDEzMjE4LDEzMjU4LDEzMTk3LDEzMTk4LDEzMTk5LDEzMjYzLDEzMTkyLDEzMTkzLDEzMjU2LDEzMjIzLDEzMjI0LDEzMjMyLDEzMjMzLDEzMjM0LDEzMjM1LDEzMjM2LDEzMjM3LDEzMjM4LDEzMjM5LDEzMjQwLDEzMjQxLDEzMTg0LDEzMTg1LDEzMTg2LDEzMTg3LDEzMTg4LDEzMjQyLDEzMjQzLDEzMjQ0LDEzMjQ1LDEzMjQ2LDEzMjQ3LDEzMjAwLDEzMjAxLDEzMjAyLDEzMjAzLDEzMjA0LDg0ODYsMTMyNDgsMTMyNDksMTMxOTQsMTMxOTUsMTMxOTYsMTMyNzAsMTMyNTMsMTMyMjksMTMyMzAsMTMyMzEsMTMyNzUsMTMyMjUsMTMyMjYsMTMyMjcsMTMyMjgsMTMyNzcsMTMyNjQsMTMyNjcsMTMyNTEsMTMyNTcsMTMyNzYsMTMyNTQsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTIwNzcsNTIwNzgsNTIwNzksNTIwODAsNTIwODEsNTIwODIsNTIwODMsNTIwODQsNTIwODUsNTIwODYsNTIwODcsNTIwOTAsNTIwOTEsNTIwOTIsNTIwOTMsNTIwOTQsNTIwOTUsNTIwOTYsNTIwOTcsNTIwOTgsNTIwOTksNTIxMDAsNTIxMDEsNTIxMDIsNTIxMDMsNTIxMDQsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTIxMDUsNTIxMDYsNTIxMDcsNTIxMDgsNTIxMDksNTIxMTAsNTIxMTEsNTIxMTIsNTIxMTMsNTIxMTQsNTIxMTUsNTIxMTYsNTIxMTcsNTIxMTgsNTIxMTksNTIxMjAsNTIxMjEsNTIxMjIsNTIxMjMsNTIxMjUsNTIxMjYsNTIxMjcsNTIxMjgsNTIxMjksNTIxMzAsNTIxMzEsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTIxMzIsNTIxMzMsNTIxMzQsNTIxMzUsNTIxMzYsNTIxMzcsNTIxMzgsNTIxMzksNTIxNDAsNTIxNDEsNTIxNDIsNTIxNDMsNTIxNDQsNTIxNDUsNTIxNDYsNTIxNDcsNTIxNDgsNTIxNDksNTIxNTAsNTIxNTEsNTIxNTMsNTIxNTQsNTIxNTUsNTIxNTYsNTIxNTcsNTIxNTgsNTIxNTksNTIxNjAsNTIxNjEsNTIxNjIsNTIxNjMsNTIxNjQsMTk4LDIwOCwxNzAsMjk0LG51bGwsMzA2LG51bGwsMzE5LDMyMSwyMTYsMzM4LDE4NiwyMjIsMzU4LDMzMCxudWxsLDEyODk2LDEyODk3LDEyODk4LDEyODk5LDEyOTAwLDEyOTAxLDEyOTAyLDEyOTAzLDEyOTA0LDEyOTA1LDEyOTA2LDEyOTA3LDEyOTA4LDEyOTA5LDEyOTEwLDEyOTExLDEyOTEyLDEyOTEzLDEyOTE0LDEyOTE1LDEyOTE2LDEyOTE3LDEyOTE4LDEyOTE5LDEyOTIwLDEyOTIxLDEyOTIyLDEyOTIzLDk0MjQsOTQyNSw5NDI2LDk0MjcsOTQyOCw5NDI5LDk0MzAsOTQzMSw5NDMyLDk0MzMsOTQzNCw5NDM1LDk0MzYsOTQzNyw5NDM4LDk0MzksOTQ0MCw5NDQxLDk0NDIsOTQ0Myw5NDQ0LDk0NDUsOTQ0Niw5NDQ3LDk0NDgsOTQ0OSw5MzEyLDkzMTMsOTMxNCw5MzE1LDkzMTYsOTMxNyw5MzE4LDkzMTksOTMyMCw5MzIxLDkzMjIsOTMyMyw5MzI0LDkzMjUsOTMyNiwxODksODUzMSw4NTMyLDE4OCwxOTAsODUzOSw4NTQwLDg1NDEsODU0Miw1MjE2NSw1MjE2Niw1MjE2Nyw1MjE2OCw1MjE2OSw1MjE3MCw1MjE3MSw1MjE3Miw1MjE3Myw1MjE3NCw1MjE3NSw1MjE3Niw1MjE3Nyw1MjE3OCw1MjE3OSw1MjE4MSw1MjE4Miw1MjE4Myw1MjE4NCw1MjE4NSw1MjE4Niw1MjE4Nyw1MjE4OCw1MjE4OSw1MjE5MCw1MjE5MSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MjE5Miw1MjE5Myw1MjE5NCw1MjE5NSw1MjE5Nyw1MjE5OCw1MjIwMCw1MjIwMiw1MjIwMyw1MjIwNCw1MjIwNSw1MjIwNiw1MjIwNyw1MjIwOCw1MjIwOSw1MjIxMCw1MjIxMSw1MjIxMiw1MjIxMyw1MjIxNCw1MjIxNSw1MjIxNiw1MjIxNyw1MjIxOCw1MjIxOSw1MjIyMCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MjIyMSw1MjIyMiw1MjIyMyw1MjIyNCw1MjIyNSw1MjIyNiw1MjIyNyw1MjIyOCw1MjIyOSw1MjIzMCw1MjIzMSw1MjIzMiw1MjIzMyw1MjIzNCw1MjIzNSw1MjIzOCw1MjIzOSw1MjI0MSw1MjI0Miw1MjI0Myw1MjI0NSw1MjI0Niw1MjI0Nyw1MjI0OCw1MjI0OSw1MjI1MCw1MjI1MSw1MjI1NCw1MjI1NSw1MjI1Niw1MjI1OSw1MjI2MCwyMzAsMjczLDI0MCwyOTUsMzA1LDMwNywzMTIsMzIwLDMyMiwyNDgsMzM5LDIyMywyNTQsMzU5LDMzMSwzMjksMTI4MDAsMTI4MDEsMTI4MDIsMTI4MDMsMTI4MDQsMTI4MDUsMTI4MDYsMTI4MDcsMTI4MDgsMTI4MDksMTI4MTAsMTI4MTEsMTI4MTIsMTI4MTMsMTI4MTQsMTI4MTUsMTI4MTYsMTI4MTcsMTI4MTgsMTI4MTksMTI4MjAsMTI4MjEsMTI4MjIsMTI4MjMsMTI4MjQsMTI4MjUsMTI4MjYsMTI4MjcsOTM3Miw5MzczLDkzNzQsOTM3NSw5Mzc2LDkzNzcsOTM3OCw5Mzc5LDkzODAsOTM4MSw5MzgyLDkzODMsOTM4NCw5Mzg1LDkzODYsOTM4Nyw5Mzg4LDkzODksOTM5MCw5MzkxLDkzOTIsOTM5Myw5Mzk0LDkzOTUsOTM5Niw5Mzk3LDkzMzIsOTMzMyw5MzM0LDkzMzUsOTMzNiw5MzM3LDkzMzgsOTMzOSw5MzQwLDkzNDEsOTM0Miw5MzQzLDkzNDQsOTM0NSw5MzQ2LDE4NSwxNzgsMTc5LDgzMDgsODMxOSw4MzIxLDgzMjIsODMyMyw4MzI0LDUyMjYxLDUyMjYyLDUyMjY2LDUyMjY3LDUyMjY5LDUyMjcxLDUyMjczLDUyMjc0LDUyMjc1LDUyMjc2LDUyMjc3LDUyMjc4LDUyMjc5LDUyMjgyLDUyMjg3LDUyMjg4LDUyMjg5LDUyMjkwLDUyMjkxLDUyMjk0LDUyMjk1LDUyMjk3LDUyMjk4LDUyMjk5LDUyMzAxLDUyMzAyLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDUyMzAzLDUyMzA0LDUyMzA1LDUyMzA2LDUyMzA3LDUyMzEwLDUyMzE0LDUyMzE1LDUyMzE2LDUyMzE3LDUyMzE4LDUyMzE5LDUyMzIxLDUyMzIyLDUyMzIzLDUyMzI1LDUyMzI3LDUyMzI5LDUyMzMwLDUyMzMxLDUyMzMyLDUyMzMzLDUyMzM0LDUyMzM1LDUyMzM3LDUyMzM4LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDUyMzM5LDUyMzQwLDUyMzQyLDUyMzQzLDUyMzQ0LDUyMzQ1LDUyMzQ2LDUyMzQ3LDUyMzQ4LDUyMzQ5LDUyMzUwLDUyMzUxLDUyMzUyLDUyMzUzLDUyMzU0LDUyMzU1LDUyMzU2LDUyMzU3LDUyMzU4LDUyMzU5LDUyMzYwLDUyMzYxLDUyMzYyLDUyMzYzLDUyMzY0LDUyMzY1LDUyMzY2LDUyMzY3LDUyMzY4LDUyMzY5LDUyMzcwLDUyMzcxLDEyMzUzLDEyMzU0LDEyMzU1LDEyMzU2LDEyMzU3LDEyMzU4LDEyMzU5LDEyMzYwLDEyMzYxLDEyMzYyLDEyMzYzLDEyMzY0LDEyMzY1LDEyMzY2LDEyMzY3LDEyMzY4LDEyMzY5LDEyMzcwLDEyMzcxLDEyMzcyLDEyMzczLDEyMzc0LDEyMzc1LDEyMzc2LDEyMzc3LDEyMzc4LDEyMzc5LDEyMzgwLDEyMzgxLDEyMzgyLDEyMzgzLDEyMzg0LDEyMzg1LDEyMzg2LDEyMzg3LDEyMzg4LDEyMzg5LDEyMzkwLDEyMzkxLDEyMzkyLDEyMzkzLDEyMzk0LDEyMzk1LDEyMzk2LDEyMzk3LDEyMzk4LDEyMzk5LDEyNDAwLDEyNDAxLDEyNDAyLDEyNDAzLDEyNDA0LDEyNDA1LDEyNDA2LDEyNDA3LDEyNDA4LDEyNDA5LDEyNDEwLDEyNDExLDEyNDEyLDEyNDEzLDEyNDE0LDEyNDE1LDEyNDE2LDEyNDE3LDEyNDE4LDEyNDE5LDEyNDIwLDEyNDIxLDEyNDIyLDEyNDIzLDEyNDI0LDEyNDI1LDEyNDI2LDEyNDI3LDEyNDI4LDEyNDI5LDEyNDMwLDEyNDMxLDEyNDMyLDEyNDMzLDEyNDM0LDEyNDM1LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MjM3Miw1MjM3Myw1MjM3NCw1MjM3NSw1MjM3OCw1MjM3OSw1MjM4MSw1MjM4Miw1MjM4Myw1MjM4NSw1MjM4Niw1MjM4Nyw1MjM4OCw1MjM4OSw1MjM5MCw1MjM5MSw1MjM5NCw1MjM5OCw1MjM5OSw1MjQwMCw1MjQwMSw1MjQwMiw1MjQwMyw1MjQwNiw1MjQwNyw1MjQwOSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MjQxMCw1MjQxMSw1MjQxMyw1MjQxNCw1MjQxNSw1MjQxNiw1MjQxNyw1MjQxOCw1MjQxOSw1MjQyMiw1MjQyNCw1MjQyNiw1MjQyNyw1MjQyOCw1MjQyOSw1MjQzMCw1MjQzMSw1MjQzMyw1MjQzNCw1MjQzNSw1MjQzNyw1MjQzOCw1MjQzOSw1MjQ0MCw1MjQ0MSw1MjQ0MixudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MjQ0Myw1MjQ0NCw1MjQ0NSw1MjQ0Niw1MjQ0Nyw1MjQ0OCw1MjQ0OSw1MjQ1MCw1MjQ1MSw1MjQ1Myw1MjQ1NCw1MjQ1NSw1MjQ1Niw1MjQ1Nyw1MjQ1OCw1MjQ1OSw1MjQ2MSw1MjQ2Miw1MjQ2Myw1MjQ2NSw1MjQ2Niw1MjQ2Nyw1MjQ2OCw1MjQ2OSw1MjQ3MCw1MjQ3MSw1MjQ3Miw1MjQ3Myw1MjQ3NCw1MjQ3NSw1MjQ3Niw1MjQ3NywxMjQ0OSwxMjQ1MCwxMjQ1MSwxMjQ1MiwxMjQ1MywxMjQ1NCwxMjQ1NSwxMjQ1NiwxMjQ1NywxMjQ1OCwxMjQ1OSwxMjQ2MCwxMjQ2MSwxMjQ2MiwxMjQ2MywxMjQ2NCwxMjQ2NSwxMjQ2NiwxMjQ2NywxMjQ2OCwxMjQ2OSwxMjQ3MCwxMjQ3MSwxMjQ3MiwxMjQ3MywxMjQ3NCwxMjQ3NSwxMjQ3NiwxMjQ3NywxMjQ3OCwxMjQ3OSwxMjQ4MCwxMjQ4MSwxMjQ4MiwxMjQ4MywxMjQ4NCwxMjQ4NSwxMjQ4NiwxMjQ4NywxMjQ4OCwxMjQ4OSwxMjQ5MCwxMjQ5MSwxMjQ5MiwxMjQ5MywxMjQ5NCwxMjQ5NSwxMjQ5NiwxMjQ5NywxMjQ5OCwxMjQ5OSwxMjUwMCwxMjUwMSwxMjUwMiwxMjUwMywxMjUwNCwxMjUwNSwxMjUwNiwxMjUwNywxMjUwOCwxMjUwOSwxMjUxMCwxMjUxMSwxMjUxMiwxMjUxMywxMjUxNCwxMjUxNSwxMjUxNiwxMjUxNywxMjUxOCwxMjUxOSwxMjUyMCwxMjUyMSwxMjUyMiwxMjUyMywxMjUyNCwxMjUyNSwxMjUyNiwxMjUyNywxMjUyOCwxMjUyOSwxMjUzMCwxMjUzMSwxMjUzMiwxMjUzMywxMjUzNCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTI0NzgsNTI0NzksNTI0ODAsNTI0ODIsNTI0ODMsNTI0ODQsNTI0ODUsNTI0ODYsNTI0ODcsNTI0OTAsNTI0OTEsNTI0OTMsNTI0OTQsNTI0OTUsNTI0OTcsNTI0OTgsNTI0OTksNTI1MDAsNTI1MDEsNTI1MDIsNTI1MDMsNTI1MDYsNTI1MDgsNTI1MTAsNTI1MTEsNTI1MTIsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTI1MTMsNTI1MTQsNTI1MTUsNTI1MTcsNTI1MTgsNTI1MTksNTI1MjEsNTI1MjIsNTI1MjMsNTI1MjUsNTI1MjYsNTI1MjcsNTI1MjgsNTI1MjksNTI1MzAsNTI1MzEsNTI1MzIsNTI1MzMsNTI1MzQsNTI1MzUsNTI1MzYsNTI1MzgsNTI1MzksNTI1NDAsNTI1NDEsNTI1NDIsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTI1NDMsNTI1NDQsNTI1NDUsNTI1NDYsNTI1NDcsNTI1NDgsNTI1NDksNTI1NTAsNTI1NTEsNTI1NTIsNTI1NTMsNTI1NTQsNTI1NTUsNTI1NTYsNTI1NTcsNTI1NTgsNTI1NTksNTI1NjAsNTI1NjEsNTI1NjIsNTI1NjMsNTI1NjQsNTI1NjUsNTI1NjYsNTI1NjcsNTI1NjgsNTI1NjksNTI1NzAsNTI1NzEsNTI1NzMsNTI1NzQsNTI1NzUsMTA0MCwxMDQxLDEwNDIsMTA0MywxMDQ0LDEwNDUsMTAyNSwxMDQ2LDEwNDcsMTA0OCwxMDQ5LDEwNTAsMTA1MSwxMDUyLDEwNTMsMTA1NCwxMDU1LDEwNTYsMTA1NywxMDU4LDEwNTksMTA2MCwxMDYxLDEwNjIsMTA2MywxMDY0LDEwNjUsMTA2NiwxMDY3LDEwNjgsMTA2OSwxMDcwLDEwNzEsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsMTA3MiwxMDczLDEwNzQsMTA3NSwxMDc2LDEwNzcsMTEwNSwxMDc4LDEwNzksMTA4MCwxMDgxLDEwODIsMTA4MywxMDg0LDEwODUsMTA4NiwxMDg3LDEwODgsMTA4OSwxMDkwLDEwOTEsMTA5MiwxMDkzLDEwOTQsMTA5NSwxMDk2LDEwOTcsMTA5OCwxMDk5LDExMDAsMTEwMSwxMTAyLDExMDMsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MjU3Nyw1MjU3OCw1MjU3OSw1MjU4MSw1MjU4Miw1MjU4Myw1MjU4NCw1MjU4NSw1MjU4Niw1MjU4Nyw1MjU5MCw1MjU5Miw1MjU5NCw1MjU5NSw1MjU5Niw1MjU5Nyw1MjU5OCw1MjU5OSw1MjYwMSw1MjYwMiw1MjYwMyw1MjYwNCw1MjYwNSw1MjYwNiw1MjYwNyw1MjYwOCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MjYwOSw1MjYxMCw1MjYxMSw1MjYxMiw1MjYxMyw1MjYxNCw1MjYxNSw1MjYxNyw1MjYxOCw1MjYxOSw1MjYyMCw1MjYyMSw1MjYyMiw1MjYyMyw1MjYyNCw1MjYyNSw1MjYyNiw1MjYyNyw1MjYzMCw1MjYzMSw1MjYzMyw1MjYzNCw1MjYzNSw1MjYzNyw1MjYzOCw1MjYzOSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MjY0MCw1MjY0MSw1MjY0Miw1MjY0Myw1MjY0Niw1MjY0OCw1MjY1MCw1MjY1MSw1MjY1Miw1MjY1Myw1MjY1NCw1MjY1NSw1MjY1Nyw1MjY1OCw1MjY1OSw1MjY2MCw1MjY2MSw1MjY2Miw1MjY2Myw1MjY2NCw1MjY2NSw1MjY2Niw1MjY2Nyw1MjY2OCw1MjY2OSw1MjY3MCw1MjY3MSw1MjY3Miw1MjY3Myw1MjY3NCw1MjY3NSw1MjY3NyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDUyNjc4LDUyNjc5LDUyNjgwLDUyNjgxLDUyNjgyLDUyNjgzLDUyNjg1LDUyNjg2LDUyNjg3LDUyNjg5LDUyNjkwLDUyNjkxLDUyNjkyLDUyNjkzLDUyNjk0LDUyNjk1LDUyNjk2LDUyNjk3LDUyNjk4LDUyNjk5LDUyNzAwLDUyNzAxLDUyNzAyLDUyNzAzLDUyNzA0LDUyNzA1LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDUyNzA2LDUyNzA3LDUyNzA4LDUyNzA5LDUyNzEwLDUyNzExLDUyNzEzLDUyNzE0LDUyNzE1LDUyNzE3LDUyNzE4LDUyNzE5LDUyNzIxLDUyNzIyLDUyNzIzLDUyNzI0LDUyNzI1LDUyNzI2LDUyNzI3LDUyNzMwLDUyNzMyLDUyNzM0LDUyNzM1LDUyNzM2LDUyNzM3LDUyNzM4LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDUyNzM5LDUyNzQxLDUyNzQyLDUyNzQzLDUyNzQ1LDUyNzQ2LDUyNzQ3LDUyNzQ5LDUyNzUwLDUyNzUxLDUyNzUyLDUyNzUzLDUyNzU0LDUyNzU1LDUyNzU3LDUyNzU4LDUyNzU5LDUyNzYwLDUyNzYyLDUyNzYzLDUyNzY0LDUyNzY1LDUyNzY2LDUyNzY3LDUyNzcwLDUyNzcxLDUyNzczLDUyNzc0LDUyNzc1LDUyNzc3LDUyNzc4LDUyNzc5LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTI3ODAsNTI3ODEsNTI3ODIsNTI3ODMsNTI3ODYsNTI3ODgsNTI3OTAsNTI3OTEsNTI3OTIsNTI3OTMsNTI3OTQsNTI3OTUsNTI3OTYsNTI3OTcsNTI3OTgsNTI3OTksNTI4MDAsNTI4MDEsNTI4MDIsNTI4MDMsNTI4MDQsNTI4MDUsNTI4MDYsNTI4MDcsNTI4MDgsNTI4MDksbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTI4MTAsNTI4MTEsNTI4MTIsNTI4MTMsNTI4MTQsNTI4MTUsNTI4MTYsNTI4MTcsNTI4MTgsNTI4MTksNTI4MjAsNTI4MjEsNTI4MjIsNTI4MjMsNTI4MjYsNTI4MjcsNTI4MjksNTI4MzAsNTI4MzQsNTI4MzUsNTI4MzYsNTI4MzcsNTI4MzgsNTI4MzksNTI4NDIsNTI4NDQsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNTI4NDYsNTI4NDcsNTI4NDgsNTI4NDksNTI4NTAsNTI4NTEsNTI4NTQsNTI4NTUsNTI4NTcsNTI4NTgsNTI4NTksNTI4NjEsNTI4NjIsNTI4NjMsNTI4NjQsNTI4NjUsNTI4NjYsNTI4NjcsNTI4NzAsNTI4NzIsNTI4NzQsNTI4NzUsNTI4NzYsNTI4NzcsNTI4NzgsNTI4NzksNTI4ODIsNTI4ODMsNTI4ODUsNTI4ODYsNTI4ODcsNTI4ODksbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1Mjg5MCw1Mjg5MSw1Mjg5Miw1Mjg5Myw1Mjg5NCw1Mjg5NSw1Mjg5OCw1MjkwMiw1MjkwMyw1MjkwNCw1MjkwNSw1MjkwNiw1MjkwNyw1MjkxMCw1MjkxMSw1MjkxMiw1MjkxMyw1MjkxNCw1MjkxNSw1MjkxNiw1MjkxNyw1MjkxOCw1MjkxOSw1MjkyMCw1MjkyMSw1MjkyMixudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MjkyMyw1MjkyNCw1MjkyNSw1MjkyNiw1MjkyNyw1MjkyOCw1MjkzMCw1MjkzMSw1MjkzMiw1MjkzMyw1MjkzNCw1MjkzNSw1MjkzNiw1MjkzNyw1MjkzOCw1MjkzOSw1Mjk0MCw1Mjk0MSw1Mjk0Miw1Mjk0Myw1Mjk0NCw1Mjk0NSw1Mjk0Niw1Mjk0Nyw1Mjk0OCw1Mjk0OSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1Mjk1MCw1Mjk1MSw1Mjk1Miw1Mjk1Myw1Mjk1NCw1Mjk1NSw1Mjk1Niw1Mjk1Nyw1Mjk1OCw1Mjk1OSw1Mjk2MCw1Mjk2MSw1Mjk2Miw1Mjk2Myw1Mjk2Niw1Mjk2Nyw1Mjk2OSw1Mjk3MCw1Mjk3Myw1Mjk3NCw1Mjk3NSw1Mjk3Niw1Mjk3Nyw1Mjk3OCw1Mjk3OSw1Mjk4Miw1Mjk4Niw1Mjk4Nyw1Mjk4OCw1Mjk4OSw1Mjk5MCw1Mjk5MSw0NDAzMiw0NDAzMyw0NDAzNiw0NDAzOSw0NDA0MCw0NDA0MSw0NDA0Miw0NDA0OCw0NDA0OSw0NDA1MCw0NDA1MSw0NDA1Miw0NDA1Myw0NDA1NCw0NDA1NSw0NDA1Nyw0NDA1OCw0NDA1OSw0NDA2MCw0NDA2MSw0NDA2NCw0NDA2OCw0NDA3Niw0NDA3Nyw0NDA3OSw0NDA4MCw0NDA4MSw0NDA4OCw0NDA4OSw0NDA5Miw0NDA5Niw0NDEwNyw0NDEwOSw0NDExNiw0NDEyMCw0NDEyNCw0NDE0NCw0NDE0NSw0NDE0OCw0NDE1MSw0NDE1Miw0NDE1NCw0NDE2MCw0NDE2MSw0NDE2Myw0NDE2NCw0NDE2NSw0NDE2Niw0NDE2OSw0NDE3MCw0NDE3MSw0NDE3Miw0NDE3Niw0NDE4MCw0NDE4OCw0NDE4OSw0NDE5MSw0NDE5Miw0NDE5Myw0NDIwMCw0NDIwMSw0NDIwMiw0NDIwNCw0NDIwNyw0NDIwOCw0NDIxNiw0NDIxNyw0NDIxOSw0NDIyMCw0NDIyMSw0NDIyNSw0NDIyOCw0NDIzMiw0NDIzNiw0NDI0NSw0NDI0Nyw0NDI1Niw0NDI1Nyw0NDI2MCw0NDI2Myw0NDI2NCw0NDI2Niw0NDI2OCw0NDI3MSw0NDI3Miw0NDI3Myw0NDI3NSw0NDI3Nyw0NDI3OCw0NDI4NCw0NDI4NSw0NDI4OCw0NDI5Miw0NDI5NCw1Mjk5NCw1Mjk5NSw1Mjk5Nyw1Mjk5OCw1Mjk5OSw1MzAwMSw1MzAwMiw1MzAwMyw1MzAwNCw1MzAwNSw1MzAwNiw1MzAwNyw1MzAxMCw1MzAxMiw1MzAxNCw1MzAxNSw1MzAxNiw1MzAxNyw1MzAxOCw1MzAxOSw1MzAyMSw1MzAyMiw1MzAyMyw1MzAyNSw1MzAyNiw1MzAyNyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MzAyOSw1MzAzMCw1MzAzMSw1MzAzMiw1MzAzMyw1MzAzNCw1MzAzNSw1MzAzOCw1MzA0Miw1MzA0Myw1MzA0NCw1MzA0NSw1MzA0Niw1MzA0Nyw1MzA0OSw1MzA1MCw1MzA1MSw1MzA1Miw1MzA1Myw1MzA1NCw1MzA1NSw1MzA1Niw1MzA1Nyw1MzA1OCw1MzA1OSw1MzA2MCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MzA2MSw1MzA2Miw1MzA2Myw1MzA2NCw1MzA2NSw1MzA2Niw1MzA2Nyw1MzA2OCw1MzA2OSw1MzA3MCw1MzA3MSw1MzA3Miw1MzA3Myw1MzA3NCw1MzA3NSw1MzA3OCw1MzA3OSw1MzA4MSw1MzA4Miw1MzA4Myw1MzA4NSw1MzA4Niw1MzA4Nyw1MzA4OCw1MzA4OSw1MzA5MCw1MzA5MSw1MzA5NCw1MzA5Niw1MzA5OCw1MzA5OSw1MzEwMCw0NDMwMCw0NDMwMSw0NDMwMyw0NDMwNSw0NDMxMiw0NDMxNiw0NDMyMCw0NDMyOSw0NDMzMiw0NDMzMyw0NDM0MCw0NDM0MSw0NDM0NCw0NDM0OCw0NDM1Niw0NDM1Nyw0NDM1OSw0NDM2MSw0NDM2OCw0NDM3Miw0NDM3Niw0NDM4NSw0NDM4Nyw0NDM5Niw0NDM5Nyw0NDQwMCw0NDQwMyw0NDQwNCw0NDQwNSw0NDQwNiw0NDQxMSw0NDQxMiw0NDQxMyw0NDQxNSw0NDQxNyw0NDQxOCw0NDQyNCw0NDQyNSw0NDQyOCw0NDQzMiw0NDQ0NCw0NDQ0NSw0NDQ1Miw0NDQ3MSw0NDQ4MCw0NDQ4MSw0NDQ4NCw0NDQ4OCw0NDQ5Niw0NDQ5Nyw0NDQ5OSw0NDUwOCw0NDUxMiw0NDUxNiw0NDUzNiw0NDUzNyw0NDU0MCw0NDU0Myw0NDU0NCw0NDU0NSw0NDU1Miw0NDU1Myw0NDU1NSw0NDU1Nyw0NDU2NCw0NDU5Miw0NDU5Myw0NDU5Niw0NDU5OSw0NDYwMCw0NDYwMiw0NDYwOCw0NDYwOSw0NDYxMSw0NDYxMyw0NDYxNCw0NDYxOCw0NDYyMCw0NDYyMSw0NDYyMiw0NDYyNCw0NDYyOCw0NDYzMCw0NDYzNiw0NDYzNyw0NDYzOSw0NDY0MCw0NDY0MSw0NDY0NSw0NDY0OCw0NDY0OSw0NDY1Miw0NDY1Niw0NDY2NCw1MzEwMSw1MzEwMiw1MzEwMyw1MzEwNiw1MzEwNyw1MzEwOSw1MzExMCw1MzExMSw1MzExMyw1MzExNCw1MzExNSw1MzExNiw1MzExNyw1MzExOCw1MzExOSw1MzEyMSw1MzEyMiw1MzEyMyw1MzEyNCw1MzEyNiw1MzEyNyw1MzEyOCw1MzEyOSw1MzEzMCw1MzEzMSw1MzEzMyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MzEzNCw1MzEzNSw1MzEzNiw1MzEzNyw1MzEzOCw1MzEzOSw1MzE0MCw1MzE0MSw1MzE0Miw1MzE0Myw1MzE0NCw1MzE0NSw1MzE0Niw1MzE0Nyw1MzE0OCw1MzE0OSw1MzE1MCw1MzE1MSw1MzE1Miw1MzE1NCw1MzE1NSw1MzE1Niw1MzE1Nyw1MzE1OCw1MzE1OSw1MzE2MSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MzE2Miw1MzE2Myw1MzE2NCw1MzE2NSw1MzE2Niw1MzE2Nyw1MzE2OSw1MzE3MCw1MzE3MSw1MzE3Miw1MzE3Myw1MzE3NCw1MzE3NSw1MzE3Niw1MzE3Nyw1MzE3OCw1MzE3OSw1MzE4MCw1MzE4MSw1MzE4Miw1MzE4Myw1MzE4NCw1MzE4NSw1MzE4Niw1MzE4Nyw1MzE4OSw1MzE5MCw1MzE5MSw1MzE5Miw1MzE5Myw1MzE5NCw1MzE5NSw0NDY2NSw0NDY2Nyw0NDY2OCw0NDY2OSw0NDY3Niw0NDY3Nyw0NDY4NCw0NDczMiw0NDczMyw0NDczNCw0NDczNiw0NDc0MCw0NDc0OCw0NDc0OSw0NDc1MSw0NDc1Miw0NDc1Myw0NDc2MCw0NDc2MSw0NDc2NCw0NDc3Niw0NDc3OSw0NDc4MSw0NDc4OCw0NDc5Miw0NDc5Niw0NDgwNyw0NDgwOCw0NDgxMyw0NDgxNiw0NDg0NCw0NDg0NSw0NDg0OCw0NDg1MCw0NDg1Miw0NDg2MCw0NDg2MSw0NDg2Myw0NDg2NSw0NDg2Niw0NDg2Nyw0NDg3Miw0NDg3Myw0NDg4MCw0NDg5Miw0NDg5Myw0NDkwMCw0NDkwMSw0NDkyMSw0NDkyOCw0NDkzMiw0NDkzNiw0NDk0NCw0NDk0NSw0NDk0OSw0NDk1Niw0NDk4NCw0NDk4NSw0NDk4OCw0NDk5Miw0NDk5OSw0NTAwMCw0NTAwMSw0NTAwMyw0NTAwNSw0NTAwNiw0NTAxMiw0NTAyMCw0NTAzMiw0NTAzMyw0NTA0MCw0NTA0MSw0NTA0NCw0NTA0OCw0NTA1Niw0NTA1Nyw0NTA2MCw0NTA2OCw0NTA3Miw0NTA3Niw0NTA4NCw0NTA4NSw0NTA5Niw0NTEyNCw0NTEyNSw0NTEyOCw0NTEzMCw0NTEzMiw0NTEzNCw0NTEzOSw0NTE0MCw0NTE0MSw0NTE0Myw0NTE0NSw1MzE5Niw1MzE5Nyw1MzE5OCw1MzE5OSw1MzIwMCw1MzIwMSw1MzIwMiw1MzIwMyw1MzIwNCw1MzIwNSw1MzIwNiw1MzIwNyw1MzIwOCw1MzIwOSw1MzIxMCw1MzIxMSw1MzIxMiw1MzIxMyw1MzIxNCw1MzIxNSw1MzIxOCw1MzIxOSw1MzIyMSw1MzIyMiw1MzIyMyw1MzIyNSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MzIyNiw1MzIyNyw1MzIyOCw1MzIyOSw1MzIzMCw1MzIzMSw1MzIzNCw1MzIzNiw1MzIzOCw1MzIzOSw1MzI0MCw1MzI0MSw1MzI0Miw1MzI0Myw1MzI0NSw1MzI0Niw1MzI0Nyw1MzI0OSw1MzI1MCw1MzI1MSw1MzI1Myw1MzI1NCw1MzI1NSw1MzI1Niw1MzI1Nyw1MzI1OCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MzI1OSw1MzI2MCw1MzI2MSw1MzI2Miw1MzI2Myw1MzI2NCw1MzI2Niw1MzI2Nyw1MzI2OCw1MzI2OSw1MzI3MCw1MzI3MSw1MzI3Myw1MzI3NCw1MzI3NSw1MzI3Niw1MzI3Nyw1MzI3OCw1MzI3OSw1MzI4MCw1MzI4MSw1MzI4Miw1MzI4Myw1MzI4NCw1MzI4NSw1MzI4Niw1MzI4Nyw1MzI4OCw1MzI4OSw1MzI5MCw1MzI5MSw1MzI5Miw0NTE0OSw0NTE4MCw0NTE4MSw0NTE4NCw0NTE4OCw0NTE5Niw0NTE5Nyw0NTE5OSw0NTIwMSw0NTIwOCw0NTIwOSw0NTIxMCw0NTIxMiw0NTIxNSw0NTIxNiw0NTIxNyw0NTIxOCw0NTIyNCw0NTIyNSw0NTIyNyw0NTIyOCw0NTIyOSw0NTIzMCw0NTIzMSw0NTIzMyw0NTIzNSw0NTIzNiw0NTIzNyw0NTI0MCw0NTI0NCw0NTI1Miw0NTI1Myw0NTI1NSw0NTI1Niw0NTI1Nyw0NTI2NCw0NTI2NSw0NTI2OCw0NTI3Miw0NTI4MCw0NTI4NSw0NTMyMCw0NTMyMSw0NTMyMyw0NTMyNCw0NTMyOCw0NTMzMCw0NTMzMSw0NTMzNiw0NTMzNyw0NTMzOSw0NTM0MCw0NTM0MSw0NTM0Nyw0NTM0OCw0NTM0OSw0NTM1Miw0NTM1Niw0NTM2NCw0NTM2NSw0NTM2Nyw0NTM2OCw0NTM2OSw0NTM3Niw0NTM3Nyw0NTM4MCw0NTM4NCw0NTM5Miw0NTM5Myw0NTM5Niw0NTM5Nyw0NTQwMCw0NTQwNCw0NTQwOCw0NTQzMiw0NTQzMyw0NTQzNiw0NTQ0MCw0NTQ0Miw0NTQ0OCw0NTQ0OSw0NTQ1MSw0NTQ1Myw0NTQ1OCw0NTQ1OSw0NTQ2MCw0NTQ2NCw0NTQ2OCw0NTQ4MCw0NTUxNiw0NTUyMCw0NTUyNCw0NTUzMiw0NTUzMyw1MzI5NCw1MzI5NSw1MzI5Niw1MzI5Nyw1MzI5OCw1MzI5OSw1MzMwMiw1MzMwMyw1MzMwNSw1MzMwNiw1MzMwNyw1MzMwOSw1MzMxMCw1MzMxMSw1MzMxMiw1MzMxMyw1MzMxNCw1MzMxNSw1MzMxOCw1MzMyMCw1MzMyMiw1MzMyMyw1MzMyNCw1MzMyNSw1MzMyNiw1MzMyNyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MzMyOSw1MzMzMCw1MzMzMSw1MzMzMyw1MzMzNCw1MzMzNSw1MzMzNyw1MzMzOCw1MzMzOSw1MzM0MCw1MzM0MSw1MzM0Miw1MzM0Myw1MzM0NSw1MzM0Niw1MzM0Nyw1MzM0OCw1MzM0OSw1MzM1MCw1MzM1MSw1MzM1Miw1MzM1Myw1MzM1NCw1MzM1NSw1MzM1OCw1MzM1OSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MzM2MSw1MzM2Miw1MzM2Myw1MzM2NSw1MzM2Niw1MzM2Nyw1MzM2OCw1MzM2OSw1MzM3MCw1MzM3MSw1MzM3NCw1MzM3NSw1MzM3Niw1MzM3OCw1MzM3OSw1MzM4MCw1MzM4MSw1MzM4Miw1MzM4Myw1MzM4NCw1MzM4NSw1MzM4Niw1MzM4Nyw1MzM4OCw1MzM4OSw1MzM5MCw1MzM5MSw1MzM5Miw1MzM5Myw1MzM5NCw1MzM5NSw1MzM5Niw0NTUzNSw0NTU0NCw0NTU0NSw0NTU0OCw0NTU1Miw0NTU2MSw0NTU2Myw0NTU2NSw0NTU3Miw0NTU3Myw0NTU3Niw0NTU3OSw0NTU4MCw0NTU4OCw0NTU4OSw0NTU5MSw0NTU5Myw0NTYwMCw0NTYyMCw0NTYyOCw0NTY1Niw0NTY2MCw0NTY2NCw0NTY3Miw0NTY3Myw0NTY4NCw0NTY4NSw0NTY5Miw0NTcwMCw0NTcwMSw0NTcwNSw0NTcxMiw0NTcxMyw0NTcxNiw0NTcyMCw0NTcyMSw0NTcyMiw0NTcyOCw0NTcyOSw0NTczMSw0NTczMyw0NTczNCw0NTczOCw0NTc0MCw0NTc0NCw0NTc0OCw0NTc2OCw0NTc2OSw0NTc3Miw0NTc3Niw0NTc3OCw0NTc4NCw0NTc4NSw0NTc4Nyw0NTc4OSw0NTc5NCw0NTc5Niw0NTc5Nyw0NTc5OCw0NTgwMCw0NTgwMyw0NTgwNCw0NTgwNSw0NTgwNiw0NTgwNyw0NTgxMSw0NTgxMiw0NTgxMyw0NTgxNSw0NTgxNiw0NTgxNyw0NTgxOCw0NTgxOSw0NTgyMyw0NTgyNCw0NTgyNSw0NTgyOCw0NTgzMiw0NTg0MCw0NTg0MSw0NTg0Myw0NTg0NCw0NTg0NSw0NTg1Miw0NTkwOCw0NTkwOSw0NTkxMCw0NTkxMiw0NTkxNSw0NTkxNiw0NTkxOCw0NTkxOSw0NTkyNCw0NTkyNSw1MzM5Nyw1MzM5OCw1MzM5OSw1MzQwMCw1MzQwMSw1MzQwMiw1MzQwMyw1MzQwNCw1MzQwNSw1MzQwNiw1MzQwNyw1MzQwOCw1MzQwOSw1MzQxMCw1MzQxMSw1MzQxNCw1MzQxNSw1MzQxNyw1MzQxOCw1MzQxOSw1MzQyMSw1MzQyMiw1MzQyMyw1MzQyNCw1MzQyNSw1MzQyNixudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MzQyNyw1MzQzMCw1MzQzMiw1MzQzNCw1MzQzNSw1MzQzNiw1MzQzNyw1MzQzOCw1MzQzOSw1MzQ0Miw1MzQ0Myw1MzQ0NSw1MzQ0Niw1MzQ0Nyw1MzQ1MCw1MzQ1MSw1MzQ1Miw1MzQ1Myw1MzQ1NCw1MzQ1NSw1MzQ1OCw1MzQ2Miw1MzQ2Myw1MzQ2NCw1MzQ2NSw1MzQ2NixudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MzQ2Nyw1MzQ3MCw1MzQ3MSw1MzQ3Myw1MzQ3NCw1MzQ3NSw1MzQ3Nyw1MzQ3OCw1MzQ3OSw1MzQ4MCw1MzQ4MSw1MzQ4Miw1MzQ4Myw1MzQ4Niw1MzQ5MCw1MzQ5MSw1MzQ5Miw1MzQ5Myw1MzQ5NCw1MzQ5NSw1MzQ5Nyw1MzQ5OCw1MzQ5OSw1MzUwMCw1MzUwMSw1MzUwMiw1MzUwMyw1MzUwNCw1MzUwNSw1MzUwNiw1MzUwNyw1MzUwOCw0NTkyNyw0NTkyOSw0NTkzMSw0NTkzNCw0NTkzNiw0NTkzNyw0NTk0MCw0NTk0NCw0NTk1Miw0NTk1Myw0NTk1NSw0NTk1Niw0NTk1Nyw0NTk2NCw0NTk2OCw0NTk3Miw0NTk4NCw0NTk4NSw0NTk5Miw0NTk5Niw0NjAyMCw0NjAyMSw0NjAyNCw0NjAyNyw0NjAyOCw0NjAzMCw0NjAzMiw0NjAzNiw0NjAzNyw0NjAzOSw0NjA0MSw0NjA0Myw0NjA0NSw0NjA0OCw0NjA1Miw0NjA1Niw0NjA3Niw0NjA5Niw0NjEwNCw0NjEwOCw0NjExMiw0NjEyMCw0NjEyMSw0NjEyMyw0NjEzMiw0NjE2MCw0NjE2MSw0NjE2NCw0NjE2OCw0NjE3Niw0NjE3Nyw0NjE3OSw0NjE4MSw0NjE4OCw0NjIwOCw0NjIxNiw0NjIzNyw0NjI0NCw0NjI0OCw0NjI1Miw0NjI2MSw0NjI2Myw0NjI2NSw0NjI3Miw0NjI3Niw0NjI4MCw0NjI4OCw0NjI5Myw0NjMwMCw0NjMwMSw0NjMwNCw0NjMwNyw0NjMwOCw0NjMxMCw0NjMxNiw0NjMxNyw0NjMxOSw0NjMyMSw0NjMyOCw0NjM1Niw0NjM1Nyw0NjM2MCw0NjM2Myw0NjM2NCw0NjM3Miw0NjM3Myw0NjM3NSw0NjM3Niw0NjM3Nyw0NjM3OCw0NjM4NCw0NjM4NSw0NjM4OCw0NjM5Miw1MzUwOSw1MzUxMCw1MzUxMSw1MzUxMiw1MzUxMyw1MzUxNCw1MzUxNSw1MzUxNiw1MzUxOCw1MzUxOSw1MzUyMCw1MzUyMSw1MzUyMiw1MzUyMyw1MzUyNCw1MzUyNSw1MzUyNiw1MzUyNyw1MzUyOCw1MzUyOSw1MzUzMCw1MzUzMSw1MzUzMiw1MzUzMyw1MzUzNCw1MzUzNSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MzUzNiw1MzUzNyw1MzUzOCw1MzUzOSw1MzU0MCw1MzU0MSw1MzU0Miw1MzU0Myw1MzU0NCw1MzU0NSw1MzU0Niw1MzU0Nyw1MzU0OCw1MzU0OSw1MzU1MCw1MzU1MSw1MzU1NCw1MzU1NSw1MzU1Nyw1MzU1OCw1MzU1OSw1MzU2MSw1MzU2Myw1MzU2NCw1MzU2NSw1MzU2NixudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MzU2Nyw1MzU3MCw1MzU3NCw1MzU3NSw1MzU3Niw1MzU3Nyw1MzU3OCw1MzU3OSw1MzU4Miw1MzU4Myw1MzU4NSw1MzU4Niw1MzU4Nyw1MzU4OSw1MzU5MCw1MzU5MSw1MzU5Miw1MzU5Myw1MzU5NCw1MzU5NSw1MzU5OCw1MzYwMCw1MzYwMiw1MzYwMyw1MzYwNCw1MzYwNSw1MzYwNiw1MzYwNyw1MzYwOSw1MzYxMCw1MzYxMSw1MzYxMyw0NjQwMCw0NjQwMSw0NjQwMyw0NjQwNCw0NjQwNSw0NjQxMSw0NjQxMiw0NjQxMyw0NjQxNiw0NjQyMCw0NjQyOCw0NjQyOSw0NjQzMSw0NjQzMiw0NjQzMyw0NjQ5Niw0NjQ5Nyw0NjUwMCw0NjUwNCw0NjUwNiw0NjUwNyw0NjUxMiw0NjUxMyw0NjUxNSw0NjUxNiw0NjUxNyw0NjUyMyw0NjUyNCw0NjUyNSw0NjUyOCw0NjUzMiw0NjU0MCw0NjU0MSw0NjU0Myw0NjU0NCw0NjU0NSw0NjU1Miw0NjU3Miw0NjYwOCw0NjYwOSw0NjYxMiw0NjYxNiw0NjYyOSw0NjYzNiw0NjY0NCw0NjY2NCw0NjY5Miw0NjY5Niw0Njc0OCw0Njc0OSw0Njc1Miw0Njc1Niw0Njc2Myw0Njc2NCw0Njc2OSw0NjgwNCw0NjgzMiw0NjgzNiw0Njg0MCw0Njg0OCw0Njg0OSw0Njg1Myw0Njg4OCw0Njg4OSw0Njg5Miw0Njg5NSw0Njg5Niw0NjkwNCw0NjkwNSw0NjkwNyw0NjkxNiw0NjkyMCw0NjkyNCw0NjkzMiw0NjkzMyw0Njk0NCw0Njk0OCw0Njk1Miw0Njk2MCw0Njk2MSw0Njk2Myw0Njk2NSw0Njk3Miw0Njk3Myw0Njk3Niw0Njk4MCw0Njk4OCw0Njk4OSw0Njk5MSw0Njk5Miw0Njk5Myw0Njk5NCw0Njk5OCw0Njk5OSw1MzYxNCw1MzYxNSw1MzYxNiw1MzYxNyw1MzYxOCw1MzYxOSw1MzYyMCw1MzYyMSw1MzYyMiw1MzYyMyw1MzYyNCw1MzYyNSw1MzYyNiw1MzYyNyw1MzYyOSw1MzYzMCw1MzYzMSw1MzYzMiw1MzYzMyw1MzYzNCw1MzYzNSw1MzYzNyw1MzYzOCw1MzYzOSw1MzY0MSw1MzY0MixudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MzY0Myw1MzY0NCw1MzY0NSw1MzY0Niw1MzY0Nyw1MzY0OCw1MzY0OSw1MzY1MCw1MzY1MSw1MzY1Miw1MzY1Myw1MzY1NCw1MzY1NSw1MzY1Niw1MzY1Nyw1MzY1OCw1MzY1OSw1MzY2MCw1MzY2MSw1MzY2Miw1MzY2Myw1MzY2Niw1MzY2Nyw1MzY2OSw1MzY3MCw1MzY3MSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MzY3Myw1MzY3NCw1MzY3NSw1MzY3Niw1MzY3Nyw1MzY3OCw1MzY3OSw1MzY4Miw1MzY4NCw1MzY4Niw1MzY4Nyw1MzY4OCw1MzY4OSw1MzY5MSw1MzY5Myw1MzY5NCw1MzY5NSw1MzY5Nyw1MzY5OCw1MzY5OSw1MzcwMCw1MzcwMSw1MzcwMiw1MzcwMyw1MzcwNCw1MzcwNSw1MzcwNiw1MzcwNyw1MzcwOCw1MzcwOSw1MzcxMCw1MzcxMSw0NzAwMCw0NzAwMSw0NzAwNCw0NzAwOCw0NzAxNiw0NzAxNyw0NzAxOSw0NzAyMCw0NzAyMSw0NzAyOCw0NzAyOSw0NzAzMiw0NzA0Nyw0NzA0OSw0NzA4NCw0NzA4NSw0NzA4OCw0NzA5Miw0NzEwMCw0NzEwMSw0NzEwMyw0NzEwNCw0NzEwNSw0NzExMSw0NzExMiw0NzExMyw0NzExNiw0NzEyMCw0NzEyOCw0NzEyOSw0NzEzMSw0NzEzMyw0NzE0MCw0NzE0MSw0NzE0NCw0NzE0OCw0NzE1Niw0NzE1Nyw0NzE1OSw0NzE2MCw0NzE2MSw0NzE2OCw0NzE3Miw0NzE4NSw0NzE4Nyw0NzE5Niw0NzE5Nyw0NzIwMCw0NzIwNCw0NzIxMiw0NzIxMyw0NzIxNSw0NzIxNyw0NzIyNCw0NzIyOCw0NzI0NSw0NzI3Miw0NzI4MCw0NzI4NCw0NzI4OCw0NzI5Niw0NzI5Nyw0NzI5OSw0NzMwMSw0NzMwOCw0NzMxMiw0NzMxNiw0NzMyNSw0NzMyNyw0NzMyOSw0NzMzNiw0NzMzNyw0NzM0MCw0NzM0NCw0NzM1Miw0NzM1Myw0NzM1NSw0NzM1Nyw0NzM2NCw0NzM4NCw0NzM5Miw0NzQyMCw0NzQyMSw0NzQyNCw0NzQyOCw0NzQzNiw0NzQzOSw0NzQ0MSw0NzQ0OCw0NzQ0OSw0NzQ1Miw0NzQ1Niw0NzQ2NCw0NzQ2NSw1MzcxMiw1MzcxMyw1MzcxNCw1MzcxNSw1MzcxNiw1MzcxNyw1MzcxOCw1MzcxOSw1MzcyMSw1MzcyMiw1MzcyMyw1MzcyNCw1MzcyNSw1MzcyNiw1MzcyNyw1MzcyOCw1MzcyOSw1MzczMCw1MzczMSw1MzczMiw1MzczMyw1MzczNCw1MzczNSw1MzczNiw1MzczNyw1MzczOCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MzczOSw1Mzc0MCw1Mzc0MSw1Mzc0Miw1Mzc0Myw1Mzc0NCw1Mzc0NSw1Mzc0Niw1Mzc0Nyw1Mzc0OSw1Mzc1MCw1Mzc1MSw1Mzc1Myw1Mzc1NCw1Mzc1NSw1Mzc1Niw1Mzc1Nyw1Mzc1OCw1Mzc1OSw1Mzc2MCw1Mzc2MSw1Mzc2Miw1Mzc2Myw1Mzc2NCw1Mzc2NSw1Mzc2NixudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1Mzc2OCw1Mzc3MCw1Mzc3MSw1Mzc3Miw1Mzc3Myw1Mzc3NCw1Mzc3NSw1Mzc3Nyw1Mzc3OCw1Mzc3OSw1Mzc4MCw1Mzc4MSw1Mzc4Miw1Mzc4Myw1Mzc4NCw1Mzc4NSw1Mzc4Niw1Mzc4Nyw1Mzc4OCw1Mzc4OSw1Mzc5MCw1Mzc5MSw1Mzc5Miw1Mzc5Myw1Mzc5NCw1Mzc5NSw1Mzc5Niw1Mzc5Nyw1Mzc5OCw1Mzc5OSw1MzgwMCw1MzgwMSw0NzQ2Nyw0NzQ2OSw0NzQ3Niw0NzQ3Nyw0NzQ4MCw0NzQ4NCw0NzQ5Miw0NzQ5Myw0NzQ5NSw0NzQ5Nyw0NzQ5OCw0NzUwMSw0NzUwMiw0NzUzMiw0NzUzMyw0NzUzNiw0NzU0MCw0NzU0OCw0NzU0OSw0NzU1MSw0NzU1Myw0NzU2MCw0NzU2MSw0NzU2NCw0NzU2Niw0NzU2Nyw0NzU2OCw0NzU2OSw0NzU3MCw0NzU3Niw0NzU3Nyw0NzU3OSw0NzU4MSw0NzU4Miw0NzU4NSw0NzU4Nyw0NzU4OCw0NzU4OSw0NzU5Miw0NzU5Niw0NzYwNCw0NzYwNSw0NzYwNyw0NzYwOCw0NzYwOSw0NzYxMCw0NzYxNiw0NzYxNyw0NzYyNCw0NzYzNyw0NzY3Miw0NzY3Myw0NzY3Niw0NzY4MCw0NzY4Miw0NzY4OCw0NzY4OSw0NzY5MSw0NzY5Myw0NzY5NCw0NzY5OSw0NzcwMCw0NzcwMSw0NzcwNCw0NzcwOCw0NzcxNiw0NzcxNyw0NzcxOSw0NzcyMCw0NzcyMSw0NzcyOCw0NzcyOSw0NzczMiw0NzczNiw0Nzc0Nyw0Nzc0OCw0Nzc0OSw0Nzc1MSw0Nzc1Niw0Nzc4NCw0Nzc4NSw0Nzc4Nyw0Nzc4OCw0Nzc5Miw0Nzc5NCw0NzgwMCw0NzgwMSw0NzgwMyw0NzgwNSw0NzgxMiw0NzgxNiw0NzgzMiw0NzgzMyw0Nzg2OCw1MzgwMiw1MzgwMyw1MzgwNiw1MzgwNyw1MzgwOSw1MzgxMCw1MzgxMSw1MzgxMyw1MzgxNCw1MzgxNSw1MzgxNiw1MzgxNyw1MzgxOCw1MzgxOSw1MzgyMiw1MzgyNCw1MzgyNiw1MzgyNyw1MzgyOCw1MzgyOSw1MzgzMCw1MzgzMSw1MzgzMyw1MzgzNCw1MzgzNSw1MzgzNixudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MzgzNyw1MzgzOCw1MzgzOSw1Mzg0MCw1Mzg0MSw1Mzg0Miw1Mzg0Myw1Mzg0NCw1Mzg0NSw1Mzg0Niw1Mzg0Nyw1Mzg0OCw1Mzg0OSw1Mzg1MCw1Mzg1MSw1Mzg1Myw1Mzg1NCw1Mzg1NSw1Mzg1Niw1Mzg1Nyw1Mzg1OCw1Mzg1OSw1Mzg2MSw1Mzg2Miw1Mzg2Myw1Mzg2NCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1Mzg2NSw1Mzg2Niw1Mzg2Nyw1Mzg2OCw1Mzg2OSw1Mzg3MCw1Mzg3MSw1Mzg3Miw1Mzg3Myw1Mzg3NCw1Mzg3NSw1Mzg3Niw1Mzg3Nyw1Mzg3OCw1Mzg3OSw1Mzg4MCw1Mzg4MSw1Mzg4Miw1Mzg4Myw1Mzg4NCw1Mzg4NSw1Mzg4Niw1Mzg4Nyw1Mzg5MCw1Mzg5MSw1Mzg5Myw1Mzg5NCw1Mzg5NSw1Mzg5Nyw1Mzg5OCw1Mzg5OSw1MzkwMCw0Nzg3Miw0Nzg3Niw0Nzg4NSw0Nzg4Nyw0Nzg4OSw0Nzg5Niw0NzkwMCw0NzkwNCw0NzkxMyw0NzkxNSw0NzkyNCw0NzkyNSw0NzkyNiw0NzkyOCw0NzkzMSw0NzkzMiw0NzkzMyw0NzkzNCw0Nzk0MCw0Nzk0MSw0Nzk0Myw0Nzk0NSw0Nzk0OSw0Nzk1MSw0Nzk1Miw0Nzk1Niw0Nzk2MCw0Nzk2OSw0Nzk3MSw0Nzk4MCw0ODAwOCw0ODAxMiw0ODAxNiw0ODAzNiw0ODA0MCw0ODA0NCw0ODA1Miw0ODA1NSw0ODA2NCw0ODA2OCw0ODA3Miw0ODA4MCw0ODA4Myw0ODEyMCw0ODEyMSw0ODEyNCw0ODEyNyw0ODEyOCw0ODEzMCw0ODEzNiw0ODEzNyw0ODEzOSw0ODE0MCw0ODE0MSw0ODE0Myw0ODE0NSw0ODE0OCw0ODE0OSw0ODE1MCw0ODE1MSw0ODE1Miw0ODE1NSw0ODE1Niw0ODE1Nyw0ODE1OCw0ODE1OSw0ODE2NCw0ODE2NSw0ODE2Nyw0ODE2OSw0ODE3Myw0ODE3Niw0ODE3Nyw0ODE4MCw0ODE4NCw0ODE5Miw0ODE5Myw0ODE5NSw0ODE5Niw0ODE5Nyw0ODIwMSw0ODIwNCw0ODIwNSw0ODIwOCw0ODIyMSw0ODI2MCw0ODI2MSw0ODI2NCw0ODI2Nyw0ODI2OCw0ODI3MCw0ODI3Niw0ODI3Nyw0ODI3OSw1MzkwMSw1MzkwMiw1MzkwMyw1MzkwNiw1MzkwNyw1MzkwOCw1MzkxMCw1MzkxMSw1MzkxMiw1MzkxMyw1MzkxNCw1MzkxNSw1MzkxNyw1MzkxOCw1MzkxOSw1MzkyMSw1MzkyMiw1MzkyMyw1MzkyNSw1MzkyNiw1MzkyNyw1MzkyOCw1MzkyOSw1MzkzMCw1MzkzMSw1MzkzMyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1MzkzNCw1MzkzNSw1MzkzNiw1MzkzOCw1MzkzOSw1Mzk0MCw1Mzk0MSw1Mzk0Miw1Mzk0Myw1Mzk0Niw1Mzk0Nyw1Mzk0OSw1Mzk1MCw1Mzk1Myw1Mzk1NSw1Mzk1Niw1Mzk1Nyw1Mzk1OCw1Mzk1OSw1Mzk2Miw1Mzk2NCw1Mzk2NSw1Mzk2Niw1Mzk2Nyw1Mzk2OCw1Mzk2OSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1Mzk3MCw1Mzk3MSw1Mzk3Myw1Mzk3NCw1Mzk3NSw1Mzk3Nyw1Mzk3OCw1Mzk3OSw1Mzk4MSw1Mzk4Miw1Mzk4Myw1Mzk4NCw1Mzk4NSw1Mzk4Niw1Mzk4Nyw1Mzk5MCw1Mzk5MSw1Mzk5Miw1Mzk5Myw1Mzk5NCw1Mzk5NSw1Mzk5Niw1Mzk5Nyw1Mzk5OCw1Mzk5OSw1NDAwMiw1NDAwMyw1NDAwNSw1NDAwNiw1NDAwNyw1NDAwOSw1NDAxMCw0ODI4MSw0ODI4Miw0ODI4OCw0ODI4OSw0ODI5Miw0ODI5NSw0ODI5Niw0ODMwNCw0ODMwNSw0ODMwNyw0ODMwOCw0ODMwOSw0ODMxNiw0ODMxNyw0ODMyMCw0ODMyNCw0ODMzMyw0ODMzNSw0ODMzNiw0ODMzNyw0ODM0MSw0ODM0NCw0ODM0OCw0ODM3Miw0ODM3Myw0ODM3NCw0ODM3Niw0ODM4MCw0ODM4OCw0ODM4OSw0ODM5MSw0ODM5Myw0ODQwMCw0ODQwNCw0ODQyMCw0ODQyOCw0ODQ0OCw0ODQ1Niw0ODQ1Nyw0ODQ2MCw0ODQ2NCw0ODQ3Miw0ODQ3Myw0ODQ4NCw0ODQ4OCw0ODUxMiw0ODUxMyw0ODUxNiw0ODUxOSw0ODUyMCw0ODUyMSw0ODUyMiw0ODUyOCw0ODUyOSw0ODUzMSw0ODUzMyw0ODUzNyw0ODUzOCw0ODU0MCw0ODU0OCw0ODU2MCw0ODU2OCw0ODU5Niw0ODU5Nyw0ODYwMCw0ODYwNCw0ODYxNyw0ODYyNCw0ODYyOCw0ODYzMiw0ODY0MCw0ODY0Myw0ODY0NSw0ODY1Miw0ODY1Myw0ODY1Niw0ODY2MCw0ODY2OCw0ODY2OSw0ODY3MSw0ODcwOCw0ODcwOSw0ODcxMiw0ODcxNiw0ODcxOCw0ODcyNCw0ODcyNSw0ODcyNyw0ODcyOSw0ODczMCw0ODczMSw0ODczNiw0ODczNyw0ODc0MCw1NDAxMSw1NDAxMiw1NDAxMyw1NDAxNCw1NDAxNSw1NDAxOCw1NDAyMCw1NDAyMiw1NDAyMyw1NDAyNCw1NDAyNSw1NDAyNiw1NDAyNyw1NDAzMSw1NDAzMyw1NDAzNCw1NDAzNSw1NDAzNyw1NDAzOSw1NDA0MCw1NDA0MSw1NDA0Miw1NDA0Myw1NDA0Niw1NDA1MCw1NDA1MSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDA1Miw1NDA1NCw1NDA1NSw1NDA1OCw1NDA1OSw1NDA2MSw1NDA2Miw1NDA2Myw1NDA2NSw1NDA2Niw1NDA2Nyw1NDA2OCw1NDA2OSw1NDA3MCw1NDA3MSw1NDA3NCw1NDA3OCw1NDA3OSw1NDA4MCw1NDA4MSw1NDA4Miw1NDA4Myw1NDA4Niw1NDA4Nyw1NDA4OCw1NDA4OSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDA5MCw1NDA5MSw1NDA5Miw1NDA5Myw1NDA5NCw1NDA5NSw1NDA5Niw1NDA5Nyw1NDA5OCw1NDA5OSw1NDEwMCw1NDEwMSw1NDEwMiw1NDEwMyw1NDEwNCw1NDEwNSw1NDEwNiw1NDEwNyw1NDEwOCw1NDEwOSw1NDExMCw1NDExMSw1NDExMiw1NDExMyw1NDExNCw1NDExNSw1NDExNiw1NDExNyw1NDExOCw1NDExOSw1NDEyMCw1NDEyMSw0ODc0NCw0ODc0Niw0ODc1Miw0ODc1Myw0ODc1NSw0ODc1Niw0ODc1Nyw0ODc2Myw0ODc2NCw0ODc2NSw0ODc2OCw0ODc3Miw0ODc4MCw0ODc4MSw0ODc4Myw0ODc4NCw0ODc4NSw0ODc5Miw0ODc5Myw0ODgwOCw0ODg0OCw0ODg0OSw0ODg1Miw0ODg1NSw0ODg1Niw0ODg2NCw0ODg2Nyw0ODg2OCw0ODg2OSw0ODg3Niw0ODg5Nyw0ODkwNCw0ODkwNSw0ODkyMCw0ODkyMSw0ODkyMyw0ODkyNCw0ODkyNSw0ODk2MCw0ODk2MSw0ODk2NCw0ODk2OCw0ODk3Niw0ODk3Nyw0ODk4MSw0OTA0NCw0OTA3Miw0OTA5Myw0OTEwMCw0OTEwMSw0OTEwNCw0OTEwOCw0OTExNiw0OTExOSw0OTEyMSw0OTIxMiw0OTIzMyw0OTI0MCw0OTI0NCw0OTI0OCw0OTI1Niw0OTI1Nyw0OTI5Niw0OTI5Nyw0OTMwMCw0OTMwNCw0OTMxMiw0OTMxMyw0OTMxNSw0OTMxNyw0OTMyNCw0OTMyNSw0OTMyNyw0OTMyOCw0OTMzMSw0OTMzMiw0OTMzMyw0OTMzNCw0OTM0MCw0OTM0MSw0OTM0Myw0OTM0NCw0OTM0NSw0OTM0OSw0OTM1Miw0OTM1Myw0OTM1Niw0OTM2MCw0OTM2OCw0OTM2OSw0OTM3MSw0OTM3Miw0OTM3Myw0OTM4MCw1NDEyMiw1NDEyMyw1NDEyNCw1NDEyNSw1NDEyNiw1NDEyNyw1NDEyOCw1NDEyOSw1NDEzMCw1NDEzMSw1NDEzMiw1NDEzMyw1NDEzNCw1NDEzNSw1NDEzNiw1NDEzNyw1NDEzOCw1NDEzOSw1NDE0Miw1NDE0Myw1NDE0NSw1NDE0Niw1NDE0Nyw1NDE0OSw1NDE1MCw1NDE1MSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDE1Miw1NDE1Myw1NDE1NCw1NDE1NSw1NDE1OCw1NDE2Miw1NDE2Myw1NDE2NCw1NDE2NSw1NDE2Niw1NDE2Nyw1NDE3MCw1NDE3MSw1NDE3Myw1NDE3NCw1NDE3NSw1NDE3Nyw1NDE3OCw1NDE3OSw1NDE4MCw1NDE4MSw1NDE4Miw1NDE4Myw1NDE4Niw1NDE4OCw1NDE5MCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDE5MSw1NDE5Miw1NDE5Myw1NDE5NCw1NDE5NSw1NDE5Nyw1NDE5OCw1NDE5OSw1NDIwMSw1NDIwMiw1NDIwMyw1NDIwNSw1NDIwNiw1NDIwNyw1NDIwOCw1NDIwOSw1NDIxMCw1NDIxMSw1NDIxNCw1NDIxNSw1NDIxOCw1NDIxOSw1NDIyMCw1NDIyMSw1NDIyMiw1NDIyMyw1NDIyNSw1NDIyNiw1NDIyNyw1NDIyOCw1NDIyOSw1NDIzMCw0OTM4MSw0OTM4NCw0OTM4OCw0OTM5Niw0OTM5Nyw0OTM5OSw0OTQwMSw0OTQwOCw0OTQxMiw0OTQxNiw0OTQyNCw0OTQyOSw0OTQzNiw0OTQzNyw0OTQzOCw0OTQzOSw0OTQ0MCw0OTQ0Myw0OTQ0NCw0OTQ0Niw0OTQ0Nyw0OTQ1Miw0OTQ1Myw0OTQ1NSw0OTQ1Niw0OTQ1Nyw0OTQ2Miw0OTQ2NCw0OTQ2NSw0OTQ2OCw0OTQ3Miw0OTQ4MCw0OTQ4MSw0OTQ4Myw0OTQ4NCw0OTQ4NSw0OTQ5Miw0OTQ5Myw0OTQ5Niw0OTUwMCw0OTUwOCw0OTUwOSw0OTUxMSw0OTUxMiw0OTUxMyw0OTUyMCw0OTUyNCw0OTUyOCw0OTU0MSw0OTU0OCw0OTU0OSw0OTU1MCw0OTU1Miw0OTU1Niw0OTU1OCw0OTU2NCw0OTU2NSw0OTU2Nyw0OTU2OSw0OTU3Myw0OTU3Niw0OTU3Nyw0OTU4MCw0OTU4NCw0OTU5Nyw0OTYwNCw0OTYwOCw0OTYxMiw0OTYyMCw0OTYyMyw0OTYyNCw0OTYzMiw0OTYzNiw0OTY0MCw0OTY0OCw0OTY0OSw0OTY1MSw0OTY2MCw0OTY2MSw0OTY2NCw0OTY2OCw0OTY3Niw0OTY3Nyw0OTY3OSw0OTY4MSw0OTY4OCw0OTY4OSw0OTY5Miw0OTY5NSw0OTY5Niw0OTcwNCw0OTcwNSw0OTcwNyw0OTcwOSw1NDIzMSw1NDIzMyw1NDIzNCw1NDIzNSw1NDIzNiw1NDIzNyw1NDIzOCw1NDIzOSw1NDI0MCw1NDI0Miw1NDI0NCw1NDI0NSw1NDI0Niw1NDI0Nyw1NDI0OCw1NDI0OSw1NDI1MCw1NDI1MSw1NDI1NCw1NDI1NSw1NDI1Nyw1NDI1OCw1NDI1OSw1NDI2MSw1NDI2Miw1NDI2MyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDI2NCw1NDI2NSw1NDI2Niw1NDI2Nyw1NDI3MCw1NDI3Miw1NDI3NCw1NDI3NSw1NDI3Niw1NDI3Nyw1NDI3OCw1NDI3OSw1NDI4MSw1NDI4Miw1NDI4Myw1NDI4NCw1NDI4NSw1NDI4Niw1NDI4Nyw1NDI4OCw1NDI4OSw1NDI5MCw1NDI5MSw1NDI5Miw1NDI5Myw1NDI5NCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDI5NSw1NDI5Niw1NDI5Nyw1NDI5OCw1NDI5OSw1NDMwMCw1NDMwMiw1NDMwMyw1NDMwNCw1NDMwNSw1NDMwNiw1NDMwNyw1NDMwOCw1NDMwOSw1NDMxMCw1NDMxMSw1NDMxMiw1NDMxMyw1NDMxNCw1NDMxNSw1NDMxNiw1NDMxNyw1NDMxOCw1NDMxOSw1NDMyMCw1NDMyMSw1NDMyMiw1NDMyMyw1NDMyNCw1NDMyNSw1NDMyNiw1NDMyNyw0OTcxMSw0OTcxMyw0OTcxNCw0OTcxNiw0OTczNiw0OTc0NCw0OTc0NSw0OTc0OCw0OTc1Miw0OTc2MCw0OTc2NSw0OTc3Miw0OTc3Myw0OTc3Niw0OTc4MCw0OTc4OCw0OTc4OSw0OTc5MSw0OTc5Myw0OTgwMCw0OTgwMSw0OTgwOCw0OTgxNiw0OTgxOSw0OTgyMSw0OTgyOCw0OTgyOSw0OTgzMiw0OTgzNiw0OTgzNyw0OTg0NCw0OTg0NSw0OTg0Nyw0OTg0OSw0OTg4NCw0OTg4NSw0OTg4OCw0OTg5MSw0OTg5Miw0OTg5OSw0OTkwMCw0OTkwMSw0OTkwMyw0OTkwNSw0OTkxMCw0OTkxMiw0OTkxMyw0OTkxNSw0OTkxNiw0OTkyMCw0OTkyOCw0OTkyOSw0OTkzMiw0OTkzMyw0OTkzOSw0OTk0MCw0OTk0MSw0OTk0NCw0OTk0OCw0OTk1Niw0OTk1Nyw0OTk2MCw0OTk2MSw0OTk4OSw1MDAyNCw1MDAyNSw1MDAyOCw1MDAzMiw1MDAzNCw1MDA0MCw1MDA0MSw1MDA0NCw1MDA0NSw1MDA1Miw1MDA1Niw1MDA2MCw1MDExMiw1MDEzNiw1MDEzNyw1MDE0MCw1MDE0Myw1MDE0NCw1MDE0Niw1MDE1Miw1MDE1Myw1MDE1Nyw1MDE2NCw1MDE2NSw1MDE2OCw1MDE4NCw1MDE5Miw1MDIxMiw1MDIyMCw1MDIyNCw1NDMyOCw1NDMyOSw1NDMzMCw1NDMzMSw1NDMzMiw1NDMzMyw1NDMzNCw1NDMzNSw1NDMzNyw1NDMzOCw1NDMzOSw1NDM0MSw1NDM0Miw1NDM0Myw1NDM0NCw1NDM0NSw1NDM0Niw1NDM0Nyw1NDM0OCw1NDM0OSw1NDM1MCw1NDM1MSw1NDM1Miw1NDM1Myw1NDM1NCw1NDM1NSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDM1Niw1NDM1Nyw1NDM1OCw1NDM1OSw1NDM2MCw1NDM2MSw1NDM2Miw1NDM2Myw1NDM2NSw1NDM2Niw1NDM2Nyw1NDM2OSw1NDM3MCw1NDM3MSw1NDM3Myw1NDM3NCw1NDM3NSw1NDM3Niw1NDM3Nyw1NDM3OCw1NDM3OSw1NDM4MCw1NDM4Miw1NDM4NCw1NDM4NSw1NDM4NixudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDM4Nyw1NDM4OCw1NDM4OSw1NDM5MCw1NDM5MSw1NDM5NCw1NDM5NSw1NDM5Nyw1NDM5OCw1NDQwMSw1NDQwMyw1NDQwNCw1NDQwNSw1NDQwNiw1NDQwNyw1NDQxMCw1NDQxMiw1NDQxNCw1NDQxNSw1NDQxNiw1NDQxNyw1NDQxOCw1NDQxOSw1NDQyMSw1NDQyMiw1NDQyMyw1NDQyNCw1NDQyNSw1NDQyNiw1NDQyNyw1NDQyOCw1NDQyOSw1MDIyOCw1MDIzNiw1MDIzNyw1MDI0OCw1MDI3Niw1MDI3Nyw1MDI4MCw1MDI4NCw1MDI5Miw1MDI5Myw1MDI5Nyw1MDMwNCw1MDMyNCw1MDMzMiw1MDM2MCw1MDM2NCw1MDQwOSw1MDQxNiw1MDQxNyw1MDQyMCw1MDQyNCw1MDQyNiw1MDQzMSw1MDQzMiw1MDQzMyw1MDQ0NCw1MDQ0OCw1MDQ1Miw1MDQ2MCw1MDQ3Miw1MDQ3Myw1MDQ3Niw1MDQ4MCw1MDQ4OCw1MDQ4OSw1MDQ5MSw1MDQ5Myw1MDUwMCw1MDUwMSw1MDUwNCw1MDUwNSw1MDUwNiw1MDUwOCw1MDUwOSw1MDUxMCw1MDUxNSw1MDUxNiw1MDUxNyw1MDUxOSw1MDUyMCw1MDUyMSw1MDUyNSw1MDUyNiw1MDUyOCw1MDUyOSw1MDUzMiw1MDUzNiw1MDU0NCw1MDU0NSw1MDU0Nyw1MDU0OCw1MDU0OSw1MDU1Niw1MDU1Nyw1MDU2MCw1MDU2NCw1MDU2Nyw1MDU3Miw1MDU3Myw1MDU3NSw1MDU3Nyw1MDU4MSw1MDU4Myw1MDU4NCw1MDU4OCw1MDU5Miw1MDYwMSw1MDYxMiw1MDYxMyw1MDYxNiw1MDYxNyw1MDYxOSw1MDYyMCw1MDYyMSw1MDYyMiw1MDYyOCw1MDYyOSw1MDYzMCw1MDYzMSw1MDYzMiw1MDYzMyw1MDYzNCw1MDYzNiw1MDYzOCw1NDQzMCw1NDQzMSw1NDQzMiw1NDQzMyw1NDQzNCw1NDQzNSw1NDQzNiw1NDQzNyw1NDQzOCw1NDQzOSw1NDQ0MCw1NDQ0Miw1NDQ0Myw1NDQ0NCw1NDQ0NSw1NDQ0Niw1NDQ0Nyw1NDQ0OCw1NDQ0OSw1NDQ1MCw1NDQ1MSw1NDQ1Miw1NDQ1Myw1NDQ1NCw1NDQ1NSw1NDQ1NixudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDQ1Nyw1NDQ1OCw1NDQ1OSw1NDQ2MCw1NDQ2MSw1NDQ2Miw1NDQ2Myw1NDQ2NCw1NDQ2NSw1NDQ2Niw1NDQ2Nyw1NDQ2OCw1NDQ2OSw1NDQ3MCw1NDQ3MSw1NDQ3Miw1NDQ3Myw1NDQ3NCw1NDQ3NSw1NDQ3Nyw1NDQ3OCw1NDQ3OSw1NDQ4MSw1NDQ4Miw1NDQ4Myw1NDQ4NSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDQ4Niw1NDQ4Nyw1NDQ4OCw1NDQ4OSw1NDQ5MCw1NDQ5MSw1NDQ5Myw1NDQ5NCw1NDQ5Niw1NDQ5Nyw1NDQ5OCw1NDQ5OSw1NDUwMCw1NDUwMSw1NDUwMiw1NDUwMyw1NDUwNSw1NDUwNiw1NDUwNyw1NDUwOSw1NDUxMCw1NDUxMSw1NDUxMyw1NDUxNCw1NDUxNSw1NDUxNiw1NDUxNyw1NDUxOCw1NDUxOSw1NDUyMSw1NDUyMiw1NDUyNCw1MDY0MCw1MDY0MSw1MDY0NCw1MDY0OCw1MDY1Niw1MDY1Nyw1MDY1OSw1MDY2MSw1MDY2OCw1MDY2OSw1MDY3MCw1MDY3Miw1MDY3Niw1MDY3OCw1MDY3OSw1MDY4NCw1MDY4NSw1MDY4Niw1MDY4Nyw1MDY4OCw1MDY4OSw1MDY5Myw1MDY5NCw1MDY5NSw1MDY5Niw1MDcwMCw1MDcwNCw1MDcxMiw1MDcxMyw1MDcxNSw1MDcxNiw1MDcyNCw1MDcyNSw1MDcyOCw1MDczMiw1MDczMyw1MDczNCw1MDczNiw1MDczOSw1MDc0MCw1MDc0MSw1MDc0Myw1MDc0NSw1MDc0Nyw1MDc1Miw1MDc1Myw1MDc1Niw1MDc2MCw1MDc2OCw1MDc2OSw1MDc3MSw1MDc3Miw1MDc3Myw1MDc4MCw1MDc4MSw1MDc4NCw1MDc5Niw1MDc5OSw1MDgwMSw1MDgwOCw1MDgwOSw1MDgxMiw1MDgxNiw1MDgyNCw1MDgyNSw1MDgyNyw1MDgyOSw1MDgzNiw1MDgzNyw1MDg0MCw1MDg0NCw1MDg1Miw1MDg1Myw1MDg1NSw1MDg1Nyw1MDg2NCw1MDg2NSw1MDg2OCw1MDg3Miw1MDg3Myw1MDg3NCw1MDg4MCw1MDg4MSw1MDg4Myw1MDg4NSw1MDg5Miw1MDg5Myw1MDg5Niw1MDkwMCw1MDkwOCw1MDkwOSw1MDkxMiw1MDkxMyw1MDkyMCw1NDUyNiw1NDUyNyw1NDUyOCw1NDUyOSw1NDUzMCw1NDUzMSw1NDUzMyw1NDUzNCw1NDUzNSw1NDUzNyw1NDUzOCw1NDUzOSw1NDU0MSw1NDU0Miw1NDU0Myw1NDU0NCw1NDU0NSw1NDU0Niw1NDU0Nyw1NDU1MCw1NDU1Miw1NDU1Myw1NDU1NCw1NDU1NSw1NDU1Niw1NDU1NyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDU1OCw1NDU1OSw1NDU2MCw1NDU2MSw1NDU2Miw1NDU2Myw1NDU2NCw1NDU2NSw1NDU2Niw1NDU2Nyw1NDU2OCw1NDU2OSw1NDU3MCw1NDU3MSw1NDU3Miw1NDU3Myw1NDU3NCw1NDU3NSw1NDU3Niw1NDU3Nyw1NDU3OCw1NDU3OSw1NDU4MCw1NDU4MSw1NDU4Miw1NDU4MyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDU4NCw1NDU4NSw1NDU4Niw1NDU4Nyw1NDU5MCw1NDU5MSw1NDU5Myw1NDU5NCw1NDU5NSw1NDU5Nyw1NDU5OCw1NDU5OSw1NDYwMCw1NDYwMSw1NDYwMiw1NDYwMyw1NDYwNiw1NDYwOCw1NDYxMCw1NDYxMSw1NDYxMiw1NDYxMyw1NDYxNCw1NDYxNSw1NDYxOCw1NDYxOSw1NDYyMSw1NDYyMiw1NDYyMyw1NDYyNSw1NDYyNiw1NDYyNyw1MDkyMSw1MDkyNCw1MDkyOCw1MDkzNiw1MDkzNyw1MDk0MSw1MDk0OCw1MDk0OSw1MDk1Miw1MDk1Niw1MDk2NCw1MDk2NSw1MDk2Nyw1MDk2OSw1MDk3Niw1MDk3Nyw1MDk4MCw1MDk4NCw1MDk5Miw1MDk5Myw1MDk5NSw1MDk5Nyw1MDk5OSw1MTAwNCw1MTAwNSw1MTAwOCw1MTAxMiw1MTAxOCw1MTAyMCw1MTAyMSw1MTAyMyw1MTAyNSw1MTAyNiw1MTAyNyw1MTAyOCw1MTAyOSw1MTAzMCw1MTAzMSw1MTAzMiw1MTAzNiw1MTA0MCw1MTA0OCw1MTA1MSw1MTA2MCw1MTA2MSw1MTA2NCw1MTA2OCw1MTA2OSw1MTA3MCw1MTA3NSw1MTA3Niw1MTA3Nyw1MTA3OSw1MTA4MCw1MTA4MSw1MTA4Miw1MTA4Niw1MTA4OCw1MTA4OSw1MTA5Miw1MTA5NCw1MTA5NSw1MTA5Niw1MTA5OCw1MTEwNCw1MTEwNSw1MTEwNyw1MTEwOCw1MTEwOSw1MTExMCw1MTExNiw1MTExNyw1MTEyMCw1MTEyNCw1MTEzMiw1MTEzMyw1MTEzNSw1MTEzNiw1MTEzNyw1MTE0NCw1MTE0NSw1MTE0OCw1MTE1MCw1MTE1Miw1MTE2MCw1MTE2NSw1MTE3Miw1MTE3Niw1MTE4MCw1MTIwMCw1MTIwMSw1MTIwNCw1MTIwOCw1MTIxMCw1NDYyOCw1NDYzMCw1NDYzMSw1NDYzNCw1NDYzNiw1NDYzOCw1NDYzOSw1NDY0MCw1NDY0MSw1NDY0Miw1NDY0Myw1NDY0Niw1NDY0Nyw1NDY0OSw1NDY1MCw1NDY1MSw1NDY1Myw1NDY1NCw1NDY1NSw1NDY1Niw1NDY1Nyw1NDY1OCw1NDY1OSw1NDY2Miw1NDY2Niw1NDY2NyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDY2OCw1NDY2OSw1NDY3MCw1NDY3MSw1NDY3Myw1NDY3NCw1NDY3NSw1NDY3Niw1NDY3Nyw1NDY3OCw1NDY3OSw1NDY4MCw1NDY4MSw1NDY4Miw1NDY4Myw1NDY4NCw1NDY4NSw1NDY4Niw1NDY4Nyw1NDY4OCw1NDY4OSw1NDY5MCw1NDY5MSw1NDY5Miw1NDY5NCw1NDY5NSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDY5Niw1NDY5Nyw1NDY5OCw1NDY5OSw1NDcwMCw1NDcwMSw1NDcwMiw1NDcwMyw1NDcwNCw1NDcwNSw1NDcwNiw1NDcwNyw1NDcwOCw1NDcwOSw1NDcxMCw1NDcxMSw1NDcxMiw1NDcxMyw1NDcxNCw1NDcxNSw1NDcxNiw1NDcxNyw1NDcxOCw1NDcxOSw1NDcyMCw1NDcyMSw1NDcyMiw1NDcyMyw1NDcyNCw1NDcyNSw1NDcyNiw1NDcyNyw1MTIxNiw1MTIxNyw1MTIxOSw1MTIyMSw1MTIyMiw1MTIyOCw1MTIyOSw1MTIzMiw1MTIzNiw1MTI0NCw1MTI0NSw1MTI0Nyw1MTI0OSw1MTI1Niw1MTI2MCw1MTI2NCw1MTI3Miw1MTI3Myw1MTI3Niw1MTI3Nyw1MTI4NCw1MTMxMiw1MTMxMyw1MTMxNiw1MTMyMCw1MTMyMiw1MTMyOCw1MTMyOSw1MTMzMSw1MTMzMyw1MTMzNCw1MTMzNSw1MTMzOSw1MTM0MCw1MTM0MSw1MTM0OCw1MTM1Nyw1MTM1OSw1MTM2MSw1MTM2OCw1MTM4OCw1MTM4OSw1MTM5Niw1MTQwMCw1MTQwNCw1MTQxMiw1MTQxMyw1MTQxNSw1MTQxNyw1MTQyNCw1MTQyNSw1MTQyOCw1MTQ0NSw1MTQ1Miw1MTQ1Myw1MTQ1Niw1MTQ2MCw1MTQ2MSw1MTQ2Miw1MTQ2OCw1MTQ2OSw1MTQ3MSw1MTQ3Myw1MTQ4MCw1MTUwMCw1MTUwOCw1MTUzNiw1MTUzNyw1MTU0MCw1MTU0NCw1MTU1Miw1MTU1Myw1MTU1NSw1MTU2NCw1MTU2OCw1MTU3Miw1MTU4MCw1MTU5Miw1MTU5Myw1MTU5Niw1MTYwMCw1MTYwOCw1MTYwOSw1MTYxMSw1MTYxMyw1MTY0OCw1MTY0OSw1MTY1Miw1MTY1NSw1MTY1Niw1MTY1OCw1MTY2NCw1MTY2NSw1MTY2Nyw1NDczMCw1NDczMSw1NDczMyw1NDczNCw1NDczNSw1NDczNyw1NDczOSw1NDc0MCw1NDc0MSw1NDc0Miw1NDc0Myw1NDc0Niw1NDc0OCw1NDc1MCw1NDc1MSw1NDc1Miw1NDc1Myw1NDc1NCw1NDc1NSw1NDc1OCw1NDc1OSw1NDc2MSw1NDc2Miw1NDc2Myw1NDc2NSw1NDc2NixudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDc2Nyw1NDc2OCw1NDc2OSw1NDc3MCw1NDc3MSw1NDc3NCw1NDc3Niw1NDc3OCw1NDc3OSw1NDc4MCw1NDc4MSw1NDc4Miw1NDc4Myw1NDc4Niw1NDc4Nyw1NDc4OSw1NDc5MCw1NDc5MSw1NDc5Myw1NDc5NCw1NDc5NSw1NDc5Niw1NDc5Nyw1NDc5OCw1NDc5OSw1NDgwMixudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDgwNiw1NDgwNyw1NDgwOCw1NDgwOSw1NDgxMCw1NDgxMSw1NDgxMyw1NDgxNCw1NDgxNSw1NDgxNyw1NDgxOCw1NDgxOSw1NDgyMSw1NDgyMiw1NDgyMyw1NDgyNCw1NDgyNSw1NDgyNiw1NDgyNyw1NDgyOCw1NDgzMCw1NDgzMSw1NDgzMiw1NDgzMyw1NDgzNCw1NDgzNSw1NDgzNiw1NDgzNyw1NDgzOCw1NDgzOSw1NDg0Miw1NDg0Myw1MTY2OSw1MTY3MCw1MTY3Myw1MTY3NCw1MTY3Niw1MTY3Nyw1MTY4MCw1MTY4Miw1MTY4NCw1MTY4Nyw1MTY5Miw1MTY5Myw1MTY5NSw1MTY5Niw1MTY5Nyw1MTcwNCw1MTcwNSw1MTcwOCw1MTcxMiw1MTcyMCw1MTcyMSw1MTcyMyw1MTcyNCw1MTcyNSw1MTczMiw1MTczNiw1MTc1Myw1MTc4OCw1MTc4OSw1MTc5Miw1MTc5Niw1MTgwNCw1MTgwNSw1MTgwNyw1MTgwOCw1MTgwOSw1MTgxNiw1MTgzNyw1MTg0NCw1MTg2NCw1MTkwMCw1MTkwMSw1MTkwNCw1MTkwOCw1MTkxNiw1MTkxNyw1MTkxOSw1MTkyMSw1MTkyMyw1MTkyOCw1MTkyOSw1MTkzNiw1MTk0OCw1MTk1Niw1MTk3Niw1MTk4NCw1MTk4OCw1MTk5Miw1MjAwMCw1MjAwMSw1MjAzMyw1MjA0MCw1MjA0MSw1MjA0NCw1MjA0OCw1MjA1Niw1MjA1Nyw1MjA2MSw1MjA2OCw1MjA4OCw1MjA4OSw1MjEyNCw1MjE1Miw1MjE4MCw1MjE5Niw1MjE5OSw1MjIwMSw1MjIzNiw1MjIzNyw1MjI0MCw1MjI0NCw1MjI1Miw1MjI1Myw1MjI1Nyw1MjI1OCw1MjI2Myw1MjI2NCw1MjI2NSw1MjI2OCw1MjI3MCw1MjI3Miw1MjI4MCw1MjI4MSw1MjI4Myw1NDg0NSw1NDg0Niw1NDg0Nyw1NDg0OSw1NDg1MCw1NDg1MSw1NDg1Miw1NDg1NCw1NDg1NSw1NDg1OCw1NDg2MCw1NDg2Miw1NDg2Myw1NDg2NCw1NDg2Niw1NDg2Nyw1NDg3MCw1NDg3MSw1NDg3Myw1NDg3NCw1NDg3NSw1NDg3Nyw1NDg3OCw1NDg3OSw1NDg4MCw1NDg4MSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDg4Miw1NDg4Myw1NDg4NCw1NDg4NSw1NDg4Niw1NDg4OCw1NDg5MCw1NDg5MSw1NDg5Miw1NDg5Myw1NDg5NCw1NDg5NSw1NDg5OCw1NDg5OSw1NDkwMSw1NDkwMiw1NDkwMyw1NDkwNCw1NDkwNSw1NDkwNiw1NDkwNyw1NDkwOCw1NDkwOSw1NDkxMCw1NDkxMSw1NDkxMixudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDkxMyw1NDkxNCw1NDkxNiw1NDkxOCw1NDkxOSw1NDkyMCw1NDkyMSw1NDkyMiw1NDkyMyw1NDkyNiw1NDkyNyw1NDkyOSw1NDkzMCw1NDkzMSw1NDkzMyw1NDkzNCw1NDkzNSw1NDkzNiw1NDkzNyw1NDkzOCw1NDkzOSw1NDk0MCw1NDk0Miw1NDk0NCw1NDk0Niw1NDk0Nyw1NDk0OCw1NDk0OSw1NDk1MCw1NDk1MSw1NDk1Myw1NDk1NCw1MjI4NCw1MjI4NSw1MjI4Niw1MjI5Miw1MjI5Myw1MjI5Niw1MjMwMCw1MjMwOCw1MjMwOSw1MjMxMSw1MjMxMiw1MjMxMyw1MjMyMCw1MjMyNCw1MjMyNiw1MjMyOCw1MjMzNiw1MjM0MSw1MjM3Niw1MjM3Nyw1MjM4MCw1MjM4NCw1MjM5Miw1MjM5Myw1MjM5NSw1MjM5Niw1MjM5Nyw1MjQwNCw1MjQwNSw1MjQwOCw1MjQxMiw1MjQyMCw1MjQyMSw1MjQyMyw1MjQyNSw1MjQzMiw1MjQzNiw1MjQ1Miw1MjQ2MCw1MjQ2NCw1MjQ4MSw1MjQ4OCw1MjQ4OSw1MjQ5Miw1MjQ5Niw1MjUwNCw1MjUwNSw1MjUwNyw1MjUwOSw1MjUxNiw1MjUyMCw1MjUyNCw1MjUzNyw1MjU3Miw1MjU3Niw1MjU4MCw1MjU4OCw1MjU4OSw1MjU5MSw1MjU5Myw1MjYwMCw1MjYxNiw1MjYyOCw1MjYyOSw1MjYzMiw1MjYzNiw1MjY0NCw1MjY0NSw1MjY0Nyw1MjY0OSw1MjY1Niw1MjY3Niw1MjY4NCw1MjY4OCw1MjcxMiw1MjcxNiw1MjcyMCw1MjcyOCw1MjcyOSw1MjczMSw1MjczMyw1Mjc0MCw1Mjc0NCw1Mjc0OCw1Mjc1Niw1Mjc2MSw1Mjc2OCw1Mjc2OSw1Mjc3Miw1Mjc3Niw1Mjc4NCw1Mjc4NSw1Mjc4Nyw1Mjc4OSw1NDk1NSw1NDk1Nyw1NDk1OCw1NDk1OSw1NDk2MSw1NDk2Miw1NDk2Myw1NDk2NCw1NDk2NSw1NDk2Niw1NDk2Nyw1NDk2OCw1NDk3MCw1NDk3Miw1NDk3Myw1NDk3NCw1NDk3NSw1NDk3Niw1NDk3Nyw1NDk3OCw1NDk3OSw1NDk4Miw1NDk4Myw1NDk4NSw1NDk4Niw1NDk4NyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDk4OSw1NDk5MCw1NDk5MSw1NDk5Miw1NDk5NCw1NDk5NSw1NDk5Nyw1NDk5OCw1NTAwMCw1NTAwMiw1NTAwMyw1NTAwNCw1NTAwNSw1NTAwNiw1NTAwNyw1NTAwOSw1NTAxMCw1NTAxMSw1NTAxMyw1NTAxNCw1NTAxNSw1NTAxNyw1NTAxOCw1NTAxOSw1NTAyMCw1NTAyMSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NTAyMiw1NTAyMyw1NTAyNSw1NTAyNiw1NTAyNyw1NTAyOCw1NTAzMCw1NTAzMSw1NTAzMiw1NTAzMyw1NTAzNCw1NTAzNSw1NTAzOCw1NTAzOSw1NTA0MSw1NTA0Miw1NTA0Myw1NTA0NSw1NTA0Niw1NTA0Nyw1NTA0OCw1NTA0OSw1NTA1MCw1NTA1MSw1NTA1Miw1NTA1Myw1NTA1NCw1NTA1NSw1NTA1Niw1NTA1OCw1NTA1OSw1NTA2MCw1MjgyNCw1MjgyNSw1MjgyOCw1MjgzMSw1MjgzMiw1MjgzMyw1Mjg0MCw1Mjg0MSw1Mjg0Myw1Mjg0NSw1Mjg1Miw1Mjg1Myw1Mjg1Niw1Mjg2MCw1Mjg2OCw1Mjg2OSw1Mjg3MSw1Mjg3Myw1Mjg4MCw1Mjg4MSw1Mjg4NCw1Mjg4OCw1Mjg5Niw1Mjg5Nyw1Mjg5OSw1MjkwMCw1MjkwMSw1MjkwOCw1MjkwOSw1MjkyOSw1Mjk2NCw1Mjk2NSw1Mjk2OCw1Mjk3MSw1Mjk3Miw1Mjk4MCw1Mjk4MSw1Mjk4Myw1Mjk4NCw1Mjk4NSw1Mjk5Miw1Mjk5Myw1Mjk5Niw1MzAwMCw1MzAwOCw1MzAwOSw1MzAxMSw1MzAxMyw1MzAyMCw1MzAyNCw1MzAyOCw1MzAzNiw1MzAzNyw1MzAzOSw1MzA0MCw1MzA0MSw1MzA0OCw1MzA3Niw1MzA3Nyw1MzA4MCw1MzA4NCw1MzA5Miw1MzA5Myw1MzA5NSw1MzA5Nyw1MzEwNCw1MzEwNSw1MzEwOCw1MzExMiw1MzEyMCw1MzEyNSw1MzEzMiw1MzE1Myw1MzE2MCw1MzE2OCw1MzE4OCw1MzIxNiw1MzIxNyw1MzIyMCw1MzIyNCw1MzIzMiw1MzIzMyw1MzIzNSw1MzIzNyw1MzI0NCw1MzI0OCw1MzI1Miw1MzI2NSw1MzI3Miw1MzI5Myw1MzMwMCw1MzMwMSw1MzMwNCw1MzMwOCw1NTA2MSw1NTA2Miw1NTA2Myw1NTA2Niw1NTA2Nyw1NTA2OSw1NTA3MCw1NTA3MSw1NTA3Myw1NTA3NCw1NTA3NSw1NTA3Niw1NTA3Nyw1NTA3OCw1NTA3OSw1NTA4Miw1NTA4NCw1NTA4Niw1NTA4Nyw1NTA4OCw1NTA4OSw1NTA5MCw1NTA5MSw1NTA5NCw1NTA5NSw1NTA5NyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NTA5OCw1NTA5OSw1NTEwMSw1NTEwMiw1NTEwMyw1NTEwNCw1NTEwNSw1NTEwNiw1NTEwNyw1NTEwOSw1NTExMCw1NTExMiw1NTExNCw1NTExNSw1NTExNiw1NTExNyw1NTExOCw1NTExOSw1NTEyMiw1NTEyMyw1NTEyNSw1NTEzMCw1NTEzMSw1NTEzMiw1NTEzMyw1NTEzNCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NTEzNSw1NTEzOCw1NTE0MCw1NTE0Miw1NTE0Myw1NTE0NCw1NTE0Niw1NTE0Nyw1NTE0OSw1NTE1MCw1NTE1MSw1NTE1Myw1NTE1NCw1NTE1NSw1NTE1Nyw1NTE1OCw1NTE1OSw1NTE2MCw1NTE2MSw1NTE2Miw1NTE2Myw1NTE2Niw1NTE2Nyw1NTE2OCw1NTE3MCw1NTE3MSw1NTE3Miw1NTE3Myw1NTE3NCw1NTE3NSw1NTE3OCw1NTE3OSw1MzMxNiw1MzMxNyw1MzMxOSw1MzMyMSw1MzMyOCw1MzMzMiw1MzMzNiw1MzM0NCw1MzM1Niw1MzM1Nyw1MzM2MCw1MzM2NCw1MzM3Miw1MzM3Myw1MzM3Nyw1MzQxMiw1MzQxMyw1MzQxNiw1MzQyMCw1MzQyOCw1MzQyOSw1MzQzMSw1MzQzMyw1MzQ0MCw1MzQ0MSw1MzQ0NCw1MzQ0OCw1MzQ0OSw1MzQ1Niw1MzQ1Nyw1MzQ1OSw1MzQ2MCw1MzQ2MSw1MzQ2OCw1MzQ2OSw1MzQ3Miw1MzQ3Niw1MzQ4NCw1MzQ4NSw1MzQ4Nyw1MzQ4OCw1MzQ4OSw1MzQ5Niw1MzUxNyw1MzU1Miw1MzU1Myw1MzU1Niw1MzU2MCw1MzU2Miw1MzU2OCw1MzU2OSw1MzU3MSw1MzU3Miw1MzU3Myw1MzU4MCw1MzU4MSw1MzU4NCw1MzU4OCw1MzU5Niw1MzU5Nyw1MzU5OSw1MzYwMSw1MzYwOCw1MzYxMiw1MzYyOCw1MzYzNiw1MzY0MCw1MzY2NCw1MzY2NSw1MzY2OCw1MzY3Miw1MzY4MCw1MzY4MSw1MzY4Myw1MzY4NSw1MzY5MCw1MzY5Miw1MzY5Niw1MzcyMCw1Mzc0OCw1Mzc1Miw1Mzc2Nyw1Mzc2OSw1Mzc3Niw1MzgwNCw1MzgwNSw1MzgwOCw1MzgxMiw1MzgyMCw1MzgyMSw1MzgyMyw1MzgyNSw1MzgzMiw1Mzg1Miw1NTE4MSw1NTE4Miw1NTE4Myw1NTE4NSw1NTE4Niw1NTE4Nyw1NTE4OCw1NTE4OSw1NTE5MCw1NTE5MSw1NTE5NCw1NTE5Niw1NTE5OCw1NTE5OSw1NTIwMCw1NTIwMSw1NTIwMiw1NTIwMyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1Mzg2MCw1Mzg4OCw1Mzg4OSw1Mzg5Miw1Mzg5Niw1MzkwNCw1MzkwNSw1MzkwOSw1MzkxNiw1MzkyMCw1MzkyNCw1MzkzMiw1MzkzNyw1Mzk0NCw1Mzk0NSw1Mzk0OCw1Mzk1MSw1Mzk1Miw1Mzk1NCw1Mzk2MCw1Mzk2MSw1Mzk2Myw1Mzk3Miw1Mzk3Niw1Mzk4MCw1Mzk4OCw1Mzk4OSw1NDAwMCw1NDAwMSw1NDAwNCw1NDAwOCw1NDAxNiw1NDAxNyw1NDAxOSw1NDAyMSw1NDAyOCw1NDAyOSw1NDAzMCw1NDAzMiw1NDAzNiw1NDAzOCw1NDA0NCw1NDA0NSw1NDA0Nyw1NDA0OCw1NDA0OSw1NDA1Myw1NDA1Niw1NDA1Nyw1NDA2MCw1NDA2NCw1NDA3Miw1NDA3Myw1NDA3NSw1NDA3Niw1NDA3Nyw1NDA4NCw1NDA4NSw1NDE0MCw1NDE0MSw1NDE0NCw1NDE0OCw1NDE1Niw1NDE1Nyw1NDE1OSw1NDE2MCw1NDE2MSw1NDE2OCw1NDE2OSw1NDE3Miw1NDE3Niw1NDE4NCw1NDE4NSw1NDE4Nyw1NDE4OSw1NDE5Niw1NDIwMCw1NDIwNCw1NDIxMiw1NDIxMyw1NDIxNiw1NDIxNyw1NDIyNCw1NDIzMiw1NDI0MSw1NDI0Myw1NDI1Miw1NDI1Myw1NDI1Niw1NDI2MCw1NDI2OCw1NDI2OSw1NDI3MSw1NDI3MyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDI4MCw1NDMwMSw1NDMzNiw1NDM0MCw1NDM2NCw1NDM2OCw1NDM3Miw1NDM4MSw1NDM4Myw1NDM5Miw1NDM5Myw1NDM5Niw1NDM5OSw1NDQwMCw1NDQwMiw1NDQwOCw1NDQwOSw1NDQxMSw1NDQxMyw1NDQyMCw1NDQ0MSw1NDQ3Niw1NDQ4MCw1NDQ4NCw1NDQ5Miw1NDQ5NSw1NDUwNCw1NDUwOCw1NDUxMiw1NDUyMCw1NDUyMyw1NDUyNSw1NDUzMiw1NDUzNiw1NDU0MCw1NDU0OCw1NDU0OSw1NDU1MSw1NDU4OCw1NDU4OSw1NDU5Miw1NDU5Niw1NDYwNCw1NDYwNSw1NDYwNyw1NDYwOSw1NDYxNiw1NDYxNyw1NDYyMCw1NDYyNCw1NDYyOSw1NDYzMiw1NDYzMyw1NDYzNSw1NDYzNyw1NDY0NCw1NDY0NSw1NDY0OCw1NDY1Miw1NDY2MCw1NDY2MSw1NDY2Myw1NDY2NCw1NDY2NSw1NDY3Miw1NDY5Myw1NDcyOCw1NDcyOSw1NDczMiw1NDczNiw1NDczOCw1NDc0NCw1NDc0NSw1NDc0Nyw1NDc0OSw1NDc1Niw1NDc1Nyw1NDc2MCw1NDc2NCw1NDc3Miw1NDc3Myw1NDc3NSw1NDc3Nyw1NDc4NCw1NDc4NSw1NDc4OCw1NDc5Miw1NDgwMCw1NDgwMSw1NDgwMyw1NDgwNCw1NDgwNSw1NDgxMiw1NDgxNixudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw1NDgyMCw1NDgyOSw1NDg0MCw1NDg0MSw1NDg0NCw1NDg0OCw1NDg1Myw1NDg1Niw1NDg1Nyw1NDg1OSw1NDg2MSw1NDg2NSw1NDg2OCw1NDg2OSw1NDg3Miw1NDg3Niw1NDg4Nyw1NDg4OSw1NDg5Niw1NDg5Nyw1NDkwMCw1NDkxNSw1NDkxNyw1NDkyNCw1NDkyNSw1NDkyOCw1NDkzMiw1NDk0MSw1NDk0Myw1NDk0NSw1NDk1Miw1NDk1Niw1NDk2MCw1NDk2OSw1NDk3MSw1NDk4MCw1NDk4MSw1NDk4NCw1NDk4OCw1NDk5Myw1NDk5Niw1NDk5OSw1NTAwMSw1NTAwOCw1NTAxMiw1NTAxNiw1NTAyNCw1NTAyOSw1NTAzNiw1NTAzNyw1NTA0MCw1NTA0NCw1NTA1Nyw1NTA2NCw1NTA2NSw1NTA2OCw1NTA3Miw1NTA4MCw1NTA4MSw1NTA4Myw1NTA4NSw1NTA5Miw1NTA5Myw1NTA5Niw1NTEwMCw1NTEwOCw1NTExMSw1NTExMyw1NTEyMCw1NTEyMSw1NTEyNCw1NTEyNiw1NTEyNyw1NTEyOCw1NTEyOSw1NTEzNiw1NTEzNyw1NTEzOSw1NTE0MSw1NTE0NSw1NTE0OCw1NTE1Miw1NTE1Niw1NTE2NCw1NTE2NSw1NTE2OSw1NTE3Niw1NTE3Nyw1NTE4MCw1NTE4NCw1NTE5Miw1NTE5Myw1NTE5NSw1NTE5NyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDIwMjg1LDIwMzM5LDIwNTUxLDIwNzI5LDIxMTUyLDIxNDg3LDIxNjIxLDIxNzMzLDIyMDI1LDIzMjMzLDIzNDc4LDI2MjQ3LDI2NTUwLDI2NTUxLDI2NjA3LDI3NDY4LDI5NjM0LDMwMTQ2LDMxMjkyLDMzNDk5LDMzNTQwLDM0OTAzLDM0OTUyLDM1MzgyLDM2MDQwLDM2MzAzLDM2NjAzLDM2ODM4LDM5MzgxLDIxMDUxLDIxMzY0LDIxNTA4LDI0NjgyLDI0OTMyLDI3NTgwLDI5NjQ3LDMzMDUwLDM1MjU4LDM1MjgyLDM4MzA3LDIwMzU1LDIxMDAyLDIyNzE4LDIyOTA0LDIzMDE0LDI0MTc4LDI0MTg1LDI1MDMxLDI1NTM2LDI2NDM4LDI2NjA0LDI2NzUxLDI4NTY3LDMwMjg2LDMwNDc1LDMwOTY1LDMxMjQwLDMxNDg3LDMxNzc3LDMyOTI1LDMzMzkwLDMzMzkzLDM1NTYzLDM4MjkxLDIwMDc1LDIxOTE3LDI2MzU5LDI4MjEyLDMwODgzLDMxNDY5LDMzODgzLDM1MDg4LDM0NjM4LDM4ODI0LDIxMjA4LDIyMzUwLDIyNTcwLDIzODg0LDI0ODYzLDI1MDIyLDI1MTIxLDI1OTU0LDI2NTc3LDI3MjA0LDI4MTg3LDI5OTc2LDMwMTMxLDMwNDM1LDMwNjQwLDMyMDU4LDM3MDM5LDM3OTY5LDM3OTcwLDQwODUzLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDIxMjgzLDIzNzI0LDMwMDAyLDMyOTg3LDM3NDQwLDM4Mjk2LDIxMDgzLDIyNTM2LDIzMDA0LDIzNzEzLDIzODMxLDI0MjQ3LDI0Mzc4LDI0Mzk0LDI0OTUxLDI3NzQzLDMwMDc0LDMwMDg2LDMxOTY4LDMyMTE1LDMyMTc3LDMyNjUyLDMzMTA4LDMzMzEzLDM0MTkzLDM1MTM3LDM1NjExLDM3NjI4LDM4NDc3LDQwMDA3LDIwMTcxLDIwMjE1LDIwNDkxLDIwOTc3LDIyNjA3LDI0ODg3LDI0ODk0LDI0OTM2LDI1OTEzLDI3MTE0LDI4NDMzLDMwMTE3LDMwMzQyLDMwNDIyLDMxNjIzLDMzNDQ1LDMzOTk1LDYzNzQ0LDM3Nzk5LDM4MjgzLDIxODg4LDIzNDU4LDIyMzUzLDYzNzQ1LDMxOTIzLDMyNjk3LDM3MzAxLDIwNTIwLDIxNDM1LDIzNjIxLDI0MDQwLDI1Mjk4LDI1NDU0LDI1ODE4LDI1ODMxLDI4MTkyLDI4ODQ0LDMxMDY3LDM2MzE3LDM2MzgyLDYzNzQ2LDM2OTg5LDM3NDQ1LDM3NjI0LDIwMDk0LDIwMjE0LDIwNTgxLDI0MDYyLDI0MzE0LDI0ODM4LDI2OTY3LDMzMTM3LDM0Mzg4LDM2NDIzLDM3NzQ5LDM5NDY3LDIwMDYyLDIwNjI1LDI2NDgwLDI2Njg4LDIwNzQ1LDIxMTMzLDIxMTM4LDI3Mjk4LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDMwNjUyLDM3MzkyLDQwNjYwLDIxMTYzLDI0NjIzLDM2ODUwLDIwNTUyLDI1MDAxLDI1NTgxLDI1ODAyLDI2Njg0LDI3MjY4LDI4NjA4LDMzMTYwLDM1MjMzLDM4NTQ4LDIyNTMzLDI5MzA5LDI5MzU2LDI5OTU2LDMyMTIxLDMyMzY1LDMyOTM3LDM1MjExLDM1NzAwLDM2OTYzLDQwMjczLDI1MjI1LDI3NzcwLDI4NTAwLDMyMDgwLDMyNTcwLDM1MzYzLDIwODYwLDI0OTA2LDMxNjQ1LDM1NjA5LDM3NDYzLDM3NzcyLDIwMTQwLDIwNDM1LDIwNTEwLDIwNjcwLDIwNzQyLDIxMTg1LDIxMTk3LDIxMzc1LDIyMzg0LDIyNjU5LDI0MjE4LDI0NDY1LDI0OTUwLDI1MDA0LDI1ODA2LDI1OTY0LDI2MjIzLDI2Mjk5LDI2MzU2LDI2Nzc1LDI4MDM5LDI4ODA1LDI4OTEzLDI5ODU1LDI5ODYxLDI5ODk4LDMwMTY5LDMwODI4LDMwOTU2LDMxNDU1LDMxNDc4LDMyMDY5LDMyMTQ3LDMyNzg5LDMyODMxLDMzMDUxLDMzNjg2LDM1Njg2LDM2NjI5LDM2ODg1LDM3ODU3LDM4OTE1LDM4OTY4LDM5NTE0LDM5OTEyLDIwNDE4LDIxODQzLDIyNTg2LDIyODY1LDIzMzk1LDIzNjIyLDI0NzYwLDI1MTA2LDI2NjkwLDI2ODAwLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDI2ODU2LDI4MzMwLDMwMDI4LDMwMzI4LDMwOTI2LDMxMjkzLDMxOTk1LDMyMzYzLDMyMzgwLDM1MzM2LDM1NDg5LDM1OTAzLDM4NTQyLDQwMzg4LDIxNDc2LDIxNDgxLDIxNTc4LDIxNjE3LDIyMjY2LDIyOTkzLDIzMzk2LDIzNjExLDI0MjM1LDI1MzM1LDI1OTExLDI1OTI1LDI1OTcwLDI2MjcyLDI2NTQzLDI3MDczLDI3ODM3LDMwMjA0LDMwMzUyLDMwNTkwLDMxMjk1LDMyNjYwLDMyNzcxLDMyOTI5LDMzMTY3LDMzNTEwLDMzNTMzLDMzNzc2LDM0MjQxLDM0ODY1LDM0OTk2LDM1NDkzLDYzNzQ3LDM2NzY0LDM3Njc4LDM4NTk5LDM5MDE1LDM5NjQwLDQwNzIzLDIxNzQxLDI2MDExLDI2MzU0LDI2NzY3LDMxMjk2LDM1ODk1LDQwMjg4LDIyMjU2LDIyMzcyLDIzODI1LDI2MTE4LDI2ODAxLDI2ODI5LDI4NDE0LDI5NzM2LDM0OTc0LDM5OTA4LDI3NzUyLDYzNzQ4LDM5NTkyLDIwMzc5LDIwODQ0LDIwODQ5LDIxMTUxLDIzMzgwLDI0MDM3LDI0NjU2LDI0Njg1LDI1MzI5LDI1NTExLDI1OTE1LDI5NjU3LDMxMzU0LDM0NDY3LDM2MDAyLDM4Nzk5LDIwMDE4LDIzNTIxLDI1MDk2LDI2NTI0LDI5OTE2LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDMxMTg1LDMzNzQ3LDM1NDYzLDM1NTA2LDM2MzI4LDM2OTQyLDM3NzA3LDM4OTgyLDI0Mjc1LDI3MTEyLDM0MzAzLDM3MTAxLDYzNzQ5LDIwODk2LDIzNDQ4LDIzNTMyLDI0OTMxLDI2ODc0LDI3NDU0LDI4NzQ4LDI5NzQzLDI5OTEyLDMxNjQ5LDMyNTkyLDMzNzMzLDM1MjY0LDM2MDExLDM4MzY0LDM5MjA4LDIxMDM4LDI0NjY5LDI1MzI0LDM2ODY2LDIwMzYyLDIwODA5LDIxMjgxLDIyNzQ1LDI0MjkxLDI2MzM2LDI3OTYwLDI4ODI2LDI5Mzc4LDI5NjU0LDMxNTY4LDMzMDA5LDM3OTc5LDIxMzUwLDI1NDk5LDMyNjE5LDIwMDU0LDIwNjA4LDIyNjAyLDIyNzUwLDI0NjE4LDI0ODcxLDI1Mjk2LDI3MDg4LDM5NzQ1LDIzNDM5LDMyMDI0LDMyOTQ1LDM2NzAzLDIwMTMyLDIwNjg5LDIxNjc2LDIxOTMyLDIzMzA4LDIzOTY4LDI0MDM5LDI1ODk4LDI1OTM0LDI2NjU3LDI3MjExLDI5NDA5LDMwMzUwLDMwNzAzLDMyMDk0LDMyNzYxLDMzMTg0LDM0MTI2LDM0NTI3LDM2NjExLDM2Njg2LDM3MDY2LDM5MTcxLDM5NTA5LDM5ODUxLDE5OTkyLDIwMDM3LDIwMDYxLDIwMTY3LDIwNDY1LDIwODU1LDIxMjQ2LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDIxMzEyLDIxNDc1LDIxNDc3LDIxNjQ2LDIyMDM2LDIyMzg5LDIyNDM0LDIzNDk1LDIzOTQzLDI0MjcyLDI1MDg0LDI1MzA0LDI1OTM3LDI2NTUyLDI2NjAxLDI3MDgzLDI3NDcyLDI3NTkwLDI3NjI4LDI3NzE0LDI4MzE3LDI4NzkyLDI5Mzk5LDI5NTkwLDI5Njk5LDMwNjU1LDMwNjk3LDMxMzUwLDMyMTI3LDMyNzc3LDMzMjc2LDMzMjg1LDMzMjkwLDMzNTAzLDM0OTE0LDM1NjM1LDM2MDkyLDM2NTQ0LDM2ODgxLDM3MDQxLDM3NDc2LDM3NTU4LDM5Mzc4LDM5NDkzLDQwMTY5LDQwNDA3LDQwODYwLDIyMjgzLDIzNjE2LDMzNzM4LDM4ODE2LDM4ODI3LDQwNjI4LDIxNTMxLDMxMzg0LDMyNjc2LDM1MDMzLDM2NTU3LDM3MDg5LDIyNTI4LDIzNjI0LDI1NDk2LDMxMzkxLDIzNDcwLDI0MzM5LDMxMzUzLDMxNDA2LDMzNDIyLDM2NTI0LDIwNTE4LDIxMDQ4LDIxMjQwLDIxMzY3LDIyMjgwLDI1MzMxLDI1NDU4LDI3NDAyLDI4MDk5LDMwNTE5LDIxNDEzLDI5NTI3LDM0MTUyLDM2NDcwLDM4MzU3LDI2NDI2LDI3MzMxLDI4NTI4LDM1NDM3LDM2NTU2LDM5MjQzLDYzNzUwLDI2MjMxLDI3NTEyLDM2MDIwLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDM5NzQwLDYzNzUxLDIxNDgzLDIyMzE3LDIyODYyLDI1NTQyLDI3MTMxLDI5Njc0LDMwNzg5LDMxNDE4LDMxNDI5LDMxOTk4LDMzOTA5LDM1MjE1LDM2MjExLDM2OTE3LDM4MzEyLDIxMjQzLDIyMzQzLDMwMDIzLDMxNTg0LDMzNzQwLDM3NDA2LDYzNzUyLDI3MjI0LDIwODExLDIxMDY3LDIxMTI3LDI1MTE5LDI2ODQwLDI2OTk3LDM4NTUzLDIwNjc3LDIxMTU2LDIxMjIwLDI1MDI3LDI2MDIwLDI2NjgxLDI3MTM1LDI5ODIyLDMxNTYzLDMzNDY1LDMzNzcxLDM1MjUwLDM1NjQxLDM2ODE3LDM5MjQxLDYzNzUzLDIwMTcwLDIyOTM1LDI1ODEwLDI2MTI5LDI3Mjc4LDI5NzQ4LDMxMTA1LDMxMTY1LDMzNDQ5LDM0OTQyLDM0OTQzLDM1MTY3LDYzNzU0LDM3NjcwLDIwMjM1LDIxNDUwLDI0NjEzLDI1MjAxLDI3NzYyLDMyMDI2LDMyMTAyLDIwMTIwLDIwODM0LDMwNjg0LDMyOTQzLDIwMjI1LDIwMjM4LDIwODU0LDIwODY0LDIxOTgwLDIyMTIwLDIyMzMxLDIyNTIyLDIyNTI0LDIyODA0LDIyODU1LDIyOTMxLDIzNDkyLDIzNjk2LDIzODIyLDI0MDQ5LDI0MTkwLDI0NTI0LDI1MjE2LDI2MDcxLDI2MDgzLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDI2Mzk4LDI2Mzk5LDI2NDYyLDI2ODI3LDI2ODIwLDI3MjMxLDI3NDUwLDI3NjgzLDI3NzczLDI3Nzc4LDI4MTAzLDI5NTkyLDI5NzM0LDI5NzM4LDI5ODI2LDI5ODU5LDMwMDcyLDMwMDc5LDMwODQ5LDMwOTU5LDMxMDQxLDMxMDQ3LDMxMDQ4LDMxMDk4LDMxNjM3LDMyMDAwLDMyMTg2LDMyNjQ4LDMyNzc0LDMyODEzLDMyOTA4LDM1MzUyLDM1NjYzLDM1OTEyLDM2MjE1LDM3NjY1LDM3NjY4LDM5MTM4LDM5MjQ5LDM5NDM4LDM5NDM5LDM5NTI1LDQwNTk0LDMyMjAyLDIwMzQyLDIxNTEzLDI1MzI2LDI2NzA4LDM3MzI5LDIxOTMxLDIwNzk0LDYzNzU1LDYzNzU2LDIzMDY4LDI1MDYyLDYzNzU3LDI1Mjk1LDI1MzQzLDYzNzU4LDYzNzU5LDYzNzYwLDYzNzYxLDYzNzYyLDYzNzYzLDM3MDI3LDYzNzY0LDYzNzY1LDYzNzY2LDYzNzY3LDYzNzY4LDM1NTgyLDYzNzY5LDYzNzcwLDYzNzcxLDYzNzcyLDI2MjYyLDYzNzczLDI5MDE0LDYzNzc0LDYzNzc1LDM4NjI3LDYzNzc2LDI1NDIzLDI1NDY2LDIxMzM1LDYzNzc3LDI2NTExLDI2OTc2LDI4Mjc1LDYzNzc4LDMwMDA3LDYzNzc5LDYzNzgwLDYzNzgxLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDMyMDEzLDYzNzgyLDYzNzgzLDM0OTMwLDIyMjE4LDIzMDY0LDYzNzg0LDYzNzg1LDYzNzg2LDYzNzg3LDYzNzg4LDIwMDM1LDYzNzg5LDIwODM5LDIyODU2LDI2NjA4LDMyNzg0LDYzNzkwLDIyODk5LDI0MTgwLDI1NzU0LDMxMTc4LDI0NTY1LDI0Njg0LDI1Mjg4LDI1NDY3LDIzNTI3LDIzNTExLDIxMTYyLDYzNzkxLDIyOTAwLDI0MzYxLDI0NTk0LDYzNzkyLDYzNzkzLDYzNzk0LDI5Nzg1LDYzNzk1LDYzNzk2LDYzNzk3LDYzNzk4LDYzNzk5LDYzODAwLDM5Mzc3LDYzODAxLDYzODAyLDYzODAzLDYzODA0LDYzODA1LDYzODA2LDYzODA3LDYzODA4LDYzODA5LDYzODEwLDYzODExLDI4NjExLDYzODEyLDYzODEzLDMzMjE1LDM2Nzg2LDI0ODE3LDYzODE0LDYzODE1LDMzMTI2LDYzODE2LDYzODE3LDIzNjE1LDYzODE4LDYzODE5LDYzODIwLDYzODIxLDYzODIyLDYzODIzLDYzODI0LDYzODI1LDIzMjczLDM1MzY1LDI2NDkxLDMyMDE2LDYzODI2LDYzODI3LDYzODI4LDYzODI5LDYzODMwLDYzODMxLDMzMDIxLDYzODMyLDYzODMzLDIzNjEyLDI3ODc3LDIxMzExLDI4MzQ2LDIyODEwLDMzNTkwLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDIwMDI1LDIwMTUwLDIwMjk0LDIxOTM0LDIyMjk2LDIyNzI3LDI0NDA2LDI2MDM5LDI2MDg2LDI3MjY0LDI3NTczLDI4MjM3LDMwNzAxLDMxNDcxLDMxNzc0LDMyMjIyLDM0NTA3LDM0OTYyLDM3MTcwLDM3NzIzLDI1Nzg3LDI4NjA2LDI5NTYyLDMwMTM2LDM2OTQ4LDIxODQ2LDIyMzQ5LDI1MDE4LDI1ODEyLDI2MzExLDI4MTI5LDI4MjUxLDI4NTI1LDI4NjAxLDMwMTkyLDMyODM1LDMzMjEzLDM0MTEzLDM1MjAzLDM1NTI3LDM1Njc0LDM3NjYzLDI3Nzk1LDMwMDM1LDMxNTcyLDM2MzY3LDM2OTU3LDIxNzc2LDIyNTMwLDIyNjE2LDI0MTYyLDI1MDk1LDI1NzU4LDI2ODQ4LDMwMDcwLDMxOTU4LDM0NzM5LDQwNjgwLDIwMTk1LDIyNDA4LDIyMzgyLDIyODIzLDIzNTY1LDIzNzI5LDI0MTE4LDI0NDUzLDI1MTQwLDI1ODI1LDI5NjE5LDMzMjc0LDM0OTU1LDM2MDI0LDM4NTM4LDQwNjY3LDIzNDI5LDI0NTAzLDI0NzU1LDIwNDk4LDIwOTkyLDIxMDQwLDIyMjk0LDIyNTgxLDIyNjE1LDIzNTY2LDIzNjQ4LDIzNzk4LDIzOTQ3LDI0MjMwLDI0NDY2LDI0NzY0LDI1MzYxLDI1NDgxLDI1NjIzLDI2NjkxLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDI2ODczLDI3MzMwLDI4MTIwLDI4MTkzLDI4MzcyLDI4NjQ0LDI5MTgyLDMwNDI4LDMwNTg1LDMxMTUzLDMxMjkxLDMzNzk2LDM1MjQxLDM2MDc3LDM2MzM5LDM2NDI0LDM2ODY3LDM2ODg0LDM2OTQ3LDM3MTE3LDM3NzA5LDM4NTE4LDM4ODc2LDI3NjAyLDI4Njc4LDI5MjcyLDI5MzQ2LDI5NTQ0LDMwNTYzLDMxMTY3LDMxNzE2LDMyNDExLDM1NzEyLDIyNjk3LDI0Nzc1LDI1OTU4LDI2MTA5LDI2MzAyLDI3Nzg4LDI4OTU4LDI5MTI5LDM1OTMwLDM4OTMxLDIwMDc3LDMxMzYxLDIwMTg5LDIwOTA4LDIwOTQxLDIxMjA1LDIxNTE2LDI0OTk5LDI2NDgxLDI2NzA0LDI2ODQ3LDI3OTM0LDI4NTQwLDMwMTQwLDMwNjQzLDMxNDYxLDMzMDEyLDMzODkxLDM3NTA5LDIwODI4LDI2MDA3LDI2NDYwLDI2NTE1LDMwMTY4LDMxNDMxLDMzNjUxLDYzODM0LDM1OTEwLDM2ODg3LDM4OTU3LDIzNjYzLDMzMjE2LDMzNDM0LDM2OTI5LDM2OTc1LDM3Mzg5LDI0NDcxLDIzOTY1LDI3MjI1LDI5MTI4LDMwMzMxLDMxNTYxLDM0Mjc2LDM1NTg4LDM3MTU5LDM5NDcyLDIxODk1LDI1MDc4LDYzODM1LDMwMzEzLDMyNjQ1LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDM0MzY3LDM0NzQ2LDM1MDY0LDM3MDA3LDYzODM2LDI3OTMxLDI4ODg5LDI5NjYyLDMyMDk3LDMzODUzLDYzODM3LDM3MjI2LDM5NDA5LDYzODM4LDIwMDk4LDIxMzY1LDI3Mzk2LDI3NDEwLDI4NzM0LDI5MjExLDM0MzQ5LDQwNDc4LDIxMDY4LDM2NzcxLDIzODg4LDI1ODI5LDI1OTAwLDI3NDE0LDI4NjUxLDMxODExLDMyNDEyLDM0MjUzLDM1MTcyLDM1MjYxLDI1Mjg5LDMzMjQwLDM0ODQ3LDI0MjY2LDI2MzkxLDI4MDEwLDI5NDM2LDI5NzAxLDI5ODA3LDM0NjkwLDM3MDg2LDIwMzU4LDIzODIxLDI0NDgwLDMzODAyLDIwOTE5LDI1NTA0LDMwMDUzLDIwMTQyLDIwNDg2LDIwODQxLDIwOTM3LDI2NzUzLDI3MTUzLDMxOTE4LDMxOTIxLDMxOTc1LDMzMzkxLDM1NTM4LDM2NjM1LDM3MzI3LDIwNDA2LDIwNzkxLDIxMjM3LDIxNTcwLDI0MzAwLDI0OTQyLDI1MTUwLDI2MDUzLDI3MzU0LDI4NjcwLDMxMDE4LDM0MjY4LDM0ODUxLDM4MzE3LDM5NTIyLDM5NTMwLDQwNTk5LDQwNjU0LDIxMTQ3LDI2MzEwLDI3NTExLDI4NzAxLDMxMDE5LDM2NzA2LDM4NzIyLDI0OTc2LDI1MDg4LDI1ODkxLDI4NDUxLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDI5MDAxLDI5ODMzLDMyMjQ0LDMyODc5LDM0MDMwLDM2NjQ2LDM2ODk5LDM3NzA2LDIwOTI1LDIxMDE1LDIxMTU1LDI3OTE2LDI4ODcyLDM1MDEwLDI0MjY1LDI1OTg2LDI3NTY2LDI4NjEwLDMxODA2LDI5NTU3LDIwMTk2LDIwMjc4LDIyMjY1LDYzODM5LDIzNzM4LDIzOTk0LDI0NjA0LDI5NjE4LDMxNTMzLDMyNjY2LDMyNzE4LDMyODM4LDM2ODk0LDM3NDI4LDM4NjQ2LDM4NzI4LDM4OTM2LDQwODAxLDIwMzYzLDI4NTgzLDMxMTUwLDM3MzAwLDM4NTgzLDIxMjE0LDYzODQwLDI1NzM2LDI1Nzk2LDI3MzQ3LDI4NTEwLDI4Njk2LDI5MjAwLDMwNDM5LDMyNzY5LDM0MzEwLDM0Mzk2LDM2MzM1LDM2NjEzLDM4NzA2LDM5NzkxLDQwNDQyLDQwNTY1LDMwODYwLDMxMTAzLDMyMTYwLDMzNzM3LDM3NjM2LDQwNTc1LDQwNTk1LDM1NTQyLDIyNzUxLDI0MzI0LDI2NDA3LDI4NzExLDI5OTAzLDMxODQwLDMyODk0LDIwNzY5LDI4NzEyLDI5MjgyLDMwOTIyLDM2MDM0LDM2MDU4LDM2MDg0LDM4NjQ3LDIwMTAyLDIwNjk4LDIzNTM0LDI0Mjc4LDI2MDA5LDI5MTM0LDMwMjc0LDMwNjM3LDMyODQyLDM0MDQ0LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDM2OTg4LDM5NzE5LDQwODQ1LDIyNzQ0LDIzMTA1LDIzNjUwLDI3MTU1LDI4MTIyLDI4NDMxLDMwMjY3LDMyMDQ3LDMyMzExLDM0MDc4LDM1MTI4LDM3ODYwLDM4NDc1LDIxMTI5LDI2MDY2LDI2NjExLDI3MDYwLDI3OTY5LDI4MzE2LDI4Njg3LDI5NzA1LDI5NzkyLDMwMDQxLDMwMjQ0LDMwODI3LDM1NjI4LDM5MDA2LDIwODQ1LDI1MTM0LDM4NTIwLDIwMzc0LDIwNTIzLDIzODMzLDI4MTM4LDMyMTg0LDM2NjUwLDI0NDU5LDI0OTAwLDI2NjQ3LDYzODQxLDM4NTM0LDIxMjAyLDMyOTA3LDIwOTU2LDIwOTQwLDI2OTc0LDMxMjYwLDMyMTkwLDMzNzc3LDM4NTE3LDIwNDQyLDIxMDMzLDIxNDAwLDIxNTE5LDIxNzc0LDIzNjUzLDI0NzQzLDI2NDQ2LDI2NzkyLDI4MDEyLDI5MzEzLDI5NDMyLDI5NzAyLDI5ODI3LDYzODQyLDMwMTc4LDMxODUyLDMyNjMzLDMyNjk2LDMzNjczLDM1MDIzLDM1MDQxLDM3MzI0LDM3MzI4LDM4NjI2LDM5ODgxLDIxNTMzLDI4NTQyLDI5MTM2LDI5ODQ4LDM0Mjk4LDM2NTIyLDM4NTYzLDQwMDIzLDQwNjA3LDI2NTE5LDI4MTA3LDI5NzQ3LDMzMjU2LDM4Njc4LDMwNzY0LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDMxNDM1LDMxNTIwLDMxODkwLDI1NzA1LDI5ODAyLDMwMTk0LDMwOTA4LDMwOTUyLDM5MzQwLDM5NzY0LDQwNjM1LDIzNTE4LDI0MTQ5LDI4NDQ4LDMzMTgwLDMzNzA3LDM3MDAwLDE5OTc1LDIxMzI1LDIzMDgxLDI0MDE4LDI0Mzk4LDI0OTMwLDI1NDA1LDI2MjE3LDI2MzY0LDI4NDE1LDI4NDU5LDI4NzcxLDMwNjIyLDMzODM2LDM0MDY3LDM0ODc1LDM2NjI3LDM5MjM3LDM5OTk1LDIxNzg4LDI1MjczLDI2NDExLDI3ODE5LDMzNTQ1LDM1MTc4LDM4Nzc4LDIwMTI5LDIyOTE2LDI0NTM2LDI0NTM3LDI2Mzk1LDMyMTc4LDMyNTk2LDMzNDI2LDMzNTc5LDMzNzI1LDM2NjM4LDM3MDE3LDIyNDc1LDIyOTY5LDIzMTg2LDIzNTA0LDI2MTUxLDI2NTIyLDI2NzU3LDI3NTk5LDI5MDI4LDMyNjI5LDM2MDIzLDM2MDY3LDM2OTkzLDM5NzQ5LDMzMDMyLDM1OTc4LDM4NDc2LDM5NDg4LDQwNjEzLDIzMzkxLDI3NjY3LDI5NDY3LDMwNDUwLDMwNDMxLDMzODA0LDIwOTA2LDM1MjE5LDIwODEzLDIwODg1LDIxMTkzLDI2ODI1LDI3Nzk2LDMwNDY4LDMwNDk2LDMyMTkxLDMyMjM2LDM4NzU0LDQwNjI5LDI4MzU3LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDM0MDY1LDIwOTAxLDIxNTE3LDIxNjI5LDI2MTI2LDI2MjY5LDI2OTE5LDI4MzE5LDMwMzk5LDMwNjA5LDMzNTU5LDMzOTg2LDM0NzE5LDM3MjI1LDM3NTI4LDQwMTgwLDM0OTQ2LDIwMzk4LDIwODgyLDIxMjE1LDIyOTgyLDI0MTI1LDI0OTE3LDI1NzIwLDI1NzIxLDI2Mjg2LDI2NTc2LDI3MTY5LDI3NTk3LDI3NjExLDI5Mjc5LDI5MjgxLDI5NzYxLDMwNTIwLDMwNjgzLDMyNzkxLDMzNDY4LDMzNTQxLDM1NTg0LDM1NjI0LDM1OTgwLDI2NDA4LDI3NzkyLDI5Mjg3LDMwNDQ2LDMwNTY2LDMxMzAyLDQwMzYxLDI3NTE5LDI3Nzk0LDIyODE4LDI2NDA2LDMzOTQ1LDIxMzU5LDIyNjc1LDIyOTM3LDI0Mjg3LDI1NTUxLDI2MTY0LDI2NDgzLDI4MjE4LDI5NDgzLDMxNDQ3LDMzNDk1LDM3NjcyLDIxMjA5LDI0MDQzLDI1MDA2LDI1MDM1LDI1MDk4LDI1Mjg3LDI1NzcxLDI2MDgwLDI2OTY5LDI3NDk0LDI3NTk1LDI4OTYxLDI5Njg3LDMwMDQ1LDMyMzI2LDMzMzEwLDMzNTM4LDM0MTU0LDM1NDkxLDM2MDMxLDM4Njk1LDQwMjg5LDIyNjk2LDQwNjY0LDIwNDk3LDIxMDA2LDIxNTYzLDIxODM5LDI1OTkxLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDI3NzY2LDMyMDEwLDMyMDExLDMyODYyLDM0NDQyLDM4MjcyLDM4NjM5LDIxMjQ3LDI3Nzk3LDI5Mjg5LDIxNjE5LDIzMTk0LDIzNjE0LDIzODgzLDI0Mzk2LDI0NDk0LDI2NDEwLDI2ODA2LDI2OTc5LDI4MjIwLDI4MjI4LDMwNDczLDMxODU5LDMyNjU0LDM0MTgzLDM1NTk4LDM2ODU1LDM4NzUzLDQwNjkyLDIzNzM1LDI0NzU4LDI0ODQ1LDI1MDAzLDI1OTM1LDI2MTA3LDI2MTA4LDI3NjY1LDI3ODg3LDI5NTk5LDI5NjQxLDMyMjI1LDM4MjkyLDIzNDk0LDM0NTg4LDM1NjAwLDIxMDg1LDIxMzM4LDI1MjkzLDI1NjE1LDI1Nzc4LDI2NDIwLDI3MTkyLDI3ODUwLDI5NjMyLDI5ODU0LDMxNjM2LDMxODkzLDMyMjgzLDMzMTYyLDMzMzM0LDM0MTgwLDM2ODQzLDM4NjQ5LDM5MzYxLDIwMjc2LDIxMzIyLDIxNDUzLDIxNDY3LDI1MjkyLDI1NjQ0LDI1ODU2LDI2MDAxLDI3MDc1LDI3ODg2LDI4NTA0LDI5Njc3LDMwMDM2LDMwMjQyLDMwNDM2LDMwNDYwLDMwOTI4LDMwOTcxLDMxMDIwLDMyMDcwLDMzMzI0LDM0Nzg0LDM2ODIwLDM4OTMwLDM5MTUxLDIxMTg3LDI1MzAwLDI1NzY1LDI4MTk2LDI4NDk3LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDMwMzMyLDM2Mjk5LDM3Mjk3LDM3NDc0LDM5NjYyLDM5NzQ3LDIwNTE1LDIwNjIxLDIyMzQ2LDIyOTUyLDIzNTkyLDI0MTM1LDI0NDM5LDI1MTUxLDI1OTE4LDI2MDQxLDI2MDQ5LDI2MTIxLDI2NTA3LDI3MDM2LDI4MzU0LDMwOTE3LDMyMDMzLDMyOTM4LDMzMTUyLDMzMzIzLDMzNDU5LDMzOTUzLDM0NDQ0LDM1MzcwLDM1NjA3LDM3MDMwLDM4NDUwLDQwODQ4LDIwNDkzLDIwNDY3LDYzODQzLDIyNTIxLDI0NDcyLDI1MzA4LDI1NDkwLDI2NDc5LDI4MjI3LDI4OTUzLDMwNDAzLDMyOTcyLDMyOTg2LDM1MDYwLDM1MDYxLDM1MDk3LDM2MDY0LDM2NjQ5LDM3MTk3LDM4NTA2LDIwMjcxLDIwMzM2LDI0MDkxLDI2NTc1LDI2NjU4LDMwMzMzLDMwMzM0LDM5NzQ4LDI0MTYxLDI3MTQ2LDI5MDMzLDI5MTQwLDMwMDU4LDYzODQ0LDMyMzIxLDM0MTE1LDM0MjgxLDM5MTMyLDIwMjQwLDMxNTY3LDMyNjI0LDM4MzA5LDIwOTYxLDI0MDcwLDI2ODA1LDI3NzEwLDI3NzI2LDI3ODY3LDI5MzU5LDMxNjg0LDMzNTM5LDI3ODYxLDI5NzU0LDIwNzMxLDIxMTI4LDIyNzIxLDI1ODE2LDI3Mjg3LDI5ODYzLDMwMjk0LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDMwODg3LDM0MzI3LDM4MzcwLDM4NzEzLDYzODQ1LDIxMzQyLDI0MzIxLDM1NzIyLDM2Nzc2LDM2NzgzLDM3MDAyLDIxMDI5LDMwNjI5LDQwMDA5LDQwNzEyLDE5OTkzLDIwNDgyLDIwODUzLDIzNjQzLDI0MTgzLDI2MTQyLDI2MTcwLDI2NTY0LDI2ODIxLDI4ODUxLDI5OTUzLDMwMTQ5LDMxMTc3LDMxNDUzLDM2NjQ3LDM5MjAwLDM5NDMyLDIwNDQ1LDIyNTYxLDIyNTc3LDIzNTQyLDI2MjIyLDI3NDkzLDI3OTIxLDI4MjgyLDI4NTQxLDI5NjY4LDI5OTk1LDMzNzY5LDM1MDM2LDM1MDkxLDM1Njc2LDM2NjI4LDIwMjM5LDIwNjkzLDIxMjY0LDIxMzQwLDIzNDQzLDI0NDg5LDI2MzgxLDMxMTE5LDMzMTQ1LDMzNTgzLDM0MDY4LDM1MDc5LDM1MjA2LDM2NjY1LDM2NjY3LDM5MzMzLDM5OTU0LDI2NDEyLDIwMDg2LDIwNDcyLDIyODU3LDIzNTUzLDIzNzkxLDIzNzkyLDI1NDQ3LDI2ODM0LDI4OTI1LDI5MDkwLDI5NzM5LDMyMjk5LDM0MDI4LDM0NTYyLDM2ODk4LDM3NTg2LDQwMTc5LDE5OTgxLDIwMTg0LDIwNDYzLDIwNjEzLDIxMDc4LDIxMTAzLDIxNTQyLDIxNjQ4LDIyNDk2LDIyODI3LDIzMTQyLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDIzMzg2LDIzNDEzLDIzNTAwLDI0MjIwLDYzODQ2LDI1MjA2LDI1OTc1LDI2MDIzLDI4MDE0LDI4MzI1LDI5MjM4LDMxNTI2LDMxODA3LDMyNTY2LDMzMTA0LDMzMTA1LDMzMTc4LDMzMzQ0LDMzNDMzLDMzNzA1LDM1MzMxLDM2MDAwLDM2MDcwLDM2MDkxLDM2MjEyLDM2MjgyLDM3MDk2LDM3MzQwLDM4NDI4LDM4NDY4LDM5Mzg1LDQwMTY3LDIxMjcxLDIwOTk4LDIxNTQ1LDIyMTMyLDIyNzA3LDIyODY4LDIyODk0LDI0NTc1LDI0OTk2LDI1MTk4LDI2MTI4LDI3Nzc0LDI4OTU0LDMwNDA2LDMxODgxLDMxOTY2LDMyMDI3LDMzNDUyLDM2MDMzLDM4NjQwLDYzODQ3LDIwMzE1LDI0MzQzLDI0NDQ3LDI1MjgyLDIzODQ5LDI2Mzc5LDI2ODQyLDMwODQ0LDMyMzIzLDQwMzAwLDE5OTg5LDIwNjMzLDIxMjY5LDIxMjkwLDIxMzI5LDIyOTE1LDIzMTM4LDI0MTk5LDI0NzU0LDI0OTcwLDI1MTYxLDI1MjA5LDI2MDAwLDI2NTAzLDI3MDQ3LDI3NjA0LDI3NjA2LDI3NjA3LDI3NjA4LDI3ODMyLDYzODQ4LDI5NzQ5LDMwMjAyLDMwNzM4LDMwODY1LDMxMTg5LDMxMTkyLDMxODc1LDMyMjAzLDMyNzM3LDMyOTMzLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDMzMDg2LDMzMjE4LDMzNzc4LDM0NTg2LDM1MDQ4LDM1NTEzLDM1NjkyLDM2MDI3LDM3MTQ1LDM4NzUwLDM5MTMxLDQwNzYzLDIyMTg4LDIzMzM4LDI0NDI4LDI1OTk2LDI3MzE1LDI3NTY3LDI3OTk2LDI4NjU3LDI4NjkzLDI5Mjc3LDI5NjEzLDM2MDA3LDM2MDUxLDM4OTcxLDI0OTc3LDI3NzAzLDMyODU2LDM5NDI1LDIwMDQ1LDIwMTA3LDIwMTIzLDIwMTgxLDIwMjgyLDIwMjg0LDIwMzUxLDIwNDQ3LDIwNzM1LDIxNDkwLDIxNDk2LDIxNzY2LDIxOTg3LDIyMjM1LDIyNzYzLDIyODgyLDIzMDU3LDIzNTMxLDIzNTQ2LDIzNTU2LDI0MDUxLDI0MTA3LDI0NDczLDI0NjA1LDI1NDQ4LDI2MDEyLDI2MDMxLDI2NjE0LDI2NjE5LDI2Nzk3LDI3NTE1LDI3ODAxLDI3ODYzLDI4MTk1LDI4NjgxLDI5NTA5LDMwNzIyLDMxMDM4LDMxMDQwLDMxMDcyLDMxMTY5LDMxNzIxLDMyMDIzLDMyMTE0LDMyOTAyLDMzMjkzLDMzNjc4LDM0MDAxLDM0NTAzLDM1MDM5LDM1NDA4LDM1NDIyLDM1NjEzLDM2MDYwLDM2MTk4LDM2NzgxLDM3MDM0LDM5MTY0LDM5MzkxLDQwNjA1LDIxMDY2LDYzODQ5LDI2Mzg4LDYzODUwLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDIwNjMyLDIxMDM0LDIzNjY1LDI1OTU1LDI3NzMzLDI5NjQyLDI5OTg3LDMwMTA5LDMxNjM5LDMzOTQ4LDM3MjQwLDM4NzA0LDIwMDg3LDI1NzQ2LDI3NTc4LDI5MDIyLDM0MjE3LDE5OTc3LDYzODUxLDI2NDQxLDI2ODYyLDI4MTgzLDMzNDM5LDM0MDcyLDM0OTIzLDI1NTkxLDI4NTQ1LDM3Mzk0LDM5MDg3LDE5OTc4LDIwNjYzLDIwNjg3LDIwNzY3LDIxODMwLDIxOTMwLDIyMDM5LDIzMzYwLDIzNTc3LDIzNzc2LDI0MTIwLDI0MjAyLDI0MjI0LDI0MjU4LDI0ODE5LDI2NzA1LDI3MjMzLDI4MjQ4LDI5MjQ1LDI5MjQ4LDI5Mzc2LDMwNDU2LDMxMDc3LDMxNjY1LDMyNzI0LDM1MDU5LDM1MzE2LDM1NDQzLDM1OTM3LDM2MDYyLDM4Njg0LDIyNjIyLDI5ODg1LDM2MDkzLDIxOTU5LDYzODUyLDMxMzI5LDMyMDM0LDMzMzk0LDI5Mjk4LDI5OTgzLDI5OTg5LDYzODUzLDMxNTEzLDIyNjYxLDIyNzc5LDIzOTk2LDI0MjA3LDI0MjQ2LDI0NDY0LDI0NjYxLDI1MjM0LDI1NDcxLDI1OTMzLDI2MjU3LDI2MzI5LDI2MzYwLDI2NjQ2LDI2ODY2LDI5MzEyLDI5NzkwLDMxNTk4LDMyMTEwLDMyMjE0LDMyNjI2LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDMyOTk3LDMzMjk4LDM0MjIzLDM1MTk5LDM1NDc1LDM2ODkzLDM3NjA0LDQwNjUzLDQwNzM2LDIyODA1LDIyODkzLDI0MTA5LDI0Nzk2LDI2MTMyLDI2MjI3LDI2NTEyLDI3NzI4LDI4MTAxLDI4NTExLDMwNzA3LDMwODg5LDMzOTkwLDM3MzIzLDM3Njc1LDIwMTg1LDIwNjgyLDIwODA4LDIxODkyLDIzMzA3LDIzNDU5LDI1MTU5LDI1OTgyLDI2MDU5LDI4MjEwLDI5MDUzLDI5Njk3LDI5NzY0LDI5ODMxLDI5ODg3LDMwMzE2LDMxMTQ2LDMyMjE4LDMyMzQxLDMyNjgwLDMzMTQ2LDMzMjAzLDMzMzM3LDM0MzMwLDM0Nzk2LDM1NDQ1LDM2MzIzLDM2OTg0LDM3NTIxLDM3OTI1LDM5MjQ1LDM5ODU0LDIxMzUyLDIzNjMzLDI2OTY0LDI3ODQ0LDI3OTQ1LDI4MjAzLDMzMjkyLDM0MjAzLDM1MTMxLDM1MzczLDM1NDk4LDM4NjM0LDQwODA3LDIxMDg5LDI2Mjk3LDI3NTcwLDMyNDA2LDM0ODE0LDM2MTA5LDM4Mjc1LDM4NDkzLDI1ODg1LDI4MDQxLDI5MTY2LDYzODU0LDIyNDc4LDIyOTk1LDIzNDY4LDI0NjE1LDI0ODI2LDI1MTA0LDI2MTQzLDI2MjA3LDI5NDgxLDI5Njg5LDMwNDI3LDMwNDY1LDMxNTk2LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDMyODU0LDMyODgyLDMzMTI1LDM1NDg4LDM3MjY2LDE5OTkwLDIxMjE4LDI3NTA2LDI3OTI3LDMxMjM3LDMxNTQ1LDMyMDQ4LDYzODU1LDM2MDE2LDIxNDg0LDIyMDYzLDIyNjA5LDIzNDc3LDIzNTY3LDIzNTY5LDI0MDM0LDI1MTUyLDI1NDc1LDI1NjIwLDI2MTU3LDI2ODAzLDI3ODM2LDI4MDQwLDI4MzM1LDI4NzAzLDI4ODM2LDI5MTM4LDI5OTkwLDMwMDk1LDMwMDk0LDMwMjMzLDMxNTA1LDMxNzEyLDMxNzg3LDMyMDMyLDMyMDU3LDM0MDkyLDM0MTU3LDM0MzExLDM1MzgwLDM2ODc3LDM2OTYxLDM3MDQ1LDM3NTU5LDM4OTAyLDM5NDc5LDIwNDM5LDIzNjYwLDI2NDYzLDI4MDQ5LDMxOTAzLDMyMzk2LDM1NjA2LDM2MTE4LDM2ODk1LDIzNDAzLDI0MDYxLDI1NjEzLDMzOTg0LDM2OTU2LDM5MTM3LDI5NTc1LDIzNDM1LDI0NzMwLDI2NDk0LDI4MTI2LDM1MzU5LDM1NDk0LDM2ODY1LDM4OTI0LDIxMDQ3LDYzODU2LDI4NzUzLDMwODYyLDM3NzgyLDM0OTI4LDM3MzM1LDIwNDYyLDIxNDYzLDIyMDEzLDIyMjM0LDIyNDAyLDIyNzgxLDIzMjM0LDIzNDMyLDIzNzIzLDIzNzQ0LDI0MTAxLDI0ODMzLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDI1MTAxLDI1MTYzLDI1NDgwLDI1NjI4LDI1OTEwLDI1OTc2LDI3MTkzLDI3NTMwLDI3NzAwLDI3OTI5LDI4NDY1LDI5MTU5LDI5NDE3LDI5NTYwLDI5NzAzLDI5ODc0LDMwMjQ2LDMwNTYxLDMxMTY4LDMxMzE5LDMxNDY2LDMxOTI5LDMyMTQzLDMyMTcyLDMyMzUzLDMyNjcwLDMzMDY1LDMzNTg1LDMzOTM2LDM0MDEwLDM0MjgyLDM0OTY2LDM1NTA0LDM1NzI4LDM2NjY0LDM2OTMwLDM2OTk1LDM3MjI4LDM3NTI2LDM3NTYxLDM4NTM5LDM4NTY3LDM4NTY4LDM4NjE0LDM4NjU2LDM4OTIwLDM5MzE4LDM5NjM1LDM5NzA2LDIxNDYwLDIyNjU0LDIyODA5LDIzNDA4LDIzNDg3LDI4MTEzLDI4NTA2LDI5MDg3LDI5NzI5LDI5ODgxLDMyOTAxLDMzNzg5LDI0MDMzLDI0NDU1LDI0NDkwLDI0NjQyLDI2MDkyLDI2NjQyLDI2OTkxLDI3MjE5LDI3NTI5LDI3OTU3LDI4MTQ3LDI5NjY3LDMwNDYyLDMwNjM2LDMxNTY1LDMyMDIwLDMzMDU5LDMzMzA4LDMzNjAwLDM0MDM2LDM0MTQ3LDM1NDI2LDM1NTI0LDM3MjU1LDM3NjYyLDM4OTE4LDM5MzQ4LDI1MTAwLDM0ODk5LDM2ODQ4LDM3NDc3LDIzODE1LDIzODQ3LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDIzOTEzLDI5NzkxLDMzMTgxLDM0NjY0LDI4NjI5LDI1MzQyLDMyNzIyLDM1MTI2LDM1MTg2LDE5OTk4LDIwMDU2LDIwNzExLDIxMjEzLDIxMzE5LDI1MjE1LDI2MTE5LDMyMzYxLDM0ODIxLDM4NDk0LDIwMzY1LDIxMjczLDIyMDcwLDIyOTg3LDIzMjA0LDIzNjA4LDIzNjMwLDIzNjI5LDI0MDY2LDI0MzM3LDI0NjQzLDI2MDQ1LDI2MTU5LDI2MTc4LDI2NTU4LDI2NjEyLDI5NDY4LDMwNjkwLDMxMDM0LDMyNzA5LDMzOTQwLDMzOTk3LDM1MjIyLDM1NDMwLDM1NDMzLDM1NTUzLDM1OTI1LDM1OTYyLDIyNTE2LDIzNTA4LDI0MzM1LDI0Njg3LDI1MzI1LDI2ODkzLDI3NTQyLDI4MjUyLDI5MDYwLDMxNjk4LDM0NjQ1LDM1NjcyLDM2NjA2LDM5MTM1LDM5MTY2LDIwMjgwLDIwMzUzLDIwNDQ5LDIxNjI3LDIzMDcyLDIzNDgwLDI0ODkyLDI2MDMyLDI2MjE2LDI5MTgwLDMwMDAzLDMxMDcwLDMyMDUxLDMzMTAyLDMzMjUxLDMzNjg4LDM0MjE4LDM0MjU0LDM0NTYzLDM1MzM4LDM2NTIzLDM2NzYzLDYzODU3LDM2ODA1LDIyODMzLDIzNDYwLDIzNTI2LDI0NzEzLDIzNTI5LDIzNTYzLDI0NTE1LDI3Nzc3LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDYzODU4LDI4MTQ1LDI4NjgzLDI5OTc4LDMzNDU1LDM1NTc0LDIwMTYwLDIxMzEzLDYzODU5LDM4NjE3LDI3NjYzLDIwMTI2LDIwNDIwLDIwODE4LDIxODU0LDIzMDc3LDIzNzg0LDI1MTA1LDI5MjczLDMzNDY5LDMzNzA2LDM0NTU4LDM0OTA1LDM1MzU3LDM4NDYzLDM4NTk3LDM5MTg3LDQwMjAxLDQwMjg1LDIyNTM4LDIzNzMxLDIzOTk3LDI0MTMyLDI0ODAxLDI0ODUzLDI1NTY5LDI3MTM4LDI4MTk3LDM3MTIyLDM3NzE2LDM4OTkwLDM5OTUyLDQwODIzLDIzNDMzLDIzNzM2LDI1MzUzLDI2MTkxLDI2Njk2LDMwNTI0LDM4NTkzLDM4Nzk3LDM4OTk2LDM5ODM5LDI2MDE3LDM1NTg1LDM2NTU1LDM4MzMyLDIxODEzLDIzNzIxLDI0MDIyLDI0MjQ1LDI2MjYzLDMwMjg0LDMzNzgwLDM4MzQzLDIyNzM5LDI1Mjc2LDI5MzkwLDQwMjMyLDIwMjA4LDIyODMwLDI0NTkxLDI2MTcxLDI3NTIzLDMxMjA3LDQwMjMwLDIxMzk1LDIxNjk2LDIyNDY3LDIzODMwLDI0ODU5LDI2MzI2LDI4MDc5LDMwODYxLDMzNDA2LDM4NTUyLDM4NzI0LDIxMzgwLDI1MjEyLDI1NDk0LDI4MDgyLDMyMjY2LDMzMDk5LDM4OTg5LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDI3Mzg3LDMyNTg4LDQwMzY3LDQwNDc0LDIwMDYzLDIwNTM5LDIwOTE4LDIyODEyLDI0ODI1LDI1NTkwLDI2OTI4LDI5MjQyLDMyODIyLDYzODYwLDM3MzI2LDI0MzY5LDYzODYxLDYzODYyLDMyMDA0LDMzNTA5LDMzOTAzLDMzOTc5LDM0Mjc3LDM2NDkzLDYzODYzLDIwMzM1LDYzODY0LDYzODY1LDIyNzU2LDIzMzYzLDI0NjY1LDI1NTYyLDI1ODgwLDI1OTY1LDI2MjY0LDYzODY2LDI2OTU0LDI3MTcxLDI3OTE1LDI4NjczLDI5MDM2LDMwMTYyLDMwMjIxLDMxMTU1LDMxMzQ0LDYzODY3LDMyNjUwLDYzODY4LDM1MTQwLDYzODY5LDM1NzMxLDM3MzEyLDM4NTI1LDYzODcwLDM5MTc4LDIyMjc2LDI0NDgxLDI2MDQ0LDI4NDE3LDMwMjA4LDMxMTQyLDM1NDg2LDM5MzQxLDM5NzcwLDQwODEyLDIwNzQwLDI1MDE0LDI1MjMzLDI3Mjc3LDMzMjIyLDIwNTQ3LDIyNTc2LDI0NDIyLDI4OTM3LDM1MzI4LDM1NTc4LDIzNDIwLDM0MzI2LDIwNDc0LDIwNzk2LDIyMTk2LDIyODUyLDI1NTEzLDI4MTUzLDIzOTc4LDI2OTg5LDIwODcwLDIwMTA0LDIwMzEzLDYzODcxLDYzODcyLDYzODczLDIyOTE0LDYzODc0LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDYzODc1LDI3NDg3LDI3NzQxLDYzODc2LDI5ODc3LDMwOTk4LDYzODc3LDMzMjg3LDMzMzQ5LDMzNTkzLDM2NjcxLDM2NzAxLDYzODc4LDM5MTkyLDYzODc5LDYzODgwLDYzODgxLDIwMTM0LDYzODgyLDIyNDk1LDI0NDQxLDI2MTMxLDYzODgzLDYzODg0LDMwMTIzLDMyMzc3LDM1Njk1LDYzODg1LDM2ODcwLDM5NTE1LDIyMTgxLDIyNTY3LDIzMDMyLDIzMDcxLDIzNDc2LDYzODg2LDI0MzEwLDYzODg3LDYzODg4LDI1NDI0LDI1NDAzLDYzODg5LDI2OTQxLDI3NzgzLDI3ODM5LDI4MDQ2LDI4MDUxLDI4MTQ5LDI4NDM2LDYzODkwLDI4ODk1LDI4OTgyLDI5MDE3LDYzODkxLDI5MTIzLDI5MTQxLDYzODkyLDMwNzk5LDMwODMxLDYzODkzLDMxNjA1LDMyMjI3LDYzODk0LDMyMzAzLDYzODk1LDM0ODkzLDM2NTc1LDYzODk2LDYzODk3LDYzODk4LDM3NDY3LDYzODk5LDQwMTgyLDYzOTAwLDYzOTAxLDYzOTAyLDI0NzA5LDI4MDM3LDYzOTAzLDI5MTA1LDYzOTA0LDYzOTA1LDM4MzIxLDIxNDIxLDYzOTA2LDYzOTA3LDYzOTA4LDI2NTc5LDYzOTA5LDI4ODE0LDI4OTc2LDI5NzQ0LDMzMzk4LDMzNDkwLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDYzOTEwLDM4MzMxLDM5NjUzLDQwNTczLDI2MzA4LDYzOTExLDI5MTIxLDMzODY1LDYzOTEyLDYzOTEzLDIyNjAzLDYzOTE0LDYzOTE1LDIzOTkyLDI0NDMzLDYzOTE2LDI2MTQ0LDI2MjU0LDI3MDAxLDI3MDU0LDI3NzA0LDI3ODkxLDI4MjE0LDI4NDgxLDI4NjM0LDI4Njk5LDI4NzE5LDI5MDA4LDI5MTUxLDI5NTUyLDYzOTE3LDI5Nzg3LDYzOTE4LDI5OTA4LDMwNDA4LDMxMzEwLDMyNDAzLDYzOTE5LDYzOTIwLDMzNTIxLDM1NDI0LDM2ODE0LDYzOTIxLDM3NzA0LDYzOTIyLDM4NjgxLDYzOTIzLDYzOTI0LDIwMDM0LDIwNTIyLDYzOTI1LDIxMDAwLDIxNDczLDI2MzU1LDI3NzU3LDI4NjE4LDI5NDUwLDMwNTkxLDMxMzMwLDMzNDU0LDM0MjY5LDM0MzA2LDYzOTI2LDM1MDI4LDM1NDI3LDM1NzA5LDM1OTQ3LDYzOTI3LDM3NTU1LDYzOTI4LDM4Njc1LDM4OTI4LDIwMTE2LDIwMjM3LDIwNDI1LDIwNjU4LDIxMzIwLDIxNTY2LDIxNTU1LDIxOTc4LDIyNjI2LDIyNzE0LDIyODg3LDIzMDY3LDIzNTI0LDI0NzM1LDYzOTI5LDI1MDM0LDI1OTQyLDI2MTExLDI2MjEyLDI2NzkxLDI3NzM4LDI4NTk1LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDI4ODc5LDI5MTAwLDI5NTIyLDMxNjEzLDM0NTY4LDM1NDkyLDM5OTg2LDQwNzExLDIzNjI3LDI3Nzc5LDI5NTA4LDI5NTc3LDM3NDM0LDI4MzMxLDI5Nzk3LDMwMjM5LDMxMzM3LDMyMjc3LDM0MzE0LDIwODAwLDIyNzI1LDI1NzkzLDI5OTM0LDI5OTczLDMwMzIwLDMyNzA1LDM3MDEzLDM4NjA1LDM5MjUyLDI4MTk4LDI5OTI2LDMxNDAxLDMxNDAyLDMzMjUzLDM0NTIxLDM0NjgwLDM1MzU1LDIzMTEzLDIzNDM2LDIzNDUxLDI2Nzg1LDI2ODgwLDI4MDAzLDI5NjA5LDI5NzE1LDI5NzQwLDMwODcxLDMyMjMzLDMyNzQ3LDMzMDQ4LDMzMTA5LDMzNjk0LDM1OTE2LDM4NDQ2LDM4OTI5LDI2MzUyLDI0NDQ4LDI2MTA2LDI2NTA1LDI3NzU0LDI5NTc5LDIwNTI1LDIzMDQzLDI3NDk4LDMwNzAyLDIyODA2LDIzOTE2LDI0MDEzLDI5NDc3LDMwMDMxLDYzOTMwLDYzOTMxLDIwNzA5LDIwOTg1LDIyNTc1LDIyODI5LDIyOTM0LDIzMDAyLDIzNTI1LDYzOTMyLDYzOTMzLDIzOTcwLDI1MzAzLDI1NjIyLDI1NzQ3LDI1ODU0LDYzOTM0LDI2MzMyLDYzOTM1LDI3MjA4LDYzOTM2LDI5MTgzLDI5Nzk2LDYzOTM3LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDMxMzY4LDMxNDA3LDMyMzI3LDMyMzUwLDMyNzY4LDMzMTM2LDYzOTM4LDM0Nzk5LDM1MjAxLDM1NjE2LDM2OTUzLDYzOTM5LDM2OTkyLDM5MjUwLDI0OTU4LDI3NDQyLDI4MDIwLDMyMjg3LDM1MTA5LDM2Nzg1LDIwNDMzLDIwNjUzLDIwODg3LDIxMTkxLDIyNDcxLDIyNjY1LDIzNDgxLDI0MjQ4LDI0ODk4LDI3MDI5LDI4MDQ0LDI4MjYzLDI4MzQyLDI5MDc2LDI5Nzk0LDI5OTkyLDI5OTk2LDMyODgzLDMzNTkyLDMzOTkzLDM2MzYyLDM3NzgwLDM3ODU0LDYzOTQwLDIwMTEwLDIwMzA1LDIwNTk4LDIwNzc4LDIxNDQ4LDIxNDUxLDIxNDkxLDIzNDMxLDIzNTA3LDIzNTg4LDI0ODU4LDI0OTYyLDI2MTAwLDI5Mjc1LDI5NTkxLDI5NzYwLDMwNDAyLDMxMDU2LDMxMTIxLDMxMTYxLDMyMDA2LDMyNzAxLDMzNDE5LDM0MjYxLDM0Mzk4LDM2ODAyLDM2OTM1LDM3MTA5LDM3MzU0LDM4NTMzLDM4NjMyLDM4NjMzLDIxMjA2LDI0NDIzLDI2MDkzLDI2MTYxLDI2NjcxLDI5MDIwLDMxMjg2LDM3MDU3LDM4OTIyLDIwMTEzLDYzOTQxLDI3MjE4LDI3NTUwLDI4NTYwLDI5MDY1LDMyNzkyLDMzNDY0LDM0MTMxLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDM2OTM5LDM4NTQ5LDM4NjQyLDM4OTA3LDM0MDc0LDM5NzI5LDIwMTEyLDI5MDY2LDM4NTk2LDIwODAzLDIxNDA3LDIxNzI5LDIyMjkxLDIyMjkwLDIyNDM1LDIzMTk1LDIzMjM2LDIzNDkxLDI0NjE2LDI0ODk1LDI1NTg4LDI3NzgxLDI3OTYxLDI4Mjc0LDI4MzA0LDI5MjMyLDI5NTAzLDI5NzgzLDMzNDg5LDM0OTQ1LDM2Njc3LDM2OTYwLDYzOTQyLDM4NDk4LDM5MDAwLDQwMjE5LDI2Mzc2LDM2MjM0LDM3NDcwLDIwMzAxLDIwNTUzLDIwNzAyLDIxMzYxLDIyMjg1LDIyOTk2LDIzMDQxLDIzNTYxLDI0OTQ0LDI2MjU2LDI4MjA1LDI5MjM0LDI5NzcxLDMyMjM5LDMyOTYzLDMzODA2LDMzODk0LDM0MTExLDM0NjU1LDM0OTA3LDM1MDk2LDM1NTg2LDM2OTQ5LDM4ODU5LDM5NzU5LDIwMDgzLDIwMzY5LDIwNzU0LDIwODQyLDYzOTQzLDIxODA3LDIxOTI5LDIzNDE4LDIzNDYxLDI0MTg4LDI0MTg5LDI0MjU0LDI0NzM2LDI0Nzk5LDI0ODQwLDI0ODQxLDI1NTQwLDI1OTEyLDI2Mzc3LDYzOTQ0LDI2NTgwLDI2NTg2LDYzOTQ1LDI2OTc3LDI2OTc4LDI3ODMzLDI3OTQzLDYzOTQ2LDI4MjE2LDYzOTQ3LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDI4NjQxLDI5NDk0LDI5NDk1LDYzOTQ4LDI5Nzg4LDMwMDAxLDYzOTQ5LDMwMjkwLDYzOTUwLDYzOTUxLDMyMTczLDMzMjc4LDMzODQ4LDM1MDI5LDM1NDgwLDM1NTQ3LDM1NTY1LDM2NDAwLDM2NDE4LDM2OTM4LDM2OTI2LDM2OTg2LDM3MTkzLDM3MzIxLDM3NzQyLDYzOTUyLDYzOTUzLDIyNTM3LDYzOTU0LDI3NjAzLDMyOTA1LDMyOTQ2LDYzOTU1LDYzOTU2LDIwODAxLDIyODkxLDIzNjA5LDYzOTU3LDYzOTU4LDI4NTE2LDI5NjA3LDMyOTk2LDM2MTAzLDYzOTU5LDM3Mzk5LDM4Mjg3LDYzOTYwLDYzOTYxLDYzOTYyLDYzOTYzLDMyODk1LDI1MTAyLDI4NzAwLDMyMTA0LDM0NzAxLDYzOTY0LDIyNDMyLDI0NjgxLDI0OTAzLDI3NTc1LDM1NTE4LDM3NTA0LDM4NTc3LDIwMDU3LDIxNTM1LDI4MTM5LDM0MDkzLDM4NTEyLDM4ODk5LDM5MTUwLDI1NTU4LDI3ODc1LDM3MDA5LDIwOTU3LDI1MDMzLDMzMjEwLDQwNDQxLDIwMzgxLDIwNTA2LDIwNzM2LDIzNDUyLDI0ODQ3LDI1MDg3LDI1ODM2LDI2ODg1LDI3NTg5LDMwMDk3LDMwNjkxLDMyNjgxLDMzMzgwLDM0MTkxLDM0ODExLDM0OTE1LDM1NTE2LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDM1Njk2LDM3MjkxLDIwMTA4LDIwMTk3LDIwMjM0LDYzOTY1LDYzOTY2LDIyODM5LDIzMDE2LDYzOTY3LDI0MDUwLDI0MzQ3LDI0NDExLDI0NjA5LDYzOTY4LDYzOTY5LDYzOTcwLDYzOTcxLDI5MjQ2LDI5NjY5LDYzOTcyLDMwMDY0LDMwMTU3LDYzOTczLDMxMjI3LDYzOTc0LDMyNzgwLDMyODE5LDMyOTAwLDMzNTA1LDMzNjE3LDYzOTc1LDYzOTc2LDM2MDI5LDM2MDE5LDM2OTk5LDYzOTc3LDYzOTc4LDM5MTU2LDM5MTgwLDYzOTc5LDYzOTgwLDI4NzI3LDMwNDEwLDMyNzE0LDMyNzE2LDMyNzY0LDM1NjEwLDIwMTU0LDIwMTYxLDIwOTk1LDIxMzYwLDYzOTgxLDIxNjkzLDIyMjQwLDIzMDM1LDIzNDkzLDI0MzQxLDI0NTI1LDI4MjcwLDYzOTgyLDYzOTgzLDMyMTA2LDMzNTg5LDYzOTg0LDM0NDUxLDM1NDY5LDYzOTg1LDM4NzY1LDM4Nzc1LDYzOTg2LDYzOTg3LDE5OTY4LDIwMzE0LDIwMzUwLDIyNzc3LDI2MDg1LDI4MzIyLDM2OTIwLDM3ODA4LDM5MzUzLDIwMjE5LDIyNzY0LDIyOTIyLDIzMDAxLDI0NjQxLDYzOTg4LDYzOTg5LDMxMjUyLDYzOTkwLDMzNjE1LDM2MDM1LDIwODM3LDIxMzE2LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDYzOTkxLDYzOTkyLDYzOTkzLDIwMTczLDIxMDk3LDIzMzgxLDMzNDcxLDIwMTgwLDIxMDUwLDIxNjcyLDIyOTg1LDIzMDM5LDIzMzc2LDIzMzgzLDIzMzg4LDI0Njc1LDI0OTA0LDI4MzYzLDI4ODI1LDI5MDM4LDI5NTc0LDI5OTQzLDMwMTMzLDMwOTEzLDMyMDQzLDMyNzczLDMzMjU4LDMzNTc2LDM0MDcxLDM0MjQ5LDM1NTY2LDM2MDM5LDM4NjA0LDIwMzE2LDIxMjQyLDIyMjA0LDI2MDI3LDI2MTUyLDI4Nzk2LDI4ODU2LDI5MjM3LDMyMTg5LDMzNDIxLDM3MTk2LDM4NTkyLDQwMzA2LDIzNDA5LDI2ODU1LDI3NTQ0LDI4NTM4LDMwNDMwLDIzNjk3LDI2MjgzLDI4NTA3LDMxNjY4LDMxNzg2LDM0ODcwLDM4NjIwLDE5OTc2LDIwMTgzLDIxMjgwLDIyNTgwLDIyNzE1LDIyNzY3LDIyODkyLDIzNTU5LDI0MTE1LDI0MTk2LDI0MzczLDI1NDg0LDI2MjkwLDI2NDU0LDI3MTY3LDI3Mjk5LDI3NDA0LDI4NDc5LDI5MjU0LDYzOTk0LDI5NTIwLDI5ODM1LDMxNDU2LDMxOTExLDMzMTQ0LDMzMjQ3LDMzMjU1LDMzNjc0LDMzOTAwLDM0MDgzLDM0MTk2LDM0MjU1LDM1MDM3LDM2MTE1LDM3MjkyLDM4MjYzLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDM4NTU2LDIwODc3LDIxNzA1LDIyMzEyLDIzNDcyLDI1MTY1LDI2NDQ4LDI2Njg1LDI2NzcxLDI4MjIxLDI4MzcxLDI4Nzk3LDMyMjg5LDM1MDA5LDM2MDAxLDM2NjE3LDQwNzc5LDQwNzgyLDI5MjI5LDMxNjMxLDM1NTMzLDM3NjU4LDIwMjk1LDIwMzAyLDIwNzg2LDIxNjMyLDIyOTkyLDI0MjEzLDI1MjY5LDI2NDg1LDI2OTkwLDI3MTU5LDI3ODIyLDI4MTg2LDI5NDAxLDI5NDgyLDMwMTQxLDMxNjcyLDMyMDUzLDMzNTExLDMzNzg1LDMzODc5LDM0Mjk1LDM1NDE5LDM2MDE1LDM2NDg3LDM2ODg5LDM3MDQ4LDM4NjA2LDQwNzk5LDIxMjE5LDIxNTE0LDIzMjY1LDIzNDkwLDI1Njg4LDI1OTczLDI4NDA0LDI5MzgwLDYzOTk1LDMwMzQwLDMxMzA5LDMxNTE1LDMxODIxLDMyMzE4LDMyNzM1LDMzNjU5LDM1NjI3LDM2MDQyLDM2MTk2LDM2MzIxLDM2NDQ3LDM2ODQyLDM2ODU3LDM2OTY5LDM3ODQxLDIwMjkxLDIwMzQ2LDIwNjU5LDIwODQwLDIwODU2LDIxMDY5LDIxMDk4LDIyNjI1LDIyNjUyLDIyODgwLDIzNTYwLDIzNjM3LDI0MjgzLDI0NzMxLDI1MTM2LDI2NjQzLDI3NTgzLDI3NjU2LDI4NTkzLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDI5MDA2LDI5NzI4LDMwMDAwLDMwMDA4LDMwMDMzLDMwMzIyLDMxNTY0LDMxNjI3LDMxNjYxLDMxNjg2LDMyMzk5LDM1NDM4LDM2NjcwLDM2NjgxLDM3NDM5LDM3NTIzLDM3NjY2LDM3OTMxLDM4NjUxLDM5MDAyLDM5MDE5LDM5MTk4LDIwOTk5LDI1MTMwLDI1MjQwLDI3OTkzLDMwMzA4LDMxNDM0LDMxNjgwLDMyMTE4LDIxMzQ0LDIzNzQyLDI0MjE1LDI4NDcyLDI4ODU3LDMxODk2LDM4NjczLDM5ODIyLDQwNjcwLDI1NTA5LDI1NzIyLDM0Njc4LDE5OTY5LDIwMTE3LDIwMTQxLDIwNTcyLDIwNTk3LDIxNTc2LDIyOTc5LDIzNDUwLDI0MTI4LDI0MjM3LDI0MzExLDI0NDQ5LDI0NzczLDI1NDAyLDI1OTE5LDI1OTcyLDI2MDYwLDI2MjMwLDI2MjMyLDI2NjIyLDI2OTg0LDI3MjczLDI3NDkxLDI3NzEyLDI4MDk2LDI4MTM2LDI4MTkxLDI4MjU0LDI4NzAyLDI4ODMzLDI5NTgyLDI5NjkzLDMwMDEwLDMwNTU1LDMwODU1LDMxMTE4LDMxMjQzLDMxMzU3LDMxOTM0LDMyMTQyLDMzMzUxLDM1MzMwLDM1NTYyLDM1OTk4LDM3MTY1LDM3MTk0LDM3MzM2LDM3NDc4LDM3NTgwLDM3NjY0LDM4NjYyLDM4NzQyLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDM4NzQ4LDM4OTE0LDQwNzE4LDIxMDQ2LDIxMTM3LDIxODg0LDIyNTY0LDI0MDkzLDI0MzUxLDI0NzE2LDI1NTUyLDI2Nzk5LDI4NjM5LDMxMDg1LDMxNTMyLDMzMjI5LDM0MjM0LDM1MDY5LDM1NTc2LDM2NDIwLDM3MjYxLDM4NTAwLDM4NTU1LDM4NzE3LDM4OTg4LDQwNzc4LDIwNDMwLDIwODA2LDIwOTM5LDIxMTYxLDIyMDY2LDI0MzQwLDI0NDI3LDI1NTE0LDI1ODA1LDI2MDg5LDI2MTc3LDI2MzYyLDI2MzYxLDI2Mzk3LDI2NzgxLDI2ODM5LDI3MTMzLDI4NDM3LDI4NTI2LDI5MDMxLDI5MTU3LDI5MjI2LDI5ODY2LDMwNTIyLDMxMDYyLDMxMDY2LDMxMTk5LDMxMjY0LDMxMzgxLDMxODk1LDMxOTY3LDMyMDY4LDMyMzY4LDMyOTAzLDM0Mjk5LDM0NDY4LDM1NDEyLDM1NTE5LDM2MjQ5LDM2NDgxLDM2ODk2LDM2OTczLDM3MzQ3LDM4NDU5LDM4NjEzLDQwMTY1LDI2MDYzLDMxNzUxLDM2Mjc1LDM3ODI3LDIzMzg0LDIzNTYyLDIxMzMwLDI1MzA1LDI5NDY5LDIwNTE5LDIzNDQ3LDI0NDc4LDI0NzUyLDI0OTM5LDI2ODM3LDI4MTIxLDI5NzQyLDMxMjc4LDMyMDY2LDMyMTU2LDMyMzA1LDMzMTMxLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDM2Mzk0LDM2NDA1LDM3NzU4LDM3OTEyLDIwMzA0LDIyMzUyLDI0MDM4LDI0MjMxLDI1Mzg3LDMyNjE4LDIwMDI3LDIwMzAzLDIwMzY3LDIwNTcwLDIzMDA1LDMyOTY0LDIxNjEwLDIxNjA4LDIyMDE0LDIyODYzLDIzNDQ5LDI0MDMwLDI0MjgyLDI2MjA1LDI2NDE3LDI2NjA5LDI2NjY2LDI3ODgwLDI3OTU0LDI4MjM0LDI4NTU3LDI4ODU1LDI5NjY0LDMwMDg3LDMxODIwLDMyMDAyLDMyMDQ0LDMyMTYyLDMzMzExLDM0NTIzLDM1Mzg3LDM1NDYxLDM2MjA4LDM2NDkwLDM2NjU5LDM2OTEzLDM3MTk4LDM3MjAyLDM3OTU2LDM5Mzc2LDMxNDgxLDMxOTA5LDIwNDI2LDIwNzM3LDIwOTM0LDIyNDcyLDIzNTM1LDIzODAzLDI2MjAxLDI3MTk3LDI3OTk0LDI4MzEwLDI4NjUyLDI4OTQwLDMwMDYzLDMxNDU5LDM0ODUwLDM2ODk3LDM2OTgxLDM4NjAzLDM5NDIzLDMzNTM3LDIwMDEzLDIwMjEwLDM0ODg2LDM3MzI1LDIxMzczLDI3MzU1LDI2OTg3LDI3NzEzLDMzOTE0LDIyNjg2LDI0OTc0LDI2MzY2LDI1MzI3LDI4ODkzLDI5OTY5LDMwMTUxLDMyMzM4LDMzOTc2LDM1NjU3LDM2MTA0LDIwMDQzLDIxNDgyLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDIxNjc1LDIyMzIwLDIyMzM2LDI0NTM1LDI1MzQ1LDI1MzUxLDI1NzExLDI1OTAzLDI2MDg4LDI2MjM0LDI2NTI1LDI2NTQ3LDI3NDkwLDI3NzQ0LDI3ODAyLDI4NDYwLDMwNjkzLDMwNzU3LDMxMDQ5LDMxMDYzLDMyMDI1LDMyOTMwLDMzMDI2LDMzMjY3LDMzNDM3LDMzNDYzLDM0NTg0LDM1NDY4LDYzOTk2LDM2MTAwLDM2Mjg2LDM2OTc4LDMwNDUyLDMxMjU3LDMxMjg3LDMyMzQwLDMyODg3LDIxNzY3LDIxOTcyLDIyNjQ1LDI1MzkxLDI1NjM0LDI2MTg1LDI2MTg3LDI2NzMzLDI3MDM1LDI3NTI0LDI3OTQxLDI4MzM3LDI5NjQ1LDI5ODAwLDI5ODU3LDMwMDQzLDMwMTM3LDMwNDMzLDMwNDk0LDMwNjAzLDMxMjA2LDMyMjY1LDMyMjg1LDMzMjc1LDM0MDk1LDM0OTY3LDM1Mzg2LDM2MDQ5LDM2NTg3LDM2Nzg0LDM2OTE0LDM3ODA1LDM4NDk5LDM4NTE1LDM4NjYzLDIwMzU2LDIxNDg5LDIzMDE4LDIzMjQxLDI0MDg5LDI2NzAyLDI5ODk0LDMwMTQyLDMxMjA5LDMxMzc4LDMzMTg3LDM0NTQxLDM2MDc0LDM2MzAwLDM2ODQ1LDI2MDE1LDI2Mzg5LDYzOTk3LDIyNTE5LDI4NTAzLDMyMjIxLDM2NjU1LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDM3ODc4LDM4NTk4LDI0NTAxLDI1MDc0LDI4NTQ4LDE5OTg4LDIwMzc2LDIwNTExLDIxNDQ5LDIxOTgzLDIzOTE5LDI0MDQ2LDI3NDI1LDI3NDkyLDMwOTIzLDMxNjQyLDYzOTk4LDM2NDI1LDM2NTU0LDM2OTc0LDI1NDE3LDI1NjYyLDMwNTI4LDMxMzY0LDM3Njc5LDM4MDE1LDQwODEwLDI1Nzc2LDI4NTkxLDI5MTU4LDI5ODY0LDI5OTE0LDMxNDI4LDMxNzYyLDMyMzg2LDMxOTIyLDMyNDA4LDM1NzM4LDM2MTA2LDM4MDEzLDM5MTg0LDM5MjQ0LDIxMDQ5LDIzNTE5LDI1ODMwLDI2NDEzLDMyMDQ2LDIwNzE3LDIxNDQzLDIyNjQ5LDI0OTIwLDI0OTIxLDI1MDgyLDI2MDI4LDMxNDQ5LDM1NzMwLDM1NzM0LDIwNDg5LDIwNTEzLDIxMTA5LDIxODA5LDIzMTAwLDI0Mjg4LDI0NDMyLDI0ODg0LDI1OTUwLDI2MTI0LDI2MTY2LDI2Mjc0LDI3MDg1LDI4MzU2LDI4NDY2LDI5NDYyLDMwMjQxLDMxMzc5LDMzMDgxLDMzMzY5LDMzNzUwLDMzOTgwLDIwNjYxLDIyNTEyLDIzNDg4LDIzNTI4LDI0NDI1LDI1NTA1LDMwNzU4LDMyMTgxLDMzNzU2LDM0MDgxLDM3MzE5LDM3MzY1LDIwODc0LDI2NjEzLDMxNTc0LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDM2MDEyLDIwOTMyLDIyOTcxLDI0NzY1LDM0Mzg5LDIwNTA4LDYzOTk5LDIxMDc2LDIzNjEwLDI0OTU3LDI1MTE0LDI1Mjk5LDI1ODQyLDI2MDIxLDI4MzY0LDMwMjQwLDMzMDM0LDM2NDQ4LDM4NDk1LDM4NTg3LDIwMTkxLDIxMzE1LDIxOTEyLDIyODI1LDI0MDI5LDI1Nzk3LDI3ODQ5LDI4MTU0LDI5NTg4LDMxMzU5LDMzMzA3LDM0MjE0LDM2MDY4LDM2MzY4LDM2OTgzLDM3MzUxLDM4MzY5LDM4NDMzLDM4ODU0LDIwOTg0LDIxNzQ2LDIxODk0LDI0NTA1LDI1NzY0LDI4NTUyLDMyMTgwLDM2NjM5LDM2Njg1LDM3OTQxLDIwNjgxLDIzNTc0LDI3ODM4LDI4MTU1LDI5OTc5LDMwNjUxLDMxODA1LDMxODQ0LDM1NDQ5LDM1NTIyLDIyNTU4LDIyOTc0LDI0MDg2LDI1NDYzLDI5MjY2LDMwMDkwLDMwNTcxLDM1NTQ4LDM2MDI4LDM2NjI2LDI0MzA3LDI2MjI4LDI4MTUyLDMyODkzLDMzNzI5LDM1NTMxLDM4NzM3LDM5ODk0LDY0MDAwLDIxMDU5LDI2MzY3LDI4MDUzLDI4Mzk5LDMyMjI0LDM1NTU4LDM2OTEwLDM2OTU4LDM5NjM2LDIxMDIxLDIxMTE5LDIxNzM2LDI0OTgwLDI1MjIwLDI1MzA3LDI2Nzg2LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDI2ODk4LDI2OTcwLDI3MTg5LDI4ODE4LDI4OTY2LDMwODEzLDMwOTc3LDMwOTkwLDMxMTg2LDMxMjQ1LDMyOTE4LDMzNDAwLDMzNDkzLDMzNjA5LDM0MTIxLDM1OTcwLDM2MjI5LDM3MjE4LDM3MjU5LDM3Mjk0LDIwNDE5LDIyMjI1LDI5MTY1LDMwNjc5LDM0NTYwLDM1MzIwLDIzNTQ0LDI0NTM0LDI2NDQ5LDM3MDMyLDIxNDc0LDIyNjE4LDIzNTQxLDI0NzQwLDI0OTYxLDI1Njk2LDMyMzE3LDMyODgwLDM0MDg1LDM3NTA3LDI1Nzc0LDIwNjUyLDIzODI4LDI2MzY4LDIyNjg0LDI1Mjc3LDI1NTEyLDI2ODk0LDI3MDAwLDI3MTY2LDI4MjY3LDMwMzk0LDMxMTc5LDMzNDY3LDMzODMzLDM1NTM1LDM2MjY0LDM2ODYxLDM3MTM4LDM3MTk1LDM3Mjc2LDM3NjQ4LDM3NjU2LDM3Nzg2LDM4NjE5LDM5NDc4LDM5OTQ5LDE5OTg1LDMwMDQ0LDMxMDY5LDMxNDgyLDMxNTY5LDMxNjg5LDMyMzAyLDMzOTg4LDM2NDQxLDM2NDY4LDM2NjAwLDM2ODgwLDI2MTQ5LDI2OTQzLDI5NzYzLDIwOTg2LDI2NDE0LDQwNjY4LDIwODA1LDI0NTQ0LDI3Nzk4LDM0ODAyLDM0OTA5LDM0OTM1LDI0NzU2LDMzMjA1LDMzNzk1LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDM2MTAxLDIxNDYyLDIxNTYxLDIyMDY4LDIzMDk0LDIzNjAxLDI4ODEwLDMyNzM2LDMyODU4LDMzMDMwLDMzMjYxLDM2MjU5LDM3MjU3LDM5NTE5LDQwNDM0LDIwNTk2LDIwMTY0LDIxNDA4LDI0ODI3LDI4MjA0LDIzNjUyLDIwMzYwLDIwNTE2LDIxOTg4LDIzNzY5LDI0MTU5LDI0Njc3LDI2NzcyLDI3ODM1LDI4MTAwLDI5MTE4LDMwMTY0LDMwMTk2LDMwMzA1LDMxMjU4LDMxMzA1LDMyMTk5LDMyMjUxLDMyNjIyLDMzMjY4LDM0NDczLDM2NjM2LDM4NjAxLDM5MzQ3LDQwNzg2LDIxMDYzLDIxMTg5LDM5MTQ5LDM1MjQyLDE5OTcxLDI2NTc4LDI4NDIyLDIwNDA1LDIzNTIyLDI2NTE3LDI3Nzg0LDI4MDI0LDI5NzIzLDMwNzU5LDM3MzQxLDM3NzU2LDM0NzU2LDMxMjA0LDMxMjgxLDI0NTU1LDIwMTgyLDIxNjY4LDIxODIyLDIyNzAyLDIyOTQ5LDI0ODE2LDI1MTcxLDI1MzAyLDI2NDIyLDI2OTY1LDMzMzMzLDM4NDY0LDM5MzQ1LDM5Mzg5LDIwNTI0LDIxMzMxLDIxODI4LDIyMzk2LDY0MDAxLDI1MTc2LDY0MDAyLDI1ODI2LDI2MjE5LDI2NTg5LDI4NjA5LDI4NjU1LDI5NzMwLDI5NzUyLDM1MzUxLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDM3OTQ0LDIxNTg1LDIyMDIyLDIyMzc0LDI0MzkyLDI0OTg2LDI3NDcwLDI4NzYwLDI4ODQ1LDMyMTg3LDM1NDc3LDIyODkwLDMzMDY3LDI1NTA2LDMwNDcyLDMyODI5LDM2MDEwLDIyNjEyLDI1NjQ1LDI3MDY3LDIzNDQ1LDI0MDgxLDI4MjcxLDY0MDAzLDM0MTUzLDIwODEyLDIxNDg4LDIyODI2LDI0NjA4LDI0OTA3LDI3NTI2LDI3NzYwLDI3ODg4LDMxNTE4LDMyOTc0LDMzNDkyLDM2Mjk0LDM3MDQwLDM5MDg5LDY0MDA0LDI1Nzk5LDI4NTgwLDI1NzQ1LDI1ODYwLDIwODE0LDIxNTIwLDIyMzAzLDM1MzQyLDI0OTI3LDI2NzQyLDY0MDA1LDMwMTcxLDMxNTcwLDMyMTEzLDM2ODkwLDIyNTM0LDI3MDg0LDMzMTUxLDM1MTE0LDM2ODY0LDM4OTY5LDIwNjAwLDIyODcxLDIyOTU2LDI1MjM3LDM2ODc5LDM5NzIyLDI0OTI1LDI5MzA1LDM4MzU4LDIyMzY5LDIzMTEwLDI0MDUyLDI1MjI2LDI1NzczLDI1ODUwLDI2NDg3LDI3ODc0LDI3OTY2LDI5MjI4LDI5NzUwLDMwNzcyLDMyNjMxLDMzNDUzLDM2MzE1LDM4OTM1LDIxMDI4LDIyMzM4LDI2NDk1LDI5MjU2LDI5OTIzLDM2MDA5LDM2Nzc0LDM3MzkzLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDM4NDQyLDIwODQzLDIxNDg1LDI1NDIwLDIwMzI5LDIxNzY0LDI0NzI2LDI1OTQzLDI3ODAzLDI4MDMxLDI5MjYwLDI5NDM3LDMxMjU1LDM1MjA3LDM1OTk3LDI0NDI5LDI4NTU4LDI4OTIxLDMzMTkyLDI0ODQ2LDIwNDE1LDIwNTU5LDI1MTUzLDI5MjU1LDMxNjg3LDMyMjMyLDMyNzQ1LDM2OTQxLDM4ODI5LDM5NDQ5LDM2MDIyLDIyMzc4LDI0MTc5LDI2NTQ0LDMzODA1LDM1NDEzLDIxNTM2LDIzMzE4LDI0MTYzLDI0MjkwLDI0MzMwLDI1OTg3LDMyOTU0LDM0MTA5LDM4MjgxLDM4NDkxLDIwMjk2LDIxMjUzLDIxMjYxLDIxMjYzLDIxNjM4LDIxNzU0LDIyMjc1LDI0MDY3LDI0NTk4LDI1MjQzLDI1MjY1LDI1NDI5LDY0MDA2LDI3ODczLDI4MDA2LDMwMTI5LDMwNzcwLDMyOTkwLDMzMDcxLDMzNTAyLDMzODg5LDMzOTcwLDM0OTU3LDM1MDkwLDM2ODc1LDM3NjEwLDM5MTY1LDM5ODI1LDI0MTMzLDI2MjkyLDI2MzMzLDI4Njg5LDI5MTkwLDY0MDA3LDIwNDY5LDIxMTE3LDI0NDI2LDI0OTE1LDI2NDUxLDI3MTYxLDI4NDE4LDI5OTIyLDMxMDgwLDM0OTIwLDM1OTYxLDM5MTExLDM5MTA4LDM5NDkxLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDIxNjk3LDMxMjYzLDI2OTYzLDM1NTc1LDM1OTE0LDM5MDgwLDM5MzQyLDI0NDQ0LDI1MjU5LDMwMTMwLDMwMzgyLDM0OTg3LDM2OTkxLDM4NDY2LDIxMzA1LDI0MzgwLDI0NTE3LDI3ODUyLDI5NjQ0LDMwMDUwLDMwMDkxLDMxNTU4LDMzNTM0LDM5MzI1LDIwMDQ3LDM2OTI0LDE5OTc5LDIwMzA5LDIxNDE0LDIyNzk5LDI0MjY0LDI2MTYwLDI3ODI3LDI5NzgxLDMzNjU1LDM0NjYyLDM2MDMyLDM2OTQ0LDM4Njg2LDM5OTU3LDIyNzM3LDIzNDE2LDM0Mzg0LDM1NjA0LDQwMzcyLDIzNTA2LDI0NjgwLDI0NzE3LDI2MDk3LDI3NzM1LDI4NDUwLDI4NTc5LDI4Njk4LDMyNTk3LDMyNzUyLDM4Mjg5LDM4MjkwLDM4NDgwLDM4ODY3LDIxMTA2LDM2Njc2LDIwOTg5LDIxNTQ3LDIxNjg4LDIxODU5LDIxODk4LDI3MzIzLDI4MDg1LDMyMjE2LDMzMzgyLDM3NTMyLDM4NTE5LDQwNTY5LDIxNTEyLDIxNzA0LDMwNDE4LDM0NTMyLDM4MzA4LDM4MzU2LDM4NDkyLDIwMTMwLDIwMjMzLDIzMDIyLDIzMjcwLDI0MDU1LDI0NjU4LDI1MjM5LDI2NDc3LDI2Njg5LDI3NzgyLDI4MjA3LDMyNTY4LDMyOTIzLDMzMzIyLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDY0MDA4LDY0MDA5LDM4OTE3LDIwMTMzLDIwNTY1LDIxNjgzLDIyNDE5LDIyODc0LDIzNDAxLDIzNDc1LDI1MDMyLDI2OTk5LDI4MDIzLDI4NzA3LDM0ODA5LDM1Mjk5LDM1NDQyLDM1NTU5LDM2OTk0LDM5NDA1LDM5NjA4LDIxMTgyLDI2NjgwLDIwNTAyLDI0MTg0LDI2NDQ3LDMzNjA3LDM0ODkyLDIwMTM5LDIxNTIxLDIyMTkwLDI5NjcwLDM3MTQxLDM4OTExLDM5MTc3LDM5MjU1LDM5MzIxLDIyMDk5LDIyNjg3LDM0Mzk1LDM1Mzc3LDI1MDEwLDI3MzgyLDI5NTYzLDM2NTYyLDI3NDYzLDM4NTcwLDM5NTExLDIyODY5LDI5MTg0LDM2MjAzLDM4NzYxLDIwNDM2LDIzNzk2LDI0MzU4LDI1MDgwLDI2MjAzLDI3ODgzLDI4ODQzLDI5NTcyLDI5NjI1LDI5Njk0LDMwNTA1LDMwNTQxLDMyMDY3LDMyMDk4LDMyMjkxLDMzMzM1LDM0ODk4LDY0MDEwLDM2MDY2LDM3NDQ5LDM5MDIzLDIzMzc3LDMxMzQ4LDM0ODgwLDM4OTEzLDIzMjQ0LDIwNDQ4LDIxMzMyLDIyODQ2LDIzODA1LDI1NDA2LDI4MDI1LDI5NDMzLDMzMDI5LDMzMDMxLDMzNjk4LDM3NTgzLDM4OTYwLDIwMTM2LDIwODA0LDIxMDA5LDIyNDExLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDI0NDE4LDI3ODQyLDI4MzY2LDI4Njc3LDI4NzUyLDI4ODQ3LDI5MDc0LDI5NjczLDI5ODAxLDMzNjEwLDM0NzIyLDM0OTEzLDM2ODcyLDM3MDI2LDM3Nzk1LDM5MzM2LDIwODQ2LDI0NDA3LDI0ODAwLDI0OTM1LDI2MjkxLDM0MTM3LDM2NDI2LDM3Mjk1LDM4Nzk1LDIwMDQ2LDIwMTE0LDIxNjI4LDIyNzQxLDIyNzc4LDIyOTA5LDIzNzMzLDI0MzU5LDI1MTQyLDI1MTYwLDI2MTIyLDI2MjE1LDI3NjI3LDI4MDA5LDI4MTExLDI4MjQ2LDI4NDA4LDI4NTY0LDI4NjQwLDI4NjQ5LDI4NzY1LDI5MzkyLDI5NzMzLDI5Nzg2LDI5OTIwLDMwMzU1LDMxMDY4LDMxOTQ2LDMyMjg2LDMyOTkzLDMzNDQ2LDMzODk5LDMzOTgzLDM0MzgyLDM0Mzk5LDM0Njc2LDM1NzAzLDM1OTQ2LDM3ODA0LDM4OTEyLDM5MDEzLDI0Nzg1LDI1MTEwLDM3MjM5LDIzMTMwLDI2MTI3LDI4MTUxLDI4MjIyLDI5NzU5LDM5NzQ2LDI0NTczLDI0Nzk0LDMxNTAzLDIxNzAwLDI0MzQ0LDI3NzQyLDI3ODU5LDI3OTQ2LDI4ODg4LDMyMDA1LDM0NDI1LDM1MzQwLDQwMjUxLDIxMjcwLDIxNjQ0LDIzMzAxLDI3MTk0LDI4Nzc5LDMwMDY5LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDMxMTE3LDMxMTY2LDMzNDU3LDMzNzc1LDM1NDQxLDM1NjQ5LDM2MDA4LDM4NzcyLDY0MDExLDI1ODQ0LDI1ODk5LDMwOTA2LDMwOTA3LDMxMzM5LDIwMDI0LDIxOTE0LDIyODY0LDIzNDYyLDI0MTg3LDI0NzM5LDI1NTYzLDI3NDg5LDI2MjEzLDI2NzA3LDI4MTg1LDI5MDI5LDI5ODcyLDMyMDA4LDM2OTk2LDM5NTI5LDM5OTczLDI3OTYzLDI4MzY5LDI5NTAyLDM1OTA1LDM4MzQ2LDIwOTc2LDI0MTQwLDI0NDg4LDI0NjUzLDI0ODIyLDI0ODgwLDI0OTA4LDI2MTc5LDI2MTgwLDI3MDQ1LDI3ODQxLDI4MjU1LDI4MzYxLDI4NTE0LDI5MDA0LDI5ODUyLDMwMzQzLDMxNjgxLDMxNzgzLDMzNjE4LDM0NjQ3LDM2OTQ1LDM4NTQxLDQwNjQzLDIxMjk1LDIyMjM4LDI0MzE1LDI0NDU4LDI0Njc0LDI0NzI0LDI1MDc5LDI2MjE0LDI2MzcxLDI3MjkyLDI4MTQyLDI4NTkwLDI4Nzg0LDI5NTQ2LDMyMzYyLDMzMjE0LDMzNTg4LDM0NTE2LDM1NDk2LDM2MDM2LDIxMTIzLDI5NTU0LDIzNDQ2LDI3MjQzLDM3ODkyLDIxNzQyLDIyMTUwLDIzMzg5LDI1OTI4LDI1OTg5LDI2MzEzLDI2NzgzLDI4MDQ1LDI4MTAyLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDI5MjQzLDMyOTQ4LDM3MjM3LDM5NTAxLDIwMzk5LDIwNTA1LDIxNDAyLDIxNTE4LDIxNTY0LDIxODk3LDIxOTU3LDI0MTI3LDI0NDYwLDI2NDI5LDI5MDMwLDI5NjYxLDM2ODY5LDIxMjExLDIxMjM1LDIyNjI4LDIyNzM0LDI4OTMyLDI5MDcxLDI5MTc5LDM0MjI0LDM1MzQ3LDI2MjQ4LDM0MjE2LDIxOTI3LDI2MjQ0LDI5MDAyLDMzODQxLDIxMzIxLDIxOTEzLDI3NTg1LDI0NDA5LDI0NTA5LDI1NTgyLDI2MjQ5LDI4OTk5LDM1NTY5LDM2NjM3LDQwNjM4LDIwMjQxLDI1NjU4LDI4ODc1LDMwMDU0LDM0NDA3LDI0Njc2LDM1NjYyLDQwNDQwLDIwODA3LDIwOTgyLDIxMjU2LDI3OTU4LDMzMDE2LDQwNjU3LDI2MTMzLDI3NDI3LDI4ODI0LDMwMTY1LDIxNTA3LDIzNjczLDMyMDA3LDM1MzUwLDI3NDI0LDI3NDUzLDI3NDYyLDIxNTYwLDI0Njg4LDI3OTY1LDMyNzI1LDMzMjg4LDIwNjk0LDIwOTU4LDIxOTE2LDIyMTIzLDIyMjIxLDIzMDIwLDIzMzA1LDI0MDc2LDI0OTg1LDI0OTg0LDI1MTM3LDI2MjA2LDI2MzQyLDI5MDgxLDI5MTEzLDI5MTE0LDI5MzUxLDMxMTQzLDMxMjMyLDMyNjkwLDM1NDQwLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGxdLFxuICBcImdiMTgwMzBcIjpbMTk5NzAsMTk5NzIsMTk5NzMsMTk5NzQsMTk5ODMsMTk5ODYsMTk5OTEsMTk5OTksMjAwMDAsMjAwMDEsMjAwMDMsMjAwMDYsMjAwMDksMjAwMTQsMjAwMTUsMjAwMTcsMjAwMTksMjAwMjEsMjAwMjMsMjAwMjgsMjAwMzIsMjAwMzMsMjAwMzQsMjAwMzYsMjAwMzgsMjAwNDIsMjAwNDksMjAwNTMsMjAwNTUsMjAwNTgsMjAwNTksMjAwNjYsMjAwNjcsMjAwNjgsMjAwNjksMjAwNzEsMjAwNzIsMjAwNzQsMjAwNzUsMjAwNzYsMjAwNzcsMjAwNzgsMjAwNzksMjAwODIsMjAwODQsMjAwODUsMjAwODYsMjAwODcsMjAwODgsMjAwODksMjAwOTAsMjAwOTEsMjAwOTIsMjAwOTMsMjAwOTUsMjAwOTYsMjAwOTcsMjAwOTgsMjAwOTksMjAxMDAsMjAxMDEsMjAxMDMsMjAxMDYsMjAxMTIsMjAxMTgsMjAxMTksMjAxMjEsMjAxMjQsMjAxMjUsMjAxMjYsMjAxMzEsMjAxMzgsMjAxNDMsMjAxNDQsMjAxNDUsMjAxNDgsMjAxNTAsMjAxNTEsMjAxNTIsMjAxNTMsMjAxNTYsMjAxNTcsMjAxNTgsMjAxNjgsMjAxNzIsMjAxNzUsMjAxNzYsMjAxNzgsMjAxODYsMjAxODcsMjAxODgsMjAxOTIsMjAxOTQsMjAxOTgsMjAxOTksMjAyMDEsMjAyMDUsMjAyMDYsMjAyMDcsMjAyMDksMjAyMTIsMjAyMTYsMjAyMTcsMjAyMTgsMjAyMjAsMjAyMjIsMjAyMjQsMjAyMjYsMjAyMjcsMjAyMjgsMjAyMjksMjAyMzAsMjAyMzEsMjAyMzIsMjAyMzUsMjAyMzYsMjAyNDIsMjAyNDMsMjAyNDQsMjAyNDUsMjAyNDYsMjAyNTIsMjAyNTMsMjAyNTcsMjAyNTksMjAyNjQsMjAyNjUsMjAyNjgsMjAyNjksMjAyNzAsMjAyNzMsMjAyNzUsMjAyNzcsMjAyNzksMjAyODEsMjAyODMsMjAyODYsMjAyODcsMjAyODgsMjAyODksMjAyOTAsMjAyOTIsMjAyOTMsMjAyOTUsMjAyOTYsMjAyOTcsMjAyOTgsMjAyOTksMjAzMDAsMjAzMDYsMjAzMDgsMjAzMTAsMjAzMjEsMjAzMjIsMjAzMjYsMjAzMjgsMjAzMzAsMjAzMzEsMjAzMzMsMjAzMzQsMjAzMzcsMjAzMzgsMjAzNDEsMjAzNDMsMjAzNDQsMjAzNDUsMjAzNDYsMjAzNDksMjAzNTIsMjAzNTMsMjAzNTQsMjAzNTcsMjAzNTgsMjAzNTksMjAzNjIsMjAzNjQsMjAzNjYsMjAzNjgsMjAzNzAsMjAzNzEsMjAzNzMsMjAzNzQsMjAzNzYsMjAzNzcsMjAzNzgsMjAzODAsMjAzODIsMjAzODMsMjAzODUsMjAzODYsMjAzODgsMjAzOTUsMjAzOTcsMjA0MDAsMjA0MDEsMjA0MDIsMjA0MDMsMjA0MDQsMjA0MDYsMjA0MDcsMjA0MDgsMjA0MDksMjA0MTAsMjA0MTEsMjA0MTIsMjA0MTMsMjA0MTQsMjA0MTYsMjA0MTcsMjA0MTgsMjA0MjIsMjA0MjMsMjA0MjQsMjA0MjUsMjA0MjcsMjA0MjgsMjA0MjksMjA0MzQsMjA0MzUsMjA0MzYsMjA0MzcsMjA0MzgsMjA0NDEsMjA0NDMsMjA0NDgsMjA0NTAsMjA0NTIsMjA0NTMsMjA0NTUsMjA0NTksMjA0NjAsMjA0NjQsMjA0NjYsMjA0NjgsMjA0NjksMjA0NzAsMjA0NzEsMjA0NzMsMjA0NzUsMjA0NzYsMjA0NzcsMjA0NzksMjA0ODAsMjA0ODEsMjA0ODIsMjA0ODMsMjA0ODQsMjA0ODUsMjA0ODYsMjA0ODcsMjA0ODgsMjA0ODksMjA0OTAsMjA0OTEsMjA0OTQsMjA0OTYsMjA0OTcsMjA0OTksMjA1MDEsMjA1MDIsMjA1MDMsMjA1MDcsMjA1MDksMjA1MTAsMjA1MTIsMjA1MTQsMjA1MTUsMjA1MTYsMjA1MTksMjA1MjMsMjA1MjcsMjA1MjgsMjA1MjksMjA1MzAsMjA1MzEsMjA1MzIsMjA1MzMsMjA1MzQsMjA1MzUsMjA1MzYsMjA1MzcsMjA1MzksMjA1NDEsMjA1NDMsMjA1NDQsMjA1NDUsMjA1NDYsMjA1NDgsMjA1NDksMjA1NTAsMjA1NTMsMjA1NTQsMjA1NTUsMjA1NTcsMjA1NjAsMjA1NjEsMjA1NjIsMjA1NjMsMjA1NjQsMjA1NjYsMjA1NjcsMjA1NjgsMjA1NjksMjA1NzEsMjA1NzMsMjA1NzQsMjA1NzUsMjA1NzYsMjA1NzcsMjA1NzgsMjA1NzksMjA1ODAsMjA1ODIsMjA1ODMsMjA1ODQsMjA1ODUsMjA1ODYsMjA1ODcsMjA1ODksMjA1OTAsMjA1OTEsMjA1OTIsMjA1OTMsMjA1OTQsMjA1OTUsMjA1OTYsMjA1OTcsMjA2MDAsMjA2MDEsMjA2MDIsMjA2MDQsMjA2MDUsMjA2MDksMjA2MTAsMjA2MTEsMjA2MTIsMjA2MTQsMjA2MTUsMjA2MTcsMjA2MTgsMjA2MTksMjA2MjAsMjA2MjIsMjA2MjMsMjA2MjQsMjA2MjUsMjA2MjYsMjA2MjcsMjA2MjgsMjA2MjksMjA2MzAsMjA2MzEsMjA2MzIsMjA2MzMsMjA2MzQsMjA2MzUsMjA2MzYsMjA2MzcsMjA2MzgsMjA2MzksMjA2NDAsMjA2NDEsMjA2NDIsMjA2NDQsMjA2NDYsMjA2NTAsMjA2NTEsMjA2NTMsMjA2NTQsMjA2NTUsMjA2NTYsMjA2NTcsMjA2NTksMjA2NjAsMjA2NjEsMjA2NjIsMjA2NjMsMjA2NjQsMjA2NjUsMjA2NjgsMjA2NjksMjA2NzAsMjA2NzEsMjA2NzIsMjA2NzMsMjA2NzQsMjA2NzUsMjA2NzYsMjA2NzcsMjA2NzgsMjA2NzksMjA2ODAsMjA2ODEsMjA2ODIsMjA2ODMsMjA2ODQsMjA2ODUsMjA2ODYsMjA2ODgsMjA2ODksMjA2OTAsMjA2OTEsMjA2OTIsMjA2OTMsMjA2OTUsMjA2OTYsMjA2OTcsMjA2OTksMjA3MDAsMjA3MDEsMjA3MDIsMjA3MDMsMjA3MDQsMjA3MDUsMjA3MDYsMjA3MDcsMjA3MDgsMjA3MDksMjA3MTIsMjA3MTMsMjA3MTQsMjA3MTUsMjA3MTksMjA3MjAsMjA3MjEsMjA3MjIsMjA3MjQsMjA3MjYsMjA3MjcsMjA3MjgsMjA3MjksMjA3MzAsMjA3MzIsMjA3MzMsMjA3MzQsMjA3MzUsMjA3MzYsMjA3MzcsMjA3MzgsMjA3MzksMjA3NDAsMjA3NDEsMjA3NDQsMjA3NDUsMjA3NDYsMjA3NDgsMjA3NDksMjA3NTAsMjA3NTEsMjA3NTIsMjA3NTMsMjA3NTUsMjA3NTYsMjA3NTcsMjA3NTgsMjA3NTksMjA3NjAsMjA3NjEsMjA3NjIsMjA3NjMsMjA3NjQsMjA3NjUsMjA3NjYsMjA3NjcsMjA3NjgsMjA3NzAsMjA3NzEsMjA3NzIsMjA3NzMsMjA3NzQsMjA3NzUsMjA3NzYsMjA3NzcsMjA3NzgsMjA3NzksMjA3ODAsMjA3ODEsMjA3ODIsMjA3ODMsMjA3ODQsMjA3ODUsMjA3ODYsMjA3ODcsMjA3ODgsMjA3ODksMjA3OTAsMjA3OTEsMjA3OTIsMjA3OTMsMjA3OTQsMjA3OTUsMjA3OTYsMjA3OTcsMjA3OTgsMjA4MDIsMjA4MDcsMjA4MTAsMjA4MTIsMjA4MTQsMjA4MTUsMjA4MTYsMjA4MTgsMjA4MTksMjA4MjMsMjA4MjQsMjA4MjUsMjA4MjcsMjA4MjksMjA4MzAsMjA4MzEsMjA4MzIsMjA4MzMsMjA4MzUsMjA4MzYsMjA4MzgsMjA4MzksMjA4NDEsMjA4NDIsMjA4NDcsMjA4NTAsMjA4NTgsMjA4NjIsMjA4NjMsMjA4NjcsMjA4NjgsMjA4NzAsMjA4NzEsMjA4NzQsMjA4NzUsMjA4NzgsMjA4NzksMjA4ODAsMjA4ODEsMjA4ODMsMjA4ODQsMjA4ODgsMjA4OTAsMjA4OTMsMjA4OTQsMjA4OTUsMjA4OTcsMjA4OTksMjA5MDIsMjA5MDMsMjA5MDQsMjA5MDUsMjA5MDYsMjA5MDksMjA5MTAsMjA5MTYsMjA5MjAsMjA5MjEsMjA5MjIsMjA5MjYsMjA5MjcsMjA5MjksMjA5MzAsMjA5MzEsMjA5MzMsMjA5MzYsMjA5MzgsMjA5NDEsMjA5NDIsMjA5NDQsMjA5NDYsMjA5NDcsMjA5NDgsMjA5NDksMjA5NTAsMjA5NTEsMjA5NTIsMjA5NTMsMjA5NTQsMjA5NTYsMjA5NTgsMjA5NTksMjA5NjIsMjA5NjMsMjA5NjUsMjA5NjYsMjA5NjcsMjA5NjgsMjA5NjksMjA5NzAsMjA5NzIsMjA5NzQsMjA5NzcsMjA5NzgsMjA5ODAsMjA5ODMsMjA5OTAsMjA5OTYsMjA5OTcsMjEwMDEsMjEwMDMsMjEwMDQsMjEwMDcsMjEwMDgsMjEwMTEsMjEwMTIsMjEwMTMsMjEwMjAsMjEwMjIsMjEwMjMsMjEwMjUsMjEwMjYsMjEwMjcsMjEwMjksMjEwMzAsMjEwMzEsMjEwMzQsMjEwMzYsMjEwMzksMjEwNDEsMjEwNDIsMjEwNDQsMjEwNDUsMjEwNTIsMjEwNTQsMjEwNjAsMjEwNjEsMjEwNjIsMjEwNjMsMjEwNjQsMjEwNjUsMjEwNjcsMjEwNzAsMjEwNzEsMjEwNzQsMjEwNzUsMjEwNzcsMjEwNzksMjEwODAsMjEwODEsMjEwODIsMjEwODMsMjEwODUsMjEwODcsMjEwODgsMjEwOTAsMjEwOTEsMjEwOTIsMjEwOTQsMjEwOTYsMjEwOTksMjExMDAsMjExMDEsMjExMDIsMjExMDQsMjExMDUsMjExMDcsMjExMDgsMjExMDksMjExMTAsMjExMTEsMjExMTIsMjExMTMsMjExMTQsMjExMTUsMjExMTYsMjExMTgsMjExMjAsMjExMjMsMjExMjQsMjExMjUsMjExMjYsMjExMjcsMjExMjksMjExMzAsMjExMzEsMjExMzIsMjExMzMsMjExMzQsMjExMzUsMjExMzcsMjExMzgsMjExNDAsMjExNDEsMjExNDIsMjExNDMsMjExNDQsMjExNDUsMjExNDYsMjExNDgsMjExNTYsMjExNTcsMjExNTgsMjExNTksMjExNjYsMjExNjcsMjExNjgsMjExNzIsMjExNzMsMjExNzQsMjExNzUsMjExNzYsMjExNzcsMjExNzgsMjExNzksMjExODAsMjExODEsMjExODQsMjExODUsMjExODYsMjExODgsMjExODksMjExOTAsMjExOTIsMjExOTQsMjExOTYsMjExOTcsMjExOTgsMjExOTksMjEyMDEsMjEyMDMsMjEyMDQsMjEyMDUsMjEyMDcsMjEyMDksMjEyMTAsMjEyMTEsMjEyMTIsMjEyMTMsMjEyMTQsMjEyMTYsMjEyMTcsMjEyMTgsMjEyMTksMjEyMjEsMjEyMjIsMjEyMjMsMjEyMjQsMjEyMjUsMjEyMjYsMjEyMjcsMjEyMjgsMjEyMjksMjEyMzAsMjEyMzEsMjEyMzMsMjEyMzQsMjEyMzUsMjEyMzYsMjEyMzcsMjEyMzgsMjEyMzksMjEyNDAsMjEyNDMsMjEyNDQsMjEyNDUsMjEyNDksMjEyNTAsMjEyNTEsMjEyNTIsMjEyNTUsMjEyNTcsMjEyNTgsMjEyNTksMjEyNjAsMjEyNjIsMjEyNjUsMjEyNjYsMjEyNjcsMjEyNjgsMjEyNzIsMjEyNzUsMjEyNzYsMjEyNzgsMjEyNzksMjEyODIsMjEyODQsMjEyODUsMjEyODcsMjEyODgsMjEyODksMjEyOTEsMjEyOTIsMjEyOTMsMjEyOTUsMjEyOTYsMjEyOTcsMjEyOTgsMjEyOTksMjEzMDAsMjEzMDEsMjEzMDIsMjEzMDMsMjEzMDQsMjEzMDgsMjEzMDksMjEzMTIsMjEzMTQsMjEzMTYsMjEzMTgsMjEzMjMsMjEzMjQsMjEzMjUsMjEzMjgsMjEzMzIsMjEzMzYsMjEzMzcsMjEzMzksMjEzNDEsMjEzNDksMjEzNTIsMjEzNTQsMjEzNTYsMjEzNTcsMjEzNjIsMjEzNjYsMjEzNjksMjEzNzEsMjEzNzIsMjEzNzMsMjEzNzQsMjEzNzYsMjEzNzcsMjEzNzksMjEzODMsMjEzODQsMjEzODYsMjEzOTAsMjEzOTEsMjEzOTIsMjEzOTMsMjEzOTQsMjEzOTUsMjEzOTYsMjEzOTgsMjEzOTksMjE0MDEsMjE0MDMsMjE0MDQsMjE0MDYsMjE0MDgsMjE0MDksMjE0MTIsMjE0MTUsMjE0MTgsMjE0MTksMjE0MjAsMjE0MjEsMjE0MjMsMjE0MjQsMjE0MjUsMjE0MjYsMjE0MjcsMjE0MjgsMjE0MjksMjE0MzEsMjE0MzIsMjE0MzMsMjE0MzQsMjE0MzYsMjE0MzcsMjE0MzgsMjE0NDAsMjE0NDMsMjE0NDQsMjE0NDUsMjE0NDYsMjE0NDcsMjE0NTQsMjE0NTUsMjE0NTYsMjE0NTgsMjE0NTksMjE0NjEsMjE0NjYsMjE0NjgsMjE0NjksMjE0NzAsMjE0NzMsMjE0NzQsMjE0NzksMjE0OTIsMjE0OTgsMjE1MDIsMjE1MDMsMjE1MDQsMjE1MDYsMjE1MDksMjE1MTEsMjE1MTUsMjE1MjQsMjE1MjgsMjE1MjksMjE1MzAsMjE1MzIsMjE1MzgsMjE1NDAsMjE1NDEsMjE1NDYsMjE1NTIsMjE1NTUsMjE1NTgsMjE1NTksMjE1NjIsMjE1NjUsMjE1NjcsMjE1NjksMjE1NzAsMjE1NzIsMjE1NzMsMjE1NzUsMjE1NzcsMjE1ODAsMjE1ODEsMjE1ODIsMjE1ODMsMjE1ODUsMjE1OTQsMjE1OTcsMjE1OTgsMjE1OTksMjE2MDAsMjE2MDEsMjE2MDMsMjE2MDUsMjE2MDcsMjE2MDksMjE2MTAsMjE2MTEsMjE2MTIsMjE2MTMsMjE2MTQsMjE2MTUsMjE2MTYsMjE2MjAsMjE2MjUsMjE2MjYsMjE2MzAsMjE2MzEsMjE2MzMsMjE2MzUsMjE2MzcsMjE2MzksMjE2NDAsMjE2NDEsMjE2NDIsMjE2NDUsMjE2NDksMjE2NTEsMjE2NTUsMjE2NTYsMjE2NjAsMjE2NjIsMjE2NjMsMjE2NjQsMjE2NjUsMjE2NjYsMjE2NjksMjE2NzgsMjE2ODAsMjE2ODIsMjE2ODUsMjE2ODYsMjE2ODcsMjE2ODksMjE2OTAsMjE2OTIsMjE2OTQsMjE2OTksMjE3MDEsMjE3MDYsMjE3MDcsMjE3MTgsMjE3MjAsMjE3MjMsMjE3MjgsMjE3MjksMjE3MzAsMjE3MzEsMjE3MzIsMjE3MzksMjE3NDAsMjE3NDMsMjE3NDQsMjE3NDUsMjE3NDgsMjE3NDksMjE3NTAsMjE3NTEsMjE3NTIsMjE3NTMsMjE3NTUsMjE3NTgsMjE3NjAsMjE3NjIsMjE3NjMsMjE3NjQsMjE3NjUsMjE3NjgsMjE3NzAsMjE3NzEsMjE3NzIsMjE3NzMsMjE3NzQsMjE3NzgsMjE3NzksMjE3ODEsMjE3ODIsMjE3ODMsMjE3ODQsMjE3ODUsMjE3ODYsMjE3ODgsMjE3ODksMjE3OTAsMjE3OTEsMjE3OTMsMjE3OTcsMjE3OTgsMjE4MDAsMjE4MDEsMjE4MDMsMjE4MDUsMjE4MTAsMjE4MTIsMjE4MTMsMjE4MTQsMjE4MTYsMjE4MTcsMjE4MTgsMjE4MTksMjE4MjEsMjE4MjQsMjE4MjYsMjE4MjksMjE4MzEsMjE4MzIsMjE4MzUsMjE4MzYsMjE4MzcsMjE4MzgsMjE4MzksMjE4NDEsMjE4NDIsMjE4NDMsMjE4NDQsMjE4NDcsMjE4NDgsMjE4NDksMjE4NTAsMjE4NTEsMjE4NTMsMjE4NTQsMjE4NTUsMjE4NTYsMjE4NTgsMjE4NTksMjE4NjQsMjE4NjUsMjE4NjcsMjE4NzEsMjE4NzIsMjE4NzMsMjE4NzQsMjE4NzUsMjE4NzYsMjE4ODEsMjE4ODIsMjE4ODUsMjE4ODcsMjE4OTMsMjE4OTQsMjE5MDAsMjE5MDEsMjE5MDIsMjE5MDQsMjE5MDYsMjE5MDcsMjE5MDksMjE5MTAsMjE5MTEsMjE5MTQsMjE5MTUsMjE5MTgsMjE5MjAsMjE5MjEsMjE5MjIsMjE5MjMsMjE5MjQsMjE5MjUsMjE5MjYsMjE5MjgsMjE5MjksMjE5MzAsMjE5MzEsMjE5MzIsMjE5MzMsMjE5MzQsMjE5MzUsMjE5MzYsMjE5MzgsMjE5NDAsMjE5NDIsMjE5NDQsMjE5NDYsMjE5NDgsMjE5NTEsMjE5NTIsMjE5NTMsMjE5NTQsMjE5NTUsMjE5NTgsMjE5NTksMjE5NjAsMjE5NjIsMjE5NjMsMjE5NjYsMjE5NjcsMjE5NjgsMjE5NzMsMjE5NzUsMjE5NzYsMjE5NzcsMjE5NzgsMjE5NzksMjE5ODIsMjE5ODQsMjE5ODYsMjE5OTEsMjE5OTMsMjE5OTcsMjE5OTgsMjIwMDAsMjIwMDEsMjIwMDQsMjIwMDYsMjIwMDgsMjIwMDksMjIwMTAsMjIwMTEsMjIwMTIsMjIwMTUsMjIwMTgsMjIwMTksMjIwMjAsMjIwMjEsMjIwMjIsMjIwMjMsMjIwMjYsMjIwMjcsMjIwMjksMjIwMzIsMjIwMzMsMjIwMzQsMjIwMzUsMjIwMzYsMjIwMzcsMjIwMzgsMjIwMzksMjIwNDEsMjIwNDIsMjIwNDQsMjIwNDUsMjIwNDgsMjIwNDksMjIwNTAsMjIwNTMsMjIwNTQsMjIwNTYsMjIwNTcsMjIwNTgsMjIwNTksMjIwNjIsMjIwNjMsMjIwNjQsMjIwNjcsMjIwNjksMjIwNzEsMjIwNzIsMjIwNzQsMjIwNzYsMjIwNzcsMjIwNzgsMjIwODAsMjIwODEsMjIwODIsMjIwODMsMjIwODQsMjIwODUsMjIwODYsMjIwODcsMjIwODgsMjIwODksMjIwOTAsMjIwOTEsMjIwOTUsMjIwOTYsMjIwOTcsMjIwOTgsMjIwOTksMjIxMDEsMjIxMDIsMjIxMDYsMjIxMDcsMjIxMDksMjIxMTAsMjIxMTEsMjIxMTIsMjIxMTMsMjIxMTUsMjIxMTcsMjIxMTgsMjIxMTksMjIxMjUsMjIxMjYsMjIxMjcsMjIxMjgsMjIxMzAsMjIxMzEsMjIxMzIsMjIxMzMsMjIxMzUsMjIxMzYsMjIxMzcsMjIxMzgsMjIxNDEsMjIxNDIsMjIxNDMsMjIxNDQsMjIxNDUsMjIxNDYsMjIxNDcsMjIxNDgsMjIxNTEsMjIxNTIsMjIxNTMsMjIxNTQsMjIxNTUsMjIxNTYsMjIxNTcsMjIxNjAsMjIxNjEsMjIxNjIsMjIxNjQsMjIxNjUsMjIxNjYsMjIxNjcsMjIxNjgsMjIxNjksMjIxNzAsMjIxNzEsMjIxNzIsMjIxNzMsMjIxNzQsMjIxNzUsMjIxNzYsMjIxNzcsMjIxNzgsMjIxODAsMjIxODEsMjIxODIsMjIxODMsMjIxODQsMjIxODUsMjIxODYsMjIxODcsMjIxODgsMjIxODksMjIxOTAsMjIxOTIsMjIxOTMsMjIxOTQsMjIxOTUsMjIxOTYsMjIxOTcsMjIxOTgsMjIyMDAsMjIyMDEsMjIyMDIsMjIyMDMsMjIyMDUsMjIyMDYsMjIyMDcsMjIyMDgsMjIyMDksMjIyMTAsMjIyMTEsMjIyMTIsMjIyMTMsMjIyMTQsMjIyMTUsMjIyMTYsMjIyMTcsMjIyMTksMjIyMjAsMjIyMjEsMjIyMjIsMjIyMjMsMjIyMjQsMjIyMjUsMjIyMjYsMjIyMjcsMjIyMjksMjIyMzAsMjIyMzIsMjIyMzMsMjIyMzYsMjIyNDMsMjIyNDUsMjIyNDYsMjIyNDcsMjIyNDgsMjIyNDksMjIyNTAsMjIyNTIsMjIyNTQsMjIyNTUsMjIyNTgsMjIyNTksMjIyNjIsMjIyNjMsMjIyNjQsMjIyNjcsMjIyNjgsMjIyNzIsMjIyNzMsMjIyNzQsMjIyNzcsMjIyNzksMjIyODMsMjIyODQsMjIyODUsMjIyODYsMjIyODcsMjIyODgsMjIyODksMjIyOTAsMjIyOTEsMjIyOTIsMjIyOTMsMjIyOTQsMjIyOTUsMjIyOTYsMjIyOTcsMjIyOTgsMjIyOTksMjIzMDEsMjIzMDIsMjIzMDQsMjIzMDUsMjIzMDYsMjIzMDgsMjIzMDksMjIzMTAsMjIzMTEsMjIzMTUsMjIzMjEsMjIzMjIsMjIzMjQsMjIzMjUsMjIzMjYsMjIzMjcsMjIzMjgsMjIzMzIsMjIzMzMsMjIzMzUsMjIzMzcsMjIzMzksMjIzNDAsMjIzNDEsMjIzNDIsMjIzNDQsMjIzNDUsMjIzNDcsMjIzNTQsMjIzNTUsMjIzNTYsMjIzNTcsMjIzNTgsMjIzNjAsMjIzNjEsMjIzNzAsMjIzNzEsMjIzNzMsMjIzNzUsMjIzODAsMjIzODIsMjIzODQsMjIzODUsMjIzODYsMjIzODgsMjIzODksMjIzOTIsMjIzOTMsMjIzOTQsMjIzOTcsMjIzOTgsMjIzOTksMjI0MDAsMjI0MDEsMjI0MDcsMjI0MDgsMjI0MDksMjI0MTAsMjI0MTMsMjI0MTQsMjI0MTUsMjI0MTYsMjI0MTcsMjI0MjAsMjI0MjEsMjI0MjIsMjI0MjMsMjI0MjQsMjI0MjUsMjI0MjYsMjI0MjgsMjI0MjksMjI0MzAsMjI0MzEsMjI0MzcsMjI0NDAsMjI0NDIsMjI0NDQsMjI0NDcsMjI0NDgsMjI0NDksMjI0NTEsMjI0NTMsMjI0NTQsMjI0NTUsMjI0NTcsMjI0NTgsMjI0NTksMjI0NjAsMjI0NjEsMjI0NjIsMjI0NjMsMjI0NjQsMjI0NjUsMjI0NjgsMjI0NjksMjI0NzAsMjI0NzEsMjI0NzIsMjI0NzMsMjI0NzQsMjI0NzYsMjI0NzcsMjI0ODAsMjI0ODEsMjI0ODMsMjI0ODYsMjI0ODcsMjI0OTEsMjI0OTIsMjI0OTQsMjI0OTcsMjI0OTgsMjI0OTksMjI1MDEsMjI1MDIsMjI1MDMsMjI1MDQsMjI1MDUsMjI1MDYsMjI1MDcsMjI1MDgsMjI1MTAsMjI1MTIsMjI1MTMsMjI1MTQsMjI1MTUsMjI1MTcsMjI1MTgsMjI1MTksMjI1MjMsMjI1MjQsMjI1MjYsMjI1MjcsMjI1MjksMjI1MzEsMjI1MzIsMjI1MzMsMjI1MzYsMjI1MzcsMjI1MzgsMjI1NDAsMjI1NDIsMjI1NDMsMjI1NDQsMjI1NDYsMjI1NDcsMjI1NDgsMjI1NTAsMjI1NTEsMjI1NTIsMjI1NTQsMjI1NTUsMjI1NTYsMjI1NTcsMjI1NTksMjI1NjIsMjI1NjMsMjI1NjUsMjI1NjYsMjI1NjcsMjI1NjgsMjI1NjksMjI1NzEsMjI1NzIsMjI1NzMsMjI1NzQsMjI1NzUsMjI1NzcsMjI1NzgsMjI1NzksMjI1ODAsMjI1ODIsMjI1ODMsMjI1ODQsMjI1ODUsMjI1ODYsMjI1ODcsMjI1ODgsMjI1ODksMjI1OTAsMjI1OTEsMjI1OTIsMjI1OTMsMjI1OTQsMjI1OTUsMjI1OTcsMjI1OTgsMjI1OTksMjI2MDAsMjI2MDEsMjI2MDIsMjI2MDMsMjI2MDYsMjI2MDcsMjI2MDgsMjI2MTAsMjI2MTEsMjI2MTMsMjI2MTQsMjI2MTUsMjI2MTcsMjI2MTgsMjI2MTksMjI2MjAsMjI2MjEsMjI2MjMsMjI2MjQsMjI2MjUsMjI2MjYsMjI2MjcsMjI2MjgsMjI2MzAsMjI2MzEsMjI2MzIsMjI2MzMsMjI2MzQsMjI2MzcsMjI2MzgsMjI2MzksMjI2NDAsMjI2NDEsMjI2NDIsMjI2NDMsMjI2NDQsMjI2NDUsMjI2NDYsMjI2NDcsMjI2NDgsMjI2NDksMjI2NTAsMjI2NTEsMjI2NTIsMjI2NTMsMjI2NTUsMjI2NTgsMjI2NjAsMjI2NjIsMjI2NjMsMjI2NjQsMjI2NjYsMjI2NjcsMjI2NjgsMjI2NjksMjI2NzAsMjI2NzEsMjI2NzIsMjI2NzMsMjI2NzYsMjI2NzcsMjI2NzgsMjI2NzksMjI2ODAsMjI2ODMsMjI2ODQsMjI2ODUsMjI2ODgsMjI2ODksMjI2OTAsMjI2OTEsMjI2OTIsMjI2OTMsMjI2OTQsMjI2OTUsMjI2OTgsMjI2OTksMjI3MDAsMjI3MDEsMjI3MDIsMjI3MDMsMjI3MDQsMjI3MDUsMjI3MDYsMjI3MDcsMjI3MDgsMjI3MDksMjI3MTAsMjI3MTEsMjI3MTIsMjI3MTMsMjI3MTQsMjI3MTUsMjI3MTcsMjI3MTgsMjI3MTksMjI3MjAsMjI3MjIsMjI3MjMsMjI3MjQsMjI3MjYsMjI3MjcsMjI3MjgsMjI3MjksMjI3MzAsMjI3MzEsMjI3MzIsMjI3MzMsMjI3MzQsMjI3MzUsMjI3MzYsMjI3MzgsMjI3MzksMjI3NDAsMjI3NDIsMjI3NDMsMjI3NDQsMjI3NDUsMjI3NDYsMjI3NDcsMjI3NDgsMjI3NDksMjI3NTAsMjI3NTEsMjI3NTIsMjI3NTMsMjI3NTQsMjI3NTUsMjI3NTcsMjI3NTgsMjI3NTksMjI3NjAsMjI3NjEsMjI3NjIsMjI3NjUsMjI3NjcsMjI3NjksMjI3NzAsMjI3NzIsMjI3NzMsMjI3NzUsMjI3NzYsMjI3NzgsMjI3NzksMjI3ODAsMjI3ODEsMjI3ODIsMjI3ODMsMjI3ODQsMjI3ODUsMjI3ODcsMjI3ODksMjI3OTAsMjI3OTIsMjI3OTMsMjI3OTQsMjI3OTUsMjI3OTYsMjI3OTgsMjI4MDAsMjI4MDEsMjI4MDIsMjI4MDMsMjI4MDcsMjI4MDgsMjI4MTEsMjI4MTMsMjI4MTQsMjI4MTYsMjI4MTcsMjI4MTgsMjI4MTksMjI4MjIsMjI4MjQsMjI4MjgsMjI4MzIsMjI4MzQsMjI4MzUsMjI4MzcsMjI4MzgsMjI4NDMsMjI4NDUsMjI4NDYsMjI4NDcsMjI4NDgsMjI4NTEsMjI4NTMsMjI4NTQsMjI4NTgsMjI4NjAsMjI4NjEsMjI4NjQsMjI4NjYsMjI4NjcsMjI4NzMsMjI4NzUsMjI4NzYsMjI4NzcsMjI4NzgsMjI4NzksMjI4ODEsMjI4ODMsMjI4ODQsMjI4ODYsMjI4ODcsMjI4ODgsMjI4ODksMjI4OTAsMjI4OTEsMjI4OTIsMjI4OTMsMjI4OTQsMjI4OTUsMjI4OTYsMjI4OTcsMjI4OTgsMjI5MDEsMjI5MDMsMjI5MDYsMjI5MDcsMjI5MDgsMjI5MTAsMjI5MTEsMjI5MTIsMjI5MTcsMjI5MjEsMjI5MjMsMjI5MjQsMjI5MjYsMjI5MjcsMjI5MjgsMjI5MjksMjI5MzIsMjI5MzMsMjI5MzYsMjI5MzgsMjI5MzksMjI5NDAsMjI5NDEsMjI5NDMsMjI5NDQsMjI5NDUsMjI5NDYsMjI5NTAsMjI5NTEsMjI5NTYsMjI5NTcsMjI5NjAsMjI5NjEsMjI5NjMsMjI5NjQsMjI5NjUsMjI5NjYsMjI5NjcsMjI5NjgsMjI5NzAsMjI5NzIsMjI5NzMsMjI5NzUsMjI5NzYsMjI5NzcsMjI5NzgsMjI5NzksMjI5ODAsMjI5ODEsMjI5ODMsMjI5ODQsMjI5ODUsMjI5ODgsMjI5ODksMjI5OTAsMjI5OTEsMjI5OTcsMjI5OTgsMjMwMDEsMjMwMDMsMjMwMDYsMjMwMDcsMjMwMDgsMjMwMDksMjMwMTAsMjMwMTIsMjMwMTQsMjMwMTUsMjMwMTcsMjMwMTgsMjMwMTksMjMwMjEsMjMwMjIsMjMwMjMsMjMwMjQsMjMwMjUsMjMwMjYsMjMwMjcsMjMwMjgsMjMwMjksMjMwMzAsMjMwMzEsMjMwMzIsMjMwMzQsMjMwMzYsMjMwMzcsMjMwMzgsMjMwNDAsMjMwNDIsMjMwNTAsMjMwNTEsMjMwNTMsMjMwNTQsMjMwNTUsMjMwNTYsMjMwNTgsMjMwNjAsMjMwNjEsMjMwNjIsMjMwNjMsMjMwNjUsMjMwNjYsMjMwNjcsMjMwNjksMjMwNzAsMjMwNzMsMjMwNzQsMjMwNzYsMjMwNzgsMjMwNzksMjMwODAsMjMwODIsMjMwODMsMjMwODQsMjMwODUsMjMwODYsMjMwODcsMjMwODgsMjMwOTEsMjMwOTMsMjMwOTUsMjMwOTYsMjMwOTcsMjMwOTgsMjMwOTksMjMxMDEsMjMxMDIsMjMxMDMsMjMxMDUsMjMxMDYsMjMxMDcsMjMxMDgsMjMxMDksMjMxMTEsMjMxMTIsMjMxMTUsMjMxMTYsMjMxMTcsMjMxMTgsMjMxMTksMjMxMjAsMjMxMjEsMjMxMjIsMjMxMjMsMjMxMjQsMjMxMjYsMjMxMjcsMjMxMjgsMjMxMjksMjMxMzEsMjMxMzIsMjMxMzMsMjMxMzQsMjMxMzUsMjMxMzYsMjMxMzcsMjMxMzksMjMxNDAsMjMxNDEsMjMxNDIsMjMxNDQsMjMxNDUsMjMxNDcsMjMxNDgsMjMxNDksMjMxNTAsMjMxNTEsMjMxNTIsMjMxNTMsMjMxNTQsMjMxNTUsMjMxNjAsMjMxNjEsMjMxNjMsMjMxNjQsMjMxNjUsMjMxNjYsMjMxNjgsMjMxNjksMjMxNzAsMjMxNzEsMjMxNzIsMjMxNzMsMjMxNzQsMjMxNzUsMjMxNzYsMjMxNzcsMjMxNzgsMjMxNzksMjMxODAsMjMxODEsMjMxODIsMjMxODMsMjMxODQsMjMxODUsMjMxODcsMjMxODgsMjMxODksMjMxOTAsMjMxOTEsMjMxOTIsMjMxOTMsMjMxOTYsMjMxOTcsMjMxOTgsMjMxOTksMjMyMDAsMjMyMDEsMjMyMDIsMjMyMDMsMjMyMDQsMjMyMDUsMjMyMDYsMjMyMDcsMjMyMDgsMjMyMDksMjMyMTEsMjMyMTIsMjMyMTMsMjMyMTQsMjMyMTUsMjMyMTYsMjMyMTcsMjMyMjAsMjMyMjIsMjMyMjMsMjMyMjUsMjMyMjYsMjMyMjcsMjMyMjgsMjMyMjksMjMyMzEsMjMyMzIsMjMyMzUsMjMyMzYsMjMyMzcsMjMyMzgsMjMyMzksMjMyNDAsMjMyNDIsMjMyNDMsMjMyNDUsMjMyNDYsMjMyNDcsMjMyNDgsMjMyNDksMjMyNTEsMjMyNTMsMjMyNTUsMjMyNTcsMjMyNTgsMjMyNTksMjMyNjEsMjMyNjIsMjMyNjMsMjMyNjYsMjMyNjgsMjMyNjksMjMyNzEsMjMyNzIsMjMyNzQsMjMyNzYsMjMyNzcsMjMyNzgsMjMyNzksMjMyODAsMjMyODIsMjMyODMsMjMyODQsMjMyODUsMjMyODYsMjMyODcsMjMyODgsMjMyODksMjMyOTAsMjMyOTEsMjMyOTIsMjMyOTMsMjMyOTQsMjMyOTUsMjMyOTYsMjMyOTcsMjMyOTgsMjMyOTksMjMzMDAsMjMzMDEsMjMzMDIsMjMzMDMsMjMzMDQsMjMzMDYsMjMzMDcsMjMzMDgsMjMzMDksMjMzMTAsMjMzMTEsMjMzMTIsMjMzMTMsMjMzMTQsMjMzMTUsMjMzMTYsMjMzMTcsMjMzMjAsMjMzMjEsMjMzMjIsMjMzMjMsMjMzMjQsMjMzMjUsMjMzMjYsMjMzMjcsMjMzMjgsMjMzMjksMjMzMzAsMjMzMzEsMjMzMzIsMjMzMzMsMjMzMzQsMjMzMzUsMjMzMzYsMjMzMzcsMjMzMzgsMjMzMzksMjMzNDAsMjMzNDEsMjMzNDIsMjMzNDMsMjMzNDQsMjMzNDUsMjMzNDcsMjMzNDksMjMzNTAsMjMzNTIsMjMzNTMsMjMzNTQsMjMzNTUsMjMzNTYsMjMzNTcsMjMzNTgsMjMzNTksMjMzNjEsMjMzNjIsMjMzNjMsMjMzNjQsMjMzNjUsMjMzNjYsMjMzNjcsMjMzNjgsMjMzNjksMjMzNzAsMjMzNzEsMjMzNzIsMjMzNzMsMjMzNzQsMjMzNzUsMjMzNzgsMjMzODIsMjMzOTAsMjMzOTIsMjMzOTMsMjMzOTksMjM0MDAsMjM0MDMsMjM0MDUsMjM0MDYsMjM0MDcsMjM0MTAsMjM0MTIsMjM0MTQsMjM0MTUsMjM0MTYsMjM0MTcsMjM0MTksMjM0MjAsMjM0MjIsMjM0MjMsMjM0MjYsMjM0MzAsMjM0MzQsMjM0MzcsMjM0MzgsMjM0NDAsMjM0NDEsMjM0NDIsMjM0NDQsMjM0NDYsMjM0NTUsMjM0NjMsMjM0NjQsMjM0NjUsMjM0NjgsMjM0NjksMjM0NzAsMjM0NzEsMjM0NzMsMjM0NzQsMjM0NzksMjM0ODIsMjM0ODMsMjM0ODQsMjM0ODgsMjM0ODksMjM0OTEsMjM0OTYsMjM0OTcsMjM0OTgsMjM0OTksMjM1MDEsMjM1MDIsMjM1MDMsMjM1MDUsMjM1MDgsMjM1MDksMjM1MTAsMjM1MTEsMjM1MTIsMjM1MTMsMjM1MTQsMjM1MTUsMjM1MTYsMjM1MjAsMjM1MjIsMjM1MjMsMjM1MjYsMjM1MjcsMjM1MjksMjM1MzAsMjM1MzEsMjM1MzIsMjM1MzMsMjM1MzUsMjM1MzcsMjM1MzgsMjM1MzksMjM1NDAsMjM1NDEsMjM1NDIsMjM1NDMsMjM1NDksMjM1NTAsMjM1NTIsMjM1NTQsMjM1NTUsMjM1NTcsMjM1NTksMjM1NjAsMjM1NjMsMjM1NjQsMjM1NjUsMjM1NjYsMjM1NjgsMjM1NzAsMjM1NzEsMjM1NzUsMjM1NzcsMjM1NzksMjM1ODIsMjM1ODMsMjM1ODQsMjM1ODUsMjM1ODcsMjM1OTAsMjM1OTIsMjM1OTMsMjM1OTQsMjM1OTUsMjM1OTcsMjM1OTgsMjM1OTksMjM2MDAsMjM2MDIsMjM2MDMsMjM2MDUsMjM2MDYsMjM2MDcsMjM2MTksMjM2MjAsMjM2MjIsMjM2MjMsMjM2MjgsMjM2MjksMjM2MzQsMjM2MzUsMjM2MzYsMjM2MzgsMjM2MzksMjM2NDAsMjM2NDIsMjM2NDMsMjM2NDQsMjM2NDUsMjM2NDcsMjM2NTAsMjM2NTIsMjM2NTUsMjM2NTYsMjM2NTcsMjM2NTgsMjM2NTksMjM2NjAsMjM2NjEsMjM2NjQsMjM2NjYsMjM2NjcsMjM2NjgsMjM2NjksMjM2NzAsMjM2NzEsMjM2NzIsMjM2NzUsMjM2NzYsMjM2NzcsMjM2NzgsMjM2ODAsMjM2ODMsMjM2ODQsMjM2ODUsMjM2ODYsMjM2ODcsMjM2ODksMjM2OTAsMjM2OTEsMjM2OTQsMjM2OTUsMjM2OTgsMjM2OTksMjM3MDEsMjM3MDksMjM3MTAsMjM3MTEsMjM3MTIsMjM3MTMsMjM3MTYsMjM3MTcsMjM3MTgsMjM3MTksMjM3MjAsMjM3MjIsMjM3MjYsMjM3MjcsMjM3MjgsMjM3MzAsMjM3MzIsMjM3MzQsMjM3MzcsMjM3MzgsMjM3MzksMjM3NDAsMjM3NDIsMjM3NDQsMjM3NDYsMjM3NDcsMjM3NDksMjM3NTAsMjM3NTEsMjM3NTIsMjM3NTMsMjM3NTQsMjM3NTYsMjM3NTcsMjM3NTgsMjM3NTksMjM3NjAsMjM3NjEsMjM3NjMsMjM3NjQsMjM3NjUsMjM3NjYsMjM3NjcsMjM3NjgsMjM3NzAsMjM3NzEsMjM3NzIsMjM3NzMsMjM3NzQsMjM3NzUsMjM3NzYsMjM3NzgsMjM3NzksMjM3ODMsMjM3ODUsMjM3ODcsMjM3ODgsMjM3OTAsMjM3OTEsMjM3OTMsMjM3OTQsMjM3OTUsMjM3OTYsMjM3OTcsMjM3OTgsMjM3OTksMjM4MDAsMjM4MDEsMjM4MDIsMjM4MDQsMjM4MDUsMjM4MDYsMjM4MDcsMjM4MDgsMjM4MDksMjM4MTIsMjM4MTMsMjM4MTYsMjM4MTcsMjM4MTgsMjM4MTksMjM4MjAsMjM4MjEsMjM4MjMsMjM4MjQsMjM4MjUsMjM4MjYsMjM4MjcsMjM4MjksMjM4MzEsMjM4MzIsMjM4MzMsMjM4MzQsMjM4MzYsMjM4MzcsMjM4MzksMjM4NDAsMjM4NDEsMjM4NDIsMjM4NDMsMjM4NDUsMjM4NDgsMjM4NTAsMjM4NTEsMjM4NTIsMjM4NTUsMjM4NTYsMjM4NTcsMjM4NTgsMjM4NTksMjM4NjEsMjM4NjIsMjM4NjMsMjM4NjQsMjM4NjUsMjM4NjYsMjM4NjcsMjM4NjgsMjM4NzEsMjM4NzIsMjM4NzMsMjM4NzQsMjM4NzUsMjM4NzYsMjM4NzcsMjM4NzgsMjM4ODAsMjM4ODEsMjM4ODUsMjM4ODYsMjM4ODcsMjM4ODgsMjM4ODksMjM4OTAsMjM4OTEsMjM4OTIsMjM4OTMsMjM4OTQsMjM4OTUsMjM4OTcsMjM4OTgsMjM5MDAsMjM5MDIsMjM5MDMsMjM5MDQsMjM5MDUsMjM5MDYsMjM5MDcsMjM5MDgsMjM5MDksMjM5MTAsMjM5MTEsMjM5MTIsMjM5MTQsMjM5MTcsMjM5MTgsMjM5MjAsMjM5MjEsMjM5MjIsMjM5MjMsMjM5MjUsMjM5MjYsMjM5MjcsMjM5MjgsMjM5MjksMjM5MzAsMjM5MzEsMjM5MzIsMjM5MzMsMjM5MzQsMjM5MzUsMjM5MzYsMjM5MzcsMjM5MzksMjM5NDAsMjM5NDEsMjM5NDIsMjM5NDMsMjM5NDQsMjM5NDUsMjM5NDYsMjM5NDcsMjM5NDgsMjM5NDksMjM5NTAsMjM5NTEsMjM5NTIsMjM5NTMsMjM5NTQsMjM5NTUsMjM5NTYsMjM5NTcsMjM5NTgsMjM5NTksMjM5NjAsMjM5NjIsMjM5NjMsMjM5NjQsMjM5NjYsMjM5NjcsMjM5NjgsMjM5NjksMjM5NzAsMjM5NzEsMjM5NzIsMjM5NzMsMjM5NzQsMjM5NzUsMjM5NzYsMjM5NzcsMjM5NzgsMjM5NzksMjM5ODAsMjM5ODEsMjM5ODIsMjM5ODMsMjM5ODQsMjM5ODUsMjM5ODYsMjM5ODcsMjM5ODgsMjM5ODksMjM5OTAsMjM5OTIsMjM5OTMsMjM5OTQsMjM5OTUsMjM5OTYsMjM5OTcsMjM5OTgsMjM5OTksMjQwMDAsMjQwMDEsMjQwMDIsMjQwMDMsMjQwMDQsMjQwMDYsMjQwMDcsMjQwMDgsMjQwMDksMjQwMTAsMjQwMTEsMjQwMTIsMjQwMTQsMjQwMTUsMjQwMTYsMjQwMTcsMjQwMTgsMjQwMTksMjQwMjAsMjQwMjEsMjQwMjIsMjQwMjMsMjQwMjQsMjQwMjUsMjQwMjYsMjQwMjgsMjQwMzEsMjQwMzIsMjQwMzUsMjQwMzYsMjQwNDIsMjQwNDQsMjQwNDUsMjQwNDgsMjQwNTMsMjQwNTQsMjQwNTYsMjQwNTcsMjQwNTgsMjQwNTksMjQwNjAsMjQwNjMsMjQwNjQsMjQwNjgsMjQwNzEsMjQwNzMsMjQwNzQsMjQwNzUsMjQwNzcsMjQwNzgsMjQwODIsMjQwODMsMjQwODcsMjQwOTQsMjQwOTUsMjQwOTYsMjQwOTcsMjQwOTgsMjQwOTksMjQxMDAsMjQxMDEsMjQxMDQsMjQxMDUsMjQxMDYsMjQxMDcsMjQxMDgsMjQxMTEsMjQxMTIsMjQxMTQsMjQxMTUsMjQxMTYsMjQxMTcsMjQxMTgsMjQxMjEsMjQxMjIsMjQxMjYsMjQxMjcsMjQxMjgsMjQxMjksMjQxMzEsMjQxMzQsMjQxMzUsMjQxMzYsMjQxMzcsMjQxMzgsMjQxMzksMjQxNDEsMjQxNDIsMjQxNDMsMjQxNDQsMjQxNDUsMjQxNDYsMjQxNDcsMjQxNTAsMjQxNTEsMjQxNTIsMjQxNTMsMjQxNTQsMjQxNTYsMjQxNTcsMjQxNTksMjQxNjAsMjQxNjMsMjQxNjQsMjQxNjUsMjQxNjYsMjQxNjcsMjQxNjgsMjQxNjksMjQxNzAsMjQxNzEsMjQxNzIsMjQxNzMsMjQxNzQsMjQxNzUsMjQxNzYsMjQxNzcsMjQxODEsMjQxODMsMjQxODUsMjQxOTAsMjQxOTMsMjQxOTQsMjQxOTUsMjQxOTcsMjQyMDAsMjQyMDEsMjQyMDQsMjQyMDUsMjQyMDYsMjQyMTAsMjQyMTYsMjQyMTksMjQyMjEsMjQyMjUsMjQyMjYsMjQyMjcsMjQyMjgsMjQyMzIsMjQyMzMsMjQyMzQsMjQyMzUsMjQyMzYsMjQyMzgsMjQyMzksMjQyNDAsMjQyNDEsMjQyNDIsMjQyNDQsMjQyNTAsMjQyNTEsMjQyNTIsMjQyNTMsMjQyNTUsMjQyNTYsMjQyNTcsMjQyNTgsMjQyNTksMjQyNjAsMjQyNjEsMjQyNjIsMjQyNjMsMjQyNjQsMjQyNjcsMjQyNjgsMjQyNjksMjQyNzAsMjQyNzEsMjQyNzIsMjQyNzYsMjQyNzcsMjQyNzksMjQyODAsMjQyODEsMjQyODIsMjQyODQsMjQyODUsMjQyODYsMjQyODcsMjQyODgsMjQyODksMjQyOTAsMjQyOTEsMjQyOTIsMjQyOTMsMjQyOTQsMjQyOTUsMjQyOTcsMjQyOTksMjQzMDAsMjQzMDEsMjQzMDIsMjQzMDMsMjQzMDQsMjQzMDUsMjQzMDYsMjQzMDcsMjQzMDksMjQzMTIsMjQzMTMsMjQzMTUsMjQzMTYsMjQzMTcsMjQzMjUsMjQzMjYsMjQzMjcsMjQzMjksMjQzMzIsMjQzMzMsMjQzMzQsMjQzMzYsMjQzMzgsMjQzNDAsMjQzNDIsMjQzNDUsMjQzNDYsMjQzNDgsMjQzNDksMjQzNTAsMjQzNTMsMjQzNTQsMjQzNTUsMjQzNTYsMjQzNjAsMjQzNjMsMjQzNjQsMjQzNjYsMjQzNjgsMjQzNzAsMjQzNzEsMjQzNzIsMjQzNzMsMjQzNzQsMjQzNzUsMjQzNzYsMjQzNzksMjQzODEsMjQzODIsMjQzODMsMjQzODUsMjQzODYsMjQzODcsMjQzODgsMjQzODksMjQzOTAsMjQzOTEsMjQzOTIsMjQzOTMsMjQzOTQsMjQzOTUsMjQzOTYsMjQzOTcsMjQzOTgsMjQzOTksMjQ0MDEsMjQ0MDQsMjQ0MDksMjQ0MTAsMjQ0MTEsMjQ0MTIsMjQ0MTQsMjQ0MTUsMjQ0MTYsMjQ0MTksMjQ0MjEsMjQ0MjMsMjQ0MjQsMjQ0MjcsMjQ0MzAsMjQ0MzEsMjQ0MzQsMjQ0MzYsMjQ0MzcsMjQ0MzgsMjQ0NDAsMjQ0NDIsMjQ0NDUsMjQ0NDYsMjQ0NDcsMjQ0NTEsMjQ0NTQsMjQ0NjEsMjQ0NjIsMjQ0NjMsMjQ0NjUsMjQ0NjcsMjQ0NjgsMjQ0NzAsMjQ0NzQsMjQ0NzUsMjQ0NzcsMjQ0NzgsMjQ0NzksMjQ0ODAsMjQ0ODIsMjQ0ODMsMjQ0ODQsMjQ0ODUsMjQ0ODYsMjQ0ODcsMjQ0ODksMjQ0OTEsMjQ0OTIsMjQ0OTUsMjQ0OTYsMjQ0OTcsMjQ0OTgsMjQ0OTksMjQ1MDAsMjQ1MDIsMjQ1MDQsMjQ1MDUsMjQ1MDYsMjQ1MDcsMjQ1MTAsMjQ1MTEsMjQ1MTIsMjQ1MTMsMjQ1MTQsMjQ1MTksMjQ1MjAsMjQ1MjIsMjQ1MjMsMjQ1MjYsMjQ1MzEsMjQ1MzIsMjQ1MzMsMjQ1MzgsMjQ1MzksMjQ1NDAsMjQ1NDIsMjQ1NDMsMjQ1NDYsMjQ1NDcsMjQ1NDksMjQ1NTAsMjQ1NTIsMjQ1NTMsMjQ1NTYsMjQ1NTksMjQ1NjAsMjQ1NjIsMjQ1NjMsMjQ1NjQsMjQ1NjYsMjQ1NjcsMjQ1NjksMjQ1NzAsMjQ1NzIsMjQ1ODMsMjQ1ODQsMjQ1ODUsMjQ1ODcsMjQ1ODgsMjQ1OTIsMjQ1OTMsMjQ1OTUsMjQ1OTksMjQ2MDAsMjQ2MDIsMjQ2MDYsMjQ2MDcsMjQ2MTAsMjQ2MTEsMjQ2MTIsMjQ2MjAsMjQ2MjEsMjQ2MjIsMjQ2MjQsMjQ2MjUsMjQ2MjYsMjQ2MjcsMjQ2MjgsMjQ2MzAsMjQ2MzEsMjQ2MzIsMjQ2MzMsMjQ2MzQsMjQ2MzcsMjQ2MzgsMjQ2NDAsMjQ2NDQsMjQ2NDUsMjQ2NDYsMjQ2NDcsMjQ2NDgsMjQ2NDksMjQ2NTAsMjQ2NTIsMjQ2NTQsMjQ2NTUsMjQ2NTcsMjQ2NTksMjQ2NjAsMjQ2NjIsMjQ2NjMsMjQ2NjQsMjQ2NjcsMjQ2NjgsMjQ2NzAsMjQ2NzEsMjQ2NzIsMjQ2NzMsMjQ2NzcsMjQ2NzgsMjQ2ODYsMjQ2ODksMjQ2OTAsMjQ2OTIsMjQ2OTMsMjQ2OTUsMjQ3MDIsMjQ3MDQsMjQ3MDUsMjQ3MDYsMjQ3MDksMjQ3MTAsMjQ3MTEsMjQ3MTIsMjQ3MTQsMjQ3MTUsMjQ3MTgsMjQ3MTksMjQ3MjAsMjQ3MjEsMjQ3MjMsMjQ3MjUsMjQ3MjcsMjQ3MjgsMjQ3MjksMjQ3MzIsMjQ3MzQsMjQ3MzcsMjQ3MzgsMjQ3NDAsMjQ3NDEsMjQ3NDMsMjQ3NDUsMjQ3NDYsMjQ3NTAsMjQ3NTIsMjQ3NTUsMjQ3NTcsMjQ3NTgsMjQ3NTksMjQ3NjEsMjQ3NjIsMjQ3NjUsMjQ3NjYsMjQ3NjcsMjQ3NjgsMjQ3NjksMjQ3NzAsMjQ3NzEsMjQ3NzIsMjQ3NzUsMjQ3NzYsMjQ3NzcsMjQ3ODAsMjQ3ODEsMjQ3ODIsMjQ3ODMsMjQ3ODQsMjQ3ODYsMjQ3ODcsMjQ3ODgsMjQ3OTAsMjQ3OTEsMjQ3OTMsMjQ3OTUsMjQ3OTgsMjQ4MDEsMjQ4MDIsMjQ4MDMsMjQ4MDQsMjQ4MDUsMjQ4MTAsMjQ4MTcsMjQ4MTgsMjQ4MjEsMjQ4MjMsMjQ4MjQsMjQ4MjcsMjQ4MjgsMjQ4MjksMjQ4MzAsMjQ4MzEsMjQ4MzQsMjQ4MzUsMjQ4MzYsMjQ4MzcsMjQ4MzksMjQ4NDIsMjQ4NDMsMjQ4NDQsMjQ4NDgsMjQ4NDksMjQ4NTAsMjQ4NTEsMjQ4NTIsMjQ4NTQsMjQ4NTUsMjQ4NTYsMjQ4NTcsMjQ4NTksMjQ4NjAsMjQ4NjEsMjQ4NjIsMjQ4NjUsMjQ4NjYsMjQ4NjksMjQ4NzIsMjQ4NzMsMjQ4NzQsMjQ4NzYsMjQ4NzcsMjQ4NzgsMjQ4NzksMjQ4ODAsMjQ4ODEsMjQ4ODIsMjQ4ODMsMjQ4ODQsMjQ4ODUsMjQ4ODYsMjQ4ODcsMjQ4ODgsMjQ4ODksMjQ4OTAsMjQ4OTEsMjQ4OTIsMjQ4OTMsMjQ4OTQsMjQ4OTYsMjQ4OTcsMjQ4OTgsMjQ4OTksMjQ5MDAsMjQ5MDEsMjQ5MDIsMjQ5MDMsMjQ5MDUsMjQ5MDcsMjQ5MDksMjQ5MTEsMjQ5MTIsMjQ5MTQsMjQ5MTUsMjQ5MTYsMjQ5MTgsMjQ5MTksMjQ5MjAsMjQ5MjEsMjQ5MjIsMjQ5MjMsMjQ5MjQsMjQ5MjYsMjQ5MjcsMjQ5MjgsMjQ5MjksMjQ5MzEsMjQ5MzIsMjQ5MzMsMjQ5MzQsMjQ5MzcsMjQ5MzgsMjQ5MzksMjQ5NDAsMjQ5NDEsMjQ5NDIsMjQ5NDMsMjQ5NDUsMjQ5NDYsMjQ5NDcsMjQ5NDgsMjQ5NTAsMjQ5NTIsMjQ5NTMsMjQ5NTQsMjQ5NTUsMjQ5NTYsMjQ5NTcsMjQ5NTgsMjQ5NTksMjQ5NjAsMjQ5NjEsMjQ5NjIsMjQ5NjMsMjQ5NjQsMjQ5NjUsMjQ5NjYsMjQ5NjcsMjQ5NjgsMjQ5NjksMjQ5NzAsMjQ5NzIsMjQ5NzMsMjQ5NzUsMjQ5NzYsMjQ5NzcsMjQ5NzgsMjQ5NzksMjQ5ODEsMjQ5ODIsMjQ5ODMsMjQ5ODQsMjQ5ODUsMjQ5ODYsMjQ5ODcsMjQ5ODgsMjQ5OTAsMjQ5OTEsMjQ5OTIsMjQ5OTMsMjQ5OTQsMjQ5OTUsMjQ5OTYsMjQ5OTcsMjQ5OTgsMjUwMDIsMjUwMDMsMjUwMDUsMjUwMDYsMjUwMDcsMjUwMDgsMjUwMDksMjUwMTAsMjUwMTEsMjUwMTIsMjUwMTMsMjUwMTQsMjUwMTYsMjUwMTcsMjUwMTgsMjUwMTksMjUwMjAsMjUwMjEsMjUwMjMsMjUwMjQsMjUwMjUsMjUwMjcsMjUwMjgsMjUwMjksMjUwMzAsMjUwMzEsMjUwMzMsMjUwMzYsMjUwMzcsMjUwMzgsMjUwMzksMjUwNDAsMjUwNDMsMjUwNDUsMjUwNDYsMjUwNDcsMjUwNDgsMjUwNDksMjUwNTAsMjUwNTEsMjUwNTIsMjUwNTMsMjUwNTQsMjUwNTUsMjUwNTYsMjUwNTcsMjUwNTgsMjUwNTksMjUwNjAsMjUwNjEsMjUwNjMsMjUwNjQsMjUwNjUsMjUwNjYsMjUwNjcsMjUwNjgsMjUwNjksMjUwNzAsMjUwNzEsMjUwNzIsMjUwNzMsMjUwNzQsMjUwNzUsMjUwNzYsMjUwNzgsMjUwNzksMjUwODAsMjUwODEsMjUwODIsMjUwODMsMjUwODQsMjUwODUsMjUwODYsMjUwODgsMjUwODksMjUwOTAsMjUwOTEsMjUwOTIsMjUwOTMsMjUwOTUsMjUwOTcsMjUxMDcsMjUxMDgsMjUxMTMsMjUxMTYsMjUxMTcsMjUxMTgsMjUxMjAsMjUxMjMsMjUxMjYsMjUxMjcsMjUxMjgsMjUxMjksMjUxMzEsMjUxMzMsMjUxMzUsMjUxMzYsMjUxMzcsMjUxMzgsMjUxNDEsMjUxNDIsMjUxNDQsMjUxNDUsMjUxNDYsMjUxNDcsMjUxNDgsMjUxNTQsMjUxNTYsMjUxNTcsMjUxNTgsMjUxNjIsMjUxNjcsMjUxNjgsMjUxNzMsMjUxNzQsMjUxNzUsMjUxNzcsMjUxNzgsMjUxODAsMjUxODEsMjUxODIsMjUxODMsMjUxODQsMjUxODUsMjUxODYsMjUxODgsMjUxODksMjUxOTIsMjUyMDEsMjUyMDIsMjUyMDQsMjUyMDUsMjUyMDcsMjUyMDgsMjUyMTAsMjUyMTEsMjUyMTMsMjUyMTcsMjUyMTgsMjUyMTksMjUyMjEsMjUyMjIsMjUyMjMsMjUyMjQsMjUyMjcsMjUyMjgsMjUyMjksMjUyMzAsMjUyMzEsMjUyMzIsMjUyMzYsMjUyNDEsMjUyNDQsMjUyNDUsMjUyNDYsMjUyNTEsMjUyNTQsMjUyNTUsMjUyNTcsMjUyNTgsMjUyNjEsMjUyNjIsMjUyNjMsMjUyNjQsMjUyNjYsMjUyNjcsMjUyNjgsMjUyNzAsMjUyNzEsMjUyNzIsMjUyNzQsMjUyNzgsMjUyODAsMjUyODEsMjUyODMsMjUyOTEsMjUyOTUsMjUyOTcsMjUzMDEsMjUzMDksMjUzMTAsMjUzMTIsMjUzMTMsMjUzMTYsMjUzMjIsMjUzMjMsMjUzMjgsMjUzMzAsMjUzMzMsMjUzMzYsMjUzMzcsMjUzMzgsMjUzMzksMjUzNDQsMjUzNDcsMjUzNDgsMjUzNDksMjUzNTAsMjUzNTQsMjUzNTUsMjUzNTYsMjUzNTcsMjUzNTksMjUzNjAsMjUzNjIsMjUzNjMsMjUzNjQsMjUzNjUsMjUzNjcsMjUzNjgsMjUzNjksMjUzNzIsMjUzODIsMjUzODMsMjUzODUsMjUzODgsMjUzODksMjUzOTAsMjUzOTIsMjUzOTMsMjUzOTUsMjUzOTYsMjUzOTcsMjUzOTgsMjUzOTksMjU0MDAsMjU0MDMsMjU0MDQsMjU0MDYsMjU0MDcsMjU0MDgsMjU0MDksMjU0MTIsMjU0MTUsMjU0MTYsMjU0MTgsMjU0MjUsMjU0MjYsMjU0MjcsMjU0MjgsMjU0MzAsMjU0MzEsMjU0MzIsMjU0MzMsMjU0MzQsMjU0MzUsMjU0MzYsMjU0MzcsMjU0NDAsMjU0NDQsMjU0NDUsMjU0NDYsMjU0NDgsMjU0NTAsMjU0NTEsMjU0NTIsMjU0NTUsMjU0NTYsMjU0NTgsMjU0NTksMjU0NjAsMjU0NjEsMjU0NjQsMjU0NjUsMjU0NjgsMjU0NjksMjU0NzAsMjU0NzEsMjU0NzMsMjU0NzUsMjU0NzYsMjU0NzcsMjU0NzgsMjU0ODMsMjU0ODUsMjU0ODksMjU0OTEsMjU0OTIsMjU0OTMsMjU0OTUsMjU0OTcsMjU0OTgsMjU0OTksMjU1MDAsMjU1MDEsMjU1MDIsMjU1MDMsMjU1MDUsMjU1MDgsMjU1MTAsMjU1MTUsMjU1MTksMjU1MjEsMjU1MjIsMjU1MjUsMjU1MjYsMjU1MjksMjU1MzEsMjU1MzMsMjU1MzUsMjU1MzYsMjU1MzcsMjU1MzgsMjU1MzksMjU1NDEsMjU1NDMsMjU1NDQsMjU1NDYsMjU1NDcsMjU1NDgsMjU1NTMsMjU1NTUsMjU1NTYsMjU1NTcsMjU1NTksMjU1NjAsMjU1NjEsMjU1NjIsMjU1NjMsMjU1NjQsMjU1NjUsMjU1NjcsMjU1NzAsMjU1NzIsMjU1NzMsMjU1NzQsMjU1NzUsMjU1NzYsMjU1NzksMjU1ODAsMjU1ODIsMjU1ODMsMjU1ODQsMjU1ODUsMjU1ODcsMjU1ODksMjU1OTEsMjU1OTMsMjU1OTQsMjU1OTUsMjU1OTYsMjU1OTgsMjU2MDMsMjU2MDQsMjU2MDYsMjU2MDcsMjU2MDgsMjU2MDksMjU2MTAsMjU2MTMsMjU2MTQsMjU2MTcsMjU2MTgsMjU2MjEsMjU2MjIsMjU2MjMsMjU2MjQsMjU2MjUsMjU2MjYsMjU2MjksMjU2MzEsMjU2MzQsMjU2MzUsMjU2MzYsMjU2MzcsMjU2MzksMjU2NDAsMjU2NDEsMjU2NDMsMjU2NDYsMjU2NDcsMjU2NDgsMjU2NDksMjU2NTAsMjU2NTEsMjU2NTMsMjU2NTQsMjU2NTUsMjU2NTYsMjU2NTcsMjU2NTksMjU2NjAsMjU2NjIsMjU2NjQsMjU2NjYsMjU2NjcsMjU2NzMsMjU2NzUsMjU2NzYsMjU2NzcsMjU2NzgsMjU2NzksMjU2ODAsMjU2ODEsMjU2ODMsMjU2ODUsMjU2ODYsMjU2ODcsMjU2ODksMjU2OTAsMjU2OTEsMjU2OTIsMjU2OTMsMjU2OTUsMjU2OTYsMjU2OTcsMjU2OTgsMjU2OTksMjU3MDAsMjU3MDEsMjU3MDIsMjU3MDQsMjU3MDYsMjU3MDcsMjU3MDgsMjU3MTAsMjU3MTEsMjU3MTIsMjU3MTMsMjU3MTQsMjU3MTUsMjU3MTYsMjU3MTcsMjU3MTgsMjU3MTksMjU3MjMsMjU3MjQsMjU3MjUsMjU3MjYsMjU3MjcsMjU3MjgsMjU3MjksMjU3MzEsMjU3MzQsMjU3MzYsMjU3MzcsMjU3MzgsMjU3MzksMjU3NDAsMjU3NDEsMjU3NDIsMjU3NDMsMjU3NDQsMjU3NDcsMjU3NDgsMjU3NTEsMjU3NTIsMjU3NTQsMjU3NTUsMjU3NTYsMjU3NTcsMjU3NTksMjU3NjAsMjU3NjEsMjU3NjIsMjU3NjMsMjU3NjUsMjU3NjYsMjU3NjcsMjU3NjgsMjU3NzAsMjU3NzEsMjU3NzUsMjU3NzcsMjU3NzgsMjU3NzksMjU3ODAsMjU3ODIsMjU3ODUsMjU3ODcsMjU3ODksMjU3OTAsMjU3OTEsMjU3OTMsMjU3OTUsMjU3OTYsMjU3OTgsMjU3OTksMjU4MDAsMjU4MDEsMjU4MDIsMjU4MDMsMjU4MDQsMjU4MDcsMjU4MDksMjU4MTEsMjU4MTIsMjU4MTMsMjU4MTQsMjU4MTcsMjU4MTgsMjU4MTksMjU4MjAsMjU4MjEsMjU4MjMsMjU4MjQsMjU4MjUsMjU4MjcsMjU4MjksMjU4MzEsMjU4MzIsMjU4MzMsMjU4MzQsMjU4MzUsMjU4MzYsMjU4MzcsMjU4MzgsMjU4MzksMjU4NDAsMjU4NDEsMjU4NDIsMjU4NDMsMjU4NDQsMjU4NDUsMjU4NDYsMjU4NDcsMjU4NDgsMjU4NDksMjU4NTAsMjU4NTEsMjU4NTIsMjU4NTMsMjU4NTQsMjU4NTUsMjU4NTcsMjU4NTgsMjU4NTksMjU4NjAsMjU4NjEsMjU4NjIsMjU4NjMsMjU4NjQsMjU4NjYsMjU4NjcsMjU4NjgsMjU4NjksMjU4NzAsMjU4NzEsMjU4NzIsMjU4NzMsMjU4NzUsMjU4NzYsMjU4NzcsMjU4NzgsMjU4NzksMjU4ODEsMjU4ODIsMjU4ODMsMjU4ODQsMjU4ODUsMjU4ODYsMjU4ODcsMjU4ODgsMjU4ODksMjU4OTAsMjU4OTEsMjU4OTIsMjU4OTQsMjU4OTUsMjU4OTYsMjU4OTcsMjU4OTgsMjU5MDAsMjU5MDEsMjU5MDQsMjU5MDUsMjU5MDYsMjU5MDcsMjU5MTEsMjU5MTQsMjU5MTYsMjU5MTcsMjU5MjAsMjU5MjEsMjU5MjIsMjU5MjMsMjU5MjQsMjU5MjYsMjU5MjcsMjU5MzAsMjU5MzEsMjU5MzMsMjU5MzQsMjU5MzYsMjU5MzgsMjU5MzksMjU5NDAsMjU5NDMsMjU5NDQsMjU5NDYsMjU5NDgsMjU5NTEsMjU5NTIsMjU5NTMsMjU5NTYsMjU5NTcsMjU5NTksMjU5NjAsMjU5NjEsMjU5NjIsMjU5NjUsMjU5NjYsMjU5NjcsMjU5NjksMjU5NzEsMjU5NzMsMjU5NzQsMjU5NzYsMjU5NzcsMjU5NzgsMjU5NzksMjU5ODAsMjU5ODEsMjU5ODIsMjU5ODMsMjU5ODQsMjU5ODUsMjU5ODYsMjU5ODcsMjU5ODgsMjU5ODksMjU5OTAsMjU5OTIsMjU5OTMsMjU5OTQsMjU5OTcsMjU5OTgsMjU5OTksMjYwMDIsMjYwMDQsMjYwMDUsMjYwMDYsMjYwMDgsMjYwMTAsMjYwMTMsMjYwMTQsMjYwMTYsMjYwMTgsMjYwMTksMjYwMjIsMjYwMjQsMjYwMjYsMjYwMjgsMjYwMzAsMjYwMzMsMjYwMzQsMjYwMzUsMjYwMzYsMjYwMzcsMjYwMzgsMjYwMzksMjYwNDAsMjYwNDIsMjYwNDMsMjYwNDYsMjYwNDcsMjYwNDgsMjYwNTAsMjYwNTUsMjYwNTYsMjYwNTcsMjYwNTgsMjYwNjEsMjYwNjQsMjYwNjUsMjYwNjcsMjYwNjgsMjYwNjksMjYwNzIsMjYwNzMsMjYwNzQsMjYwNzUsMjYwNzYsMjYwNzcsMjYwNzgsMjYwNzksMjYwODEsMjYwODMsMjYwODQsMjYwOTAsMjYwOTEsMjYwOTgsMjYwOTksMjYxMDAsMjYxMDEsMjYxMDQsMjYxMDUsMjYxMDcsMjYxMDgsMjYxMDksMjYxMTAsMjYxMTEsMjYxMTMsMjYxMTYsMjYxMTcsMjYxMTksMjYxMjAsMjYxMjEsMjYxMjMsMjYxMjUsMjYxMjgsMjYxMjksMjYxMzAsMjYxMzQsMjYxMzUsMjYxMzYsMjYxMzgsMjYxMzksMjYxNDAsMjYxNDIsMjYxNDUsMjYxNDYsMjYxNDcsMjYxNDgsMjYxNTAsMjYxNTMsMjYxNTQsMjYxNTUsMjYxNTYsMjYxNTgsMjYxNjAsMjYxNjIsMjYxNjMsMjYxNjcsMjYxNjgsMjYxNjksMjYxNzAsMjYxNzEsMjYxNzMsMjYxNzUsMjYxNzYsMjYxNzgsMjYxODAsMjYxODEsMjYxODIsMjYxODMsMjYxODQsMjYxODUsMjYxODYsMjYxODksMjYxOTAsMjYxOTIsMjYxOTMsMjYyMDAsMjYyMDEsMjYyMDMsMjYyMDQsMjYyMDUsMjYyMDYsMjYyMDgsMjYyMTAsMjYyMTEsMjYyMTMsMjYyMTUsMjYyMTcsMjYyMTgsMjYyMTksMjYyMjAsMjYyMjEsMjYyMjUsMjYyMjYsMjYyMjcsMjYyMjksMjYyMzIsMjYyMzMsMjYyMzUsMjYyMzYsMjYyMzcsMjYyMzksMjYyNDAsMjYyNDEsMjYyNDMsMjYyNDUsMjYyNDYsMjYyNDgsMjYyNDksMjYyNTAsMjYyNTEsMjYyNTMsMjYyNTQsMjYyNTUsMjYyNTYsMjYyNTgsMjYyNTksMjYyNjAsMjYyNjEsMjYyNjQsMjYyNjUsMjYyNjYsMjYyNjcsMjYyNjgsMjYyNzAsMjYyNzEsMjYyNzIsMjYyNzMsMjYyNzQsMjYyNzUsMjYyNzYsMjYyNzcsMjYyNzgsMjYyODEsMjYyODIsMjYyODMsMjYyODQsMjYyODUsMjYyODcsMjYyODgsMjYyODksMjYyOTAsMjYyOTEsMjYyOTMsMjYyOTQsMjYyOTUsMjYyOTYsMjYyOTgsMjYyOTksMjYzMDAsMjYzMDEsMjYzMDMsMjYzMDQsMjYzMDUsMjYzMDYsMjYzMDcsMjYzMDgsMjYzMDksMjYzMTAsMjYzMTEsMjYzMTIsMjYzMTMsMjYzMTQsMjYzMTUsMjYzMTYsMjYzMTcsMjYzMTgsMjYzMTksMjYzMjAsMjYzMjEsMjYzMjIsMjYzMjMsMjYzMjQsMjYzMjUsMjYzMjYsMjYzMjcsMjYzMjgsMjYzMzAsMjYzMzQsMjYzMzUsMjYzMzYsMjYzMzcsMjYzMzgsMjYzMzksMjYzNDAsMjYzNDEsMjYzNDMsMjYzNDQsMjYzNDYsMjYzNDcsMjYzNDgsMjYzNDksMjYzNTAsMjYzNTEsMjYzNTMsMjYzNTcsMjYzNTgsMjYzNjAsMjYzNjIsMjYzNjMsMjYzNjUsMjYzNjksMjYzNzAsMjYzNzEsMjYzNzIsMjYzNzMsMjYzNzQsMjYzNzUsMjYzODAsMjYzODIsMjYzODMsMjYzODUsMjYzODYsMjYzODcsMjYzOTAsMjYzOTIsMjYzOTMsMjYzOTQsMjYzOTYsMjYzOTgsMjY0MDAsMjY0MDEsMjY0MDIsMjY0MDMsMjY0MDQsMjY0MDUsMjY0MDcsMjY0MDksMjY0MTQsMjY0MTYsMjY0MTgsMjY0MTksMjY0MjIsMjY0MjMsMjY0MjQsMjY0MjUsMjY0MjcsMjY0MjgsMjY0MzAsMjY0MzEsMjY0MzMsMjY0MzYsMjY0MzcsMjY0MzksMjY0NDIsMjY0NDMsMjY0NDUsMjY0NTAsMjY0NTIsMjY0NTMsMjY0NTUsMjY0NTYsMjY0NTcsMjY0NTgsMjY0NTksMjY0NjEsMjY0NjYsMjY0NjcsMjY0NjgsMjY0NzAsMjY0NzEsMjY0NzUsMjY0NzYsMjY0NzgsMjY0ODEsMjY0ODQsMjY0ODYsMjY0ODgsMjY0ODksMjY0OTAsMjY0OTEsMjY0OTMsMjY0OTYsMjY0OTgsMjY0OTksMjY1MDEsMjY1MDIsMjY1MDQsMjY1MDYsMjY1MDgsMjY1MDksMjY1MTAsMjY1MTEsMjY1MTMsMjY1MTQsMjY1MTUsMjY1MTYsMjY1MTgsMjY1MjEsMjY1MjMsMjY1MjcsMjY1MjgsMjY1MjksMjY1MzIsMjY1MzQsMjY1MzcsMjY1NDAsMjY1NDIsMjY1NDUsMjY1NDYsMjY1NDgsMjY1NTMsMjY1NTQsMjY1NTUsMjY1NTYsMjY1NTcsMjY1NTgsMjY1NTksMjY1NjAsMjY1NjIsMjY1NjUsMjY1NjYsMjY1NjcsMjY1NjgsMjY1NjksMjY1NzAsMjY1NzEsMjY1NzIsMjY1NzMsMjY1NzQsMjY1ODEsMjY1ODIsMjY1ODMsMjY1ODcsMjY1OTEsMjY1OTMsMjY1OTUsMjY1OTYsMjY1OTgsMjY1OTksMjY2MDAsMjY2MDIsMjY2MDMsMjY2MDUsMjY2MDYsMjY2MTAsMjY2MTMsMjY2MTQsMjY2MTUsMjY2MTYsMjY2MTcsMjY2MTgsMjY2MTksMjY2MjAsMjY2MjIsMjY2MjUsMjY2MjYsMjY2MjcsMjY2MjgsMjY2MzAsMjY2MzcsMjY2NDAsMjY2NDIsMjY2NDQsMjY2NDUsMjY2NDgsMjY2NDksMjY2NTAsMjY2NTEsMjY2NTIsMjY2NTQsMjY2NTUsMjY2NTYsMjY2NTgsMjY2NTksMjY2NjAsMjY2NjEsMjY2NjIsMjY2NjMsMjY2NjQsMjY2NjcsMjY2NjgsMjY2NjksMjY2NzAsMjY2NzEsMjY2NzIsMjY2NzMsMjY2NzYsMjY2NzcsMjY2NzgsMjY2ODIsMjY2ODMsMjY2ODcsMjY2OTUsMjY2OTksMjY3MDEsMjY3MDMsMjY3MDYsMjY3MTAsMjY3MTEsMjY3MTIsMjY3MTMsMjY3MTQsMjY3MTUsMjY3MTYsMjY3MTcsMjY3MTgsMjY3MTksMjY3MzAsMjY3MzIsMjY3MzMsMjY3MzQsMjY3MzUsMjY3MzYsMjY3MzcsMjY3MzgsMjY3MzksMjY3NDEsMjY3NDQsMjY3NDUsMjY3NDYsMjY3NDcsMjY3NDgsMjY3NDksMjY3NTAsMjY3NTEsMjY3NTIsMjY3NTQsMjY3NTYsMjY3NTksMjY3NjAsMjY3NjEsMjY3NjIsMjY3NjMsMjY3NjQsMjY3NjUsMjY3NjYsMjY3NjgsMjY3NjksMjY3NzAsMjY3NzIsMjY3NzMsMjY3NzQsMjY3NzYsMjY3NzcsMjY3NzgsMjY3NzksMjY3ODAsMjY3ODEsMjY3ODIsMjY3ODMsMjY3ODQsMjY3ODUsMjY3ODcsMjY3ODgsMjY3ODksMjY3OTMsMjY3OTQsMjY3OTUsMjY3OTYsMjY3OTgsMjY4MDEsMjY4MDIsMjY4MDQsMjY4MDYsMjY4MDcsMjY4MDgsMjY4MDksMjY4MTAsMjY4MTEsMjY4MTIsMjY4MTMsMjY4MTQsMjY4MTUsMjY4MTcsMjY4MTksMjY4MjAsMjY4MjEsMjY4MjIsMjY4MjMsMjY4MjQsMjY4MjYsMjY4MjgsMjY4MzAsMjY4MzEsMjY4MzIsMjY4MzMsMjY4MzUsMjY4MzYsMjY4MzgsMjY4MzksMjY4NDEsMjY4NDMsMjY4NDQsMjY4NDUsMjY4NDYsMjY4NDcsMjY4NDksMjY4NTAsMjY4NTIsMjY4NTMsMjY4NTQsMjY4NTUsMjY4NTYsMjY4NTcsMjY4NTgsMjY4NTksMjY4NjAsMjY4NjEsMjY4NjMsMjY4NjYsMjY4NjcsMjY4NjgsMjY4NzAsMjY4NzEsMjY4NzIsMjY4NzUsMjY4NzcsMjY4NzgsMjY4NzksMjY4ODAsMjY4ODIsMjY4ODMsMjY4ODQsMjY4ODYsMjY4ODcsMjY4ODgsMjY4ODksMjY4OTAsMjY4OTIsMjY4OTUsMjY4OTcsMjY4OTksMjY5MDAsMjY5MDEsMjY5MDIsMjY5MDMsMjY5MDQsMjY5MDUsMjY5MDYsMjY5MDcsMjY5MDgsMjY5MDksMjY5MTAsMjY5MTMsMjY5MTQsMjY5MTUsMjY5MTcsMjY5MTgsMjY5MTksMjY5MjAsMjY5MjEsMjY5MjIsMjY5MjMsMjY5MjQsMjY5MjYsMjY5MjcsMjY5MjksMjY5MzAsMjY5MzEsMjY5MzMsMjY5MzQsMjY5MzUsMjY5MzYsMjY5MzgsMjY5MzksMjY5NDAsMjY5NDIsMjY5NDQsMjY5NDUsMjY5NDcsMjY5NDgsMjY5NDksMjY5NTAsMjY5NTEsMjY5NTIsMjY5NTMsMjY5NTQsMjY5NTUsMjY5NTYsMjY5NTcsMjY5NTgsMjY5NTksMjY5NjAsMjY5NjEsMjY5NjIsMjY5NjMsMjY5NjUsMjY5NjYsMjY5NjgsMjY5NjksMjY5NzEsMjY5NzIsMjY5NzUsMjY5NzcsMjY5NzgsMjY5ODAsMjY5ODEsMjY5ODMsMjY5ODQsMjY5ODUsMjY5ODYsMjY5ODgsMjY5ODksMjY5OTEsMjY5OTIsMjY5OTQsMjY5OTUsMjY5OTYsMjY5OTcsMjY5OTgsMjcwMDIsMjcwMDMsMjcwMDUsMjcwMDYsMjcwMDcsMjcwMDksMjcwMTEsMjcwMTMsMjcwMTgsMjcwMTksMjcwMjAsMjcwMjIsMjcwMjMsMjcwMjQsMjcwMjUsMjcwMjYsMjcwMjcsMjcwMzAsMjcwMzEsMjcwMzMsMjcwMzQsMjcwMzcsMjcwMzgsMjcwMzksMjcwNDAsMjcwNDEsMjcwNDIsMjcwNDMsMjcwNDQsMjcwNDUsMjcwNDYsMjcwNDksMjcwNTAsMjcwNTIsMjcwNTQsMjcwNTUsMjcwNTYsMjcwNTgsMjcwNTksMjcwNjEsMjcwNjIsMjcwNjQsMjcwNjUsMjcwNjYsMjcwNjgsMjcwNjksMjcwNzAsMjcwNzEsMjcwNzIsMjcwNzQsMjcwNzUsMjcwNzYsMjcwNzcsMjcwNzgsMjcwNzksMjcwODAsMjcwODEsMjcwODMsMjcwODUsMjcwODcsMjcwODksMjcwOTAsMjcwOTEsMjcwOTMsMjcwOTQsMjcwOTUsMjcwOTYsMjcwOTcsMjcwOTgsMjcxMDAsMjcxMDEsMjcxMDIsMjcxMDUsMjcxMDYsMjcxMDcsMjcxMDgsMjcxMDksMjcxMTAsMjcxMTEsMjcxMTIsMjcxMTMsMjcxMTQsMjcxMTUsMjcxMTYsMjcxMTgsMjcxMTksMjcxMjAsMjcxMjEsMjcxMjMsMjcxMjQsMjcxMjUsMjcxMjYsMjcxMjcsMjcxMjgsMjcxMjksMjcxMzAsMjcxMzEsMjcxMzIsMjcxMzQsMjcxMzYsMjcxMzcsMjcxMzgsMjcxMzksMjcxNDAsMjcxNDEsMjcxNDIsMjcxNDMsMjcxNDQsMjcxNDUsMjcxNDcsMjcxNDgsMjcxNDksMjcxNTAsMjcxNTEsMjcxNTIsMjcxNTMsMjcxNTQsMjcxNTUsMjcxNTYsMjcxNTcsMjcxNTgsMjcxNjEsMjcxNjIsMjcxNjMsMjcxNjQsMjcxNjUsMjcxNjYsMjcxNjgsMjcxNzAsMjcxNzEsMjcxNzIsMjcxNzMsMjcxNzQsMjcxNzUsMjcxNzcsMjcxNzksMjcxODAsMjcxODEsMjcxODIsMjcxODQsMjcxODYsMjcxODcsMjcxODgsMjcxOTAsMjcxOTEsMjcxOTIsMjcxOTMsMjcxOTQsMjcxOTUsMjcxOTYsMjcxOTksMjcyMDAsMjcyMDEsMjcyMDIsMjcyMDMsMjcyMDUsMjcyMDYsMjcyMDgsMjcyMDksMjcyMTAsMjcyMTEsMjcyMTIsMjcyMTMsMjcyMTQsMjcyMTUsMjcyMTcsMjcyMTgsMjcyMTksMjcyMjAsMjcyMjEsMjcyMjIsMjcyMjMsMjcyMjYsMjcyMjgsMjcyMjksMjcyMzAsMjcyMzEsMjcyMzIsMjcyMzQsMjcyMzUsMjcyMzYsMjcyMzgsMjcyMzksMjcyNDAsMjcyNDEsMjcyNDIsMjcyNDMsMjcyNDQsMjcyNDUsMjcyNDYsMjcyNDcsMjcyNDgsMjcyNTAsMjcyNTEsMjcyNTIsMjcyNTMsMjcyNTQsMjcyNTUsMjcyNTYsMjcyNTgsMjcyNTksMjcyNjEsMjcyNjIsMjcyNjMsMjcyNjUsMjcyNjYsMjcyNjcsMjcyNjksMjcyNzAsMjcyNzEsMjcyNzIsMjcyNzMsMjcyNzQsMjcyNzUsMjcyNzYsMjcyNzcsMjcyNzksMjcyODIsMjcyODMsMjcyODQsMjcyODUsMjcyODYsMjcyODgsMjcyODksMjcyOTAsMjcyOTEsMjcyOTIsMjcyOTMsMjcyOTQsMjcyOTUsMjcyOTcsMjcyOTgsMjcyOTksMjczMDAsMjczMDEsMjczMDIsMjczMDMsMjczMDQsMjczMDYsMjczMDksMjczMTAsMjczMTEsMjczMTIsMjczMTMsMjczMTQsMjczMTUsMjczMTYsMjczMTcsMjczMTgsMjczMTksMjczMjAsMjczMjEsMjczMjIsMjczMjMsMjczMjQsMjczMjUsMjczMjYsMjczMjcsMjczMjgsMjczMjksMjczMzAsMjczMzEsMjczMzIsMjczMzMsMjczMzQsMjczMzUsMjczMzYsMjczMzcsMjczMzgsMjczMzksMjczNDAsMjczNDEsMjczNDIsMjczNDMsMjczNDQsMjczNDUsMjczNDYsMjczNDcsMjczNDgsMjczNDksMjczNTAsMjczNTEsMjczNTIsMjczNTMsMjczNTQsMjczNTUsMjczNTYsMjczNTcsMjczNTgsMjczNTksMjczNjAsMjczNjEsMjczNjIsMjczNjMsMjczNjQsMjczNjUsMjczNjYsMjczNjcsMjczNjgsMjczNjksMjczNzAsMjczNzEsMjczNzIsMjczNzMsMjczNzQsMjczNzUsMjczNzYsMjczNzcsMjczNzgsMjczNzksMjczODAsMjczODEsMjczODIsMjczODMsMjczODQsMjczODUsMjczODYsMjczODcsMjczODgsMjczODksMjczOTAsMjczOTEsMjczOTIsMjczOTMsMjczOTQsMjczOTUsMjczOTYsMjczOTcsMjczOTgsMjczOTksMjc0MDAsMjc0MDEsMjc0MDIsMjc0MDMsMjc0MDQsMjc0MDUsMjc0MDYsMjc0MDcsMjc0MDgsMjc0MDksMjc0MTAsMjc0MTEsMjc0MTIsMjc0MTMsMjc0MTQsMjc0MTUsMjc0MTYsMjc0MTcsMjc0MTgsMjc0MTksMjc0MjAsMjc0MjEsMjc0MjIsMjc0MjMsMjc0MjksMjc0MzAsMjc0MzIsMjc0MzMsMjc0MzQsMjc0MzUsMjc0MzYsMjc0MzcsMjc0MzgsMjc0MzksMjc0NDAsMjc0NDEsMjc0NDMsMjc0NDQsMjc0NDUsMjc0NDYsMjc0NDgsMjc0NTEsMjc0NTIsMjc0NTMsMjc0NTUsMjc0NTYsMjc0NTcsMjc0NTgsMjc0NjAsMjc0NjEsMjc0NjQsMjc0NjYsMjc0NjcsMjc0NjksMjc0NzAsMjc0NzEsMjc0NzIsMjc0NzMsMjc0NzQsMjc0NzUsMjc0NzYsMjc0NzcsMjc0NzgsMjc0NzksMjc0ODAsMjc0ODIsMjc0ODMsMjc0ODQsMjc0ODUsMjc0ODYsMjc0ODcsMjc0ODgsMjc0ODksMjc0OTYsMjc0OTcsMjc0OTksMjc1MDAsMjc1MDEsMjc1MDIsMjc1MDMsMjc1MDQsMjc1MDUsMjc1MDYsMjc1MDcsMjc1MDgsMjc1MDksMjc1MTAsMjc1MTEsMjc1MTIsMjc1MTQsMjc1MTcsMjc1MTgsMjc1MTksMjc1MjAsMjc1MjUsMjc1MjgsMjc1MzIsMjc1MzQsMjc1MzUsMjc1MzYsMjc1MzcsMjc1NDAsMjc1NDEsMjc1NDMsMjc1NDQsMjc1NDUsMjc1NDgsMjc1NDksMjc1NTAsMjc1NTEsMjc1NTIsMjc1NTQsMjc1NTUsMjc1NTYsMjc1NTcsMjc1NTgsMjc1NTksMjc1NjAsMjc1NjEsMjc1NjMsMjc1NjQsMjc1NjUsMjc1NjYsMjc1NjcsMjc1NjgsMjc1NjksMjc1NzAsMjc1NzQsMjc1NzYsMjc1NzcsMjc1NzgsMjc1NzksMjc1ODAsMjc1ODEsMjc1ODIsMjc1ODQsMjc1ODcsMjc1ODgsMjc1OTAsMjc1OTEsMjc1OTIsMjc1OTMsMjc1OTQsMjc1OTYsMjc1OTgsMjc2MDAsMjc2MDEsMjc2MDgsMjc2MTAsMjc2MTIsMjc2MTMsMjc2MTQsMjc2MTUsMjc2MTYsMjc2MTgsMjc2MTksMjc2MjAsMjc2MjEsMjc2MjIsMjc2MjMsMjc2MjQsMjc2MjUsMjc2MjgsMjc2MjksMjc2MzAsMjc2MzIsMjc2MzMsMjc2MzQsMjc2MzYsMjc2MzgsMjc2MzksMjc2NDAsMjc2NDIsMjc2NDMsMjc2NDQsMjc2NDYsMjc2NDcsMjc2NDgsMjc2NDksMjc2NTAsMjc2NTEsMjc2NTIsMjc2NTYsMjc2NTcsMjc2NTgsMjc2NTksMjc2NjAsMjc2NjIsMjc2NjYsMjc2NzEsMjc2NzYsMjc2NzcsMjc2NzgsMjc2ODAsMjc2ODMsMjc2ODUsMjc2OTEsMjc2OTIsMjc2OTMsMjc2OTcsMjc2OTksMjc3MDIsMjc3MDMsMjc3MDUsMjc3MDYsMjc3MDcsMjc3MDgsMjc3MTAsMjc3MTEsMjc3MTUsMjc3MTYsMjc3MTcsMjc3MjAsMjc3MjMsMjc3MjQsMjc3MjUsMjc3MjYsMjc3MjcsMjc3MjksMjc3MzAsMjc3MzEsMjc3MzQsMjc3MzYsMjc3MzcsMjc3MzgsMjc3NDYsMjc3NDcsMjc3NDksMjc3NTAsMjc3NTEsMjc3NTUsMjc3NTYsMjc3NTcsMjc3NTgsMjc3NTksMjc3NjEsMjc3NjMsMjc3NjUsMjc3NjcsMjc3NjgsMjc3NzAsMjc3NzEsMjc3NzIsMjc3NzUsMjc3NzYsMjc3ODAsMjc3ODMsMjc3ODYsMjc3ODcsMjc3ODksMjc3OTAsMjc3OTMsMjc3OTQsMjc3OTcsMjc3OTgsMjc3OTksMjc4MDAsMjc4MDIsMjc4MDQsMjc4MDUsMjc4MDYsMjc4MDgsMjc4MTAsMjc4MTYsMjc4MjAsMjc4MjMsMjc4MjQsMjc4MjgsMjc4MjksMjc4MzAsMjc4MzEsMjc4MzQsMjc4NDAsMjc4NDEsMjc4NDIsMjc4NDMsMjc4NDYsMjc4NDcsMjc4NDgsMjc4NTEsMjc4NTMsMjc4NTQsMjc4NTUsMjc4NTcsMjc4NTgsMjc4NjQsMjc4NjUsMjc4NjYsMjc4NjgsMjc4NjksMjc4NzEsMjc4NzYsMjc4NzgsMjc4NzksMjc4ODEsMjc4ODQsMjc4ODUsMjc4OTAsMjc4OTIsMjc4OTcsMjc5MDMsMjc5MDQsMjc5MDYsMjc5MDcsMjc5MDksMjc5MTAsMjc5MTIsMjc5MTMsMjc5MTQsMjc5MTcsMjc5MTksMjc5MjAsMjc5MjEsMjc5MjMsMjc5MjQsMjc5MjUsMjc5MjYsMjc5MjgsMjc5MzIsMjc5MzMsMjc5MzUsMjc5MzYsMjc5MzcsMjc5MzgsMjc5MzksMjc5NDAsMjc5NDIsMjc5NDQsMjc5NDUsMjc5NDgsMjc5NDksMjc5NTEsMjc5NTIsMjc5NTYsMjc5NTgsMjc5NTksMjc5NjAsMjc5NjIsMjc5NjcsMjc5NjgsMjc5NzAsMjc5NzIsMjc5NzcsMjc5ODAsMjc5ODQsMjc5ODksMjc5OTAsMjc5OTEsMjc5OTIsMjc5OTUsMjc5OTcsMjc5OTksMjgwMDEsMjgwMDIsMjgwMDQsMjgwMDUsMjgwMDcsMjgwMDgsMjgwMTEsMjgwMTIsMjgwMTMsMjgwMTYsMjgwMTcsMjgwMTgsMjgwMTksMjgwMjEsMjgwMjIsMjgwMjUsMjgwMjYsMjgwMjcsMjgwMjksMjgwMzAsMjgwMzEsMjgwMzIsMjgwMzMsMjgwMzUsMjgwMzYsMjgwMzgsMjgwMzksMjgwNDIsMjgwNDMsMjgwNDUsMjgwNDcsMjgwNDgsMjgwNTAsMjgwNTQsMjgwNTUsMjgwNTYsMjgwNTcsMjgwNTgsMjgwNjAsMjgwNjYsMjgwNjksMjgwNzYsMjgwNzcsMjgwODAsMjgwODEsMjgwODMsMjgwODQsMjgwODYsMjgwODcsMjgwODksMjgwOTAsMjgwOTEsMjgwOTIsMjgwOTMsMjgwOTQsMjgwOTcsMjgwOTgsMjgwOTksMjgxMDQsMjgxMDUsMjgxMDYsMjgxMDksMjgxMTAsMjgxMTEsMjgxMTIsMjgxMTQsMjgxMTUsMjgxMTYsMjgxMTcsMjgxMTksMjgxMjIsMjgxMjMsMjgxMjQsMjgxMjcsMjgxMzAsMjgxMzEsMjgxMzMsMjgxMzUsMjgxMzYsMjgxMzcsMjgxMzgsMjgxNDEsMjgxNDMsMjgxNDQsMjgxNDYsMjgxNDgsMjgxNDksMjgxNTAsMjgxNTIsMjgxNTQsMjgxNTcsMjgxNTgsMjgxNTksMjgxNjAsMjgxNjEsMjgxNjIsMjgxNjMsMjgxNjQsMjgxNjYsMjgxNjcsMjgxNjgsMjgxNjksMjgxNzEsMjgxNzUsMjgxNzgsMjgxNzksMjgxODEsMjgxODQsMjgxODUsMjgxODcsMjgxODgsMjgxOTAsMjgxOTEsMjgxOTQsMjgxOTgsMjgxOTksMjgyMDAsMjgyMDIsMjgyMDQsMjgyMDYsMjgyMDgsMjgyMDksMjgyMTEsMjgyMTMsMjgyMTQsMjgyMTUsMjgyMTcsMjgyMTksMjgyMjAsMjgyMjEsMjgyMjIsMjgyMjMsMjgyMjQsMjgyMjUsMjgyMjYsMjgyMjksMjgyMzAsMjgyMzEsMjgyMzIsMjgyMzMsMjgyMzQsMjgyMzUsMjgyMzYsMjgyMzksMjgyNDAsMjgyNDEsMjgyNDIsMjgyNDUsMjgyNDcsMjgyNDksMjgyNTAsMjgyNTIsMjgyNTMsMjgyNTQsMjgyNTYsMjgyNTcsMjgyNTgsMjgyNTksMjgyNjAsMjgyNjEsMjgyNjIsMjgyNjMsMjgyNjQsMjgyNjUsMjgyNjYsMjgyNjgsMjgyNjksMjgyNzEsMjgyNzIsMjgyNzMsMjgyNzQsMjgyNzUsMjgyNzYsMjgyNzcsMjgyNzgsMjgyNzksMjgyODAsMjgyODEsMjgyODIsMjgyODMsMjgyODQsMjgyODUsMjgyODgsMjgyODksMjgyOTAsMjgyOTIsMjgyOTUsMjgyOTYsMjgyOTgsMjgyOTksMjgzMDAsMjgzMDEsMjgzMDIsMjgzMDUsMjgzMDYsMjgzMDcsMjgzMDgsMjgzMDksMjgzMTAsMjgzMTEsMjgzMTMsMjgzMTQsMjgzMTUsMjgzMTcsMjgzMTgsMjgzMjAsMjgzMjEsMjgzMjMsMjgzMjQsMjgzMjYsMjgzMjgsMjgzMjksMjgzMzEsMjgzMzIsMjgzMzMsMjgzMzQsMjgzMzYsMjgzMzksMjgzNDEsMjgzNDQsMjgzNDUsMjgzNDgsMjgzNTAsMjgzNTEsMjgzNTIsMjgzNTUsMjgzNTYsMjgzNTcsMjgzNTgsMjgzNjAsMjgzNjEsMjgzNjIsMjgzNjQsMjgzNjUsMjgzNjYsMjgzNjgsMjgzNzAsMjgzNzQsMjgzNzYsMjgzNzcsMjgzNzksMjgzODAsMjgzODEsMjgzODcsMjgzOTEsMjgzOTQsMjgzOTUsMjgzOTYsMjgzOTcsMjgzOTgsMjgzOTksMjg0MDAsMjg0MDEsMjg0MDIsMjg0MDMsMjg0MDUsMjg0MDYsMjg0MDcsMjg0MDgsMjg0MTAsMjg0MTEsMjg0MTIsMjg0MTMsMjg0MTQsMjg0MTUsMjg0MTYsMjg0MTcsMjg0MTksMjg0MjAsMjg0MjEsMjg0MjMsMjg0MjQsMjg0MjYsMjg0MjcsMjg0MjgsMjg0MjksMjg0MzAsMjg0MzIsMjg0MzMsMjg0MzQsMjg0MzgsMjg0MzksMjg0NDAsMjg0NDEsMjg0NDIsMjg0NDMsMjg0NDQsMjg0NDUsMjg0NDYsMjg0NDcsMjg0NDksMjg0NTAsMjg0NTEsMjg0NTMsMjg0NTQsMjg0NTUsMjg0NTYsMjg0NjAsMjg0NjIsMjg0NjQsMjg0NjYsMjg0NjgsMjg0NjksMjg0NzEsMjg0NzIsMjg0NzMsMjg0NzQsMjg0NzUsMjg0NzYsMjg0NzcsMjg0NzksMjg0ODAsMjg0ODEsMjg0ODIsMjg0ODMsMjg0ODQsMjg0ODUsMjg0ODgsMjg0ODksMjg0OTAsMjg0OTIsMjg0OTQsMjg0OTUsMjg0OTYsMjg0OTcsMjg0OTgsMjg0OTksMjg1MDAsMjg1MDEsMjg1MDIsMjg1MDMsMjg1MDUsMjg1MDYsMjg1MDcsMjg1MDksMjg1MTEsMjg1MTIsMjg1MTMsMjg1MTUsMjg1MTYsMjg1MTcsMjg1MTksMjg1MjAsMjg1MjEsMjg1MjIsMjg1MjMsMjg1MjQsMjg1MjcsMjg1MjgsMjg1MjksMjg1MzEsMjg1MzMsMjg1MzQsMjg1MzUsMjg1MzcsMjg1MzksMjg1NDEsMjg1NDIsMjg1NDMsMjg1NDQsMjg1NDUsMjg1NDYsMjg1NDcsMjg1NDksMjg1NTAsMjg1NTEsMjg1NTQsMjg1NTUsMjg1NTksMjg1NjAsMjg1NjEsMjg1NjIsMjg1NjMsMjg1NjQsMjg1NjUsMjg1NjYsMjg1NjcsMjg1NjgsMjg1NjksMjg1NzAsMjg1NzEsMjg1NzMsMjg1NzQsMjg1NzUsMjg1NzYsMjg1NzgsMjg1NzksMjg1ODAsMjg1ODEsMjg1ODIsMjg1ODQsMjg1ODUsMjg1ODYsMjg1ODcsMjg1ODgsMjg1ODksMjg1OTAsMjg1OTEsMjg1OTIsMjg1OTMsMjg1OTQsMjg1OTYsMjg1OTcsMjg1OTksMjg2MDAsMjg2MDIsMjg2MDMsMjg2MDQsMjg2MDUsMjg2MDYsMjg2MDcsMjg2MDksMjg2MTEsMjg2MTIsMjg2MTMsMjg2MTQsMjg2MTUsMjg2MTYsMjg2MTgsMjg2MTksMjg2MjAsMjg2MjEsMjg2MjIsMjg2MjMsMjg2MjQsMjg2MjcsMjg2MjgsMjg2MjksMjg2MzAsMjg2MzEsMjg2MzIsMjg2MzMsMjg2MzQsMjg2MzUsMjg2MzYsMjg2MzcsMjg2MzksMjg2NDIsMjg2NDMsMjg2NDQsMjg2NDUsMjg2NDYsMjg2NDcsMjg2NDgsMjg2NDksMjg2NTAsMjg2NTEsMjg2NTIsMjg2NTMsMjg2NTYsMjg2NTcsMjg2NTgsMjg2NTksMjg2NjAsMjg2NjEsMjg2NjIsMjg2NjMsMjg2NjQsMjg2NjUsMjg2NjYsMjg2NjcsMjg2NjgsMjg2NjksMjg2NzAsMjg2NzEsMjg2NzIsMjg2NzMsMjg2NzQsMjg2NzUsMjg2NzYsMjg2NzcsMjg2NzgsMjg2NzksMjg2ODAsMjg2ODEsMjg2ODIsMjg2ODMsMjg2ODQsMjg2ODUsMjg2ODYsMjg2ODcsMjg2ODgsMjg2OTAsMjg2OTEsMjg2OTIsMjg2OTMsMjg2OTQsMjg2OTUsMjg2OTYsMjg2OTcsMjg3MDAsMjg3MDEsMjg3MDIsMjg3MDMsMjg3MDQsMjg3MDUsMjg3MDYsMjg3MDgsMjg3MDksMjg3MTAsMjg3MTEsMjg3MTIsMjg3MTMsMjg3MTQsMjg3MTUsMjg3MTYsMjg3MTcsMjg3MTgsMjg3MTksMjg3MjAsMjg3MjEsMjg3MjIsMjg3MjMsMjg3MjQsMjg3MjYsMjg3MjcsMjg3MjgsMjg3MzAsMjg3MzEsMjg3MzIsMjg3MzMsMjg3MzQsMjg3MzUsMjg3MzYsMjg3MzcsMjg3MzgsMjg3MzksMjg3NDAsMjg3NDEsMjg3NDIsMjg3NDMsMjg3NDQsMjg3NDUsMjg3NDYsMjg3NDcsMjg3NDksMjg3NTAsMjg3NTIsMjg3NTMsMjg3NTQsMjg3NTUsMjg3NTYsMjg3NTcsMjg3NTgsMjg3NTksMjg3NjAsMjg3NjEsMjg3NjIsMjg3NjMsMjg3NjQsMjg3NjUsMjg3NjcsMjg3NjgsMjg3NjksMjg3NzAsMjg3NzEsMjg3NzIsMjg3NzMsMjg3NzQsMjg3NzUsMjg3NzYsMjg3NzcsMjg3NzgsMjg3ODIsMjg3ODUsMjg3ODYsMjg3ODcsMjg3ODgsMjg3OTEsMjg3OTMsMjg3OTQsMjg3OTUsMjg3OTcsMjg4MDEsMjg4MDIsMjg4MDMsMjg4MDQsMjg4MDYsMjg4MDcsMjg4MDgsMjg4MTEsMjg4MTIsMjg4MTMsMjg4MTUsMjg4MTYsMjg4MTcsMjg4MTksMjg4MjMsMjg4MjQsMjg4MjYsMjg4MjcsMjg4MzAsMjg4MzEsMjg4MzIsMjg4MzMsMjg4MzQsMjg4MzUsMjg4MzYsMjg4MzcsMjg4MzgsMjg4MzksMjg4NDAsMjg4NDEsMjg4NDIsMjg4NDgsMjg4NTAsMjg4NTIsMjg4NTMsMjg4NTQsMjg4NTgsMjg4NjIsMjg4NjMsMjg4NjgsMjg4NjksMjg4NzAsMjg4NzEsMjg4NzMsMjg4NzUsMjg4NzYsMjg4NzcsMjg4NzgsMjg4NzksMjg4ODAsMjg4ODEsMjg4ODIsMjg4ODMsMjg4ODQsMjg4ODUsMjg4ODYsMjg4ODcsMjg4OTAsMjg4OTIsMjg4OTMsMjg4OTQsMjg4OTYsMjg4OTcsMjg4OTgsMjg4OTksMjg5MDEsMjg5MDYsMjg5MTAsMjg5MTIsMjg5MTMsMjg5MTQsMjg5MTUsMjg5MTYsMjg5MTcsMjg5MTgsMjg5MjAsMjg5MjIsMjg5MjMsMjg5MjQsMjg5MjYsMjg5MjcsMjg5MjgsMjg5MjksMjg5MzAsMjg5MzEsMjg5MzIsMjg5MzMsMjg5MzQsMjg5MzUsMjg5MzYsMjg5MzksMjg5NDAsMjg5NDEsMjg5NDIsMjg5NDMsMjg5NDUsMjg5NDYsMjg5NDgsMjg5NTEsMjg5NTUsMjg5NTYsMjg5NTcsMjg5NTgsMjg5NTksMjg5NjAsMjg5NjEsMjg5NjIsMjg5NjMsMjg5NjQsMjg5NjUsMjg5NjcsMjg5NjgsMjg5NjksMjg5NzAsMjg5NzEsMjg5NzIsMjg5NzMsMjg5NzQsMjg5NzgsMjg5NzksMjg5ODAsMjg5ODEsMjg5ODMsMjg5ODQsMjg5ODUsMjg5ODYsMjg5ODcsMjg5ODgsMjg5ODksMjg5OTAsMjg5OTEsMjg5OTIsMjg5OTMsMjg5OTQsMjg5OTUsMjg5OTYsMjg5OTgsMjg5OTksMjkwMDAsMjkwMDEsMjkwMDMsMjkwMDUsMjkwMDcsMjkwMDgsMjkwMDksMjkwMTAsMjkwMTEsMjkwMTIsMjkwMTMsMjkwMTQsMjkwMTUsMjkwMTYsMjkwMTcsMjkwMTgsMjkwMTksMjkwMjEsMjkwMjMsMjkwMjQsMjkwMjUsMjkwMjYsMjkwMjcsMjkwMjksMjkwMzMsMjkwMzQsMjkwMzUsMjkwMzYsMjkwMzcsMjkwMzksMjkwNDAsMjkwNDEsMjkwNDQsMjkwNDUsMjkwNDYsMjkwNDcsMjkwNDksMjkwNTEsMjkwNTIsMjkwNTQsMjkwNTUsMjkwNTYsMjkwNTcsMjkwNTgsMjkwNTksMjkwNjEsMjkwNjIsMjkwNjMsMjkwNjQsMjkwNjUsMjkwNjcsMjkwNjgsMjkwNjksMjkwNzAsMjkwNzIsMjkwNzMsMjkwNzQsMjkwNzUsMjkwNzcsMjkwNzgsMjkwNzksMjkwODIsMjkwODMsMjkwODQsMjkwODUsMjkwODYsMjkwODksMjkwOTAsMjkwOTEsMjkwOTIsMjkwOTMsMjkwOTQsMjkwOTUsMjkwOTcsMjkwOTgsMjkwOTksMjkxMDEsMjkxMDIsMjkxMDMsMjkxMDQsMjkxMDUsMjkxMDYsMjkxMDgsMjkxMTAsMjkxMTEsMjkxMTIsMjkxMTQsMjkxMTUsMjkxMTYsMjkxMTcsMjkxMTgsMjkxMTksMjkxMjAsMjkxMjEsMjkxMjIsMjkxMjQsMjkxMjUsMjkxMjYsMjkxMjcsMjkxMjgsMjkxMjksMjkxMzAsMjkxMzEsMjkxMzIsMjkxMzMsMjkxMzUsMjkxMzYsMjkxMzcsMjkxMzgsMjkxMzksMjkxNDIsMjkxNDMsMjkxNDQsMjkxNDUsMjkxNDYsMjkxNDcsMjkxNDgsMjkxNDksMjkxNTAsMjkxNTEsMjkxNTMsMjkxNTQsMjkxNTUsMjkxNTYsMjkxNTgsMjkxNjAsMjkxNjEsMjkxNjIsMjkxNjMsMjkxNjQsMjkxNjUsMjkxNjcsMjkxNjgsMjkxNjksMjkxNzAsMjkxNzEsMjkxNzIsMjkxNzMsMjkxNzQsMjkxNzUsMjkxNzYsMjkxNzgsMjkxNzksMjkxODAsMjkxODEsMjkxODIsMjkxODMsMjkxODQsMjkxODUsMjkxODYsMjkxODcsMjkxODgsMjkxODksMjkxOTEsMjkxOTIsMjkxOTMsMjkxOTQsMjkxOTUsMjkxOTYsMjkxOTcsMjkxOTgsMjkxOTksMjkyMDAsMjkyMDEsMjkyMDIsMjkyMDMsMjkyMDQsMjkyMDUsMjkyMDYsMjkyMDcsMjkyMDgsMjkyMDksMjkyMTAsMjkyMTEsMjkyMTIsMjkyMTQsMjkyMTUsMjkyMTYsMjkyMTcsMjkyMTgsMjkyMTksMjkyMjAsMjkyMjEsMjkyMjIsMjkyMjMsMjkyMjUsMjkyMjcsMjkyMjksMjkyMzAsMjkyMzEsMjkyMzQsMjkyMzUsMjkyMzYsMjkyNDIsMjkyNDQsMjkyNDYsMjkyNDgsMjkyNDksMjkyNTAsMjkyNTEsMjkyNTIsMjkyNTMsMjkyNTQsMjkyNTcsMjkyNTgsMjkyNTksMjkyNjIsMjkyNjMsMjkyNjQsMjkyNjUsMjkyNjcsMjkyNjgsMjkyNjksMjkyNzEsMjkyNzIsMjkyNzQsMjkyNzYsMjkyNzgsMjkyODAsMjkyODMsMjkyODQsMjkyODUsMjkyODgsMjkyOTAsMjkyOTEsMjkyOTIsMjkyOTMsMjkyOTYsMjkyOTcsMjkyOTksMjkzMDAsMjkzMDIsMjkzMDMsMjkzMDQsMjkzMDcsMjkzMDgsMjkzMDksMjkzMTQsMjkzMTUsMjkzMTcsMjkzMTgsMjkzMTksMjkzMjAsMjkzMjEsMjkzMjQsMjkzMjYsMjkzMjgsMjkzMjksMjkzMzEsMjkzMzIsMjkzMzMsMjkzMzQsMjkzMzUsMjkzMzYsMjkzMzcsMjkzMzgsMjkzMzksMjkzNDAsMjkzNDEsMjkzNDIsMjkzNDQsMjkzNDUsMjkzNDYsMjkzNDcsMjkzNDgsMjkzNDksMjkzNTAsMjkzNTEsMjkzNTIsMjkzNTMsMjkzNTQsMjkzNTUsMjkzNTgsMjkzNjEsMjkzNjIsMjkzNjMsMjkzNjUsMjkzNzAsMjkzNzEsMjkzNzIsMjkzNzMsMjkzNzQsMjkzNzUsMjkzNzYsMjkzODEsMjkzODIsMjkzODMsMjkzODUsMjkzODYsMjkzODcsMjkzODgsMjkzOTEsMjkzOTMsMjkzOTUsMjkzOTYsMjkzOTcsMjkzOTgsMjk0MDAsMjk0MDIsMjk0MDMsNTg1NjYsNTg1NjcsNTg1NjgsNTg1NjksNTg1NzAsNTg1NzEsNTg1NzIsNTg1NzMsNTg1NzQsNTg1NzUsNTg1NzYsNTg1NzcsNTg1NzgsNTg1NzksNTg1ODAsNTg1ODEsNTg1ODIsNTg1ODMsNTg1ODQsNTg1ODUsNTg1ODYsNTg1ODcsNTg1ODgsNTg1ODksNTg1OTAsNTg1OTEsNTg1OTIsNTg1OTMsNTg1OTQsNTg1OTUsNTg1OTYsNTg1OTcsNTg1OTgsNTg1OTksNTg2MDAsNTg2MDEsNTg2MDIsNTg2MDMsNTg2MDQsNTg2MDUsNTg2MDYsNTg2MDcsNTg2MDgsNTg2MDksNTg2MTAsNTg2MTEsNTg2MTIsNTg2MTMsNTg2MTQsNTg2MTUsNTg2MTYsNTg2MTcsNTg2MTgsNTg2MTksNTg2MjAsNTg2MjEsNTg2MjIsNTg2MjMsNTg2MjQsNTg2MjUsNTg2MjYsNTg2MjcsNTg2MjgsNTg2MjksNTg2MzAsNTg2MzEsNTg2MzIsNTg2MzMsNTg2MzQsNTg2MzUsNTg2MzYsNTg2MzcsNTg2MzgsNTg2MzksNTg2NDAsNTg2NDEsNTg2NDIsNTg2NDMsNTg2NDQsNTg2NDUsNTg2NDYsNTg2NDcsNTg2NDgsNTg2NDksNTg2NTAsNTg2NTEsNTg2NTIsNTg2NTMsNTg2NTQsNTg2NTUsNTg2NTYsNTg2NTcsNTg2NTgsNTg2NTksNTg2NjAsNTg2NjEsMTIyODgsMTIyODksMTIyOTAsMTgzLDcxMyw3MTEsMTY4LDEyMjkxLDEyMjkzLDgyMTIsNjUzNzQsODIxNCw4MjMwLDgyMTYsODIxNyw4MjIwLDgyMjEsMTIzMDgsMTIzMDksMTIyOTYsMTIyOTcsMTIyOTgsMTIyOTksMTIzMDAsMTIzMDEsMTIzMDIsMTIzMDMsMTIzMTAsMTIzMTEsMTIzMDQsMTIzMDUsMTc3LDIxNSwyNDcsODc1OCw4NzQzLDg3NDQsODcyMSw4NzE5LDg3NDYsODc0NSw4NzEyLDg3NTksODczMCw4ODY5LDg3NDEsODczNiw4OTc4LDg4NTcsODc0Nyw4NzUwLDg4MDEsODc4MCw4Nzc2LDg3NjUsODczMyw4ODAwLDg4MTQsODgxNSw4ODA0LDg4MDUsODczNCw4NzU3LDg3NTYsOTc5NCw5NzkyLDE3Niw4MjQyLDgyNDMsODQ1MSw2NTI4NCwxNjQsNjU1MDQsNjU1MDUsODI0MCwxNjcsODQ3MCw5NzM0LDk3MzMsOTY3NSw5Njc5LDk2NzgsOTY3MSw5NjcwLDk2MzMsOTYzMiw5NjUxLDk2NTAsODI1MSw4NTk0LDg1OTIsODU5Myw4NTk1LDEyMzA3LDU4NjYyLDU4NjYzLDU4NjY0LDU4NjY1LDU4NjY2LDU4NjY3LDU4NjY4LDU4NjY5LDU4NjcwLDU4NjcxLDU4NjcyLDU4NjczLDU4Njc0LDU4Njc1LDU4Njc2LDU4Njc3LDU4Njc4LDU4Njc5LDU4NjgwLDU4NjgxLDU4NjgyLDU4NjgzLDU4Njg0LDU4Njg1LDU4Njg2LDU4Njg3LDU4Njg4LDU4Njg5LDU4NjkwLDU4NjkxLDU4NjkyLDU4NjkzLDU4Njk0LDU4Njk1LDU4Njk2LDU4Njk3LDU4Njk4LDU4Njk5LDU4NzAwLDU4NzAxLDU4NzAyLDU4NzAzLDU4NzA0LDU4NzA1LDU4NzA2LDU4NzA3LDU4NzA4LDU4NzA5LDU4NzEwLDU4NzExLDU4NzEyLDU4NzEzLDU4NzE0LDU4NzE1LDU4NzE2LDU4NzE3LDU4NzE4LDU4NzE5LDU4NzIwLDU4NzIxLDU4NzIyLDU4NzIzLDU4NzI0LDU4NzI1LDU4NzI2LDU4NzI3LDU4NzI4LDU4NzI5LDU4NzMwLDU4NzMxLDU4NzMyLDU4NzMzLDU4NzM0LDU4NzM1LDU4NzM2LDU4NzM3LDU4NzM4LDU4NzM5LDU4NzQwLDU4NzQxLDU4NzQyLDU4NzQzLDU4NzQ0LDU4NzQ1LDU4NzQ2LDU4NzQ3LDU4NzQ4LDU4NzQ5LDU4NzUwLDU4NzUxLDU4NzUyLDU4NzUzLDU4NzU0LDU4NzU1LDU4NzU2LDU4NzU3LDg1NjAsODU2MSw4NTYyLDg1NjMsODU2NCw4NTY1LDg1NjYsODU2Nyw4NTY4LDg1NjksNTkyMzgsNTkyMzksNTkyNDAsNTkyNDEsNTkyNDIsNTkyNDMsOTM1Miw5MzUzLDkzNTQsOTM1NSw5MzU2LDkzNTcsOTM1OCw5MzU5LDkzNjAsOTM2MSw5MzYyLDkzNjMsOTM2NCw5MzY1LDkzNjYsOTM2Nyw5MzY4LDkzNjksOTM3MCw5MzcxLDkzMzIsOTMzMyw5MzM0LDkzMzUsOTMzNiw5MzM3LDkzMzgsOTMzOSw5MzQwLDkzNDEsOTM0Miw5MzQzLDkzNDQsOTM0NSw5MzQ2LDkzNDcsOTM0OCw5MzQ5LDkzNTAsOTM1MSw5MzEyLDkzMTMsOTMxNCw5MzE1LDkzMTYsOTMxNyw5MzE4LDkzMTksOTMyMCw5MzIxLDgzNjQsNTkyNDUsMTI4MzIsMTI4MzMsMTI4MzQsMTI4MzUsMTI4MzYsMTI4MzcsMTI4MzgsMTI4MzksMTI4NDAsMTI4NDEsNTkyNDYsNTkyNDcsODU0NCw4NTQ1LDg1NDYsODU0Nyw4NTQ4LDg1NDksODU1MCw4NTUxLDg1NTIsODU1Myw4NTU0LDg1NTUsNTkyNDgsNTkyNDksNTg3NTgsNTg3NTksNTg3NjAsNTg3NjEsNTg3NjIsNTg3NjMsNTg3NjQsNTg3NjUsNTg3NjYsNTg3NjcsNTg3NjgsNTg3NjksNTg3NzAsNTg3NzEsNTg3NzIsNTg3NzMsNTg3NzQsNTg3NzUsNTg3NzYsNTg3NzcsNTg3NzgsNTg3NzksNTg3ODAsNTg3ODEsNTg3ODIsNTg3ODMsNTg3ODQsNTg3ODUsNTg3ODYsNTg3ODcsNTg3ODgsNTg3ODksNTg3OTAsNTg3OTEsNTg3OTIsNTg3OTMsNTg3OTQsNTg3OTUsNTg3OTYsNTg3OTcsNTg3OTgsNTg3OTksNTg4MDAsNTg4MDEsNTg4MDIsNTg4MDMsNTg4MDQsNTg4MDUsNTg4MDYsNTg4MDcsNTg4MDgsNTg4MDksNTg4MTAsNTg4MTEsNTg4MTIsNTg4MTMsNTg4MTQsNTg4MTUsNTg4MTYsNTg4MTcsNTg4MTgsNTg4MTksNTg4MjAsNTg4MjEsNTg4MjIsNTg4MjMsNTg4MjQsNTg4MjUsNTg4MjYsNTg4MjcsNTg4MjgsNTg4MjksNTg4MzAsNTg4MzEsNTg4MzIsNTg4MzMsNTg4MzQsNTg4MzUsNTg4MzYsNTg4MzcsNTg4MzgsNTg4MzksNTg4NDAsNTg4NDEsNTg4NDIsNTg4NDMsNTg4NDQsNTg4NDUsNTg4NDYsNTg4NDcsNTg4NDgsNTg4NDksNTg4NTAsNTg4NTEsNTg4NTIsMTIyODgsNjUyODEsNjUyODIsNjUyODMsNjU1MDksNjUyODUsNjUyODYsNjUyODcsNjUyODgsNjUyODksNjUyOTAsNjUyOTEsNjUyOTIsNjUyOTMsNjUyOTQsNjUyOTUsNjUyOTYsNjUyOTcsNjUyOTgsNjUyOTksNjUzMDAsNjUzMDEsNjUzMDIsNjUzMDMsNjUzMDQsNjUzMDUsNjUzMDYsNjUzMDcsNjUzMDgsNjUzMDksNjUzMTAsNjUzMTEsNjUzMTIsNjUzMTMsNjUzMTQsNjUzMTUsNjUzMTYsNjUzMTcsNjUzMTgsNjUzMTksNjUzMjAsNjUzMjEsNjUzMjIsNjUzMjMsNjUzMjQsNjUzMjUsNjUzMjYsNjUzMjcsNjUzMjgsNjUzMjksNjUzMzAsNjUzMzEsNjUzMzIsNjUzMzMsNjUzMzQsNjUzMzUsNjUzMzYsNjUzMzcsNjUzMzgsNjUzMzksNjUzNDAsNjUzNDEsNjUzNDIsNjUzNDMsNjUzNDQsNjUzNDUsNjUzNDYsNjUzNDcsNjUzNDgsNjUzNDksNjUzNTAsNjUzNTEsNjUzNTIsNjUzNTMsNjUzNTQsNjUzNTUsNjUzNTYsNjUzNTcsNjUzNTgsNjUzNTksNjUzNjAsNjUzNjEsNjUzNjIsNjUzNjMsNjUzNjQsNjUzNjUsNjUzNjYsNjUzNjcsNjUzNjgsNjUzNjksNjUzNzAsNjUzNzEsNjUzNzIsNjUzNzMsNjU1MDcsNTg4NTQsNTg4NTUsNTg4NTYsNTg4NTcsNTg4NTgsNTg4NTksNTg4NjAsNTg4NjEsNTg4NjIsNTg4NjMsNTg4NjQsNTg4NjUsNTg4NjYsNTg4NjcsNTg4NjgsNTg4NjksNTg4NzAsNTg4NzEsNTg4NzIsNTg4NzMsNTg4NzQsNTg4NzUsNTg4NzYsNTg4NzcsNTg4NzgsNTg4NzksNTg4ODAsNTg4ODEsNTg4ODIsNTg4ODMsNTg4ODQsNTg4ODUsNTg4ODYsNTg4ODcsNTg4ODgsNTg4ODksNTg4OTAsNTg4OTEsNTg4OTIsNTg4OTMsNTg4OTQsNTg4OTUsNTg4OTYsNTg4OTcsNTg4OTgsNTg4OTksNTg5MDAsNTg5MDEsNTg5MDIsNTg5MDMsNTg5MDQsNTg5MDUsNTg5MDYsNTg5MDcsNTg5MDgsNTg5MDksNTg5MTAsNTg5MTEsNTg5MTIsNTg5MTMsNTg5MTQsNTg5MTUsNTg5MTYsNTg5MTcsNTg5MTgsNTg5MTksNTg5MjAsNTg5MjEsNTg5MjIsNTg5MjMsNTg5MjQsNTg5MjUsNTg5MjYsNTg5MjcsNTg5MjgsNTg5MjksNTg5MzAsNTg5MzEsNTg5MzIsNTg5MzMsNTg5MzQsNTg5MzUsNTg5MzYsNTg5MzcsNTg5MzgsNTg5MzksNTg5NDAsNTg5NDEsNTg5NDIsNTg5NDMsNTg5NDQsNTg5NDUsNTg5NDYsNTg5NDcsNTg5NDgsNTg5NDksMTIzNTMsMTIzNTQsMTIzNTUsMTIzNTYsMTIzNTcsMTIzNTgsMTIzNTksMTIzNjAsMTIzNjEsMTIzNjIsMTIzNjMsMTIzNjQsMTIzNjUsMTIzNjYsMTIzNjcsMTIzNjgsMTIzNjksMTIzNzAsMTIzNzEsMTIzNzIsMTIzNzMsMTIzNzQsMTIzNzUsMTIzNzYsMTIzNzcsMTIzNzgsMTIzNzksMTIzODAsMTIzODEsMTIzODIsMTIzODMsMTIzODQsMTIzODUsMTIzODYsMTIzODcsMTIzODgsMTIzODksMTIzOTAsMTIzOTEsMTIzOTIsMTIzOTMsMTIzOTQsMTIzOTUsMTIzOTYsMTIzOTcsMTIzOTgsMTIzOTksMTI0MDAsMTI0MDEsMTI0MDIsMTI0MDMsMTI0MDQsMTI0MDUsMTI0MDYsMTI0MDcsMTI0MDgsMTI0MDksMTI0MTAsMTI0MTEsMTI0MTIsMTI0MTMsMTI0MTQsMTI0MTUsMTI0MTYsMTI0MTcsMTI0MTgsMTI0MTksMTI0MjAsMTI0MjEsMTI0MjIsMTI0MjMsMTI0MjQsMTI0MjUsMTI0MjYsMTI0MjcsMTI0MjgsMTI0MjksMTI0MzAsMTI0MzEsMTI0MzIsMTI0MzMsMTI0MzQsMTI0MzUsNTkyNTAsNTkyNTEsNTkyNTIsNTkyNTMsNTkyNTQsNTkyNTUsNTkyNTYsNTkyNTcsNTkyNTgsNTkyNTksNTkyNjAsNTg5NTAsNTg5NTEsNTg5NTIsNTg5NTMsNTg5NTQsNTg5NTUsNTg5NTYsNTg5NTcsNTg5NTgsNTg5NTksNTg5NjAsNTg5NjEsNTg5NjIsNTg5NjMsNTg5NjQsNTg5NjUsNTg5NjYsNTg5NjcsNTg5NjgsNTg5NjksNTg5NzAsNTg5NzEsNTg5NzIsNTg5NzMsNTg5NzQsNTg5NzUsNTg5NzYsNTg5NzcsNTg5NzgsNTg5NzksNTg5ODAsNTg5ODEsNTg5ODIsNTg5ODMsNTg5ODQsNTg5ODUsNTg5ODYsNTg5ODcsNTg5ODgsNTg5ODksNTg5OTAsNTg5OTEsNTg5OTIsNTg5OTMsNTg5OTQsNTg5OTUsNTg5OTYsNTg5OTcsNTg5OTgsNTg5OTksNTkwMDAsNTkwMDEsNTkwMDIsNTkwMDMsNTkwMDQsNTkwMDUsNTkwMDYsNTkwMDcsNTkwMDgsNTkwMDksNTkwMTAsNTkwMTEsNTkwMTIsNTkwMTMsNTkwMTQsNTkwMTUsNTkwMTYsNTkwMTcsNTkwMTgsNTkwMTksNTkwMjAsNTkwMjEsNTkwMjIsNTkwMjMsNTkwMjQsNTkwMjUsNTkwMjYsNTkwMjcsNTkwMjgsNTkwMjksNTkwMzAsNTkwMzEsNTkwMzIsNTkwMzMsNTkwMzQsNTkwMzUsNTkwMzYsNTkwMzcsNTkwMzgsNTkwMzksNTkwNDAsNTkwNDEsNTkwNDIsNTkwNDMsNTkwNDQsNTkwNDUsMTI0NDksMTI0NTAsMTI0NTEsMTI0NTIsMTI0NTMsMTI0NTQsMTI0NTUsMTI0NTYsMTI0NTcsMTI0NTgsMTI0NTksMTI0NjAsMTI0NjEsMTI0NjIsMTI0NjMsMTI0NjQsMTI0NjUsMTI0NjYsMTI0NjcsMTI0NjgsMTI0NjksMTI0NzAsMTI0NzEsMTI0NzIsMTI0NzMsMTI0NzQsMTI0NzUsMTI0NzYsMTI0NzcsMTI0NzgsMTI0NzksMTI0ODAsMTI0ODEsMTI0ODIsMTI0ODMsMTI0ODQsMTI0ODUsMTI0ODYsMTI0ODcsMTI0ODgsMTI0ODksMTI0OTAsMTI0OTEsMTI0OTIsMTI0OTMsMTI0OTQsMTI0OTUsMTI0OTYsMTI0OTcsMTI0OTgsMTI0OTksMTI1MDAsMTI1MDEsMTI1MDIsMTI1MDMsMTI1MDQsMTI1MDUsMTI1MDYsMTI1MDcsMTI1MDgsMTI1MDksMTI1MTAsMTI1MTEsMTI1MTIsMTI1MTMsMTI1MTQsMTI1MTUsMTI1MTYsMTI1MTcsMTI1MTgsMTI1MTksMTI1MjAsMTI1MjEsMTI1MjIsMTI1MjMsMTI1MjQsMTI1MjUsMTI1MjYsMTI1MjcsMTI1MjgsMTI1MjksMTI1MzAsMTI1MzEsMTI1MzIsMTI1MzMsMTI1MzQsNTkyNjEsNTkyNjIsNTkyNjMsNTkyNjQsNTkyNjUsNTkyNjYsNTkyNjcsNTkyNjgsNTkwNDYsNTkwNDcsNTkwNDgsNTkwNDksNTkwNTAsNTkwNTEsNTkwNTIsNTkwNTMsNTkwNTQsNTkwNTUsNTkwNTYsNTkwNTcsNTkwNTgsNTkwNTksNTkwNjAsNTkwNjEsNTkwNjIsNTkwNjMsNTkwNjQsNTkwNjUsNTkwNjYsNTkwNjcsNTkwNjgsNTkwNjksNTkwNzAsNTkwNzEsNTkwNzIsNTkwNzMsNTkwNzQsNTkwNzUsNTkwNzYsNTkwNzcsNTkwNzgsNTkwNzksNTkwODAsNTkwODEsNTkwODIsNTkwODMsNTkwODQsNTkwODUsNTkwODYsNTkwODcsNTkwODgsNTkwODksNTkwOTAsNTkwOTEsNTkwOTIsNTkwOTMsNTkwOTQsNTkwOTUsNTkwOTYsNTkwOTcsNTkwOTgsNTkwOTksNTkxMDAsNTkxMDEsNTkxMDIsNTkxMDMsNTkxMDQsNTkxMDUsNTkxMDYsNTkxMDcsNTkxMDgsNTkxMDksNTkxMTAsNTkxMTEsNTkxMTIsNTkxMTMsNTkxMTQsNTkxMTUsNTkxMTYsNTkxMTcsNTkxMTgsNTkxMTksNTkxMjAsNTkxMjEsNTkxMjIsNTkxMjMsNTkxMjQsNTkxMjUsNTkxMjYsNTkxMjcsNTkxMjgsNTkxMjksNTkxMzAsNTkxMzEsNTkxMzIsNTkxMzMsNTkxMzQsNTkxMzUsNTkxMzYsNTkxMzcsNTkxMzgsNTkxMzksNTkxNDAsNTkxNDEsOTEzLDkxNCw5MTUsOTE2LDkxNyw5MTgsOTE5LDkyMCw5MjEsOTIyLDkyMyw5MjQsOTI1LDkyNiw5MjcsOTI4LDkyOSw5MzEsOTMyLDkzMyw5MzQsOTM1LDkzNiw5MzcsNTkyNjksNTkyNzAsNTkyNzEsNTkyNzIsNTkyNzMsNTkyNzQsNTkyNzUsNTkyNzYsOTQ1LDk0Niw5NDcsOTQ4LDk0OSw5NTAsOTUxLDk1Miw5NTMsOTU0LDk1NSw5NTYsOTU3LDk1OCw5NTksOTYwLDk2MSw5NjMsOTY0LDk2NSw5NjYsOTY3LDk2OCw5NjksNTkyNzcsNTkyNzgsNTkyNzksNTkyODAsNTkyODEsNTkyODIsNTkyODMsNjUwNzcsNjUwNzgsNjUwODEsNjUwODIsNjUwODcsNjUwODgsNjUwODUsNjUwODYsNjUwODksNjUwOTAsNjUwOTEsNjUwOTIsNTkyODQsNTkyODUsNjUwODMsNjUwODQsNjUwNzksNjUwODAsNjUwNzMsNTkyODYsNjUwNzUsNjUwNzYsNTkyODcsNTkyODgsNTkyODksNTkyOTAsNTkyOTEsNTkyOTIsNTkyOTMsNTkyOTQsNTkyOTUsNTkxNDIsNTkxNDMsNTkxNDQsNTkxNDUsNTkxNDYsNTkxNDcsNTkxNDgsNTkxNDksNTkxNTAsNTkxNTEsNTkxNTIsNTkxNTMsNTkxNTQsNTkxNTUsNTkxNTYsNTkxNTcsNTkxNTgsNTkxNTksNTkxNjAsNTkxNjEsNTkxNjIsNTkxNjMsNTkxNjQsNTkxNjUsNTkxNjYsNTkxNjcsNTkxNjgsNTkxNjksNTkxNzAsNTkxNzEsNTkxNzIsNTkxNzMsNTkxNzQsNTkxNzUsNTkxNzYsNTkxNzcsNTkxNzgsNTkxNzksNTkxODAsNTkxODEsNTkxODIsNTkxODMsNTkxODQsNTkxODUsNTkxODYsNTkxODcsNTkxODgsNTkxODksNTkxOTAsNTkxOTEsNTkxOTIsNTkxOTMsNTkxOTQsNTkxOTUsNTkxOTYsNTkxOTcsNTkxOTgsNTkxOTksNTkyMDAsNTkyMDEsNTkyMDIsNTkyMDMsNTkyMDQsNTkyMDUsNTkyMDYsNTkyMDcsNTkyMDgsNTkyMDksNTkyMTAsNTkyMTEsNTkyMTIsNTkyMTMsNTkyMTQsNTkyMTUsNTkyMTYsNTkyMTcsNTkyMTgsNTkyMTksNTkyMjAsNTkyMjEsNTkyMjIsNTkyMjMsNTkyMjQsNTkyMjUsNTkyMjYsNTkyMjcsNTkyMjgsNTkyMjksNTkyMzAsNTkyMzEsNTkyMzIsNTkyMzMsNTkyMzQsNTkyMzUsNTkyMzYsNTkyMzcsMTA0MCwxMDQxLDEwNDIsMTA0MywxMDQ0LDEwNDUsMTAyNSwxMDQ2LDEwNDcsMTA0OCwxMDQ5LDEwNTAsMTA1MSwxMDUyLDEwNTMsMTA1NCwxMDU1LDEwNTYsMTA1NywxMDU4LDEwNTksMTA2MCwxMDYxLDEwNjIsMTA2MywxMDY0LDEwNjUsMTA2NiwxMDY3LDEwNjgsMTA2OSwxMDcwLDEwNzEsNTkyOTYsNTkyOTcsNTkyOTgsNTkyOTksNTkzMDAsNTkzMDEsNTkzMDIsNTkzMDMsNTkzMDQsNTkzMDUsNTkzMDYsNTkzMDcsNTkzMDgsNTkzMDksNTkzMTAsMTA3MiwxMDczLDEwNzQsMTA3NSwxMDc2LDEwNzcsMTEwNSwxMDc4LDEwNzksMTA4MCwxMDgxLDEwODIsMTA4MywxMDg0LDEwODUsMTA4NiwxMDg3LDEwODgsMTA4OSwxMDkwLDEwOTEsMTA5MiwxMDkzLDEwOTQsMTA5NSwxMDk2LDEwOTcsMTA5OCwxMDk5LDExMDAsMTEwMSwxMTAyLDExMDMsNTkzMTEsNTkzMTIsNTkzMTMsNTkzMTQsNTkzMTUsNTkzMTYsNTkzMTcsNTkzMTgsNTkzMTksNTkzMjAsNTkzMjEsNTkzMjIsNTkzMjMsNzE0LDcxNSw3MjksODIxMSw4MjEzLDgyMjksODI0NSw4NDUzLDg0NTcsODU5OCw4NTk5LDg2MDAsODYwMSw4NzI1LDg3MzUsODczOSw4Nzg2LDg4MDYsODgwNyw4ODk1LDk1NTIsOTU1Myw5NTU0LDk1NTUsOTU1Niw5NTU3LDk1NTgsOTU1OSw5NTYwLDk1NjEsOTU2Miw5NTYzLDk1NjQsOTU2NSw5NTY2LDk1NjcsOTU2OCw5NTY5LDk1NzAsOTU3MSw5NTcyLDk1NzMsOTU3NCw5NTc1LDk1NzYsOTU3Nyw5NTc4LDk1NzksOTU4MCw5NTgxLDk1ODIsOTU4Myw5NTg0LDk1ODUsOTU4Niw5NTg3LDk2MDEsOTYwMiw5NjAzLDk2MDQsOTYwNSw5NjA2LDk2MDcsOTYwOCw5NjA5LDk2MTAsOTYxMSw5NjEyLDk2MTMsOTYxNCw5NjE1LDk2MTksOTYyMCw5NjIxLDk2NjAsOTY2MSw5Njk4LDk2OTksOTcwMCw5NzAxLDk3MzcsODg1MywxMjMwNiwxMjMxNywxMjMxOCw1OTMyNCw1OTMyNSw1OTMyNiw1OTMyNyw1OTMyOCw1OTMyOSw1OTMzMCw1OTMzMSw1OTMzMiw1OTMzMyw1OTMzNCwyNTcsMjI1LDQ2MiwyMjQsMjc1LDIzMywyODMsMjMyLDI5OSwyMzcsNDY0LDIzNiwzMzMsMjQzLDQ2NiwyNDIsMzYzLDI1MCw0NjgsMjQ5LDQ3MCw0NzIsNDc0LDQ3NiwyNTIsMjM0LDU5Myw3NzQzLDMyNCwzMjgsNTA1LDYwOSw1OTMzNyw1OTMzOCw1OTMzOSw1OTM0MCwxMjU0OSwxMjU1MCwxMjU1MSwxMjU1MiwxMjU1MywxMjU1NCwxMjU1NSwxMjU1NiwxMjU1NywxMjU1OCwxMjU1OSwxMjU2MCwxMjU2MSwxMjU2MiwxMjU2MywxMjU2NCwxMjU2NSwxMjU2NiwxMjU2NywxMjU2OCwxMjU2OSwxMjU3MCwxMjU3MSwxMjU3MiwxMjU3MywxMjU3NCwxMjU3NSwxMjU3NiwxMjU3NywxMjU3OCwxMjU3OSwxMjU4MCwxMjU4MSwxMjU4MiwxMjU4MywxMjU4NCwxMjU4NSw1OTM0MSw1OTM0Miw1OTM0Myw1OTM0NCw1OTM0NSw1OTM0Niw1OTM0Nyw1OTM0OCw1OTM0OSw1OTM1MCw1OTM1MSw1OTM1Miw1OTM1Myw1OTM1NCw1OTM1NSw1OTM1Niw1OTM1Nyw1OTM1OCw1OTM1OSw1OTM2MCw1OTM2MSwxMjMyMSwxMjMyMiwxMjMyMywxMjMyNCwxMjMyNSwxMjMyNiwxMjMyNywxMjMyOCwxMjMyOSwxMjk2MywxMzE5OCwxMzE5OSwxMzIxMiwxMzIxMywxMzIxNCwxMzIxNywxMzI1MiwxMzI2MiwxMzI2NSwxMzI2NiwxMzI2OSw2NTA3Miw2NTUwNiw2NTUwOCw1OTM2Miw4NDgxLDEyODQ5LDU5MzYzLDgyMDgsNTkzNjQsNTkzNjUsNTkzNjYsMTI1NDAsMTI0NDMsMTI0NDQsMTI1NDEsMTI1NDIsMTIyOTQsMTI0NDUsMTI0NDYsNjUwOTcsNjUwOTgsNjUwOTksNjUxMDAsNjUxMDEsNjUxMDIsNjUxMDMsNjUxMDQsNjUxMDUsNjUxMDYsNjUxMDgsNjUxMDksNjUxMTAsNjUxMTEsNjUxMTMsNjUxMTQsNjUxMTUsNjUxMTYsNjUxMTcsNjUxMTgsNjUxMTksNjUxMjAsNjUxMjEsNjUxMjIsNjUxMjMsNjUxMjQsNjUxMjUsNjUxMjYsNjUxMjgsNjUxMjksNjUxMzAsNjUxMzEsMTIzNTAsMTIyNzIsMTIyNzMsMTIyNzQsMTIyNzUsMTIyNzYsMTIyNzcsMTIyNzgsMTIyNzksMTIyODAsMTIyODEsMTIyODIsMTIyODMsMTIyOTUsNTkzODAsNTkzODEsNTkzODIsNTkzODMsNTkzODQsNTkzODUsNTkzODYsNTkzODcsNTkzODgsNTkzODksNTkzOTAsNTkzOTEsNTkzOTIsOTQ3Miw5NDczLDk0NzQsOTQ3NSw5NDc2LDk0NzcsOTQ3OCw5NDc5LDk0ODAsOTQ4MSw5NDgyLDk0ODMsOTQ4NCw5NDg1LDk0ODYsOTQ4Nyw5NDg4LDk0ODksOTQ5MCw5NDkxLDk0OTIsOTQ5Myw5NDk0LDk0OTUsOTQ5Niw5NDk3LDk0OTgsOTQ5OSw5NTAwLDk1MDEsOTUwMiw5NTAzLDk1MDQsOTUwNSw5NTA2LDk1MDcsOTUwOCw5NTA5LDk1MTAsOTUxMSw5NTEyLDk1MTMsOTUxNCw5NTE1LDk1MTYsOTUxNyw5NTE4LDk1MTksOTUyMCw5NTIxLDk1MjIsOTUyMyw5NTI0LDk1MjUsOTUyNiw5NTI3LDk1MjgsOTUyOSw5NTMwLDk1MzEsOTUzMiw5NTMzLDk1MzQsOTUzNSw5NTM2LDk1MzcsOTUzOCw5NTM5LDk1NDAsOTU0MSw5NTQyLDk1NDMsOTU0NCw5NTQ1LDk1NDYsOTU0Nyw1OTM5Myw1OTM5NCw1OTM5NSw1OTM5Niw1OTM5Nyw1OTM5OCw1OTM5OSw1OTQwMCw1OTQwMSw1OTQwMiw1OTQwMyw1OTQwNCw1OTQwNSw1OTQwNiw1OTQwNywyOTQwNCwyOTQwNSwyOTQwNywyOTQxMCwyOTQxMSwyOTQxMiwyOTQxMywyOTQxNCwyOTQxNSwyOTQxOCwyOTQxOSwyOTQyOSwyOTQzMCwyOTQzMywyOTQzNywyOTQzOCwyOTQzOSwyOTQ0MCwyOTQ0MiwyOTQ0NCwyOTQ0NSwyOTQ0NiwyOTQ0NywyOTQ0OCwyOTQ0OSwyOTQ1MSwyOTQ1MiwyOTQ1MywyOTQ1NSwyOTQ1NiwyOTQ1NywyOTQ1OCwyOTQ2MCwyOTQ2NCwyOTQ2NSwyOTQ2NiwyOTQ3MSwyOTQ3MiwyOTQ3NSwyOTQ3NiwyOTQ3OCwyOTQ3OSwyOTQ4MCwyOTQ4NSwyOTQ4NywyOTQ4OCwyOTQ5MCwyOTQ5MSwyOTQ5MywyOTQ5NCwyOTQ5OCwyOTQ5OSwyOTUwMCwyOTUwMSwyOTUwNCwyOTUwNSwyOTUwNiwyOTUwNywyOTUwOCwyOTUwOSwyOTUxMCwyOTUxMSwyOTUxMiwyOTUxMywyOTUxNCwyOTUxNSwyOTUxNiwyOTUxOCwyOTUxOSwyOTUyMSwyOTUyMywyOTUyNCwyOTUyNSwyOTUyNiwyOTUyOCwyOTUyOSwyOTUzMCwyOTUzMSwyOTUzMiwyOTUzMywyOTUzNCwyOTUzNSwyOTUzNywyOTUzOCwyOTUzOSwyOTU0MCwyOTU0MSwyOTU0MiwyOTU0MywyOTU0NCwyOTU0NSwyOTU0NiwyOTU0NywyOTU1MCwyOTU1MiwyOTU1Myw1NzM0NCw1NzM0NSw1NzM0Niw1NzM0Nyw1NzM0OCw1NzM0OSw1NzM1MCw1NzM1MSw1NzM1Miw1NzM1Myw1NzM1NCw1NzM1NSw1NzM1Niw1NzM1Nyw1NzM1OCw1NzM1OSw1NzM2MCw1NzM2MSw1NzM2Miw1NzM2Myw1NzM2NCw1NzM2NSw1NzM2Niw1NzM2Nyw1NzM2OCw1NzM2OSw1NzM3MCw1NzM3MSw1NzM3Miw1NzM3Myw1NzM3NCw1NzM3NSw1NzM3Niw1NzM3Nyw1NzM3OCw1NzM3OSw1NzM4MCw1NzM4MSw1NzM4Miw1NzM4Myw1NzM4NCw1NzM4NSw1NzM4Niw1NzM4Nyw1NzM4OCw1NzM4OSw1NzM5MCw1NzM5MSw1NzM5Miw1NzM5Myw1NzM5NCw1NzM5NSw1NzM5Niw1NzM5Nyw1NzM5OCw1NzM5OSw1NzQwMCw1NzQwMSw1NzQwMiw1NzQwMyw1NzQwNCw1NzQwNSw1NzQwNiw1NzQwNyw1NzQwOCw1NzQwOSw1NzQxMCw1NzQxMSw1NzQxMiw1NzQxMyw1NzQxNCw1NzQxNSw1NzQxNiw1NzQxNyw1NzQxOCw1NzQxOSw1NzQyMCw1NzQyMSw1NzQyMiw1NzQyMyw1NzQyNCw1NzQyNSw1NzQyNiw1NzQyNyw1NzQyOCw1NzQyOSw1NzQzMCw1NzQzMSw1NzQzMiw1NzQzMyw1NzQzNCw1NzQzNSw1NzQzNiw1NzQzNywyOTU1NCwyOTU1NSwyOTU1NiwyOTU1NywyOTU1OCwyOTU1OSwyOTU2MCwyOTU2MSwyOTU2MiwyOTU2MywyOTU2NCwyOTU2NSwyOTU2NywyOTU2OCwyOTU2OSwyOTU3MCwyOTU3MSwyOTU3MywyOTU3NCwyOTU3NiwyOTU3OCwyOTU4MCwyOTU4MSwyOTU4MywyOTU4NCwyOTU4NiwyOTU4NywyOTU4OCwyOTU4OSwyOTU5MSwyOTU5MiwyOTU5MywyOTU5NCwyOTU5NiwyOTU5NywyOTU5OCwyOTYwMCwyOTYwMSwyOTYwMywyOTYwNCwyOTYwNSwyOTYwNiwyOTYwNywyOTYwOCwyOTYxMCwyOTYxMiwyOTYxMywyOTYxNywyOTYyMCwyOTYyMSwyOTYyMiwyOTYyNCwyOTYyNSwyOTYyOCwyOTYyOSwyOTYzMCwyOTYzMSwyOTYzMywyOTYzNSwyOTYzNiwyOTYzNywyOTYzOCwyOTYzOSwyOTY0MywyOTY0NCwyOTY0NiwyOTY1MCwyOTY1MSwyOTY1MiwyOTY1MywyOTY1NCwyOTY1NSwyOTY1NiwyOTY1OCwyOTY1OSwyOTY2MCwyOTY2MSwyOTY2MywyOTY2NSwyOTY2NiwyOTY2NywyOTY2OCwyOTY3MCwyOTY3MiwyOTY3NCwyOTY3NSwyOTY3NiwyOTY3OCwyOTY3OSwyOTY4MCwyOTY4MSwyOTY4MywyOTY4NCwyOTY4NSwyOTY4NiwyOTY4Nyw1NzQzOCw1NzQzOSw1NzQ0MCw1NzQ0MSw1NzQ0Miw1NzQ0Myw1NzQ0NCw1NzQ0NSw1NzQ0Niw1NzQ0Nyw1NzQ0OCw1NzQ0OSw1NzQ1MCw1NzQ1MSw1NzQ1Miw1NzQ1Myw1NzQ1NCw1NzQ1NSw1NzQ1Niw1NzQ1Nyw1NzQ1OCw1NzQ1OSw1NzQ2MCw1NzQ2MSw1NzQ2Miw1NzQ2Myw1NzQ2NCw1NzQ2NSw1NzQ2Niw1NzQ2Nyw1NzQ2OCw1NzQ2OSw1NzQ3MCw1NzQ3MSw1NzQ3Miw1NzQ3Myw1NzQ3NCw1NzQ3NSw1NzQ3Niw1NzQ3Nyw1NzQ3OCw1NzQ3OSw1NzQ4MCw1NzQ4MSw1NzQ4Miw1NzQ4Myw1NzQ4NCw1NzQ4NSw1NzQ4Niw1NzQ4Nyw1NzQ4OCw1NzQ4OSw1NzQ5MCw1NzQ5MSw1NzQ5Miw1NzQ5Myw1NzQ5NCw1NzQ5NSw1NzQ5Niw1NzQ5Nyw1NzQ5OCw1NzQ5OSw1NzUwMCw1NzUwMSw1NzUwMiw1NzUwMyw1NzUwNCw1NzUwNSw1NzUwNiw1NzUwNyw1NzUwOCw1NzUwOSw1NzUxMCw1NzUxMSw1NzUxMiw1NzUxMyw1NzUxNCw1NzUxNSw1NzUxNiw1NzUxNyw1NzUxOCw1NzUxOSw1NzUyMCw1NzUyMSw1NzUyMiw1NzUyMyw1NzUyNCw1NzUyNSw1NzUyNiw1NzUyNyw1NzUyOCw1NzUyOSw1NzUzMCw1NzUzMSwyOTY4OCwyOTY4OSwyOTY5MCwyOTY5MSwyOTY5MiwyOTY5MywyOTY5NCwyOTY5NSwyOTY5NiwyOTY5NywyOTY5OCwyOTcwMCwyOTcwMywyOTcwNCwyOTcwNywyOTcwOCwyOTcwOSwyOTcxMCwyOTcxMywyOTcxNCwyOTcxNSwyOTcxNiwyOTcxNywyOTcxOCwyOTcxOSwyOTcyMCwyOTcyMSwyOTcyNCwyOTcyNSwyOTcyNiwyOTcyNywyOTcyOCwyOTcyOSwyOTczMSwyOTczMiwyOTczNSwyOTczNywyOTczOSwyOTc0MSwyOTc0MywyOTc0NSwyOTc0NiwyOTc1MSwyOTc1MiwyOTc1MywyOTc1NCwyOTc1NSwyOTc1NywyOTc1OCwyOTc1OSwyOTc2MCwyOTc2MiwyOTc2MywyOTc2NCwyOTc2NSwyOTc2NiwyOTc2NywyOTc2OCwyOTc2OSwyOTc3MCwyOTc3MSwyOTc3MiwyOTc3MywyOTc3NCwyOTc3NSwyOTc3NiwyOTc3NywyOTc3OCwyOTc3OSwyOTc4MCwyOTc4MiwyOTc4NCwyOTc4OSwyOTc5MiwyOTc5MywyOTc5NCwyOTc5NSwyOTc5NiwyOTc5NywyOTc5OCwyOTc5OSwyOTgwMCwyOTgwMSwyOTgwMiwyOTgwMywyOTgwNCwyOTgwNiwyOTgwNywyOTgwOSwyOTgxMCwyOTgxMSwyOTgxMiwyOTgxMywyOTgxNiwyOTgxNywyOTgxOCw1NzUzMiw1NzUzMyw1NzUzNCw1NzUzNSw1NzUzNiw1NzUzNyw1NzUzOCw1NzUzOSw1NzU0MCw1NzU0MSw1NzU0Miw1NzU0Myw1NzU0NCw1NzU0NSw1NzU0Niw1NzU0Nyw1NzU0OCw1NzU0OSw1NzU1MCw1NzU1MSw1NzU1Miw1NzU1Myw1NzU1NCw1NzU1NSw1NzU1Niw1NzU1Nyw1NzU1OCw1NzU1OSw1NzU2MCw1NzU2MSw1NzU2Miw1NzU2Myw1NzU2NCw1NzU2NSw1NzU2Niw1NzU2Nyw1NzU2OCw1NzU2OSw1NzU3MCw1NzU3MSw1NzU3Miw1NzU3Myw1NzU3NCw1NzU3NSw1NzU3Niw1NzU3Nyw1NzU3OCw1NzU3OSw1NzU4MCw1NzU4MSw1NzU4Miw1NzU4Myw1NzU4NCw1NzU4NSw1NzU4Niw1NzU4Nyw1NzU4OCw1NzU4OSw1NzU5MCw1NzU5MSw1NzU5Miw1NzU5Myw1NzU5NCw1NzU5NSw1NzU5Niw1NzU5Nyw1NzU5OCw1NzU5OSw1NzYwMCw1NzYwMSw1NzYwMiw1NzYwMyw1NzYwNCw1NzYwNSw1NzYwNiw1NzYwNyw1NzYwOCw1NzYwOSw1NzYxMCw1NzYxMSw1NzYxMiw1NzYxMyw1NzYxNCw1NzYxNSw1NzYxNiw1NzYxNyw1NzYxOCw1NzYxOSw1NzYyMCw1NzYyMSw1NzYyMiw1NzYyMyw1NzYyNCw1NzYyNSwyOTgxOSwyOTgyMCwyOTgyMSwyOTgyMywyOTgyNiwyOTgyOCwyOTgyOSwyOTgzMCwyOTgzMiwyOTgzMywyOTgzNCwyOTgzNiwyOTgzNywyOTgzOSwyOTg0MSwyOTg0MiwyOTg0MywyOTg0NCwyOTg0NSwyOTg0NiwyOTg0NywyOTg0OCwyOTg0OSwyOTg1MCwyOTg1MSwyOTg1MywyOTg1NSwyOTg1NiwyOTg1NywyOTg1OCwyOTg1OSwyOTg2MCwyOTg2MSwyOTg2MiwyOTg2NiwyOTg2NywyOTg2OCwyOTg2OSwyOTg3MCwyOTg3MSwyOTg3MiwyOTg3MywyOTg3NCwyOTg3NSwyOTg3NiwyOTg3NywyOTg3OCwyOTg3OSwyOTg4MCwyOTg4MSwyOTg4MywyOTg4NCwyOTg4NSwyOTg4NiwyOTg4NywyOTg4OCwyOTg4OSwyOTg5MCwyOTg5MSwyOTg5MiwyOTg5MywyOTg5NCwyOTg5NSwyOTg5NiwyOTg5NywyOTg5OCwyOTg5OSwyOTkwMCwyOTkwMSwyOTkwMiwyOTkwMywyOTkwNCwyOTkwNSwyOTkwNywyOTkwOCwyOTkwOSwyOTkxMCwyOTkxMSwyOTkxMiwyOTkxMywyOTkxNCwyOTkxNSwyOTkxNywyOTkxOSwyOTkyMSwyOTkyNSwyOTkyNywyOTkyOCwyOTkyOSwyOTkzMCwyOTkzMSwyOTkzMiwyOTkzMywyOTkzNiwyOTkzNywyOTkzOCw1NzYyNiw1NzYyNyw1NzYyOCw1NzYyOSw1NzYzMCw1NzYzMSw1NzYzMiw1NzYzMyw1NzYzNCw1NzYzNSw1NzYzNiw1NzYzNyw1NzYzOCw1NzYzOSw1NzY0MCw1NzY0MSw1NzY0Miw1NzY0Myw1NzY0NCw1NzY0NSw1NzY0Niw1NzY0Nyw1NzY0OCw1NzY0OSw1NzY1MCw1NzY1MSw1NzY1Miw1NzY1Myw1NzY1NCw1NzY1NSw1NzY1Niw1NzY1Nyw1NzY1OCw1NzY1OSw1NzY2MCw1NzY2MSw1NzY2Miw1NzY2Myw1NzY2NCw1NzY2NSw1NzY2Niw1NzY2Nyw1NzY2OCw1NzY2OSw1NzY3MCw1NzY3MSw1NzY3Miw1NzY3Myw1NzY3NCw1NzY3NSw1NzY3Niw1NzY3Nyw1NzY3OCw1NzY3OSw1NzY4MCw1NzY4MSw1NzY4Miw1NzY4Myw1NzY4NCw1NzY4NSw1NzY4Niw1NzY4Nyw1NzY4OCw1NzY4OSw1NzY5MCw1NzY5MSw1NzY5Miw1NzY5Myw1NzY5NCw1NzY5NSw1NzY5Niw1NzY5Nyw1NzY5OCw1NzY5OSw1NzcwMCw1NzcwMSw1NzcwMiw1NzcwMyw1NzcwNCw1NzcwNSw1NzcwNiw1NzcwNyw1NzcwOCw1NzcwOSw1NzcxMCw1NzcxMSw1NzcxMiw1NzcxMyw1NzcxNCw1NzcxNSw1NzcxNiw1NzcxNyw1NzcxOCw1NzcxOSwyOTkzOSwyOTk0MSwyOTk0NCwyOTk0NSwyOTk0NiwyOTk0NywyOTk0OCwyOTk0OSwyOTk1MCwyOTk1MiwyOTk1MywyOTk1NCwyOTk1NSwyOTk1NywyOTk1OCwyOTk1OSwyOTk2MCwyOTk2MSwyOTk2MiwyOTk2MywyOTk2NCwyOTk2NiwyOTk2OCwyOTk3MCwyOTk3MiwyOTk3MywyOTk3NCwyOTk3NSwyOTk3OSwyOTk4MSwyOTk4MiwyOTk4NCwyOTk4NSwyOTk4NiwyOTk4NywyOTk4OCwyOTk5MCwyOTk5MSwyOTk5NCwyOTk5OCwzMDAwNCwzMDAwNiwzMDAwOSwzMDAxMiwzMDAxMywzMDAxNSwzMDAxNywzMDAxOCwzMDAxOSwzMDAyMCwzMDAyMiwzMDAyMywzMDAyNSwzMDAyNiwzMDAyOSwzMDAzMiwzMDAzMywzMDAzNCwzMDAzNSwzMDAzNywzMDAzOCwzMDAzOSwzMDA0MCwzMDA0NSwzMDA0NiwzMDA0NywzMDA0OCwzMDA0OSwzMDA1MCwzMDA1MSwzMDA1MiwzMDA1NSwzMDA1NiwzMDA1NywzMDA1OSwzMDA2MCwzMDA2MSwzMDA2MiwzMDA2MywzMDA2NCwzMDA2NSwzMDA2NywzMDA2OSwzMDA3MCwzMDA3MSwzMDA3NCwzMDA3NSwzMDA3NiwzMDA3NywzMDA3OCwzMDA4MCwzMDA4MSwzMDA4MiwzMDA4NCwzMDA4NSwzMDA4Nyw1NzcyMCw1NzcyMSw1NzcyMiw1NzcyMyw1NzcyNCw1NzcyNSw1NzcyNiw1NzcyNyw1NzcyOCw1NzcyOSw1NzczMCw1NzczMSw1NzczMiw1NzczMyw1NzczNCw1NzczNSw1NzczNiw1NzczNyw1NzczOCw1NzczOSw1Nzc0MCw1Nzc0MSw1Nzc0Miw1Nzc0Myw1Nzc0NCw1Nzc0NSw1Nzc0Niw1Nzc0Nyw1Nzc0OCw1Nzc0OSw1Nzc1MCw1Nzc1MSw1Nzc1Miw1Nzc1Myw1Nzc1NCw1Nzc1NSw1Nzc1Niw1Nzc1Nyw1Nzc1OCw1Nzc1OSw1Nzc2MCw1Nzc2MSw1Nzc2Miw1Nzc2Myw1Nzc2NCw1Nzc2NSw1Nzc2Niw1Nzc2Nyw1Nzc2OCw1Nzc2OSw1Nzc3MCw1Nzc3MSw1Nzc3Miw1Nzc3Myw1Nzc3NCw1Nzc3NSw1Nzc3Niw1Nzc3Nyw1Nzc3OCw1Nzc3OSw1Nzc4MCw1Nzc4MSw1Nzc4Miw1Nzc4Myw1Nzc4NCw1Nzc4NSw1Nzc4Niw1Nzc4Nyw1Nzc4OCw1Nzc4OSw1Nzc5MCw1Nzc5MSw1Nzc5Miw1Nzc5Myw1Nzc5NCw1Nzc5NSw1Nzc5Niw1Nzc5Nyw1Nzc5OCw1Nzc5OSw1NzgwMCw1NzgwMSw1NzgwMiw1NzgwMyw1NzgwNCw1NzgwNSw1NzgwNiw1NzgwNyw1NzgwOCw1NzgwOSw1NzgxMCw1NzgxMSw1NzgxMiw1NzgxMywzMDA4OCwzMDA4OSwzMDA5MCwzMDA5MiwzMDA5MywzMDA5NCwzMDA5NiwzMDA5OSwzMDEwMSwzMDEwNCwzMDEwNywzMDEwOCwzMDExMCwzMDExNCwzMDExOCwzMDExOSwzMDEyMCwzMDEyMSwzMDEyMiwzMDEyNSwzMDEzNCwzMDEzNSwzMDEzOCwzMDEzOSwzMDE0MywzMDE0NCwzMDE0NSwzMDE1MCwzMDE1NSwzMDE1NiwzMDE1OCwzMDE1OSwzMDE2MCwzMDE2MSwzMDE2MywzMDE2NywzMDE2OSwzMDE3MCwzMDE3MiwzMDE3MywzMDE3NSwzMDE3NiwzMDE3NywzMDE4MSwzMDE4NSwzMDE4OCwzMDE4OSwzMDE5MCwzMDE5MSwzMDE5NCwzMDE5NSwzMDE5NywzMDE5OCwzMDE5OSwzMDIwMCwzMDIwMiwzMDIwMywzMDIwNSwzMDIwNiwzMDIxMCwzMDIxMiwzMDIxNCwzMDIxNSwzMDIxNiwzMDIxNywzMDIxOSwzMDIyMSwzMDIyMiwzMDIyMywzMDIyNSwzMDIyNiwzMDIyNywzMDIyOCwzMDIzMCwzMDIzNCwzMDIzNiwzMDIzNywzMDIzOCwzMDI0MSwzMDI0MywzMDI0NywzMDI0OCwzMDI1MiwzMDI1NCwzMDI1NSwzMDI1NywzMDI1OCwzMDI2MiwzMDI2MywzMDI2NSwzMDI2NiwzMDI2NywzMDI2OSwzMDI3MywzMDI3NCwzMDI3Niw1NzgxNCw1NzgxNSw1NzgxNiw1NzgxNyw1NzgxOCw1NzgxOSw1NzgyMCw1NzgyMSw1NzgyMiw1NzgyMyw1NzgyNCw1NzgyNSw1NzgyNiw1NzgyNyw1NzgyOCw1NzgyOSw1NzgzMCw1NzgzMSw1NzgzMiw1NzgzMyw1NzgzNCw1NzgzNSw1NzgzNiw1NzgzNyw1NzgzOCw1NzgzOSw1Nzg0MCw1Nzg0MSw1Nzg0Miw1Nzg0Myw1Nzg0NCw1Nzg0NSw1Nzg0Niw1Nzg0Nyw1Nzg0OCw1Nzg0OSw1Nzg1MCw1Nzg1MSw1Nzg1Miw1Nzg1Myw1Nzg1NCw1Nzg1NSw1Nzg1Niw1Nzg1Nyw1Nzg1OCw1Nzg1OSw1Nzg2MCw1Nzg2MSw1Nzg2Miw1Nzg2Myw1Nzg2NCw1Nzg2NSw1Nzg2Niw1Nzg2Nyw1Nzg2OCw1Nzg2OSw1Nzg3MCw1Nzg3MSw1Nzg3Miw1Nzg3Myw1Nzg3NCw1Nzg3NSw1Nzg3Niw1Nzg3Nyw1Nzg3OCw1Nzg3OSw1Nzg4MCw1Nzg4MSw1Nzg4Miw1Nzg4Myw1Nzg4NCw1Nzg4NSw1Nzg4Niw1Nzg4Nyw1Nzg4OCw1Nzg4OSw1Nzg5MCw1Nzg5MSw1Nzg5Miw1Nzg5Myw1Nzg5NCw1Nzg5NSw1Nzg5Niw1Nzg5Nyw1Nzg5OCw1Nzg5OSw1NzkwMCw1NzkwMSw1NzkwMiw1NzkwMyw1NzkwNCw1NzkwNSw1NzkwNiw1NzkwNywzMDI3NywzMDI3OCwzMDI3OSwzMDI4MCwzMDI4MSwzMDI4MiwzMDI4MywzMDI4NiwzMDI4NywzMDI4OCwzMDI4OSwzMDI5MCwzMDI5MSwzMDI5MywzMDI5NSwzMDI5NiwzMDI5NywzMDI5OCwzMDI5OSwzMDMwMSwzMDMwMywzMDMwNCwzMDMwNSwzMDMwNiwzMDMwOCwzMDMwOSwzMDMxMCwzMDMxMSwzMDMxMiwzMDMxMywzMDMxNCwzMDMxNiwzMDMxNywzMDMxOCwzMDMyMCwzMDMyMSwzMDMyMiwzMDMyMywzMDMyNCwzMDMyNSwzMDMyNiwzMDMyNywzMDMyOSwzMDMzMCwzMDMzMiwzMDMzNSwzMDMzNiwzMDMzNywzMDMzOSwzMDM0MSwzMDM0NSwzMDM0NiwzMDM0OCwzMDM0OSwzMDM1MSwzMDM1MiwzMDM1NCwzMDM1NiwzMDM1NywzMDM1OSwzMDM2MCwzMDM2MiwzMDM2MywzMDM2NCwzMDM2NSwzMDM2NiwzMDM2NywzMDM2OCwzMDM2OSwzMDM3MCwzMDM3MSwzMDM3MywzMDM3NCwzMDM3NSwzMDM3NiwzMDM3NywzMDM3OCwzMDM3OSwzMDM4MCwzMDM4MSwzMDM4MywzMDM4NCwzMDM4NywzMDM4OSwzMDM5MCwzMDM5MSwzMDM5MiwzMDM5MywzMDM5NCwzMDM5NSwzMDM5NiwzMDM5NywzMDM5OCwzMDQwMCwzMDQwMSwzMDQwMywyMTgzNCwzODQ2MywyMjQ2NywyNTM4NCwyMTcxMCwyMTc2OSwyMTY5NiwzMDM1MywzMDI4NCwzNDEwOCwzMDcwMiwzMzQwNiwzMDg2MSwyOTIzMywzODU1MiwzODc5NywyNzY4OCwyMzQzMywyMDQ3NCwyNTM1MywyNjI2MywyMzczNiwzMzAxOCwyNjY5NiwzMjk0MiwyNjExNCwzMDQxNCwyMDk4NSwyNTk0MiwyOTEwMCwzMjc1MywzNDk0OCwyMDY1OCwyMjg4NSwyNTAzNCwyODU5NSwzMzQ1MywyNTQyMCwyNTE3MCwyMTQ4NSwyMTU0MywzMTQ5NCwyMDg0MywzMDExNiwyNDA1MiwyNTMwMCwzNjI5OSwzODc3NCwyNTIyNiwzMjc5MywyMjM2NSwzODcxMiwzMjYxMCwyOTI0MCwzMDMzMywyNjU3NSwzMDMzNCwyNTY3MCwyMDMzNiwzNjEzMywyNTMwOCwzMTI1NSwyNjAwMSwyOTY3NywyNTY0NCwyNTIwMywzMzMyNCwzOTA0MSwyNjQ5NSwyOTI1NiwyNTE5OCwyNTI5MiwyMDI3NiwyOTkyMywyMTMyMiwyMTE1MCwzMjQ1OCwzNzAzMCwyNDExMCwyNjc1OCwyNzAzNiwzMzE1MiwzMjQ2NSwyNjgzNCwzMDkxNywzNDQ0NCwzODIyNSwyMDYyMSwzNTg3NiwzMzUwMiwzMjk5MCwyMTI1MywzNTA5MCwyMTA5MywzMDQwNCwzMDQwNywzMDQwOSwzMDQxMSwzMDQxMiwzMDQxOSwzMDQyMSwzMDQyNSwzMDQyNiwzMDQyOCwzMDQyOSwzMDQzMCwzMDQzMiwzMDQzMywzMDQzNCwzMDQzNSwzMDQzNiwzMDQzOCwzMDQzOSwzMDQ0MCwzMDQ0MSwzMDQ0MiwzMDQ0MywzMDQ0NCwzMDQ0NSwzMDQ0OCwzMDQ1MSwzMDQ1MywzMDQ1NCwzMDQ1NSwzMDQ1OCwzMDQ1OSwzMDQ2MSwzMDQ2MywzMDQ2NCwzMDQ2NiwzMDQ2NywzMDQ2OSwzMDQ3MCwzMDQ3NCwzMDQ3NiwzMDQ3OCwzMDQ3OSwzMDQ4MCwzMDQ4MSwzMDQ4MiwzMDQ4MywzMDQ4NCwzMDQ4NSwzMDQ4NiwzMDQ4NywzMDQ4OCwzMDQ5MSwzMDQ5MiwzMDQ5MywzMDQ5NCwzMDQ5NywzMDQ5OSwzMDUwMCwzMDUwMSwzMDUwMywzMDUwNiwzMDUwNywzMDUwOCwzMDUxMCwzMDUxMiwzMDUxMywzMDUxNCwzMDUxNSwzMDUxNiwzMDUyMSwzMDUyMywzMDUyNSwzMDUyNiwzMDUyNywzMDUzMCwzMDUzMiwzMDUzMywzMDUzNCwzMDUzNiwzMDUzNywzMDUzOCwzMDUzOSwzMDU0MCwzMDU0MSwzMDU0MiwzMDU0MywzMDU0NiwzMDU0NywzMDU0OCwzMDU0OSwzMDU1MCwzMDU1MSwzMDU1MiwzMDU1MywzMDU1NiwzNDE4MCwzODY0OSwyMDQ0NSwyMjU2MSwzOTI4MSwyMzQ1MywyNTI2NSwyNTI1MywyNjI5MiwzNTk2MSw0MDA3NywyOTE5MCwyNjQ3OSwzMDg2NSwyNDc1NCwyMTMyOSwyMTI3MSwzNjc0NCwzMjk3MiwzNjEyNSwzODA0OSwyMDQ5MywyOTM4NCwyMjc5MSwyNDgxMSwyODk1MywzNDk4NywyMjg2OCwzMzUxOSwyNjQxMiwzMTUyOCwyMzg0OSwzMjUwMywyOTk5NywyNzg5MywzNjQ1NCwzNjg1NiwzNjkyNCw0MDc2MywyNzYwNCwzNzE0NSwzMTUwOCwyNDQ0NCwzMDg4NywzNDAwNiwzNDEwOSwyNzYwNSwyNzYwOSwyNzYwNiwyNDA2NSwyNDE5OSwzMDIwMSwzODM4MSwyNTk0OSwyNDMzMCwyNDUxNywzNjc2NywyMjcyMSwzMzIxOCwzNjk5MSwzODQ5MSwzODgyOSwzNjc5MywzMjUzNCwzNjE0MCwyNTE1MywyMDQxNSwyMTQ2NCwyMTM0MiwzNjc3NiwzNjc3NywzNjc3OSwzNjk0MSwyNjYzMSwyNDQyNiwzMzE3NiwzNDkyMCw0MDE1MCwyNDk3MSwyMTAzNSwzMDI1MCwyNDQyOCwyNTk5NiwyODYyNiwyODM5MiwyMzQ4NiwyNTY3MiwyMDg1MywyMDkxMiwyNjU2NCwxOTk5MywzMTE3NywzOTI5MiwyODg1MSwzMDU1NywzMDU1OCwzMDU1OSwzMDU2MCwzMDU2NCwzMDU2NywzMDU2OSwzMDU3MCwzMDU3MywzMDU3NCwzMDU3NSwzMDU3NiwzMDU3NywzMDU3OCwzMDU3OSwzMDU4MCwzMDU4MSwzMDU4MiwzMDU4MywzMDU4NCwzMDU4NiwzMDU4NywzMDU4OCwzMDU5MywzMDU5NCwzMDU5NSwzMDU5OCwzMDU5OSwzMDYwMCwzMDYwMSwzMDYwMiwzMDYwMywzMDYwNywzMDYwOCwzMDYxMSwzMDYxMiwzMDYxMywzMDYxNCwzMDYxNSwzMDYxNiwzMDYxNywzMDYxOCwzMDYxOSwzMDYyMCwzMDYyMSwzMDYyMiwzMDYyNSwzMDYyNywzMDYyOCwzMDYzMCwzMDYzMiwzMDYzNSwzMDYzNywzMDYzOCwzMDYzOSwzMDY0MSwzMDY0MiwzMDY0NCwzMDY0NiwzMDY0NywzMDY0OCwzMDY0OSwzMDY1MCwzMDY1MiwzMDY1NCwzMDY1NiwzMDY1NywzMDY1OCwzMDY1OSwzMDY2MCwzMDY2MSwzMDY2MiwzMDY2MywzMDY2NCwzMDY2NSwzMDY2NiwzMDY2NywzMDY2OCwzMDY3MCwzMDY3MSwzMDY3MiwzMDY3MywzMDY3NCwzMDY3NSwzMDY3NiwzMDY3NywzMDY3OCwzMDY4MCwzMDY4MSwzMDY4MiwzMDY4NSwzMDY4NiwzMDY4NywzMDY4OCwzMDY4OSwzMDY5MiwzMDE0OSwyNDE4MiwyOTYyNywzMzc2MCwyNTc3MywyNTMyMCwzODA2OSwyNzg3NCwyMTMzOCwyMTE4NywyNTYxNSwzODA4MiwzMTYzNiwyMDI3MSwyNDA5MSwzMzMzNCwzMzA0NiwzMzE2MiwyODE5NiwyNzg1MCwzOTUzOSwyNTQyOSwyMTM0MCwyMTc1NCwzNDkxNywyMjQ5NiwxOTk4MSwyNDA2NywyNzQ5MywzMTgwNywzNzA5NiwyNDU5OCwyNTgzMCwyOTQ2OCwzNTAwOSwyNjQ0OCwyNTE2NSwzNjEzMCwzMDU3MiwzNjM5MywzNzMxOSwyNDQyNSwzMzc1NiwzNDA4MSwzOTE4NCwyMTQ0MiwzNDQ1MywyNzUzMSwyNDgxMywyNDgwOCwyODc5OSwzMzQ4NSwzMzMyOSwyMDE3OSwyNzgxNSwzNDI1NSwyNTgwNSwzMTk2MSwyNzEzMywyNjM2MSwzMzYwOSwyMTM5NywzMTU3NCwyMDM5MSwyMDg3NiwyNzk3OSwyMzYxOCwzNjQ2MSwyNTU1NCwyMTQ0OSwzMzU4MCwzMzU5MCwyNjU5NywzMDkwMCwyNTY2MSwyMzUxOSwyMzcwMCwyNDA0NiwzNTgxNSwyNTI4NiwyNjYxMiwzNTk2MiwyNTYwMCwyNTUzMCwzNDYzMywzOTMwNywzNTg2MywzMjU0NCwzODEzMCwyMDEzNSwzODQxNiwzOTA3NiwyNjEyNCwyOTQ2MiwzMDY5NCwzMDY5NiwzMDY5OCwzMDcwMywzMDcwNCwzMDcwNSwzMDcwNiwzMDcwOCwzMDcwOSwzMDcxMSwzMDcxMywzMDcxNCwzMDcxNSwzMDcxNiwzMDcyMywzMDcyNCwzMDcyNSwzMDcyNiwzMDcyNywzMDcyOCwzMDczMCwzMDczMSwzMDczNCwzMDczNSwzMDczNiwzMDczOSwzMDc0MSwzMDc0NSwzMDc0NywzMDc1MCwzMDc1MiwzMDc1MywzMDc1NCwzMDc1NiwzMDc2MCwzMDc2MiwzMDc2MywzMDc2NiwzMDc2NywzMDc2OSwzMDc3MCwzMDc3MSwzMDc3MywzMDc3NCwzMDc4MSwzMDc4MywzMDc4NSwzMDc4NiwzMDc4NywzMDc4OCwzMDc5MCwzMDc5MiwzMDc5MywzMDc5NCwzMDc5NSwzMDc5NywzMDc5OSwzMDgwMSwzMDgwMywzMDgwNCwzMDgwOCwzMDgwOSwzMDgxMCwzMDgxMSwzMDgxMiwzMDgxNCwzMDgxNSwzMDgxNiwzMDgxNywzMDgxOCwzMDgxOSwzMDgyMCwzMDgyMSwzMDgyMiwzMDgyMywzMDgyNCwzMDgyNSwzMDgzMSwzMDgzMiwzMDgzMywzMDgzNCwzMDgzNSwzMDgzNiwzMDgzNywzMDgzOCwzMDg0MCwzMDg0MSwzMDg0MiwzMDg0MywzMDg0NSwzMDg0NiwzMDg0NywzMDg0OCwzMDg0OSwzMDg1MCwzMDg1MSwyMjMzMCwyMzU4MSwyNDEyMCwzODI3MSwyMDYwNywzMjkyOCwyMTM3OCwyNTk1MCwzMDAyMSwyMTgwOSwyMDUxMywzNjIyOSwyNTIyMCwzODA0NiwyNjM5NywyMjA2NiwyODUyNiwyNDAzNCwyMTU1NywyODgxOCwzNjcxMCwyNTE5OSwyNTc2NCwyNTUwNywyNDQ0MywyODU1MiwzNzEwOCwzMzI1MSwzNjc4NCwyMzU3NiwyNjIxNiwyNDU2MSwyNzc4NSwzODQ3MiwzNjIyNSwzNDkyNCwyNTc0NSwzMTIxNiwyMjQ3OCwyNzIyNSwyNTEwNCwyMTU3NiwyMDA1NiwzMTI0MywyNDgwOSwyODU0OCwzNTgwMiwyNTIxNSwzNjg5NCwzOTU2MywzMTIwNCwyMTUwNywzMDE5NiwyNTM0NSwyMTI3MywyNzc0NCwzNjgzMSwyNDM0NywzOTUzNiwzMjgyNyw0MDgzMSwyMDM2MCwyMzYxMCwzNjE5NiwzMjcwOSwyNjAyMSwyODg2MSwyMDgwNSwyMDkxNCwzNDQxMSwyMzgxNSwyMzQ1NiwyNTI3NywzNzIyOCwzMDA2OCwzNjM2NCwzMTI2NCwyNDgzMywzMTYwOSwyMDE2NywzMjUwNCwzMDU5NywxOTk4NSwzMzI2MSwyMTAyMSwyMDk4NiwyNzI0OSwyMTQxNiwzNjQ4NywzODE0OCwzODYwNywyODM1MywzODUwMCwyNjk3MCwzMDg1MiwzMDg1MywzMDg1NCwzMDg1NiwzMDg1OCwzMDg1OSwzMDg2MywzMDg2NCwzMDg2NiwzMDg2OCwzMDg2OSwzMDg3MCwzMDg3MywzMDg3NywzMDg3OCwzMDg4MCwzMDg4MiwzMDg4NCwzMDg4NiwzMDg4OCwzMDg4OSwzMDg5MCwzMDg5MSwzMDg5MiwzMDg5MywzMDg5NCwzMDg5NSwzMDkwMSwzMDkwMiwzMDkwMywzMDkwNCwzMDkwNiwzMDkwNywzMDkwOCwzMDkwOSwzMDkxMSwzMDkxMiwzMDkxNCwzMDkxNSwzMDkxNiwzMDkxOCwzMDkxOSwzMDkyMCwzMDkyNCwzMDkyNSwzMDkyNiwzMDkyNywzMDkyOSwzMDkzMCwzMDkzMSwzMDkzNCwzMDkzNSwzMDkzNiwzMDkzOCwzMDkzOSwzMDk0MCwzMDk0MSwzMDk0MiwzMDk0MywzMDk0NCwzMDk0NSwzMDk0NiwzMDk0NywzMDk0OCwzMDk0OSwzMDk1MCwzMDk1MSwzMDk1MywzMDk1NCwzMDk1NSwzMDk1NywzMDk1OCwzMDk1OSwzMDk2MCwzMDk2MSwzMDk2MywzMDk2NSwzMDk2NiwzMDk2OCwzMDk2OSwzMDk3MSwzMDk3MiwzMDk3MywzMDk3NCwzMDk3NSwzMDk3NiwzMDk3OCwzMDk3OSwzMDk4MCwzMDk4MiwzMDk4MywzMDk4NCwzMDk4NSwzMDk4NiwzMDk4NywzMDk4OCwzMDc4NCwyMDY0OCwzMDY3OSwyNTYxNiwzNTMwMiwyMjc4OCwyNTU3MSwyNDAyOSwzMTM1OSwyNjk0MSwyMDI1NiwzMzMzNywyMTkxMiwyMDAxOCwzMDEyNiwzMTM4MywyNDE2MiwyNDIwMiwzODM4MywyMTAxOSwyMTU2MSwyODgxMCwyNTQ2MiwzODE4MCwyMjQwMiwyNjE0OSwyNjk0MywzNzI1NSwyMTc2NywyODE0NywzMjQzMSwzNDg1MCwyNTEzOSwzMjQ5NiwzMDEzMywzMzU3NiwzMDkxMywzODYwNCwzNjc2NiwyNDkwNCwyOTk0MywzNTc4OSwyNzQ5MiwyMTA1MCwzNjE3NiwyNzQyNSwzMjg3NCwzMzkwNSwyMjI1NywyMTI1NCwyMDE3NCwxOTk5NSwyMDk0NSwzMTg5NSwzNzI1OSwzMTc1MSwyMDQxOSwzNjQ3OSwzMTcxMywzMTM4OCwyNTcwMywyMzgyOCwyMDY1MiwzMzAzMCwzMDIwOSwzMTkyOSwyODE0MCwzMjczNiwyNjQ0OSwyMzM4NCwyMzU0NCwzMDkyMywyNTc3NCwyNTYxOSwyNTUxNCwyNTM4NywzODE2OSwyNTY0NSwzNjc5OCwzMTU3MiwzMDI0OSwyNTE3MSwyMjgyMywyMTU3NCwyNzUxMywyMDY0MywyNTE0MCwyNDEwMiwyNzUyNiwyMDE5NSwzNjE1MSwzNDk1NSwyNDQ1MywzNjkxMCwzMDk4OSwzMDk5MCwzMDk5MSwzMDk5MiwzMDk5MywzMDk5NCwzMDk5NiwzMDk5NywzMDk5OCwzMDk5OSwzMTAwMCwzMTAwMSwzMTAwMiwzMTAwMywzMTAwNCwzMTAwNSwzMTAwNywzMTAwOCwzMTAwOSwzMTAxMCwzMTAxMSwzMTAxMywzMTAxNCwzMTAxNSwzMTAxNiwzMTAxNywzMTAxOCwzMTAxOSwzMTAyMCwzMTAyMSwzMTAyMiwzMTAyMywzMTAyNCwzMTAyNSwzMTAyNiwzMTAyNywzMTAyOSwzMTAzMCwzMTAzMSwzMTAzMiwzMTAzMywzMTAzNywzMTAzOSwzMTA0MiwzMTA0MywzMTA0NCwzMTA0NSwzMTA0NywzMTA1MCwzMTA1MSwzMTA1MiwzMTA1MywzMTA1NCwzMTA1NSwzMTA1NiwzMTA1NywzMTA1OCwzMTA2MCwzMTA2MSwzMTA2NCwzMTA2NSwzMTA3MywzMTA3NSwzMTA3NiwzMTA3OCwzMTA4MSwzMTA4MiwzMTA4MywzMTA4NCwzMTA4NiwzMTA4OCwzMTA4OSwzMTA5MCwzMTA5MSwzMTA5MiwzMTA5MywzMTA5NCwzMTA5NywzMTA5OSwzMTEwMCwzMTEwMSwzMTEwMiwzMTEwMywzMTEwNiwzMTEwNywzMTExMCwzMTExMSwzMTExMiwzMTExMywzMTExNSwzMTExNiwzMTExNywzMTExOCwzMTEyMCwzMTEyMSwzMTEyMiwyNDYwOCwzMjgyOSwyNTI4NSwyMDAyNSwyMTMzMywzNzExMiwyNTUyOCwzMjk2NiwyNjA4NiwyNzY5NCwyMDI5NCwyNDgxNCwyODEyOSwzNTgwNiwyNDM3NywzNDUwNywyNDQwMywyNTM3NywyMDgyNiwzMzYzMywyNjcyMywyMDk5MiwyNTQ0MywzNjQyNCwyMDQ5OCwyMzcwNywzMTA5NSwyMzU0OCwyMTA0MCwzMTI5MSwyNDc2NCwzNjk0NywzMDQyMywyNDUwMywyNDQ3MSwzMDM0MCwzNjQ2MCwyODc4MywzMDMzMSwzMTU2MSwzMDYzNCwyMDk3OSwzNzAxMSwyMjU2NCwyMDMwMiwyODQwNCwzNjg0MiwyNTkzMiwzMTUxNSwyOTM4MCwyODA2OCwzMjczNSwyMzI2NSwyNTI2OSwyNDIxMywyMjMyMCwzMzkyMiwzMTUzMiwyNDA5MywyNDM1MSwzNjg4MiwzMjUzMiwzOTA3MiwyNTQ3NCwyODM1OSwzMDg3MiwyODg1NywyMDg1NiwzODc0NywyMjQ0MywzMDAwNSwyMDI5MSwzMDAwOCwyNDIxNSwyNDgwNiwyMjg4MCwyODA5NiwyNzU4MywzMDg1NywyMTUwMCwzODYxMywyMDkzOSwyMDk5MywyNTQ4MSwyMTUxNCwzODAzNSwzNTg0MywzNjMwMCwyOTI0MSwzMDg3OSwzNDY3OCwzNjg0NSwzNTg1MywyMTQ3MiwzMTEyMywzMTEyNCwzMTEyNSwzMTEyNiwzMTEyNywzMTEyOCwzMTEyOSwzMTEzMSwzMTEzMiwzMTEzMywzMTEzNCwzMTEzNSwzMTEzNiwzMTEzNywzMTEzOCwzMTEzOSwzMTE0MCwzMTE0MSwzMTE0MiwzMTE0NCwzMTE0NSwzMTE0NiwzMTE0NywzMTE0OCwzMTE0OSwzMTE1MCwzMTE1MSwzMTE1MiwzMTE1MywzMTE1NCwzMTE1NiwzMTE1NywzMTE1OCwzMTE1OSwzMTE2MCwzMTE2NCwzMTE2NywzMTE3MCwzMTE3MiwzMTE3MywzMTE3NSwzMTE3NiwzMTE3OCwzMTE4MCwzMTE4MiwzMTE4MywzMTE4NCwzMTE4NywzMTE4OCwzMTE5MCwzMTE5MSwzMTE5MywzMTE5NCwzMTE5NSwzMTE5NiwzMTE5NywzMTE5OCwzMTIwMCwzMTIwMSwzMTIwMiwzMTIwNSwzMTIwOCwzMTIxMCwzMTIxMiwzMTIxNCwzMTIxNywzMTIxOCwzMTIxOSwzMTIyMCwzMTIyMSwzMTIyMiwzMTIyMywzMTIyNSwzMTIyNiwzMTIyOCwzMTIzMCwzMTIzMSwzMTIzMywzMTIzNiwzMTIzNywzMTIzOSwzMTI0MCwzMTI0MSwzMTI0MiwzMTI0NCwzMTI0NywzMTI0OCwzMTI0OSwzMTI1MCwzMTI1MSwzMTI1MywzMTI1NCwzMTI1NiwzMTI1NywzMTI1OSwzMTI2MCwxOTk2OSwzMDQ0NywyMTQ4NiwzODAyNSwzOTAzMCw0MDcxOCwzODE4OSwyMzQ1MCwzNTc0NiwyMDAwMiwxOTk5NiwyMDkwOCwzMzg5MSwyNTAyNiwyMTE2MCwyNjYzNSwyMDM3NSwyNDY4MywyMDkyMywyNzkzNCwyMDgyOCwyNTIzOCwyNjAwNywzODQ5NywzNTkxMCwzNjg4NywzMDE2OCwzNzExNywzMDU2MywyNzYwMiwyOTMyMiwyOTQyMCwzNTgzNSwyMjU4MSwzMDU4NSwzNjE3MiwyNjQ2MCwzODIwOCwzMjkyMiwyNDIzMCwyODE5MywyMjkzMCwzMTQ3MSwzMDcwMSwzODIwMywyNzU3MywyNjAyOSwzMjUyNiwyMjUzNCwyMDgxNywzODQzMSwyMzU0NSwyMjY5NywyMTU0NCwzNjQ2NiwyNTk1OCwzOTAzOSwyMjI0NCwzODA0NSwzMDQ2MiwzNjkyOSwyNTQ3OSwyMTcwMiwyMjgxMCwyMjg0MiwyMjQyNywzNjUzMCwyNjQyMSwzNjM0NiwzMzMzMywyMTA1NywyNDgxNiwyMjU0OSwzNDU1OCwyMzc4NCw0MDUxNywyMDQyMCwzOTA2OSwzNTc2OSwyMzA3NywyNDY5NCwyMTM4MCwyNTIxMiwzNjk0MywzNzEyMiwzOTI5NSwyNDY4MSwzMjc4MCwyMDc5OSwzMjgxOSwyMzU3MiwzOTI4NSwyNzk1MywyMDEwOCwzMTI2MSwzMTI2MywzMTI2NSwzMTI2NiwzMTI2OCwzMTI2OSwzMTI3MCwzMTI3MSwzMTI3MiwzMTI3MywzMTI3NCwzMTI3NSwzMTI3NiwzMTI3NywzMTI3OCwzMTI3OSwzMTI4MCwzMTI4MSwzMTI4MiwzMTI4NCwzMTI4NSwzMTI4NiwzMTI4OCwzMTI5MCwzMTI5NCwzMTI5NiwzMTI5NywzMTI5OCwzMTI5OSwzMTMwMCwzMTMwMSwzMTMwMywzMTMwNCwzMTMwNSwzMTMwNiwzMTMwNywzMTMwOCwzMTMwOSwzMTMxMCwzMTMxMSwzMTMxMiwzMTMxNCwzMTMxNSwzMTMxNiwzMTMxNywzMTMxOCwzMTMyMCwzMTMyMSwzMTMyMiwzMTMyMywzMTMyNCwzMTMyNSwzMTMyNiwzMTMyNywzMTMyOCwzMTMyOSwzMTMzMCwzMTMzMSwzMTMzMiwzMTMzMywzMTMzNCwzMTMzNSwzMTMzNiwzMTMzNywzMTMzOCwzMTMzOSwzMTM0MCwzMTM0MSwzMTM0MiwzMTM0MywzMTM0NSwzMTM0NiwzMTM0NywzMTM0OSwzMTM1NSwzMTM1NiwzMTM1NywzMTM1OCwzMTM2MiwzMTM2NSwzMTM2NywzMTM2OSwzMTM3MCwzMTM3MSwzMTM3MiwzMTM3NCwzMTM3NSwzMTM3NiwzMTM3OSwzMTM4MCwzMTM4NSwzMTM4NiwzMTM4NywzMTM5MCwzMTM5MywzMTM5NCwzNjE0NCwyMTQ1NywzMjYwMiwzMTU2NywyMDI0MCwyMDA0NywzODQwMCwyNzg2MSwyOTY0OCwzNDI4MSwyNDA3MCwzMDA1OCwzMjc2MywyNzE0NiwzMDcxOCwzODAzNCwzMjMyMSwyMDk2MSwyODkwMiwyMTQ1MywzNjgyMCwzMzUzOSwzNjEzNywyOTM1OSwzOTI3NywyNzg2NywyMjM0NiwzMzQ1OSwyNjA0MSwzMjkzOCwyNTE1MSwzODQ1MCwyMjk1MiwyMDIyMywzNTc3NSwzMjQ0MiwyNTkxOCwzMzc3OCwzODc1MCwyMTg1NywzOTEzNCwzMjkzMywyMTI5MCwzNTgzNywyMTUzNiwzMjk1NCwyNDIyMywyNzgzMiwzNjE1MywzMzQ1MiwzNzIxMCwyMTU0NSwyNzY3NSwyMDk5OCwzMjQzOSwyMjM2NywyODk1NCwyNzc3NCwzMTg4MSwyMjg1OSwyMDIyMSwyNDU3NSwyNDg2OCwzMTkxNCwyMDAxNiwyMzU1MywyNjUzOSwzNDU2MiwyMzc5MiwzODE1NSwzOTExOCwzMDEyNywyODkyNSwzNjg5OCwyMDkxMSwzMjU0MSwzNTc3MywyMjg1NywyMDk2NCwyMDMxNSwyMTU0MiwyMjgyNywyNTk3NSwzMjkzMiwyMzQxMywyNTIwNiwyNTI4MiwzNjc1MiwyNDEzMywyNzY3OSwzMTUyNiwyMDIzOSwyMDQ0MCwyNjM4MSwzMTM5NSwzMTM5NiwzMTM5OSwzMTQwMSwzMTQwMiwzMTQwMywzMTQwNiwzMTQwNywzMTQwOCwzMTQwOSwzMTQxMCwzMTQxMiwzMTQxMywzMTQxNCwzMTQxNSwzMTQxNiwzMTQxNywzMTQxOCwzMTQxOSwzMTQyMCwzMTQyMSwzMTQyMiwzMTQyNCwzMTQyNSwzMTQyNiwzMTQyNywzMTQyOCwzMTQyOSwzMTQzMCwzMTQzMSwzMTQzMiwzMTQzMywzMTQzNCwzMTQzNiwzMTQzNywzMTQzOCwzMTQzOSwzMTQ0MCwzMTQ0MSwzMTQ0MiwzMTQ0MywzMTQ0NCwzMTQ0NSwzMTQ0NywzMTQ0OCwzMTQ1MCwzMTQ1MSwzMTQ1MiwzMTQ1MywzMTQ1NywzMTQ1OCwzMTQ2MCwzMTQ2MywzMTQ2NCwzMTQ2NSwzMTQ2NiwzMTQ2NywzMTQ2OCwzMTQ3MCwzMTQ3MiwzMTQ3MywzMTQ3NCwzMTQ3NSwzMTQ3NiwzMTQ3NywzMTQ3OCwzMTQ3OSwzMTQ4MCwzMTQ4MywzMTQ4NCwzMTQ4NiwzMTQ4OCwzMTQ4OSwzMTQ5MCwzMTQ5MywzMTQ5NSwzMTQ5NywzMTUwMCwzMTUwMSwzMTUwMiwzMTUwNCwzMTUwNiwzMTUwNywzMTUxMCwzMTUxMSwzMTUxMiwzMTUxNCwzMTUxNiwzMTUxNywzMTUxOSwzMTUyMSwzMTUyMiwzMTUyMywzMTUyNywzMTUyOSwzMTUzMywyODAxNCwyODA3NCwzMTExOSwzNDk5MywyNDM0MywyOTk5NSwyNTI0MiwzNjc0MSwyMDQ2MywzNzM0MCwyNjAyMywzMzA3MSwzMzEwNSwyNDIyMCwzMzEwNCwzNjIxMiwyMTEwMywzNTIwNiwzNjE3MSwyMjc5NywyMDYxMywyMDE4NCwzODQyOCwyOTIzOCwzMzE0NSwzNjEyNywyMzUwMCwzNTc0NywzODQ2OCwyMjkxOSwzMjUzOCwyMTY0OCwyMjEzNCwyMjAzMCwzNTgxMywyNTkxMywyNzAxMCwzODA0MSwzMDQyMiwyODI5NywyNDE3OCwyOTk3NiwyNjQzOCwyNjU3NywzMTQ4NywzMjkyNSwzNjIxNCwyNDg2MywzMTE3NCwyNTk1NCwzNjE5NSwyMDg3MiwyMTAxOCwzODA1MCwzMjU2OCwzMjkyMywzMjQzNCwyMzcwMywyODIwNywyNjQ2NCwzMTcwNSwzMDM0NywzOTY0MCwzMzE2NywzMjY2MCwzMTk1NywyNTYzMCwzODIyNCwzMTI5NSwyMTU3OCwyMTczMywyNzQ2OCwyNTYwMSwyNTA5Niw0MDUwOSwzMzAxMSwzMDEwNSwyMTEwNiwzODc2MSwzMzg4MywyNjY4NCwzNDUzMiwzODQwMSwzODU0OCwzODEyNCwyMDAxMCwyMTUwOCwzMjQ3MywyNjY4MSwzNjMxOSwzMjc4OSwyNjM1NiwyNDIxOCwzMjY5NywzMTUzNSwzMTUzNiwzMTUzOCwzMTU0MCwzMTU0MSwzMTU0MiwzMTU0MywzMTU0NSwzMTU0NywzMTU0OSwzMTU1MSwzMTU1MiwzMTU1MywzMTU1NCwzMTU1NSwzMTU1NiwzMTU1OCwzMTU2MCwzMTU2MiwzMTU2NSwzMTU2NiwzMTU3MSwzMTU3MywzMTU3NSwzMTU3NywzMTU4MCwzMTU4MiwzMTU4MywzMTU4NSwzMTU4NywzMTU4OCwzMTU4OSwzMTU5MCwzMTU5MSwzMTU5MiwzMTU5MywzMTU5NCwzMTU5NSwzMTU5NiwzMTU5NywzMTU5OSwzMTYwMCwzMTYwMywzMTYwNCwzMTYwNiwzMTYwOCwzMTYxMCwzMTYxMiwzMTYxMywzMTYxNSwzMTYxNywzMTYxOCwzMTYxOSwzMTYyMCwzMTYyMiwzMTYyMywzMTYyNCwzMTYyNSwzMTYyNiwzMTYyNywzMTYyOCwzMTYzMCwzMTYzMSwzMTYzMywzMTYzNCwzMTYzNSwzMTYzOCwzMTY0MCwzMTY0MSwzMTY0MiwzMTY0MywzMTY0NiwzMTY0NywzMTY0OCwzMTY1MSwzMTY1MiwzMTY1MywzMTY2MiwzMTY2MywzMTY2NCwzMTY2NiwzMTY2NywzMTY2OSwzMTY3MCwzMTY3MSwzMTY3MywzMTY3NCwzMTY3NSwzMTY3NiwzMTY3NywzMTY3OCwzMTY3OSwzMTY4MCwzMTY4MiwzMTY4MywzMTY4NCwyMjQ2NiwzMjgzMSwyNjc3NSwyNDAzNywyNTkxNSwyMTE1MSwyNDY4NSw0MDg1OCwyMDM3OSwzNjUyNCwyMDg0NCwyMzQ2NywyNDMzOSwyNDA0MSwyNzc0MiwyNTMyOSwzNjEyOSwyMDg0OSwzODA1NywyMTI0NiwyNzgwNywzMzUwMywyOTM5OSwyMjQzNCwyNjUwMCwzNjE0MSwyMjgxNSwzNjc2NCwzMzczNSwyMTY1MywzMTYyOSwyMDI3MiwyNzgzNywyMzM5NiwyMjk5Myw0MDcyMywyMTQ3NiwzNDUwNiwzOTU5MiwzNTg5NSwzMjkyOSwyNTkyNSwzOTAzOCwyMjI2NiwzODU5OSwyMTAzOCwyOTkxNiwyMTA3MiwyMzUyMSwyNTM0NiwzNTA3NCwyMDA1NCwyNTI5NiwyNDYxOCwyNjg3NCwyMDg1MSwyMzQ0OCwyMDg5NiwzNTI2NiwzMTY0OSwzOTMwMiwzMjU5MiwyNDgxNSwyODc0OCwzNjE0MywyMDgwOSwyNDE5MSwzNjg5MSwyOTgwOCwzNTI2OCwyMjMxNywzMDc4OSwyNDQwMiw0MDg2MywzODM5NCwzNjcxMiwzOTc0MCwzNTgwOSwzMDMyOCwyNjY5MCwyNjU4OCwzNjMzMCwzNjE0OSwyMTA1MywzNjc0NiwyODM3OCwyNjgyOSwzODE0OSwzNzEwMSwyMjI2OSwyNjUyNCwzNTA2NSwzNjgwNywyMTcwNCwzMTY4NSwzMTY4OCwzMTY4OSwzMTY5MCwzMTY5MSwzMTY5MywzMTY5NCwzMTY5NSwzMTY5NiwzMTY5OCwzMTcwMCwzMTcwMSwzMTcwMiwzMTcwMywzMTcwNCwzMTcwNywzMTcwOCwzMTcxMCwzMTcxMSwzMTcxMiwzMTcxNCwzMTcxNSwzMTcxNiwzMTcxOSwzMTcyMCwzMTcyMSwzMTcyMywzMTcyNCwzMTcyNSwzMTcyNywzMTcyOCwzMTczMCwzMTczMSwzMTczMiwzMTczMywzMTczNCwzMTczNiwzMTczNywzMTczOCwzMTczOSwzMTc0MSwzMTc0MywzMTc0NCwzMTc0NSwzMTc0NiwzMTc0NywzMTc0OCwzMTc0OSwzMTc1MCwzMTc1MiwzMTc1MywzMTc1NCwzMTc1NywzMTc1OCwzMTc2MCwzMTc2MSwzMTc2MiwzMTc2MywzMTc2NCwzMTc2NSwzMTc2NywzMTc2OCwzMTc2OSwzMTc3MCwzMTc3MSwzMTc3MiwzMTc3MywzMTc3NCwzMTc3NiwzMTc3NywzMTc3OCwzMTc3OSwzMTc4MCwzMTc4MSwzMTc4NCwzMTc4NSwzMTc4NywzMTc4OCwzMTc4OSwzMTc5MCwzMTc5MSwzMTc5MiwzMTc5MywzMTc5NCwzMTc5NSwzMTc5NiwzMTc5NywzMTc5OCwzMTc5OSwzMTgwMSwzMTgwMiwzMTgwMywzMTgwNCwzMTgwNSwzMTgwNiwzMTgxMCwzOTYwOCwyMzQwMSwyODAyMywyNzY4NiwyMDEzMywyMzQ3NSwzOTU1OSwzNzIxOSwyNTAwMCwzNzAzOSwzODg4OSwyMTU0NywyODA4NSwyMzUwNiwyMDk4OSwyMTg5OCwzMjU5NywzMjc1MiwyNTc4OCwyNTQyMSwyNjA5NywyNTAyMiwyNDcxNywyODkzOCwyNzczNSwyNzcyMSwyMjgzMSwyNjQ3NywzMzMyMiwyMjc0MSwyMjE1OCwzNTk0NiwyNzYyNywzNzA4NSwyMjkwOSwzMjc5MSwyMTQ5NSwyODAwOSwyMTYyMSwyMTkxNywzMzY1NSwzMzc0MywyNjY4MCwzMTE2NiwyMTY0NCwyMDMwOSwyMTUxMiwzMDQxOCwzNTk3NywzODQwMiwyNzgyNywyODA4OCwzNjIwMywzNTA4OCw0MDU0OCwzNjE1NCwyMjA3OSw0MDY1NywzMDE2NSwyNDQ1NiwyOTQwOCwyNDY4MCwyMTc1NiwyMDEzNiwyNzE3OCwzNDkxMywyNDY1OCwzNjcyMCwyMTcwMCwyODg4OCwzNDQyNSw0MDUxMSwyNzk0NiwyMzQzOSwyNDM0NCwzMjQxOCwyMTg5NywyMDM5OSwyOTQ5MiwyMTU2NCwyMTQwMiwyMDUwNSwyMTUxOCwyMTYyOCwyMDA0NiwyNDU3MywyOTc4NiwyMjc3NCwzMzg5OSwzMjk5MywzNDY3NiwyOTM5MiwzMTk0NiwyODI0NiwzMTgxMSwzMTgxMiwzMTgxMywzMTgxNCwzMTgxNSwzMTgxNiwzMTgxNywzMTgxOCwzMTgxOSwzMTgyMCwzMTgyMiwzMTgyMywzMTgyNCwzMTgyNSwzMTgyNiwzMTgyNywzMTgyOCwzMTgyOSwzMTgzMCwzMTgzMSwzMTgzMiwzMTgzMywzMTgzNCwzMTgzNSwzMTgzNiwzMTgzNywzMTgzOCwzMTgzOSwzMTg0MCwzMTg0MSwzMTg0MiwzMTg0MywzMTg0NCwzMTg0NSwzMTg0NiwzMTg0NywzMTg0OCwzMTg0OSwzMTg1MCwzMTg1MSwzMTg1MiwzMTg1MywzMTg1NCwzMTg1NSwzMTg1NiwzMTg1NywzMTg1OCwzMTg2MSwzMTg2MiwzMTg2MywzMTg2NCwzMTg2NSwzMTg2NiwzMTg3MCwzMTg3MSwzMTg3MiwzMTg3MywzMTg3NCwzMTg3NSwzMTg3NiwzMTg3NywzMTg3OCwzMTg3OSwzMTg4MCwzMTg4MiwzMTg4MywzMTg4NCwzMTg4NSwzMTg4NiwzMTg4NywzMTg4OCwzMTg5MSwzMTg5MiwzMTg5NCwzMTg5NywzMTg5OCwzMTg5OSwzMTkwNCwzMTkwNSwzMTkwNywzMTkxMCwzMTkxMSwzMTkxMiwzMTkxMywzMTkxNSwzMTkxNiwzMTkxNywzMTkxOSwzMTkyMCwzMTkyNCwzMTkyNSwzMTkyNiwzMTkyNywzMTkyOCwzMTkzMCwzMTkzMSwyNDM1OSwzNDM4MiwyMTgwNCwyNTI1MiwyMDExNCwyNzgxOCwyNTE0MywzMzQ1NywyMTcxOSwyMTMyNiwyOTUwMiwyODM2OSwzMDAxMSwyMTAxMCwyMTI3MCwzNTgwNSwyNzA4OCwyNDQ1OCwyNDU3NiwyODE0MiwyMjM1MSwyNzQyNiwyOTYxNSwyNjcwNywzNjgyNCwzMjUzMSwyNTQ0MiwyNDczOSwyMTc5NiwzMDE4NiwzNTkzOCwyODk0OSwyODA2NywyMzQ2MiwyNDE4NywzMzYxOCwyNDkwOCw0MDY0NCwzMDk3MCwzNDY0NywzMTc4MywzMDM0MywyMDk3NiwyNDgyMiwyOTAwNCwyNjE3OSwyNDE0MCwyNDY1MywzNTg1NCwyODc4NCwyNTM4MSwzNjc0NSwyNDUwOSwyNDY3NCwzNDUxNiwyMjIzOCwyNzU4NSwyNDcyNCwyNDkzNSwyMTMyMSwyNDgwMCwyNjIxNCwzNjE1OSwzMTIyOSwyMDI1MCwyODkwNSwyNzcxOSwzNTc2MywzNTgyNiwzMjQ3MiwzMzYzNiwyNjEyNywyMzEzMCwzOTc0NiwyNzk4NSwyODE1MSwzNTkwNSwyNzk2MywyMDI0OSwyODc3OSwzMzcxOSwyNTExMCwyNDc4NSwzODY2OSwzNjEzNSwzMTA5NiwyMDk4NywyMjMzNCwyMjUyMiwyNjQyNiwzMDA3MiwzMTI5MywzMTIxNSwzMTYzNywzMTkzNSwzMTkzNiwzMTkzOCwzMTkzOSwzMTk0MCwzMTk0MiwzMTk0NSwzMTk0NywzMTk1MCwzMTk1MSwzMTk1MiwzMTk1MywzMTk1NCwzMTk1NSwzMTk1NiwzMTk2MCwzMTk2MiwzMTk2MywzMTk2NSwzMTk2NiwzMTk2OSwzMTk3MCwzMTk3MSwzMTk3MiwzMTk3MywzMTk3NCwzMTk3NSwzMTk3NywzMTk3OCwzMTk3OSwzMTk4MCwzMTk4MSwzMTk4MiwzMTk4NCwzMTk4NSwzMTk4NiwzMTk4NywzMTk4OCwzMTk4OSwzMTk5MCwzMTk5MSwzMTk5MywzMTk5NCwzMTk5NiwzMTk5NywzMTk5OCwzMTk5OSwzMjAwMCwzMjAwMSwzMjAwMiwzMjAwMywzMjAwNCwzMjAwNSwzMjAwNiwzMjAwNywzMjAwOCwzMjAwOSwzMjAxMSwzMjAxMiwzMjAxMywzMjAxNCwzMjAxNSwzMjAxNiwzMjAxNywzMjAxOCwzMjAxOSwzMjAyMCwzMjAyMSwzMjAyMiwzMjAyMywzMjAyNCwzMjAyNSwzMjAyNiwzMjAyNywzMjAyOCwzMjAyOSwzMjAzMCwzMjAzMSwzMjAzMywzMjAzNSwzMjAzNiwzMjAzNywzMjAzOCwzMjA0MCwzMjA0MSwzMjA0MiwzMjA0NCwzMjA0NSwzMjA0NiwzMjA0OCwzMjA0OSwzMjA1MCwzMjA1MSwzMjA1MiwzMjA1MywzMjA1NCwzMjkwOCwzOTI2OSwzNjg1NywyODYwOCwzNTc0OSw0MDQ4MSwyMzAyMCwzMjQ4OSwzMjUyMSwyMTUxMywyNjQ5NywyNjg0MCwzNjc1MywzMTgyMSwzODU5OCwyMTQ1MCwyNDYxMywzMDE0MiwyNzc2MiwyMTM2MywyMzI0MSwzMjQyMywyNTM4MCwyMDk2MCwzMzAzNCwyNDA0OSwzNDAxNSwyNTIxNiwyMDg2NCwyMzM5NSwyMDIzOCwzMTA4NSwyMTA1OCwyNDc2MCwyNzk4MiwyMzQ5MiwyMzQ5MCwzNTc0NSwzNTc2MCwyNjA4MiwyNDUyNCwzODQ2OSwyMjkzMSwzMjQ4NywzMjQyNiwyMjAyNSwyNjU1MSwyMjg0MSwyMDMzOSwyMzQ3OCwyMTE1MiwzMzYyNiwzOTA1MCwzNjE1OCwzMDAwMiwzODA3OCwyMDU1MSwzMTI5MiwyMDIxNSwyNjU1MCwzOTU1MCwyMzIzMywyNzUxNiwzMDQxNywyMjM2MiwyMzU3NCwzMTU0NiwzODM4OCwyOTAwNiwyMDg2MCwzMjkzNywzMzM5MiwyMjkwNCwzMjUxNiwzMzU3NSwyNjgxNiwyNjYwNCwzMDg5NywzMDgzOSwyNTMxNSwyNTQ0MSwzMTYxNiwyMDQ2MSwyMTA5OCwyMDk0MywzMzYxNiwyNzA5OSwzNzQ5MiwzNjM0MSwzNjE0NSwzNTI2NSwzODE5MCwzMTY2MSwyMDIxNCwzMjA1NSwzMjA1NiwzMjA1NywzMjA1OCwzMjA1OSwzMjA2MCwzMjA2MSwzMjA2MiwzMjA2MywzMjA2NCwzMjA2NSwzMjA2NiwzMjA2NywzMjA2OCwzMjA2OSwzMjA3MCwzMjA3MSwzMjA3MiwzMjA3MywzMjA3NCwzMjA3NSwzMjA3NiwzMjA3NywzMjA3OCwzMjA3OSwzMjA4MCwzMjA4MSwzMjA4MiwzMjA4MywzMjA4NCwzMjA4NSwzMjA4NiwzMjA4NywzMjA4OCwzMjA4OSwzMjA5MCwzMjA5MSwzMjA5MiwzMjA5MywzMjA5NCwzMjA5NSwzMjA5NiwzMjA5NywzMjA5OCwzMjA5OSwzMjEwMCwzMjEwMSwzMjEwMiwzMjEwMywzMjEwNCwzMjEwNSwzMjEwNiwzMjEwNywzMjEwOCwzMjEwOSwzMjExMSwzMjExMiwzMjExMywzMjExNCwzMjExNSwzMjExNiwzMjExNywzMjExOCwzMjEyMCwzMjEyMSwzMjEyMiwzMjEyMywzMjEyNCwzMjEyNSwzMjEyNiwzMjEyNywzMjEyOCwzMjEyOSwzMjEzMCwzMjEzMSwzMjEzMiwzMjEzMywzMjEzNCwzMjEzNSwzMjEzNiwzMjEzNywzMjEzOCwzMjEzOSwzMjE0MCwzMjE0MSwzMjE0MiwzMjE0MywzMjE0NCwzMjE0NSwzMjE0NiwzMjE0NywzMjE0OCwzMjE0OSwzMjE1MCwzMjE1MSwzMjE1MiwyMDU4MSwzMzMyOCwyMTA3MywzOTI3OSwyODE3NiwyODI5MywyODA3MSwyNDMxNCwyMDcyNSwyMzAwNCwyMzU1OCwyNzk3NCwyNzc0MywzMDA4NiwzMzkzMSwyNjcyOCwyMjg3MCwzNTc2MiwyMTI4MCwzNzIzMywzODQ3NywzNDEyMSwyNjg5OCwzMDk3NywyODk2NiwzMzAxNCwyMDEzMiwzNzA2NiwyNzk3NSwzOTU1NiwyMzA0NywyMjIwNCwyNTYwNSwzODEyOCwzMDY5OSwyMDM4OSwzMzA1MCwyOTQwOSwzNTI4MiwzOTI5MCwzMjU2NCwzMjQ3OCwyMTExOSwyNTk0NSwzNzIzNywzNjczNSwzNjczOSwyMTQ4MywzMTM4MiwyNTU4MSwyNTUwOSwzMDM0MiwzMTIyNCwzNDkwMywzODQ1NCwyNTEzMCwyMTE2MywzMzQxMCwyNjcwOCwyNjQ4MCwyNTQ2MywzMDU3MSwzMTQ2OSwyNzkwNSwzMjQ2NywzNTI5OSwyMjk5MiwyNTEwNiwzNDI0OSwzMzQ0NSwzMDAyOCwyMDUxMSwyMDE3MSwzMDExNywzNTgxOSwyMzYyNiwyNDA2MiwzMTU2MywyNjAyMCwzNzMyOSwyMDE3MCwyNzk0MSwzNTE2NywzMjAzOSwzODE4MiwyMDE2NSwzNTg4MCwzNjgyNywzODc3MSwyNjE4NywzMTEwNSwzNjgxNywyODkwOCwyODAyNCwzMjE1MywzMjE1NCwzMjE1NSwzMjE1NiwzMjE1NywzMjE1OCwzMjE1OSwzMjE2MCwzMjE2MSwzMjE2MiwzMjE2MywzMjE2NCwzMjE2NSwzMjE2NywzMjE2OCwzMjE2OSwzMjE3MCwzMjE3MSwzMjE3MiwzMjE3MywzMjE3NSwzMjE3NiwzMjE3NywzMjE3OCwzMjE3OSwzMjE4MCwzMjE4MSwzMjE4MiwzMjE4MywzMjE4NCwzMjE4NSwzMjE4NiwzMjE4NywzMjE4OCwzMjE4OSwzMjE5MCwzMjE5MSwzMjE5MiwzMjE5MywzMjE5NCwzMjE5NSwzMjE5NiwzMjE5NywzMjE5OCwzMjE5OSwzMjIwMCwzMjIwMSwzMjIwMiwzMjIwMywzMjIwNCwzMjIwNSwzMjIwNiwzMjIwNywzMjIwOCwzMjIwOSwzMjIxMCwzMjIxMSwzMjIxMiwzMjIxMywzMjIxNCwzMjIxNSwzMjIxNiwzMjIxNywzMjIxOCwzMjIxOSwzMjIyMCwzMjIyMSwzMjIyMiwzMjIyMywzMjIyNCwzMjIyNSwzMjIyNiwzMjIyNywzMjIyOCwzMjIyOSwzMjIzMCwzMjIzMSwzMjIzMiwzMjIzMywzMjIzNCwzMjIzNSwzMjIzNiwzMjIzNywzMjIzOCwzMjIzOSwzMjI0MCwzMjI0MSwzMjI0MiwzMjI0MywzMjI0NCwzMjI0NSwzMjI0NiwzMjI0NywzMjI0OCwzMjI0OSwzMjI1MCwyMzYxMywyMTE3MCwzMzYwNiwyMDgzNCwzMzU1MCwzMDU1NSwyNjIzMCw0MDEyMCwyMDE0MCwyNDc3OCwzMTkzNCwzMTkyMywzMjQ2MywyMDExNywzNTY4NiwyNjIyMywzOTA0OCwzODc0NSwyMjY1OSwyNTk2NCwzODIzNiwyNDQ1MiwzMDE1MywzODc0MiwzMTQ1NSwzMTQ1NCwyMDkyOCwyODg0NywzMTM4NCwyNTU3OCwzMTM1MCwzMjQxNiwyOTU5MCwzODg5MywyMDAzNywyODc5MiwyMDA2MSwzNzIwMiwyMTQxNywyNTkzNywyNjA4NywzMzI3NiwzMzI4NSwyMTY0NiwyMzYwMSwzMDEwNiwzODgxNiwyNTMwNCwyOTQwMSwzMDE0MSwyMzYyMSwzOTU0NSwzMzczOCwyMzYxNiwyMTYzMiwzMDY5NywyMDAzMCwyNzgyMiwzMjg1OCwyNTI5OCwyNTQ1NCwyNDA0MCwyMDg1NSwzNjMxNywzNjM4MiwzODE5MSwyMDQ2NSwyMTQ3NywyNDgwNywyODg0NCwyMTA5NSwyNTQyNCw0MDUxNSwyMzA3MSwyMDUxOCwzMDUxOSwyMTM2NywzMjQ4MiwyNTczMywyNTg5OSwyNTIyNSwyNTQ5NiwyMDUwMCwyOTIzNywzNTI3MywyMDkxNSwzNTc3NiwzMjQ3NywyMjM0MywzMzc0MCwzODA1NSwyMDg5MSwyMTUzMSwyMzgwMywzMjI1MSwzMjI1MiwzMjI1MywzMjI1NCwzMjI1NSwzMjI1NiwzMjI1NywzMjI1OCwzMjI1OSwzMjI2MCwzMjI2MSwzMjI2MiwzMjI2MywzMjI2NCwzMjI2NSwzMjI2NiwzMjI2NywzMjI2OCwzMjI2OSwzMjI3MCwzMjI3MSwzMjI3MiwzMjI3MywzMjI3NCwzMjI3NSwzMjI3NiwzMjI3NywzMjI3OCwzMjI3OSwzMjI4MCwzMjI4MSwzMjI4MiwzMjI4MywzMjI4NCwzMjI4NSwzMjI4NiwzMjI4NywzMjI4OCwzMjI4OSwzMjI5MCwzMjI5MSwzMjI5MiwzMjI5MywzMjI5NCwzMjI5NSwzMjI5NiwzMjI5NywzMjI5OCwzMjI5OSwzMjMwMCwzMjMwMSwzMjMwMiwzMjMwMywzMjMwNCwzMjMwNSwzMjMwNiwzMjMwNywzMjMwOCwzMjMwOSwzMjMxMCwzMjMxMSwzMjMxMiwzMjMxMywzMjMxNCwzMjMxNiwzMjMxNywzMjMxOCwzMjMxOSwzMjMyMCwzMjMyMiwzMjMyMywzMjMyNCwzMjMyNSwzMjMyNiwzMjMyOCwzMjMyOSwzMjMzMCwzMjMzMSwzMjMzMiwzMjMzMywzMjMzNCwzMjMzNSwzMjMzNiwzMjMzNywzMjMzOCwzMjMzOSwzMjM0MCwzMjM0MSwzMjM0MiwzMjM0MywzMjM0NCwzMjM0NSwzMjM0NiwzMjM0NywzMjM0OCwzMjM0OSwyMDQyNiwzMTQ1OSwyNzk5NCwzNzA4OSwzOTU2NywyMTg4OCwyMTY1NCwyMTM0NSwyMTY3OSwyNDMyMCwyNTU3NywyNjk5OSwyMDk3NSwyNDkzNiwyMTAwMiwyMjU3MCwyMTIwOCwyMjM1MCwzMDczMywzMDQ3NSwyNDI0NywyNDk1MSwzMTk2OCwyNTE3OSwyNTIzOSwyMDEzMCwyODgyMSwzMjc3MSwyNTMzNSwyODkwMCwzODc1MiwyMjM5MSwzMzQ5OSwyNjYwNywyNjg2OSwzMDkzMywzOTA2MywzMTE4NSwyMjc3MSwyMTY4MywyMTQ4NywyODIxMiwyMDgxMSwyMTA1MSwyMzQ1OCwzNTgzOCwzMjk0MywyMTgyNywyMjQzOCwyNDY5MSwyMjM1MywyMTU0OSwzMTM1NCwyNDY1NiwyMzM4MCwyNTUxMSwyNTI0OCwyMTQ3NSwyNTE4NywyMzQ5NSwyNjU0MywyMTc0MSwzMTM5MSwzMzUxMCwzNzIzOSwyNDIxMSwzNTA0NCwyMjg0MCwyMjQ0NiwyNTM1OCwzNjMyOCwzMzAwNywyMjM1OSwzMTYwNywyMDM5MywyNDU1NSwyMzQ4NSwyNzQ1NCwyMTI4MSwzMTU2OCwyOTM3OCwyNjY5NCwzMDcxOSwzMDUxOCwyNjEwMywyMDkxNywyMDExMSwzMDQyMCwyMzc0MywzMTM5NywzMzkwOSwyMjg2MiwzOTc0NSwyMDYwOCwzMjM1MCwzMjM1MSwzMjM1MiwzMjM1MywzMjM1NCwzMjM1NSwzMjM1NiwzMjM1NywzMjM1OCwzMjM1OSwzMjM2MCwzMjM2MSwzMjM2MiwzMjM2MywzMjM2NCwzMjM2NSwzMjM2NiwzMjM2NywzMjM2OCwzMjM2OSwzMjM3MCwzMjM3MSwzMjM3MiwzMjM3MywzMjM3NCwzMjM3NSwzMjM3NiwzMjM3NywzMjM3OCwzMjM3OSwzMjM4MCwzMjM4MSwzMjM4MiwzMjM4MywzMjM4NCwzMjM4NSwzMjM4NywzMjM4OCwzMjM4OSwzMjM5MCwzMjM5MSwzMjM5MiwzMjM5MywzMjM5NCwzMjM5NSwzMjM5NiwzMjM5NywzMjM5OCwzMjM5OSwzMjQwMCwzMjQwMSwzMjQwMiwzMjQwMywzMjQwNCwzMjQwNSwzMjQwNiwzMjQwNywzMjQwOCwzMjQwOSwzMjQxMCwzMjQxMiwzMjQxMywzMjQxNCwzMjQzMCwzMjQzNiwzMjQ0MywzMjQ0NCwzMjQ3MCwzMjQ4NCwzMjQ5MiwzMjUwNSwzMjUyMiwzMjUyOCwzMjU0MiwzMjU2NywzMjU2OSwzMjU3MSwzMjU3MiwzMjU3MywzMjU3NCwzMjU3NSwzMjU3NiwzMjU3NywzMjU3OSwzMjU4MiwzMjU4MywzMjU4NCwzMjU4NSwzMjU4NiwzMjU4NywzMjU4OCwzMjU4OSwzMjU5MCwzMjU5MSwzMjU5NCwzMjU5NSwzOTMwNCwyNDg3MSwyODI5MSwyMjM3MiwyNjExOCwyNTQxNCwyMjI1NiwyNTMyNCwyNTE5MywyNDI3NSwzODQyMCwyMjQwMywyNTI4OSwyMTg5NSwzNDU5MywzMzA5OCwzNjc3MSwyMTg2MiwzMzcxMywyNjQ2OSwzNjE4MiwzNDAxMywyMzE0NiwyNjYzOSwyNTMxOCwzMTcyNiwzODQxNywyMDg0OCwyODU3MiwzNTg4OCwyNTU5NywzNTI3MiwyNTA0MiwzMjUxOCwyODg2NiwyODM4OSwyOTcwMSwyNzAyOCwyOTQzNiwyNDI2NiwzNzA3MCwyNjM5MSwyODAxMCwyNTQzOCwyMTE3MSwyOTI4MiwzMjc2OSwyMDMzMiwyMzAxMywzNzIyNiwyODg4OSwyODA2MSwyMTIwMiwyMDA0OCwzODY0NywzODI1MywzNDE3NCwzMDkyMiwzMjA0NywyMDc2OSwyMjQxOCwyNTc5NCwzMjkwNywzMTg2NywyNzg4MiwyNjg2NSwyNjk3NCwyMDkxOSwyMTQwMCwyNjc5MiwyOTMxMyw0MDY1NCwzMTcyOSwyOTQzMiwzMTE2MywyODQzNSwyOTcwMiwyNjQ0NiwzNzMyNCw0MDEwMCwzMTAzNiwzMzY3MywzMzYyMCwyMTUxOSwyNjY0NywyMDAyOSwyMTM4NSwyMTE2OSwzMDc4MiwyMTM4MiwyMTAzMywyMDYxNiwyMDM2MywyMDQzMiwzMjU5OCwzMjYwMSwzMjYwMywzMjYwNCwzMjYwNSwzMjYwNiwzMjYwOCwzMjYxMSwzMjYxMiwzMjYxMywzMjYxNCwzMjYxNSwzMjYxOSwzMjYyMCwzMjYyMSwzMjYyMywzMjYyNCwzMjYyNywzMjYyOSwzMjYzMCwzMjYzMSwzMjYzMiwzMjYzNCwzMjYzNSwzMjYzNiwzMjYzNywzMjYzOSwzMjY0MCwzMjY0MiwzMjY0MywzMjY0NCwzMjY0NSwzMjY0NiwzMjY0NywzMjY0OCwzMjY0OSwzMjY1MSwzMjY1MywzMjY1NSwzMjY1NiwzMjY1NywzMjY1OCwzMjY1OSwzMjY2MSwzMjY2MiwzMjY2MywzMjY2NCwzMjY2NSwzMjY2NywzMjY2OCwzMjY3MiwzMjY3NCwzMjY3NSwzMjY3NywzMjY3OCwzMjY4MCwzMjY4MSwzMjY4MiwzMjY4MywzMjY4NCwzMjY4NSwzMjY4NiwzMjY4OSwzMjY5MSwzMjY5MiwzMjY5MywzMjY5NCwzMjY5NSwzMjY5OCwzMjY5OSwzMjcwMiwzMjcwNCwzMjcwNiwzMjcwNywzMjcwOCwzMjcxMCwzMjcxMSwzMjcxMiwzMjcxMywzMjcxNSwzMjcxNywzMjcxOSwzMjcyMCwzMjcyMSwzMjcyMiwzMjcyMywzMjcyNiwzMjcyNywzMjcyOSwzMjczMCwzMjczMSwzMjczMiwzMjczMywzMjczNCwzMjczOCwzMjczOSwzMDE3OCwzMTQzNSwzMTg5MCwyNzgxMywzODU4MiwyMTE0NywyOTgyNywyMTczNywyMDQ1NywzMjg1MiwzMzcxNCwzNjgzMCwzODI1NiwyNDI2NSwyNDYwNCwyODA2MywyNDA4OCwyNTk0NywzMzA4MCwzODE0MiwyNDY1MSwyODg2MCwzMjQ1MSwzMTkxOCwyMDkzNywyNjc1MywzMTkyMSwzMzM5MSwyMDAwNCwzNjc0MiwzNzMyNywyNjIzOCwyMDE0MiwzNTg0NSwyNTc2OSwzMjg0MiwyMDY5OCwzMDEwMywyOTEzNCwyMzUyNSwzNjc5NywyODUxOCwyMDEwMiwyNTczMCwzODI0MywyNDI3OCwyNjAwOSwyMTAxNSwzNTAxMCwyODg3MiwyMTE1NSwyOTQ1NCwyOTc0NywyNjUxOSwzMDk2NywzODY3OCwyMDAyMCwzNzA1MSw0MDE1OCwyODEwNywyMDk1NSwzNjE2MSwyMTUzMywyNTI5NCwyOTYxOCwzMzc3NywzODY0Niw0MDgzNiwzODA4MywyMDI3OCwzMjY2NiwyMDk0MCwyODc4OSwzODUxNywyMzcyNSwzOTA0NiwyMTQ3OCwyMDE5NiwyODMxNiwyOTcwNSwyNzA2MCwzMDgyNywzOTMxMSwzMDA0MSwyMTAxNiwzMDI0NCwyNzk2OSwyNjYxMSwyMDg0NSw0MDg1NywzMjg0MywyMTY1NywzMTU0OCwzMTQyMywzMjc0MCwzMjc0MywzMjc0NCwzMjc0NiwzMjc0NywzMjc0OCwzMjc0OSwzMjc1MSwzMjc1NCwzMjc1NiwzMjc1NywzMjc1OCwzMjc1OSwzMjc2MCwzMjc2MSwzMjc2MiwzMjc2NSwzMjc2NiwzMjc2NywzMjc3MCwzMjc3NSwzMjc3NiwzMjc3NywzMjc3OCwzMjc4MiwzMjc4MywzMjc4NSwzMjc4NywzMjc5NCwzMjc5NSwzMjc5NywzMjc5OCwzMjc5OSwzMjgwMSwzMjgwMywzMjgwNCwzMjgxMSwzMjgxMiwzMjgxMywzMjgxNCwzMjgxNSwzMjgxNiwzMjgxOCwzMjgyMCwzMjgyNSwzMjgyNiwzMjgyOCwzMjgzMCwzMjgzMiwzMjgzMywzMjgzNiwzMjgzNywzMjgzOSwzMjg0MCwzMjg0MSwzMjg0NiwzMjg0NywzMjg0OCwzMjg0OSwzMjg1MSwzMjg1MywzMjg1NCwzMjg1NSwzMjg1NywzMjg1OSwzMjg2MCwzMjg2MSwzMjg2MiwzMjg2MywzMjg2NCwzMjg2NSwzMjg2NiwzMjg2NywzMjg2OCwzMjg2OSwzMjg3MCwzMjg3MSwzMjg3MiwzMjg3NSwzMjg3NiwzMjg3NywzMjg3OCwzMjg3OSwzMjg4MCwzMjg4MiwzMjg4MywzMjg4NCwzMjg4NSwzMjg4NiwzMjg4NywzMjg4OCwzMjg4OSwzMjg5MCwzMjg5MSwzMjg5MiwzMjg5MywzODUzNCwyMjQwNCwyNTMxNCwzODQ3MSwyNzAwNCwyMzA0NCwyNTYwMiwzMTY5OSwyODQzMSwzODQ3NSwzMzQ0NiwyMTM0NiwzOTA0NSwyNDIwOCwyODgwOSwyNTUyMywyMTM0OCwzNDM4Myw0MDA2NSw0MDU5NSwzMDg2MCwzODcwNiwzNjMzNSwzNjE2Miw0MDU3NSwyODUxMCwzMTEwOCwyNDQwNSwzODQ3MCwyNTEzNCwzOTU0MCwyMTUyNSwzODEwOSwyMDM4NywyNjA1MywyMzY1MywyMzY0OSwzMjUzMywzNDM4NSwyNzY5NSwyNDQ1OSwyOTU3NSwyODM4OCwzMjUxMSwyMzc4MiwyNTM3MSwyMzQwMiwyODM5MCwyMTM2NSwyMDA4MSwyNTUwNCwzMDA1MywyNTI0OSwzNjcxOCwyMDI2MiwyMDE3NywyNzgxNCwzMjQzOCwzNTc3MCwzMzgyMSwzNDc0NiwzMjU5OSwzNjkyMywzODE3OSwzMTY1NywzOTU4NSwzNTA2NCwzMzg1MywyNzkzMSwzOTU1OCwzMjQ3NiwyMjkyMCw0MDYzNSwyOTU5NSwzMDcyMSwzNDQzNCwzOTUzMiwzOTU1NCwyMjA0MywyMTUyNywyMjQ3NSwyMDA4MCw0MDYxNCwyMTMzNCwzNjgwOCwzMzAzMywzMDYxMCwzOTMxNCwzNDU0MiwyODM4NSwzNDA2NywyNjM2NCwyNDkzMCwyODQ1OSwzMjg5NCwzMjg5NywzMjg5OCwzMjkwMSwzMjkwNCwzMjkwNiwzMjkwOSwzMjkxMCwzMjkxMSwzMjkxMiwzMjkxMywzMjkxNCwzMjkxNiwzMjkxNywzMjkxOSwzMjkyMSwzMjkyNiwzMjkzMSwzMjkzNCwzMjkzNSwzMjkzNiwzMjk0MCwzMjk0NCwzMjk0NywzMjk0OSwzMjk1MCwzMjk1MiwzMjk1MywzMjk1NSwzMjk2NSwzMjk2NywzMjk2OCwzMjk2OSwzMjk3MCwzMjk3MSwzMjk3NSwzMjk3NiwzMjk3NywzMjk3OCwzMjk3OSwzMjk4MCwzMjk4MSwzMjk4NCwzMjk5MSwzMjk5MiwzMjk5NCwzMjk5NSwzMjk5OCwzMzAwNiwzMzAxMywzMzAxNSwzMzAxNywzMzAxOSwzMzAyMiwzMzAyMywzMzAyNCwzMzAyNSwzMzAyNywzMzAyOCwzMzAyOSwzMzAzMSwzMzAzMiwzMzAzNSwzMzAzNiwzMzA0NSwzMzA0NywzMzA0OSwzMzA1MSwzMzA1MiwzMzA1MywzMzA1NSwzMzA1NiwzMzA1NywzMzA1OCwzMzA1OSwzMzA2MCwzMzA2MSwzMzA2MiwzMzA2MywzMzA2NCwzMzA2NSwzMzA2NiwzMzA2NywzMzA2OSwzMzA3MCwzMzA3MiwzMzA3NSwzMzA3NiwzMzA3NywzMzA3OSwzMzA4MSwzMzA4MiwzMzA4MywzMzA4NCwzMzA4NSwzMzA4NywzNTg4MSwzMzQyNiwzMzU3OSwzMDQ1MCwyNzY2NywyNDUzNywzMzcyNSwyOTQ4MywzMzU0MSwzODE3MCwyNzYxMSwzMDY4MywzODA4NiwyMTM1OSwzMzUzOCwyMDg4MiwyNDEyNSwzNTk4MCwzNjE1MiwyMDA0MCwyOTYxMSwyNjUyMiwyNjc1NywzNzIzOCwzODY2NSwyOTAyOCwyNzgwOSwzMDQ3MywyMzE4NiwzODIwOSwyNzU5OSwzMjY1NCwyNjE1MSwyMzUwNCwyMjk2OSwyMzE5NCwzODM3NiwzODM5MSwyMDIwNCwzMzgwNCwzMzk0NSwyNzMwOCwzMDQzMSwzODE5MiwyOTQ2NywyNjc5MCwyMzM5MSwzMDUxMSwzNzI3NCwzODc1MywzMTk2NCwzNjg1NSwzNTg2OCwyNDM1NywzMTg1OSwzMTE5MiwzNTI2OSwyNzg1MiwzNDU4OCwyMzQ5NCwyNDEzMCwyNjgyNSwzMDQ5NiwzMjUwMSwyMDg4NSwyMDgxMywyMTE5MywyMzA4MSwzMjUxNywzODc1NCwzMzQ5NSwyNTU1MSwzMDU5NiwzNDI1NiwzMTE4NiwyODIxOCwyNDIxNywyMjkzNywzNDA2NSwyODc4MSwyNzY2NSwyNTI3OSwzMDM5OSwyNTkzNSwyNDc1MSwzODM5NywyNjEyNiwzNDcxOSw0MDQ4MywzODEyNSwyMTUxNywyMTYyOSwzNTg4NCwyNTcyMCwzMzA4OCwzMzA4OSwzMzA5MCwzMzA5MSwzMzA5MiwzMzA5MywzMzA5NSwzMzA5NywzMzEwMSwzMzEwMiwzMzEwMywzMzEwNiwzMzExMCwzMzExMSwzMzExMiwzMzExNSwzMzExNiwzMzExNywzMzExOCwzMzExOSwzMzEyMSwzMzEyMiwzMzEyMywzMzEyNCwzMzEyNiwzMzEyOCwzMzEzMCwzMzEzMSwzMzEzMiwzMzEzNSwzMzEzOCwzMzEzOSwzMzE0MSwzMzE0MiwzMzE0MywzMzE0NCwzMzE1MywzMzE1NSwzMzE1NiwzMzE1NywzMzE1OCwzMzE1OSwzMzE2MSwzMzE2MywzMzE2NCwzMzE2NSwzMzE2NiwzMzE2OCwzMzE3MCwzMzE3MSwzMzE3MiwzMzE3MywzMzE3NCwzMzE3NSwzMzE3NywzMzE3OCwzMzE4MiwzMzE4MywzMzE4NCwzMzE4NSwzMzE4NiwzMzE4OCwzMzE4OSwzMzE5MSwzMzE5MywzMzE5NSwzMzE5NiwzMzE5NywzMzE5OCwzMzE5OSwzMzIwMCwzMzIwMSwzMzIwMiwzMzIwNCwzMzIwNSwzMzIwNiwzMzIwNywzMzIwOCwzMzIwOSwzMzIxMiwzMzIxMywzMzIxNCwzMzIxNSwzMzIyMCwzMzIyMSwzMzIyMywzMzIyNCwzMzIyNSwzMzIyNywzMzIyOSwzMzIzMCwzMzIzMSwzMzIzMiwzMzIzMywzMzIzNCwzMzIzNSwyNTcyMSwzNDMyMSwyNzE2OSwzMzE4MCwzMDk1MiwyNTcwNSwzOTc2NCwyNTI3MywyNjQxMSwzMzcwNywyMjY5Niw0MDY2NCwyNzgxOSwyODQ0OCwyMzUxOCwzODQ3NiwzNTg1MSwyOTI3OSwyNjU3NiwyNTI4NywyOTI4MSwyMDEzNywyMjk4MiwyNzU5NywyMjY3NSwyNjI4NiwyNDE0OSwyMTIxNSwyNDkxNywyNjQwOCwzMDQ0NiwzMDU2NiwyOTI4NywzMTMwMiwyNTM0MywyMTczOCwyMTU4NCwzODA0OCwzNzAyNywyMzA2OCwzMjQzNSwyNzY3MCwyMDAzNSwyMjkwMiwzMjc4NCwyMjg1NiwyMTMzNSwzMDAwNywzODU5MCwyMjIxOCwyNTM3NiwzMzA0MSwyNDcwMCwzODM5MywyODExOCwyMTYwMiwzOTI5NywyMDg2OSwyMzI3MywzMzAyMSwyMjk1OCwzODY3NSwyMDUyMiwyNzg3NywyMzYxMiwyNTMxMSwyMDMyMCwyMTMxMSwzMzE0NywzNjg3MCwyODM0NiwzNDA5MSwyNTI4OCwyNDE4MCwzMDkxMCwyNTc4MSwyNTQ2NywyNDU2NSwyMzA2NCwzNzI0Nyw0MDQ3OSwyMzYxNSwyNTQyMywzMjgzNCwyMzQyMSwyMTg3MCwzODIxOCwzODIyMSwyODAzNywyNDc0NCwyNjU5MiwyOTQwNiwyMDk1NywyMzQyNSwzMzIzNiwzMzIzNywzMzIzOCwzMzIzOSwzMzI0MCwzMzI0MSwzMzI0MiwzMzI0MywzMzI0NCwzMzI0NSwzMzI0NiwzMzI0NywzMzI0OCwzMzI0OSwzMzI1MCwzMzI1MiwzMzI1MywzMzI1NCwzMzI1NiwzMzI1NywzMzI1OSwzMzI2MiwzMzI2MywzMzI2NCwzMzI2NSwzMzI2NiwzMzI2OSwzMzI3MCwzMzI3MSwzMzI3MiwzMzI3MywzMzI3NCwzMzI3NywzMzI3OSwzMzI4MywzMzI4NywzMzI4OCwzMzI4OSwzMzI5MCwzMzI5MSwzMzI5NCwzMzI5NSwzMzI5NywzMzI5OSwzMzMwMSwzMzMwMiwzMzMwMywzMzMwNCwzMzMwNSwzMzMwNiwzMzMwOSwzMzMxMiwzMzMxNiwzMzMxNywzMzMxOCwzMzMxOSwzMzMyMSwzMzMyNiwzMzMzMCwzMzMzOCwzMzM0MCwzMzM0MSwzMzM0MywzMzM0NCwzMzM0NSwzMzM0NiwzMzM0NywzMzM0OSwzMzM1MCwzMzM1MiwzMzM1NCwzMzM1NiwzMzM1NywzMzM1OCwzMzM2MCwzMzM2MSwzMzM2MiwzMzM2MywzMzM2NCwzMzM2NSwzMzM2NiwzMzM2NywzMzM2OSwzMzM3MSwzMzM3MiwzMzM3MywzMzM3NCwzMzM3NiwzMzM3NywzMzM3OCwzMzM3OSwzMzM4MCwzMzM4MSwzMzM4MiwzMzM4MywzMzM4NSwyNTMxOSwyNzg3MCwyOTI3NSwyNTE5NywzODA2MiwzMjQ0NSwzMzA0MywyNzk4NywyMDg5MiwyNDMyNCwyMjkwMCwyMTE2MiwyNDU5NCwyMjg5OSwyNjI2MiwzNDM4NCwzMDExMSwyNTM4NiwyNTA2MiwzMTk4MywzNTgzNCwyMTczNCwyNzQzMSw0MDQ4NSwyNzU3MiwzNDI2MSwyMTU4OSwyMDU5OCwyNzgxMiwyMTg2NiwzNjI3NiwyOTIyOCwyNDA4NSwyNDU5NywyOTc1MCwyNTI5MywyNTQ5MCwyOTI2MCwyNDQ3MiwyODIyNywyNzk2NiwyNTg1NiwyODUwNCwzMDQyNCwzMDkyOCwzMDQ2MCwzMDAzNiwyMTAyOCwyMTQ2NywyMDA1MSwyNDIyMiwyNjA0OSwzMjgxMCwzMjk4MiwyNTI0MywyMTYzOCwyMTAzMiwyODg0NiwzNDk1NywzNjMwNSwyNzg3MywyMTYyNCwzMjk4NiwyMjUyMSwzNTA2MCwzNjE4MCwzODUwNiwzNzE5NywyMDMyOSwyNzgwMywyMTk0MywzMDQwNiwzMDc2OCwyNTI1NiwyODkyMSwyODU1OCwyNDQyOSwzNDAyOCwyNjg0MiwzMDg0NCwzMTczNSwzMzE5MiwyNjM3OSw0MDUyNywyNTQ0NywzMDg5NiwyMjM4MywzMDczOCwzODcxMywyNTIwOSwyNTI1OSwyMTEyOCwyOTc0OSwyNzYwNywzMzM4NiwzMzM4NywzMzM4OCwzMzM4OSwzMzM5MywzMzM5NywzMzM5OCwzMzM5OSwzMzQwMCwzMzQwMywzMzQwNCwzMzQwOCwzMzQwOSwzMzQxMSwzMzQxMywzMzQxNCwzMzQxNSwzMzQxNywzMzQyMCwzMzQyNCwzMzQyNywzMzQyOCwzMzQyOSwzMzQzMCwzMzQzNCwzMzQzNSwzMzQzOCwzMzQ0MCwzMzQ0MiwzMzQ0MywzMzQ0NywzMzQ1OCwzMzQ2MSwzMzQ2MiwzMzQ2NiwzMzQ2NywzMzQ2OCwzMzQ3MSwzMzQ3MiwzMzQ3NCwzMzQ3NSwzMzQ3NywzMzQ3OCwzMzQ4MSwzMzQ4OCwzMzQ5NCwzMzQ5NywzMzQ5OCwzMzUwMSwzMzUwNiwzMzUxMSwzMzUxMiwzMzUxMywzMzUxNCwzMzUxNiwzMzUxNywzMzUxOCwzMzUyMCwzMzUyMiwzMzUyMywzMzUyNSwzMzUyNiwzMzUyOCwzMzUzMCwzMzUzMiwzMzUzMywzMzUzNCwzMzUzNSwzMzUzNiwzMzU0NiwzMzU0NywzMzU0OSwzMzU1MiwzMzU1NCwzMzU1NSwzMzU1OCwzMzU2MCwzMzU2MSwzMzU2NSwzMzU2NiwzMzU2NywzMzU2OCwzMzU2OSwzMzU3MCwzMzU3MSwzMzU3MiwzMzU3MywzMzU3NCwzMzU3NywzMzU3OCwzMzU4MiwzMzU4NCwzMzU4NiwzMzU5MSwzMzU5NSwzMzU5NywyMTg2MCwzMzA4NiwzMDEzMCwzMDM4MiwyMTMwNSwzMDE3NCwyMDczMSwyMzYxNywzNTY5MiwzMTY4NywyMDU1OSwyOTI1NSwzOTU3NSwzOTEyOCwyODQxOCwyOTkyMiwzMTA4MCwyNTczNSwzMDYyOSwyNTM0MCwzOTA1NywzNjEzOSwyMTY5NywzMjg1NiwyMDA1MCwyMjM3OCwzMzUyOSwzMzgwNSwyNDE3OSwyMDk3MywyOTk0MiwzNTc4MCwyMzYzMSwyMjM2OSwyNzkwMCwzOTA0NywyMzExMCwzMDc3MiwzOTc0OCwzNjg0MywzMTg5MywyMTA3OCwyNTE2OSwzODEzOCwyMDE2NiwzMzY3MCwzMzg4OSwzMzc2OSwzMzk3MCwyMjQ4NCwyNjQyMCwyMjI3NSwyNjIyMiwyODAwNiwzNTg4OSwyNjMzMywyODY4OSwyNjM5OSwyNzQ1MCwyNjY0NiwyNTExNCwyMjk3MSwxOTk3MSwyMDkzMiwyODQyMiwyNjU3OCwyNzc5MSwyMDg1NCwyNjgyNywyMjg1NSwyNzQ5NSwzMDA1NCwyMzgyMiwzMzA0MCw0MDc4NCwyNjA3MSwzMTA0OCwzMTA0MSwzOTU2OSwzNjIxNSwyMzY4MiwyMDA2MiwyMDIyNSwyMTU1MSwyMjg2NSwzMDczMiwyMjEyMCwyNzY2OCwzNjgwNCwyNDMyMywyNzc3MywyNzg3NSwzNTc1NSwyNTQ4OCwzMzU5OCwzMzU5OSwzMzYwMSwzMzYwMiwzMzYwNCwzMzYwNSwzMzYwOCwzMzYxMCwzMzYxMSwzMzYxMiwzMzYxMywzMzYxNCwzMzYxOSwzMzYyMSwzMzYyMiwzMzYyMywzMzYyNCwzMzYyNSwzMzYyOSwzMzYzNCwzMzY0OCwzMzY0OSwzMzY1MCwzMzY1MSwzMzY1MiwzMzY1MywzMzY1NCwzMzY1NywzMzY1OCwzMzY2MiwzMzY2MywzMzY2NCwzMzY2NSwzMzY2NiwzMzY2NywzMzY2OCwzMzY3MSwzMzY3MiwzMzY3NCwzMzY3NSwzMzY3NiwzMzY3NywzMzY3OSwzMzY4MCwzMzY4MSwzMzY4NCwzMzY4NSwzMzY4NiwzMzY4NywzMzY4OSwzMzY5MCwzMzY5MywzMzY5NSwzMzY5NywzMzY5OCwzMzY5OSwzMzcwMCwzMzcwMSwzMzcwMiwzMzcwMywzMzcwOCwzMzcwOSwzMzcxMCwzMzcxMSwzMzcxNywzMzcyMywzMzcyNiwzMzcyNywzMzczMCwzMzczMSwzMzczMiwzMzczNCwzMzczNiwzMzczNywzMzczOSwzMzc0MSwzMzc0MiwzMzc0NCwzMzc0NSwzMzc0NiwzMzc0NywzMzc0OSwzMzc1MSwzMzc1MywzMzc1NCwzMzc1NSwzMzc1OCwzMzc2MiwzMzc2MywzMzc2NCwzMzc2NiwzMzc2NywzMzc2OCwzMzc3MSwzMzc3MiwzMzc3MywyNDY4OCwyNzk2NSwyOTMwMSwyNTE5MCwzODAzMCwzODA4NSwyMTMxNSwzNjgwMSwzMTYxNCwyMDE5MSwzNTg3OCwyMDA5NCw0MDY2MCwzODA2NSwzODA2NywyMTA2OSwyODUwOCwzNjk2MywyNzk3MywzNTg5MiwyMjU0NSwyMzg4NCwyNzQyNCwyNzQ2NSwyNjUzOCwyMTU5NSwzMzEwOCwzMjY1MiwyMjY4MSwzNDEwMywyNDM3OCwyNTI1MCwyNzIwNywzODIwMSwyNTk3MCwyNDcwOCwyNjcyNSwzMDYzMSwyMDA1MiwyMDM5MiwyNDAzOSwzODgwOCwyNTc3MiwzMjcyOCwyMzc4OSwyMDQzMSwzMTM3MywyMDk5OSwzMzU0MCwxOTk4OCwyNDYyMywzMTM2MywzODA1NCwyMDQwNSwyMDE0NiwzMTIwNiwyOTc0OCwyMTIyMCwzMzQ2NSwyNTgxMCwzMTE2NSwyMzUxNywyNzc3NywzODczOCwzNjczMSwyNzY4MiwyMDU0MiwyMTM3NSwyODE2NSwyNTgwNiwyNjIyOCwyNzY5NiwyNDc3MywzOTAzMSwzNTgzMSwyNDE5OCwyOTc1NiwzMTM1MSwzMTE3OSwxOTk5MiwzNzA0MSwyOTY5OSwyNzcxNCwyMjIzNCwzNzE5NSwyNzg0NSwzNjIzNSwyMTMwNiwzNDUwMiwyNjM1NCwzNjUyNywyMzYyNCwzOTUzNywyODE5MiwzMzc3NCwzMzc3NSwzMzc3OSwzMzc4MCwzMzc4MSwzMzc4MiwzMzc4MywzMzc4NiwzMzc4NywzMzc4OCwzMzc5MCwzMzc5MSwzMzc5MiwzMzc5NCwzMzc5NywzMzc5OSwzMzgwMCwzMzgwMSwzMzgwMiwzMzgwOCwzMzgxMCwzMzgxMSwzMzgxMiwzMzgxMywzMzgxNCwzMzgxNSwzMzgxNywzMzgxOCwzMzgxOSwzMzgyMiwzMzgyMywzMzgyNCwzMzgyNSwzMzgyNiwzMzgyNywzMzgzMywzMzgzNCwzMzgzNSwzMzgzNiwzMzgzNywzMzgzOCwzMzgzOSwzMzg0MCwzMzg0MiwzMzg0MywzMzg0NCwzMzg0NSwzMzg0NiwzMzg0NywzMzg0OSwzMzg1MCwzMzg1MSwzMzg1NCwzMzg1NSwzMzg1NiwzMzg1NywzMzg1OCwzMzg1OSwzMzg2MCwzMzg2MSwzMzg2MywzMzg2NCwzMzg2NSwzMzg2NiwzMzg2NywzMzg2OCwzMzg2OSwzMzg3MCwzMzg3MSwzMzg3MiwzMzg3NCwzMzg3NSwzMzg3NiwzMzg3NywzMzg3OCwzMzg4MCwzMzg4NSwzMzg4NiwzMzg4NywzMzg4OCwzMzg5MCwzMzg5MiwzMzg5MywzMzg5NCwzMzg5NSwzMzg5NiwzMzg5OCwzMzkwMiwzMzkwMywzMzkwNCwzMzkwNiwzMzkwOCwzMzkxMSwzMzkxMywzMzkxNSwzMzkxNiwyMTQ2MiwyMzA5NCw0MDg0MywzNjI1OSwyMTQzNSwyMjI4MCwzOTA3OSwyNjQzNSwzNzI3NSwyNzg0OSwyMDg0MCwzMDE1NCwyNTMzMSwyOTM1NiwyMTA0OCwyMTE0OSwzMjU3MCwyODgyMCwzMDI2NCwyMTM2NCw0MDUyMiwyNzA2MywzMDgzMCwzODU5MiwzNTAzMywzMjY3NiwyODk4MiwyOTEyMywyMDg3MywyNjU3OSwyOTkyNCwyMjc1NiwyNTg4MCwyMjE5OSwzNTc1MywzOTI4NiwyNTIwMCwzMjQ2OSwyNDgyNSwyODkwOSwyMjc2NCwyMDE2MSwyMDE1NCwyNDUyNSwzODg4NywyMDIxOSwzNTc0OCwyMDk5NSwyMjkyMiwzMjQyNywyNTE3MiwyMDE3MywyNjA4NSwyNTEwMiwzMzU5MiwzMzk5MywzMzYzNSwzNDcwMSwyOTA3NiwyODM0MiwyMzQ4MSwzMjQ2NiwyMDg4NywyNTU0NSwyNjU4MCwzMjkwNSwzMzU5MywzNDgzNywyMDc1NCwyMzQxOCwyMjkxNCwzNjc4NSwyMDA4MywyNzc0MSwyMDgzNywzNTEwOSwzNjcxOSwzODQ0NiwzNDEyMiwyOTc5MCwzODE2MCwzODM4NCwyODA3MCwzMzUwOSwyNDM2OSwyNTc0NiwyNzkyMiwzMzgzMiwzMzEzNCw0MDEzMSwyMjYyMiwzNjE4NywxOTk3NywyMTQ0MSwzMzkxNywzMzkxOCwzMzkxOSwzMzkyMCwzMzkyMSwzMzkyMywzMzkyNCwzMzkyNSwzMzkyNiwzMzkzMCwzMzkzMywzMzkzNSwzMzkzNiwzMzkzNywzMzkzOCwzMzkzOSwzMzk0MCwzMzk0MSwzMzk0MiwzMzk0NCwzMzk0NiwzMzk0NywzMzk0OSwzMzk1MCwzMzk1MSwzMzk1MiwzMzk1NCwzMzk1NSwzMzk1NiwzMzk1NywzMzk1OCwzMzk1OSwzMzk2MCwzMzk2MSwzMzk2MiwzMzk2MywzMzk2NCwzMzk2NSwzMzk2NiwzMzk2OCwzMzk2OSwzMzk3MSwzMzk3MywzMzk3NCwzMzk3NSwzMzk3OSwzMzk4MCwzMzk4MiwzMzk4NCwzMzk4NiwzMzk4NywzMzk4OSwzMzk5MCwzMzk5MSwzMzk5MiwzMzk5NSwzMzk5NiwzMzk5OCwzMzk5OSwzNDAwMiwzNDAwNCwzNDAwNSwzNDAwNywzNDAwOCwzNDAwOSwzNDAxMCwzNDAxMSwzNDAxMiwzNDAxNCwzNDAxNywzNDAxOCwzNDAyMCwzNDAyMywzNDAyNCwzNDAyNSwzNDAyNiwzNDAyNywzNDAyOSwzNDAzMCwzNDAzMSwzNDAzMywzNDAzNCwzNDAzNSwzNDAzNiwzNDAzNywzNDAzOCwzNDAzOSwzNDA0MCwzNDA0MSwzNDA0MiwzNDA0MywzNDA0NSwzNDA0NiwzNDA0OCwzNDA0OSwzNDA1MCwyMDI1NCwyNTk1NSwyNjcwNSwyMTk3MSwyMDAwNywyNTYyMCwzOTU3OCwyNTE5NSwyMzIzNCwyOTc5MSwzMzM5NCwyODA3MywyNjg2MiwyMDcxMSwzMzY3OCwzMDcyMiwyNjQzMiwyMTA0OSwyNzgwMSwzMjQzMywyMDY2NywyMTg2MSwyOTAyMiwzMTU3OSwyNjE5NCwyOTY0MiwzMzUxNSwyNjQ0MSwyMzY2NSwyMTAyNCwyOTA1MywzNDkyMywzODM3OCwzODQ4NSwyNTc5NywzNjE5MywzMzIwMywyMTg5MiwyNzczMywyNTE1OSwzMjU1OCwyMjY3NCwyMDI2MCwyMTgzMCwzNjE3NSwyNjE4OCwxOTk3OCwyMzU3OCwzNTA1OSwyNjc4NiwyNTQyMiwzMTI0NSwyODkwMywzMzQyMSwyMTI0MiwzODkwMiwyMzU2OSwyMTczNiwzNzA0NSwzMjQ2MSwyMjg4MiwzNjE3MCwzNDUwMywzMzI5MiwzMzI5MywzNjE5OCwyNTY2OCwyMzU1NiwyNDkxMywyODA0MSwzMTAzOCwzNTc3NCwzMDc3NSwzMDAwMywyMTYyNywyMDI4MCwzNjUyMywyODE0NSwyMzA3MiwzMjQ1MywzMTA3MCwyNzc4NCwyMzQ1NywyMzE1OCwyOTk3OCwzMjk1OCwyNDkxMCwyODE4MywyMjc2OCwyOTk4MywyOTk4OSwyOTI5OCwyMTMxOSwzMjQ5OSwzNDA1MSwzNDA1MiwzNDA1MywzNDA1NCwzNDA1NSwzNDA1NiwzNDA1NywzNDA1OCwzNDA1OSwzNDA2MSwzNDA2MiwzNDA2MywzNDA2NCwzNDA2NiwzNDA2OCwzNDA2OSwzNDA3MCwzNDA3MiwzNDA3MywzNDA3NSwzNDA3NiwzNDA3NywzNDA3OCwzNDA4MCwzNDA4MiwzNDA4MywzNDA4NCwzNDA4NSwzNDA4NiwzNDA4NywzNDA4OCwzNDA4OSwzNDA5MCwzNDA5MywzNDA5NCwzNDA5NSwzNDA5NiwzNDA5NywzNDA5OCwzNDA5OSwzNDEwMCwzNDEwMSwzNDEwMiwzNDExMCwzNDExMSwzNDExMiwzNDExMywzNDExNCwzNDExNiwzNDExNywzNDExOCwzNDExOSwzNDEyMywzNDEyNCwzNDEyNSwzNDEyNiwzNDEyNywzNDEyOCwzNDEyOSwzNDEzMCwzNDEzMSwzNDEzMiwzNDEzMywzNDEzNSwzNDEzNiwzNDEzOCwzNDEzOSwzNDE0MCwzNDE0MSwzNDE0MywzNDE0NCwzNDE0NSwzNDE0NiwzNDE0NywzNDE0OSwzNDE1MCwzNDE1MSwzNDE1MywzNDE1NCwzNDE1NSwzNDE1NiwzNDE1NywzNDE1OCwzNDE1OSwzNDE2MCwzNDE2MSwzNDE2MywzNDE2NSwzNDE2NiwzNDE2NywzNDE2OCwzNDE3MiwzNDE3MywzNDE3NSwzNDE3NiwzNDE3NywzMDQ2NSwzMDQyNywyMTA5NywzMjk4OCwyMjMwNywyNDA3MiwyMjgzMywyOTQyMiwyNjA0NSwyODI4NywzNTc5OSwyMzYwOCwzNDQxNywyMTMxMywzMDcwNywyNTM0MiwyNjEwMiwyMDE2MCwzOTEzNSwzNDQzMiwyMzQ1NCwzNTc4MiwyMTQ5MCwzMDY5MCwyMDM1MSwyMzYzMCwzOTU0MiwyMjk4NywyNDMzNSwzMTAzNCwyMjc2MywxOTk5MCwyNjYyMywyMDEwNywyNTMyNSwzNTQ3NSwzNjg5MywyMTE4MywyNjE1OSwyMTk4MCwyMjEyNCwzNjg2NiwyMDE4MSwyMDM2NSwzNzMyMiwzOTI4MCwyNzY2MywyNDA2NiwyNDY0MywyMzQ2MCwzNTI3MCwzNTc5NywyNTkxMCwyNTE2MywzOTMxOCwyMzQzMiwyMzU1MSwyNTQ4MCwyMTgwNiwyMTQ2MywzMDI0NiwyMDg2MSwzNDA5MiwyNjUzMCwyNjgwMywyNzUzMCwyNTIzNCwzNjc1NSwyMTQ2MCwzMzI5OCwyODExMywzMDA5NSwyMDA3MCwzNjE3NCwyMzQwOCwyOTA4NywzNDIyMywyNjI1NywyNjMyOSwzMjYyNiwzNDU2MCw0MDY1Myw0MDczNiwyMzY0NiwyNjQxNSwzNjg0OCwyNjY0MSwyNjQ2MywyNTEwMSwzMTQ0NiwyMjY2MSwyNDI0NiwyNTk2OCwyODQ2NSwzNDE3OCwzNDE3OSwzNDE4MiwzNDE4NCwzNDE4NSwzNDE4NiwzNDE4NywzNDE4OCwzNDE4OSwzNDE5MCwzNDE5MiwzNDE5MywzNDE5NCwzNDE5NSwzNDE5NiwzNDE5NywzNDE5OCwzNDE5OSwzNDIwMCwzNDIwMSwzNDIwMiwzNDIwNSwzNDIwNiwzNDIwNywzNDIwOCwzNDIwOSwzNDIxMCwzNDIxMSwzNDIxMywzNDIxNCwzNDIxNSwzNDIxNywzNDIxOSwzNDIyMCwzNDIyMSwzNDIyNSwzNDIyNiwzNDIyNywzNDIyOCwzNDIyOSwzNDIzMCwzNDIzMiwzNDIzNCwzNDIzNSwzNDIzNiwzNDIzNywzNDIzOCwzNDIzOSwzNDI0MCwzNDI0MiwzNDI0MywzNDI0NCwzNDI0NSwzNDI0NiwzNDI0NywzNDI0OCwzNDI1MCwzNDI1MSwzNDI1MiwzNDI1MywzNDI1NCwzNDI1NywzNDI1OCwzNDI2MCwzNDI2MiwzNDI2MywzNDI2NCwzNDI2NSwzNDI2NiwzNDI2NywzNDI2OSwzNDI3MCwzNDI3MSwzNDI3MiwzNDI3MywzNDI3NCwzNDI3NSwzNDI3NywzNDI3OCwzNDI3OSwzNDI4MCwzNDI4MiwzNDI4MywzNDI4NCwzNDI4NSwzNDI4NiwzNDI4NywzNDI4OCwzNDI4OSwzNDI5MCwzNDI5MSwzNDI5MiwzNDI5MywzNDI5NCwzNDI5NSwzNDI5NiwyNDY2MSwyMTA0NywzMjc4MSwyNTY4NCwzNDkyOCwyOTk5MywyNDA2OSwyNjY0MywyNTMzMiwzODY4NCwyMTQ1MiwyOTI0NSwzNTg0MSwyNzcwMCwzMDU2MSwzMTI0NiwyMTU1MCwzMDYzNiwzOTAzNCwzMzMwOCwzNTgyOCwzMDgwNSwyNjM4OCwyODg2NSwyNjAzMSwyNTc0OSwyMjA3MCwyNDYwNSwzMTE2OSwyMTQ5NiwxOTk5NywyNzUxNSwzMjkwMiwyMzU0NiwyMTk4NywyMjIzNSwyMDI4MiwyMDI4NCwzOTI4MiwyNDA1MSwyNjQ5NCwzMjgyNCwyNDU3OCwzOTA0MiwzNjg2NSwyMzQzNSwzNTc3MiwzNTgyOSwyNTYyOCwzMzM2OCwyNTgyMiwyMjAxMywzMzQ4NywzNzIyMSwyMDQzOSwzMjAzMiwzNjg5NSwzMTkwMywyMDcyMywyMjYwOSwyODMzNSwyMzQ4NywzNTc4NSwzMjg5OSwzNzI0MCwzMzk0OCwzMTYzOSwzNDQyOSwzODUzOSwzODU0MywzMjQ4NSwzOTYzNSwzMDg2MiwyMzY4MSwzMTMxOSwzNjkzMCwzODU2NywzMTA3MSwyMzM4NSwyNTQzOSwzMTQ5OSwzNDAwMSwyNjc5NywyMTc2NiwzMjU1MywyOTcxMiwzMjAzNCwzODE0NSwyNTE1MiwyMjYwNCwyMDE4MiwyMzQyNywyMjkwNSwyMjYxMiwzNDI5NywzNDI5OCwzNDMwMCwzNDMwMSwzNDMwMiwzNDMwNCwzNDMwNSwzNDMwNiwzNDMwNywzNDMwOCwzNDMxMCwzNDMxMSwzNDMxMiwzNDMxMywzNDMxNCwzNDMxNSwzNDMxNiwzNDMxNywzNDMxOCwzNDMxOSwzNDMyMCwzNDMyMiwzNDMyMywzNDMyNCwzNDMyNSwzNDMyNywzNDMyOCwzNDMyOSwzNDMzMCwzNDMzMSwzNDMzMiwzNDMzMywzNDMzNCwzNDMzNSwzNDMzNiwzNDMzNywzNDMzOCwzNDMzOSwzNDM0MCwzNDM0MSwzNDM0MiwzNDM0NCwzNDM0NiwzNDM0NywzNDM0OCwzNDM0OSwzNDM1MCwzNDM1MSwzNDM1MiwzNDM1MywzNDM1NCwzNDM1NSwzNDM1NiwzNDM1NywzNDM1OCwzNDM1OSwzNDM2MSwzNDM2MiwzNDM2MywzNDM2NSwzNDM2NiwzNDM2NywzNDM2OCwzNDM2OSwzNDM3MCwzNDM3MSwzNDM3MiwzNDM3MywzNDM3NCwzNDM3NSwzNDM3NiwzNDM3NywzNDM3OCwzNDM3OSwzNDM4MCwzNDM4NiwzNDM4NywzNDM4OSwzNDM5MCwzNDM5MSwzNDM5MiwzNDM5MywzNDM5NSwzNDM5NiwzNDM5NywzNDM5OSwzNDQwMCwzNDQwMSwzNDQwMywzNDQwNCwzNDQwNSwzNDQwNiwzNDQwNywzNDQwOCwzNDQwOSwzNDQxMCwyOTU0OSwyNTM3NCwzNjQyNywzNjM2NywzMjk3NCwzMzQ5MiwyNTI2MCwyMTQ4OCwyNzg4OCwzNzIxNCwyMjgyNiwyNDU3NywyNzc2MCwyMjM0OSwyNTY3NCwzNjEzOCwzMDI1MSwyODM5MywyMjM2MywyNzI2NCwzMDE5MiwyODUyNSwzNTg4NSwzNTg0OCwyMjM3NCwyNzYzMSwzNDk2MiwzMDg5OSwyNTUwNiwyMTQ5NywyODg0NSwyNzc0OCwyMjYxNiwyNTY0MiwyMjUzMCwyNjg0OCwzMzE3OSwyMTc3NiwzMTk1OCwyMDUwNCwzNjUzOCwyODEwOCwzNjI1NSwyODkwNywyNTQ4NywyODA1OSwyODM3MiwzMjQ4NiwzMzc5NiwyNjY5MSwzNjg2NywyODEyMCwzODUxOCwzNTc1MiwyMjg3MSwyOTMwNSwzNDI3NiwzMzE1MCwzMDE0MCwzNTQ2NiwyNjc5OSwyMTA3NiwzNjM4NiwzODE2MSwyNTU1MiwzOTA2NCwzNjQyMCwyMTg4NCwyMDMwNywyNjM2NywyMjE1OSwyNDc4OSwyODA1MywyMTA1OSwyMzYyNSwyMjgyNSwyODE1NSwyMjYzNSwzMDAwMCwyOTk4MCwyNDY4NCwzMzMwMCwzMzA5NCwyNTM2MSwyNjQ2NSwzNjgzNCwzMDUyMiwzNjMzOSwzNjE0OCwzODA4MSwyNDA4NiwyMTM4MSwyMTU0OCwyODg2NywzNDQxMywzNDQxNSwzNDQxNiwzNDQxOCwzNDQxOSwzNDQyMCwzNDQyMSwzNDQyMiwzNDQyMywzNDQyNCwzNDQzNSwzNDQzNiwzNDQzNywzNDQzOCwzNDQzOSwzNDQ0MCwzNDQ0MSwzNDQ0NiwzNDQ0NywzNDQ0OCwzNDQ0OSwzNDQ1MCwzNDQ1MiwzNDQ1NCwzNDQ1NSwzNDQ1NiwzNDQ1NywzNDQ1OCwzNDQ1OSwzNDQ2MiwzNDQ2MywzNDQ2NCwzNDQ2NSwzNDQ2NiwzNDQ2OSwzNDQ3MCwzNDQ3NSwzNDQ3NywzNDQ3OCwzNDQ4MiwzNDQ4MywzNDQ4NywzNDQ4OCwzNDQ4OSwzNDQ5MSwzNDQ5MiwzNDQ5MywzNDQ5NCwzNDQ5NSwzNDQ5NywzNDQ5OCwzNDQ5OSwzNDUwMSwzNDUwNCwzNDUwOCwzNDUwOSwzNDUxNCwzNDUxNSwzNDUxNywzNDUxOCwzNDUxOSwzNDUyMiwzNDUyNCwzNDUyNSwzNDUyOCwzNDUyOSwzNDUzMCwzNDUzMSwzNDUzMywzNDUzNCwzNDUzNSwzNDUzNiwzNDUzOCwzNDUzOSwzNDU0MCwzNDU0MywzNDU0OSwzNDU1MCwzNDU1MSwzNDU1NCwzNDU1NSwzNDU1NiwzNDU1NywzNDU1OSwzNDU2MSwzNDU2NCwzNDU2NSwzNDU2NiwzNDU3MSwzNDU3MiwzNDU3NCwzNDU3NSwzNDU3NiwzNDU3NywzNDU4MCwzNDU4MiwyNzcxMiwyNDMxMSwyMDU3MiwyMDE0MSwyNDIzNywyNTQwMiwzMzM1MSwzNjg5MCwyNjcwNCwzNzIzMCwzMDY0MywyMTUxNiwzODEwOCwyNDQyMCwzMTQ2MSwyNjc0MiwyNTQxMywzMTU3MCwzMjQ3OSwzMDE3MSwyMDU5OSwyNTIzNywyMjgzNiwzNjg3OSwyMDk4NCwzMTE3MSwzMTM2MSwyMjI3MCwyNDQ2NiwzNjg4NCwyODAzNCwyMzY0OCwyMjMwMywyMTUyMCwyMDgyMCwyODIzNywyMjI0MiwyNTUxMiwzOTA1OSwzMzE1MSwzNDU4MSwzNTExNCwzNjg2NCwyMTUzNCwyMzY2MywzMzIxNiwyNTMwMiwyNTE3NiwzMzA3Myw0MDUwMSwzODQ2NCwzOTUzNCwzOTU0OCwyNjkyNSwyMjk0OSwyNTI5OSwyMTgyMiwyNTM2NiwyMTcwMywzNDUyMSwyNzk2NCwyMzA0MywyOTkyNiwzNDk3MiwyNzQ5OCwyMjgwNiwzNTkxNiwyNDM2NywyODI4NiwyOTYwOSwzOTAzNywyMDAyNCwyODkxOSwyMzQzNiwzMDg3MSwyNTQwNSwyNjIwMiwzMDM1OCwyNDc3OSwyMzQ1MSwyMzExMywxOTk3NSwzMzEwOSwyNzc1NCwyOTU3OSwyMDEyOSwyNjUwNSwzMjU5MywyNDQ0OCwyNjEwNiwyNjM5NSwyNDUzNiwyMjkxNiwyMzA0MSwzNDU4NSwzNDU4NywzNDU4OSwzNDU5MSwzNDU5MiwzNDU5NiwzNDU5OCwzNDU5OSwzNDYwMCwzNDYwMiwzNDYwMywzNDYwNCwzNDYwNSwzNDYwNywzNDYwOCwzNDYxMCwzNDYxMSwzNDYxMywzNDYxNCwzNDYxNiwzNDYxNywzNDYxOCwzNDYyMCwzNDYyMSwzNDYyNCwzNDYyNSwzNDYyNiwzNDYyNywzNDYyOCwzNDYyOSwzNDYzMCwzNDYzNCwzNDYzNSwzNDYzNywzNDYzOSwzNDY0MCwzNDY0MSwzNDY0MiwzNDY0NCwzNDY0NSwzNDY0NiwzNDY0OCwzNDY1MCwzNDY1MSwzNDY1MiwzNDY1MywzNDY1NCwzNDY1NSwzNDY1NywzNDY1OCwzNDY2MiwzNDY2MywzNDY2NCwzNDY2NSwzNDY2NiwzNDY2NywzNDY2OCwzNDY2OSwzNDY3MSwzNDY3MywzNDY3NCwzNDY3NSwzNDY3NywzNDY3OSwzNDY4MCwzNDY4MSwzNDY4MiwzNDY4NywzNDY4OCwzNDY4OSwzNDY5MiwzNDY5NCwzNDY5NSwzNDY5NywzNDY5OCwzNDcwMCwzNDcwMiwzNDcwMywzNDcwNCwzNDcwNSwzNDcwNiwzNDcwOCwzNDcwOSwzNDcxMCwzNDcxMiwzNDcxMywzNDcxNCwzNDcxNSwzNDcxNiwzNDcxNywzNDcxOCwzNDcyMCwzNDcyMSwzNDcyMiwzNDcyMywzNDcyNCwyNDAxMywyNDQ5NCwyMTM2MSwzODg4NiwzNjgyOSwyNjY5MywyMjI2MCwyMTgwNywyNDc5OSwyMDAyNiwyODQ5MywzMjUwMCwzMzQ3OSwzMzgwNiwyMjk5NiwyMDI1NSwyMDI2NiwyMzYxNCwzMjQyOCwyNjQxMCwzNDA3NCwyMTYxOSwzMDAzMSwzMjk2MywyMTg5MCwzOTc1OSwyMDMwMSwyODIwNSwzNTg1OSwyMzU2MSwyNDk0NCwyMTM1NSwzMDIzOSwyODIwMSwzNDQ0MiwyNTk5MSwzODM5NSwzMjQ0MSwyMTU2MywzMTI4MywzMjAxMCwzODM4MiwyMTk4NSwzMjcwNSwyOTkzNCwyNTM3MywzNDU4MywyODA2NSwzMTM4OSwyNTEwNSwyNjAxNywyMTM1MSwyNTU2OSwyNzc3OSwyNDA0MywyMTU5NiwzODA1NiwyMDA0NCwyNzc0NSwzNTgyMCwyMzYyNywyNjA4MCwzMzQzNiwyNjc5MSwyMTU2NiwyMTU1NiwyNzU5NSwyNzQ5NCwyMDExNiwyNTQxMCwyMTMyMCwzMzMxMCwyMDIzNywyMDM5OCwyMjM2NiwyNTA5OCwzODY1NCwyNjIxMiwyOTI4OSwyMTI0NywyMTE1MywyNDczNSwzNTgyMywyNjEzMiwyOTA4MSwyNjUxMiwzNTE5OSwzMDgwMiwzMDcxNywyNjIyNCwyMjA3NSwyMTU2MCwzODE3NywyOTMwNiwzNDcyNSwzNDcyNiwzNDcyNywzNDcyOSwzNDczMCwzNDczNCwzNDczNiwzNDczNywzNDczOCwzNDc0MCwzNDc0MiwzNDc0MywzNDc0NCwzNDc0NSwzNDc0NywzNDc0OCwzNDc1MCwzNDc1MSwzNDc1MywzNDc1NCwzNDc1NSwzNDc1NiwzNDc1NywzNDc1OSwzNDc2MCwzNDc2MSwzNDc2NCwzNDc2NSwzNDc2NiwzNDc2NywzNDc2OCwzNDc3MiwzNDc3MywzNDc3NCwzNDc3NSwzNDc3NiwzNDc3NywzNDc3OCwzNDc4MCwzNDc4MSwzNDc4MiwzNDc4MywzNDc4NSwzNDc4NiwzNDc4NywzNDc4OCwzNDc5MCwzNDc5MSwzNDc5MiwzNDc5MywzNDc5NSwzNDc5NiwzNDc5NywzNDc5OSwzNDgwMCwzNDgwMSwzNDgwMiwzNDgwMywzNDgwNCwzNDgwNSwzNDgwNiwzNDgwNywzNDgwOCwzNDgxMCwzNDgxMSwzNDgxMiwzNDgxMywzNDgxNSwzNDgxNiwzNDgxNywzNDgxOCwzNDgyMCwzNDgyMSwzNDgyMiwzNDgyMywzNDgyNCwzNDgyNSwzNDgyNywzNDgyOCwzNDgyOSwzNDgzMCwzNDgzMSwzNDgzMiwzNDgzMywzNDgzNCwzNDgzNiwzNDgzOSwzNDg0MCwzNDg0MSwzNDg0MiwzNDg0NCwzNDg0NSwzNDg0NiwzNDg0NywzNDg0OCwzNDg1MSwzMTIzMiwyNDY4NywyNDA3NiwyNDcxMywzMzE4MSwyMjgwNSwyNDc5NiwyOTA2MCwyODkxMSwyODMzMCwyNzcyOCwyOTMxMiwyNzI2OCwzNDk4OSwyNDEwOSwyMDA2NCwyMzIxOSwyMTkxNiwzODExNSwyNzkyNywzMTk5NSwzODU1MywyNTEwMywzMjQ1NCwzMDYwNiwzNDQzMCwyMTI4MywzODY4NiwzNjc1OCwyNjI0NywyMzc3NywyMDM4NCwyOTQyMSwxOTk3OSwyMTQxNCwyMjc5OSwyMTUyMywyNTQ3MiwzODE4NCwyMDgwOCwyMDE4NSw0MDA5MiwzMjQyMCwyMTY4OCwzNjEzMiwzNDkwMCwzMzMzNSwzODM4NiwyODA0NiwyNDM1OCwyMzI0NCwyNjE3NCwzODUwNSwyOTYxNiwyOTQ4NiwyMTQzOSwzMzE0NiwzOTMwMSwzMjY3MywyMzQ2NiwzODUxOSwzODQ4MCwzMjQ0NywzMDQ1NiwyMTQxMCwzODI2MiwzOTMyMSwzMTY2NSwzNTE0MCwyODI0OCwyMDA2NSwzMjcyNCwzMTA3NywzNTgxNCwyNDgxOSwyMTcwOSwyMDEzOSwzOTAzMywyNDA1NSwyNzIzMywyMDY4NywyMTUyMSwzNTkzNywzMzgzMSwzMDgxMywzODY2MCwyMTA2NiwyMTc0MiwyMjE3OSwzODE0NCwyODA0MCwyMzQ3NywyODEwMiwyNjE5NSwzNDg1MiwzNDg1MywzNDg1NCwzNDg1NSwzNDg1NiwzNDg1NywzNDg1OCwzNDg1OSwzNDg2MCwzNDg2MSwzNDg2MiwzNDg2MywzNDg2NCwzNDg2NSwzNDg2NywzNDg2OCwzNDg2OSwzNDg3MCwzNDg3MSwzNDg3MiwzNDg3NCwzNDg3NSwzNDg3NywzNDg3OCwzNDg3OSwzNDg4MSwzNDg4MiwzNDg4MywzNDg4NiwzNDg4NywzNDg4OCwzNDg4OSwzNDg5MCwzNDg5MSwzNDg5NCwzNDg5NSwzNDg5NiwzNDg5NywzNDg5OCwzNDg5OSwzNDkwMSwzNDkwMiwzNDkwNCwzNDkwNiwzNDkwNywzNDkwOCwzNDkwOSwzNDkxMCwzNDkxMSwzNDkxMiwzNDkxOCwzNDkxOSwzNDkyMiwzNDkyNSwzNDkyNywzNDkyOSwzNDkzMSwzNDkzMiwzNDkzMywzNDkzNCwzNDkzNiwzNDkzNywzNDkzOCwzNDkzOSwzNDk0MCwzNDk0NCwzNDk0NywzNDk1MCwzNDk1MSwzNDk1MywzNDk1NCwzNDk1NiwzNDk1OCwzNDk1OSwzNDk2MCwzNDk2MSwzNDk2MywzNDk2NCwzNDk2NSwzNDk2NywzNDk2OCwzNDk2OSwzNDk3MCwzNDk3MSwzNDk3MywzNDk3NCwzNDk3NSwzNDk3NiwzNDk3NywzNDk3OSwzNDk4MSwzNDk4MiwzNDk4MywzNDk4NCwzNDk4NSwzNDk4NiwyMzU2NywyMzM4OSwyNjY1NywzMjkxOCwyMTg4MCwzMTUwNSwyNTkyOCwyNjk2NCwyMDEyMywyNzQ2MywzNDYzOCwzODc5NSwyMTMyNywyNTM3NSwyNTY1OCwzNzAzNCwyNjAxMiwzMjk2MSwzNTg1NiwyMDg4OSwyNjgwMCwyMTM2OCwzNDgwOSwyNTAzMiwyNzg0NCwyNzg5OSwzNTg3NCwyMzYzMywzNDIxOCwzMzQ1NSwzODE1NiwyNzQyNywzNjc2MywyNjAzMiwyNDU3MSwyNDUxNSwyMDQ0OSwzNDg4NSwyNjE0MywzMzEyNSwyOTQ4MSwyNDgyNiwyMDg1MiwyMTAwOSwyMjQxMSwyNDQxOCwzNzAyNiwzNDg5MiwzNzI2NiwyNDE4NCwyNjQ0NywyNDYxNSwyMjk5NSwyMDgwNCwyMDk4MiwzMzAxNiwyMTI1NiwyNzc2OSwzODU5NiwyOTA2NiwyMDI0MSwyMDQ2MiwzMjY3MCwyNjQyOSwyMTk1NywzODE1MiwzMTE2OCwzNDk2NiwzMjQ4MywyMjY4NywyNTEwMCwzODY1NiwzNDM5NCwyMjA0MCwzOTAzNSwyNDQ2NCwzNTc2OCwzMzk4OCwzNzIwNywyMTQ2NSwyNjA5MywyNDIwNywzMDA0NCwyNDY3NiwzMjExMCwyMzE2NywzMjQ5MCwzMjQ5MywzNjcxMywyMTkyNywyMzQ1OSwyNDc0OCwyNjA1OSwyOTU3MiwzNDk4OCwzNDk5MCwzNDk5MSwzNDk5MiwzNDk5NCwzNDk5NSwzNDk5NiwzNDk5NywzNDk5OCwzNTAwMCwzNTAwMSwzNTAwMiwzNTAwMywzNTAwNSwzNTAwNiwzNTAwNywzNTAwOCwzNTAxMSwzNTAxMiwzNTAxNSwzNTAxNiwzNTAxOCwzNTAxOSwzNTAyMCwzNTAyMSwzNTAyMywzNTAyNCwzNTAyNSwzNTAyNywzNTAzMCwzNTAzMSwzNTAzNCwzNTAzNSwzNTAzNiwzNTAzNywzNTAzOCwzNTA0MCwzNTA0MSwzNTA0NiwzNTA0NywzNTA0OSwzNTA1MCwzNTA1MSwzNTA1MiwzNTA1MywzNTA1NCwzNTA1NSwzNTA1OCwzNTA2MSwzNTA2MiwzNTA2MywzNTA2NiwzNTA2NywzNTA2OSwzNTA3MSwzNTA3MiwzNTA3MywzNTA3NSwzNTA3NiwzNTA3NywzNTA3OCwzNTA3OSwzNTA4MCwzNTA4MSwzNTA4MywzNTA4NCwzNTA4NSwzNTA4NiwzNTA4NywzNTA4OSwzNTA5MiwzNTA5MywzNTA5NCwzNTA5NSwzNTA5NiwzNTEwMCwzNTEwMSwzNTEwMiwzNTEwMywzNTEwNCwzNTEwNiwzNTEwNywzNTEwOCwzNTExMCwzNTExMSwzNTExMiwzNTExMywzNTExNiwzNTExNywzNTExOCwzNTExOSwzNTEyMSwzNTEyMiwzNTEyMywzNTEyNSwzNTEyNywzNjg3MywzMDMwNywzMDUwNSwzMjQ3NCwzODc3MiwzNDIwMywyMzM5OCwzMTM0OCwzODYzNCwzNDg4MCwyMTE5NSwyOTA3MSwyNDQ5MCwyNjA5MiwzNTgxMCwyMzU0NywzOTUzNSwyNDAzMywyNzUyOSwyNzczOSwzNTc1NywzNTc1OSwzNjg3NCwzNjgwNSwyMTM4NywyNTI3Niw0MDQ4Niw0MDQ5MywyMTU2OCwyMDAxMSwzMzQ2OSwyOTI3MywzNDQ2MCwyMzgzMCwzNDkwNSwyODA3OSwzODU5NywyMTcxMywyMDEyMiwzNTc2NiwyODkzNywyMTY5MywzODQwOSwyODg5NSwyODE1MywzMDQxNiwyMDAwNSwzMDc0MCwzNDU3OCwyMzcyMSwyNDMxMCwzNTMyOCwzOTA2OCwzODQxNCwyODgxNCwyNzgzOSwyMjg1MiwyNTUxMywzMDUyNCwzNDg5MywyODQzNiwzMzM5NSwyMjU3NiwyOTE0MSwyMTM4OCwzMDc0NiwzODU5MywyMTc2MSwyNDQyMiwyODk3NiwyMzQ3NiwzNTg2NiwzOTU2NCwyNzUyMywyMjgzMCw0MDQ5NSwzMTIwNywyNjQ3MiwyNTE5NiwyMDMzNSwzMDExMywzMjY1MCwyNzkxNSwzODQ1MSwyNzY4NywyMDIwOCwzMDE2MiwyMDg1OSwyNjY3OSwyODQ3OCwzNjk5MiwzMzEzNiwyMjkzNCwyOTgxNCwzNTEyOCwzNTEyOSwzNTEzMCwzNTEzMSwzNTEzMiwzNTEzMywzNTEzNCwzNTEzNSwzNTEzNiwzNTEzOCwzNTEzOSwzNTE0MSwzNTE0MiwzNTE0MywzNTE0NCwzNTE0NSwzNTE0NiwzNTE0NywzNTE0OCwzNTE0OSwzNTE1MCwzNTE1MSwzNTE1MiwzNTE1MywzNTE1NCwzNTE1NSwzNTE1NiwzNTE1NywzNTE1OCwzNTE1OSwzNTE2MCwzNTE2MSwzNTE2MiwzNTE2MywzNTE2NCwzNTE2NSwzNTE2OCwzNTE2OSwzNTE3MCwzNTE3MSwzNTE3MiwzNTE3MywzNTE3NSwzNTE3NiwzNTE3NywzNTE3OCwzNTE3OSwzNTE4MCwzNTE4MSwzNTE4MiwzNTE4MywzNTE4NCwzNTE4NSwzNTE4NiwzNTE4NywzNTE4OCwzNTE4OSwzNTE5MCwzNTE5MSwzNTE5MiwzNTE5MywzNTE5NCwzNTE5NiwzNTE5NywzNTE5OCwzNTIwMCwzNTIwMiwzNTIwNCwzNTIwNSwzNTIwNywzNTIwOCwzNTIwOSwzNTIxMCwzNTIxMSwzNTIxMiwzNTIxMywzNTIxNCwzNTIxNSwzNTIxNiwzNTIxNywzNTIxOCwzNTIxOSwzNTIyMCwzNTIyMSwzNTIyMiwzNTIyMywzNTIyNCwzNTIyNSwzNTIyNiwzNTIyNywzNTIyOCwzNTIyOSwzNTIzMCwzNTIzMSwzNTIzMiwzNTIzMywyNTY3MSwyMzU5MSwzNjk2NSwzMTM3NywzNTg3NSwyMzAwMiwyMTY3NiwzMzI4MCwzMzY0NywzNTIwMSwzMjc2OCwyNjkyOCwyMjA5NCwzMjgyMiwyOTIzOSwzNzMyNiwyMDkxOCwyMDA2MywzOTAyOSwyNTQ5NCwxOTk5NCwyMTQ5NCwyNjM1NSwzMzA5OSwyMjgxMiwyODA4MiwxOTk2OCwyMjc3NywyMTMwNywyNTU1OCwzODEyOSwyMDM4MSwyMDIzNCwzNDkxNSwzOTA1NiwyMjgzOSwzNjk1MSwzMTIyNywyMDIwMiwzMzAwOCwzMDA5NywyNzc3OCwyMzQ1MiwyMzAxNiwyNDQxMywyNjg4NSwzNDQzMywyMDUwNiwyNDA1MCwyMDA1NywzMDY5MSwyMDE5NywzMzQwMiwyNTIzMywyNjEzMSwzNzAwOSwyMzY3MywyMDE1OSwyNDQ0MSwzMzIyMiwzNjkyMCwzMjkwMCwzMDEyMywyMDEzNCwzNTAyOCwyNDg0NywyNzU4OSwyNDUxOCwyMDA0MSwzMDQxMCwyODMyMiwzNTgxMSwzNTc1OCwzNTg1MCwzNTc5MywyNDMyMiwzMjc2NCwzMjcxNiwzMjQ2MiwzMzU4OSwzMzY0MywyMjI0MCwyNzU3NSwzODg5OSwzODQ1MiwyMzAzNSwyMTUzNSwzODEzNCwyODEzOSwyMzQ5MywzOTI3OCwyMzYwOSwyNDM0MSwzODU0NCwzNTIzNCwzNTIzNSwzNTIzNiwzNTIzNywzNTIzOCwzNTIzOSwzNTI0MCwzNTI0MSwzNTI0MiwzNTI0MywzNTI0NCwzNTI0NSwzNTI0NiwzNTI0NywzNTI0OCwzNTI0OSwzNTI1MCwzNTI1MSwzNTI1MiwzNTI1MywzNTI1NCwzNTI1NSwzNTI1NiwzNTI1NywzNTI1OCwzNTI1OSwzNTI2MCwzNTI2MSwzNTI2MiwzNTI2MywzNTI2NCwzNTI2NywzNTI3NywzNTI4MywzNTI4NCwzNTI4NSwzNTI4NywzNTI4OCwzNTI4OSwzNTI5MSwzNTI5MywzNTI5NSwzNTI5NiwzNTI5NywzNTI5OCwzNTMwMCwzNTMwMywzNTMwNCwzNTMwNSwzNTMwNiwzNTMwOCwzNTMwOSwzNTMxMCwzNTMxMiwzNTMxMywzNTMxNCwzNTMxNiwzNTMxNywzNTMxOCwzNTMxOSwzNTMyMCwzNTMyMSwzNTMyMiwzNTMyMywzNTMyNCwzNTMyNSwzNTMyNiwzNTMyNywzNTMyOSwzNTMzMCwzNTMzMSwzNTMzMiwzNTMzMywzNTMzNCwzNTMzNiwzNTMzNywzNTMzOCwzNTMzOSwzNTM0MCwzNTM0MSwzNTM0MiwzNTM0MywzNTM0NCwzNTM0NSwzNTM0NiwzNTM0NywzNTM0OCwzNTM0OSwzNTM1MCwzNTM1MSwzNTM1MiwzNTM1MywzNTM1NCwzNTM1NSwzNTM1NiwzNTM1NywyMTM2MCwzMzUyMSwyNzE4NSwyMzE1Niw0MDU2MCwyNDIxMiwzMjU1MiwzMzcyMSwzMzgyOCwzMzgyOSwzMzYzOSwzNDYzMSwzNjgxNCwzNjE5NCwzMDQwOCwyNDQzMywzOTA2MiwzMDgyOCwyNjE0NCwyMTcyNywyNTMxNywyMDMyMywzMzIxOSwzMDE1MiwyNDI0OCwzODYwNSwzNjM2MiwzNDU1MywyMTY0NywyNzg5MSwyODA0NCwyNzcwNCwyNDcwMywyMTE5MSwyOTk5MiwyNDE4OSwyMDI0OCwyNDczNiwyNDU1MSwyMzU4OCwzMDAwMSwzNzAzOCwzODA4MCwyOTM2OSwyNzgzMywyODIxNiwzNzE5MywyNjM3NywyMTQ1MSwyMTQ5MSwyMDMwNSwzNzMyMSwzNTgyNSwyMTQ0OCwyNDE4OCwzNjgwMiwyODEzMiwyMDExMCwzMDQwMiwyNzAxNCwzNDM5OCwyNDg1OCwzMzI4NiwyMDMxMywyMDQ0NiwzNjkyNiw0MDA2MCwyNDg0MSwyODE4OSwyODE4MCwzODUzMywyMDEwNCwyMzA4OSwzODYzMiwxOTk4MiwyMzY3OSwzMTE2MSwyMzQzMSwzNTgyMSwzMjcwMSwyOTU3NywyMjQ5NSwzMzQxOSwzNzA1NywyMTUwNSwzNjkzNSwyMTk0NywyMzc4NiwyNDQ4MSwyNDg0MCwyNzQ0MiwyOTQyNSwzMjk0NiwzNTQ2NSwzNTM1OCwzNTM1OSwzNTM2MCwzNTM2MSwzNTM2MiwzNTM2MywzNTM2NCwzNTM2NSwzNTM2NiwzNTM2NywzNTM2OCwzNTM2OSwzNTM3MCwzNTM3MSwzNTM3MiwzNTM3MywzNTM3NCwzNTM3NSwzNTM3NiwzNTM3NywzNTM3OCwzNTM3OSwzNTM4MCwzNTM4MSwzNTM4MiwzNTM4MywzNTM4NCwzNTM4NSwzNTM4NiwzNTM4NywzNTM4OCwzNTM4OSwzNTM5MSwzNTM5MiwzNTM5MywzNTM5NCwzNTM5NSwzNTM5NiwzNTM5NywzNTM5OCwzNTM5OSwzNTQwMSwzNTQwMiwzNTQwMywzNTQwNCwzNTQwNSwzNTQwNiwzNTQwNywzNTQwOCwzNTQwOSwzNTQxMCwzNTQxMSwzNTQxMiwzNTQxMywzNTQxNCwzNTQxNSwzNTQxNiwzNTQxNywzNTQxOCwzNTQxOSwzNTQyMCwzNTQyMSwzNTQyMiwzNTQyMywzNTQyNCwzNTQyNSwzNTQyNiwzNTQyNywzNTQyOCwzNTQyOSwzNTQzMCwzNTQzMSwzNTQzMiwzNTQzMywzNTQzNCwzNTQzNSwzNTQzNiwzNTQzNywzNTQzOCwzNTQzOSwzNTQ0MCwzNTQ0MSwzNTQ0MiwzNTQ0MywzNTQ0NCwzNTQ0NSwzNTQ0NiwzNTQ0NywzNTQ0OCwzNTQ1MCwzNTQ1MSwzNTQ1MiwzNTQ1MywzNTQ1NCwzNTQ1NSwzNTQ1NiwyODAyMCwyMzUwNywzNTAyOSwzOTA0NCwzNTk0NywzOTUzMyw0MDQ5OSwyODE3MCwyMDkwMCwyMDgwMywyMjQzNSwzNDk0NSwyMTQwNywyNTU4OCwzNjc1NywyMjI1MywyMTU5MiwyMjI3OCwyOTUwMywyODMwNCwzMjUzNiwzNjgyOCwzMzQ4OSwyNDg5NSwyNDYxNiwzODQ5OCwyNjM1MiwzMjQyMiwzNjIzNCwzNjI5MSwzODA1MywyMzczMSwzMTkwOCwyNjM3NiwyNDc0MiwzODQwNSwzMjc5MiwyMDExMywzNzA5NSwyMTI0OCwzODUwNCwyMDgwMSwzNjgxNiwzNDE2NCwzNzIxMywyNjE5NywzODkwMSwyMzM4MSwyMTI3NywzMDc3NiwyNjQzNCwyNjY4NSwyMTcwNSwyODc5OCwyMzQ3MiwzNjczMywyMDg3NywyMjMxMiwyMTY4MSwyNTg3NCwyNjI0MiwzNjE5MCwzNjE2MywzMzAzOSwzMzkwMCwzNjk3MywzMTk2NywyMDk5MSwzNDI5OSwyNjUzMSwyNjA4OSwyODU3NywzNDQ2OCwzNjQ4MSwyMjEyMiwzNjg5NiwzMDMzOCwyODc5MCwyOTE1NywzNjEzMSwyNTMyMSwyMTAxNywyNzkwMSwzNjE1NiwyNDU5MCwyMjY4NiwyNDk3NCwyNjM2NiwzNjE5MiwyNTE2NiwyMTkzOSwyODE5NSwyNjQxMywzNjcxMSwzNTQ1NywzNTQ1OCwzNTQ1OSwzNTQ2MCwzNTQ2MSwzNTQ2MiwzNTQ2MywzNTQ2NCwzNTQ2NywzNTQ2OCwzNTQ2OSwzNTQ3MCwzNTQ3MSwzNTQ3MiwzNTQ3MywzNTQ3NCwzNTQ3NiwzNTQ3NywzNTQ3OCwzNTQ3OSwzNTQ4MCwzNTQ4MSwzNTQ4MiwzNTQ4MywzNTQ4NCwzNTQ4NSwzNTQ4NiwzNTQ4NywzNTQ4OCwzNTQ4OSwzNTQ5MCwzNTQ5MSwzNTQ5MiwzNTQ5MywzNTQ5NCwzNTQ5NSwzNTQ5NiwzNTQ5NywzNTQ5OCwzNTQ5OSwzNTUwMCwzNTUwMSwzNTUwMiwzNTUwMywzNTUwNCwzNTUwNSwzNTUwNiwzNTUwNywzNTUwOCwzNTUwOSwzNTUxMCwzNTUxMSwzNTUxMiwzNTUxMywzNTUxNCwzNTUxNSwzNTUxNiwzNTUxNywzNTUxOCwzNTUxOSwzNTUyMCwzNTUyMSwzNTUyMiwzNTUyMywzNTUyNCwzNTUyNSwzNTUyNiwzNTUyNywzNTUyOCwzNTUyOSwzNTUzMCwzNTUzMSwzNTUzMiwzNTUzMywzNTUzNCwzNTUzNSwzNTUzNiwzNTUzNywzNTUzOCwzNTUzOSwzNTU0MCwzNTU0MSwzNTU0MiwzNTU0MywzNTU0NCwzNTU0NSwzNTU0NiwzNTU0NywzNTU0OCwzNTU0OSwzNTU1MCwzNTU1MSwzNTU1MiwzNTU1MywzNTU1NCwzNTU1NSwzODExMywzODM5MiwzMDUwNCwyNjYyOSwyNzA0OCwyMTY0MywyMDA0NSwyODg1NiwzNTc4NCwyNTY4OCwyNTk5NSwyMzQyOSwzMTM2NCwyMDUzOCwyMzUyOCwzMDY1MSwyNzYxNywzNTQ0OSwzMTg5NiwyNzgzOCwzMDQxNSwyNjAyNSwzNjc1OSwyMzg1MywyMzYzNywzNDM2MCwyNjYzMiwyMTM0NCwyNTExMiwzMTQ0OSwyODI1MSwzMjUwOSwyNzE2NywzMTQ1NiwyNDQzMiwyODQ2NywyNDM1MiwyNTQ4NCwyODA3MiwyNjQ1NCwxOTk3NiwyNDA4MCwzNjEzNCwyMDE4MywzMjk2MCwzMDI2MCwzODU1NiwyNTMwNywyNjE1NywyNTIxNCwyNzgzNiwzNjIxMywyOTAzMSwzMjYxNywyMDgwNiwzMjkwMywyMTQ4NCwzNjk3NCwyNTI0MCwyMTc0NiwzNDU0NCwzNjc2MSwzMjc3MywzODE2NywzNDA3MSwzNjgyNSwyNzk5MywyOTY0NSwyNjAxNSwzMDQ5NSwyOTk1NiwzMDc1OSwzMzI3NSwzNjEyNiwzODAyNCwyMDM5MCwyNjUxNywzMDEzNywzNTc4NiwzODY2MywyNTM5MSwzODIxNSwzODQ1MywzMzk3NiwyNTM3OSwzMDUyOSwyNDQ0OSwyOTQyNCwyMDEwNSwyNDU5NiwyNTk3MiwyNTMyNywyNzQ5MSwyNTkxOSwzNTU1NiwzNTU1NywzNTU1OCwzNTU1OSwzNTU2MCwzNTU2MSwzNTU2MiwzNTU2MywzNTU2NCwzNTU2NSwzNTU2NiwzNTU2NywzNTU2OCwzNTU2OSwzNTU3MCwzNTU3MSwzNTU3MiwzNTU3MywzNTU3NCwzNTU3NSwzNTU3NiwzNTU3NywzNTU3OCwzNTU3OSwzNTU4MCwzNTU4MSwzNTU4MiwzNTU4MywzNTU4NCwzNTU4NSwzNTU4NiwzNTU4NywzNTU4OCwzNTU4OSwzNTU5MCwzNTU5MiwzNTU5MywzNTU5NCwzNTU5NSwzNTU5NiwzNTU5NywzNTU5OCwzNTU5OSwzNTYwMCwzNTYwMSwzNTYwMiwzNTYwMywzNTYwNCwzNTYwNSwzNTYwNiwzNTYwNywzNTYwOCwzNTYwOSwzNTYxMCwzNTYxMSwzNTYxMiwzNTYxMywzNTYxNCwzNTYxNSwzNTYxNiwzNTYxNywzNTYxOCwzNTYxOSwzNTYyMCwzNTYyMSwzNTYyMywzNTYyNCwzNTYyNSwzNTYyNiwzNTYyNywzNTYyOCwzNTYyOSwzNTYzMCwzNTYzMSwzNTYzMiwzNTYzMywzNTYzNCwzNTYzNSwzNTYzNiwzNTYzNywzNTYzOCwzNTYzOSwzNTY0MCwzNTY0MSwzNTY0MiwzNTY0MywzNTY0NCwzNTY0NSwzNTY0NiwzNTY0NywzNTY0OCwzNTY0OSwzNTY1MCwzNTY1MSwzNTY1MiwzNTY1MywyNDEwMywzMDE1MSwzNzA3MywzNTc3NywzMzQzNywyNjUyNSwyNTkwMywyMTU1MywzNDU4NCwzMDY5MywzMjkzMCwzMzAyNiwyNzcxMywyMDA0MywzMjQ1NSwzMjg0NCwzMDQ1MiwyNjg5MywyNzU0MiwyNTE5MSwyMDU0MCwyMDM1NiwyMjMzNiwyNTM1MSwyNzQ5MCwzNjI4NiwyMTQ4MiwyNjA4OCwzMjQ0MCwyNDUzNSwyNTM3MCwyNTUyNywzMzI2NywzMzI2OCwzMjYyMiwyNDA5MiwyMzc2OSwyMTA0NiwyNjIzNCwzMTIwOSwzMTI1OCwzNjEzNiwyODgyNSwzMDE2NCwyODM4MiwyNzgzNSwzMTM3OCwyMDAxMywzMDQwNSwyNDU0NCwzODA0NywzNDkzNSwzMjQ1NiwzMTE4MSwzMjk1OSwzNzMyNSwyMDIxMCwyMDI0NywzMzMxMSwyMTYwOCwyNDAzMCwyNzk1NCwzNTc4OCwzMTkwOSwzNjcyNCwzMjkyMCwyNDA5MCwyMTY1MCwzMDM4NSwyMzQ0OSwyNjE3MiwzOTU4OCwyOTY2NCwyNjY2NiwzNDUyMywyNjQxNywyOTQ4MiwzNTgzMiwzNTgwMywzNjg4MCwzMTQ4MSwyODg5MSwyOTAzOCwyNTI4NCwzMDYzMywyMjA2NSwyMDAyNywzMzg3OSwyNjYwOSwyMTE2MSwzNDQ5NiwzNjE0MiwzODEzNiwzMTU2OSwzNTY1NCwzNTY1NSwzNTY1NiwzNTY1NywzNTY1OCwzNTY1OSwzNTY2MCwzNTY2MSwzNTY2MiwzNTY2MywzNTY2NCwzNTY2NSwzNTY2NiwzNTY2NywzNTY2OCwzNTY2OSwzNTY3MCwzNTY3MSwzNTY3MiwzNTY3MywzNTY3NCwzNTY3NSwzNTY3NiwzNTY3NywzNTY3OCwzNTY3OSwzNTY4MCwzNTY4MSwzNTY4MiwzNTY4MywzNTY4NCwzNTY4NSwzNTY4NywzNTY4OCwzNTY4OSwzNTY5MCwzNTY5MSwzNTY5MywzNTY5NCwzNTY5NSwzNTY5NiwzNTY5NywzNTY5OCwzNTY5OSwzNTcwMCwzNTcwMSwzNTcwMiwzNTcwMywzNTcwNCwzNTcwNSwzNTcwNiwzNTcwNywzNTcwOCwzNTcwOSwzNTcxMCwzNTcxMSwzNTcxMiwzNTcxMywzNTcxNCwzNTcxNSwzNTcxNiwzNTcxNywzNTcxOCwzNTcxOSwzNTcyMCwzNTcyMSwzNTcyMiwzNTcyMywzNTcyNCwzNTcyNSwzNTcyNiwzNTcyNywzNTcyOCwzNTcyOSwzNTczMCwzNTczMSwzNTczMiwzNTczMywzNTczNCwzNTczNSwzNTczNiwzNTczNywzNTczOCwzNTczOSwzNTc0MCwzNTc0MSwzNTc0MiwzNTc0MywzNTc1NiwzNTc2MSwzNTc3MSwzNTc4MywzNTc5MiwzNTgxOCwzNTg0OSwzNTg3MCwyMDMwMywyNzg4MCwzMTA2OSwzOTU0NywyNTIzNSwyOTIyNiwyNTM0MSwxOTk4NywzMDc0MiwzNjcxNiwyNTc3NiwzNjE4NiwzMTY4NiwyNjcyOSwyNDE5NiwzNTAxMywyMjkxOCwyNTc1OCwyMjc2NiwyOTM2NiwyNjg5NCwzODE4MSwzNjg2MSwzNjE4NCwyMjM2OCwzMjUxMiwzNTg0NiwyMDkzNCwyNTQxNywyNTMwNSwyMTMzMSwyNjcwMCwyOTczMCwzMzUzNywzNzE5NiwyMTgyOCwzMDUyOCwyODc5NiwyNzk3OCwyMDg1NywyMTY3MiwzNjE2NCwyMzAzOSwyODM2MywyODEwMCwyMzM4OCwzMjA0MywyMDE4MCwzMTg2OSwyODM3MSwyMzM3NiwzMzI1OCwyODE3MywyMzM4MywzOTY4MywyNjgzNywzNjM5NCwyMzQ0NywzMjUwOCwyNDYzNSwzMjQzNywzNzA0OSwzNjIwOCwyMjg2MywyNTU0OSwzMTE5OSwzNjI3NSwyMTMzMCwyNjA2MywzMTA2MiwzNTc4MSwzODQ1OSwzMjQ1MiwzODA3NSwzMjM4NiwyMjA2OCwzNzI1NywyNjM2OCwzMjYxOCwyMzU2MiwzNjk4MSwyNjE1MiwyNDAzOCwyMDMwNCwyNjU5MCwyMDU3MCwyMDMxNiwyMjM1MiwyNDIzMSw1OTQwOCw1OTQwOSw1OTQxMCw1OTQxMSw1OTQxMiwzNTg5NiwzNTg5NywzNTg5OCwzNTg5OSwzNTkwMCwzNTkwMSwzNTkwMiwzNTkwMywzNTkwNCwzNTkwNiwzNTkwNywzNTkwOCwzNTkwOSwzNTkxMiwzNTkxNCwzNTkxNSwzNTkxNywzNTkxOCwzNTkxOSwzNTkyMCwzNTkyMSwzNTkyMiwzNTkyMywzNTkyNCwzNTkyNiwzNTkyNywzNTkyOCwzNTkyOSwzNTkzMSwzNTkzMiwzNTkzMywzNTkzNCwzNTkzNSwzNTkzNiwzNTkzOSwzNTk0MCwzNTk0MSwzNTk0MiwzNTk0MywzNTk0NCwzNTk0NSwzNTk0OCwzNTk0OSwzNTk1MCwzNTk1MSwzNTk1MiwzNTk1MywzNTk1NCwzNTk1NiwzNTk1NywzNTk1OCwzNTk1OSwzNTk2MywzNTk2NCwzNTk2NSwzNTk2NiwzNTk2NywzNTk2OCwzNTk2OSwzNTk3MSwzNTk3MiwzNTk3NCwzNTk3NSwzNTk3NiwzNTk3OSwzNTk4MSwzNTk4MiwzNTk4MywzNTk4NCwzNTk4NSwzNTk4NiwzNTk4NywzNTk4OSwzNTk5MCwzNTk5MSwzNTk5MywzNTk5NCwzNTk5NSwzNTk5NiwzNTk5NywzNTk5OCwzNTk5OSwzNjAwMCwzNjAwMSwzNjAwMiwzNjAwMywzNjAwNCwzNjAwNSwzNjAwNiwzNjAwNywzNjAwOCwzNjAwOSwzNjAxMCwzNjAxMSwzNjAxMiwzNjAxMywyMDEwOSwxOTk4MCwyMDgwMCwxOTk4NCwyNDMxOSwyMTMxNywxOTk4OSwyMDEyMCwxOTk5OCwzOTczMCwyMzQwNCwyMjEyMSwyMDAwOCwzMTE2MiwyMDAzMSwyMTI2OSwyMDAzOSwyMjgyOSwyOTI0MywyMTM1OCwyNzY2NCwyMjIzOSwzMjk5NiwzOTMxOSwyNzYwMywzMDU5MCw0MDcyNywyMDAyMiwyMDEyNyw0MDcyMCwyMDA2MCwyMDA3MywyMDExNSwzMzQxNiwyMzM4NywyMTg2OCwyMjAzMSwyMDE2NCwyMTM4OSwyMTQwNSwyMTQxMSwyMTQxMywyMTQyMiwzODc1NywzNjE4OSwyMTI3NCwyMTQ5MywyMTI4NiwyMTI5NCwyMTMxMCwzNjE4OCwyMTM1MCwyMTM0NywyMDk5NCwyMTAwMCwyMTAwNiwyMTAzNywyMTA0MywyMTA1NSwyMTA1NiwyMTA2OCwyMTA4NiwyMTA4OSwyMTA4NCwzMzk2NywyMTExNywyMTEyMiwyMTEyMSwyMTEzNiwyMTEzOSwyMDg2NiwzMjU5NiwyMDE1NSwyMDE2MywyMDE2OSwyMDE2MiwyMDIwMCwyMDE5MywyMDIwMywyMDE5MCwyMDI1MSwyMDIxMSwyMDI1OCwyMDMyNCwyMDIxMywyMDI2MSwyMDI2MywyMDIzMywyMDI2NywyMDMxOCwyMDMyNywyNTkxMiwyMDMxNCwyMDMxNywzNjAxNCwzNjAxNSwzNjAxNiwzNjAxNywzNjAxOCwzNjAxOSwzNjAyMCwzNjAyMSwzNjAyMiwzNjAyMywzNjAyNCwzNjAyNSwzNjAyNiwzNjAyNywzNjAyOCwzNjAyOSwzNjAzMCwzNjAzMSwzNjAzMiwzNjAzMywzNjAzNCwzNjAzNSwzNjAzNiwzNjAzNywzNjAzOCwzNjAzOSwzNjA0MCwzNjA0MSwzNjA0MiwzNjA0MywzNjA0NCwzNjA0NSwzNjA0NiwzNjA0NywzNjA0OCwzNjA0OSwzNjA1MCwzNjA1MSwzNjA1MiwzNjA1MywzNjA1NCwzNjA1NSwzNjA1NiwzNjA1NywzNjA1OCwzNjA1OSwzNjA2MCwzNjA2MSwzNjA2MiwzNjA2MywzNjA2NCwzNjA2NSwzNjA2NiwzNjA2NywzNjA2OCwzNjA2OSwzNjA3MCwzNjA3MSwzNjA3MiwzNjA3MywzNjA3NCwzNjA3NSwzNjA3NiwzNjA3NywzNjA3OCwzNjA3OSwzNjA4MCwzNjA4MSwzNjA4MiwzNjA4MywzNjA4NCwzNjA4NSwzNjA4NiwzNjA4NywzNjA4OCwzNjA4OSwzNjA5MCwzNjA5MSwzNjA5MiwzNjA5MywzNjA5NCwzNjA5NSwzNjA5NiwzNjA5NywzNjA5OCwzNjA5OSwzNjEwMCwzNjEwMSwzNjEwMiwzNjEwMywzNjEwNCwzNjEwNSwzNjEwNiwzNjEwNywzNjEwOCwzNjEwOSwyMDMxOSwyMDMxMSwyMDI3NCwyMDI4NSwyMDM0MiwyMDM0MCwyMDM2OSwyMDM2MSwyMDM1NSwyMDM2NywyMDM1MCwyMDM0NywyMDM5NCwyMDM0OCwyMDM5NiwyMDM3MiwyMDQ1NCwyMDQ1NiwyMDQ1OCwyMDQyMSwyMDQ0MiwyMDQ1MSwyMDQ0NCwyMDQzMywyMDQ0NywyMDQ3MiwyMDUyMSwyMDU1NiwyMDQ2NywyMDUyNCwyMDQ5NSwyMDUyNiwyMDUyNSwyMDQ3OCwyMDUwOCwyMDQ5MiwyMDUxNywyMDUyMCwyMDYwNiwyMDU0NywyMDU2NSwyMDU1MiwyMDU1OCwyMDU4OCwyMDYwMywyMDY0NSwyMDY0NywyMDY0OSwyMDY2NiwyMDY5NCwyMDc0MiwyMDcxNywyMDcxNiwyMDcxMCwyMDcxOCwyMDc0MywyMDc0NywyMDE4OSwyNzcwOSwyMDMxMiwyMDMyNSwyMDQzMCw0MDg2NCwyNzcxOCwzMTg2MCwyMDg0NiwyNDA2MSw0MDY0OSwzOTMyMCwyMDg2NSwyMjgwNCwyMTI0MSwyMTI2MSwzNTMzNSwyMTI2NCwyMDk3MSwyMjgwOSwyMDgyMSwyMDEyOCwyMDgyMiwyMDE0NywzNDkyNiwzNDk4MCwyMDE0OSwzMzA0NCwzNTAyNiwzMTEwNCwyMzM0OCwzNDgxOSwzMjY5NiwyMDkwNywyMDkxMywyMDkyNSwyMDkyNCwzNjExMCwzNjExMSwzNjExMiwzNjExMywzNjExNCwzNjExNSwzNjExNiwzNjExNywzNjExOCwzNjExOSwzNjEyMCwzNjEyMSwzNjEyMiwzNjEyMywzNjEyNCwzNjEyOCwzNjE3NywzNjE3OCwzNjE4MywzNjE5MSwzNjE5NywzNjIwMCwzNjIwMSwzNjIwMiwzNjIwNCwzNjIwNiwzNjIwNywzNjIwOSwzNjIxMCwzNjIxNiwzNjIxNywzNjIxOCwzNjIxOSwzNjIyMCwzNjIyMSwzNjIyMiwzNjIyMywzNjIyNCwzNjIyNiwzNjIyNywzNjIzMCwzNjIzMSwzNjIzMiwzNjIzMywzNjIzNiwzNjIzNywzNjIzOCwzNjIzOSwzNjI0MCwzNjI0MiwzNjI0MywzNjI0NSwzNjI0NiwzNjI0NywzNjI0OCwzNjI0OSwzNjI1MCwzNjI1MSwzNjI1MiwzNjI1MywzNjI1NCwzNjI1NiwzNjI1NywzNjI1OCwzNjI2MCwzNjI2MSwzNjI2MiwzNjI2MywzNjI2NCwzNjI2NSwzNjI2NiwzNjI2NywzNjI2OCwzNjI2OSwzNjI3MCwzNjI3MSwzNjI3MiwzNjI3NCwzNjI3OCwzNjI3OSwzNjI4MSwzNjI4MywzNjI4NSwzNjI4OCwzNjI4OSwzNjI5MCwzNjI5MywzNjI5NSwzNjI5NiwzNjI5NywzNjI5OCwzNjMwMSwzNjMwNCwzNjMwNiwzNjMwNywzNjMwOCwyMDkzNSwyMDg4NiwyMDg5OCwyMDkwMSwzNTc0NCwzNTc1MCwzNTc1MSwzNTc1NCwzNTc2NCwzNTc2NSwzNTc2NywzNTc3OCwzNTc3OSwzNTc4NywzNTc5MSwzNTc5MCwzNTc5NCwzNTc5NSwzNTc5NiwzNTc5OCwzNTgwMCwzNTgwMSwzNTgwNCwzNTgwNywzNTgwOCwzNTgxMiwzNTgxNiwzNTgxNywzNTgyMiwzNTgyNCwzNTgyNywzNTgzMCwzNTgzMywzNTgzNiwzNTgzOSwzNTg0MCwzNTg0MiwzNTg0NCwzNTg0NywzNTg1MiwzNTg1NSwzNTg1NywzNTg1OCwzNTg2MCwzNTg2MSwzNTg2MiwzNTg2NSwzNTg2NywzNTg2NCwzNTg2OSwzNTg3MSwzNTg3MiwzNTg3MywzNTg3NywzNTg3OSwzNTg4MiwzNTg4MywzNTg4NiwzNTg4NywzNTg5MCwzNTg5MSwzNTg5MywzNTg5NCwyMTM1MywyMTM3MCwzODQyOSwzODQzNCwzODQzMywzODQ0OSwzODQ0MiwzODQ2MSwzODQ2MCwzODQ2NiwzODQ3MywzODQ4NCwzODQ5NSwzODUwMywzODUwOCwzODUxNCwzODUxNiwzODUzNiwzODU0MSwzODU1MSwzODU3NiwzNzAxNSwzNzAxOSwzNzAyMSwzNzAxNywzNzAzNiwzNzAyNSwzNzA0NCwzNzA0MywzNzA0NiwzNzA1MCwzNjMwOSwzNjMxMiwzNjMxMywzNjMxNiwzNjMyMCwzNjMyMSwzNjMyMiwzNjMyNSwzNjMyNiwzNjMyNywzNjMyOSwzNjMzMywzNjMzNCwzNjMzNiwzNjMzNywzNjMzOCwzNjM0MCwzNjM0MiwzNjM0OCwzNjM1MCwzNjM1MSwzNjM1MiwzNjM1MywzNjM1NCwzNjM1NSwzNjM1NiwzNjM1OCwzNjM1OSwzNjM2MCwzNjM2MywzNjM2NSwzNjM2NiwzNjM2OCwzNjM2OSwzNjM3MCwzNjM3MSwzNjM3MywzNjM3NCwzNjM3NSwzNjM3NiwzNjM3NywzNjM3OCwzNjM3OSwzNjM4MCwzNjM4NCwzNjM4NSwzNjM4OCwzNjM4OSwzNjM5MCwzNjM5MSwzNjM5MiwzNjM5NSwzNjM5NywzNjQwMCwzNjQwMiwzNjQwMywzNjQwNCwzNjQwNiwzNjQwNywzNjQwOCwzNjQxMSwzNjQxMiwzNjQxNCwzNjQxNSwzNjQxOSwzNjQyMSwzNjQyMiwzNjQyOCwzNjQyOSwzNjQzMCwzNjQzMSwzNjQzMiwzNjQzNSwzNjQzNiwzNjQzNywzNjQzOCwzNjQzOSwzNjQ0MCwzNjQ0MiwzNjQ0MywzNjQ0NCwzNjQ0NSwzNjQ0NiwzNjQ0NywzNjQ0OCwzNjQ0OSwzNjQ1MCwzNjQ1MSwzNjQ1MiwzNjQ1MywzNjQ1NSwzNjQ1NiwzNjQ1OCwzNjQ1OSwzNjQ2MiwzNjQ2NSwzNzA0OCwzNzA0MCwzNzA3MSwzNzA2MSwzNzA1NCwzNzA3MiwzNzA2MCwzNzA2MywzNzA3NSwzNzA5NCwzNzA5MCwzNzA4NCwzNzA3OSwzNzA4MywzNzA5OSwzNzEwMywzNzExOCwzNzEyNCwzNzE1NCwzNzE1MCwzNzE1NSwzNzE2OSwzNzE2NywzNzE3NywzNzE4NywzNzE5MCwyMTAwNSwyMjg1MCwyMTE1NCwyMTE2NCwyMTE2NSwyMTE4MiwyMTc1OSwyMTIwMCwyMTIwNiwyMTIzMiwyMTQ3MSwyOTE2NiwzMDY2OSwyNDMwOCwyMDk4MSwyMDk4OCwzOTcyNywyMTQzMCwyNDMyMSwzMDA0MiwyNDA0NywyMjM0OCwyMjQ0MSwyMjQzMywyMjY1NCwyMjcxNiwyMjcyNSwyMjczNywyMjMxMywyMjMxNiwyMjMxNCwyMjMyMywyMjMyOSwyMjMxOCwyMjMxOSwyMjM2NCwyMjMzMSwyMjMzOCwyMjM3NywyMjQwNSwyMjM3OSwyMjQwNiwyMjM5NiwyMjM5NSwyMjM3NiwyMjM4MSwyMjM5MCwyMjM4NywyMjQ0NSwyMjQzNiwyMjQxMiwyMjQ1MCwyMjQ3OSwyMjQzOSwyMjQ1MiwyMjQxOSwyMjQzMiwyMjQ4NSwyMjQ4OCwyMjQ5MCwyMjQ4OSwyMjQ4MiwyMjQ1NiwyMjUxNiwyMjUxMSwyMjUyMCwyMjUwMCwyMjQ5MywzNjQ2NywzNjQ2OSwzNjQ3MSwzNjQ3MiwzNjQ3MywzNjQ3NCwzNjQ3NSwzNjQ3NywzNjQ3OCwzNjQ4MCwzNjQ4MiwzNjQ4MywzNjQ4NCwzNjQ4NiwzNjQ4OCwzNjQ4OSwzNjQ5MCwzNjQ5MSwzNjQ5MiwzNjQ5MywzNjQ5NCwzNjQ5NywzNjQ5OCwzNjQ5OSwzNjUwMSwzNjUwMiwzNjUwMywzNjUwNCwzNjUwNSwzNjUwNiwzNjUwNywzNjUwOSwzNjUxMSwzNjUxMiwzNjUxMywzNjUxNCwzNjUxNSwzNjUxNiwzNjUxNywzNjUxOCwzNjUxOSwzNjUyMCwzNjUyMSwzNjUyMiwzNjUyNSwzNjUyNiwzNjUyOCwzNjUyOSwzNjUzMSwzNjUzMiwzNjUzMywzNjUzNCwzNjUzNSwzNjUzNiwzNjUzNywzNjUzOSwzNjU0MCwzNjU0MSwzNjU0MiwzNjU0MywzNjU0NCwzNjU0NSwzNjU0NiwzNjU0NywzNjU0OCwzNjU0OSwzNjU1MCwzNjU1MSwzNjU1MiwzNjU1MywzNjU1NCwzNjU1NSwzNjU1NiwzNjU1NywzNjU1OSwzNjU2MCwzNjU2MSwzNjU2MiwzNjU2MywzNjU2NCwzNjU2NSwzNjU2NiwzNjU2NywzNjU2OCwzNjU2OSwzNjU3MCwzNjU3MSwzNjU3MiwzNjU3MywzNjU3NCwzNjU3NSwzNjU3NiwzNjU3NywzNjU3OCwzNjU3OSwzNjU4MCwyMjUzOSwyMjU0MSwyMjUyNSwyMjUwOSwyMjUyOCwyMjU1OCwyMjU1MywyMjU5NiwyMjU2MCwyMjYyOSwyMjYzNiwyMjY1NywyMjY2NSwyMjY4MiwyMjY1NiwzOTMzNiw0MDcyOSwyNTA4NywzMzQwMSwzMzQwNSwzMzQwNywzMzQyMywzMzQxOCwzMzQ0OCwzMzQxMiwzMzQyMiwzMzQyNSwzMzQzMSwzMzQzMywzMzQ1MSwzMzQ2NCwzMzQ3MCwzMzQ1NiwzMzQ4MCwzMzQ4MiwzMzUwNywzMzQzMiwzMzQ2MywzMzQ1NCwzMzQ4MywzMzQ4NCwzMzQ3MywzMzQ0OSwzMzQ2MCwzMzQ0MSwzMzQ1MCwzMzQzOSwzMzQ3NiwzMzQ4NiwzMzQ0NCwzMzUwNSwzMzU0NSwzMzUyNywzMzUwOCwzMzU1MSwzMzU0MywzMzUwMCwzMzUyNCwzMzQ5MCwzMzQ5NiwzMzU0OCwzMzUzMSwzMzQ5MSwzMzU1MywzMzU2MiwzMzU0MiwzMzU1NiwzMzU1NywzMzUwNCwzMzQ5MywzMzU2NCwzMzYxNywzMzYyNywzMzYyOCwzMzU0NCwzMzY4MiwzMzU5NiwzMzU4OCwzMzU4NSwzMzY5MSwzMzYzMCwzMzU4MywzMzYxNSwzMzYwNywzMzYwMywzMzYzMSwzMzYwMCwzMzU1OSwzMzYzMiwzMzU4MSwzMzU5NCwzMzU4NywzMzYzOCwzMzYzNywzNjU4MSwzNjU4MiwzNjU4MywzNjU4NCwzNjU4NSwzNjU4NiwzNjU4NywzNjU4OCwzNjU4OSwzNjU5MCwzNjU5MSwzNjU5MiwzNjU5MywzNjU5NCwzNjU5NSwzNjU5NiwzNjU5NywzNjU5OCwzNjU5OSwzNjYwMCwzNjYwMSwzNjYwMiwzNjYwMywzNjYwNCwzNjYwNSwzNjYwNiwzNjYwNywzNjYwOCwzNjYwOSwzNjYxMCwzNjYxMSwzNjYxMiwzNjYxMywzNjYxNCwzNjYxNSwzNjYxNiwzNjYxNywzNjYxOCwzNjYxOSwzNjYyMCwzNjYyMSwzNjYyMiwzNjYyMywzNjYyNCwzNjYyNSwzNjYyNiwzNjYyNywzNjYyOCwzNjYyOSwzNjYzMCwzNjYzMSwzNjYzMiwzNjYzMywzNjYzNCwzNjYzNSwzNjYzNiwzNjYzNywzNjYzOCwzNjYzOSwzNjY0MCwzNjY0MSwzNjY0MiwzNjY0MywzNjY0NCwzNjY0NSwzNjY0NiwzNjY0NywzNjY0OCwzNjY0OSwzNjY1MCwzNjY1MSwzNjY1MiwzNjY1MywzNjY1NCwzNjY1NSwzNjY1NiwzNjY1NywzNjY1OCwzNjY1OSwzNjY2MCwzNjY2MSwzNjY2MiwzNjY2MywzNjY2NCwzNjY2NSwzNjY2NiwzNjY2NywzNjY2OCwzNjY2OSwzNjY3MCwzNjY3MSwzNjY3MiwzNjY3MywzNjY3NCwzNjY3NSwzNjY3NiwzMzY0MCwzMzU2MywzMzY0MSwzMzY0NCwzMzY0MiwzMzY0NSwzMzY0NiwzMzcxMiwzMzY1NiwzMzcxNSwzMzcxNiwzMzY5NiwzMzcwNiwzMzY4MywzMzY5MiwzMzY2OSwzMzY2MCwzMzcxOCwzMzcwNSwzMzY2MSwzMzcyMCwzMzY1OSwzMzY4OCwzMzY5NCwzMzcwNCwzMzcyMiwzMzcyNCwzMzcyOSwzMzc5MywzMzc2NSwzMzc1MiwyMjUzNSwzMzgxNiwzMzgwMywzMzc1NywzMzc4OSwzMzc1MCwzMzgyMCwzMzg0OCwzMzgwOSwzMzc5OCwzMzc0OCwzMzc1OSwzMzgwNywzMzc5NSwzMzc4NCwzMzc4NSwzMzc3MCwzMzczMywzMzcyOCwzMzgzMCwzMzc3NiwzMzc2MSwzMzg4NCwzMzg3MywzMzg4MiwzMzg4MSwzMzkwNywzMzkyNywzMzkyOCwzMzkxNCwzMzkyOSwzMzkxMiwzMzg1MiwzMzg2MiwzMzg5NywzMzkxMCwzMzkzMiwzMzkzNCwzMzg0MSwzMzkwMSwzMzk4NSwzMzk5NywzNDAwMCwzNDAyMiwzMzk4MSwzNDAwMywzMzk5NCwzMzk4MywzMzk3OCwzNDAxNiwzMzk1MywzMzk3NywzMzk3MiwzMzk0MywzNDAyMSwzNDAxOSwzNDA2MCwyOTk2NSwzNDEwNCwzNDAzMiwzNDEwNSwzNDA3OSwzNDEwNiwzNjY3NywzNjY3OCwzNjY3OSwzNjY4MCwzNjY4MSwzNjY4MiwzNjY4MywzNjY4NCwzNjY4NSwzNjY4NiwzNjY4NywzNjY4OCwzNjY4OSwzNjY5MCwzNjY5MSwzNjY5MiwzNjY5MywzNjY5NCwzNjY5NSwzNjY5NiwzNjY5NywzNjY5OCwzNjY5OSwzNjcwMCwzNjcwMSwzNjcwMiwzNjcwMywzNjcwNCwzNjcwNSwzNjcwNiwzNjcwNywzNjcwOCwzNjcwOSwzNjcxNCwzNjczNiwzNjc0OCwzNjc1NCwzNjc2NSwzNjc2OCwzNjc2OSwzNjc3MCwzNjc3MiwzNjc3MywzNjc3NCwzNjc3NSwzNjc3OCwzNjc4MCwzNjc4MSwzNjc4MiwzNjc4MywzNjc4NiwzNjc4NywzNjc4OCwzNjc4OSwzNjc5MSwzNjc5MiwzNjc5NCwzNjc5NSwzNjc5NiwzNjc5OSwzNjgwMCwzNjgwMywzNjgwNiwzNjgwOSwzNjgxMCwzNjgxMSwzNjgxMiwzNjgxMywzNjgxNSwzNjgxOCwzNjgyMiwzNjgyMywzNjgyNiwzNjgzMiwzNjgzMywzNjgzNSwzNjgzOSwzNjg0NCwzNjg0NywzNjg0OSwzNjg1MCwzNjg1MiwzNjg1MywzNjg1NCwzNjg1OCwzNjg1OSwzNjg2MCwzNjg2MiwzNjg2MywzNjg3MSwzNjg3MiwzNjg3NiwzNjg3OCwzNjg4MywzNjg4NSwzNjg4OCwzNDEzNCwzNDEwNywzNDA0NywzNDA0NCwzNDEzNywzNDEyMCwzNDE1MiwzNDE0OCwzNDE0MiwzNDE3MCwzMDYyNiwzNDExNSwzNDE2MiwzNDE3MSwzNDIxMiwzNDIxNiwzNDE4MywzNDE5MSwzNDE2OSwzNDIyMiwzNDIwNCwzNDE4MSwzNDIzMywzNDIzMSwzNDIyNCwzNDI1OSwzNDI0MSwzNDI2OCwzNDMwMywzNDM0MywzNDMwOSwzNDM0NSwzNDMyNiwzNDM2NCwyNDMxOCwyNDMyOCwyMjg0NCwyMjg0OSwzMjgyMywyMjg2OSwyMjg3NCwyMjg3MiwyMTI2MywyMzU4NiwyMzU4OSwyMzU5NiwyMzYwNCwyNTE2NCwyNTE5NCwyNTI0NywyNTI3NSwyNTI5MCwyNTMwNiwyNTMwMywyNTMyNiwyNTM3OCwyNTMzNCwyNTQwMSwyNTQxOSwyNTQxMSwyNTUxNywyNTU5MCwyNTQ1NywyNTQ2NiwyNTQ4NiwyNTUyNCwyNTQ1MywyNTUxNiwyNTQ4MiwyNTQ0OSwyNTUxOCwyNTUzMiwyNTU4NiwyNTU5MiwyNTU2OCwyNTU5OSwyNTU0MCwyNTU2NiwyNTU1MCwyNTY4MiwyNTU0MiwyNTUzNCwyNTY2OSwyNTY2NSwyNTYxMSwyNTYyNywyNTYzMiwyNTYxMiwyNTYzOCwyNTYzMywyNTY5NCwyNTczMiwyNTcwOSwyNTc1MCwzNjg4OSwzNjg5MiwzNjg5OSwzNjkwMCwzNjkwMSwzNjkwMywzNjkwNCwzNjkwNSwzNjkwNiwzNjkwNywzNjkwOCwzNjkxMiwzNjkxMywzNjkxNCwzNjkxNSwzNjkxNiwzNjkxOSwzNjkyMSwzNjkyMiwzNjkyNSwzNjkyNywzNjkyOCwzNjkzMSwzNjkzMywzNjkzNCwzNjkzNiwzNjkzNywzNjkzOCwzNjkzOSwzNjk0MCwzNjk0MiwzNjk0OCwzNjk0OSwzNjk1MCwzNjk1MywzNjk1NCwzNjk1NiwzNjk1NywzNjk1OCwzNjk1OSwzNjk2MCwzNjk2MSwzNjk2NCwzNjk2NiwzNjk2NywzNjk2OSwzNjk3MCwzNjk3MSwzNjk3MiwzNjk3NSwzNjk3NiwzNjk3NywzNjk3OCwzNjk3OSwzNjk4MiwzNjk4MywzNjk4NCwzNjk4NSwzNjk4NiwzNjk4NywzNjk4OCwzNjk5MCwzNjk5MywzNjk5NiwzNjk5NywzNjk5OCwzNjk5OSwzNzAwMSwzNzAwMiwzNzAwNCwzNzAwNSwzNzAwNiwzNzAwNywzNzAwOCwzNzAxMCwzNzAxMiwzNzAxNCwzNzAxNiwzNzAxOCwzNzAyMCwzNzAyMiwzNzAyMywzNzAyNCwzNzAyOCwzNzAyOSwzNzAzMSwzNzAzMiwzNzAzMywzNzAzNSwzNzAzNywzNzA0MiwzNzA0NywzNzA1MiwzNzA1MywzNzA1NSwzNzA1NiwyNTcyMiwyNTc4MywyNTc4NCwyNTc1MywyNTc4NiwyNTc5MiwyNTgwOCwyNTgxNSwyNTgyOCwyNTgyNiwyNTg2NSwyNTg5MywyNTkwMiwyNDMzMSwyNDUzMCwyOTk3NywyNDMzNywyMTM0MywyMTQ4OSwyMTUwMSwyMTQ4MSwyMTQ4MCwyMTQ5OSwyMTUyMiwyMTUyNiwyMTUxMCwyMTU3OSwyMTU4NiwyMTU4NywyMTU4OCwyMTU5MCwyMTU3MSwyMTUzNywyMTU5MSwyMTU5MywyMTUzOSwyMTU1NCwyMTYzNCwyMTY1MiwyMTYyMywyMTYxNywyMTYwNCwyMTY1OCwyMTY1OSwyMTYzNiwyMTYyMiwyMTYwNiwyMTY2MSwyMTcxMiwyMTY3NywyMTY5OCwyMTY4NCwyMTcxNCwyMTY3MSwyMTY3MCwyMTcxNSwyMTcxNiwyMTYxOCwyMTY2NywyMTcxNywyMTY5MSwyMTY5NSwyMTcwOCwyMTcyMSwyMTcyMiwyMTcyNCwyMTY3MywyMTY3NCwyMTY2OCwyMTcyNSwyMTcxMSwyMTcyNiwyMTc4NywyMTczNSwyMTc5MiwyMTc1NywyMTc4MCwyMTc0NywyMTc5NCwyMTc5NSwyMTc3NSwyMTc3NywyMTc5OSwyMTgwMiwyMTg2MywyMTkwMywyMTk0MSwyMTgzMywyMTg2OSwyMTgyNSwyMTg0NSwyMTgyMywyMTg0MCwyMTgyMCwzNzA1OCwzNzA1OSwzNzA2MiwzNzA2NCwzNzA2NSwzNzA2NywzNzA2OCwzNzA2OSwzNzA3NCwzNzA3NiwzNzA3NywzNzA3OCwzNzA4MCwzNzA4MSwzNzA4MiwzNzA4NiwzNzA4NywzNzA4OCwzNzA5MSwzNzA5MiwzNzA5MywzNzA5NywzNzA5OCwzNzEwMCwzNzEwMiwzNzEwNCwzNzEwNSwzNzEwNiwzNzEwNywzNzEwOSwzNzExMCwzNzExMSwzNzExMywzNzExNCwzNzExNSwzNzExNiwzNzExOSwzNzEyMCwzNzEyMSwzNzEyMywzNzEyNSwzNzEyNiwzNzEyNywzNzEyOCwzNzEyOSwzNzEzMCwzNzEzMSwzNzEzMiwzNzEzMywzNzEzNCwzNzEzNSwzNzEzNiwzNzEzNywzNzEzOCwzNzEzOSwzNzE0MCwzNzE0MSwzNzE0MiwzNzE0MywzNzE0NCwzNzE0NiwzNzE0NywzNzE0OCwzNzE0OSwzNzE1MSwzNzE1MiwzNzE1MywzNzE1NiwzNzE1NywzNzE1OCwzNzE1OSwzNzE2MCwzNzE2MSwzNzE2MiwzNzE2MywzNzE2NCwzNzE2NSwzNzE2NiwzNzE2OCwzNzE3MCwzNzE3MSwzNzE3MiwzNzE3MywzNzE3NCwzNzE3NSwzNzE3NiwzNzE3OCwzNzE3OSwzNzE4MCwzNzE4MSwzNzE4MiwzNzE4MywzNzE4NCwzNzE4NSwzNzE4NiwzNzE4OCwyMTgxNSwyMTg0NiwyMTg3NywyMTg3OCwyMTg3OSwyMTgxMSwyMTgwOCwyMTg1MiwyMTg5OSwyMTk3MCwyMTg5MSwyMTkzNywyMTk0NSwyMTg5NiwyMTg4OSwyMTkxOSwyMTg4NiwyMTk3NCwyMTkwNSwyMTg4MywyMTk4MywyMTk0OSwyMTk1MCwyMTkwOCwyMTkxMywyMTk5NCwyMjAwNywyMTk2MSwyMjA0NywyMTk2OSwyMTk5NSwyMTk5NiwyMTk3MiwyMTk5MCwyMTk4MSwyMTk1NiwyMTk5OSwyMTk4OSwyMjAwMiwyMjAwMywyMTk2NCwyMTk2NSwyMTk5MiwyMjAwNSwyMTk4OCwzNjc1NiwyMjA0NiwyMjAyNCwyMjAyOCwyMjAxNywyMjA1MiwyMjA1MSwyMjAxNCwyMjAxNiwyMjA1NSwyMjA2MSwyMjEwNCwyMjA3MywyMjEwMywyMjA2MCwyMjA5MywyMjExNCwyMjEwNSwyMjEwOCwyMjA5MiwyMjEwMCwyMjE1MCwyMjExNiwyMjEyOSwyMjEyMywyMjEzOSwyMjE0MCwyMjE0OSwyMjE2MywyMjE5MSwyMjIyOCwyMjIzMSwyMjIzNywyMjI0MSwyMjI2MSwyMjI1MSwyMjI2NSwyMjI3MSwyMjI3NiwyMjI4MiwyMjI4MSwyMjMwMCwyNDA3OSwyNDA4OSwyNDA4NCwyNDA4MSwyNDExMywyNDEyMywyNDEyNCwzNzE4OSwzNzE5MSwzNzE5MiwzNzIwMSwzNzIwMywzNzIwNCwzNzIwNSwzNzIwNiwzNzIwOCwzNzIwOSwzNzIxMSwzNzIxMiwzNzIxNSwzNzIxNiwzNzIyMiwzNzIyMywzNzIyNCwzNzIyNywzNzIyOSwzNzIzNSwzNzI0MiwzNzI0MywzNzI0NCwzNzI0OCwzNzI0OSwzNzI1MCwzNzI1MSwzNzI1MiwzNzI1NCwzNzI1NiwzNzI1OCwzNzI2MiwzNzI2MywzNzI2NywzNzI2OCwzNzI2OSwzNzI3MCwzNzI3MSwzNzI3MiwzNzI3MywzNzI3NiwzNzI3NywzNzI3OCwzNzI3OSwzNzI4MCwzNzI4MSwzNzI4NCwzNzI4NSwzNzI4NiwzNzI4NywzNzI4OCwzNzI4OSwzNzI5MSwzNzI5MiwzNzI5NiwzNzI5NywzNzI5OCwzNzI5OSwzNzMwMiwzNzMwMywzNzMwNCwzNzMwNSwzNzMwNywzNzMwOCwzNzMwOSwzNzMxMCwzNzMxMSwzNzMxMiwzNzMxMywzNzMxNCwzNzMxNSwzNzMxNiwzNzMxNywzNzMxOCwzNzMyMCwzNzMyMywzNzMyOCwzNzMzMCwzNzMzMSwzNzMzMiwzNzMzMywzNzMzNCwzNzMzNSwzNzMzNiwzNzMzNywzNzMzOCwzNzMzOSwzNzM0MSwzNzM0MiwzNzM0MywzNzM0NCwzNzM0NSwzNzM0NiwzNzM0NywzNzM0OCwzNzM0OSwyNDExOSwyNDEzMiwyNDE0OCwyNDE1NSwyNDE1OCwyNDE2MSwyMzY5MiwyMzY3NCwyMzY5MywyMzY5NiwyMzcwMiwyMzY4OCwyMzcwNCwyMzcwNSwyMzY5NywyMzcwNiwyMzcwOCwyMzczMywyMzcxNCwyMzc0MSwyMzcyNCwyMzcyMywyMzcyOSwyMzcxNSwyMzc0NSwyMzczNSwyMzc0OCwyMzc2MiwyMzc4MCwyMzc1NSwyMzc4MSwyMzgxMCwyMzgxMSwyMzg0NywyMzg0NiwyMzg1NCwyMzg0NCwyMzgzOCwyMzgxNCwyMzgzNSwyMzg5NiwyMzg3MCwyMzg2MCwyMzg2OSwyMzkxNiwyMzg5OSwyMzkxOSwyMzkwMSwyMzkxNSwyMzg4MywyMzg4MiwyMzkxMywyMzkyNCwyMzkzOCwyMzk2MSwyMzk2NSwzNTk1NSwyMzk5MSwyNDAwNSwyNDQzNSwyNDQzOSwyNDQ1MCwyNDQ1NSwyNDQ1NywyNDQ2MCwyNDQ2OSwyNDQ3MywyNDQ3NiwyNDQ4OCwyNDQ5MywyNDUwMSwyNDUwOCwzNDkxNCwyNDQxNywyOTM1NywyOTM2MCwyOTM2NCwyOTM2NywyOTM2OCwyOTM3OSwyOTM3NywyOTM5MCwyOTM4OSwyOTM5NCwyOTQxNiwyOTQyMywyOTQxNywyOTQyNiwyOTQyOCwyOTQzMSwyOTQ0MSwyOTQyNywyOTQ0MywyOTQzNCwzNzM1MCwzNzM1MSwzNzM1MiwzNzM1MywzNzM1NCwzNzM1NSwzNzM1NiwzNzM1NywzNzM1OCwzNzM1OSwzNzM2MCwzNzM2MSwzNzM2MiwzNzM2MywzNzM2NCwzNzM2NSwzNzM2NiwzNzM2NywzNzM2OCwzNzM2OSwzNzM3MCwzNzM3MSwzNzM3MiwzNzM3MywzNzM3NCwzNzM3NSwzNzM3NiwzNzM3NywzNzM3OCwzNzM3OSwzNzM4MCwzNzM4MSwzNzM4MiwzNzM4MywzNzM4NCwzNzM4NSwzNzM4NiwzNzM4NywzNzM4OCwzNzM4OSwzNzM5MCwzNzM5MSwzNzM5MiwzNzM5MywzNzM5NCwzNzM5NSwzNzM5NiwzNzM5NywzNzM5OCwzNzM5OSwzNzQwMCwzNzQwMSwzNzQwMiwzNzQwMywzNzQwNCwzNzQwNSwzNzQwNiwzNzQwNywzNzQwOCwzNzQwOSwzNzQxMCwzNzQxMSwzNzQxMiwzNzQxMywzNzQxNCwzNzQxNSwzNzQxNiwzNzQxNywzNzQxOCwzNzQxOSwzNzQyMCwzNzQyMSwzNzQyMiwzNzQyMywzNzQyNCwzNzQyNSwzNzQyNiwzNzQyNywzNzQyOCwzNzQyOSwzNzQzMCwzNzQzMSwzNzQzMiwzNzQzMywzNzQzNCwzNzQzNSwzNzQzNiwzNzQzNywzNzQzOCwzNzQzOSwzNzQ0MCwzNzQ0MSwzNzQ0MiwzNzQ0MywzNzQ0NCwzNzQ0NSwyOTQzNSwyOTQ2MywyOTQ1OSwyOTQ3MywyOTQ1MCwyOTQ3MCwyOTQ2OSwyOTQ2MSwyOTQ3NCwyOTQ5NywyOTQ3NywyOTQ4NCwyOTQ5NiwyOTQ4OSwyOTUyMCwyOTUxNywyOTUyNywyOTUzNiwyOTU0OCwyOTU1MSwyOTU2NiwzMzMwNywyMjgyMSwzOTE0MywyMjgyMCwyMjc4NiwzOTI2NywzOTI3MSwzOTI3MiwzOTI3MywzOTI3NCwzOTI3NSwzOTI3NiwzOTI4NCwzOTI4NywzOTI5MywzOTI5NiwzOTMwMCwzOTMwMywzOTMwNiwzOTMwOSwzOTMxMiwzOTMxMywzOTMxNSwzOTMxNiwzOTMxNywyNDE5MiwyNDIwOSwyNDIwMywyNDIxNCwyNDIyOSwyNDIyNCwyNDI0OSwyNDI0NSwyNDI1NCwyNDI0MywzNjE3OSwyNDI3NCwyNDI3MywyNDI4MywyNDI5NiwyNDI5OCwzMzIxMCwyNDUxNiwyNDUyMSwyNDUzNCwyNDUyNywyNDU3OSwyNDU1OCwyNDU4MCwyNDU0NSwyNDU0OCwyNDU3NCwyNDU4MSwyNDU4MiwyNDU1NCwyNDU1NywyNDU2OCwyNDYwMSwyNDYyOSwyNDYxNCwyNDYwMywyNDU5MSwyNDU4OSwyNDYxNywyNDYxOSwyNDU4NiwyNDYzOSwyNDYwOSwyNDY5NiwyNDY5NywyNDY5OSwyNDY5OCwyNDY0MiwzNzQ0NiwzNzQ0NywzNzQ0OCwzNzQ0OSwzNzQ1MCwzNzQ1MSwzNzQ1MiwzNzQ1MywzNzQ1NCwzNzQ1NSwzNzQ1NiwzNzQ1NywzNzQ1OCwzNzQ1OSwzNzQ2MCwzNzQ2MSwzNzQ2MiwzNzQ2MywzNzQ2NCwzNzQ2NSwzNzQ2NiwzNzQ2NywzNzQ2OCwzNzQ2OSwzNzQ3MCwzNzQ3MSwzNzQ3MiwzNzQ3MywzNzQ3NCwzNzQ3NSwzNzQ3NiwzNzQ3NywzNzQ3OCwzNzQ3OSwzNzQ4MCwzNzQ4MSwzNzQ4MiwzNzQ4MywzNzQ4NCwzNzQ4NSwzNzQ4NiwzNzQ4NywzNzQ4OCwzNzQ4OSwzNzQ5MCwzNzQ5MSwzNzQ5MywzNzQ5NCwzNzQ5NSwzNzQ5NiwzNzQ5NywzNzQ5OCwzNzQ5OSwzNzUwMCwzNzUwMSwzNzUwMiwzNzUwMywzNzUwNCwzNzUwNSwzNzUwNiwzNzUwNywzNzUwOCwzNzUwOSwzNzUxMCwzNzUxMSwzNzUxMiwzNzUxMywzNzUxNCwzNzUxNSwzNzUxNiwzNzUxNywzNzUxOSwzNzUyMCwzNzUyMSwzNzUyMiwzNzUyMywzNzUyNCwzNzUyNSwzNzUyNiwzNzUyNywzNzUyOCwzNzUyOSwzNzUzMCwzNzUzMSwzNzUzMiwzNzUzMywzNzUzNCwzNzUzNSwzNzUzNiwzNzUzNywzNzUzOCwzNzUzOSwzNzU0MCwzNzU0MSwzNzU0MiwzNzU0MywyNDY4MiwyNDcwMSwyNDcyNiwyNDczMCwyNDc0OSwyNDczMywyNDcwNywyNDcyMiwyNDcxNiwyNDczMSwyNDgxMiwyNDc2MywyNDc1MywyNDc5NywyNDc5MiwyNDc3NCwyNDc5NCwyNDc1NiwyNDg2NCwyNDg3MCwyNDg1MywyNDg2NywyNDgyMCwyNDgzMiwyNDg0NiwyNDg3NSwyNDkwNiwyNDk0OSwyNTAwNCwyNDk4MCwyNDk5OSwyNTAxNSwyNTA0NCwyNTA3NywyNDU0MSwzODU3OSwzODM3NywzODM3OSwzODM4NSwzODM4NywzODM4OSwzODM5MCwzODM5NiwzODM5OCwzODQwMywzODQwNCwzODQwNiwzODQwOCwzODQxMCwzODQxMSwzODQxMiwzODQxMywzODQxNSwzODQxOCwzODQyMSwzODQyMiwzODQyMywzODQyNSwzODQyNiwyMDAxMiwyOTI0NywyNTEwOSwyNzcwMSwyNzczMiwyNzc0MCwyNzcyMiwyNzgxMSwyNzc4MSwyNzc5MiwyNzc5NiwyNzc4OCwyNzc1MiwyNzc1MywyNzc2NCwyNzc2NiwyNzc4MiwyNzgxNywyNzg1NiwyNzg2MCwyNzgyMSwyNzg5NSwyNzg5NiwyNzg4OSwyNzg2MywyNzgyNiwyNzg3MiwyNzg2MiwyNzg5OCwyNzg4MywyNzg4NiwyNzgyNSwyNzg1OSwyNzg4NywyNzkwMiwzNzU0NCwzNzU0NSwzNzU0NiwzNzU0NywzNzU0OCwzNzU0OSwzNzU1MSwzNzU1MiwzNzU1MywzNzU1NCwzNzU1NSwzNzU1NiwzNzU1NywzNzU1OCwzNzU1OSwzNzU2MCwzNzU2MSwzNzU2MiwzNzU2MywzNzU2NCwzNzU2NSwzNzU2NiwzNzU2NywzNzU2OCwzNzU2OSwzNzU3MCwzNzU3MSwzNzU3MiwzNzU3MywzNzU3NCwzNzU3NSwzNzU3NywzNzU3OCwzNzU3OSwzNzU4MCwzNzU4MSwzNzU4MiwzNzU4MywzNzU4NCwzNzU4NSwzNzU4NiwzNzU4NywzNzU4OCwzNzU4OSwzNzU5MCwzNzU5MSwzNzU5MiwzNzU5MywzNzU5NCwzNzU5NSwzNzU5NiwzNzU5NywzNzU5OCwzNzU5OSwzNzYwMCwzNzYwMSwzNzYwMiwzNzYwMywzNzYwNCwzNzYwNSwzNzYwNiwzNzYwNywzNzYwOCwzNzYwOSwzNzYxMCwzNzYxMSwzNzYxMiwzNzYxMywzNzYxNCwzNzYxNSwzNzYxNiwzNzYxNywzNzYxOCwzNzYxOSwzNzYyMCwzNzYyMSwzNzYyMiwzNzYyMywzNzYyNCwzNzYyNSwzNzYyNiwzNzYyNywzNzYyOCwzNzYyOSwzNzYzMCwzNzYzMSwzNzYzMiwzNzYzMywzNzYzNCwzNzYzNSwzNzYzNiwzNzYzNywzNzYzOCwzNzYzOSwzNzY0MCwzNzY0MSwyNzk2MSwyNzk0MywyNzkxNiwyNzk3MSwyNzk3NiwyNzkxMSwyNzkwOCwyNzkyOSwyNzkxOCwyNzk0NywyNzk4MSwyNzk1MCwyNzk1NywyNzkzMCwyNzk4MywyNzk4NiwyNzk4OCwyNzk1NSwyODA0OSwyODAxNSwyODA2MiwyODA2NCwyNzk5OCwyODA1MSwyODA1MiwyNzk5NiwyODAwMCwyODAyOCwyODAwMywyODE4NiwyODEwMywyODEwMSwyODEyNiwyODE3NCwyODA5NSwyODEyOCwyODE3NywyODEzNCwyODEyNSwyODEyMSwyODE4MiwyODA3NSwyODE3MiwyODA3OCwyODIwMywyODI3MCwyODIzOCwyODI2NywyODMzOCwyODI1NSwyODI5NCwyODI0MywyODI0NCwyODIxMCwyODE5NywyODIyOCwyODM4MywyODMzNywyODMxMiwyODM4NCwyODQ2MSwyODM4NiwyODMyNSwyODMyNywyODM0OSwyODM0NywyODM0MywyODM3NSwyODM0MCwyODM2NywyODMwMywyODM1NCwyODMxOSwyODUxNCwyODQ4NiwyODQ4NywyODQ1MiwyODQzNywyODQwOSwyODQ2MywyODQ3MCwyODQ5MSwyODUzMiwyODQ1OCwyODQyNSwyODQ1NywyODU1MywyODU1NywyODU1NiwyODUzNiwyODUzMCwyODU0MCwyODUzOCwyODYyNSwzNzY0MiwzNzY0MywzNzY0NCwzNzY0NSwzNzY0NiwzNzY0NywzNzY0OCwzNzY0OSwzNzY1MCwzNzY1MSwzNzY1MiwzNzY1MywzNzY1NCwzNzY1NSwzNzY1NiwzNzY1NywzNzY1OCwzNzY1OSwzNzY2MCwzNzY2MSwzNzY2MiwzNzY2MywzNzY2NCwzNzY2NSwzNzY2NiwzNzY2NywzNzY2OCwzNzY2OSwzNzY3MCwzNzY3MSwzNzY3MiwzNzY3MywzNzY3NCwzNzY3NSwzNzY3NiwzNzY3NywzNzY3OCwzNzY3OSwzNzY4MCwzNzY4MSwzNzY4MiwzNzY4MywzNzY4NCwzNzY4NSwzNzY4NiwzNzY4NywzNzY4OCwzNzY4OSwzNzY5MCwzNzY5MSwzNzY5MiwzNzY5MywzNzY5NSwzNzY5NiwzNzY5NywzNzY5OCwzNzY5OSwzNzcwMCwzNzcwMSwzNzcwMiwzNzcwMywzNzcwNCwzNzcwNSwzNzcwNiwzNzcwNywzNzcwOCwzNzcwOSwzNzcxMCwzNzcxMSwzNzcxMiwzNzcxMywzNzcxNCwzNzcxNSwzNzcxNiwzNzcxNywzNzcxOCwzNzcxOSwzNzcyMCwzNzcyMSwzNzcyMiwzNzcyMywzNzcyNCwzNzcyNSwzNzcyNiwzNzcyNywzNzcyOCwzNzcyOSwzNzczMCwzNzczMSwzNzczMiwzNzczMywzNzczNCwzNzczNSwzNzczNiwzNzczNywzNzczOSwyODYxNywyODU4MywyODYwMSwyODU5OCwyODYxMCwyODY0MSwyODY1NCwyODYzOCwyODY0MCwyODY1NSwyODY5OCwyODcwNywyODY5OSwyODcyOSwyODcyNSwyODc1MSwyODc2NiwyMzQyNCwyMzQyOCwyMzQ0NSwyMzQ0MywyMzQ2MSwyMzQ4MCwyOTk5OSwzOTU4MiwyNTY1MiwyMzUyNCwyMzUzNCwzNTEyMCwyMzUzNiwzNjQyMywzNTU5MSwzNjc5MCwzNjgxOSwzNjgyMSwzNjgzNywzNjg0NiwzNjgzNiwzNjg0MSwzNjgzOCwzNjg1MSwzNjg0MCwzNjg2OSwzNjg2OCwzNjg3NSwzNjkwMiwzNjg4MSwzNjg3NywzNjg4NiwzNjg5NywzNjkxNywzNjkxOCwzNjkwOSwzNjkxMSwzNjkzMiwzNjk0NSwzNjk0NiwzNjk0NCwzNjk2OCwzNjk1MiwzNjk2MiwzNjk1NSwyNjI5NywzNjk4MCwzNjk4OSwzNjk5NCwzNzAwMCwzNjk5NSwzNzAwMywyNDQwMCwyNDQwNywyNDQwNiwyNDQwOCwyMzYxMSwyMTY3NSwyMzYzMiwyMzY0MSwyMzQwOSwyMzY1MSwyMzY1NCwzMjcwMCwyNDM2MiwyNDM2MSwyNDM2NSwzMzM5NiwyNDM4MCwzOTczOSwyMzY2MiwyMjkxMywyMjkxNSwyMjkyNSwyMjk1MywyMjk1NCwyMjk0NywzNzc0MCwzNzc0MSwzNzc0MiwzNzc0MywzNzc0NCwzNzc0NSwzNzc0NiwzNzc0NywzNzc0OCwzNzc0OSwzNzc1MCwzNzc1MSwzNzc1MiwzNzc1MywzNzc1NCwzNzc1NSwzNzc1NiwzNzc1NywzNzc1OCwzNzc1OSwzNzc2MCwzNzc2MSwzNzc2MiwzNzc2MywzNzc2NCwzNzc2NSwzNzc2NiwzNzc2NywzNzc2OCwzNzc2OSwzNzc3MCwzNzc3MSwzNzc3MiwzNzc3MywzNzc3NCwzNzc3NiwzNzc3NywzNzc3OCwzNzc3OSwzNzc4MCwzNzc4MSwzNzc4MiwzNzc4MywzNzc4NCwzNzc4NSwzNzc4NiwzNzc4NywzNzc4OCwzNzc4OSwzNzc5MCwzNzc5MSwzNzc5MiwzNzc5MywzNzc5NCwzNzc5NSwzNzc5NiwzNzc5NywzNzc5OCwzNzc5OSwzNzgwMCwzNzgwMSwzNzgwMiwzNzgwMywzNzgwNCwzNzgwNSwzNzgwNiwzNzgwNywzNzgwOCwzNzgwOSwzNzgxMCwzNzgxMSwzNzgxMiwzNzgxMywzNzgxNCwzNzgxNSwzNzgxNiwzNzgxNywzNzgxOCwzNzgxOSwzNzgyMCwzNzgyMSwzNzgyMiwzNzgyMywzNzgyNCwzNzgyNSwzNzgyNiwzNzgyNywzNzgyOCwzNzgyOSwzNzgzMCwzNzgzMSwzNzgzMiwzNzgzMywzNzgzNSwzNzgzNiwzNzgzNywyMjkzNSwyMjk4NiwyMjk1NSwyMjk0MiwyMjk0OCwyMjk5NCwyMjk2MiwyMjk1OSwyMjk5OSwyMjk3NCwyMzA0NSwyMzA0NiwyMzAwNSwyMzA0OCwyMzAxMSwyMzAwMCwyMzAzMywyMzA1MiwyMzA0OSwyMzA5MCwyMzA5MiwyMzA1NywyMzA3NSwyMzA1OSwyMzEwNCwyMzE0MywyMzExNCwyMzEyNSwyMzEwMCwyMzEzOCwyMzE1NywzMzAwNCwyMzIxMCwyMzE5NSwyMzE1OSwyMzE2MiwyMzIzMCwyMzI3NSwyMzIxOCwyMzI1MCwyMzI1MiwyMzIyNCwyMzI2NCwyMzI2NywyMzI4MSwyMzI1NCwyMzI3MCwyMzI1NiwyMzI2MCwyMzMwNSwyMzMxOSwyMzMxOCwyMzM0NiwyMzM1MSwyMzM2MCwyMzU3MywyMzU4MCwyMzM4NiwyMzM5NywyMzQxMSwyMzM3NywyMzM3OSwyMzM5NCwzOTU0MSwzOTU0MywzOTU0NCwzOTU0NiwzOTU1MSwzOTU0OSwzOTU1MiwzOTU1MywzOTU1NywzOTU2MCwzOTU2MiwzOTU2OCwzOTU3MCwzOTU3MSwzOTU3NCwzOTU3NiwzOTU3OSwzOTU4MCwzOTU4MSwzOTU4MywzOTU4NCwzOTU4NiwzOTU4NywzOTU4OSwzOTU5MSwzMjQxNSwzMjQxNywzMjQxOSwzMjQyMSwzMjQyNCwzMjQyNSwzNzgzOCwzNzgzOSwzNzg0MCwzNzg0MSwzNzg0MiwzNzg0MywzNzg0NCwzNzg0NSwzNzg0NywzNzg0OCwzNzg0OSwzNzg1MCwzNzg1MSwzNzg1MiwzNzg1MywzNzg1NCwzNzg1NSwzNzg1NiwzNzg1NywzNzg1OCwzNzg1OSwzNzg2MCwzNzg2MSwzNzg2MiwzNzg2MywzNzg2NCwzNzg2NSwzNzg2NiwzNzg2NywzNzg2OCwzNzg2OSwzNzg3MCwzNzg3MSwzNzg3MiwzNzg3MywzNzg3NCwzNzg3NSwzNzg3NiwzNzg3NywzNzg3OCwzNzg3OSwzNzg4MCwzNzg4MSwzNzg4MiwzNzg4MywzNzg4NCwzNzg4NSwzNzg4NiwzNzg4NywzNzg4OCwzNzg4OSwzNzg5MCwzNzg5MSwzNzg5MiwzNzg5MywzNzg5NCwzNzg5NSwzNzg5NiwzNzg5NywzNzg5OCwzNzg5OSwzNzkwMCwzNzkwMSwzNzkwMiwzNzkwMywzNzkwNCwzNzkwNSwzNzkwNiwzNzkwNywzNzkwOCwzNzkwOSwzNzkxMCwzNzkxMSwzNzkxMiwzNzkxMywzNzkxNCwzNzkxNSwzNzkxNiwzNzkxNywzNzkxOCwzNzkxOSwzNzkyMCwzNzkyMSwzNzkyMiwzNzkyMywzNzkyNCwzNzkyNSwzNzkyNiwzNzkyNywzNzkyOCwzNzkyOSwzNzkzMCwzNzkzMSwzNzkzMiwzNzkzMywzNzkzNCwzMjQyOSwzMjQzMiwzMjQ0NiwzMjQ0OCwzMjQ0OSwzMjQ1MCwzMjQ1NywzMjQ1OSwzMjQ2MCwzMjQ2NCwzMjQ2OCwzMjQ3MSwzMjQ3NSwzMjQ4MCwzMjQ4MSwzMjQ4OCwzMjQ5MSwzMjQ5NCwzMjQ5NSwzMjQ5NywzMjQ5OCwzMjUyNSwzMjUwMiwzMjUwNiwzMjUwNywzMjUxMCwzMjUxMywzMjUxNCwzMjUxNSwzMjUxOSwzMjUyMCwzMjUyMywzMjUyNCwzMjUyNywzMjUyOSwzMjUzMCwzMjUzNSwzMjUzNywzMjU0MCwzMjUzOSwzMjU0MywzMjU0NSwzMjU0NiwzMjU0NywzMjU0OCwzMjU0OSwzMjU1MCwzMjU1MSwzMjU1NCwzMjU1NSwzMjU1NiwzMjU1NywzMjU1OSwzMjU2MCwzMjU2MSwzMjU2MiwzMjU2MywzMjU2NSwyNDE4NiwzMDA3OSwyNDAyNywzMDAxNCwzNzAxMywyOTU4MiwyOTU4NSwyOTYxNCwyOTYwMiwyOTU5OSwyOTY0NywyOTYzNCwyOTY0OSwyOTYyMywyOTYxOSwyOTYzMiwyOTY0MSwyOTY0MCwyOTY2OSwyOTY1NywzOTAzNiwyOTcwNiwyOTY3MywyOTY3MSwyOTY2MiwyOTYyNiwyOTY4MiwyOTcxMSwyOTczOCwyOTc4NywyOTczNCwyOTczMywyOTczNiwyOTc0NCwyOTc0MiwyOTc0MCwzNzkzNSwzNzkzNiwzNzkzNywzNzkzOCwzNzkzOSwzNzk0MCwzNzk0MSwzNzk0MiwzNzk0MywzNzk0NCwzNzk0NSwzNzk0NiwzNzk0NywzNzk0OCwzNzk0OSwzNzk1MSwzNzk1MiwzNzk1MywzNzk1NCwzNzk1NSwzNzk1NiwzNzk1NywzNzk1OCwzNzk1OSwzNzk2MCwzNzk2MSwzNzk2MiwzNzk2MywzNzk2NCwzNzk2NSwzNzk2NiwzNzk2NywzNzk2OCwzNzk2OSwzNzk3MCwzNzk3MSwzNzk3MiwzNzk3MywzNzk3NCwzNzk3NSwzNzk3NiwzNzk3NywzNzk3OCwzNzk3OSwzNzk4MCwzNzk4MSwzNzk4MiwzNzk4MywzNzk4NCwzNzk4NSwzNzk4NiwzNzk4NywzNzk4OCwzNzk4OSwzNzk5MCwzNzk5MSwzNzk5MiwzNzk5MywzNzk5NCwzNzk5NiwzNzk5NywzNzk5OCwzNzk5OSwzODAwMCwzODAwMSwzODAwMiwzODAwMywzODAwNCwzODAwNSwzODAwNiwzODAwNywzODAwOCwzODAwOSwzODAxMCwzODAxMSwzODAxMiwzODAxMywzODAxNCwzODAxNSwzODAxNiwzODAxNywzODAxOCwzODAxOSwzODAyMCwzODAzMywzODAzOCwzODA0MCwzODA4NywzODA5NSwzODA5OSwzODEwMCwzODEwNiwzODExOCwzODEzOSwzODE3MiwzODE3NiwyOTcyMywyOTcyMiwyOTc2MSwyOTc4OCwyOTc4MywyOTc4MSwyOTc4NSwyOTgxNSwyOTgwNSwyOTgyMiwyOTg1MiwyOTgzOCwyOTgyNCwyOTgyNSwyOTgzMSwyOTgzNSwyOTg1NCwyOTg2NCwyOTg2NSwyOTg0MCwyOTg2MywyOTkwNiwyOTg4MiwzODg5MCwzODg5MSwzODg5MiwyNjQ0NCwyNjQ1MSwyNjQ2MiwyNjQ0MCwyNjQ3MywyNjUzMywyNjUwMywyNjQ3NCwyNjQ4MywyNjUyMCwyNjUzNSwyNjQ4NSwyNjUzNiwyNjUyNiwyNjU0MSwyNjUwNywyNjQ4NywyNjQ5MiwyNjYwOCwyNjYzMywyNjU4NCwyNjYzNCwyNjYwMSwyNjU0NCwyNjYzNiwyNjU4NSwyNjU0OSwyNjU4NiwyNjU0NywyNjU4OSwyNjYyNCwyNjU2MywyNjU1MiwyNjU5NCwyNjYzOCwyNjU2MSwyNjYyMSwyNjY3NCwyNjY3NSwyNjcyMCwyNjcyMSwyNjcwMiwyNjcyMiwyNjY5MiwyNjcyNCwyNjc1NSwyNjY1MywyNjcwOSwyNjcyNiwyNjY4OSwyNjcyNywyNjY4OCwyNjY4NiwyNjY5OCwyNjY5NywyNjY2NSwyNjgwNSwyNjc2NywyNjc0MCwyNjc0MywyNjc3MSwyNjczMSwyNjgxOCwyNjk5MCwyNjg3NiwyNjkxMSwyNjkxMiwyNjg3MywzODE4MywzODE5NSwzODIwNSwzODIxMSwzODIxNiwzODIxOSwzODIyOSwzODIzNCwzODI0MCwzODI1NCwzODI2MCwzODI2MSwzODI2MywzODI2NCwzODI2NSwzODI2NiwzODI2NywzODI2OCwzODI2OSwzODI3MCwzODI3MiwzODI3MywzODI3NCwzODI3NSwzODI3NiwzODI3NywzODI3OCwzODI3OSwzODI4MCwzODI4MSwzODI4MiwzODI4MywzODI4NCwzODI4NSwzODI4NiwzODI4NywzODI4OCwzODI4OSwzODI5MCwzODI5MSwzODI5MiwzODI5MywzODI5NCwzODI5NSwzODI5NiwzODI5NywzODI5OCwzODI5OSwzODMwMCwzODMwMSwzODMwMiwzODMwMywzODMwNCwzODMwNSwzODMwNiwzODMwNywzODMwOCwzODMwOSwzODMxMCwzODMxMSwzODMxMiwzODMxMywzODMxNCwzODMxNSwzODMxNiwzODMxNywzODMxOCwzODMxOSwzODMyMCwzODMyMSwzODMyMiwzODMyMywzODMyNCwzODMyNSwzODMyNiwzODMyNywzODMyOCwzODMyOSwzODMzMCwzODMzMSwzODMzMiwzODMzMywzODMzNCwzODMzNSwzODMzNiwzODMzNywzODMzOCwzODMzOSwzODM0MCwzODM0MSwzODM0MiwzODM0MywzODM0NCwzODM0NSwzODM0NiwzODM0NywyNjkxNiwyNjg2NCwyNjg5MSwyNjg4MSwyNjk2NywyNjg1MSwyNjg5NiwyNjk5MywyNjkzNywyNjk3NiwyNjk0NiwyNjk3MywyNzAxMiwyNjk4NywyNzAwOCwyNzAzMiwyNzAwMCwyNjkzMiwyNzA4NCwyNzAxNSwyNzAxNiwyNzA4NiwyNzAxNywyNjk4MiwyNjk3OSwyNzAwMSwyNzAzNSwyNzA0NywyNzA2NywyNzA1MSwyNzA1MywyNzA5MiwyNzA1NywyNzA3MywyNzA4MiwyNzEwMywyNzAyOSwyNzEwNCwyNzAyMSwyNzEzNSwyNzE4MywyNzExNywyNzE1OSwyNzE2MCwyNzIzNywyNzEyMiwyNzIwNCwyNzE5OCwyNzI5NiwyNzIxNiwyNzIyNywyNzE4OSwyNzI3OCwyNzI1NywyNzE5NywyNzE3NiwyNzIyNCwyNzI2MCwyNzI4MSwyNzI4MCwyNzMwNSwyNzI4NywyNzMwNywyOTQ5NSwyOTUyMiwyNzUyMSwyNzUyMiwyNzUyNywyNzUyNCwyNzUzOCwyNzUzOSwyNzUzMywyNzU0NiwyNzU0NywyNzU1MywyNzU2MiwzNjcxNSwzNjcxNywzNjcyMSwzNjcyMiwzNjcyMywzNjcyNSwzNjcyNiwzNjcyOCwzNjcyNywzNjcyOSwzNjczMCwzNjczMiwzNjczNCwzNjczNywzNjczOCwzNjc0MCwzNjc0MywzNjc0NywzODM0OCwzODM0OSwzODM1MCwzODM1MSwzODM1MiwzODM1MywzODM1NCwzODM1NSwzODM1NiwzODM1NywzODM1OCwzODM1OSwzODM2MCwzODM2MSwzODM2MiwzODM2MywzODM2NCwzODM2NSwzODM2NiwzODM2NywzODM2OCwzODM2OSwzODM3MCwzODM3MSwzODM3MiwzODM3MywzODM3NCwzODM3NSwzODM4MCwzODM5OSwzODQwNywzODQxOSwzODQyNCwzODQyNywzODQzMCwzODQzMiwzODQzNSwzODQzNiwzODQzNywzODQzOCwzODQzOSwzODQ0MCwzODQ0MSwzODQ0MywzODQ0NCwzODQ0NSwzODQ0NywzODQ0OCwzODQ1NSwzODQ1NiwzODQ1NywzODQ1OCwzODQ2MiwzODQ2NSwzODQ2NywzODQ3NCwzODQ3OCwzODQ3OSwzODQ4MSwzODQ4MiwzODQ4MywzODQ4NiwzODQ4NywzODQ4OCwzODQ4OSwzODQ5MCwzODQ5MiwzODQ5MywzODQ5NCwzODQ5NiwzODQ5OSwzODUwMSwzODUwMiwzODUwNywzODUwOSwzODUxMCwzODUxMSwzODUxMiwzODUxMywzODUxNSwzODUyMCwzODUyMSwzODUyMiwzODUyMywzODUyNCwzODUyNSwzODUyNiwzODUyNywzODUyOCwzODUyOSwzODUzMCwzODUzMSwzODUzMiwzODUzNSwzODUzNywzODUzOCwzNjc0OSwzNjc1MCwzNjc1MSwzNjc2MCwzNjc2MiwzNjU1OCwyNTA5OSwyNTExMSwyNTExNSwyNTExOSwyNTEyMiwyNTEyMSwyNTEyNSwyNTEyNCwyNTEzMiwzMzI1NSwyOTkzNSwyOTk0MCwyOTk1MSwyOTk2NywyOTk2OSwyOTk3MSwyNTkwOCwyNjA5NCwyNjA5NSwyNjA5NiwyNjEyMiwyNjEzNywyNjQ4MiwyNjExNSwyNjEzMywyNjExMiwyODgwNSwyNjM1OSwyNjE0MSwyNjE2NCwyNjE2MSwyNjE2NiwyNjE2NSwzMjc3NCwyNjIwNywyNjE5NiwyNjE3NywyNjE5MSwyNjE5OCwyNjIwOSwyNjE5OSwyNjIzMSwyNjI0NCwyNjI1MiwyNjI3OSwyNjI2OSwyNjMwMiwyNjMzMSwyNjMzMiwyNjM0MiwyNjM0NSwzNjE0NiwzNjE0NywzNjE1MCwzNjE1NSwzNjE1NywzNjE2MCwzNjE2NSwzNjE2NiwzNjE2OCwzNjE2OSwzNjE2NywzNjE3MywzNjE4MSwzNjE4NSwzNTI3MSwzNTI3NCwzNTI3NSwzNTI3NiwzNTI3OCwzNTI3OSwzNTI4MCwzNTI4MSwyOTI5NCwyOTM0MywyOTI3NywyOTI4NiwyOTI5NSwyOTMxMCwyOTMxMSwyOTMxNiwyOTMyMywyOTMyNSwyOTMyNywyOTMzMCwyNTM1MiwyNTM5NCwyNTUyMCwzODU0MCwzODU0MiwzODU0NSwzODU0NiwzODU0NywzODU0OSwzODU1MCwzODU1NCwzODU1NSwzODU1NywzODU1OCwzODU1OSwzODU2MCwzODU2MSwzODU2MiwzODU2MywzODU2NCwzODU2NSwzODU2NiwzODU2OCwzODU2OSwzODU3MCwzODU3MSwzODU3MiwzODU3MywzODU3NCwzODU3NSwzODU3NywzODU3OCwzODU4MCwzODU4MSwzODU4MywzODU4NCwzODU4NiwzODU4NywzODU5MSwzODU5NCwzODU5NSwzODYwMCwzODYwMiwzODYwMywzODYwOCwzODYwOSwzODYxMSwzODYxMiwzODYxNCwzODYxNSwzODYxNiwzODYxNywzODYxOCwzODYxOSwzODYyMCwzODYyMSwzODYyMiwzODYyMywzODYyNSwzODYyNiwzODYyNywzODYyOCwzODYyOSwzODYzMCwzODYzMSwzODYzNSwzODYzNiwzODYzNywzODYzOCwzODY0MCwzODY0MSwzODY0MiwzODY0NCwzODY0NSwzODY0OCwzODY1MCwzODY1MSwzODY1MiwzODY1MywzODY1NSwzODY1OCwzODY1OSwzODY2MSwzODY2NiwzODY2NywzODY2OCwzODY3MiwzODY3MywzODY3NCwzODY3NiwzODY3NywzODY3OSwzODY4MCwzODY4MSwzODY4MiwzODY4MywzODY4NSwzODY4NywzODY4OCwyNTY2MywyNTgxNiwzMjc3MiwyNzYyNiwyNzYzNSwyNzY0NSwyNzYzNywyNzY0MSwyNzY1MywyNzY1NSwyNzY1NCwyNzY2MSwyNzY2OSwyNzY3MiwyNzY3MywyNzY3NCwyNzY4MSwyNzY4OSwyNzY4NCwyNzY5MCwyNzY5OCwyNTkwOSwyNTk0MSwyNTk2MywyOTI2MSwyOTI2NiwyOTI3MCwyOTIzMiwzNDQwMiwyMTAxNCwzMjkyNywzMjkyNCwzMjkxNSwzMjk1NiwyNjM3OCwzMjk1NywzMjk0NSwzMjkzOSwzMjk0MSwzMjk0OCwzMjk1MSwzMjk5OSwzMzAwMCwzMzAwMSwzMzAwMiwzMjk4NywzMjk2MiwzMjk2NCwzMjk4NSwzMjk3MywzMjk4MywyNjM4NCwzMjk4OSwzMzAwMywzMzAwOSwzMzAxMiwzMzAwNSwzMzAzNywzMzAzOCwzMzAxMCwzMzAyMCwyNjM4OSwzMzA0MiwzNTkzMCwzMzA3OCwzMzA1NCwzMzA2OCwzMzA0OCwzMzA3NCwzMzA5NiwzMzEwMCwzMzEwNywzMzE0MCwzMzExMywzMzExNCwzMzEzNywzMzEyMCwzMzEyOSwzMzE0OCwzMzE0OSwzMzEzMywzMzEyNywyMjYwNSwyMzIyMSwzMzE2MCwzMzE1NCwzMzE2OSwyODM3MywzMzE4NywzMzE5NCwzMzIyOCwyNjQwNiwzMzIyNiwzMzIxMSwzODY4OSwzODY5MCwzODY5MSwzODY5MiwzODY5MywzODY5NCwzODY5NSwzODY5NiwzODY5NywzODY5OSwzODcwMCwzODcwMiwzODcwMywzODcwNSwzODcwNywzODcwOCwzODcwOSwzODcxMCwzODcxMSwzODcxNCwzODcxNSwzODcxNiwzODcxNywzODcxOSwzODcyMCwzODcyMSwzODcyMiwzODcyMywzODcyNCwzODcyNSwzODcyNiwzODcyNywzODcyOCwzODcyOSwzODczMCwzODczMSwzODczMiwzODczMywzODczNCwzODczNSwzODczNiwzODczNywzODc0MCwzODc0MSwzODc0MywzODc0NCwzODc0NiwzODc0OCwzODc0OSwzODc1MSwzODc1NSwzODc1NiwzODc1OCwzODc1OSwzODc2MCwzODc2MiwzODc2MywzODc2NCwzODc2NSwzODc2NiwzODc2NywzODc2OCwzODc2OSwzODc3MCwzODc3MywzODc3NSwzODc3NiwzODc3NywzODc3OCwzODc3OSwzODc4MSwzODc4MiwzODc4MywzODc4NCwzODc4NSwzODc4NiwzODc4NywzODc4OCwzODc5MCwzODc5MSwzODc5MiwzODc5MywzODc5NCwzODc5NiwzODc5OCwzODc5OSwzODgwMCwzODgwMywzODgwNSwzODgwNiwzODgwNywzODgwOSwzODgxMCwzODgxMSwzODgxMiwzODgxMywzMzIxNywzMzE5MCwyNzQyOCwyNzQ0NywyNzQ0OSwyNzQ1OSwyNzQ2MiwyNzQ4MSwzOTEyMSwzOTEyMiwzOTEyMywzOTEyNSwzOTEyOSwzOTEzMCwyNzU3MSwyNDM4NCwyNzU4NiwzNTMxNSwyNjAwMCw0MDc4NSwyNjAwMywyNjA0NCwyNjA1NCwyNjA1MiwyNjA1MSwyNjA2MCwyNjA2MiwyNjA2NiwyNjA3MCwyODgwMCwyODgyOCwyODgyMiwyODgyOSwyODg1OSwyODg2NCwyODg1NSwyODg0MywyODg0OSwyODkwNCwyODg3NCwyODk0NCwyODk0NywyODk1MCwyODk3NSwyODk3NywyOTA0MywyOTAyMCwyOTAzMiwyODk5NywyOTA0MiwyOTAwMiwyOTA0OCwyOTA1MCwyOTA4MCwyOTEwNywyOTEwOSwyOTA5NiwyOTA4OCwyOTE1MiwyOTE0MCwyOTE1OSwyOTE3NywyOTIxMywyOTIyNCwyODc4MCwyODk1MiwyOTAzMCwyOTExMywyNTE1MCwyNTE0OSwyNTE1NSwyNTE2MCwyNTE2MSwzMTAzNSwzMTA0MCwzMTA0NiwzMTA0OSwzMTA2NywzMTA2OCwzMTA1OSwzMTA2NiwzMTA3NCwzMTA2MywzMTA3MiwzMTA4NywzMTA3OSwzMTA5OCwzMTEwOSwzMTExNCwzMTEzMCwzMTE0MywzMTE1NSwyNDUyOSwyNDUyOCwzODgxNCwzODgxNSwzODgxNywzODgxOCwzODgyMCwzODgyMSwzODgyMiwzODgyMywzODgyNCwzODgyNSwzODgyNiwzODgyOCwzODgzMCwzODgzMiwzODgzMywzODgzNSwzODgzNywzODgzOCwzODgzOSwzODg0MCwzODg0MSwzODg0MiwzODg0MywzODg0NCwzODg0NSwzODg0NiwzODg0NywzODg0OCwzODg0OSwzODg1MCwzODg1MSwzODg1MiwzODg1MywzODg1NCwzODg1NSwzODg1NiwzODg1NywzODg1OCwzODg1OSwzODg2MCwzODg2MSwzODg2MiwzODg2MywzODg2NCwzODg2NSwzODg2NiwzODg2NywzODg2OCwzODg2OSwzODg3MCwzODg3MSwzODg3MiwzODg3MywzODg3NCwzODg3NSwzODg3NiwzODg3NywzODg3OCwzODg3OSwzODg4MCwzODg4MSwzODg4MiwzODg4MywzODg4NCwzODg4NSwzODg4OCwzODg5NCwzODg5NSwzODg5NiwzODg5NywzODg5OCwzODkwMCwzODkwMywzODkwNCwzODkwNSwzODkwNiwzODkwNywzODkwOCwzODkwOSwzODkxMCwzODkxMSwzODkxMiwzODkxMywzODkxNCwzODkxNSwzODkxNiwzODkxNywzODkxOCwzODkxOSwzODkyMCwzODkyMSwzODkyMiwzODkyMywzODkyNCwzODkyNSwzODkyNiwyNDYzNiwyNDY2OSwyNDY2NiwyNDY3OSwyNDY0MSwyNDY2NSwyNDY3NSwyNDc0NywyNDgzOCwyNDg0NSwyNDkyNSwyNTAwMSwyNDk4OSwyNTAzNSwyNTA0MSwyNTA5NCwzMjg5NiwzMjg5NSwyNzc5NSwyNzg5NCwyODE1NiwzMDcxMCwzMDcxMiwzMDcyMCwzMDcyOSwzMDc0MywzMDc0NCwzMDczNywyNjAyNywzMDc2NSwzMDc0OCwzMDc0OSwzMDc3NywzMDc3OCwzMDc3OSwzMDc1MSwzMDc4MCwzMDc1NywzMDc2NCwzMDc1NSwzMDc2MSwzMDc5OCwzMDgyOSwzMDgwNiwzMDgwNywzMDc1OCwzMDgwMCwzMDc5MSwzMDc5NiwzMDgyNiwzMDg3NSwzMDg2NywzMDg3NCwzMDg1NSwzMDg3NiwzMDg4MSwzMDg4MywzMDg5OCwzMDkwNSwzMDg4NSwzMDkzMiwzMDkzNywzMDkyMSwzMDk1NiwzMDk2MiwzMDk4MSwzMDk2NCwzMDk5NSwzMTAxMiwzMTAwNiwzMTAyOCw0MDg1OSw0MDY5Nyw0MDY5OSw0MDcwMCwzMDQ0OSwzMDQ2OCwzMDQ3NywzMDQ1NywzMDQ3MSwzMDQ3MiwzMDQ5MCwzMDQ5OCwzMDQ4OSwzMDUwOSwzMDUwMiwzMDUxNywzMDUyMCwzMDU0NCwzMDU0NSwzMDUzNSwzMDUzMSwzMDU1NCwzMDU2OCwzODkyNywzODkyOCwzODkyOSwzODkzMCwzODkzMSwzODkzMiwzODkzMywzODkzNCwzODkzNSwzODkzNiwzODkzNywzODkzOCwzODkzOSwzODk0MCwzODk0MSwzODk0MiwzODk0MywzODk0NCwzODk0NSwzODk0NiwzODk0NywzODk0OCwzODk0OSwzODk1MCwzODk1MSwzODk1MiwzODk1MywzODk1NCwzODk1NSwzODk1NiwzODk1NywzODk1OCwzODk1OSwzODk2MCwzODk2MSwzODk2MiwzODk2MywzODk2NCwzODk2NSwzODk2NiwzODk2NywzODk2OCwzODk2OSwzODk3MCwzODk3MSwzODk3MiwzODk3MywzODk3NCwzODk3NSwzODk3NiwzODk3NywzODk3OCwzODk3OSwzODk4MCwzODk4MSwzODk4MiwzODk4MywzODk4NCwzODk4NSwzODk4NiwzODk4NywzODk4OCwzODk4OSwzODk5MCwzODk5MSwzODk5MiwzODk5MywzODk5NCwzODk5NSwzODk5NiwzODk5NywzODk5OCwzODk5OSwzOTAwMCwzOTAwMSwzOTAwMiwzOTAwMywzOTAwNCwzOTAwNSwzOTAwNiwzOTAwNywzOTAwOCwzOTAwOSwzOTAxMCwzOTAxMSwzOTAxMiwzOTAxMywzOTAxNCwzOTAxNSwzOTAxNiwzOTAxNywzOTAxOCwzOTAxOSwzOTAyMCwzOTAyMSwzOTAyMiwzMDU2MiwzMDU2NSwzMDU5MSwzMDYwNSwzMDU4OSwzMDU5MiwzMDYwNCwzMDYwOSwzMDYyMywzMDYyNCwzMDY0MCwzMDY0NSwzMDY1MywzMDAxMCwzMDAxNiwzMDAzMCwzMDAyNywzMDAyNCwzMDA0MywzMDA2NiwzMDA3MywzMDA4MywzMjYwMCwzMjYwOSwzMjYwNywzNTQwMCwzMjYxNiwzMjYyOCwzMjYyNSwzMjYzMywzMjY0MSwzMjYzOCwzMDQxMywzMDQzNywzNDg2NiwzODAyMSwzODAyMiwzODAyMywzODAyNywzODAyNiwzODAyOCwzODAyOSwzODAzMSwzODAzMiwzODAzNiwzODAzOSwzODAzNywzODA0MiwzODA0MywzODA0NCwzODA1MSwzODA1MiwzODA1OSwzODA1OCwzODA2MSwzODA2MCwzODA2MywzODA2NCwzODA2NiwzODA2OCwzODA3MCwzODA3MSwzODA3MiwzODA3MywzODA3NCwzODA3NiwzODA3NywzODA3OSwzODA4NCwzODA4OCwzODA4OSwzODA5MCwzODA5MSwzODA5MiwzODA5MywzODA5NCwzODA5NiwzODA5NywzODA5OCwzODEwMSwzODEwMiwzODEwMywzODEwNSwzODEwNCwzODEwNywzODExMCwzODExMSwzODExMiwzODExNCwzODExNiwzODExNywzODExOSwzODEyMCwzODEyMiwzOTAyMywzOTAyNCwzOTAyNSwzOTAyNiwzOTAyNywzOTAyOCwzOTA1MSwzOTA1NCwzOTA1OCwzOTA2MSwzOTA2NSwzOTA3NSwzOTA4MCwzOTA4MSwzOTA4MiwzOTA4MywzOTA4NCwzOTA4NSwzOTA4NiwzOTA4NywzOTA4OCwzOTA4OSwzOTA5MCwzOTA5MSwzOTA5MiwzOTA5MywzOTA5NCwzOTA5NSwzOTA5NiwzOTA5NywzOTA5OCwzOTA5OSwzOTEwMCwzOTEwMSwzOTEwMiwzOTEwMywzOTEwNCwzOTEwNSwzOTEwNiwzOTEwNywzOTEwOCwzOTEwOSwzOTExMCwzOTExMSwzOTExMiwzOTExMywzOTExNCwzOTExNSwzOTExNiwzOTExNywzOTExOSwzOTEyMCwzOTEyNCwzOTEyNiwzOTEyNywzOTEzMSwzOTEzMiwzOTEzMywzOTEzNiwzOTEzNywzOTEzOCwzOTEzOSwzOTE0MCwzOTE0MSwzOTE0MiwzOTE0NSwzOTE0NiwzOTE0NywzOTE0OCwzOTE0OSwzOTE1MCwzOTE1MSwzOTE1MiwzOTE1MywzOTE1NCwzOTE1NSwzOTE1NiwzOTE1NywzOTE1OCwzOTE1OSwzOTE2MCwzOTE2MSwzOTE2MiwzOTE2MywzOTE2NCwzOTE2NSwzOTE2NiwzOTE2NywzOTE2OCwzOTE2OSwzOTE3MCwzOTE3MSwzOTE3MiwzOTE3MywzOTE3NCwzOTE3NSwzODEyMSwzODEyMywzODEyNiwzODEyNywzODEzMSwzODEzMiwzODEzMywzODEzNSwzODEzNywzODE0MCwzODE0MSwzODE0MywzODE0NywzODE0NiwzODE1MCwzODE1MSwzODE1MywzODE1NCwzODE1NywzODE1OCwzODE1OSwzODE2MiwzODE2MywzODE2NCwzODE2NSwzODE2NiwzODE2OCwzODE3MSwzODE3MywzODE3NCwzODE3NSwzODE3OCwzODE4NiwzODE4NywzODE4NSwzODE4OCwzODE5MywzODE5NCwzODE5NiwzODE5OCwzODE5OSwzODIwMCwzODIwNCwzODIwNiwzODIwNywzODIxMCwzODE5NywzODIxMiwzODIxMywzODIxNCwzODIxNywzODIyMCwzODIyMiwzODIyMywzODIyNiwzODIyNywzODIyOCwzODIzMCwzODIzMSwzODIzMiwzODIzMywzODIzNSwzODIzOCwzODIzOSwzODIzNywzODI0MSwzODI0MiwzODI0NCwzODI0NSwzODI0NiwzODI0NywzODI0OCwzODI0OSwzODI1MCwzODI1MSwzODI1MiwzODI1NSwzODI1NywzODI1OCwzODI1OSwzODIwMiwzMDY5NSwzMDcwMCwzODYwMSwzMTE4OSwzMTIxMywzMTIwMywzMTIxMSwzMTIzOCwyMzg3OSwzMTIzNSwzMTIzNCwzMTI2MiwzMTI1MiwzOTE3NiwzOTE3NywzOTE3OCwzOTE3OSwzOTE4MCwzOTE4MiwzOTE4MywzOTE4NSwzOTE4NiwzOTE4NywzOTE4OCwzOTE4OSwzOTE5MCwzOTE5MSwzOTE5MiwzOTE5MywzOTE5NCwzOTE5NSwzOTE5NiwzOTE5NywzOTE5OCwzOTE5OSwzOTIwMCwzOTIwMSwzOTIwMiwzOTIwMywzOTIwNCwzOTIwNSwzOTIwNiwzOTIwNywzOTIwOCwzOTIwOSwzOTIxMCwzOTIxMSwzOTIxMiwzOTIxMywzOTIxNSwzOTIxNiwzOTIxNywzOTIxOCwzOTIxOSwzOTIyMCwzOTIyMSwzOTIyMiwzOTIyMywzOTIyNCwzOTIyNSwzOTIyNiwzOTIyNywzOTIyOCwzOTIyOSwzOTIzMCwzOTIzMSwzOTIzMiwzOTIzMywzOTIzNCwzOTIzNSwzOTIzNiwzOTIzNywzOTIzOCwzOTIzOSwzOTI0MCwzOTI0MSwzOTI0MiwzOTI0MywzOTI0NCwzOTI0NSwzOTI0NiwzOTI0NywzOTI0OCwzOTI0OSwzOTI1MCwzOTI1MSwzOTI1NCwzOTI1NSwzOTI1NiwzOTI1NywzOTI1OCwzOTI1OSwzOTI2MCwzOTI2MSwzOTI2MiwzOTI2MywzOTI2NCwzOTI2NSwzOTI2NiwzOTI2OCwzOTI3MCwzOTI4MywzOTI4OCwzOTI4OSwzOTI5MSwzOTI5NCwzOTI5OCwzOTI5OSwzOTMwNSwzMTI4OSwzMTI4NywzMTMxMyw0MDY1NSwzOTMzMywzMTM0NCwzMDM0NCwzMDM1MCwzMDM1NSwzMDM2MSwzMDM3MiwyOTkxOCwyOTkyMCwyOTk5Niw0MDQ4MCw0MDQ4Miw0MDQ4OCw0MDQ4OSw0MDQ5MCw0MDQ5MSw0MDQ5Miw0MDQ5OCw0MDQ5Nyw0MDUwMiw0MDUwNCw0MDUwMyw0MDUwNSw0MDUwNiw0MDUxMCw0MDUxMyw0MDUxNCw0MDUxNiw0MDUxOCw0MDUxOSw0MDUyMCw0MDUyMSw0MDUyMyw0MDUyNCw0MDUyNiw0MDUyOSw0MDUzMyw0MDUzNSw0MDUzOCw0MDUzOSw0MDU0MCw0MDU0Miw0MDU0Nyw0MDU1MCw0MDU1MSw0MDU1Miw0MDU1Myw0MDU1NCw0MDU1NSw0MDU1Niw0MDU2MSw0MDU1Nyw0MDU2MywzMDA5OCwzMDEwMCwzMDEwMiwzMDExMiwzMDEwOSwzMDEyNCwzMDExNSwzMDEzMSwzMDEzMiwzMDEzNiwzMDE0OCwzMDEyOSwzMDEyOCwzMDE0NywzMDE0NiwzMDE2NiwzMDE1NywzMDE3OSwzMDE4NCwzMDE4MiwzMDE4MCwzMDE4NywzMDE4MywzMDIxMSwzMDE5MywzMDIwNCwzMDIwNywzMDIyNCwzMDIwOCwzMDIxMywzMDIyMCwzMDIzMSwzMDIxOCwzMDI0NSwzMDIzMiwzMDIyOSwzMDIzMywzOTMwOCwzOTMxMCwzOTMyMiwzOTMyMywzOTMyNCwzOTMyNSwzOTMyNiwzOTMyNywzOTMyOCwzOTMyOSwzOTMzMCwzOTMzMSwzOTMzMiwzOTMzNCwzOTMzNSwzOTMzNywzOTMzOCwzOTMzOSwzOTM0MCwzOTM0MSwzOTM0MiwzOTM0MywzOTM0NCwzOTM0NSwzOTM0NiwzOTM0NywzOTM0OCwzOTM0OSwzOTM1MCwzOTM1MSwzOTM1MiwzOTM1MywzOTM1NCwzOTM1NSwzOTM1NiwzOTM1NywzOTM1OCwzOTM1OSwzOTM2MCwzOTM2MSwzOTM2MiwzOTM2MywzOTM2NCwzOTM2NSwzOTM2NiwzOTM2NywzOTM2OCwzOTM2OSwzOTM3MCwzOTM3MSwzOTM3MiwzOTM3MywzOTM3NCwzOTM3NSwzOTM3NiwzOTM3NywzOTM3OCwzOTM3OSwzOTM4MCwzOTM4MSwzOTM4MiwzOTM4MywzOTM4NCwzOTM4NSwzOTM4NiwzOTM4NywzOTM4OCwzOTM4OSwzOTM5MCwzOTM5MSwzOTM5MiwzOTM5MywzOTM5NCwzOTM5NSwzOTM5NiwzOTM5NywzOTM5OCwzOTM5OSwzOTQwMCwzOTQwMSwzOTQwMiwzOTQwMywzOTQwNCwzOTQwNSwzOTQwNiwzOTQwNywzOTQwOCwzOTQwOSwzOTQxMCwzOTQxMSwzOTQxMiwzOTQxMywzOTQxNCwzOTQxNSwzOTQxNiwzOTQxNywzMDIzNSwzMDI2OCwzMDI0MiwzMDI0MCwzMDI3MiwzMDI1MywzMDI1NiwzMDI3MSwzMDI2MSwzMDI3NSwzMDI3MCwzMDI1OSwzMDI4NSwzMDMwMiwzMDI5MiwzMDMwMCwzMDI5NCwzMDMxNSwzMDMxOSwzMjcxNCwzMTQ2MiwzMTM1MiwzMTM1MywzMTM2MCwzMTM2NiwzMTM2OCwzMTM4MSwzMTM5OCwzMTM5MiwzMTQwNCwzMTQwMCwzMTQwNSwzMTQxMSwzNDkxNiwzNDkyMSwzNDkzMCwzNDk0MSwzNDk0MywzNDk0NiwzNDk3OCwzNTAxNCwzNDk5OSwzNTAwNCwzNTAxNywzNTA0MiwzNTAyMiwzNTA0MywzNTA0NSwzNTA1NywzNTA5OCwzNTA2OCwzNTA0OCwzNTA3MCwzNTA1NiwzNTEwNSwzNTA5NywzNTA5MSwzNTA5OSwzNTA4MiwzNTEyNCwzNTExNSwzNTEyNiwzNTEzNywzNTE3NCwzNTE5NSwzMDA5MSwzMjk5NywzMDM4NiwzMDM4OCwzMDY4NCwzMjc4NiwzMjc4OCwzMjc5MCwzMjc5NiwzMjgwMCwzMjgwMiwzMjgwNSwzMjgwNiwzMjgwNywzMjgwOSwzMjgwOCwzMjgxNywzMjc3OSwzMjgyMSwzMjgzNSwzMjgzOCwzMjg0NSwzMjg1MCwzMjg3MywzMjg4MSwzNTIwMywzOTAzMiwzOTA0MCwzOTA0MywzOTQxOCwzOTQxOSwzOTQyMCwzOTQyMSwzOTQyMiwzOTQyMywzOTQyNCwzOTQyNSwzOTQyNiwzOTQyNywzOTQyOCwzOTQyOSwzOTQzMCwzOTQzMSwzOTQzMiwzOTQzMywzOTQzNCwzOTQzNSwzOTQzNiwzOTQzNywzOTQzOCwzOTQzOSwzOTQ0MCwzOTQ0MSwzOTQ0MiwzOTQ0MywzOTQ0NCwzOTQ0NSwzOTQ0NiwzOTQ0NywzOTQ0OCwzOTQ0OSwzOTQ1MCwzOTQ1MSwzOTQ1MiwzOTQ1MywzOTQ1NCwzOTQ1NSwzOTQ1NiwzOTQ1NywzOTQ1OCwzOTQ1OSwzOTQ2MCwzOTQ2MSwzOTQ2MiwzOTQ2MywzOTQ2NCwzOTQ2NSwzOTQ2NiwzOTQ2NywzOTQ2OCwzOTQ2OSwzOTQ3MCwzOTQ3MSwzOTQ3MiwzOTQ3MywzOTQ3NCwzOTQ3NSwzOTQ3NiwzOTQ3NywzOTQ3OCwzOTQ3OSwzOTQ4MCwzOTQ4MSwzOTQ4MiwzOTQ4MywzOTQ4NCwzOTQ4NSwzOTQ4NiwzOTQ4NywzOTQ4OCwzOTQ4OSwzOTQ5MCwzOTQ5MSwzOTQ5MiwzOTQ5MywzOTQ5NCwzOTQ5NSwzOTQ5NiwzOTQ5NywzOTQ5OCwzOTQ5OSwzOTUwMCwzOTUwMSwzOTUwMiwzOTUwMywzOTUwNCwzOTUwNSwzOTUwNiwzOTUwNywzOTUwOCwzOTUwOSwzOTUxMCwzOTUxMSwzOTUxMiwzOTUxMywzOTA0OSwzOTA1MiwzOTA1MywzOTA1NSwzOTA2MCwzOTA2NiwzOTA2NywzOTA3MCwzOTA3MSwzOTA3MywzOTA3NCwzOTA3NywzOTA3OCwzNDM4MSwzNDM4OCwzNDQxMiwzNDQxNCwzNDQzMSwzNDQyNiwzNDQyOCwzNDQyNywzNDQ3MiwzNDQ0NSwzNDQ0MywzNDQ3NiwzNDQ2MSwzNDQ3MSwzNDQ2NywzNDQ3NCwzNDQ1MSwzNDQ3MywzNDQ4NiwzNDUwMCwzNDQ4NSwzNDUxMCwzNDQ4MCwzNDQ5MCwzNDQ4MSwzNDQ3OSwzNDUwNSwzNDUxMSwzNDQ4NCwzNDUzNywzNDU0NSwzNDU0NiwzNDU0MSwzNDU0NywzNDUxMiwzNDU3OSwzNDUyNiwzNDU0OCwzNDUyNywzNDUyMCwzNDUxMywzNDU2MywzNDU2NywzNDU1MiwzNDU2OCwzNDU3MCwzNDU3MywzNDU2OSwzNDU5NSwzNDYxOSwzNDU5MCwzNDU5NywzNDYwNiwzNDU4NiwzNDYyMiwzNDYzMiwzNDYxMiwzNDYwOSwzNDYwMSwzNDYxNSwzNDYyMywzNDY5MCwzNDU5NCwzNDY4NSwzNDY4NiwzNDY4MywzNDY1NiwzNDY3MiwzNDYzNiwzNDY3MCwzNDY5OSwzNDY0MywzNDY1OSwzNDY4NCwzNDY2MCwzNDY0OSwzNDY2MSwzNDcwNywzNDczNSwzNDcyOCwzNDc3MCwzOTUxNCwzOTUxNSwzOTUxNiwzOTUxNywzOTUxOCwzOTUxOSwzOTUyMCwzOTUyMSwzOTUyMiwzOTUyMywzOTUyNCwzOTUyNSwzOTUyNiwzOTUyNywzOTUyOCwzOTUyOSwzOTUzMCwzOTUzMSwzOTUzOCwzOTU1NSwzOTU2MSwzOTU2NSwzOTU2NiwzOTU3MiwzOTU3MywzOTU3NywzOTU5MCwzOTU5MywzOTU5NCwzOTU5NSwzOTU5NiwzOTU5NywzOTU5OCwzOTU5OSwzOTYwMiwzOTYwMywzOTYwNCwzOTYwNSwzOTYwOSwzOTYxMSwzOTYxMywzOTYxNCwzOTYxNSwzOTYxOSwzOTYyMCwzOTYyMiwzOTYyMywzOTYyNCwzOTYyNSwzOTYyNiwzOTYyOSwzOTYzMCwzOTYzMSwzOTYzMiwzOTYzNCwzOTYzNiwzOTYzNywzOTYzOCwzOTYzOSwzOTY0MSwzOTY0MiwzOTY0MywzOTY0NCwzOTY0NSwzOTY0NiwzOTY0OCwzOTY1MCwzOTY1MSwzOTY1MiwzOTY1MywzOTY1NSwzOTY1NiwzOTY1NywzOTY1OCwzOTY2MCwzOTY2MiwzOTY2NCwzOTY2NSwzOTY2NiwzOTY2NywzOTY2OCwzOTY2OSwzOTY3MCwzOTY3MSwzOTY3MiwzOTY3NCwzOTY3NiwzOTY3NywzOTY3OCwzOTY3OSwzOTY4MCwzOTY4MSwzOTY4MiwzOTY4NCwzOTY4NSwzOTY4NiwzNDc1OCwzNDY5NiwzNDY5MywzNDczMywzNDcxMSwzNDY5MSwzNDczMSwzNDc4OSwzNDczMiwzNDc0MSwzNDczOSwzNDc2MywzNDc3MSwzNDc0OSwzNDc2OSwzNDc1MiwzNDc2MiwzNDc3OSwzNDc5NCwzNDc4NCwzNDc5OCwzNDgzOCwzNDgzNSwzNDgxNCwzNDgyNiwzNDg0MywzNDg0OSwzNDg3MywzNDg3NiwzMjU2NiwzMjU3OCwzMjU4MCwzMjU4MSwzMzI5NiwzMTQ4MiwzMTQ4NSwzMTQ5NiwzMTQ5MSwzMTQ5MiwzMTUwOSwzMTQ5OCwzMTUzMSwzMTUwMywzMTU1OSwzMTU0NCwzMTUzMCwzMTUxMywzMTUzNCwzMTUzNywzMTUyMCwzMTUyNSwzMTUyNCwzMTUzOSwzMTU1MCwzMTUxOCwzMTU3NiwzMTU3OCwzMTU1NywzMTYwNSwzMTU2NCwzMTU4MSwzMTU4NCwzMTU5OCwzMTYxMSwzMTU4NiwzMTYwMiwzMTYwMSwzMTYzMiwzMTY1NCwzMTY1NSwzMTY3MiwzMTY2MCwzMTY0NSwzMTY1NiwzMTYyMSwzMTY1OCwzMTY0NCwzMTY1MCwzMTY1OSwzMTY2OCwzMTY5NywzMTY4MSwzMTY5MiwzMTcwOSwzMTcwNiwzMTcxNywzMTcxOCwzMTcyMiwzMTc1NiwzMTc0MiwzMTc0MCwzMTc1OSwzMTc2NiwzMTc1NSwzOTY4NywzOTY4OSwzOTY5MCwzOTY5MSwzOTY5MiwzOTY5MywzOTY5NCwzOTY5NiwzOTY5NywzOTY5OCwzOTcwMCwzOTcwMSwzOTcwMiwzOTcwMywzOTcwNCwzOTcwNSwzOTcwNiwzOTcwNywzOTcwOCwzOTcwOSwzOTcxMCwzOTcxMiwzOTcxMywzOTcxNCwzOTcxNiwzOTcxNywzOTcxOCwzOTcxOSwzOTcyMCwzOTcyMSwzOTcyMiwzOTcyMywzOTcyNCwzOTcyNSwzOTcyNiwzOTcyOCwzOTcyOSwzOTczMSwzOTczMiwzOTczMywzOTczNCwzOTczNSwzOTczNiwzOTczNywzOTczOCwzOTc0MSwzOTc0MiwzOTc0MywzOTc0NCwzOTc1MCwzOTc1NCwzOTc1NSwzOTc1NiwzOTc1OCwzOTc2MCwzOTc2MiwzOTc2MywzOTc2NSwzOTc2NiwzOTc2NywzOTc2OCwzOTc2OSwzOTc3MCwzOTc3MSwzOTc3MiwzOTc3MywzOTc3NCwzOTc3NSwzOTc3NiwzOTc3NywzOTc3OCwzOTc3OSwzOTc4MCwzOTc4MSwzOTc4MiwzOTc4MywzOTc4NCwzOTc4NSwzOTc4NiwzOTc4NywzOTc4OCwzOTc4OSwzOTc5MCwzOTc5MSwzOTc5MiwzOTc5MywzOTc5NCwzOTc5NSwzOTc5NiwzOTc5NywzOTc5OCwzOTc5OSwzOTgwMCwzOTgwMSwzOTgwMiwzOTgwMywzMTc3NSwzMTc4NiwzMTc4MiwzMTgwMCwzMTgwOSwzMTgwOCwzMzI3OCwzMzI4MSwzMzI4MiwzMzI4NCwzMzI2MCwzNDg4NCwzMzMxMywzMzMxNCwzMzMxNSwzMzMyNSwzMzMyNywzMzMyMCwzMzMyMywzMzMzNiwzMzMzOSwzMzMzMSwzMzMzMiwzMzM0MiwzMzM0OCwzMzM1MywzMzM1NSwzMzM1OSwzMzM3MCwzMzM3NSwzMzM4NCwzNDk0MiwzNDk0OSwzNDk1MiwzNTAzMiwzNTAzOSwzNTE2NiwzMjY2OSwzMjY3MSwzMjY3OSwzMjY4NywzMjY4OCwzMjY5MCwzMTg2OCwyNTkyOSwzMTg4OSwzMTkwMSwzMTkwMCwzMTkwMiwzMTkwNiwzMTkyMiwzMTkzMiwzMTkzMywzMTkzNywzMTk0MywzMTk0OCwzMTk0OSwzMTk0NCwzMTk0MSwzMTk1OSwzMTk3NiwzMzM5MCwyNjI4MCwzMjcwMywzMjcxOCwzMjcyNSwzMjc0MSwzMjczNywzMjc0MiwzMjc0NSwzMjc1MCwzMjc1NSwzMTk5MiwzMjExOSwzMjE2NiwzMjE3NCwzMjMyNywzMjQxMSw0MDYzMiw0MDYyOCwzNjIxMSwzNjIyOCwzNjI0NCwzNjI0MSwzNjI3MywzNjE5OSwzNjIwNSwzNTkxMSwzNTkxMywzNzE5NCwzNzIwMCwzNzE5OCwzNzE5OSwzNzIyMCwzOTgwNCwzOTgwNSwzOTgwNiwzOTgwNywzOTgwOCwzOTgwOSwzOTgxMCwzOTgxMSwzOTgxMiwzOTgxMywzOTgxNCwzOTgxNSwzOTgxNiwzOTgxNywzOTgxOCwzOTgxOSwzOTgyMCwzOTgyMSwzOTgyMiwzOTgyMywzOTgyNCwzOTgyNSwzOTgyNiwzOTgyNywzOTgyOCwzOTgyOSwzOTgzMCwzOTgzMSwzOTgzMiwzOTgzMywzOTgzNCwzOTgzNSwzOTgzNiwzOTgzNywzOTgzOCwzOTgzOSwzOTg0MCwzOTg0MSwzOTg0MiwzOTg0MywzOTg0NCwzOTg0NSwzOTg0NiwzOTg0NywzOTg0OCwzOTg0OSwzOTg1MCwzOTg1MSwzOTg1MiwzOTg1MywzOTg1NCwzOTg1NSwzOTg1NiwzOTg1NywzOTg1OCwzOTg1OSwzOTg2MCwzOTg2MSwzOTg2MiwzOTg2MywzOTg2NCwzOTg2NSwzOTg2NiwzOTg2NywzOTg2OCwzOTg2OSwzOTg3MCwzOTg3MSwzOTg3MiwzOTg3MywzOTg3NCwzOTg3NSwzOTg3NiwzOTg3NywzOTg3OCwzOTg3OSwzOTg4MCwzOTg4MSwzOTg4MiwzOTg4MywzOTg4NCwzOTg4NSwzOTg4NiwzOTg4NywzOTg4OCwzOTg4OSwzOTg5MCwzOTg5MSwzOTg5MiwzOTg5MywzOTg5NCwzOTg5NSwzOTg5NiwzOTg5NywzOTg5OCwzOTg5OSwzNzIxOCwzNzIxNywzNzIzMiwzNzIyNSwzNzIzMSwzNzI0NSwzNzI0NiwzNzIzNCwzNzIzNiwzNzI0MSwzNzI2MCwzNzI1MywzNzI2NCwzNzI2MSwzNzI2NSwzNzI4MiwzNzI4MywzNzI5MCwzNzI5MywzNzI5NCwzNzI5NSwzNzMwMSwzNzMwMCwzNzMwNiwzNTkyNSw0MDU3NCwzNjI4MCwzNjMzMSwzNjM1NywzNjQ0MSwzNjQ1NywzNjI3NywzNjI4NywzNjI4NCwzNjI4MiwzNjI5MiwzNjMxMCwzNjMxMSwzNjMxNCwzNjMxOCwzNjMwMiwzNjMwMywzNjMxNSwzNjI5NCwzNjMzMiwzNjM0MywzNjM0NCwzNjMyMywzNjM0NSwzNjM0NywzNjMyNCwzNjM2MSwzNjM0OSwzNjM3MiwzNjM4MSwzNjM4MywzNjM5NiwzNjM5OCwzNjM4NywzNjM5OSwzNjQxMCwzNjQxNiwzNjQwOSwzNjQwNSwzNjQxMywzNjQwMSwzNjQyNSwzNjQxNywzNjQxOCwzNjQzMywzNjQzNCwzNjQyNiwzNjQ2NCwzNjQ3MCwzNjQ3NiwzNjQ2MywzNjQ2OCwzNjQ4NSwzNjQ5NSwzNjUwMCwzNjQ5NiwzNjUwOCwzNjUxMCwzNTk2MCwzNTk3MCwzNTk3OCwzNTk3MywzNTk5MiwzNTk4OCwyNjAxMSwzNTI4NiwzNTI5NCwzNTI5MCwzNTI5MiwzOTkwMCwzOTkwMSwzOTkwMiwzOTkwMywzOTkwNCwzOTkwNSwzOTkwNiwzOTkwNywzOTkwOCwzOTkwOSwzOTkxMCwzOTkxMSwzOTkxMiwzOTkxMywzOTkxNCwzOTkxNSwzOTkxNiwzOTkxNywzOTkxOCwzOTkxOSwzOTkyMCwzOTkyMSwzOTkyMiwzOTkyMywzOTkyNCwzOTkyNSwzOTkyNiwzOTkyNywzOTkyOCwzOTkyOSwzOTkzMCwzOTkzMSwzOTkzMiwzOTkzMywzOTkzNCwzOTkzNSwzOTkzNiwzOTkzNywzOTkzOCwzOTkzOSwzOTk0MCwzOTk0MSwzOTk0MiwzOTk0MywzOTk0NCwzOTk0NSwzOTk0NiwzOTk0NywzOTk0OCwzOTk0OSwzOTk1MCwzOTk1MSwzOTk1MiwzOTk1MywzOTk1NCwzOTk1NSwzOTk1NiwzOTk1NywzOTk1OCwzOTk1OSwzOTk2MCwzOTk2MSwzOTk2MiwzOTk2MywzOTk2NCwzOTk2NSwzOTk2NiwzOTk2NywzOTk2OCwzOTk2OSwzOTk3MCwzOTk3MSwzOTk3MiwzOTk3MywzOTk3NCwzOTk3NSwzOTk3NiwzOTk3NywzOTk3OCwzOTk3OSwzOTk4MCwzOTk4MSwzOTk4MiwzOTk4MywzOTk4NCwzOTk4NSwzOTk4NiwzOTk4NywzOTk4OCwzOTk4OSwzOTk5MCwzOTk5MSwzOTk5MiwzOTk5MywzOTk5NCwzOTk5NSwzNTMwMSwzNTMwNywzNTMxMSwzNTM5MCwzNTYyMiwzODczOSwzODYzMywzODY0MywzODYzOSwzODY2MiwzODY1NywzODY2NCwzODY3MSwzODY3MCwzODY5OCwzODcwMSwzODcwNCwzODcxOCw0MDgzMiw0MDgzNSw0MDgzNyw0MDgzOCw0MDgzOSw0MDg0MCw0MDg0MSw0MDg0Miw0MDg0NCw0MDcwMiw0MDcxNSw0MDcxNywzODU4NSwzODU4OCwzODU4OSwzODYwNiwzODYxMCwzMDY1NSwzODYyNCwzNzUxOCwzNzU1MCwzNzU3NiwzNzY5NCwzNzczOCwzNzgzNCwzNzc3NSwzNzk1MCwzNzk5NSw0MDA2Myw0MDA2Niw0MDA2OSw0MDA3MCw0MDA3MSw0MDA3MiwzMTI2Nyw0MDA3NSw0MDA3OCw0MDA4MCw0MDA4MSw0MDA4Miw0MDA4NCw0MDA4NSw0MDA5MCw0MDA5MSw0MDA5NCw0MDA5NSw0MDA5Niw0MDA5Nyw0MDA5OCw0MDA5OSw0MDEwMSw0MDEwMiw0MDEwMyw0MDEwNCw0MDEwNSw0MDEwNyw0MDEwOSw0MDExMCw0MDExMiw0MDExMyw0MDExNCw0MDExNSw0MDExNiw0MDExNyw0MDExOCw0MDExOSw0MDEyMiw0MDEyMyw0MDEyNCw0MDEyNSw0MDEzMiw0MDEzMyw0MDEzNCw0MDEzNSw0MDEzOCw0MDEzOSwzOTk5NiwzOTk5NywzOTk5OCwzOTk5OSw0MDAwMCw0MDAwMSw0MDAwMiw0MDAwMyw0MDAwNCw0MDAwNSw0MDAwNiw0MDAwNyw0MDAwOCw0MDAwOSw0MDAxMCw0MDAxMSw0MDAxMiw0MDAxMyw0MDAxNCw0MDAxNSw0MDAxNiw0MDAxNyw0MDAxOCw0MDAxOSw0MDAyMCw0MDAyMSw0MDAyMiw0MDAyMyw0MDAyNCw0MDAyNSw0MDAyNiw0MDAyNyw0MDAyOCw0MDAyOSw0MDAzMCw0MDAzMSw0MDAzMiw0MDAzMyw0MDAzNCw0MDAzNSw0MDAzNiw0MDAzNyw0MDAzOCw0MDAzOSw0MDA0MCw0MDA0MSw0MDA0Miw0MDA0Myw0MDA0NCw0MDA0NSw0MDA0Niw0MDA0Nyw0MDA0OCw0MDA0OSw0MDA1MCw0MDA1MSw0MDA1Miw0MDA1Myw0MDA1NCw0MDA1NSw0MDA1Niw0MDA1Nyw0MDA1OCw0MDA1OSw0MDA2MSw0MDA2Miw0MDA2NCw0MDA2Nyw0MDA2OCw0MDA3Myw0MDA3NCw0MDA3Niw0MDA3OSw0MDA4Myw0MDA4Niw0MDA4Nyw0MDA4OCw0MDA4OSw0MDA5Myw0MDEwNiw0MDEwOCw0MDExMSw0MDEyMSw0MDEyNiw0MDEyNyw0MDEyOCw0MDEyOSw0MDEzMCw0MDEzNiw0MDEzNyw0MDE0NSw0MDE0Niw0MDE1NCw0MDE1NSw0MDE2MCw0MDE2MSw0MDE0MCw0MDE0MSw0MDE0Miw0MDE0Myw0MDE0NCw0MDE0Nyw0MDE0OCw0MDE0OSw0MDE1MSw0MDE1Miw0MDE1Myw0MDE1Niw0MDE1Nyw0MDE1OSw0MDE2MiwzODc4MCwzODc4OSwzODgwMSwzODgwMiwzODgwNCwzODgzMSwzODgyNywzODgxOSwzODgzNCwzODgzNiwzOTYwMSwzOTYwMCwzOTYwNyw0MDUzNiwzOTYwNiwzOTYxMCwzOTYxMiwzOTYxNywzOTYxNiwzOTYyMSwzOTYxOCwzOTYyNywzOTYyOCwzOTYzMywzOTc0OSwzOTc0NywzOTc1MSwzOTc1MywzOTc1MiwzOTc1NywzOTc2MSwzOTE0NCwzOTE4MSwzOTIxNCwzOTI1MywzOTI1MiwzOTY0NywzOTY0OSwzOTY1NCwzOTY2MywzOTY1OSwzOTY3NSwzOTY2MSwzOTY3MywzOTY4OCwzOTY5NSwzOTY5OSwzOTcxMSwzOTcxNSw0MDYzNyw0MDYzOCwzMjMxNSw0MDU3OCw0MDU4Myw0MDU4NCw0MDU4Nyw0MDU5NCwzNzg0Niw0MDYwNSw0MDYwNyw0MDY2Nyw0MDY2OCw0MDY2OSw0MDY3Miw0MDY3MSw0MDY3NCw0MDY4MSw0MDY3OSw0MDY3Nyw0MDY4Miw0MDY4Nyw0MDczOCw0MDc0OCw0MDc1MSw0MDc2MSw0MDc1OSw0MDc2NSw0MDc2Niw0MDc3Miw0MDE2Myw0MDE2NCw0MDE2NSw0MDE2Niw0MDE2Nyw0MDE2OCw0MDE2OSw0MDE3MCw0MDE3MSw0MDE3Miw0MDE3Myw0MDE3NCw0MDE3NSw0MDE3Niw0MDE3Nyw0MDE3OCw0MDE3OSw0MDE4MCw0MDE4MSw0MDE4Miw0MDE4Myw0MDE4NCw0MDE4NSw0MDE4Niw0MDE4Nyw0MDE4OCw0MDE4OSw0MDE5MCw0MDE5MSw0MDE5Miw0MDE5Myw0MDE5NCw0MDE5NSw0MDE5Niw0MDE5Nyw0MDE5OCw0MDE5OSw0MDIwMCw0MDIwMSw0MDIwMiw0MDIwMyw0MDIwNCw0MDIwNSw0MDIwNiw0MDIwNyw0MDIwOCw0MDIwOSw0MDIxMCw0MDIxMSw0MDIxMiw0MDIxMyw0MDIxNCw0MDIxNSw0MDIxNiw0MDIxNyw0MDIxOCw0MDIxOSw0MDIyMCw0MDIyMSw0MDIyMiw0MDIyMyw0MDIyNCw0MDIyNSw0MDIyNiw0MDIyNyw0MDIyOCw0MDIyOSw0MDIzMCw0MDIzMSw0MDIzMiw0MDIzMyw0MDIzNCw0MDIzNSw0MDIzNiw0MDIzNyw0MDIzOCw0MDIzOSw0MDI0MCw0MDI0MSw0MDI0Miw0MDI0Myw0MDI0NCw0MDI0NSw0MDI0Niw0MDI0Nyw0MDI0OCw0MDI0OSw0MDI1MCw0MDI1MSw0MDI1Miw0MDI1Myw0MDI1NCw0MDI1NSw0MDI1Niw0MDI1Nyw0MDI1OCw1NzkwOCw1NzkwOSw1NzkxMCw1NzkxMSw1NzkxMiw1NzkxMyw1NzkxNCw1NzkxNSw1NzkxNiw1NzkxNyw1NzkxOCw1NzkxOSw1NzkyMCw1NzkyMSw1NzkyMiw1NzkyMyw1NzkyNCw1NzkyNSw1NzkyNiw1NzkyNyw1NzkyOCw1NzkyOSw1NzkzMCw1NzkzMSw1NzkzMiw1NzkzMyw1NzkzNCw1NzkzNSw1NzkzNiw1NzkzNyw1NzkzOCw1NzkzOSw1Nzk0MCw1Nzk0MSw1Nzk0Miw1Nzk0Myw1Nzk0NCw1Nzk0NSw1Nzk0Niw1Nzk0Nyw1Nzk0OCw1Nzk0OSw1Nzk1MCw1Nzk1MSw1Nzk1Miw1Nzk1Myw1Nzk1NCw1Nzk1NSw1Nzk1Niw1Nzk1Nyw1Nzk1OCw1Nzk1OSw1Nzk2MCw1Nzk2MSw1Nzk2Miw1Nzk2Myw1Nzk2NCw1Nzk2NSw1Nzk2Niw1Nzk2Nyw1Nzk2OCw1Nzk2OSw1Nzk3MCw1Nzk3MSw1Nzk3Miw1Nzk3Myw1Nzk3NCw1Nzk3NSw1Nzk3Niw1Nzk3Nyw1Nzk3OCw1Nzk3OSw1Nzk4MCw1Nzk4MSw1Nzk4Miw1Nzk4Myw1Nzk4NCw1Nzk4NSw1Nzk4Niw1Nzk4Nyw1Nzk4OCw1Nzk4OSw1Nzk5MCw1Nzk5MSw1Nzk5Miw1Nzk5Myw1Nzk5NCw1Nzk5NSw1Nzk5Niw1Nzk5Nyw1Nzk5OCw1Nzk5OSw1ODAwMCw1ODAwMSw0MDI1OSw0MDI2MCw0MDI2MSw0MDI2Miw0MDI2Myw0MDI2NCw0MDI2NSw0MDI2Niw0MDI2Nyw0MDI2OCw0MDI2OSw0MDI3MCw0MDI3MSw0MDI3Miw0MDI3Myw0MDI3NCw0MDI3NSw0MDI3Niw0MDI3Nyw0MDI3OCw0MDI3OSw0MDI4MCw0MDI4MSw0MDI4Miw0MDI4Myw0MDI4NCw0MDI4NSw0MDI4Niw0MDI4Nyw0MDI4OCw0MDI4OSw0MDI5MCw0MDI5MSw0MDI5Miw0MDI5Myw0MDI5NCw0MDI5NSw0MDI5Niw0MDI5Nyw0MDI5OCw0MDI5OSw0MDMwMCw0MDMwMSw0MDMwMiw0MDMwMyw0MDMwNCw0MDMwNSw0MDMwNiw0MDMwNyw0MDMwOCw0MDMwOSw0MDMxMCw0MDMxMSw0MDMxMiw0MDMxMyw0MDMxNCw0MDMxNSw0MDMxNiw0MDMxNyw0MDMxOCw0MDMxOSw0MDMyMCw0MDMyMSw0MDMyMiw0MDMyMyw0MDMyNCw0MDMyNSw0MDMyNiw0MDMyNyw0MDMyOCw0MDMyOSw0MDMzMCw0MDMzMSw0MDMzMiw0MDMzMyw0MDMzNCw0MDMzNSw0MDMzNiw0MDMzNyw0MDMzOCw0MDMzOSw0MDM0MCw0MDM0MSw0MDM0Miw0MDM0Myw0MDM0NCw0MDM0NSw0MDM0Niw0MDM0Nyw0MDM0OCw0MDM0OSw0MDM1MCw0MDM1MSw0MDM1Miw0MDM1Myw0MDM1NCw1ODAwMiw1ODAwMyw1ODAwNCw1ODAwNSw1ODAwNiw1ODAwNyw1ODAwOCw1ODAwOSw1ODAxMCw1ODAxMSw1ODAxMiw1ODAxMyw1ODAxNCw1ODAxNSw1ODAxNiw1ODAxNyw1ODAxOCw1ODAxOSw1ODAyMCw1ODAyMSw1ODAyMiw1ODAyMyw1ODAyNCw1ODAyNSw1ODAyNiw1ODAyNyw1ODAyOCw1ODAyOSw1ODAzMCw1ODAzMSw1ODAzMiw1ODAzMyw1ODAzNCw1ODAzNSw1ODAzNiw1ODAzNyw1ODAzOCw1ODAzOSw1ODA0MCw1ODA0MSw1ODA0Miw1ODA0Myw1ODA0NCw1ODA0NSw1ODA0Niw1ODA0Nyw1ODA0OCw1ODA0OSw1ODA1MCw1ODA1MSw1ODA1Miw1ODA1Myw1ODA1NCw1ODA1NSw1ODA1Niw1ODA1Nyw1ODA1OCw1ODA1OSw1ODA2MCw1ODA2MSw1ODA2Miw1ODA2Myw1ODA2NCw1ODA2NSw1ODA2Niw1ODA2Nyw1ODA2OCw1ODA2OSw1ODA3MCw1ODA3MSw1ODA3Miw1ODA3Myw1ODA3NCw1ODA3NSw1ODA3Niw1ODA3Nyw1ODA3OCw1ODA3OSw1ODA4MCw1ODA4MSw1ODA4Miw1ODA4Myw1ODA4NCw1ODA4NSw1ODA4Niw1ODA4Nyw1ODA4OCw1ODA4OSw1ODA5MCw1ODA5MSw1ODA5Miw1ODA5Myw1ODA5NCw1ODA5NSw0MDM1NSw0MDM1Niw0MDM1Nyw0MDM1OCw0MDM1OSw0MDM2MCw0MDM2MSw0MDM2Miw0MDM2Myw0MDM2NCw0MDM2NSw0MDM2Niw0MDM2Nyw0MDM2OCw0MDM2OSw0MDM3MCw0MDM3MSw0MDM3Miw0MDM3Myw0MDM3NCw0MDM3NSw0MDM3Niw0MDM3Nyw0MDM3OCw0MDM3OSw0MDM4MCw0MDM4MSw0MDM4Miw0MDM4Myw0MDM4NCw0MDM4NSw0MDM4Niw0MDM4Nyw0MDM4OCw0MDM4OSw0MDM5MCw0MDM5MSw0MDM5Miw0MDM5Myw0MDM5NCw0MDM5NSw0MDM5Niw0MDM5Nyw0MDM5OCw0MDM5OSw0MDQwMCw0MDQwMSw0MDQwMiw0MDQwMyw0MDQwNCw0MDQwNSw0MDQwNiw0MDQwNyw0MDQwOCw0MDQwOSw0MDQxMCw0MDQxMSw0MDQxMiw0MDQxMyw0MDQxNCw0MDQxNSw0MDQxNiw0MDQxNyw0MDQxOCw0MDQxOSw0MDQyMCw0MDQyMSw0MDQyMiw0MDQyMyw0MDQyNCw0MDQyNSw0MDQyNiw0MDQyNyw0MDQyOCw0MDQyOSw0MDQzMCw0MDQzMSw0MDQzMiw0MDQzMyw0MDQzNCw0MDQzNSw0MDQzNiw0MDQzNyw0MDQzOCw0MDQzOSw0MDQ0MCw0MDQ0MSw0MDQ0Miw0MDQ0Myw0MDQ0NCw0MDQ0NSw0MDQ0Niw0MDQ0Nyw0MDQ0OCw0MDQ0OSw0MDQ1MCw1ODA5Niw1ODA5Nyw1ODA5OCw1ODA5OSw1ODEwMCw1ODEwMSw1ODEwMiw1ODEwMyw1ODEwNCw1ODEwNSw1ODEwNiw1ODEwNyw1ODEwOCw1ODEwOSw1ODExMCw1ODExMSw1ODExMiw1ODExMyw1ODExNCw1ODExNSw1ODExNiw1ODExNyw1ODExOCw1ODExOSw1ODEyMCw1ODEyMSw1ODEyMiw1ODEyMyw1ODEyNCw1ODEyNSw1ODEyNiw1ODEyNyw1ODEyOCw1ODEyOSw1ODEzMCw1ODEzMSw1ODEzMiw1ODEzMyw1ODEzNCw1ODEzNSw1ODEzNiw1ODEzNyw1ODEzOCw1ODEzOSw1ODE0MCw1ODE0MSw1ODE0Miw1ODE0Myw1ODE0NCw1ODE0NSw1ODE0Niw1ODE0Nyw1ODE0OCw1ODE0OSw1ODE1MCw1ODE1MSw1ODE1Miw1ODE1Myw1ODE1NCw1ODE1NSw1ODE1Niw1ODE1Nyw1ODE1OCw1ODE1OSw1ODE2MCw1ODE2MSw1ODE2Miw1ODE2Myw1ODE2NCw1ODE2NSw1ODE2Niw1ODE2Nyw1ODE2OCw1ODE2OSw1ODE3MCw1ODE3MSw1ODE3Miw1ODE3Myw1ODE3NCw1ODE3NSw1ODE3Niw1ODE3Nyw1ODE3OCw1ODE3OSw1ODE4MCw1ODE4MSw1ODE4Miw1ODE4Myw1ODE4NCw1ODE4NSw1ODE4Niw1ODE4Nyw1ODE4OCw1ODE4OSw0MDQ1MSw0MDQ1Miw0MDQ1Myw0MDQ1NCw0MDQ1NSw0MDQ1Niw0MDQ1Nyw0MDQ1OCw0MDQ1OSw0MDQ2MCw0MDQ2MSw0MDQ2Miw0MDQ2Myw0MDQ2NCw0MDQ2NSw0MDQ2Niw0MDQ2Nyw0MDQ2OCw0MDQ2OSw0MDQ3MCw0MDQ3MSw0MDQ3Miw0MDQ3Myw0MDQ3NCw0MDQ3NSw0MDQ3Niw0MDQ3Nyw0MDQ3OCw0MDQ4NCw0MDQ4Nyw0MDQ5NCw0MDQ5Niw0MDUwMCw0MDUwNyw0MDUwOCw0MDUxMiw0MDUyNSw0MDUyOCw0MDUzMCw0MDUzMSw0MDUzMiw0MDUzNCw0MDUzNyw0MDU0MSw0MDU0Myw0MDU0NCw0MDU0NSw0MDU0Niw0MDU0OSw0MDU1OCw0MDU1OSw0MDU2Miw0MDU2NCw0MDU2NSw0MDU2Niw0MDU2Nyw0MDU2OCw0MDU2OSw0MDU3MCw0MDU3MSw0MDU3Miw0MDU3Myw0MDU3Niw0MDU3Nyw0MDU3OSw0MDU4MCw0MDU4MSw0MDU4Miw0MDU4NSw0MDU4Niw0MDU4OCw0MDU4OSw0MDU5MCw0MDU5MSw0MDU5Miw0MDU5Myw0MDU5Niw0MDU5Nyw0MDU5OCw0MDU5OSw0MDYwMCw0MDYwMSw0MDYwMiw0MDYwMyw0MDYwNCw0MDYwNiw0MDYwOCw0MDYwOSw0MDYxMCw0MDYxMSw0MDYxMiw0MDYxMyw0MDYxNSw0MDYxNiw0MDYxNyw0MDYxOCw1ODE5MCw1ODE5MSw1ODE5Miw1ODE5Myw1ODE5NCw1ODE5NSw1ODE5Niw1ODE5Nyw1ODE5OCw1ODE5OSw1ODIwMCw1ODIwMSw1ODIwMiw1ODIwMyw1ODIwNCw1ODIwNSw1ODIwNiw1ODIwNyw1ODIwOCw1ODIwOSw1ODIxMCw1ODIxMSw1ODIxMiw1ODIxMyw1ODIxNCw1ODIxNSw1ODIxNiw1ODIxNyw1ODIxOCw1ODIxOSw1ODIyMCw1ODIyMSw1ODIyMiw1ODIyMyw1ODIyNCw1ODIyNSw1ODIyNiw1ODIyNyw1ODIyOCw1ODIyOSw1ODIzMCw1ODIzMSw1ODIzMiw1ODIzMyw1ODIzNCw1ODIzNSw1ODIzNiw1ODIzNyw1ODIzOCw1ODIzOSw1ODI0MCw1ODI0MSw1ODI0Miw1ODI0Myw1ODI0NCw1ODI0NSw1ODI0Niw1ODI0Nyw1ODI0OCw1ODI0OSw1ODI1MCw1ODI1MSw1ODI1Miw1ODI1Myw1ODI1NCw1ODI1NSw1ODI1Niw1ODI1Nyw1ODI1OCw1ODI1OSw1ODI2MCw1ODI2MSw1ODI2Miw1ODI2Myw1ODI2NCw1ODI2NSw1ODI2Niw1ODI2Nyw1ODI2OCw1ODI2OSw1ODI3MCw1ODI3MSw1ODI3Miw1ODI3Myw1ODI3NCw1ODI3NSw1ODI3Niw1ODI3Nyw1ODI3OCw1ODI3OSw1ODI4MCw1ODI4MSw1ODI4Miw1ODI4Myw0MDYxOSw0MDYyMCw0MDYyMSw0MDYyMiw0MDYyMyw0MDYyNCw0MDYyNSw0MDYyNiw0MDYyNyw0MDYyOSw0MDYzMCw0MDYzMSw0MDYzMyw0MDYzNCw0MDYzNiw0MDYzOSw0MDY0MCw0MDY0MSw0MDY0Miw0MDY0Myw0MDY0NSw0MDY0Niw0MDY0Nyw0MDY0OCw0MDY1MCw0MDY1MSw0MDY1Miw0MDY1Niw0MDY1OCw0MDY1OSw0MDY2MSw0MDY2Miw0MDY2Myw0MDY2NSw0MDY2Niw0MDY3MCw0MDY3Myw0MDY3NSw0MDY3Niw0MDY3OCw0MDY4MCw0MDY4Myw0MDY4NCw0MDY4NSw0MDY4Niw0MDY4OCw0MDY4OSw0MDY5MCw0MDY5MSw0MDY5Miw0MDY5Myw0MDY5NCw0MDY5NSw0MDY5Niw0MDY5OCw0MDcwMSw0MDcwMyw0MDcwNCw0MDcwNSw0MDcwNiw0MDcwNyw0MDcwOCw0MDcwOSw0MDcxMCw0MDcxMSw0MDcxMiw0MDcxMyw0MDcxNCw0MDcxNiw0MDcxOSw0MDcyMSw0MDcyMiw0MDcyNCw0MDcyNSw0MDcyNiw0MDcyOCw0MDczMCw0MDczMSw0MDczMiw0MDczMyw0MDczNCw0MDczNSw0MDczNyw0MDczOSw0MDc0MCw0MDc0MSw0MDc0Miw0MDc0Myw0MDc0NCw0MDc0NSw0MDc0Niw0MDc0Nyw0MDc0OSw0MDc1MCw0MDc1Miw0MDc1Myw1ODI4NCw1ODI4NSw1ODI4Niw1ODI4Nyw1ODI4OCw1ODI4OSw1ODI5MCw1ODI5MSw1ODI5Miw1ODI5Myw1ODI5NCw1ODI5NSw1ODI5Niw1ODI5Nyw1ODI5OCw1ODI5OSw1ODMwMCw1ODMwMSw1ODMwMiw1ODMwMyw1ODMwNCw1ODMwNSw1ODMwNiw1ODMwNyw1ODMwOCw1ODMwOSw1ODMxMCw1ODMxMSw1ODMxMiw1ODMxMyw1ODMxNCw1ODMxNSw1ODMxNiw1ODMxNyw1ODMxOCw1ODMxOSw1ODMyMCw1ODMyMSw1ODMyMiw1ODMyMyw1ODMyNCw1ODMyNSw1ODMyNiw1ODMyNyw1ODMyOCw1ODMyOSw1ODMzMCw1ODMzMSw1ODMzMiw1ODMzMyw1ODMzNCw1ODMzNSw1ODMzNiw1ODMzNyw1ODMzOCw1ODMzOSw1ODM0MCw1ODM0MSw1ODM0Miw1ODM0Myw1ODM0NCw1ODM0NSw1ODM0Niw1ODM0Nyw1ODM0OCw1ODM0OSw1ODM1MCw1ODM1MSw1ODM1Miw1ODM1Myw1ODM1NCw1ODM1NSw1ODM1Niw1ODM1Nyw1ODM1OCw1ODM1OSw1ODM2MCw1ODM2MSw1ODM2Miw1ODM2Myw1ODM2NCw1ODM2NSw1ODM2Niw1ODM2Nyw1ODM2OCw1ODM2OSw1ODM3MCw1ODM3MSw1ODM3Miw1ODM3Myw1ODM3NCw1ODM3NSw1ODM3Niw1ODM3Nyw0MDc1NCw0MDc1NSw0MDc1Niw0MDc1Nyw0MDc1OCw0MDc2MCw0MDc2Miw0MDc2NCw0MDc2Nyw0MDc2OCw0MDc2OSw0MDc3MCw0MDc3MSw0MDc3Myw0MDc3NCw0MDc3NSw0MDc3Niw0MDc3Nyw0MDc3OCw0MDc3OSw0MDc4MCw0MDc4MSw0MDc4Miw0MDc4Myw0MDc4Niw0MDc4Nyw0MDc4OCw0MDc4OSw0MDc5MCw0MDc5MSw0MDc5Miw0MDc5Myw0MDc5NCw0MDc5NSw0MDc5Niw0MDc5Nyw0MDc5OCw0MDc5OSw0MDgwMCw0MDgwMSw0MDgwMiw0MDgwMyw0MDgwNCw0MDgwNSw0MDgwNiw0MDgwNyw0MDgwOCw0MDgwOSw0MDgxMCw0MDgxMSw0MDgxMiw0MDgxMyw0MDgxNCw0MDgxNSw0MDgxNiw0MDgxNyw0MDgxOCw0MDgxOSw0MDgyMCw0MDgyMSw0MDgyMiw0MDgyMyw0MDgyNCw0MDgyNSw0MDgyNiw0MDgyNyw0MDgyOCw0MDgyOSw0MDgzMCw0MDgzMyw0MDgzNCw0MDg0NSw0MDg0Niw0MDg0Nyw0MDg0OCw0MDg0OSw0MDg1MCw0MDg1MSw0MDg1Miw0MDg1Myw0MDg1NCw0MDg1NSw0MDg1Niw0MDg2MCw0MDg2MSw0MDg2Miw0MDg2NSw0MDg2Niw0MDg2Nyw0MDg2OCw0MDg2OSw2Mzc4OCw2Mzg2NSw2Mzg5Myw2Mzk3NSw2Mzk4NSw1ODM3OCw1ODM3OSw1ODM4MCw1ODM4MSw1ODM4Miw1ODM4Myw1ODM4NCw1ODM4NSw1ODM4Niw1ODM4Nyw1ODM4OCw1ODM4OSw1ODM5MCw1ODM5MSw1ODM5Miw1ODM5Myw1ODM5NCw1ODM5NSw1ODM5Niw1ODM5Nyw1ODM5OCw1ODM5OSw1ODQwMCw1ODQwMSw1ODQwMiw1ODQwMyw1ODQwNCw1ODQwNSw1ODQwNiw1ODQwNyw1ODQwOCw1ODQwOSw1ODQxMCw1ODQxMSw1ODQxMiw1ODQxMyw1ODQxNCw1ODQxNSw1ODQxNiw1ODQxNyw1ODQxOCw1ODQxOSw1ODQyMCw1ODQyMSw1ODQyMiw1ODQyMyw1ODQyNCw1ODQyNSw1ODQyNiw1ODQyNyw1ODQyOCw1ODQyOSw1ODQzMCw1ODQzMSw1ODQzMiw1ODQzMyw1ODQzNCw1ODQzNSw1ODQzNiw1ODQzNyw1ODQzOCw1ODQzOSw1ODQ0MCw1ODQ0MSw1ODQ0Miw1ODQ0Myw1ODQ0NCw1ODQ0NSw1ODQ0Niw1ODQ0Nyw1ODQ0OCw1ODQ0OSw1ODQ1MCw1ODQ1MSw1ODQ1Miw1ODQ1Myw1ODQ1NCw1ODQ1NSw1ODQ1Niw1ODQ1Nyw1ODQ1OCw1ODQ1OSw1ODQ2MCw1ODQ2MSw1ODQ2Miw1ODQ2Myw1ODQ2NCw1ODQ2NSw1ODQ2Niw1ODQ2Nyw1ODQ2OCw1ODQ2OSw1ODQ3MCw1ODQ3MSw2NDAxMiw2NDAxMyw2NDAxNCw2NDAxNSw2NDAxNyw2NDAxOSw2NDAyMCw2NDAyNCw2NDAzMSw2NDAzMiw2NDAzMyw2NDAzNSw2NDAzNiw2NDAzOSw2NDA0MCw2NDA0MSwxMTkwNSw1OTQxNCw1OTQxNSw1OTQxNiwxMTkwOCwxMzQyNywxMzM4MywxMTkxMiwxMTkxNSw1OTQyMiwxMzcyNiwxMzg1MCwxMzgzOCwxMTkxNiwxMTkyNywxNDcwMiwxNDYxNiw1OTQzMCwxNDc5OSwxNDgxNSwxNDk2MywxNDgwMCw1OTQzNSw1OTQzNiwxNTE4MiwxNTQ3MCwxNTU4NCwxMTk0Myw1OTQ0MSw1OTQ0MiwxMTk0NiwxNjQ3MCwxNjczNSwxMTk1MCwxNzIwNywxMTk1NSwxMTk1OCwxMTk1OSw1OTQ1MSwxNzMyOSwxNzMyNCwxMTk2MywxNzM3MywxNzYyMiwxODAxNywxNzk5Niw1OTQ1OSwxODIxMSwxODIxNywxODMwMCwxODMxNywxMTk3OCwxODc1OSwxODgxMCwxODgxMywxODgxOCwxODgxOSwxODgyMSwxODgyMiwxODg0NywxODg0MywxODg3MSwxODg3MCw1OTQ3Niw1OTQ3NywxOTYxOSwxOTYxNSwxOTYxNiwxOTYxNywxOTU3NSwxOTYxOCwxOTczMSwxOTczMiwxOTczMywxOTczNCwxOTczNSwxOTczNiwxOTczNywxOTg4Niw1OTQ5Miw1ODQ3Miw1ODQ3Myw1ODQ3NCw1ODQ3NSw1ODQ3Niw1ODQ3Nyw1ODQ3OCw1ODQ3OSw1ODQ4MCw1ODQ4MSw1ODQ4Miw1ODQ4Myw1ODQ4NCw1ODQ4NSw1ODQ4Niw1ODQ4Nyw1ODQ4OCw1ODQ4OSw1ODQ5MCw1ODQ5MSw1ODQ5Miw1ODQ5Myw1ODQ5NCw1ODQ5NSw1ODQ5Niw1ODQ5Nyw1ODQ5OCw1ODQ5OSw1ODUwMCw1ODUwMSw1ODUwMiw1ODUwMyw1ODUwNCw1ODUwNSw1ODUwNiw1ODUwNyw1ODUwOCw1ODUwOSw1ODUxMCw1ODUxMSw1ODUxMiw1ODUxMyw1ODUxNCw1ODUxNSw1ODUxNiw1ODUxNyw1ODUxOCw1ODUxOSw1ODUyMCw1ODUyMSw1ODUyMiw1ODUyMyw1ODUyNCw1ODUyNSw1ODUyNiw1ODUyNyw1ODUyOCw1ODUyOSw1ODUzMCw1ODUzMSw1ODUzMiw1ODUzMyw1ODUzNCw1ODUzNSw1ODUzNiw1ODUzNyw1ODUzOCw1ODUzOSw1ODU0MCw1ODU0MSw1ODU0Miw1ODU0Myw1ODU0NCw1ODU0NSw1ODU0Niw1ODU0Nyw1ODU0OCw1ODU0OSw1ODU1MCw1ODU1MSw1ODU1Miw1ODU1Myw1ODU1NCw1ODU1NSw1ODU1Niw1ODU1Nyw1ODU1OCw1ODU1OSw1ODU2MCw1ODU2MSw1ODU2Miw1ODU2Myw1ODU2NCw1ODU2NV0sXG4gIFwiZ2IxODAzMC1yYW5nZXNcIjpbWzAsMTI4XSxbMzYsMTY1XSxbMzgsMTY5XSxbNDUsMTc4XSxbNTAsMTg0XSxbODEsMjE2XSxbODksMjI2XSxbOTUsMjM1XSxbOTYsMjM4XSxbMTAwLDI0NF0sWzEwMywyNDhdLFsxMDQsMjUxXSxbMTA1LDI1M10sWzEwOSwyNThdLFsxMjYsMjc2XSxbMTMzLDI4NF0sWzE0OCwzMDBdLFsxNzIsMzI1XSxbMTc1LDMyOV0sWzE3OSwzMzRdLFsyMDgsMzY0XSxbMzA2LDQ2M10sWzMwNyw0NjVdLFszMDgsNDY3XSxbMzA5LDQ2OV0sWzMxMCw0NzFdLFszMTEsNDczXSxbMzEyLDQ3NV0sWzMxMyw0NzddLFszNDEsNTA2XSxbNDI4LDU5NF0sWzQ0Myw2MTBdLFs1NDQsNzEyXSxbNTQ1LDcxNl0sWzU1OCw3MzBdLFs3NDEsOTMwXSxbNzQyLDkzOF0sWzc0OSw5NjJdLFs3NTAsOTcwXSxbODA1LDEwMjZdLFs4MTksMTEwNF0sWzgyMCwxMTA2XSxbNzkyMiw4MjA5XSxbNzkyNCw4MjE1XSxbNzkyNSw4MjE4XSxbNzkyNyw4MjIyXSxbNzkzNCw4MjMxXSxbNzk0Myw4MjQxXSxbNzk0NCw4MjQ0XSxbNzk0NSw4MjQ2XSxbNzk1MCw4MjUyXSxbODA2Miw4MzY1XSxbODE0OCw4NDUyXSxbODE0OSw4NDU0XSxbODE1Miw4NDU4XSxbODE2NCw4NDcxXSxbODE3NCw4NDgyXSxbODIzNiw4NTU2XSxbODI0MCw4NTcwXSxbODI2Miw4NTk2XSxbODI2NCw4NjAyXSxbODM3NCw4NzEzXSxbODM4MCw4NzIwXSxbODM4MSw4NzIyXSxbODM4NCw4NzI2XSxbODM4OCw4NzMxXSxbODM5MCw4NzM3XSxbODM5Miw4NzQwXSxbODM5Myw4NzQyXSxbODM5NCw4NzQ4XSxbODM5Niw4NzUxXSxbODQwMSw4NzYwXSxbODQwNiw4NzY2XSxbODQxNiw4Nzc3XSxbODQxOSw4NzgxXSxbODQyNCw4Nzg3XSxbODQzNyw4ODAyXSxbODQzOSw4ODA4XSxbODQ0NSw4ODE2XSxbODQ4Miw4ODU0XSxbODQ4NSw4ODU4XSxbODQ5Niw4ODcwXSxbODUyMSw4ODk2XSxbODYwMyw4OTc5XSxbODkzNiw5MzIyXSxbODk0Niw5MzcyXSxbOTA0Niw5NTQ4XSxbOTA1MCw5NTg4XSxbOTA2Myw5NjE2XSxbOTA2Niw5NjIyXSxbOTA3Niw5NjM0XSxbOTA5Miw5NjUyXSxbOTEwMCw5NjYyXSxbOTEwOCw5NjcyXSxbOTExMSw5Njc2XSxbOTExMyw5NjgwXSxbOTEzMSw5NzAyXSxbOTE2Miw5NzM1XSxbOTE2NCw5NzM4XSxbOTIxOCw5NzkzXSxbOTIxOSw5Nzk1XSxbMTEzMjksMTE5MDZdLFsxMTMzMSwxMTkwOV0sWzExMzM0LDExOTEzXSxbMTEzMzYsMTE5MTddLFsxMTM0NiwxMTkyOF0sWzExMzYxLDExOTQ0XSxbMTEzNjMsMTE5NDddLFsxMTM2NiwxMTk1MV0sWzExMzcwLDExOTU2XSxbMTEzNzIsMTE5NjBdLFsxMTM3NSwxMTk2NF0sWzExMzg5LDExOTc5XSxbMTE2ODIsMTIyODRdLFsxMTY4NiwxMjI5Ml0sWzExNjg3LDEyMzEyXSxbMTE2OTIsMTIzMTldLFsxMTY5NCwxMjMzMF0sWzExNzE0LDEyMzUxXSxbMTE3MTYsMTI0MzZdLFsxMTcyMywxMjQ0N10sWzExNzI1LDEyNTM1XSxbMTE3MzAsMTI1NDNdLFsxMTczNiwxMjU4Nl0sWzExOTgyLDEyODQyXSxbMTE5ODksMTI4NTBdLFsxMjEwMiwxMjk2NF0sWzEyMzM2LDEzMjAwXSxbMTIzNDgsMTMyMTVdLFsxMjM1MCwxMzIxOF0sWzEyMzg0LDEzMjUzXSxbMTIzOTMsMTMyNjNdLFsxMjM5NSwxMzI2N10sWzEyMzk3LDEzMjcwXSxbMTI1MTAsMTMzODRdLFsxMjU1MywxMzQyOF0sWzEyODUxLDEzNzI3XSxbMTI5NjIsMTM4MzldLFsxMjk3MywxMzg1MV0sWzEzNzM4LDE0NjE3XSxbMTM4MjMsMTQ3MDNdLFsxMzkxOSwxNDgwMV0sWzEzOTMzLDE0ODE2XSxbMTQwODAsMTQ5NjRdLFsxNDI5OCwxNTE4M10sWzE0NTg1LDE1NDcxXSxbMTQ2OTgsMTU1ODVdLFsxNTU4MywxNjQ3MV0sWzE1ODQ3LDE2NzM2XSxbMTYzMTgsMTcyMDhdLFsxNjQzNCwxNzMyNV0sWzE2NDM4LDE3MzMwXSxbMTY0ODEsMTczNzRdLFsxNjcyOSwxNzYyM10sWzE3MTAyLDE3OTk3XSxbMTcxMjIsMTgwMThdLFsxNzMxNSwxODIxMl0sWzE3MzIwLDE4MjE4XSxbMTc0MDIsMTgzMDFdLFsxNzQxOCwxODMxOF0sWzE3ODU5LDE4NzYwXSxbMTc5MDksMTg4MTFdLFsxNzkxMSwxODgxNF0sWzE3OTE1LDE4ODIwXSxbMTc5MTYsMTg4MjNdLFsxNzkzNiwxODg0NF0sWzE3OTM5LDE4ODQ4XSxbMTc5NjEsMTg4NzJdLFsxODY2NCwxOTU3Nl0sWzE4NzAzLDE5NjIwXSxbMTg4MTQsMTk3MzhdLFsxODk2MiwxOTg4N10sWzE5MDQzLDQwODcwXSxbMzM0NjksNTkyNDRdLFszMzQ3MCw1OTMzNl0sWzMzNDcxLDU5MzY3XSxbMzM0ODQsNTk0MTNdLFszMzQ4NSw1OTQxN10sWzMzNDkwLDU5NDIzXSxbMzM0OTcsNTk0MzFdLFszMzUwMSw1OTQzN10sWzMzNTA1LDU5NDQzXSxbMzM1MTMsNTk0NTJdLFszMzUyMCw1OTQ2MF0sWzMzNTM2LDU5NDc4XSxbMzM1NTAsNTk0OTNdLFszNzg0NSw2Mzc4OV0sWzM3OTIxLDYzODY2XSxbMzc5NDgsNjM4OTRdLFszODAyOSw2Mzk3Nl0sWzM4MDM4LDYzOTg2XSxbMzgwNjQsNjQwMTZdLFszODA2NSw2NDAxOF0sWzM4MDY2LDY0MDIxXSxbMzgwNjksNjQwMjVdLFszODA3NSw2NDAzNF0sWzM4MDc2LDY0MDM3XSxbMzgwNzgsNjQwNDJdLFszOTEwOCw2NTA3NF0sWzM5MTA5LDY1MDkzXSxbMzkxMTMsNjUxMDddLFszOTExNCw2NTExMl0sWzM5MTE1LDY1MTI3XSxbMzkxMTYsNjUxMzJdLFszOTI2NSw2NTM3NV0sWzM5Mzk0LDY1NTEwXSxbMTg5MDAwLDY1NTM2XV0sXG4gIFwiamlzMDIwOFwiOlsxMjI4OCwxMjI4OSwxMjI5MCw2NTI5Miw2NTI5NCwxMjUzOSw2NTMwNiw2NTMwNyw2NTMxMSw2NTI4MSwxMjQ0MywxMjQ0NCwxODAsNjUzNDQsMTY4LDY1MzQyLDY1NTA3LDY1MzQzLDEyNTQxLDEyNTQyLDEyNDQ1LDEyNDQ2LDEyMjkxLDIwMTg5LDEyMjkzLDEyMjk0LDEyMjk1LDEyNTQwLDgyMTMsODIwOCw2NTI5NSw2NTM0MCw2NTM3NCw4NzQxLDY1MzcyLDgyMzAsODIyOSw4MjE2LDgyMTcsODIyMCw4MjIxLDY1Mjg4LDY1Mjg5LDEyMzA4LDEyMzA5LDY1MzM5LDY1MzQxLDY1MzcxLDY1MzczLDEyMjk2LDEyMjk3LDEyMjk4LDEyMjk5LDEyMzAwLDEyMzAxLDEyMzAyLDEyMzAzLDEyMzA0LDEyMzA1LDY1MjkxLDY1MjkzLDE3NywyMTUsMjQ3LDY1MzA5LDg4MDAsNjUzMDgsNjUzMTAsODgwNiw4ODA3LDg3MzQsODc1Niw5Nzk0LDk3OTIsMTc2LDgyNDIsODI0Myw4NDUxLDY1NTA5LDY1Mjg0LDY1NTA0LDY1NTA1LDY1Mjg1LDY1MjgzLDY1Mjg2LDY1MjkwLDY1MzEyLDE2Nyw5NzM0LDk3MzMsOTY3NSw5Njc5LDk2NzgsOTY3MSw5NjcwLDk2MzMsOTYzMiw5NjUxLDk2NTAsOTY2MSw5NjYwLDgyNTEsMTIzMDYsODU5NCw4NTkyLDg1OTMsODU5NSwxMjMwNyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsODcxMiw4NzE1LDg4MzgsODgzOSw4ODM0LDg4MzUsODc0Niw4NzQ1LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw4NzQzLDg3NDQsNjU1MDYsODY1OCw4NjYwLDg3MDQsODcwNyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsODczNiw4ODY5LDg5NzgsODcwNiw4NzExLDg4MDEsODc4Niw4ODEwLDg4MTEsODczMCw4NzY1LDg3MzMsODc1Nyw4NzQ3LDg3NDgsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw4NDkxLDgyNDAsOTgzOSw5ODM3LDk4MzQsODIyNCw4MjI1LDE4MixudWxsLG51bGwsbnVsbCxudWxsLDk3MTEsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsNjUyOTYsNjUyOTcsNjUyOTgsNjUyOTksNjUzMDAsNjUzMDEsNjUzMDIsNjUzMDMsNjUzMDQsNjUzMDUsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw2NTMxMyw2NTMxNCw2NTMxNSw2NTMxNiw2NTMxNyw2NTMxOCw2NTMxOSw2NTMyMCw2NTMyMSw2NTMyMiw2NTMyMyw2NTMyNCw2NTMyNSw2NTMyNiw2NTMyNyw2NTMyOCw2NTMyOSw2NTMzMCw2NTMzMSw2NTMzMiw2NTMzMyw2NTMzNCw2NTMzNSw2NTMzNiw2NTMzNyw2NTMzOCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw2NTM0NSw2NTM0Niw2NTM0Nyw2NTM0OCw2NTM0OSw2NTM1MCw2NTM1MSw2NTM1Miw2NTM1Myw2NTM1NCw2NTM1NSw2NTM1Niw2NTM1Nyw2NTM1OCw2NTM1OSw2NTM2MCw2NTM2MSw2NTM2Miw2NTM2Myw2NTM2NCw2NTM2NSw2NTM2Niw2NTM2Nyw2NTM2OCw2NTM2OSw2NTM3MCxudWxsLG51bGwsbnVsbCxudWxsLDEyMzUzLDEyMzU0LDEyMzU1LDEyMzU2LDEyMzU3LDEyMzU4LDEyMzU5LDEyMzYwLDEyMzYxLDEyMzYyLDEyMzYzLDEyMzY0LDEyMzY1LDEyMzY2LDEyMzY3LDEyMzY4LDEyMzY5LDEyMzcwLDEyMzcxLDEyMzcyLDEyMzczLDEyMzc0LDEyMzc1LDEyMzc2LDEyMzc3LDEyMzc4LDEyMzc5LDEyMzgwLDEyMzgxLDEyMzgyLDEyMzgzLDEyMzg0LDEyMzg1LDEyMzg2LDEyMzg3LDEyMzg4LDEyMzg5LDEyMzkwLDEyMzkxLDEyMzkyLDEyMzkzLDEyMzk0LDEyMzk1LDEyMzk2LDEyMzk3LDEyMzk4LDEyMzk5LDEyNDAwLDEyNDAxLDEyNDAyLDEyNDAzLDEyNDA0LDEyNDA1LDEyNDA2LDEyNDA3LDEyNDA4LDEyNDA5LDEyNDEwLDEyNDExLDEyNDEyLDEyNDEzLDEyNDE0LDEyNDE1LDEyNDE2LDEyNDE3LDEyNDE4LDEyNDE5LDEyNDIwLDEyNDIxLDEyNDIyLDEyNDIzLDEyNDI0LDEyNDI1LDEyNDI2LDEyNDI3LDEyNDI4LDEyNDI5LDEyNDMwLDEyNDMxLDEyNDMyLDEyNDMzLDEyNDM0LDEyNDM1LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCwxMjQ0OSwxMjQ1MCwxMjQ1MSwxMjQ1MiwxMjQ1MywxMjQ1NCwxMjQ1NSwxMjQ1NiwxMjQ1NywxMjQ1OCwxMjQ1OSwxMjQ2MCwxMjQ2MSwxMjQ2MiwxMjQ2MywxMjQ2NCwxMjQ2NSwxMjQ2NiwxMjQ2NywxMjQ2OCwxMjQ2OSwxMjQ3MCwxMjQ3MSwxMjQ3MiwxMjQ3MywxMjQ3NCwxMjQ3NSwxMjQ3NiwxMjQ3NywxMjQ3OCwxMjQ3OSwxMjQ4MCwxMjQ4MSwxMjQ4MiwxMjQ4MywxMjQ4NCwxMjQ4NSwxMjQ4NiwxMjQ4NywxMjQ4OCwxMjQ4OSwxMjQ5MCwxMjQ5MSwxMjQ5MiwxMjQ5MywxMjQ5NCwxMjQ5NSwxMjQ5NiwxMjQ5NywxMjQ5OCwxMjQ5OSwxMjUwMCwxMjUwMSwxMjUwMiwxMjUwMywxMjUwNCwxMjUwNSwxMjUwNiwxMjUwNywxMjUwOCwxMjUwOSwxMjUxMCwxMjUxMSwxMjUxMiwxMjUxMywxMjUxNCwxMjUxNSwxMjUxNiwxMjUxNywxMjUxOCwxMjUxOSwxMjUyMCwxMjUyMSwxMjUyMiwxMjUyMywxMjUyNCwxMjUyNSwxMjUyNiwxMjUyNywxMjUyOCwxMjUyOSwxMjUzMCwxMjUzMSwxMjUzMiwxMjUzMywxMjUzNCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsOTEzLDkxNCw5MTUsOTE2LDkxNyw5MTgsOTE5LDkyMCw5MjEsOTIyLDkyMyw5MjQsOTI1LDkyNiw5MjcsOTI4LDkyOSw5MzEsOTMyLDkzMyw5MzQsOTM1LDkzNiw5MzcsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDk0NSw5NDYsOTQ3LDk0OCw5NDksOTUwLDk1MSw5NTIsOTUzLDk1NCw5NTUsOTU2LDk1Nyw5NTgsOTU5LDk2MCw5NjEsOTYzLDk2NCw5NjUsOTY2LDk2Nyw5NjgsOTY5LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCwxMDQwLDEwNDEsMTA0MiwxMDQzLDEwNDQsMTA0NSwxMDI1LDEwNDYsMTA0NywxMDQ4LDEwNDksMTA1MCwxMDUxLDEwNTIsMTA1MywxMDU0LDEwNTUsMTA1NiwxMDU3LDEwNTgsMTA1OSwxMDYwLDEwNjEsMTA2MiwxMDYzLDEwNjQsMTA2NSwxMDY2LDEwNjcsMTA2OCwxMDY5LDEwNzAsMTA3MSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCwxMDcyLDEwNzMsMTA3NCwxMDc1LDEwNzYsMTA3NywxMTA1LDEwNzgsMTA3OSwxMDgwLDEwODEsMTA4MiwxMDgzLDEwODQsMTA4NSwxMDg2LDEwODcsMTA4OCwxMDg5LDEwOTAsMTA5MSwxMDkyLDEwOTMsMTA5NCwxMDk1LDEwOTYsMTA5NywxMDk4LDEwOTksMTEwMCwxMTAxLDExMDIsMTEwMyxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDk0NzIsOTQ3NCw5NDg0LDk0ODgsOTQ5Niw5NDkyLDk1MDAsOTUxNiw5NTA4LDk1MjQsOTUzMiw5NDczLDk0NzUsOTQ4Nyw5NDkxLDk0OTksOTQ5NSw5NTA3LDk1MjMsOTUxNSw5NTMxLDk1NDcsOTUwNCw5NTE5LDk1MTIsOTUyNyw5NTM1LDk1MDEsOTUyMCw5NTA5LDk1MjgsOTUzOCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw5MzEyLDkzMTMsOTMxNCw5MzE1LDkzMTYsOTMxNyw5MzE4LDkzMTksOTMyMCw5MzIxLDkzMjIsOTMyMyw5MzI0LDkzMjUsOTMyNiw5MzI3LDkzMjgsOTMyOSw5MzMwLDkzMzEsODU0NCw4NTQ1LDg1NDYsODU0Nyw4NTQ4LDg1NDksODU1MCw4NTUxLDg1NTIsODU1MyxudWxsLDEzMTI5LDEzMDc2LDEzMDkwLDEzMTMzLDEzMDgwLDEzMDk1LDEzMDU5LDEzMTEwLDEzMTM3LDEzMTQzLDEzMDY5LDEzMDk0LDEzMDkxLDEzMDk5LDEzMTMwLDEzMTE1LDEzMjEyLDEzMjEzLDEzMjE0LDEzMTk4LDEzMTk5LDEzMjUyLDEzMjE3LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCwxMzE3OSwxMjMxNywxMjMxOSw4NDcwLDEzMjYxLDg0ODEsMTI5NjQsMTI5NjUsMTI5NjYsMTI5NjcsMTI5NjgsMTI4NDksMTI4NTAsMTI4NTcsMTMxODIsMTMxODEsMTMxODAsODc4Niw4ODAxLDg3NDcsODc1MCw4NzIxLDg3MzAsODg2OSw4NzM2LDg3MzUsODg5NSw4NzU3LDg3NDUsODc0NixudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDIwMTI0LDIxNzgyLDIzMDQzLDM4NDYzLDIxNjk2LDI0ODU5LDI1Mzg0LDIzMDMwLDM2ODk4LDMzOTA5LDMzNTY0LDMxMzEyLDI0NzQ2LDI1NTY5LDI4MTk3LDI2MDkzLDMzODk0LDMzNDQ2LDM5OTI1LDI2NzcxLDIyMzExLDI2MDE3LDI1MjAxLDIzNDUxLDIyOTkyLDM0NDI3LDM5MTU2LDMyMDk4LDMyMTkwLDM5ODIyLDI1MTEwLDMxOTAzLDM0OTk5LDIzNDMzLDI0MjQ1LDI1MzUzLDI2MjYzLDI2Njk2LDM4MzQzLDM4Nzk3LDI2NDQ3LDIwMTk3LDIwMjM0LDIwMzAxLDIwMzgxLDIwNTUzLDIyMjU4LDIyODM5LDIyOTk2LDIzMDQxLDIzNTYxLDI0Nzk5LDI0ODQ3LDI0OTQ0LDI2MTMxLDI2ODg1LDI4ODU4LDMwMDMxLDMwMDY0LDMxMjI3LDMyMTczLDMyMjM5LDMyOTYzLDMzODA2LDM0OTE1LDM1NTg2LDM2OTQ5LDM2OTg2LDIxMzA3LDIwMTE3LDIwMTMzLDIyNDk1LDMyOTQ2LDM3MDU3LDMwOTU5LDE5OTY4LDIyNzY5LDI4MzIyLDM2OTIwLDMxMjgyLDMzNTc2LDMzNDE5LDM5OTgzLDIwODAxLDIxMzYwLDIxNjkzLDIxNzI5LDIyMjQwLDIzMDM1LDI0MzQxLDM5MTU0LDI4MTM5LDMyOTk2LDM0MDkzLDM4NDk4LDM4NTEyLDM4NTYwLDM4OTA3LDIxNTE1LDIxNDkxLDIzNDMxLDI4ODc5LDMyNzAxLDM2ODAyLDM4NjMyLDIxMzU5LDQwMjg0LDMxNDE4LDE5OTg1LDMwODY3LDMzMjc2LDI4MTk4LDIyMDQwLDIxNzY0LDI3NDIxLDM0MDc0LDM5OTk1LDIzMDEzLDIxNDE3LDI4MDA2LDI5OTE2LDM4Mjg3LDIyMDgyLDIwMTEzLDM2OTM5LDM4NjQyLDMzNjE1LDM5MTgwLDIxNDczLDIxOTQyLDIzMzQ0LDI0NDMzLDI2MTQ0LDI2MzU1LDI2NjI4LDI3NzA0LDI3ODkxLDI3OTQ1LDI5Nzg3LDMwNDA4LDMxMzEwLDM4OTY0LDMzNTIxLDM0OTA3LDM1NDI0LDM3NjEzLDI4MDgyLDMwMTIzLDMwNDEwLDM5MzY1LDI0NzQyLDM1NTg1LDM2MjM0LDM4MzIyLDI3MDIyLDIxNDIxLDIwODcwLDIyMjkwLDIyNTc2LDIyODUyLDIzNDc2LDI0MzEwLDI0NjE2LDI1NTEzLDI1NTg4LDI3ODM5LDI4NDM2LDI4ODE0LDI4OTQ4LDI5MDE3LDI5MTQxLDI5NTAzLDMyMjU3LDMzMzk4LDMzNDg5LDM0MTk5LDM2OTYwLDM3NDY3LDQwMjE5LDIyNjMzLDI2MDQ0LDI3NzM4LDI5OTg5LDIwOTg1LDIyODMwLDIyODg1LDI0NDQ4LDI0NTQwLDI1Mjc2LDI2MTA2LDI3MTc4LDI3NDMxLDI3NTcyLDI5NTc5LDMyNzA1LDM1MTU4LDQwMjM2LDQwMjA2LDQwNjQ0LDIzNzEzLDI3Nzk4LDMzNjU5LDIwNzQwLDIzNjI3LDI1MDE0LDMzMjIyLDI2NzQyLDI5MjgxLDIwMDU3LDIwNDc0LDIxMzY4LDI0NjgxLDI4MjAxLDMxMzExLDM4ODk5LDE5OTc5LDIxMjcwLDIwMjA2LDIwMzA5LDIwMjg1LDIwMzg1LDIwMzM5LDIxMTUyLDIxNDg3LDIyMDI1LDIyNzk5LDIzMjMzLDIzNDc4LDIzNTIxLDMxMTg1LDI2MjQ3LDI2NTI0LDI2NTUwLDI3NDY4LDI3ODI3LDI4Nzc5LDI5NjM0LDMxMTE3LDMxMTY2LDMxMjkyLDMxNjIzLDMzNDU3LDMzNDk5LDMzNTQwLDMzNjU1LDMzNzc1LDMzNzQ3LDM0NjYyLDM1NTA2LDIyMDU3LDM2MDA4LDM2ODM4LDM2OTQyLDM4Njg2LDM0NDQyLDIwNDIwLDIzNzg0LDI1MTA1LDI5MjczLDMwMDExLDMzMjUzLDMzNDY5LDM0NTU4LDM2MDMyLDM4NTk3LDM5MTg3LDM5MzgxLDIwMTcxLDIwMjUwLDM1Mjk5LDIyMjM4LDIyNjAyLDIyNzMwLDI0MzE1LDI0NTU1LDI0NjE4LDI0NzI0LDI0Njc0LDI1MDQwLDI1MTA2LDI1Mjk2LDI1OTEzLDM5NzQ1LDI2MjE0LDI2ODAwLDI4MDIzLDI4Nzg0LDMwMDI4LDMwMzQyLDMyMTE3LDMzNDQ1LDM0ODA5LDM4MjgzLDM4NTQyLDM1OTk3LDIwOTc3LDIxMTgyLDIyODA2LDIxNjgzLDIzNDc1LDIzODMwLDI0OTM2LDI3MDEwLDI4MDc5LDMwODYxLDMzOTk1LDM0OTAzLDM1NDQyLDM3Nzk5LDM5NjA4LDI4MDEyLDM5MzM2LDM0NTIxLDIyNDM1LDI2NjIzLDM0NTEwLDM3MzkwLDIxMTIzLDIyMTUxLDIxNTA4LDI0Mjc1LDI1MzEzLDI1Nzg1LDI2Njg0LDI2NjgwLDI3NTc5LDI5NTU0LDMwOTA2LDMxMzM5LDM1MjI2LDM1MjgyLDM2MjAzLDM2NjExLDM3MTAxLDM4MzA3LDM4NTQ4LDM4NzYxLDIzMzk4LDIzNzMxLDI3MDA1LDM4OTg5LDM4OTkwLDI1NDk5LDMxNTIwLDI3MTc5LDI3MjYzLDI2ODA2LDM5OTQ5LDI4NTExLDIxMTA2LDIxOTE3LDI0Njg4LDI1MzI0LDI3OTYzLDI4MTY3LDI4MzY5LDMzODgzLDM1MDg4LDM2Njc2LDE5OTg4LDM5OTkzLDIxNDk0LDI2OTA3LDI3MTk0LDM4Nzg4LDI2NjY2LDIwODI4LDMxNDI3LDMzOTcwLDM3MzQwLDM3NzcyLDIyMTA3LDQwMjMyLDI2NjU4LDMzNTQxLDMzODQxLDMxOTA5LDIxMDAwLDMzNDc3LDI5OTI2LDIwMDk0LDIwMzU1LDIwODk2LDIzNTA2LDIxMDAyLDIxMjA4LDIxMjIzLDI0MDU5LDIxOTE0LDIyNTcwLDIzMDE0LDIzNDM2LDIzNDQ4LDIzNTE1LDI0MTc4LDI0MTg1LDI0NzM5LDI0ODYzLDI0OTMxLDI1MDIyLDI1NTYzLDI1OTU0LDI2NTc3LDI2NzA3LDI2ODc0LDI3NDU0LDI3NDc1LDI3NzM1LDI4NDUwLDI4NTY3LDI4NDg1LDI5ODcyLDI5OTc2LDMwNDM1LDMwNDc1LDMxNDg3LDMxNjQ5LDMxNzc3LDMyMjMzLDMyNTY2LDMyNzUyLDMyOTI1LDMzMzgyLDMzNjk0LDM1MjUxLDM1NTMyLDM2MDExLDM2OTk2LDM3OTY5LDM4MjkxLDM4Mjg5LDM4MzA2LDM4NTAxLDM4ODY3LDM5MjA4LDMzMzA0LDIwMDI0LDIxNTQ3LDIzNzM2LDI0MDEyLDI5NjA5LDMwMjg0LDMwNTI0LDIzNzIxLDMyNzQ3LDM2MTA3LDM4NTkzLDM4OTI5LDM4OTk2LDM5MDAwLDIwMjI1LDIwMjM4LDIxMzYxLDIxOTE2LDIyMTIwLDIyNTIyLDIyODU1LDIzMzA1LDIzNDkyLDIzNjk2LDI0MDc2LDI0MTkwLDI0NTI0LDI1NTgyLDI2NDI2LDI2MDcxLDI2MDgyLDI2Mzk5LDI2ODI3LDI2ODIwLDI3MjMxLDI0MTEyLDI3NTg5LDI3NjcxLDI3NzczLDMwMDc5LDMxMDQ4LDIzMzk1LDMxMjMyLDMyMDAwLDI0NTA5LDM1MjE1LDM1MzUyLDM2MDIwLDM2MjE1LDM2NTU2LDM2NjM3LDM5MTM4LDM5NDM4LDM5NzQwLDIwMDk2LDIwNjA1LDIwNzM2LDIyOTMxLDIzNDUyLDI1MTM1LDI1MjE2LDI1ODM2LDI3NDUwLDI5MzQ0LDMwMDk3LDMxMDQ3LDMyNjgxLDM0ODExLDM1NTE2LDM1Njk2LDI1NTE2LDMzNzM4LDM4ODE2LDIxNTEzLDIxNTA3LDIxOTMxLDI2NzA4LDI3MjI0LDM1NDQwLDMwNzU5LDI2NDg1LDQwNjUzLDIxMzY0LDIzNDU4LDMzMDUwLDM0Mzg0LDM2ODcwLDE5OTkyLDIwMDM3LDIwMTY3LDIwMjQxLDIxNDUwLDIxNTYwLDIzNDcwLDI0MzM5LDI0NjEzLDI1OTM3LDI2NDI5LDI3NzE0LDI3NzYyLDI3ODc1LDI4NzkyLDI5Njk5LDMxMzUwLDMxNDA2LDMxNDk2LDMyMDI2LDMxOTk4LDMyMTAyLDI2MDg3LDI5Mjc1LDIxNDM1LDIzNjIxLDI0MDQwLDI1Mjk4LDI1MzEyLDI1MzY5LDI4MTkyLDM0Mzk0LDM1Mzc3LDM2MzE3LDM3NjI0LDI4NDE3LDMxMTQyLDM5NzcwLDIwMTM2LDIwMTM5LDIwMTQwLDIwMzc5LDIwMzg0LDIwNjg5LDIwODA3LDMxNDc4LDIwODQ5LDIwOTgyLDIxMzMyLDIxMjgxLDIxMzc1LDIxNDgzLDIxOTMyLDIyNjU5LDIzNzc3LDI0Mzc1LDI0Mzk0LDI0NjIzLDI0NjU2LDI0Njg1LDI1Mzc1LDI1OTQ1LDI3MjExLDI3ODQxLDI5Mzc4LDI5NDIxLDMwNzAzLDMzMDE2LDMzMDI5LDMzMjg4LDM0MTI2LDM3MTExLDM3ODU3LDM4OTExLDM5MjU1LDM5NTE0LDIwMjA4LDIwOTU3LDIzNTk3LDI2MjQxLDI2OTg5LDIzNjE2LDI2MzU0LDI2OTk3LDI5NTc3LDI2NzA0LDMxODczLDIwNjc3LDIxMjIwLDIyMzQzLDI0MDYyLDM3NjcwLDI2MDIwLDI3NDI3LDI3NDUzLDI5NzQ4LDMxMTA1LDMxMTY1LDMxNTYzLDMyMjAyLDMzNDY1LDMzNzQwLDM0OTQzLDM1MTY3LDM1NjQxLDM2ODE3LDM3MzI5LDIxNTM1LDM3NTA0LDIwMDYxLDIwNTM0LDIxNDc3LDIxMzA2LDI5Mzk5LDI5NTkwLDMwNjk3LDMzNTEwLDM2NTI3LDM5MzY2LDM5MzY4LDM5Mzc4LDIwODU1LDI0ODU4LDM0Mzk4LDIxOTM2LDMxMzU0LDIwNTk4LDIzNTA3LDM2OTM1LDM4NTMzLDIwMDE4LDI3MzU1LDM3MzUxLDIzNjMzLDIzNjI0LDI1NDk2LDMxMzkxLDI3Nzk1LDM4NzcyLDM2NzA1LDMxNDAyLDI5MDY2LDM4NTM2LDMxODc0LDI2NjQ3LDMyMzY4LDI2NzA1LDM3NzQwLDIxMjM0LDIxNTMxLDM0MjE5LDM1MzQ3LDMyNjc2LDM2NTU3LDM3MDg5LDIxMzUwLDM0OTUyLDMxMDQxLDIwNDE4LDIwNjcwLDIxMDA5LDIwODA0LDIxODQzLDIyMzE3LDI5Njc0LDIyNDExLDIyODY1LDI0NDE4LDI0NDUyLDI0NjkzLDI0OTUwLDI0OTM1LDI1MDAxLDI1NTIyLDI1NjU4LDI1OTY0LDI2MjIzLDI2NjkwLDI4MTc5LDMwMDU0LDMxMjkzLDMxOTk1LDMyMDc2LDMyMTUzLDMyMzMxLDMyNjE5LDMzNTUwLDMzNjEwLDM0NTA5LDM1MzM2LDM1NDI3LDM1Njg2LDM2NjA1LDM4OTM4LDQwMzM1LDMzNDY0LDM2ODE0LDM5OTEyLDIxMTI3LDI1MTE5LDI1NzMxLDI4NjA4LDM4NTUzLDI2Njg5LDIwNjI1LDI3NDI0LDI3NzcwLDI4NTAwLDMxMzQ4LDMyMDgwLDM0ODgwLDM1MzYzLDI2Mzc2LDIwMjE0LDIwNTM3LDIwNTE4LDIwNTgxLDIwODYwLDIxMDQ4LDIxMDkxLDIxOTI3LDIyMjg3LDIyNTMzLDIzMjQ0LDI0MzE0LDI1MDEwLDI1MDgwLDI1MzMxLDI1NDU4LDI2OTA4LDI3MTc3LDI5MzA5LDI5MzU2LDI5NDg2LDMwNzQwLDMwODMxLDMyMTIxLDMwNDc2LDMyOTM3LDM1MjExLDM1NjA5LDM2MDY2LDM2NTYyLDM2OTYzLDM3NzQ5LDM4NTIyLDM4OTk3LDM5NDQzLDQwNTY4LDIwODAzLDIxNDA3LDIxNDI3LDI0MTg3LDI0MzU4LDI4MTg3LDI4MzA0LDI5NTcyLDI5Njk0LDMyMDY3LDMzMzM1LDM1MzI4LDM1NTc4LDM4NDgwLDIwMDQ2LDIwNDkxLDIxNDc2LDIxNjI4LDIyMjY2LDIyOTkzLDIzMzk2LDI0MDQ5LDI0MjM1LDI0MzU5LDI1MTQ0LDI1OTI1LDI2NTQzLDI4MjQ2LDI5MzkyLDMxOTQ2LDM0OTk2LDMyOTI5LDMyOTkzLDMzNzc2LDM0MzgyLDM1NDYzLDM2MzI4LDM3NDMxLDM4NTk5LDM5MDE1LDQwNzIzLDIwMTE2LDIwMTE0LDIwMjM3LDIxMzIwLDIxNTc3LDIxNTY2LDIzMDg3LDI0NDYwLDI0NDgxLDI0NzM1LDI2NzkxLDI3Mjc4LDI5Nzg2LDMwODQ5LDM1NDg2LDM1NDkyLDM1NzAzLDM3MjY0LDIwMDYyLDM5ODgxLDIwMTMyLDIwMzQ4LDIwMzk5LDIwNTA1LDIwNTAyLDIwODA5LDIwODQ0LDIxMTUxLDIxMTc3LDIxMjQ2LDIxNDAyLDIxNDc1LDIxNTIxLDIxNTE4LDIxODk3LDIyMzUzLDIyNDM0LDIyOTA5LDIzMzgwLDIzMzg5LDIzNDM5LDI0MDM3LDI0MDM5LDI0MDU1LDI0MTg0LDI0MTk1LDI0MjE4LDI0MjQ3LDI0MzQ0LDI0NjU4LDI0OTA4LDI1MjM5LDI1MzA0LDI1NTExLDI1OTE1LDI2MTE0LDI2MTc5LDI2MzU2LDI2NDc3LDI2NjU3LDI2Nzc1LDI3MDgzLDI3NzQzLDI3OTQ2LDI4MDA5LDI4MjA3LDI4MzE3LDMwMDAyLDMwMzQzLDMwODI4LDMxMjk1LDMxOTY4LDMyMDA1LDMyMDI0LDMyMDk0LDMyMTc3LDMyNzg5LDMyNzcxLDMyOTQzLDMyOTQ1LDMzMTA4LDMzMTY3LDMzMzIyLDMzNjE4LDM0ODkyLDM0OTEzLDM1NjExLDM2MDAyLDM2MDkyLDM3MDY2LDM3MjM3LDM3NDg5LDMwNzgzLDM3NjI4LDM4MzA4LDM4NDc3LDM4OTE3LDM5MzIxLDM5NjQwLDQwMjUxLDIxMDgzLDIxMTYzLDIxNDk1LDIxNTEyLDIyNzQxLDI1MzM1LDI4NjQwLDM1OTQ2LDM2NzAzLDQwNjMzLDIwODExLDIxMDUxLDIxNTc4LDIyMjY5LDMxMjk2LDM3MjM5LDQwMjg4LDQwNjU4LDI5NTA4LDI4NDI1LDMzMTM2LDI5OTY5LDI0NTczLDI0Nzk0LDM5NTkyLDI5NDAzLDM2Nzk2LDI3NDkyLDM4OTE1LDIwMTcwLDIyMjU2LDIyMzcyLDIyNzE4LDIzMTMwLDI0NjgwLDI1MDMxLDI2MTI3LDI2MTE4LDI2NjgxLDI2ODAxLDI4MTUxLDMwMTY1LDMyMDU4LDMzMzkwLDM5NzQ2LDIwMTIzLDIwMzA0LDIxNDQ5LDIxNzY2LDIzOTE5LDI0MDM4LDI0MDQ2LDI2NjE5LDI3ODAxLDI5ODExLDMwNzIyLDM1NDA4LDM3NzgyLDM1MDM5LDIyMzUyLDI0MjMxLDI1Mzg3LDIwNjYxLDIwNjUyLDIwODc3LDI2MzY4LDIxNzA1LDIyNjIyLDIyOTcxLDIzNDcyLDI0NDI1LDI1MTY1LDI1NTA1LDI2Njg1LDI3NTA3LDI4MTY4LDI4Nzk3LDM3MzE5LDI5MzEyLDMwNzQxLDMwNzU4LDMxMDg1LDI1OTk4LDMyMDQ4LDMzNzU2LDM1MDA5LDM2NjE3LDM4NTU1LDIxMDkyLDIyMzEyLDI2NDQ4LDMyNjE4LDM2MDAxLDIwOTE2LDIyMzM4LDM4NDQyLDIyNTg2LDI3MDE4LDMyOTQ4LDIxNjgyLDIzODIyLDIyNTI0LDMwODY5LDQwNDQyLDIwMzE2LDIxMDY2LDIxNjQzLDI1NjYyLDI2MTUyLDI2Mzg4LDI2NjEzLDMxMzY0LDMxNTc0LDMyMDM0LDM3Njc5LDI2NzE2LDM5ODUzLDMxNTQ1LDIxMjczLDIwODc0LDIxMDQ3LDIzNTE5LDI1MzM0LDI1Nzc0LDI1ODMwLDI2NDEzLDI3NTc4LDM0MjE3LDM4NjA5LDMwMzUyLDM5ODk0LDI1NDIwLDM3NjM4LDM5ODUxLDMwMzk5LDI2MTk0LDE5OTc3LDIwNjMyLDIxNDQyLDIzNjY1LDI0ODA4LDI1NzQ2LDI1OTU1LDI2NzE5LDI5MTU4LDI5NjQyLDI5OTg3LDMxNjM5LDMyMzg2LDM0NDUzLDM1NzE1LDM2MDU5LDM3MjQwLDM5MTg0LDI2MDI4LDI2MjgzLDI3NTMxLDIwMTgxLDIwMTgwLDIwMjgyLDIwMzUxLDIxMDUwLDIxNDk2LDIxNDkwLDIxOTg3LDIyMjM1LDIyNzYzLDIyOTg3LDIyOTg1LDIzMDM5LDIzMzc2LDIzNjI5LDI0MDY2LDI0MTA3LDI0NTM1LDI0NjA1LDI1MzUxLDI1OTAzLDIzMzg4LDI2MDMxLDI2MDQ1LDI2MDg4LDI2NTI1LDI3NDkwLDI3NTE1LDI3NjYzLDI5NTA5LDMxMDQ5LDMxMTY5LDMxOTkyLDMyMDI1LDMyMDQzLDMyOTMwLDMzMDI2LDMzMjY3LDM1MjIyLDM1NDIyLDM1NDMzLDM1NDMwLDM1NDY4LDM1NTY2LDM2MDM5LDM2MDYwLDM4NjA0LDM5MTY0LDI3NTAzLDIwMTA3LDIwMjg0LDIwMzY1LDIwODE2LDIzMzgzLDIzNTQ2LDI0OTA0LDI1MzQ1LDI2MTc4LDI3NDI1LDI4MzYzLDI3ODM1LDI5MjQ2LDI5ODg1LDMwMTY0LDMwOTEzLDMxMDM0LDMyNzgwLDMyODE5LDMzMjU4LDMzOTQwLDM2NzY2LDI3NzI4LDQwNTc1LDI0MzM1LDM1NjcyLDQwMjM1LDMxNDgyLDM2NjAwLDIzNDM3LDM4NjM1LDE5OTcxLDIxNDg5LDIyNTE5LDIyODMzLDIzMjQxLDIzNDYwLDI0NzEzLDI4Mjg3LDI4NDIyLDMwMTQyLDM2MDc0LDIzNDU1LDM0MDQ4LDMxNzEyLDIwNTk0LDI2NjEyLDMzNDM3LDIzNjQ5LDM0MTIyLDMyMjg2LDMzMjk0LDIwODg5LDIzNTU2LDI1NDQ4LDM2MTk4LDI2MDEyLDI5MDM4LDMxMDM4LDMyMDIzLDMyNzczLDM1NjEzLDM2NTU0LDM2OTc0LDM0NTAzLDM3MDM0LDIwNTExLDIxMjQyLDIzNjEwLDI2NDUxLDI4Nzk2LDI5MjM3LDM3MTk2LDM3MzIwLDM3Njc1LDMzNTA5LDIzNDkwLDI0MzY5LDI0ODI1LDIwMDI3LDIxNDYyLDIzNDMyLDI1MTYzLDI2NDE3LDI3NTMwLDI5NDE3LDI5NjY0LDMxMjc4LDMzMTMxLDM2MjU5LDM3MjAyLDM5MzE4LDIwNzU0LDIxNDYzLDIxNjEwLDIzNTUxLDI1NDgwLDI3MTkzLDMyMTcyLDM4NjU2LDIyMjM0LDIxNDU0LDIxNjA4LDIzNDQ3LDIzNjAxLDI0MDMwLDIwNDYyLDI0ODMzLDI1MzQyLDI3OTU0LDMxMTY4LDMxMTc5LDMyMDY2LDMyMzMzLDMyNzIyLDMzMjYxLDMzMzExLDMzOTM2LDM0ODg2LDM1MTg2LDM1NzI4LDM2NDY4LDM2NjU1LDM2OTEzLDM3MTk1LDM3MjI4LDM4NTk4LDM3Mjc2LDIwMTYwLDIwMzAzLDIwODA1LDIxMzEzLDI0NDY3LDI1MTAyLDI2NTgwLDI3NzEzLDI4MTcxLDI5NTM5LDMyMjk0LDM3MzI1LDM3NTA3LDIxNDYwLDIyODA5LDIzNDg3LDI4MTEzLDMxMDY5LDMyMzAyLDMxODk5LDIyNjU0LDI5MDg3LDIwOTg2LDM0ODk5LDM2ODQ4LDIwNDI2LDIzODAzLDI2MTQ5LDMwNjM2LDMxNDU5LDMzMzA4LDM5NDIzLDIwOTM0LDI0NDkwLDI2MDkyLDI2OTkxLDI3NTI5LDI4MTQ3LDI4MzEwLDI4NTE2LDMwNDYyLDMyMDIwLDI0MDMzLDM2OTgxLDM3MjU1LDM4OTE4LDIwOTY2LDIxMDIxLDI1MTUyLDI2MjU3LDI2MzI5LDI4MTg2LDI0MjQ2LDMyMjEwLDMyNjI2LDI2MzYwLDM0MjIzLDM0Mjk1LDM1NTc2LDIxMTYxLDIxNDY1LDIyODk5LDI0MjA3LDI0NDY0LDI0NjYxLDM3NjA0LDM4NTAwLDIwNjYzLDIwNzY3LDIxMjEzLDIxMjgwLDIxMzE5LDIxNDg0LDIxNzM2LDIxODMwLDIxODA5LDIyMDM5LDIyODg4LDIyOTc0LDIzMTAwLDIzNDc3LDIzNTU4LDIzNTY3LDIzNTY5LDIzNTc4LDI0MTk2LDI0MjAyLDI0Mjg4LDI0NDMyLDI1MjE1LDI1MjIwLDI1MzA3LDI1NDg0LDI1NDYzLDI2MTE5LDI2MTI0LDI2MTU3LDI2MjMwLDI2NDk0LDI2Nzg2LDI3MTY3LDI3MTg5LDI3ODM2LDI4MDQwLDI4MTY5LDI4MjQ4LDI4OTg4LDI4OTY2LDI5MDMxLDMwMTUxLDMwNDY1LDMwODEzLDMwOTc3LDMxMDc3LDMxMjE2LDMxNDU2LDMxNTA1LDMxOTExLDMyMDU3LDMyOTE4LDMzNzUwLDMzOTMxLDM0MTIxLDM0OTA5LDM1MDU5LDM1MzU5LDM1Mzg4LDM1NDEyLDM1NDQzLDM1OTM3LDM2MDYyLDM3Mjg0LDM3NDc4LDM3NzU4LDM3OTEyLDM4NTU2LDM4ODA4LDE5OTc4LDE5OTc2LDE5OTk4LDIwMDU1LDIwODg3LDIxMTA0LDIyNDc4LDIyNTgwLDIyNzMyLDIzMzMwLDI0MTIwLDI0NzczLDI1ODU0LDI2NDY1LDI2NDU0LDI3OTcyLDI5MzY2LDMwMDY3LDMxMzMxLDMzOTc2LDM1Njk4LDM3MzA0LDM3NjY0LDIyMDY1LDIyNTE2LDM5MTY2LDI1MzI1LDI2ODkzLDI3NTQyLDI5MTY1LDMyMzQwLDMyODg3LDMzMzk0LDM1MzAyLDM5MTM1LDM0NjQ1LDM2Nzg1LDIzNjExLDIwMjgwLDIwNDQ5LDIwNDA1LDIxNzY3LDIzMDcyLDIzNTE3LDIzNTI5LDI0NTE1LDI0OTEwLDI1MzkxLDI2MDMyLDI2MTg3LDI2ODYyLDI3MDM1LDI4MDI0LDI4MTQ1LDMwMDAzLDMwMTM3LDMwNDk1LDMxMDcwLDMxMjA2LDMyMDUxLDMzMjUxLDMzNDU1LDM0MjE4LDM1MjQyLDM1Mzg2LDM2NTIzLDM2NzYzLDM2OTE0LDM3MzQxLDM4NjYzLDIwMTU0LDIwMTYxLDIwOTk1LDIyNjQ1LDIyNzY0LDIzNTYzLDI5OTc4LDIzNjEzLDMzMTAyLDM1MzM4LDM2ODA1LDM4NDk5LDM4NzY1LDMxNTI1LDM1NTM1LDM4OTIwLDM3MjE4LDIyMjU5LDIxNDE2LDM2ODg3LDIxNTYxLDIyNDAyLDI0MTAxLDI1NTEyLDI3NzAwLDI4ODEwLDMwNTYxLDMxODgzLDMyNzM2LDM0OTI4LDM2OTMwLDM3MjA0LDM3NjQ4LDM3NjU2LDM4NTQzLDI5NzkwLDM5NjIwLDIzODE1LDIzOTEzLDI1OTY4LDI2NTMwLDM2MjY0LDM4NjE5LDI1NDU0LDI2NDQxLDI2OTA1LDMzNzMzLDM4OTM1LDM4NTkyLDM1MDcwLDI4NTQ4LDI1NzIyLDIzNTQ0LDE5OTkwLDI4NzE2LDMwMDQ1LDI2MTU5LDIwOTMyLDIxMDQ2LDIxMjE4LDIyOTk1LDI0NDQ5LDI0NjE1LDI1MTA0LDI1OTE5LDI1OTcyLDI2MTQzLDI2MjI4LDI2ODY2LDI2NjQ2LDI3NDkxLDI4MTY1LDI5Mjk4LDI5OTgzLDMwNDI3LDMxOTM0LDMyODU0LDIyNzY4LDM1MDY5LDM1MTk5LDM1NDg4LDM1NDc1LDM1NTMxLDM2ODkzLDM3MjY2LDM4NzM4LDM4NzQ1LDI1OTkzLDMxMjQ2LDMzMDMwLDM4NTg3LDI0MTA5LDI0Nzk2LDI1MTE0LDI2MDIxLDI2MTMyLDI2NTEyLDMwNzA3LDMxMzA5LDMxODIxLDMyMzE4LDMzMDM0LDM2MDEyLDM2MTk2LDM2MzIxLDM2NDQ3LDMwODg5LDIwOTk5LDI1MzA1LDI1NTA5LDI1NjY2LDI1MjQwLDM1MzczLDMxMzYzLDMxNjgwLDM1NTAwLDM4NjM0LDMyMTE4LDMzMjkyLDM0NjMzLDIwMTg1LDIwODA4LDIxMzE1LDIxMzQ0LDIzNDU5LDIzNTU0LDIzNTc0LDI0MDI5LDI1MTI2LDI1MTU5LDI1Nzc2LDI2NjQzLDI2Njc2LDI3ODQ5LDI3OTczLDI3OTI3LDI2NTc5LDI4NTA4LDI5MDA2LDI5MDUzLDI2MDU5LDMxMzU5LDMxNjYxLDMyMjE4LDMyMzMwLDMyNjgwLDMzMTQ2LDMzMzA3LDMzMzM3LDM0MjE0LDM1NDM4LDM2MDQ2LDM2MzQxLDM2OTg0LDM2OTgzLDM3NTQ5LDM3NTIxLDM4Mjc1LDM5ODU0LDIxMDY5LDIxODkyLDI4NDcyLDI4OTgyLDIwODQwLDMxMTA5LDMyMzQxLDMzMjAzLDMxOTUwLDIyMDkyLDIyNjA5LDIzNzIwLDI1NTE0LDI2MzY2LDI2MzY1LDI2OTcwLDI5NDAxLDMwMDk1LDMwMDk0LDMwOTkwLDMxMDYyLDMxMTk5LDMxODk1LDMyMDMyLDMyMDY4LDM0MzExLDM1MzgwLDM4NDU5LDM2OTYxLDQwNzM2LDIwNzExLDIxMTA5LDIxNDUyLDIxNDc0LDIwNDg5LDIxOTMwLDIyNzY2LDIyODYzLDI5MjQ1LDIzNDM1LDIzNjUyLDIxMjc3LDI0ODAzLDI0ODE5LDI1NDM2LDI1NDc1LDI1NDA3LDI1NTMxLDI1ODA1LDI2MDg5LDI2MzYxLDI0MDM1LDI3MDg1LDI3MTMzLDI4NDM3LDI5MTU3LDIwMTA1LDMwMTg1LDMwNDU2LDMxMzc5LDMxOTY3LDMyMjA3LDMyMTU2LDMyODY1LDMzNjA5LDMzNjI0LDMzOTAwLDMzOTgwLDM0Mjk5LDM1MDEzLDM2MjA4LDM2ODY1LDM2OTczLDM3NzgzLDM4Njg0LDM5NDQyLDIwNjg3LDIyNjc5LDI0OTc0LDMzMjM1LDM0MTAxLDM2MTA0LDM2ODk2LDIwNDE5LDIwNTk2LDIxMDYzLDIxMzYzLDI0Njg3LDI1NDE3LDI2NDYzLDI4MjA0LDM2Mjc1LDM2ODk1LDIwNDM5LDIzNjQ2LDM2MDQyLDI2MDYzLDMyMTU0LDIxMzMwLDM0OTY2LDIwODU0LDI1NTM5LDIzMzg0LDIzNDAzLDIzNTYyLDI1NjEzLDI2NDQ5LDM2OTU2LDIwMTgyLDIyODEwLDIyODI2LDI3NzYwLDM1NDA5LDIxODIyLDIyNTQ5LDIyOTQ5LDI0ODE2LDI1MTcxLDI2NTYxLDMzMzMzLDI2OTY1LDM4NDY0LDM5MzY0LDM5NDY0LDIwMzA3LDIyNTM0LDIzNTUwLDMyNzg0LDIzNzI5LDI0MTExLDI0NDUzLDI0NjA4LDI0OTA3LDI1MTQwLDI2MzY3LDI3ODg4LDI4MzgyLDMyOTc0LDMzMTUxLDMzNDkyLDM0OTU1LDM2MDI0LDM2ODY0LDM2OTEwLDM4NTM4LDQwNjY3LDM5ODk5LDIwMTk1LDIxNDg4LDIyODIzLDMxNTMyLDM3MjYxLDM4OTg4LDQwNDQxLDI4MzgxLDI4NzExLDIxMzMxLDIxODI4LDIzNDI5LDI1MTc2LDI1MjQ2LDI1Mjk5LDI3ODEwLDI4NjU1LDI5NzMwLDM1MzUxLDM3OTQ0LDI4NjA5LDM1NTgyLDMzNTkyLDIwOTY3LDM0NTUyLDIxNDgyLDIxNDgxLDIwMjk0LDM2OTQ4LDM2Nzg0LDIyODkwLDMzMDczLDI0MDYxLDMxNDY2LDM2Nzk5LDI2ODQyLDM1ODk1LDI5NDMyLDQwMDA4LDI3MTk3LDM1NTA0LDIwMDI1LDIxMzM2LDIyMDIyLDIyMzc0LDI1Mjg1LDI1NTA2LDI2MDg2LDI3NDcwLDI4MTI5LDI4MjUxLDI4ODQ1LDMwNzAxLDMxNDcxLDMxNjU4LDMyMTg3LDMyODI5LDMyOTY2LDM0NTA3LDM1NDc3LDM3NzIzLDIyMjQzLDIyNzI3LDI0MzgyLDI2MDI5LDI2MjYyLDI3MjY0LDI3NTczLDMwMDA3LDM1NTI3LDIwNTE2LDMwNjkzLDIyMzIwLDI0MzQ3LDI0Njc3LDI2MjM0LDI3NzQ0LDMwMTk2LDMxMjU4LDMyNjIyLDMzMjY4LDM0NTg0LDM2OTMzLDM5MzQ3LDMxNjg5LDMwMDQ0LDMxNDgxLDMxNTY5LDMzOTg4LDM2ODgwLDMxMjA5LDMxMzc4LDMzNTkwLDIzMjY1LDMwNTI4LDIwMDEzLDIwMjEwLDIzNDQ5LDI0NTQ0LDI1Mjc3LDI2MTcyLDI2NjA5LDI3ODgwLDM0NDExLDM0OTM1LDM1Mzg3LDM3MTk4LDM3NjE5LDM5Mzc2LDI3MTU5LDI4NzEwLDI5NDgyLDMzNTExLDMzODc5LDM2MDE1LDE5OTY5LDIwODA2LDIwOTM5LDIxODk5LDIzNTQxLDI0MDg2LDI0MTE1LDI0MTkzLDI0MzQwLDI0MzczLDI0NDI3LDI0NTAwLDI1MDc0LDI1MzYxLDI2Mjc0LDI2Mzk3LDI4NTI2LDI5MjY2LDMwMDEwLDMwNTIyLDMyODg0LDMzMDgxLDMzMTQ0LDM0Njc4LDM1NTE5LDM1NTQ4LDM2MjI5LDM2MzM5LDM3NTMwLDM4MjYzLDM4OTE0LDQwMTY1LDIxMTg5LDI1NDMxLDMwNDUyLDI2Mzg5LDI3Nzg0LDI5NjQ1LDM2MDM1LDM3ODA2LDM4NTE1LDI3OTQxLDIyNjg0LDI2ODk0LDI3MDg0LDM2ODYxLDM3Nzg2LDMwMTcxLDM2ODkwLDIyNjE4LDI2NjI2LDI1NTI0LDI3MTMxLDIwMjkxLDI4NDYwLDI2NTg0LDM2Nzk1LDM0MDg2LDMyMTgwLDM3NzE2LDI2OTQzLDI4NTI4LDIyMzc4LDIyNzc1LDIzMzQwLDMyMDQ0LDI5MjI2LDIxNTE0LDM3MzQ3LDQwMzcyLDIwMTQxLDIwMzAyLDIwNTcyLDIwNTk3LDIxMDU5LDM1OTk4LDIxNTc2LDIyNTY0LDIzNDUwLDI0MDkzLDI0MjEzLDI0MjM3LDI0MzExLDI0MzUxLDI0NzE2LDI1MjY5LDI1NDAyLDI1NTUyLDI2Nzk5LDI3NzEyLDMwODU1LDMxMTE4LDMxMjQzLDMyMjI0LDMzMzUxLDM1MzMwLDM1NTU4LDM2NDIwLDM2ODgzLDM3MDQ4LDM3MTY1LDM3MzM2LDQwNzE4LDI3ODc3LDI1Njg4LDI1ODI2LDI1OTczLDI4NDA0LDMwMzQwLDMxNTE1LDM2OTY5LDM3ODQxLDI4MzQ2LDIxNzQ2LDI0NTA1LDI1NzY0LDM2Njg1LDM2ODQ1LDM3NDQ0LDIwODU2LDIyNjM1LDIyODI1LDIzNjM3LDI0MjE1LDI4MTU1LDMyMzk5LDI5OTgwLDM2MDI4LDM2NTc4LDM5MDAzLDI4ODU3LDIwMjUzLDI3NTgzLDI4NTkzLDMwMDAwLDM4NjUxLDIwODE0LDIxNTIwLDIyNTgxLDIyNjE1LDIyOTU2LDIzNjQ4LDI0NDY2LDI2MDA3LDI2NDYwLDI4MTkzLDMwMzMxLDMzNzU5LDM2MDc3LDM2ODg0LDM3MTE3LDM3NzA5LDMwNzU3LDMwNzc4LDIxMTYyLDI0MjMwLDIyMzAzLDIyOTAwLDI0NTk0LDIwNDk4LDIwODI2LDIwOTA4LDIwOTQxLDIwOTkyLDIxNzc2LDIyNjEyLDIyNjE2LDIyODcxLDIzNDQ1LDIzNzk4LDIzOTQ3LDI0NzY0LDI1MjM3LDI1NjQ1LDI2NDgxLDI2NjkxLDI2ODEyLDI2ODQ3LDMwNDIzLDI4MTIwLDI4MjcxLDI4MDU5LDI4NzgzLDI5MTI4LDI0NDAzLDMwMTY4LDMxMDk1LDMxNTYxLDMxNTcyLDMxNTcwLDMxOTU4LDMyMTEzLDIxMDQwLDMzODkxLDM0MTUzLDM0Mjc2LDM1MzQyLDM1NTg4LDM1OTEwLDM2MzY3LDM2ODY3LDM2ODc5LDM3OTEzLDM4NTE4LDM4OTU3LDM5NDcyLDM4MzYwLDIwNjg1LDIxMjA1LDIxNTE2LDIyNTMwLDIzNTY2LDI0OTk5LDI1NzU4LDI3OTM0LDMwNjQzLDMxNDYxLDMzMDEyLDMzNzk2LDM2OTQ3LDM3NTA5LDIzNzc2LDQwMTk5LDIxMzExLDI0NDcxLDI0NDk5LDI4MDYwLDI5MzA1LDMwNTYzLDMxMTY3LDMxNzE2LDI3NjAyLDI5NDIwLDM1NTAxLDI2NjI3LDI3MjMzLDIwOTg0LDMxMzYxLDI2OTMyLDIzNjI2LDQwMTgyLDMzNTE1LDIzNDkzLDM3MTkzLDI4NzAyLDIyMTM2LDIzNjYzLDI0Nzc1LDI1OTU4LDI3Nzg4LDM1OTMwLDM2OTI5LDM4OTMxLDIxNTg1LDI2MzExLDM3Mzg5LDIyODU2LDM3MDI3LDIwODY5LDIwMDQ1LDIwOTcwLDM0MjAxLDM1NTk4LDI4NzYwLDI1NDY2LDM3NzA3LDI2OTc4LDM5MzQ4LDMyMjYwLDMwMDcxLDIxMzM1LDI2OTc2LDM2NTc1LDM4NjI3LDI3NzQxLDIwMTA4LDIzNjEyLDI0MzM2LDM2ODQxLDIxMjUwLDM2MDQ5LDMyOTA1LDM0NDI1LDI0MzE5LDI2MDg1LDIwMDgzLDIwODM3LDIyOTE0LDIzNjE1LDM4ODk0LDIwMjE5LDIyOTIyLDI0NTI1LDM1NDY5LDI4NjQxLDMxMTUyLDMxMDc0LDIzNTI3LDMzOTA1LDI5NDgzLDI5MTA1LDI0MTgwLDI0NTY1LDI1NDY3LDI1NzU0LDI5MTIzLDMxODk2LDIwMDM1LDI0MzE2LDIwMDQzLDIyNDkyLDIyMTc4LDI0NzQ1LDI4NjExLDMyMDEzLDMzMDIxLDMzMDc1LDMzMjE1LDM2Nzg2LDM1MjIzLDM0NDY4LDI0MDUyLDI1MjI2LDI1NzczLDM1MjA3LDI2NDg3LDI3ODc0LDI3OTY2LDI5NzUwLDMwNzcyLDIzMTEwLDMyNjI5LDMzNDUzLDM5MzQwLDIwNDY3LDI0MjU5LDI1MzA5LDI1NDkwLDI1OTQzLDI2NDc5LDMwNDAzLDI5MjYwLDMyOTcyLDMyOTU0LDM2NjQ5LDM3MTk3LDIwNDkzLDIyNTIxLDIzMTg2LDI2NzU3LDI2OTk1LDI5MDI4LDI5NDM3LDM2MDIzLDIyNzcwLDM2MDY0LDM4NTA2LDM2ODg5LDM0Njg3LDMxMjA0LDMwNjk1LDMzODMzLDIwMjcxLDIxMDkzLDIxMzM4LDI1MjkzLDI2NTc1LDI3ODUwLDMwMzMzLDMxNjM2LDMxODkzLDMzMzM0LDM0MTgwLDM2ODQzLDI2MzMzLDI4NDQ4LDI5MTkwLDMyMjgzLDMzNzA3LDM5MzYxLDQwNjE0LDIwOTg5LDMxNjY1LDMwODM0LDMxNjcyLDMyOTAzLDMxNTYwLDI3MzY4LDI0MTYxLDMyOTA4LDMwMDMzLDMwMDQ4LDIwODQzLDM3NDc0LDI4MzAwLDMwMzMwLDM3MjcxLDM5NjU4LDIwMjQwLDMyNjI0LDI1MjQ0LDMxNTY3LDM4MzA5LDQwMTY5LDIyMTM4LDIyNjE3LDM0NTMyLDM4NTg4LDIwMjc2LDIxMDI4LDIxMzIyLDIxNDUzLDIxNDY3LDI0MDcwLDI1NjQ0LDI2MDAxLDI2NDk1LDI3NzEwLDI3NzI2LDI5MjU2LDI5MzU5LDI5Njc3LDMwMDM2LDMyMzIxLDMzMzI0LDM0MjgxLDM2MDA5LDMxNjg0LDM3MzE4LDI5MDMzLDM4OTMwLDM5MTUxLDI1NDA1LDI2MjE3LDMwMDU4LDMwNDM2LDMwOTI4LDM0MTE1LDM0NTQyLDIxMjkwLDIxMzI5LDIxNTQyLDIyOTE1LDI0MTk5LDI0NDQ0LDI0NzU0LDI1MTYxLDI1MjA5LDI1MjU5LDI2MDAwLDI3NjA0LDI3ODUyLDMwMTMwLDMwMzgyLDMwODY1LDMxMTkyLDMyMjAzLDMyNjMxLDMyOTMzLDM0OTg3LDM1NTEzLDM2MDI3LDM2OTkxLDM4NzUwLDM5MTMxLDI3MTQ3LDMxODAwLDIwNjMzLDIzNjE0LDI0NDk0LDI2NTAzLDI3NjA4LDI5NzQ5LDMwNDczLDMyNjU0LDQwNzYzLDI2NTcwLDMxMjU1LDIxMzA1LDMwMDkxLDM5NjYxLDI0NDIyLDMzMTgxLDMzNzc3LDMyOTIwLDI0MzgwLDI0NTE3LDMwMDUwLDMxNTU4LDM2OTI0LDI2NzI3LDIzMDE5LDIzMTk1LDMyMDE2LDMwMzM0LDM1NjI4LDIwNDY5LDI0NDI2LDI3MTYxLDI3NzAzLDI4NDE4LDI5OTIyLDMxMDgwLDM0OTIwLDM1NDEzLDM1OTYxLDI0Mjg3LDI1NTUxLDMwMTQ5LDMxMTg2LDMzNDk1LDM3NjcyLDM3NjE4LDMzOTQ4LDM0NTQxLDM5OTgxLDIxNjk3LDI0NDI4LDI1OTk2LDI3OTk2LDI4NjkzLDM2MDA3LDM2MDUxLDM4OTcxLDI1OTM1LDI5OTQyLDE5OTgxLDIwMTg0LDIyNDk2LDIyODI3LDIzMTQyLDIzNTAwLDIwOTA0LDI0MDY3LDI0MjIwLDI0NTk4LDI1MjA2LDI1OTc1LDI2MDIzLDI2MjIyLDI4MDE0LDI5MjM4LDMxNTI2LDMzMTA0LDMzMTc4LDMzNDMzLDM1Njc2LDM2MDAwLDM2MDcwLDM2MjEyLDM4NDI4LDM4NDY4LDIwMzk4LDI1NzcxLDI3NDk0LDMzMzEwLDMzODg5LDM0MTU0LDM3MDk2LDIzNTUzLDI2OTYzLDM5MDgwLDMzOTE0LDM0MTM1LDIwMjM5LDIxMTAzLDI0NDg5LDI0MTMzLDI2MzgxLDMxMTE5LDMzMTQ1LDM1MDc5LDM1MjA2LDI4MTQ5LDI0MzQzLDI1MTczLDI3ODMyLDIwMTc1LDI5Mjg5LDM5ODI2LDIwOTk4LDIxNTYzLDIyMTMyLDIyNzA3LDI0OTk2LDI1MTk4LDI4OTU0LDIyODk0LDMxODgxLDMxOTY2LDMyMDI3LDM4NjQwLDI1OTkxLDMyODYyLDE5OTkzLDIwMzQxLDIwODUzLDIyNTkyLDI0MTYzLDI0MTc5LDI0MzMwLDI2NTY0LDIwMDA2LDM0MTA5LDM4MjgxLDM4NDkxLDMxODU5LDM4OTEzLDIwNzMxLDIyNzIxLDMwMjk0LDMwODg3LDIxMDI5LDMwNjI5LDM0MDY1LDMxNjIyLDIwNTU5LDIyNzkzLDI5MjU1LDMxNjg3LDMyMjMyLDM2Nzk0LDM2ODIwLDM2OTQxLDIwNDE1LDIxMTkzLDIzMDgxLDI0MzIxLDM4ODI5LDIwNDQ1LDMzMzAzLDM3NjEwLDIyMjc1LDI1NDI5LDI3NDk3LDI5OTk1LDM1MDM2LDM2NjI4LDMxMjk4LDIxMjE1LDIyNjc1LDI0OTE3LDI1MDk4LDI2Mjg2LDI3NTk3LDMxODA3LDMzNzY5LDIwNTE1LDIwNDcyLDIxMjUzLDIxNTc0LDIyNTc3LDIyODU3LDIzNDUzLDIzNzkyLDIzNzkxLDIzODQ5LDI0MjE0LDI1MjY1LDI1NDQ3LDI1OTE4LDI2MDQxLDI2Mzc5LDI3ODYxLDI3ODczLDI4OTIxLDMwNzcwLDMyMjk5LDMyOTkwLDMzNDU5LDMzODA0LDM0MDI4LDM0NTYyLDM1MDkwLDM1MzcwLDM1OTE0LDM3MDMwLDM3NTg2LDM5MTY1LDQwMTc5LDQwMzAwLDIwMDQ3LDIwMTI5LDIwNjIxLDIxMDc4LDIyMzQ2LDIyOTUyLDI0MTI1LDI0NTM2LDI0NTM3LDI1MTUxLDI2MjkyLDI2Mzk1LDI2NTc2LDI2ODM0LDIwODgyLDMyMDMzLDMyOTM4LDMzMTkyLDM1NTg0LDM1OTgwLDM2MDMxLDM3NTAyLDM4NDUwLDIxNTM2LDM4OTU2LDIxMjcxLDIwNjkzLDIxMzQwLDIyNjk2LDI1Nzc4LDI2NDIwLDI5Mjg3LDMwNTY2LDMxMzAyLDM3MzUwLDIxMTg3LDI3ODA5LDI3NTI2LDIyNTI4LDI0MTQwLDIyODY4LDI2NDEyLDMyNzYzLDIwOTYxLDMwNDA2LDI1NzA1LDMwOTUyLDM5NzY0LDQwNjM1LDIyNDc1LDIyOTY5LDI2MTUxLDI2NTIyLDI3NTk4LDIxNzM3LDI3MDk3LDI0MTQ5LDMzMTgwLDI2NTE3LDM5ODUwLDI2NjIyLDQwMDE4LDI2NzE3LDIwMTM0LDIwNDUxLDIxNDQ4LDI1MjczLDI2NDExLDI3ODE5LDM2ODA0LDIwMzk3LDMyMzY1LDQwNjM5LDE5OTc1LDI0OTMwLDI4Mjg4LDI4NDU5LDM0MDY3LDIxNjE5LDI2NDEwLDM5NzQ5LDI0MDUxLDMxNjM3LDIzNzI0LDIzNDk0LDM0NTg4LDI4MjM0LDM0MDAxLDMxMjUyLDMzMDMyLDIyOTM3LDMxODg1LDI3NjY1LDMwNDk2LDIxMjA5LDIyODE4LDI4OTYxLDI5Mjc5LDMwNjgzLDM4Njk1LDQwMjg5LDI2ODkxLDIzMTY3LDIzMDY0LDIwOTAxLDIxNTE3LDIxNjI5LDI2MTI2LDMwNDMxLDM2ODU1LDM3NTI4LDQwMTgwLDIzMDE4LDI5Mjc3LDI4MzU3LDIwODEzLDI2ODI1LDMyMTkxLDMyMjM2LDM4NzU0LDQwNjM0LDI1NzIwLDI3MTY5LDMzNTM4LDIyOTE2LDIzMzkxLDI3NjExLDI5NDY3LDMwNDUwLDMyMTc4LDMyNzkxLDMzOTQ1LDIwNzg2LDI2NDA4LDQwNjY1LDMwNDQ2LDI2NDY2LDIxMjQ3LDM5MTczLDIzNTg4LDI1MTQ3LDMxODcwLDM2MDE2LDIxODM5LDI0NzU4LDMyMDExLDM4MjcyLDIxMjQ5LDIwMDYzLDIwOTE4LDIyODEyLDI5MjQyLDMyODIyLDM3MzI2LDI0MzU3LDMwNjkwLDIxMzgwLDI0NDQxLDMyMDA0LDM0MjIwLDM1Mzc5LDM2NDkzLDM4NzQyLDI2NjExLDM0MjIyLDM3OTcxLDI0ODQxLDI0ODQwLDI3ODMzLDMwMjkwLDM1NTY1LDM2NjY0LDIxODA3LDIwMzA1LDIwNzc4LDIxMTkxLDIxNDUxLDIzNDYxLDI0MTg5LDI0NzM2LDI0OTYyLDI1NTU4LDI2Mzc3LDI2NTg2LDI4MjYzLDI4MDQ0LDI5NDk0LDI5NDk1LDMwMDAxLDMxMDU2LDM1MDI5LDM1NDgwLDM2OTM4LDM3MDA5LDM3MTA5LDM4NTk2LDM0NzAxLDIyODA1LDIwMTA0LDIwMzEzLDE5OTgyLDM1NDY1LDM2NjcxLDM4OTI4LDIwNjUzLDI0MTg4LDIyOTM0LDIzNDgxLDI0MjQ4LDI1NTYyLDI1NTk0LDI1NzkzLDI2MzMyLDI2OTU0LDI3MDk2LDI3OTE1LDI4MzQyLDI5MDc2LDI5OTkyLDMxNDA3LDMyNjUwLDMyNzY4LDMzODY1LDMzOTkzLDM1MjAxLDM1NjE3LDM2MzYyLDM2OTY1LDM4NTI1LDM5MTc4LDI0OTU4LDI1MjMzLDI3NDQyLDI3Nzc5LDI4MDIwLDMyNzE2LDMyNzY0LDI4MDk2LDMyNjQ1LDM0NzQ2LDM1MDY0LDI2NDY5LDMzNzEzLDM4OTcyLDM4NjQ3LDI3OTMxLDMyMDk3LDMzODUzLDM3MjI2LDIwMDgxLDIxMzY1LDIzODg4LDI3Mzk2LDI4NjUxLDM0MjUzLDM0MzQ5LDM1MjM5LDIxMDMzLDIxNTE5LDIzNjUzLDI2NDQ2LDI2NzkyLDI5NzAyLDI5ODI3LDMwMTc4LDM1MDIzLDM1MDQxLDM3MzI0LDM4NjI2LDM4NTIwLDI0NDU5LDI5NTc1LDMxNDM1LDMzODcwLDI1NTA0LDMwMDUzLDIxMTI5LDI3OTY5LDI4MzE2LDI5NzA1LDMwMDQxLDMwODI3LDMxODkwLDM4NTM0LDMxNDUyLDQwODQ1LDIwNDA2LDI0OTQyLDI2MDUzLDM0Mzk2LDIwMTAyLDIwMTQyLDIwNjk4LDIwMDAxLDIwOTQwLDIzNTM0LDI2MDA5LDI2NzUzLDI4MDkyLDI5NDcxLDMwMjc0LDMwNjM3LDMxMjYwLDMxOTc1LDMzMzkxLDM1NTM4LDM2OTg4LDM3MzI3LDM4NTE3LDM4OTM2LDIxMTQ3LDMyMjA5LDIwNTIzLDIxNDAwLDI2NTE5LDI4MTA3LDI5MTM2LDI5NzQ3LDMzMjU2LDM2NjUwLDM4NTYzLDQwMDIzLDQwNjA3LDI5NzkyLDIyNTkzLDI4MDU3LDMyMDQ3LDM5MDA2LDIwMTk2LDIwMjc4LDIwMzYzLDIwOTE5LDIxMTY5LDIzOTk0LDI0NjA0LDI5NjE4LDMxMDM2LDMzNDkxLDM3NDI4LDM4NTgzLDM4NjQ2LDM4NjY2LDQwNTk5LDQwODAyLDI2Mjc4LDI3NTA4LDIxMDE1LDIxMTU1LDI4ODcyLDM1MDEwLDI0MjY1LDI0NjUxLDI0OTc2LDI4NDUxLDI5MDAxLDMxODA2LDMyMjQ0LDMyODc5LDM0MDMwLDM2ODk5LDM3Njc2LDIxNTcwLDM5NzkxLDI3MzQ3LDI4ODA5LDM2MDM0LDM2MzM1LDM4NzA2LDIxMTcyLDIzMTA1LDI0MjY2LDI0MzI0LDI2MzkxLDI3MDA0LDI3MDI4LDI4MDEwLDI4NDMxLDI5MjgyLDI5NDM2LDMxNzI1LDMyNzY5LDMyODk0LDM0NjM1LDM3MDcwLDIwODQ1LDQwNTk1LDMxMTA4LDMyOTA3LDM3NjgyLDM1NTQyLDIwNTI1LDIxNjQ0LDM1NDQxLDI3NDk4LDM2MDM2LDMzMDMxLDI0Nzg1LDI2NTI4LDQwNDM0LDIwMTIxLDIwMTIwLDM5OTUyLDM1NDM1LDM0MjQxLDM0MTUyLDI2ODgwLDI4Mjg2LDMwODcxLDMzMTA5LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsMjQzMzIsMTk5ODQsMTk5ODksMjAwMTAsMjAwMTcsMjAwMjIsMjAwMjgsMjAwMzEsMjAwMzQsMjAwNTQsMjAwNTYsMjAwOTgsMjAxMDEsMzU5NDcsMjAxMDYsMzMyOTgsMjQzMzMsMjAxMTAsMjAxMjYsMjAxMjcsMjAxMjgsMjAxMzAsMjAxNDQsMjAxNDcsMjAxNTAsMjAxNzQsMjAxNzMsMjAxNjQsMjAxNjYsMjAxNjIsMjAxODMsMjAxOTAsMjAyMDUsMjAxOTEsMjAyMTUsMjAyMzMsMjAzMTQsMjAyNzIsMjAzMTUsMjAzMTcsMjAzMTEsMjAyOTUsMjAzNDIsMjAzNjAsMjAzNjcsMjAzNzYsMjAzNDcsMjAzMjksMjAzMzYsMjAzNjksMjAzMzUsMjAzNTgsMjAzNzQsMjA3NjAsMjA0MzYsMjA0NDcsMjA0MzAsMjA0NDAsMjA0NDMsMjA0MzMsMjA0NDIsMjA0MzIsMjA0NTIsMjA0NTMsMjA1MDYsMjA1MjAsMjA1MDAsMjA1MjIsMjA1MTcsMjA0ODUsMjAyNTIsMjA0NzAsMjA1MTMsMjA1MjEsMjA1MjQsMjA0NzgsMjA0NjMsMjA0OTcsMjA0ODYsMjA1NDcsMjA1NTEsMjYzNzEsMjA1NjUsMjA1NjAsMjA1NTIsMjA1NzAsMjA1NjYsMjA1ODgsMjA2MDAsMjA2MDgsMjA2MzQsMjA2MTMsMjA2NjAsMjA2NTgsMjA2ODEsMjA2ODIsMjA2NTksMjA2NzQsMjA2OTQsMjA3MDIsMjA3MDksMjA3MTcsMjA3MDcsMjA3MTgsMjA3MjksMjA3MjUsMjA3NDUsMjA3MzcsMjA3MzgsMjA3NTgsMjA3NTcsMjA3NTYsMjA3NjIsMjA3NjksMjA3OTQsMjA3OTEsMjA3OTYsMjA3OTUsMjA3OTksMjA4MDAsMjA4MTgsMjA4MTIsMjA4MjAsMjA4MzQsMzE0ODAsMjA4NDEsMjA4NDIsMjA4NDYsMjA4NjQsMjA4NjYsMjIyMzIsMjA4NzYsMjA4NzMsMjA4NzksMjA4ODEsMjA4ODMsMjA4ODUsMjA4ODYsMjA5MDAsMjA5MDIsMjA4OTgsMjA5MDUsMjA5MDYsMjA5MDcsMjA5MTUsMjA5MTMsMjA5MTQsMjA5MTIsMjA5MTcsMjA5MjUsMjA5MzMsMjA5MzcsMjA5NTUsMjA5NjAsMzQzODksMjA5NjksMjA5NzMsMjA5NzYsMjA5ODEsMjA5OTAsMjA5OTYsMjEwMDMsMjEwMTIsMjEwMDYsMjEwMzEsMjEwMzQsMjEwMzgsMjEwNDMsMjEwNDksMjEwNzEsMjEwNjAsMjEwNjcsMjEwNjgsMjEwODYsMjEwNzYsMjEwOTgsMjExMDgsMjEwOTcsMjExMDcsMjExMTksMjExMTcsMjExMzMsMjExNDAsMjExMzgsMjExMDUsMjExMjgsMjExMzcsMzY3NzYsMzY3NzUsMjExNjQsMjExNjUsMjExODAsMjExNzMsMjExODUsMjExOTcsMjEyMDcsMjEyMTQsMjEyMTksMjEyMjIsMzkxNDksMjEyMTYsMjEyMzUsMjEyMzcsMjEyNDAsMjEyNDEsMjEyNTQsMjEyNTYsMzAwMDgsMjEyNjEsMjEyNjQsMjEyNjMsMjEyNjksMjEyNzQsMjEyODMsMjEyOTUsMjEyOTcsMjEyOTksMjEzMDQsMjEzMTIsMjEzMTgsMjEzMTcsMTk5OTEsMjEzMjEsMjEzMjUsMjA5NTAsMjEzNDIsMjEzNTMsMjEzNTgsMjI4MDgsMjEzNzEsMjEzNjcsMjEzNzgsMjEzOTgsMjE0MDgsMjE0MTQsMjE0MTMsMjE0MjIsMjE0MjQsMjE0MzAsMjE0NDMsMzE3NjIsMzg2MTcsMjE0NzEsMjYzNjQsMjkxNjYsMjE0ODYsMjE0ODAsMjE0ODUsMjE0OTgsMjE1MDUsMjE1NjUsMjE1NjgsMjE1NDgsMjE1NDksMjE1NjQsMjE1NTAsMjE1NTgsMjE1NDUsMjE1MzMsMjE1ODIsMjE2NDcsMjE2MjEsMjE2NDYsMjE1OTksMjE2MTcsMjE2MjMsMjE2MTYsMjE2NTAsMjE2MjcsMjE2MzIsMjE2MjIsMjE2MzYsMjE2NDgsMjE2MzgsMjE3MDMsMjE2NjYsMjE2ODgsMjE2NjksMjE2NzYsMjE3MDAsMjE3MDQsMjE2NzIsMjE2NzUsMjE2OTgsMjE2NjgsMjE2OTQsMjE2OTIsMjE3MjAsMjE3MzMsMjE3MzQsMjE3NzUsMjE3ODAsMjE3NTcsMjE3NDIsMjE3NDEsMjE3NTQsMjE3MzAsMjE4MTcsMjE4MjQsMjE4NTksMjE4MzYsMjE4MDYsMjE4NTIsMjE4MjksMjE4NDYsMjE4NDcsMjE4MTYsMjE4MTEsMjE4NTMsMjE5MTMsMjE4ODgsMjE2NzksMjE4OTgsMjE5MTksMjE4ODMsMjE4ODYsMjE5MTIsMjE5MTgsMjE5MzQsMjE4ODQsMjE4OTEsMjE5MjksMjE4OTUsMjE5MjgsMjE5NzgsMjE5NTcsMjE5ODMsMjE5NTYsMjE5ODAsMjE5ODgsMjE5NzIsMjIwMzYsMjIwMDcsMjIwMzgsMjIwMTQsMjIwMTMsMjIwNDMsMjIwMDksMjIwOTQsMjIwOTYsMjkxNTEsMjIwNjgsMjIwNzAsMjIwNjYsMjIwNzIsMjIxMjMsMjIxMTYsMjIwNjMsMjIxMjQsMjIxMjIsMjIxNTAsMjIxNDQsMjIxNTQsMjIxNzYsMjIxNjQsMjIxNTksMjIxODEsMjIxOTAsMjIxOTgsMjIxOTYsMjIyMTAsMjIyMDQsMjIyMDksMjIyMTEsMjIyMDgsMjIyMTYsMjIyMjIsMjIyMjUsMjIyMjcsMjIyMzEsMjIyNTQsMjIyNjUsMjIyNzIsMjIyNzEsMjIyNzYsMjIyODEsMjIyODAsMjIyODMsMjIyODUsMjIyOTEsMjIyOTYsMjIyOTQsMjE5NTksMjIzMDAsMjIzMTAsMjIzMjcsMjIzMjgsMjIzNTAsMjIzMzEsMjIzMzYsMjIzNTEsMjIzNzcsMjI0NjQsMjI0MDgsMjIzNjksMjIzOTksMjI0MDksMjI0MTksMjI0MzIsMjI0NTEsMjI0MzYsMjI0NDIsMjI0NDgsMjI0NjcsMjI0NzAsMjI0ODQsMjI0ODIsMjI0ODMsMjI1MzgsMjI0ODYsMjI0OTksMjI1MzksMjI1NTMsMjI1NTcsMjI2NDIsMjI1NjEsMjI2MjYsMjI2MDMsMjI2NDAsMjc1ODQsMjI2MTAsMjI1ODksMjI2NDksMjI2NjEsMjI3MTMsMjI2ODcsMjI2OTksMjI3MTQsMjI3NTAsMjI3MTUsMjI3MTIsMjI3MDIsMjI3MjUsMjI3MzksMjI3MzcsMjI3NDMsMjI3NDUsMjI3NDQsMjI3NTcsMjI3NDgsMjI3NTYsMjI3NTEsMjI3NjcsMjI3NzgsMjI3NzcsMjI3NzksMjI3ODAsMjI3ODEsMjI3ODYsMjI3OTQsMjI4MDAsMjI4MTEsMjY3OTAsMjI4MjEsMjI4MjgsMjI4MjksMjI4MzQsMjI4NDAsMjI4NDYsMzE0NDIsMjI4NjksMjI4NjQsMjI4NjIsMjI4NzQsMjI4NzIsMjI4ODIsMjI4ODAsMjI4ODcsMjI4OTIsMjI4ODksMjI5MDQsMjI5MTMsMjI5NDEsMjAzMTgsMjAzOTUsMjI5NDcsMjI5NjIsMjI5ODIsMjMwMTYsMjMwMDQsMjI5MjUsMjMwMDEsMjMwMDIsMjMwNzcsMjMwNzEsMjMwNTcsMjMwNjgsMjMwNDksMjMwNjYsMjMxMDQsMjMxNDgsMjMxMTMsMjMwOTMsMjMwOTQsMjMxMzgsMjMxNDYsMjMxOTQsMjMyMjgsMjMyMzAsMjMyNDMsMjMyMzQsMjMyMjksMjMyNjcsMjMyNTUsMjMyNzAsMjMyNzMsMjMyNTQsMjMyOTAsMjMyOTEsMjMzMDgsMjMzMDcsMjMzMTgsMjMzNDYsMjMyNDgsMjMzMzgsMjMzNTAsMjMzNTgsMjMzNjMsMjMzNjUsMjMzNjAsMjMzNzcsMjMzODEsMjMzODYsMjMzODcsMjMzOTcsMjM0MDEsMjM0MDgsMjM0MTEsMjM0MTMsMjM0MTYsMjU5OTIsMjM0MTgsMjM0MjQsMjM0MjcsMjM0NjIsMjM0ODAsMjM0OTEsMjM0OTUsMjM0OTcsMjM1MDgsMjM1MDQsMjM1MjQsMjM1MjYsMjM1MjIsMjM1MTgsMjM1MjUsMjM1MzEsMjM1MzYsMjM1NDIsMjM1MzksMjM1NTcsMjM1NTksMjM1NjAsMjM1NjUsMjM1NzEsMjM1ODQsMjM1ODYsMjM1OTIsMjM2MDgsMjM2MDksMjM2MTcsMjM2MjIsMjM2MzAsMjM2MzUsMjM2MzIsMjM2MzEsMjM0MDksMjM2NjAsMjM2NjIsMjAwNjYsMjM2NzAsMjM2NzMsMjM2OTIsMjM2OTcsMjM3MDAsMjI5MzksMjM3MjMsMjM3MzksMjM3MzQsMjM3NDAsMjM3MzUsMjM3NDksMjM3NDIsMjM3NTEsMjM3NjksMjM3ODUsMjM4MDUsMjM4MDIsMjM3ODksMjM5NDgsMjM3ODYsMjM4MTksMjM4MjksMjM4MzEsMjM5MDAsMjM4MzksMjM4MzUsMjM4MjUsMjM4MjgsMjM4NDIsMjM4MzQsMjM4MzMsMjM4MzIsMjM4ODQsMjM4OTAsMjM4ODYsMjM4ODMsMjM5MTYsMjM5MjMsMjM5MjYsMjM5NDMsMjM5NDAsMjM5MzgsMjM5NzAsMjM5NjUsMjM5ODAsMjM5ODIsMjM5OTcsMjM5NTIsMjM5OTEsMjM5OTYsMjQwMDksMjQwMTMsMjQwMTksMjQwMTgsMjQwMjIsMjQwMjcsMjQwNDMsMjQwNTAsMjQwNTMsMjQwNzUsMjQwOTAsMjQwODksMjQwODEsMjQwOTEsMjQxMTgsMjQxMTksMjQxMzIsMjQxMzEsMjQxMjgsMjQxNDIsMjQxNTEsMjQxNDgsMjQxNTksMjQxNjIsMjQxNjQsMjQxMzUsMjQxODEsMjQxODIsMjQxODYsNDA2MzYsMjQxOTEsMjQyMjQsMjQyNTcsMjQyNTgsMjQyNjQsMjQyNzIsMjQyNzEsMjQyNzgsMjQyOTEsMjQyODUsMjQyODIsMjQyODMsMjQyOTAsMjQyODksMjQyOTYsMjQyOTcsMjQzMDAsMjQzMDUsMjQzMDcsMjQzMDQsMjQzMDgsMjQzMTIsMjQzMTgsMjQzMjMsMjQzMjksMjQ0MTMsMjQ0MTIsMjQzMzEsMjQzMzcsMjQzNDIsMjQzNjEsMjQzNjUsMjQzNzYsMjQzODUsMjQzOTIsMjQzOTYsMjQzOTgsMjQzNjcsMjQ0MDEsMjQ0MDYsMjQ0MDcsMjQ0MDksMjQ0MTcsMjQ0MjksMjQ0MzUsMjQ0MzksMjQ0NTEsMjQ0NTAsMjQ0NDcsMjQ0NTgsMjQ0NTYsMjQ0NjUsMjQ0NTUsMjQ0NzgsMjQ0NzMsMjQ0NzIsMjQ0ODAsMjQ0ODgsMjQ0OTMsMjQ1MDgsMjQ1MzQsMjQ1NzEsMjQ1NDgsMjQ1NjgsMjQ1NjEsMjQ1NDEsMjQ3NTUsMjQ1NzUsMjQ2MDksMjQ2NzIsMjQ2MDEsMjQ1OTIsMjQ2MTcsMjQ1OTAsMjQ2MjUsMjQ2MDMsMjQ1OTcsMjQ2MTksMjQ2MTQsMjQ1OTEsMjQ2MzQsMjQ2NjYsMjQ2NDEsMjQ2ODIsMjQ2OTUsMjQ2NzEsMjQ2NTAsMjQ2NDYsMjQ2NTMsMjQ2NzUsMjQ2NDMsMjQ2NzYsMjQ2NDIsMjQ2ODQsMjQ2ODMsMjQ2NjUsMjQ3MDUsMjQ3MTcsMjQ4MDcsMjQ3MDcsMjQ3MzAsMjQ3MDgsMjQ3MzEsMjQ3MjYsMjQ3MjcsMjQ3MjIsMjQ3NDMsMjQ3MTUsMjQ4MDEsMjQ3NjAsMjQ4MDAsMjQ3ODcsMjQ3NTYsMjQ1NjAsMjQ3NjUsMjQ3NzQsMjQ3NTcsMjQ3OTIsMjQ5MDksMjQ4NTMsMjQ4MzgsMjQ4MjIsMjQ4MjMsMjQ4MzIsMjQ4MjAsMjQ4MjYsMjQ4MzUsMjQ4NjUsMjQ4MjcsMjQ4MTcsMjQ4NDUsMjQ4NDYsMjQ5MDMsMjQ4OTQsMjQ4NzIsMjQ4NzEsMjQ5MDYsMjQ4OTUsMjQ4OTIsMjQ4NzYsMjQ4ODQsMjQ4OTMsMjQ4OTgsMjQ5MDAsMjQ5NDcsMjQ5NTEsMjQ5MjAsMjQ5MjEsMjQ5MjIsMjQ5MzksMjQ5NDgsMjQ5NDMsMjQ5MzMsMjQ5NDUsMjQ5MjcsMjQ5MjUsMjQ5MTUsMjQ5NDksMjQ5ODUsMjQ5ODIsMjQ5NjcsMjUwMDQsMjQ5ODAsMjQ5ODYsMjQ5NzAsMjQ5NzcsMjUwMDMsMjUwMDYsMjUwMzYsMjUwMzQsMjUwMzMsMjUwNzksMjUwMzIsMjUwMjcsMjUwMzAsMjUwMTgsMjUwMzUsMzI2MzMsMjUwMzcsMjUwNjIsMjUwNTksMjUwNzgsMjUwODIsMjUwNzYsMjUwODcsMjUwODUsMjUwODQsMjUwODYsMjUwODgsMjUwOTYsMjUwOTcsMjUxMDEsMjUxMDAsMjUxMDgsMjUxMTUsMjUxMTgsMjUxMjEsMjUxMzAsMjUxMzQsMjUxMzYsMjUxMzgsMjUxMzksMjUxNTMsMjUxNjYsMjUxODIsMjUxODcsMjUxNzksMjUxODQsMjUxOTIsMjUyMTIsMjUyMTgsMjUyMjUsMjUyMTQsMjUyMzQsMjUyMzUsMjUyMzgsMjUzMDAsMjUyMTksMjUyMzYsMjUzMDMsMjUyOTcsMjUyNzUsMjUyOTUsMjUzNDMsMjUyODYsMjU4MTIsMjUyODgsMjUzMDgsMjUyOTIsMjUyOTAsMjUyODIsMjUyODcsMjUyNDMsMjUyODksMjUzNTYsMjUzMjYsMjUzMjksMjUzODMsMjUzNDYsMjUzNTIsMjUzMjcsMjUzMzMsMjU0MjQsMjU0MDYsMjU0MjEsMjU2MjgsMjU0MjMsMjU0OTQsMjU0ODYsMjU0NzIsMjU1MTUsMjU0NjIsMjU1MDcsMjU0ODcsMjU0ODEsMjU1MDMsMjU1MjUsMjU0NTEsMjU0NDksMjU1MzQsMjU1NzcsMjU1MzYsMjU1NDIsMjU1NzEsMjU1NDUsMjU1NTQsMjU1OTAsMjU1NDAsMjU2MjIsMjU2NTIsMjU2MDYsMjU2MTksMjU2MzgsMjU2NTQsMjU4ODUsMjU2MjMsMjU2NDAsMjU2MTUsMjU3MDMsMjU3MTEsMjU3MTgsMjU2NzgsMjU4OTgsMjU3NDksMjU3NDcsMjU3NjUsMjU3NjksMjU3MzYsMjU3ODgsMjU4MTgsMjU4MTAsMjU3OTcsMjU3OTksMjU3ODcsMjU4MTYsMjU3OTQsMjU4NDEsMjU4MzEsMzMyODksMjU4MjQsMjU4MjUsMjUyNjAsMjU4MjcsMjU4MzksMjU5MDAsMjU4NDYsMjU4NDQsMjU4NDIsMjU4NTAsMjU4NTYsMjU4NTMsMjU4ODAsMjU4ODQsMjU4NjEsMjU4OTIsMjU4OTEsMjU4OTksMjU5MDgsMjU5MDksMjU5MTEsMjU5MTAsMjU5MTIsMzAwMjcsMjU5MjgsMjU5NDIsMjU5NDEsMjU5MzMsMjU5NDQsMjU5NTAsMjU5NDksMjU5NzAsMjU5NzYsMjU5ODYsMjU5ODcsMzU3MjIsMjYwMTEsMjYwMTUsMjYwMjcsMjYwMzksMjYwNTEsMjYwNTQsMjYwNDksMjYwNTIsMjYwNjAsMjYwNjYsMjYwNzUsMjYwNzMsMjYwODAsMjYwODEsMjYwOTcsMjY0ODIsMjYxMjIsMjYxMTUsMjYxMDcsMjY0ODMsMjYxNjUsMjYxNjYsMjYxNjQsMjYxNDAsMjYxOTEsMjYxODAsMjYxODUsMjYxNzcsMjYyMDYsMjYyMDUsMjYyMTIsMjYyMTUsMjYyMTYsMjYyMDcsMjYyMTAsMjYyMjQsMjYyNDMsMjYyNDgsMjYyNTQsMjYyNDksMjYyNDQsMjYyNjQsMjYyNjksMjYzMDUsMjYyOTcsMjYzMTMsMjYzMDIsMjYzMDAsMjYzMDgsMjYyOTYsMjYzMjYsMjYzMzAsMjYzMzYsMjYxNzUsMjYzNDIsMjYzNDUsMjYzNTIsMjYzNTcsMjYzNTksMjYzODMsMjYzOTAsMjYzOTgsMjY0MDYsMjY0MDcsMzg3MTIsMjY0MTQsMjY0MzEsMjY0MjIsMjY0MzMsMjY0MjQsMjY0MjMsMjY0MzgsMjY0NjIsMjY0NjQsMjY0NTcsMjY0NjcsMjY0NjgsMjY1MDUsMjY0ODAsMjY1MzcsMjY0OTIsMjY0NzQsMjY1MDgsMjY1MDcsMjY1MzQsMjY1MjksMjY1MDEsMjY1NTEsMjY2MDcsMjY1NDgsMjY2MDQsMjY1NDcsMjY2MDEsMjY1NTIsMjY1OTYsMjY1OTAsMjY1ODksMjY1OTQsMjY2MDYsMjY1NTMsMjY1NzQsMjY1NjYsMjY1OTksMjcyOTIsMjY2NTQsMjY2OTQsMjY2NjUsMjY2ODgsMjY3MDEsMjY2NzQsMjY3MDIsMjY4MDMsMjY2NjcsMjY3MTMsMjY3MjMsMjY3NDMsMjY3NTEsMjY3ODMsMjY3NjcsMjY3OTcsMjY3NzIsMjY3ODEsMjY3NzksMjY3NTUsMjczMTAsMjY4MDksMjY3NDAsMjY4MDUsMjY3ODQsMjY4MTAsMjY4OTUsMjY3NjUsMjY3NTAsMjY4ODEsMjY4MjYsMjY4ODgsMjY4NDAsMjY5MTQsMjY5MTgsMjY4NDksMjY4OTIsMjY4MjksMjY4MzYsMjY4NTUsMjY4MzcsMjY5MzQsMjY4OTgsMjY4ODQsMjY4MzksMjY4NTEsMjY5MTcsMjY4NzMsMjY4NDgsMjY4NjMsMjY5MjAsMjY5MjIsMjY5MDYsMjY5MTUsMjY5MTMsMjY4MjIsMjcwMDEsMjY5OTksMjY5NzIsMjcwMDAsMjY5ODcsMjY5NjQsMjcwMDYsMjY5OTAsMjY5MzcsMjY5OTYsMjY5NDEsMjY5NjksMjY5MjgsMjY5NzcsMjY5NzQsMjY5NzMsMjcwMDksMjY5ODYsMjcwNTgsMjcwNTQsMjcwODgsMjcwNzEsMjcwNzMsMjcwOTEsMjcwNzAsMjcwODYsMjM1MjgsMjcwODIsMjcxMDEsMjcwNjcsMjcwNzUsMjcwNDcsMjcxODIsMjcwMjUsMjcwNDAsMjcwMzYsMjcwMjksMjcwNjAsMjcxMDIsMjcxMTIsMjcxMzgsMjcxNjMsMjcxMzUsMjc0MDIsMjcxMjksMjcxMjIsMjcxMTEsMjcxNDEsMjcwNTcsMjcxNjYsMjcxMTcsMjcxNTYsMjcxMTUsMjcxNDYsMjcxNTQsMjczMjksMjcxNzEsMjcxNTUsMjcyMDQsMjcxNDgsMjcyNTAsMjcxOTAsMjcyNTYsMjcyMDcsMjcyMzQsMjcyMjUsMjcyMzgsMjcyMDgsMjcxOTIsMjcxNzAsMjcyODAsMjcyNzcsMjcyOTYsMjcyNjgsMjcyOTgsMjcyOTksMjcyODcsMzQzMjcsMjczMjMsMjczMzEsMjczMzAsMjczMjAsMjczMTUsMjczMDgsMjczNTgsMjczNDUsMjczNTksMjczMDYsMjczNTQsMjczNzAsMjczODcsMjczOTcsMzQzMjYsMjczODYsMjc0MTAsMjc0MTQsMzk3MjksMjc0MjMsMjc0NDgsMjc0NDcsMzA0MjgsMjc0NDksMzkxNTAsMjc0NjMsMjc0NTksMjc0NjUsMjc0NzIsMjc0ODEsMjc0NzYsMjc0ODMsMjc0ODcsMjc0ODksMjc1MTIsMjc1MTMsMjc1MTksMjc1MjAsMjc1MjQsMjc1MjMsMjc1MzMsMjc1NDQsMjc1NDEsMjc1NTAsMjc1NTYsMjc1NjIsMjc1NjMsMjc1NjcsMjc1NzAsMjc1NjksMjc1NzEsMjc1NzUsMjc1ODAsMjc1OTAsMjc1OTUsMjc2MDMsMjc2MTUsMjc2MjgsMjc2MjcsMjc2MzUsMjc2MzEsNDA2MzgsMjc2NTYsMjc2NjcsMjc2NjgsMjc2NzUsMjc2ODQsMjc2ODMsMjc3NDIsMjc3MzMsMjc3NDYsMjc3NTQsMjc3NzgsMjc3ODksMjc4MDIsMjc3NzcsMjc4MDMsMjc3NzQsMjc3NTIsMjc3NjMsMjc3OTQsMjc3OTIsMjc4NDQsMjc4ODksMjc4NTksMjc4MzcsMjc4NjMsMjc4NDUsMjc4NjksMjc4MjIsMjc4MjUsMjc4MzgsMjc4MzQsMjc4NjcsMjc4ODcsMjc4NjUsMjc4ODIsMjc5MzUsMzQ4OTMsMjc5NTgsMjc5NDcsMjc5NjUsMjc5NjAsMjc5MjksMjc5NTcsMjc5NTUsMjc5MjIsMjc5MTYsMjgwMDMsMjgwNTEsMjgwMDQsMjc5OTQsMjgwMjUsMjc5OTMsMjgwNDYsMjgwNTMsMjg2NDQsMjgwMzcsMjgxNTMsMjgxODEsMjgxNzAsMjgwODUsMjgxMDMsMjgxMzQsMjgwODgsMjgxMDIsMjgxNDAsMjgxMjYsMjgxMDgsMjgxMzYsMjgxMTQsMjgxMDEsMjgxNTQsMjgxMjEsMjgxMzIsMjgxMTcsMjgxMzgsMjgxNDIsMjgyMDUsMjgyNzAsMjgyMDYsMjgxODUsMjgyNzQsMjgyNTUsMjgyMjIsMjgxOTUsMjgyNjcsMjgyMDMsMjgyNzgsMjgyMzcsMjgxOTEsMjgyMjcsMjgyMTgsMjgyMzgsMjgxOTYsMjg0MTUsMjgxODksMjgyMTYsMjgyOTAsMjgzMzAsMjgzMTIsMjgzNjEsMjgzNDMsMjgzNzEsMjgzNDksMjgzMzUsMjgzNTYsMjgzMzgsMjgzNzIsMjgzNzMsMjgzMDMsMjgzMjUsMjgzNTQsMjgzMTksMjg0ODEsMjg0MzMsMjg3NDgsMjgzOTYsMjg0MDgsMjg0MTQsMjg0NzksMjg0MDIsMjg0NjUsMjgzOTksMjg0NjYsMjgzNjQsMjg0NzgsMjg0MzUsMjg0MDcsMjg1NTAsMjg1MzgsMjg1MzYsMjg1NDUsMjg1NDQsMjg1MjcsMjg1MDcsMjg2NTksMjg1MjUsMjg1NDYsMjg1NDAsMjg1MDQsMjg1NTgsMjg1NjEsMjg2MTAsMjg1MTgsMjg1OTUsMjg1NzksMjg1NzcsMjg1ODAsMjg2MDEsMjg2MTQsMjg1ODYsMjg2MzksMjg2MjksMjg2NTIsMjg2MjgsMjg2MzIsMjg2NTcsMjg2NTQsMjg2MzUsMjg2ODEsMjg2ODMsMjg2NjYsMjg2ODksMjg2NzMsMjg2ODcsMjg2NzAsMjg2OTksMjg2OTgsMjg1MzIsMjg3MDEsMjg2OTYsMjg3MDMsMjg3MjAsMjg3MzQsMjg3MjIsMjg3NTMsMjg3NzEsMjg4MjUsMjg4MTgsMjg4NDcsMjg5MTMsMjg4NDQsMjg4NTYsMjg4NTEsMjg4NDYsMjg4OTUsMjg4NzUsMjg4OTMsMjg4ODksMjg5MzcsMjg5MjUsMjg5NTYsMjg5NTMsMjkwMjksMjkwMTMsMjkwNjQsMjkwMzAsMjkwMjYsMjkwMDQsMjkwMTQsMjkwMzYsMjkwNzEsMjkxNzksMjkwNjAsMjkwNzcsMjkwOTYsMjkxMDAsMjkxNDMsMjkxMTMsMjkxMTgsMjkxMzgsMjkxMjksMjkxNDAsMjkxMzQsMjkxNTIsMjkxNjQsMjkxNTksMjkxNzMsMjkxODAsMjkxNzcsMjkxODMsMjkxOTcsMjkyMDAsMjkyMTEsMjkyMjQsMjkyMjksMjkyMjgsMjkyMzIsMjkyMzQsMjkyNDMsMjkyNDQsMjkyNDcsMjkyNDgsMjkyNTQsMjkyNTksMjkyNzIsMjkzMDAsMjkzMTAsMjkzMTQsMjkzMTMsMjkzMTksMjkzMzAsMjkzMzQsMjkzNDYsMjkzNTEsMjkzNjksMjkzNjIsMjkzNzksMjkzODIsMjkzODAsMjkzOTAsMjkzOTQsMjk0MTAsMjk0MDgsMjk0MDksMjk0MzMsMjk0MzEsMjA0OTUsMjk0NjMsMjk0NTAsMjk0NjgsMjk0NjIsMjk0NjksMjk0OTIsMjk0ODcsMjk0ODEsMjk0NzcsMjk1MDIsMjk1MTgsMjk1MTksNDA2NjQsMjk1MjcsMjk1NDYsMjk1NDQsMjk1NTIsMjk1NjAsMjk1NTcsMjk1NjMsMjk1NjIsMjk2NDAsMjk2MTksMjk2NDYsMjk2MjcsMjk2MzIsMjk2NjksMjk2NzgsMjk2NjIsMjk4NTgsMjk3MDEsMjk4MDcsMjk3MzMsMjk2ODgsMjk3NDYsMjk3NTQsMjk3ODEsMjk3NTksMjk3OTEsMjk3ODUsMjk3NjEsMjk3ODgsMjk4MDEsMjk4MDgsMjk3OTUsMjk4MDIsMjk4MTQsMjk4MjIsMjk4MzUsMjk4NTQsMjk4NjMsMjk4OTgsMjk5MDMsMjk5MDgsMjk2ODEsMjk5MjAsMjk5MjMsMjk5MjcsMjk5MjksMjk5MzQsMjk5MzgsMjk5MzYsMjk5MzcsMjk5NDQsMjk5NDMsMjk5NTYsMjk5NTUsMjk5NTcsMjk5NjQsMjk5NjYsMjk5NjUsMjk5NzMsMjk5NzEsMjk5ODIsMjk5OTAsMjk5OTYsMzAwMTIsMzAwMjAsMzAwMjksMzAwMjYsMzAwMjUsMzAwNDMsMzAwMjIsMzAwNDIsMzAwNTcsMzAwNTIsMzAwNTUsMzAwNTksMzAwNjEsMzAwNzIsMzAwNzAsMzAwODYsMzAwODcsMzAwNjgsMzAwOTAsMzAwODksMzAwODIsMzAxMDAsMzAxMDYsMzAxMDksMzAxMTcsMzAxMTUsMzAxNDYsMzAxMzEsMzAxNDcsMzAxMzMsMzAxNDEsMzAxMzYsMzAxNDAsMzAxMjksMzAxNTcsMzAxNTQsMzAxNjIsMzAxNjksMzAxNzksMzAxNzQsMzAyMDYsMzAyMDcsMzAyMDQsMzAyMDksMzAxOTIsMzAyMDIsMzAxOTQsMzAxOTUsMzAyMTksMzAyMjEsMzAyMTcsMzAyMzksMzAyNDcsMzAyNDAsMzAyNDEsMzAyNDIsMzAyNDQsMzAyNjAsMzAyNTYsMzAyNjcsMzAyNzksMzAyODAsMzAyNzgsMzAzMDAsMzAyOTYsMzAzMDUsMzAzMDYsMzAzMTIsMzAzMTMsMzAzMTQsMzAzMTEsMzAzMTYsMzAzMjAsMzAzMjIsMzAzMjYsMzAzMjgsMzAzMzIsMzAzMzYsMzAzMzksMzAzNDQsMzAzNDcsMzAzNTAsMzAzNTgsMzAzNTUsMzAzNjEsMzAzNjIsMzAzODQsMzAzODgsMzAzOTIsMzAzOTMsMzAzOTQsMzA0MDIsMzA0MTMsMzA0MjIsMzA0MTgsMzA0MzAsMzA0MzMsMzA0MzcsMzA0MzksMzA0NDIsMzQzNTEsMzA0NTksMzA0NzIsMzA0NzEsMzA0NjgsMzA1MDUsMzA1MDAsMzA0OTQsMzA1MDEsMzA1MDIsMzA0OTEsMzA1MTksMzA1MjAsMzA1MzUsMzA1NTQsMzA1NjgsMzA1NzEsMzA1NTUsMzA1NjUsMzA1OTEsMzA1OTAsMzA1ODUsMzA2MDYsMzA2MDMsMzA2MDksMzA2MjQsMzA2MjIsMzA2NDAsMzA2NDYsMzA2NDksMzA2NTUsMzA2NTIsMzA2NTMsMzA2NTEsMzA2NjMsMzA2NjksMzA2NzksMzA2ODIsMzA2ODQsMzA2OTEsMzA3MDIsMzA3MTYsMzA3MzIsMzA3MzgsMzEwMTQsMzA3NTIsMzEwMTgsMzA3ODksMzA4NjIsMzA4MzYsMzA4NTQsMzA4NDQsMzA4NzQsMzA4NjAsMzA4ODMsMzA5MDEsMzA4OTAsMzA4OTUsMzA5MjksMzA5MTgsMzA5MjMsMzA5MzIsMzA5MTAsMzA5MDgsMzA5MTcsMzA5MjIsMzA5NTYsMzA5NTEsMzA5MzgsMzA5NzMsMzA5NjQsMzA5ODMsMzA5OTQsMzA5OTMsMzEwMDEsMzEwMjAsMzEwMTksMzEwNDAsMzEwNzIsMzEwNjMsMzEwNzEsMzEwNjYsMzEwNjEsMzEwNTksMzEwOTgsMzExMDMsMzExMTQsMzExMzMsMzExNDMsNDA3NzksMzExNDYsMzExNTAsMzExNTUsMzExNjEsMzExNjIsMzExNzcsMzExODksMzEyMDcsMzEyMTIsMzEyMDEsMzEyMDMsMzEyNDAsMzEyNDUsMzEyNTYsMzEyNTcsMzEyNjQsMzEyNjMsMzExMDQsMzEyODEsMzEyOTEsMzEyOTQsMzEyODcsMzEyOTksMzEzMTksMzEzMDUsMzEzMjksMzEzMzAsMzEzMzcsNDA4NjEsMzEzNDQsMzEzNTMsMzEzNTcsMzEzNjgsMzEzODMsMzEzODEsMzEzODQsMzEzODIsMzE0MDEsMzE0MzIsMzE0MDgsMzE0MTQsMzE0MjksMzE0MjgsMzE0MjMsMzY5OTUsMzE0MzEsMzE0MzQsMzE0MzcsMzE0MzksMzE0NDUsMzE0NDMsMzE0NDksMzE0NTAsMzE0NTMsMzE0NTcsMzE0NTgsMzE0NjIsMzE0NjksMzE0NzIsMzE0OTAsMzE1MDMsMzE0OTgsMzE0OTQsMzE1MzksMzE1MTIsMzE1MTMsMzE1MTgsMzE1NDEsMzE1MjgsMzE1NDIsMzE1NjgsMzE2MTAsMzE0OTIsMzE1NjUsMzE0OTksMzE1NjQsMzE1NTcsMzE2MDUsMzE1ODksMzE2MDQsMzE1OTEsMzE2MDAsMzE2MDEsMzE1OTYsMzE1OTgsMzE2NDUsMzE2NDAsMzE2NDcsMzE2MjksMzE2NDQsMzE2NDIsMzE2MjcsMzE2MzQsMzE2MzEsMzE1ODEsMzE2NDEsMzE2OTEsMzE2ODEsMzE2OTIsMzE2OTUsMzE2NjgsMzE2ODYsMzE3MDksMzE3MjEsMzE3NjEsMzE3NjQsMzE3MTgsMzE3MTcsMzE4NDAsMzE3NDQsMzE3NTEsMzE3NjMsMzE3MzEsMzE3MzUsMzE3NjcsMzE3NTcsMzE3MzQsMzE3NzksMzE3ODMsMzE3ODYsMzE3NzUsMzE3OTksMzE3ODcsMzE4MDUsMzE4MjAsMzE4MTEsMzE4MjgsMzE4MjMsMzE4MDgsMzE4MjQsMzE4MzIsMzE4MzksMzE4NDQsMzE4MzAsMzE4NDUsMzE4NTIsMzE4NjEsMzE4NzUsMzE4ODgsMzE5MDgsMzE5MTcsMzE5MDYsMzE5MTUsMzE5MDUsMzE5MTIsMzE5MjMsMzE5MjIsMzE5MjEsMzE5MTgsMzE5MjksMzE5MzMsMzE5MzYsMzE5NDEsMzE5MzgsMzE5NjAsMzE5NTQsMzE5NjQsMzE5NzAsMzk3MzksMzE5ODMsMzE5ODYsMzE5ODgsMzE5OTAsMzE5OTQsMzIwMDYsMzIwMDIsMzIwMjgsMzIwMjEsMzIwMTAsMzIwNjksMzIwNzUsMzIwNDYsMzIwNTAsMzIwNjMsMzIwNTMsMzIwNzAsMzIxMTUsMzIwODYsMzIwNzgsMzIxMTQsMzIxMDQsMzIxMTAsMzIwNzksMzIwOTksMzIxNDcsMzIxMzcsMzIwOTEsMzIxNDMsMzIxMjUsMzIxNTUsMzIxODYsMzIxNzQsMzIxNjMsMzIxODEsMzIxOTksMzIxODksMzIxNzEsMzIzMTcsMzIxNjIsMzIxNzUsMzIyMjAsMzIxODQsMzIxNTksMzIxNzYsMzIyMTYsMzIyMjEsMzIyMjgsMzIyMjIsMzIyNTEsMzIyNDIsMzIyMjUsMzIyNjEsMzIyNjYsMzIyOTEsMzIyODksMzIyNzQsMzIzMDUsMzIyODcsMzIyNjUsMzIyNjcsMzIyOTAsMzIzMjYsMzIzNTgsMzIzMTUsMzIzMDksMzIzMTMsMzIzMjMsMzIzMTEsMzIzMDYsMzIzMTQsMzIzNTksMzIzNDksMzIzNDIsMzIzNTAsMzIzNDUsMzIzNDYsMzIzNzcsMzIzNjIsMzIzNjEsMzIzODAsMzIzNzksMzIzODcsMzIyMTMsMzIzODEsMzY3ODIsMzIzODMsMzIzOTIsMzIzOTMsMzIzOTYsMzI0MDIsMzI0MDAsMzI0MDMsMzI0MDQsMzI0MDYsMzIzOTgsMzI0MTEsMzI0MTIsMzI1NjgsMzI1NzAsMzI1ODEsMzI1ODgsMzI1ODksMzI1OTAsMzI1OTIsMzI1OTMsMzI1OTcsMzI1OTYsMzI2MDAsMzI2MDcsMzI2MDgsMzI2MTYsMzI2MTcsMzI2MTUsMzI2MzIsMzI2NDIsMzI2NDYsMzI2NDMsMzI2NDgsMzI2NDcsMzI2NTIsMzI2NjAsMzI2NzAsMzI2NjksMzI2NjYsMzI2NzUsMzI2ODcsMzI2OTAsMzI2OTcsMzI2ODYsMzI2OTQsMzI2OTYsMzU2OTcsMzI3MDksMzI3MTAsMzI3MTQsMzI3MjUsMzI3MjQsMzI3MzcsMzI3NDIsMzI3NDUsMzI3NTUsMzI3NjEsMzkxMzIsMzI3NzQsMzI3NzIsMzI3NzksMzI3ODYsMzI3OTIsMzI3OTMsMzI3OTYsMzI4MDEsMzI4MDgsMzI4MzEsMzI4MjcsMzI4NDIsMzI4MzgsMzI4NTAsMzI4NTYsMzI4NTgsMzI4NjMsMzI4NjYsMzI4NzIsMzI4ODMsMzI4ODIsMzI4ODAsMzI4ODYsMzI4ODksMzI4OTMsMzI4OTUsMzI5MDAsMzI5MDIsMzI5MDEsMzI5MjMsMzI5MTUsMzI5MjIsMzI5NDEsMjA4ODAsMzI5NDAsMzI5ODcsMzI5OTcsMzI5ODUsMzI5ODksMzI5NjQsMzI5ODYsMzI5ODIsMzMwMzMsMzMwMDcsMzMwMDksMzMwNTEsMzMwNjUsMzMwNTksMzMwNzEsMzMwOTksMzg1MzksMzMwOTQsMzMwODYsMzMxMDcsMzMxMDUsMzMwMjAsMzMxMzcsMzMxMzQsMzMxMjUsMzMxMjYsMzMxNDAsMzMxNTUsMzMxNjAsMzMxNjIsMzMxNTIsMzMxNTQsMzMxODQsMzMxNzMsMzMxODgsMzMxODcsMzMxMTksMzMxNzEsMzMxOTMsMzMyMDAsMzMyMDUsMzMyMTQsMzMyMDgsMzMyMTMsMzMyMTYsMzMyMTgsMzMyMTAsMzMyMjUsMzMyMjksMzMyMzMsMzMyNDEsMzMyNDAsMzMyMjQsMzMyNDIsMzMyNDcsMzMyNDgsMzMyNTUsMzMyNzQsMzMyNzUsMzMyNzgsMzMyODEsMzMyODIsMzMyODUsMzMyODcsMzMyOTAsMzMyOTMsMzMyOTYsMzMzMDIsMzMzMjEsMzMzMjMsMzMzMzYsMzMzMzEsMzMzNDQsMzMzNjksMzMzNjgsMzMzNzMsMzMzNzAsMzMzNzUsMzMzODAsMzMzNzgsMzMzODQsMzMzODYsMzMzODcsMzMzMjYsMzMzOTMsMzMzOTksMzM0MDAsMzM0MDYsMzM0MjEsMzM0MjYsMzM0NTEsMzM0MzksMzM0NjcsMzM0NTIsMzM1MDUsMzM1MDcsMzM1MDMsMzM0OTAsMzM1MjQsMzM1MjMsMzM1MzAsMzM2ODMsMzM1MzksMzM1MzEsMzM1MjksMzM1MDIsMzM1NDIsMzM1MDAsMzM1NDUsMzM0OTcsMzM1ODksMzM1ODgsMzM1NTgsMzM1ODYsMzM1ODUsMzM2MDAsMzM1OTMsMzM2MTYsMzM2MDUsMzM1ODMsMzM1NzksMzM1NTksMzM1NjAsMzM2NjksMzM2OTAsMzM3MDYsMzM2OTUsMzM2OTgsMzM2ODYsMzM1NzEsMzM2NzgsMzM2NzEsMzM2NzQsMzM2NjAsMzM3MTcsMzM2NTEsMzM2NTMsMzM2OTYsMzM2NzMsMzM3MDQsMzM3ODAsMzM4MTEsMzM3NzEsMzM3NDIsMzM3ODksMzM3OTUsMzM3NTIsMzM4MDMsMzM3MjksMzM3ODMsMzM3OTksMzM3NjAsMzM3NzgsMzM4MDUsMzM4MjYsMzM4MjQsMzM3MjUsMzM4NDgsMzQwNTQsMzM3ODcsMzM5MDEsMzM4MzQsMzM4NTIsMzQxMzgsMzM5MjQsMzM5MTEsMzM4OTksMzM5NjUsMzM5MDIsMzM5MjIsMzM4OTcsMzM4NjIsMzM4MzYsMzM5MDMsMzM5MTMsMzM4NDUsMzM5OTQsMzM4OTAsMzM5NzcsMzM5ODMsMzM5NTEsMzQwMDksMzM5OTcsMzM5NzksMzQwMTAsMzQwMDAsMzM5ODUsMzM5OTAsMzQwMDYsMzM5NTMsMzQwODEsMzQwNDcsMzQwMzYsMzQwNzEsMzQwNzIsMzQwOTIsMzQwNzksMzQwNjksMzQwNjgsMzQwNDQsMzQxMTIsMzQxNDcsMzQxMzYsMzQxMjAsMzQxMTMsMzQzMDYsMzQxMjMsMzQxMzMsMzQxNzYsMzQyMTIsMzQxODQsMzQxOTMsMzQxODYsMzQyMTYsMzQxNTcsMzQxOTYsMzQyMDMsMzQyODIsMzQxODMsMzQyMDQsMzQxNjcsMzQxNzQsMzQxOTIsMzQyNDksMzQyMzQsMzQyNTUsMzQyMzMsMzQyNTYsMzQyNjEsMzQyNjksMzQyNzcsMzQyNjgsMzQyOTcsMzQzMTQsMzQzMjMsMzQzMTUsMzQzMDIsMzQyOTgsMzQzMTAsMzQzMzgsMzQzMzAsMzQzNTIsMzQzNjcsMzQzODEsMjAwNTMsMzQzODgsMzQzOTksMzQ0MDcsMzQ0MTcsMzQ0NTEsMzQ0NjcsMzQ0NzMsMzQ0NzQsMzQ0NDMsMzQ0NDQsMzQ0ODYsMzQ0NzksMzQ1MDAsMzQ1MDIsMzQ0ODAsMzQ1MDUsMzQ4NTEsMzQ0NzUsMzQ1MTYsMzQ1MjYsMzQ1MzcsMzQ1NDAsMzQ1MjcsMzQ1MjMsMzQ1NDMsMzQ1NzgsMzQ1NjYsMzQ1NjgsMzQ1NjAsMzQ1NjMsMzQ1NTUsMzQ1NzcsMzQ1NjksMzQ1NzMsMzQ1NTMsMzQ1NzAsMzQ2MTIsMzQ2MjMsMzQ2MTUsMzQ2MTksMzQ1OTcsMzQ2MDEsMzQ1ODYsMzQ2NTYsMzQ2NTUsMzQ2ODAsMzQ2MzYsMzQ2MzgsMzQ2NzYsMzQ2NDcsMzQ2NjQsMzQ2NzAsMzQ2NDksMzQ2NDMsMzQ2NTksMzQ2NjYsMzQ4MjEsMzQ3MjIsMzQ3MTksMzQ2OTAsMzQ3MzUsMzQ3NjMsMzQ3NDksMzQ3NTIsMzQ3NjgsMzg2MTQsMzQ3MzEsMzQ3NTYsMzQ3MzksMzQ3NTksMzQ3NTgsMzQ3NDcsMzQ3OTksMzQ4MDIsMzQ3ODQsMzQ4MzEsMzQ4MjksMzQ4MTQsMzQ4MDYsMzQ4MDcsMzQ4MzAsMzQ3NzAsMzQ4MzMsMzQ4MzgsMzQ4MzcsMzQ4NTAsMzQ4NDksMzQ4NjUsMzQ4NzAsMzQ4NzMsMzQ4NTUsMzQ4NzUsMzQ4ODQsMzQ4ODIsMzQ4OTgsMzQ5MDUsMzQ5MTAsMzQ5MTQsMzQ5MjMsMzQ5NDUsMzQ5NDIsMzQ5NzQsMzQ5MzMsMzQ5NDEsMzQ5OTcsMzQ5MzAsMzQ5NDYsMzQ5NjcsMzQ5NjIsMzQ5OTAsMzQ5NjksMzQ5NzgsMzQ5NTcsMzQ5ODAsMzQ5OTIsMzUwMDcsMzQ5OTMsMzUwMTEsMzUwMTIsMzUwMjgsMzUwMzIsMzUwMzMsMzUwMzcsMzUwNjUsMzUwNzQsMzUwNjgsMzUwNjAsMzUwNDgsMzUwNTgsMzUwNzYsMzUwODQsMzUwODIsMzUwOTEsMzUxMzksMzUxMDIsMzUxMDksMzUxMTQsMzUxMTUsMzUxMzcsMzUxNDAsMzUxMzEsMzUxMjYsMzUxMjgsMzUxNDgsMzUxMDEsMzUxNjgsMzUxNjYsMzUxNzQsMzUxNzIsMzUxODEsMzUxNzgsMzUxODMsMzUxODgsMzUxOTEsMzUxOTgsMzUyMDMsMzUyMDgsMzUyMTAsMzUyMTksMzUyMjQsMzUyMzMsMzUyNDEsMzUyMzgsMzUyNDQsMzUyNDcsMzUyNTAsMzUyNTgsMzUyNjEsMzUyNjMsMzUyNjQsMzUyOTAsMzUyOTIsMzUyOTMsMzUzMDMsMzUzMTYsMzUzMjAsMzUzMzEsMzUzNTAsMzUzNDQsMzUzNDAsMzUzNTUsMzUzNTcsMzUzNjUsMzUzODIsMzUzOTMsMzU0MTksMzU0MTAsMzUzOTgsMzU0MDAsMzU0NTIsMzU0MzcsMzU0MzYsMzU0MjYsMzU0NjEsMzU0NTgsMzU0NjAsMzU0OTYsMzU0ODksMzU0NzMsMzU0OTMsMzU0OTQsMzU0ODIsMzU0OTEsMzU1MjQsMzU1MzMsMzU1MjIsMzU1NDYsMzU1NjMsMzU1NzEsMzU1NTksMzU1NTYsMzU1NjksMzU2MDQsMzU1NTIsMzU1NTQsMzU1NzUsMzU1NTAsMzU1NDcsMzU1OTYsMzU1OTEsMzU2MTAsMzU1NTMsMzU2MDYsMzU2MDAsMzU2MDcsMzU2MTYsMzU2MzUsMzg4MjcsMzU2MjIsMzU2MjcsMzU2NDYsMzU2MjQsMzU2NDksMzU2NjAsMzU2NjMsMzU2NjIsMzU2NTcsMzU2NzAsMzU2NzUsMzU2NzQsMzU2OTEsMzU2NzksMzU2OTIsMzU2OTUsMzU3MDAsMzU3MDksMzU3MTIsMzU3MjQsMzU3MjYsMzU3MzAsMzU3MzEsMzU3MzQsMzU3MzcsMzU3MzgsMzU4OTgsMzU5MDUsMzU5MDMsMzU5MTIsMzU5MTYsMzU5MTgsMzU5MjAsMzU5MjUsMzU5MzgsMzU5NDgsMzU5NjAsMzU5NjIsMzU5NzAsMzU5NzcsMzU5NzMsMzU5NzgsMzU5ODEsMzU5ODIsMzU5ODgsMzU5NjQsMzU5OTIsMjUxMTcsMzYwMTMsMzYwMTAsMzYwMjksMzYwMTgsMzYwMTksMzYwMTQsMzYwMjIsMzYwNDAsMzYwMzMsMzYwNjgsMzYwNjcsMzYwNTgsMzYwOTMsMzYwOTAsMzYwOTEsMzYxMDAsMzYxMDEsMzYxMDYsMzYxMDMsMzYxMTEsMzYxMDksMzYxMTIsNDA3ODIsMzYxMTUsMzYwNDUsMzYxMTYsMzYxMTgsMzYxOTksMzYyMDUsMzYyMDksMzYyMTEsMzYyMjUsMzYyNDksMzYyOTAsMzYyODYsMzYyODIsMzYzMDMsMzYzMTQsMzYzMTAsMzYzMDAsMzYzMTUsMzYyOTksMzYzMzAsMzYzMzEsMzYzMTksMzYzMjMsMzYzNDgsMzYzNjAsMzYzNjEsMzYzNTEsMzYzODEsMzYzODIsMzYzNjgsMzYzODMsMzY0MTgsMzY0MDUsMzY0MDAsMzY0MDQsMzY0MjYsMzY0MjMsMzY0MjUsMzY0MjgsMzY0MzIsMzY0MjQsMzY0NDEsMzY0NTIsMzY0NDgsMzYzOTQsMzY0NTEsMzY0MzcsMzY0NzAsMzY0NjYsMzY0NzYsMzY0ODEsMzY0ODcsMzY0ODUsMzY0ODQsMzY0OTEsMzY0OTAsMzY0OTksMzY0OTcsMzY1MDAsMzY1MDUsMzY1MjIsMzY1MTMsMzY1MjQsMzY1MjgsMzY1NTAsMzY1MjksMzY1NDIsMzY1NDksMzY1NTIsMzY1NTUsMzY1NzEsMzY1NzksMzY2MDQsMzY2MDMsMzY1ODcsMzY2MDYsMzY2MTgsMzY2MTMsMzY2MjksMzY2MjYsMzY2MzMsMzY2MjcsMzY2MzYsMzY2MzksMzY2MzUsMzY2MjAsMzY2NDYsMzY2NTksMzY2NjcsMzY2NjUsMzY2NzcsMzY2NzQsMzY2NzAsMzY2ODQsMzY2ODEsMzY2NzgsMzY2ODYsMzY2OTUsMzY3MDAsMzY3MDYsMzY3MDcsMzY3MDgsMzY3NjQsMzY3NjcsMzY3NzEsMzY3ODEsMzY3ODMsMzY3OTEsMzY4MjYsMzY4MzcsMzY4MzQsMzY4NDIsMzY4NDcsMzY5OTksMzY4NTIsMzY4NjksMzY4NTcsMzY4NTgsMzY4ODEsMzY4ODUsMzY4OTcsMzY4NzcsMzY4OTQsMzY4ODYsMzY4NzUsMzY5MDMsMzY5MTgsMzY5MTcsMzY5MjEsMzY4NTYsMzY5NDMsMzY5NDQsMzY5NDUsMzY5NDYsMzY4NzgsMzY5MzcsMzY5MjYsMzY5NTAsMzY5NTIsMzY5NTgsMzY5NjgsMzY5NzUsMzY5ODIsMzg1NjgsMzY5NzgsMzY5OTQsMzY5ODksMzY5OTMsMzY5OTIsMzcwMDIsMzcwMDEsMzcwMDcsMzcwMzIsMzcwMzksMzcwNDEsMzcwNDUsMzcwOTAsMzcwOTIsMjUxNjAsMzcwODMsMzcxMjIsMzcxMzgsMzcxNDUsMzcxNzAsMzcxNjgsMzcxOTQsMzcyMDYsMzcyMDgsMzcyMTksMzcyMjEsMzcyMjUsMzcyMzUsMzcyMzQsMzcyNTksMzcyNTcsMzcyNTAsMzcyODIsMzcyOTEsMzcyOTUsMzcyOTAsMzczMDEsMzczMDAsMzczMDYsMzczMTIsMzczMTMsMzczMjEsMzczMjMsMzczMjgsMzczMzQsMzczNDMsMzczNDUsMzczMzksMzczNzIsMzczNjUsMzczNjYsMzc0MDYsMzczNzUsMzczOTYsMzc0MjAsMzczOTcsMzczOTMsMzc0NzAsMzc0NjMsMzc0NDUsMzc0NDksMzc0NzYsMzc0NDgsMzc1MjUsMzc0MzksMzc0NTEsMzc0NTYsMzc1MzIsMzc1MjYsMzc1MjMsMzc1MzEsMzc0NjYsMzc1ODMsMzc1NjEsMzc1NTksMzc2MDksMzc2NDcsMzc2MjYsMzc3MDAsMzc2NzgsMzc2NTcsMzc2NjYsMzc2NTgsMzc2NjcsMzc2OTAsMzc2ODUsMzc2OTEsMzc3MjQsMzc3MjgsMzc3NTYsMzc3NDIsMzc3MTgsMzc4MDgsMzc4MDQsMzc4MDUsMzc3ODAsMzc4MTcsMzc4NDYsMzc4NDcsMzc4NjQsMzc4NjEsMzc4NDgsMzc4MjcsMzc4NTMsMzc4NDAsMzc4MzIsMzc4NjAsMzc5MTQsMzc5MDgsMzc5MDcsMzc4OTEsMzc4OTUsMzc5MDQsMzc5NDIsMzc5MzEsMzc5NDEsMzc5MjEsMzc5NDYsMzc5NTMsMzc5NzAsMzc5NTYsMzc5NzksMzc5ODQsMzc5ODYsMzc5ODIsMzc5OTQsMzc0MTcsMzgwMDAsMzgwMDUsMzgwMDcsMzgwMTMsMzc5NzgsMzgwMTIsMzgwMTQsMzgwMTcsMzgwMTUsMzgyNzQsMzgyNzksMzgyODIsMzgyOTIsMzgyOTQsMzgyOTYsMzgyOTcsMzgzMDQsMzgzMTIsMzgzMTEsMzgzMTcsMzgzMzIsMzgzMzEsMzgzMjksMzgzMzQsMzgzNDYsMjg2NjIsMzgzMzksMzgzNDksMzgzNDgsMzgzNTcsMzgzNTYsMzgzNTgsMzgzNjQsMzgzNjksMzgzNzMsMzgzNzAsMzg0MzMsMzg0NDAsMzg0NDYsMzg0NDcsMzg0NjYsMzg0NzYsMzg0NzksMzg0NzUsMzg1MTksMzg0OTIsMzg0OTQsMzg0OTMsMzg0OTUsMzg1MDIsMzg1MTQsMzg1MDgsMzg1NDEsMzg1NTIsMzg1NDksMzg1NTEsMzg1NzAsMzg1NjcsMzg1NzcsMzg1NzgsMzg1NzYsMzg1ODAsMzg1ODIsMzg1ODQsMzg1ODUsMzg2MDYsMzg2MDMsMzg2MDEsMzg2MDUsMzUxNDksMzg2MjAsMzg2NjksMzg2MTMsMzg2NDksMzg2NjAsMzg2NjIsMzg2NjQsMzg2NzUsMzg2NzAsMzg2NzMsMzg2NzEsMzg2NzgsMzg2ODEsMzg2OTIsMzg2OTgsMzg3MDQsMzg3MTMsMzg3MTcsMzg3MTgsMzg3MjQsMzg3MjYsMzg3MjgsMzg3MjIsMzg3MjksMzg3NDgsMzg3NTIsMzg3NTYsMzg3NTgsMzg3NjAsMjEyMDIsMzg3NjMsMzg3NjksMzg3NzcsMzg3ODksMzg3ODAsMzg3ODUsMzg3NzgsMzg3OTAsMzg3OTUsMzg3OTksMzg4MDAsMzg4MTIsMzg4MjQsMzg4MjIsMzg4MTksMzg4MzUsMzg4MzYsMzg4NTEsMzg4NTQsMzg4NTYsMzg4NTksMzg4NzYsMzg4OTMsNDA3ODMsMzg4OTgsMzE0NTUsMzg5MDIsMzg5MDEsMzg5MjcsMzg5MjQsMzg5NjgsMzg5NDgsMzg5NDUsMzg5NjcsMzg5NzMsMzg5ODIsMzg5OTEsMzg5ODcsMzkwMTksMzkwMjMsMzkwMjQsMzkwMjUsMzkwMjgsMzkwMjcsMzkwODIsMzkwODcsMzkwODksMzkwOTQsMzkxMDgsMzkxMDcsMzkxMTAsMzkxNDUsMzkxNDcsMzkxNzEsMzkxNzcsMzkxODYsMzkxODgsMzkxOTIsMzkyMDEsMzkxOTcsMzkxOTgsMzkyMDQsMzkyMDAsMzkyMTIsMzkyMTQsMzkyMjksMzkyMzAsMzkyMzQsMzkyNDEsMzkyMzcsMzkyNDgsMzkyNDMsMzkyNDksMzkyNTAsMzkyNDQsMzkyNTMsMzkzMTksMzkzMjAsMzkzMzMsMzkzNDEsMzkzNDIsMzkzNTYsMzkzOTEsMzkzODcsMzkzODksMzkzODQsMzkzNzcsMzk0MDUsMzk0MDYsMzk0MDksMzk0MTAsMzk0MTksMzk0MTYsMzk0MjUsMzk0MzksMzk0MjksMzkzOTQsMzk0NDksMzk0NjcsMzk0NzksMzk0OTMsMzk0OTAsMzk0ODgsMzk0OTEsMzk0ODYsMzk1MDksMzk1MDEsMzk1MTUsMzk1MTEsMzk1MTksMzk1MjIsMzk1MjUsMzk1MjQsMzk1MjksMzk1MzEsMzk1MzAsMzk1OTcsMzk2MDAsMzk2MTIsMzk2MTYsMzk2MzEsMzk2MzMsMzk2MzUsMzk2MzYsMzk2NDYsMzk2NDcsMzk2NTAsMzk2NTEsMzk2NTQsMzk2NjMsMzk2NTksMzk2NjIsMzk2NjgsMzk2NjUsMzk2NzEsMzk2NzUsMzk2ODYsMzk3MDQsMzk3MDYsMzk3MTEsMzk3MTQsMzk3MTUsMzk3MTcsMzk3MTksMzk3MjAsMzk3MjEsMzk3MjIsMzk3MjYsMzk3MjcsMzk3MzAsMzk3NDgsMzk3NDcsMzk3NTksMzk3NTcsMzk3NTgsMzk3NjEsMzk3NjgsMzk3OTYsMzk4MjcsMzk4MTEsMzk4MjUsMzk4MzAsMzk4MzEsMzk4MzksMzk4NDAsMzk4NDgsMzk4NjAsMzk4NzIsMzk4ODIsMzk4NjUsMzk4NzgsMzk4ODcsMzk4ODksMzk4OTAsMzk5MDcsMzk5MDYsMzk5MDgsMzk4OTIsMzk5MDUsMzk5OTQsMzk5MjIsMzk5MjEsMzk5MjAsMzk5NTcsMzk5NTYsMzk5NDUsMzk5NTUsMzk5NDgsMzk5NDIsMzk5NDQsMzk5NTQsMzk5NDYsMzk5NDAsMzk5ODIsMzk5NjMsMzk5NzMsMzk5NzIsMzk5NjksMzk5ODQsNDAwMDcsMzk5ODYsNDAwMDYsMzk5OTgsNDAwMjYsNDAwMzIsNDAwMzksNDAwNTQsNDAwNTYsNDAxNjcsNDAxNzIsNDAxNzYsNDAyMDEsNDAyMDAsNDAxNzEsNDAxOTUsNDAxOTgsNDAyMzQsNDAyMzAsNDAzNjcsNDAyMjcsNDAyMjMsNDAyNjAsNDAyMTMsNDAyMTAsNDAyNTcsNDAyNTUsNDAyNTQsNDAyNjIsNDAyNjQsNDAyODUsNDAyODYsNDAyOTIsNDAyNzMsNDAyNzIsNDAyODEsNDAzMDYsNDAzMjksNDAzMjcsNDAzNjMsNDAzMDMsNDAzMTQsNDAzNDYsNDAzNTYsNDAzNjEsNDAzNzAsNDAzODgsNDAzODUsNDAzNzksNDAzNzYsNDAzNzgsNDAzOTAsNDAzOTksNDAzODYsNDA0MDksNDA0MDMsNDA0NDAsNDA0MjIsNDA0MjksNDA0MzEsNDA0NDUsNDA0NzQsNDA0NzUsNDA0NzgsNDA1NjUsNDA1NjksNDA1NzMsNDA1NzcsNDA1ODQsNDA1ODcsNDA1ODgsNDA1OTQsNDA1OTcsNDA1OTMsNDA2MDUsNDA2MTMsNDA2MTcsNDA2MzIsNDA2MTgsNDA2MjEsMzg3NTMsNDA2NTIsNDA2NTQsNDA2NTUsNDA2NTYsNDA2NjAsNDA2NjgsNDA2NzAsNDA2NjksNDA2NzIsNDA2NzcsNDA2ODAsNDA2ODcsNDA2OTIsNDA2OTQsNDA2OTUsNDA2OTcsNDA2OTksNDA3MDAsNDA3MDEsNDA3MTEsNDA3MTIsMzAzOTEsNDA3MjUsNDA3MzcsNDA3NDgsNDA3NjYsNDA3NzgsNDA3ODYsNDA3ODgsNDA4MDMsNDA3OTksNDA4MDAsNDA4MDEsNDA4MDYsNDA4MDcsNDA4MTIsNDA4MTAsNDA4MjMsNDA4MTgsNDA4MjIsNDA4NTMsNDA4NjAsNDA4NjQsMjI1NzUsMjcwNzksMzY5NTMsMjk3OTYsMjA5NTYsMjkwODEsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDMyMzk0LDM1MTAwLDM3NzA0LDM3NTEyLDM0MDEyLDIwNDI1LDI4ODU5LDI2MTYxLDI2ODI0LDM3NjI1LDI2MzYzLDI0Mzg5LDIwMDA4LDIwMTkzLDIwMjIwLDIwMjI0LDIwMjI3LDIwMjgxLDIwMzEwLDIwMzcwLDIwMzYyLDIwMzc4LDIwMzcyLDIwNDI5LDIwNTQ0LDIwNTE0LDIwNDc5LDIwNTEwLDIwNTUwLDIwNTkyLDIwNTQ2LDIwNjI4LDIwNzI0LDIwNjk2LDIwODEwLDIwODM2LDIwODkzLDIwOTI2LDIwOTcyLDIxMDEzLDIxMTQ4LDIxMTU4LDIxMTg0LDIxMjExLDIxMjQ4LDIxMjU1LDIxMjg0LDIxMzYyLDIxMzk1LDIxNDI2LDIxNDY5LDY0MDE0LDIxNjYwLDIxNjQyLDIxNjczLDIxNzU5LDIxODk0LDIyMzYxLDIyMzczLDIyNDQ0LDIyNDcyLDIyNDcxLDY0MDE1LDY0MDE2LDIyNjg2LDIyNzA2LDIyNzk1LDIyODY3LDIyODc1LDIyODc3LDIyODgzLDIyOTQ4LDIyOTcwLDIzMzgyLDIzNDg4LDI5OTk5LDIzNTEyLDIzNTMyLDIzNTgyLDIzNzE4LDIzNzM4LDIzNzk3LDIzODQ3LDIzODkxLDY0MDE3LDIzODc0LDIzOTE3LDIzOTkyLDIzOTkzLDI0MDE2LDI0MzUzLDI0MzcyLDI0NDIzLDI0NTAzLDI0NTQyLDI0NjY5LDI0NzA5LDI0NzE0LDI0Nzk4LDI0Nzg5LDI0ODY0LDI0ODE4LDI0ODQ5LDI0ODg3LDI0ODgwLDI0OTg0LDI1MTA3LDI1MjU0LDI1NTg5LDI1Njk2LDI1NzU3LDI1ODA2LDI1OTM0LDI2MTEyLDI2MTMzLDI2MTcxLDI2MTIxLDI2MTU4LDI2MTQyLDI2MTQ4LDI2MjEzLDI2MTk5LDI2MjAxLDY0MDE4LDI2MjI3LDI2MjY1LDI2MjcyLDI2MjkwLDI2MzAzLDI2MzYyLDI2MzgyLDYzNzg1LDI2NDcwLDI2NTU1LDI2NzA2LDI2NTYwLDI2NjI1LDI2NjkyLDI2ODMxLDY0MDE5LDI2OTg0LDY0MDIwLDI3MDMyLDI3MTA2LDI3MTg0LDI3MjQzLDI3MjA2LDI3MjUxLDI3MjYyLDI3MzYyLDI3MzY0LDI3NjA2LDI3NzExLDI3NzQwLDI3NzgyLDI3NzU5LDI3ODY2LDI3OTA4LDI4MDM5LDI4MDE1LDI4MDU0LDI4MDc2LDI4MTExLDI4MTUyLDI4MTQ2LDI4MTU2LDI4MjE3LDI4MjUyLDI4MTk5LDI4MjIwLDI4MzUxLDI4NTUyLDI4NTk3LDI4NjYxLDI4Njc3LDI4Njc5LDI4NzEyLDI4ODA1LDI4ODQzLDI4OTQzLDI4OTMyLDI5MDIwLDI4OTk4LDI4OTk5LDY0MDIxLDI5MTIxLDI5MTgyLDI5MzYxLDI5Mzc0LDI5NDc2LDY0MDIyLDI5NTU5LDI5NjI5LDI5NjQxLDI5NjU0LDI5NjY3LDI5NjUwLDI5NzAzLDI5Njg1LDI5NzM0LDI5NzM4LDI5NzM3LDI5NzQyLDI5Nzk0LDI5ODMzLDI5ODU1LDI5OTUzLDMwMDYzLDMwMzM4LDMwMzY0LDMwMzY2LDMwMzYzLDMwMzc0LDY0MDIzLDMwNTM0LDIxMTY3LDMwNzUzLDMwNzk4LDMwODIwLDMwODQyLDMxMDI0LDY0MDI0LDY0MDI1LDY0MDI2LDMxMTI0LDY0MDI3LDMxMTMxLDMxNDQxLDMxNDYzLDY0MDI4LDMxNDY3LDMxNjQ2LDY0MDI5LDMyMDcyLDMyMDkyLDMyMTgzLDMyMTYwLDMyMjE0LDMyMzM4LDMyNTgzLDMyNjczLDY0MDMwLDMzNTM3LDMzNjM0LDMzNjYzLDMzNzM1LDMzNzgyLDMzODY0LDMzOTcyLDM0MTMxLDM0MTM3LDM0MTU1LDY0MDMxLDM0MjI0LDY0MDMyLDY0MDMzLDM0ODIzLDM1MDYxLDM1MzQ2LDM1MzgzLDM1NDQ5LDM1NDk1LDM1NTE4LDM1NTUxLDY0MDM0LDM1NTc0LDM1NjY3LDM1NzExLDM2MDgwLDM2MDg0LDM2MTE0LDM2MjE0LDY0MDM1LDM2NTU5LDY0MDM2LDY0MDM3LDM2OTY3LDM3MDg2LDY0MDM4LDM3MTQxLDM3MTU5LDM3MzM4LDM3MzM1LDM3MzQyLDM3MzU3LDM3MzU4LDM3MzQ4LDM3MzQ5LDM3MzgyLDM3MzkyLDM3Mzg2LDM3NDM0LDM3NDQwLDM3NDM2LDM3NDU0LDM3NDY1LDM3NDU3LDM3NDMzLDM3NDc5LDM3NTQzLDM3NDk1LDM3NDk2LDM3NjA3LDM3NTkxLDM3NTkzLDM3NTg0LDY0MDM5LDM3NTg5LDM3NjAwLDM3NTg3LDM3NjY5LDM3NjY1LDM3NjI3LDY0MDQwLDM3NjYyLDM3NjMxLDM3NjYxLDM3NjM0LDM3NzQ0LDM3NzE5LDM3Nzk2LDM3ODMwLDM3ODU0LDM3ODgwLDM3OTM3LDM3OTU3LDM3OTYwLDM4MjkwLDYzOTY0LDY0MDQxLDM4NTU3LDM4NTc1LDM4NzA3LDM4NzE1LDM4NzIzLDM4NzMzLDM4NzM1LDM4NzM3LDM4NzQxLDM4OTk5LDM5MDEzLDY0MDQyLDY0MDQzLDM5MjA3LDY0MDQ0LDM5MzI2LDM5NTAyLDM5NjQxLDM5NjQ0LDM5Nzk3LDM5Nzk0LDM5ODIzLDM5ODU3LDM5ODY3LDM5OTM2LDQwMzA0LDQwMjk5LDY0MDQ1LDQwNDczLDQwNjU3LG51bGwsbnVsbCw4NTYwLDg1NjEsODU2Miw4NTYzLDg1NjQsODU2NSw4NTY2LDg1NjcsODU2OCw4NTY5LDY1NTA2LDY1NTA4LDY1Mjg3LDY1MjgyLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsODU2MCw4NTYxLDg1NjIsODU2Myw4NTY0LDg1NjUsODU2Niw4NTY3LDg1NjgsODU2OSw4NTQ0LDg1NDUsODU0Niw4NTQ3LDg1NDgsODU0OSw4NTUwLDg1NTEsODU1Miw4NTUzLDY1NTA2LDY1NTA4LDY1Mjg3LDY1MjgyLDEyODQ5LDg0NzAsODQ4MSw4NzU3LDMyMzk0LDM1MTAwLDM3NzA0LDM3NTEyLDM0MDEyLDIwNDI1LDI4ODU5LDI2MTYxLDI2ODI0LDM3NjI1LDI2MzYzLDI0Mzg5LDIwMDA4LDIwMTkzLDIwMjIwLDIwMjI0LDIwMjI3LDIwMjgxLDIwMzEwLDIwMzcwLDIwMzYyLDIwMzc4LDIwMzcyLDIwNDI5LDIwNTQ0LDIwNTE0LDIwNDc5LDIwNTEwLDIwNTUwLDIwNTkyLDIwNTQ2LDIwNjI4LDIwNzI0LDIwNjk2LDIwODEwLDIwODM2LDIwODkzLDIwOTI2LDIwOTcyLDIxMDEzLDIxMTQ4LDIxMTU4LDIxMTg0LDIxMjExLDIxMjQ4LDIxMjU1LDIxMjg0LDIxMzYyLDIxMzk1LDIxNDI2LDIxNDY5LDY0MDE0LDIxNjYwLDIxNjQyLDIxNjczLDIxNzU5LDIxODk0LDIyMzYxLDIyMzczLDIyNDQ0LDIyNDcyLDIyNDcxLDY0MDE1LDY0MDE2LDIyNjg2LDIyNzA2LDIyNzk1LDIyODY3LDIyODc1LDIyODc3LDIyODgzLDIyOTQ4LDIyOTcwLDIzMzgyLDIzNDg4LDI5OTk5LDIzNTEyLDIzNTMyLDIzNTgyLDIzNzE4LDIzNzM4LDIzNzk3LDIzODQ3LDIzODkxLDY0MDE3LDIzODc0LDIzOTE3LDIzOTkyLDIzOTkzLDI0MDE2LDI0MzUzLDI0MzcyLDI0NDIzLDI0NTAzLDI0NTQyLDI0NjY5LDI0NzA5LDI0NzE0LDI0Nzk4LDI0Nzg5LDI0ODY0LDI0ODE4LDI0ODQ5LDI0ODg3LDI0ODgwLDI0OTg0LDI1MTA3LDI1MjU0LDI1NTg5LDI1Njk2LDI1NzU3LDI1ODA2LDI1OTM0LDI2MTEyLDI2MTMzLDI2MTcxLDI2MTIxLDI2MTU4LDI2MTQyLDI2MTQ4LDI2MjEzLDI2MTk5LDI2MjAxLDY0MDE4LDI2MjI3LDI2MjY1LDI2MjcyLDI2MjkwLDI2MzAzLDI2MzYyLDI2MzgyLDYzNzg1LDI2NDcwLDI2NTU1LDI2NzA2LDI2NTYwLDI2NjI1LDI2NjkyLDI2ODMxLDY0MDE5LDI2OTg0LDY0MDIwLDI3MDMyLDI3MTA2LDI3MTg0LDI3MjQzLDI3MjA2LDI3MjUxLDI3MjYyLDI3MzYyLDI3MzY0LDI3NjA2LDI3NzExLDI3NzQwLDI3NzgyLDI3NzU5LDI3ODY2LDI3OTA4LDI4MDM5LDI4MDE1LDI4MDU0LDI4MDc2LDI4MTExLDI4MTUyLDI4MTQ2LDI4MTU2LDI4MjE3LDI4MjUyLDI4MTk5LDI4MjIwLDI4MzUxLDI4NTUyLDI4NTk3LDI4NjYxLDI4Njc3LDI4Njc5LDI4NzEyLDI4ODA1LDI4ODQzLDI4OTQzLDI4OTMyLDI5MDIwLDI4OTk4LDI4OTk5LDY0MDIxLDI5MTIxLDI5MTgyLDI5MzYxLDI5Mzc0LDI5NDc2LDY0MDIyLDI5NTU5LDI5NjI5LDI5NjQxLDI5NjU0LDI5NjY3LDI5NjUwLDI5NzAzLDI5Njg1LDI5NzM0LDI5NzM4LDI5NzM3LDI5NzQyLDI5Nzk0LDI5ODMzLDI5ODU1LDI5OTUzLDMwMDYzLDMwMzM4LDMwMzY0LDMwMzY2LDMwMzYzLDMwMzc0LDY0MDIzLDMwNTM0LDIxMTY3LDMwNzUzLDMwNzk4LDMwODIwLDMwODQyLDMxMDI0LDY0MDI0LDY0MDI1LDY0MDI2LDMxMTI0LDY0MDI3LDMxMTMxLDMxNDQxLDMxNDYzLDY0MDI4LDMxNDY3LDMxNjQ2LDY0MDI5LDMyMDcyLDMyMDkyLDMyMTgzLDMyMTYwLDMyMjE0LDMyMzM4LDMyNTgzLDMyNjczLDY0MDMwLDMzNTM3LDMzNjM0LDMzNjYzLDMzNzM1LDMzNzgyLDMzODY0LDMzOTcyLDM0MTMxLDM0MTM3LDM0MTU1LDY0MDMxLDM0MjI0LDY0MDMyLDY0MDMzLDM0ODIzLDM1MDYxLDM1MzQ2LDM1MzgzLDM1NDQ5LDM1NDk1LDM1NTE4LDM1NTUxLDY0MDM0LDM1NTc0LDM1NjY3LDM1NzExLDM2MDgwLDM2MDg0LDM2MTE0LDM2MjE0LDY0MDM1LDM2NTU5LDY0MDM2LDY0MDM3LDM2OTY3LDM3MDg2LDY0MDM4LDM3MTQxLDM3MTU5LDM3MzM4LDM3MzM1LDM3MzQyLDM3MzU3LDM3MzU4LDM3MzQ4LDM3MzQ5LDM3MzgyLDM3MzkyLDM3Mzg2LDM3NDM0LDM3NDQwLDM3NDM2LDM3NDU0LDM3NDY1LDM3NDU3LDM3NDMzLDM3NDc5LDM3NTQzLDM3NDk1LDM3NDk2LDM3NjA3LDM3NTkxLDM3NTkzLDM3NTg0LDY0MDM5LDM3NTg5LDM3NjAwLDM3NTg3LDM3NjY5LDM3NjY1LDM3NjI3LDY0MDQwLDM3NjYyLDM3NjMxLDM3NjYxLDM3NjM0LDM3NzQ0LDM3NzE5LDM3Nzk2LDM3ODMwLDM3ODU0LDM3ODgwLDM3OTM3LDM3OTU3LDM3OTYwLDM4MjkwLDYzOTY0LDY0MDQxLDM4NTU3LDM4NTc1LDM4NzA3LDM4NzE1LDM4NzIzLDM4NzMzLDM4NzM1LDM4NzM3LDM4NzQxLDM4OTk5LDM5MDEzLDY0MDQyLDY0MDQzLDM5MjA3LDY0MDQ0LDM5MzI2LDM5NTAyLDM5NjQxLDM5NjQ0LDM5Nzk3LDM5Nzk0LDM5ODIzLDM5ODU3LDM5ODY3LDM5OTM2LDQwMzA0LDQwMjk5LDY0MDQ1LDQwNDczLDQwNjU3LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbF0sXG4gIFwiamlzMDIxMlwiOltudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw3MjgsNzExLDE4NCw3MjksNzMzLDE3NSw3MzEsNzMwLDY1Mzc0LDkwMCw5MDEsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDE2MSwxNjYsMTkxLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCwxODYsMTcwLDE2OSwxNzQsODQ4MiwxNjQsODQ3MCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsOTAyLDkwNCw5MDUsOTA2LDkzOCxudWxsLDkwOCxudWxsLDkxMCw5MzksbnVsbCw5MTEsbnVsbCxudWxsLG51bGwsbnVsbCw5NDAsOTQxLDk0Miw5NDMsOTcwLDkxMiw5NzIsOTYyLDk3Myw5NzEsOTQ0LDk3NCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsMTAyNiwxMDI3LDEwMjgsMTAyOSwxMDMwLDEwMzEsMTAzMiwxMDMzLDEwMzQsMTAzNSwxMDM2LDEwMzgsMTAzOSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsMTEwNiwxMTA3LDExMDgsMTEwOSwxMTEwLDExMTEsMTExMiwxMTEzLDExMTQsMTExNSwxMTE2LDExMTgsMTExOSxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDE5OCwyNzIsbnVsbCwyOTQsbnVsbCwzMDYsbnVsbCwzMjEsMzE5LG51bGwsMzMwLDIxNiwzMzgsbnVsbCwzNTgsMjIyLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsMjMwLDI3MywyNDAsMjk1LDMwNSwzMDcsMzEyLDMyMiwzMjAsMzI5LDMzMSwyNDgsMzM5LDIyMywzNTksMjU0LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsMTkzLDE5MiwxOTYsMTk0LDI1OCw0NjEsMjU2LDI2MCwxOTcsMTk1LDI2MiwyNjQsMjY4LDE5OSwyNjYsMjcwLDIwMSwyMDAsMjAzLDIwMiwyODIsMjc4LDI3NCwyODAsbnVsbCwyODQsMjg2LDI5MCwyODgsMjkyLDIwNSwyMDQsMjA3LDIwNiw0NjMsMzA0LDI5OCwzMDIsMjk2LDMwOCwzMTAsMzEzLDMxNywzMTUsMzIzLDMyNywzMjUsMjA5LDIxMSwyMTAsMjE0LDIxMiw0NjUsMzM2LDMzMiwyMTMsMzQwLDM0NCwzNDIsMzQ2LDM0OCwzNTIsMzUwLDM1NiwzNTQsMjE4LDIxNywyMjAsMjE5LDM2NCw0NjcsMzY4LDM2MiwzNzAsMzY2LDM2MCw0NzEsNDc1LDQ3Myw0NjksMzcyLDIyMSwzNzYsMzc0LDM3NywzODEsMzc5LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsMjI1LDIyNCwyMjgsMjI2LDI1OSw0NjIsMjU3LDI2MSwyMjksMjI3LDI2MywyNjUsMjY5LDIzMSwyNjcsMjcxLDIzMywyMzIsMjM1LDIzNCwyODMsMjc5LDI3NSwyODEsNTAxLDI4NSwyODcsbnVsbCwyODksMjkzLDIzNywyMzYsMjM5LDIzOCw0NjQsbnVsbCwyOTksMzAzLDI5NywzMDksMzExLDMxNCwzMTgsMzE2LDMyNCwzMjgsMzI2LDI0MSwyNDMsMjQyLDI0NiwyNDQsNDY2LDMzNywzMzMsMjQ1LDM0MSwzNDUsMzQzLDM0NywzNDksMzUzLDM1MSwzNTcsMzU1LDI1MCwyNDksMjUyLDI1MSwzNjUsNDY4LDM2OSwzNjMsMzcxLDM2NywzNjEsNDcyLDQ3Niw0NzQsNDcwLDM3MywyNTMsMjU1LDM3NSwzNzgsMzgyLDM4MCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsMTk5NzAsMTk5NzIsMTk5NzMsMTk5ODAsMTk5ODYsMTk5OTksMjAwMDMsMjAwMDQsMjAwMDgsMjAwMTEsMjAwMTQsMjAwMTUsMjAwMTYsMjAwMjEsMjAwMzIsMjAwMzMsMjAwMzYsMjAwMzksMjAwNDksMjAwNTgsMjAwNjAsMjAwNjcsMjAwNzIsMjAwNzMsMjAwODQsMjAwODUsMjAwODksMjAwOTUsMjAxMDksMjAxMTgsMjAxMTksMjAxMjUsMjAxNDMsMjAxNTMsMjAxNjMsMjAxNzYsMjAxODYsMjAxODcsMjAxOTIsMjAxOTMsMjAxOTQsMjAyMDAsMjAyMDcsMjAyMDksMjAyMTEsMjAyMTMsMjAyMjEsMjAyMjIsMjAyMjMsMjAyMjQsMjAyMjYsMjAyMjcsMjAyMzIsMjAyMzUsMjAyMzYsMjAyNDIsMjAyNDUsMjAyNDYsMjAyNDcsMjAyNDksMjAyNzAsMjAyNzMsMjAzMjAsMjAyNzUsMjAyNzcsMjAyNzksMjAyODEsMjAyODMsMjAyODYsMjAyODgsMjAyOTAsMjAyOTYsMjAyOTcsMjAyOTksMjAzMDAsMjAzMDYsMjAzMDgsMjAzMTAsMjAzMTIsMjAzMTksMjAzMjMsMjAzMzAsMjAzMzIsMjAzMzQsMjAzMzcsMjAzNDMsMjAzNDQsMjAzNDUsMjAzNDYsMjAzNDksMjAzNTAsMjAzNTMsMjAzNTQsMjAzNTYsMjAzNTcsMjAzNjEsMjAzNjIsMjAzNjQsMjAzNjYsMjAzNjgsMjAzNzAsMjAzNzEsMjAzNzIsMjAzNzUsMjAzNzcsMjAzNzgsMjAzODIsMjAzODMsMjA0MDIsMjA0MDcsMjA0MDksMjA0MTEsMjA0MTIsMjA0MTMsMjA0MTQsMjA0MTYsMjA0MTcsMjA0MjEsMjA0MjIsMjA0MjQsMjA0MjUsMjA0MjcsMjA0MjgsMjA0MjksMjA0MzEsMjA0MzQsMjA0NDQsMjA0NDgsMjA0NTAsMjA0NjQsMjA0NjYsMjA0NzYsMjA0NzcsMjA0NzksMjA0ODAsMjA0ODEsMjA0ODQsMjA0ODcsMjA0OTAsMjA0OTIsMjA0OTQsMjA0OTYsMjA0OTksMjA1MDMsMjA1MDQsMjA1MDcsMjA1MDgsMjA1MDksMjA1MTAsMjA1MTQsMjA1MTksMjA1MjYsMjA1MjgsMjA1MzAsMjA1MzEsMjA1MzMsMjA1NDQsMjA1NDUsMjA1NDYsMjA1NDksMjA1NTAsMjA1NTQsMjA1NTYsMjA1NTgsMjA1NjEsMjA1NjIsMjA1NjMsMjA1NjcsMjA1NjksMjA1NzUsMjA1NzYsMjA1NzgsMjA1NzksMjA1ODIsMjA1ODMsMjA1ODYsMjA1ODksMjA1OTIsMjA1OTMsMjA1MzksMjA2MDksMjA2MTEsMjA2MTIsMjA2MTQsMjA2MTgsMjA2MjIsMjA2MjMsMjA2MjQsMjA2MjYsMjA2MjcsMjA2MjgsMjA2MzAsMjA2MzUsMjA2MzYsMjA2MzgsMjA2MzksMjA2NDAsMjA2NDEsMjA2NDIsMjA2NTAsMjA2NTUsMjA2NTYsMjA2NjUsMjA2NjYsMjA2NjksMjA2NzIsMjA2NzUsMjA2NzYsMjA2NzksMjA2ODQsMjA2ODYsMjA2ODgsMjA2OTEsMjA2OTIsMjA2OTYsMjA3MDAsMjA3MDEsMjA3MDMsMjA3MDYsMjA3MDgsMjA3MTAsMjA3MTIsMjA3MTMsMjA3MTksMjA3MjEsMjA3MjYsMjA3MzAsMjA3MzQsMjA3MzksMjA3NDIsMjA3NDMsMjA3NDQsMjA3NDcsMjA3NDgsMjA3NDksMjA3NTAsMjA3MjIsMjA3NTIsMjA3NTksMjA3NjEsMjA3NjMsMjA3NjQsMjA3NjUsMjA3NjYsMjA3NzEsMjA3NzUsMjA3NzYsMjA3ODAsMjA3ODEsMjA3ODMsMjA3ODUsMjA3ODcsMjA3ODgsMjA3ODksMjA3OTIsMjA3OTMsMjA4MDIsMjA4MTAsMjA4MTUsMjA4MTksMjA4MjEsMjA4MjMsMjA4MjQsMjA4MzEsMjA4MzYsMjA4MzgsMjA4NjIsMjA4NjcsMjA4NjgsMjA4NzUsMjA4NzgsMjA4ODgsMjA4OTMsMjA4OTcsMjA4OTksMjA5MDksMjA5MjAsMjA5MjIsMjA5MjQsMjA5MjYsMjA5MjcsMjA5MzAsMjA5MzYsMjA5NDMsMjA5NDUsMjA5NDYsMjA5NDcsMjA5NDksMjA5NTIsMjA5NTgsMjA5NjIsMjA5NjUsMjA5NzQsMjA5NzgsMjA5NzksMjA5ODAsMjA5ODMsMjA5OTMsMjA5OTQsMjA5OTcsMjEwMTAsMjEwMTEsMjEwMTMsMjEwMTQsMjEwMTYsMjEwMjYsMjEwMzIsMjEwNDEsMjEwNDIsMjEwNDUsMjEwNTIsMjEwNjEsMjEwNjUsMjEwNzcsMjEwNzksMjEwODAsMjEwODIsMjEwODQsMjEwODcsMjEwODgsMjEwODksMjEwOTQsMjExMDIsMjExMTEsMjExMTIsMjExMTMsMjExMjAsMjExMjIsMjExMjUsMjExMzAsMjExMzIsMjExMzksMjExNDEsMjExNDIsMjExNDMsMjExNDQsMjExNDYsMjExNDgsMjExNTYsMjExNTcsMjExNTgsMjExNTksMjExNjcsMjExNjgsMjExNzQsMjExNzUsMjExNzYsMjExNzgsMjExNzksMjExODEsMjExODQsMjExODgsMjExOTAsMjExOTIsMjExOTYsMjExOTksMjEyMDEsMjEyMDQsMjEyMDYsMjEyMTEsMjEyMTIsMjEyMTcsMjEyMjEsMjEyMjQsMjEyMjUsMjEyMjYsMjEyMjgsMjEyMzIsMjEyMzMsMjEyMzYsMjEyMzgsMjEyMzksMjEyNDgsMjEyNTEsMjEyNTgsMjEyNTksMjEyNjAsMjEyNjUsMjEyNjcsMjEyNzIsMjEyNzUsMjEyNzYsMjEyNzgsMjEyNzksMjEyODUsMjEyODcsMjEyODgsMjEyODksMjEyOTEsMjEyOTIsMjEyOTMsMjEyOTYsMjEyOTgsMjEzMDEsMjEzMDgsMjEzMDksMjEzMTAsMjEzMTQsMjEzMjQsMjEzMjMsMjEzMzcsMjEzMzksMjEzNDUsMjEzNDcsMjEzNDksMjEzNTYsMjEzNTcsMjEzNjIsMjEzNjksMjEzNzQsMjEzNzksMjEzODMsMjEzODQsMjEzOTAsMjEzOTUsMjEzOTYsMjE0MDEsMjE0MDUsMjE0MDksMjE0MTIsMjE0MTgsMjE0MTksMjE0MjMsMjE0MjYsMjE0MjgsMjE0MjksMjE0MzEsMjE0MzIsMjE0MzQsMjE0MzcsMjE0NDAsMjE0NDUsMjE0NTUsMjE0NTgsMjE0NTksMjE0NjEsMjE0NjYsMjE0NjksMjE0NzAsMjE0NzIsMjE0NzgsMjE0NzksMjE0OTMsMjE1MDYsMjE1MjMsMjE1MzAsMjE1MzcsMjE1NDMsMjE1NDQsMjE1NDYsMjE1NTEsMjE1NTMsMjE1NTYsMjE1NTcsMjE1NzEsMjE1NzIsMjE1NzUsMjE1ODEsMjE1ODMsMjE1OTgsMjE2MDIsMjE2MDQsMjE2MDYsMjE2MDcsMjE2MDksMjE2MTEsMjE2MTMsMjE2MTQsMjE2MjAsMjE2MzEsMjE2MzMsMjE2MzUsMjE2MzcsMjE2NDAsMjE2NDEsMjE2NDUsMjE2NDksMjE2NTMsMjE2NTQsMjE2NjAsMjE2NjMsMjE2NjUsMjE2NzAsMjE2NzEsMjE2NzMsMjE2NzQsMjE2NzcsMjE2NzgsMjE2ODEsMjE2ODcsMjE2ODksMjE2OTAsMjE2OTEsMjE2OTUsMjE3MDIsMjE3MDYsMjE3MDksMjE3MTAsMjE3MjgsMjE3MzgsMjE3NDAsMjE3NDMsMjE3NTAsMjE3NTYsMjE3NTgsMjE3NTksMjE3NjAsMjE3NjEsMjE3NjUsMjE3NjgsMjE3NjksMjE3NzIsMjE3NzMsMjE3NzQsMjE3ODEsMjE4MDIsMjE4MDMsMjE4MTAsMjE4MTMsMjE4MTQsMjE4MTksMjE4MjAsMjE4MjEsMjE4MjUsMjE4MzEsMjE4MzMsMjE4MzQsMjE4MzcsMjE4NDAsMjE4NDEsMjE4NDgsMjE4NTAsMjE4NTEsMjE4NTQsMjE4NTYsMjE4NTcsMjE4NjAsMjE4NjIsMjE4ODcsMjE4ODksMjE4OTAsMjE4OTQsMjE4OTYsMjE5MDIsMjE5MDMsMjE5MDUsMjE5MDYsMjE5MDcsMjE5MDgsMjE5MTEsMjE5MjMsMjE5MjQsMjE5MzMsMjE5MzgsMjE5NTEsMjE5NTMsMjE5NTUsMjE5NTgsMjE5NjEsMjE5NjMsMjE5NjQsMjE5NjYsMjE5NjksMjE5NzAsMjE5NzEsMjE5NzUsMjE5NzYsMjE5NzksMjE5ODIsMjE5ODYsMjE5OTMsMjIwMDYsMjIwMTUsMjIwMjEsMjIwMjQsMjIwMjYsMjIwMjksMjIwMzAsMjIwMzEsMjIwMzIsMjIwMzMsMjIwMzQsMjIwNDEsMjIwNjAsMjIwNjQsMjIwNjcsMjIwNjksMjIwNzEsMjIwNzMsMjIwNzUsMjIwNzYsMjIwNzcsMjIwNzksMjIwODAsMjIwODEsMjIwODMsMjIwODQsMjIwODYsMjIwODksMjIwOTEsMjIwOTMsMjIwOTUsMjIxMDAsMjIxMTAsMjIxMTIsMjIxMTMsMjIxMTQsMjIxMTUsMjIxMTgsMjIxMjEsMjIxMjUsMjIxMjcsMjIxMjksMjIxMzAsMjIxMzMsMjIxNDgsMjIxNDksMjIxNTIsMjIxNTUsMjIxNTYsMjIxNjUsMjIxNjksMjIxNzAsMjIxNzMsMjIxNzQsMjIxNzUsMjIxODIsMjIxODMsMjIxODQsMjIxODUsMjIxODcsMjIxODgsMjIxODksMjIxOTMsMjIxOTUsMjIxOTksMjIyMDYsMjIyMTMsMjIyMTcsMjIyMTgsMjIyMTksMjIyMjMsMjIyMjQsMjIyMjAsMjIyMjEsMjIyMzMsMjIyMzYsMjIyMzcsMjIyMzksMjIyNDEsMjIyNDQsMjIyNDUsMjIyNDYsMjIyNDcsMjIyNDgsMjIyNTcsMjIyNTEsMjIyNTMsMjIyNjIsMjIyNjMsMjIyNzMsMjIyNzQsMjIyNzksMjIyODIsMjIyODQsMjIyODksMjIyOTMsMjIyOTgsMjIyOTksMjIzMDEsMjIzMDQsMjIzMDYsMjIzMDcsMjIzMDgsMjIzMDksMjIzMTMsMjIzMTQsMjIzMTYsMjIzMTgsMjIzMTksMjIzMjMsMjIzMjQsMjIzMzMsMjIzMzQsMjIzMzUsMjIzNDEsMjIzNDIsMjIzNDgsMjIzNDksMjIzNTQsMjIzNzAsMjIzNzMsMjIzNzUsMjIzNzYsMjIzNzksMjIzODEsMjIzODIsMjIzODMsMjIzODQsMjIzODUsMjIzODcsMjIzODgsMjIzODksMjIzOTEsMjIzOTMsMjIzOTQsMjIzOTUsMjIzOTYsMjIzOTgsMjI0MDEsMjI0MDMsMjI0MTIsMjI0MjAsMjI0MjMsMjI0MjUsMjI0MjYsMjI0MjgsMjI0MjksMjI0MzAsMjI0MzEsMjI0MzMsMjI0MjEsMjI0MzksMjI0NDAsMjI0NDEsMjI0NDQsMjI0NTYsMjI0NjEsMjI0NzEsMjI0NzIsMjI0NzYsMjI0NzksMjI0ODUsMjI0OTMsMjI0OTQsMjI1MDAsMjI1MDIsMjI1MDMsMjI1MDUsMjI1MDksMjI1MTIsMjI1MTcsMjI1MTgsMjI1MjAsMjI1MjUsMjI1MjYsMjI1MjcsMjI1MzEsMjI1MzIsMjI1MzYsMjI1MzcsMjI0OTcsMjI1NDAsMjI1NDEsMjI1NTUsMjI1NTgsMjI1NTksMjI1NjAsMjI1NjYsMjI1NjcsMjI1NzMsMjI1NzgsMjI1ODUsMjI1OTEsMjI2MDEsMjI2MDQsMjI2MDUsMjI2MDcsMjI2MDgsMjI2MTMsMjI2MjMsMjI2MjUsMjI2MjgsMjI2MzEsMjI2MzIsMjI2NDgsMjI2NTIsMjI2NTUsMjI2NTYsMjI2NTcsMjI2NjMsMjI2NjQsMjI2NjUsMjI2NjYsMjI2NjgsMjI2NjksMjI2NzEsMjI2NzIsMjI2NzYsMjI2NzgsMjI2ODUsMjI2ODgsMjI2ODksMjI2OTAsMjI2OTQsMjI2OTcsMjI3MDUsMjI3MDYsMjI3MjQsMjI3MTYsMjI3MjIsMjI3MjgsMjI3MzMsMjI3MzQsMjI3MzYsMjI3MzgsMjI3NDAsMjI3NDIsMjI3NDYsMjI3NDksMjI3NTMsMjI3NTQsMjI3NjEsMjI3NzEsMjI3ODksMjI3OTAsMjI3OTUsMjI3OTYsMjI4MDIsMjI4MDMsMjI4MDQsMzQzNjksMjI4MTMsMjI4MTcsMjI4MTksMjI4MjAsMjI4MjQsMjI4MzEsMjI4MzIsMjI4MzUsMjI4MzcsMjI4MzgsMjI4NDcsMjI4NTEsMjI4NTQsMjI4NjYsMjI4NjcsMjI4NzMsMjI4NzUsMjI4NzcsMjI4NzgsMjI4NzksMjI4ODEsMjI4ODMsMjI4OTEsMjI4OTMsMjI4OTUsMjI4OTgsMjI5MDEsMjI5MDIsMjI5MDUsMjI5MDcsMjI5MDgsMjI5MjMsMjI5MjQsMjI5MjYsMjI5MzAsMjI5MzMsMjI5MzUsMjI5NDMsMjI5NDgsMjI5NTEsMjI5NTcsMjI5NTgsMjI5NTksMjI5NjAsMjI5NjMsMjI5NjcsMjI5NzAsMjI5NzIsMjI5NzcsMjI5NzksMjI5ODAsMjI5ODQsMjI5ODYsMjI5ODksMjI5OTQsMjMwMDUsMjMwMDYsMjMwMDcsMjMwMTEsMjMwMTIsMjMwMTUsMjMwMjIsMjMwMjMsMjMwMjUsMjMwMjYsMjMwMjgsMjMwMzEsMjMwNDAsMjMwNDQsMjMwNTIsMjMwNTMsMjMwNTQsMjMwNTgsMjMwNTksMjMwNzAsMjMwNzUsMjMwNzYsMjMwNzksMjMwODAsMjMwODIsMjMwODUsMjMwODgsMjMxMDgsMjMxMDksMjMxMTEsMjMxMTIsMjMxMTYsMjMxMjAsMjMxMjUsMjMxMzQsMjMxMzksMjMxNDEsMjMxNDMsMjMxNDksMjMxNTksMjMxNjIsMjMxNjMsMjMxNjYsMjMxNzksMjMxODQsMjMxODcsMjMxOTAsMjMxOTMsMjMxOTYsMjMxOTgsMjMxOTksMjMyMDAsMjMyMDIsMjMyMDcsMjMyMTIsMjMyMTcsMjMyMTgsMjMyMTksMjMyMjEsMjMyMjQsMjMyMjYsMjMyMjcsMjMyMzEsMjMyMzYsMjMyMzgsMjMyNDAsMjMyNDcsMjMyNTgsMjMyNjAsMjMyNjQsMjMyNjksMjMyNzQsMjMyNzgsMjMyODUsMjMyODYsMjMyOTMsMjMyOTYsMjMyOTcsMjMzMDQsMjMzMTksMjMzNDgsMjMzMjEsMjMzMjMsMjMzMjUsMjMzMjksMjMzMzMsMjMzNDEsMjMzNTIsMjMzNjEsMjMzNzEsMjMzNzIsMjMzNzgsMjMzODIsMjMzOTAsMjM0MDAsMjM0MDYsMjM0MDcsMjM0MjAsMjM0MjEsMjM0MjIsMjM0MjMsMjM0MjUsMjM0MjgsMjM0MzAsMjM0MzQsMjM0MzgsMjM0NDAsMjM0NDEsMjM0NDMsMjM0NDQsMjM0NDYsMjM0NjQsMjM0NjUsMjM0NjgsMjM0NjksMjM0NzEsMjM0NzMsMjM0NzQsMjM0NzksMjM0ODIsMjM0ODQsMjM0ODgsMjM0ODksMjM1MDEsMjM1MDMsMjM1MTAsMjM1MTEsMjM1MTIsMjM1MTMsMjM1MTQsMjM1MjAsMjM1MzUsMjM1MzcsMjM1NDAsMjM1NDksMjM1NjQsMjM1NzUsMjM1ODIsMjM1ODMsMjM1ODcsMjM1OTAsMjM1OTMsMjM1OTUsMjM1OTYsMjM1OTgsMjM2MDAsMjM2MDIsMjM2MDUsMjM2MDYsMjM2NDEsMjM2NDIsMjM2NDQsMjM2NTAsMjM2NTEsMjM2NTUsMjM2NTYsMjM2NTcsMjM2NjEsMjM2NjQsMjM2NjgsMjM2NjksMjM2NzQsMjM2NzUsMjM2NzYsMjM2NzcsMjM2ODcsMjM2ODgsMjM2OTAsMjM2OTUsMjM2OTgsMjM3MDksMjM3MTEsMjM3MTIsMjM3MTQsMjM3MTUsMjM3MTgsMjM3MjIsMjM3MzAsMjM3MzIsMjM3MzMsMjM3MzgsMjM3NTMsMjM3NTUsMjM3NjIsMjM3NzMsMjM3NjcsMjM3OTAsMjM3OTMsMjM3OTQsMjM3OTYsMjM4MDksMjM4MTQsMjM4MjEsMjM4MjYsMjM4NTEsMjM4NDMsMjM4NDQsMjM4NDYsMjM4NDcsMjM4NTcsMjM4NjAsMjM4NjUsMjM4NjksMjM4NzEsMjM4NzQsMjM4NzUsMjM4NzgsMjM4ODAsMjM4OTMsMjM4ODksMjM4OTcsMjM4ODIsMjM5MDMsMjM5MDQsMjM5MDUsMjM5MDYsMjM5MDgsMjM5MTQsMjM5MTcsMjM5MjAsMjM5MjksMjM5MzAsMjM5MzQsMjM5MzUsMjM5MzcsMjM5MzksMjM5NDQsMjM5NDYsMjM5NTQsMjM5NTUsMjM5NTYsMjM5NTcsMjM5NjEsMjM5NjMsMjM5NjcsMjM5NjgsMjM5NzUsMjM5NzksMjM5ODQsMjM5ODgsMjM5OTIsMjM5OTMsMjQwMDMsMjQwMDcsMjQwMTEsMjQwMTYsMjQwMTQsMjQwMjQsMjQwMjUsMjQwMzIsMjQwMzYsMjQwNDEsMjQwNTYsMjQwNTcsMjQwNjQsMjQwNzEsMjQwNzcsMjQwODIsMjQwODQsMjQwODUsMjQwODgsMjQwOTUsMjQwOTYsMjQxMTAsMjQxMDQsMjQxMTQsMjQxMTcsMjQxMjYsMjQxMzksMjQxNDQsMjQxMzcsMjQxNDUsMjQxNTAsMjQxNTIsMjQxNTUsMjQxNTYsMjQxNTgsMjQxNjgsMjQxNzAsMjQxNzEsMjQxNzIsMjQxNzMsMjQxNzQsMjQxNzYsMjQxOTIsMjQyMDMsMjQyMDYsMjQyMjYsMjQyMjgsMjQyMjksMjQyMzIsMjQyMzQsMjQyMzYsMjQyNDEsMjQyNDMsMjQyNTMsMjQyNTQsMjQyNTUsMjQyNjIsMjQyNjgsMjQyNjcsMjQyNzAsMjQyNzMsMjQyNzQsMjQyNzYsMjQyNzcsMjQyODQsMjQyODYsMjQyOTMsMjQyOTksMjQzMjIsMjQzMjYsMjQzMjcsMjQzMjgsMjQzMzQsMjQzNDUsMjQzNDgsMjQzNDksMjQzNTMsMjQzNTQsMjQzNTUsMjQzNTYsMjQzNjAsMjQzNjMsMjQzNjQsMjQzNjYsMjQzNjgsMjQzNzIsMjQzNzQsMjQzNzksMjQzODEsMjQzODMsMjQzODQsMjQzODgsMjQzODksMjQzOTEsMjQzOTcsMjQ0MDAsMjQ0MDQsMjQ0MDgsMjQ0MTEsMjQ0MTYsMjQ0MTksMjQ0MjAsMjQ0MjMsMjQ0MzEsMjQ0MzQsMjQ0MzYsMjQ0MzcsMjQ0NDAsMjQ0NDIsMjQ0NDUsMjQ0NDYsMjQ0NTcsMjQ0NjEsMjQ0NjMsMjQ0NzAsMjQ0NzYsMjQ0NzcsMjQ0ODIsMjQ0ODcsMjQ0OTEsMjQ0ODQsMjQ0OTIsMjQ0OTUsMjQ0OTYsMjQ0OTcsMjQ1MDQsMjQ1MTYsMjQ1MTksMjQ1MjAsMjQ1MjEsMjQ1MjMsMjQ1MjgsMjQ1MjksMjQ1MzAsMjQ1MzEsMjQ1MzIsMjQ1NDIsMjQ1NDUsMjQ1NDYsMjQ1NTIsMjQ1NTMsMjQ1NTQsMjQ1NTYsMjQ1NTcsMjQ1NTgsMjQ1NTksMjQ1NjIsMjQ1NjMsMjQ1NjYsMjQ1NzAsMjQ1NzIsMjQ1ODMsMjQ1ODYsMjQ1ODksMjQ1OTUsMjQ1OTYsMjQ1OTksMjQ2MDAsMjQ2MDIsMjQ2MDcsMjQ2MTIsMjQ2MjEsMjQ2MjcsMjQ2MjksMjQ2NDAsMjQ2NDcsMjQ2NDgsMjQ2NDksMjQ2NTIsMjQ2NTcsMjQ2NjAsMjQ2NjIsMjQ2NjMsMjQ2NjksMjQ2NzMsMjQ2NzksMjQ2ODksMjQ3MDIsMjQ3MDMsMjQ3MDYsMjQ3MTAsMjQ3MTIsMjQ3MTQsMjQ3MTgsMjQ3MjEsMjQ3MjMsMjQ3MjUsMjQ3MjgsMjQ3MzMsMjQ3MzQsMjQ3MzgsMjQ3NDAsMjQ3NDEsMjQ3NDQsMjQ3NTIsMjQ3NTMsMjQ3NTksMjQ3NjMsMjQ3NjYsMjQ3NzAsMjQ3NzIsMjQ3NzYsMjQ3NzcsMjQ3NzgsMjQ3NzksMjQ3ODIsMjQ3ODMsMjQ3ODgsMjQ3ODksMjQ3OTMsMjQ3OTUsMjQ3OTcsMjQ3OTgsMjQ4MDIsMjQ4MDUsMjQ4MTgsMjQ4MjEsMjQ4MjQsMjQ4MjgsMjQ4MjksMjQ4MzQsMjQ4MzksMjQ4NDIsMjQ4NDQsMjQ4NDgsMjQ4NDksMjQ4NTAsMjQ4NTEsMjQ4NTIsMjQ4NTQsMjQ4NTUsMjQ4NTcsMjQ4NjAsMjQ4NjIsMjQ4NjYsMjQ4NzQsMjQ4NzUsMjQ4ODAsMjQ4ODEsMjQ4ODUsMjQ4ODYsMjQ4ODcsMjQ4ODksMjQ4OTcsMjQ5MDEsMjQ5MDIsMjQ5MDUsMjQ5MjYsMjQ5MjgsMjQ5NDAsMjQ5NDYsMjQ5NTIsMjQ5NTUsMjQ5NTYsMjQ5NTksMjQ5NjAsMjQ5NjEsMjQ5NjMsMjQ5NjQsMjQ5NzEsMjQ5NzMsMjQ5NzgsMjQ5NzksMjQ5ODMsMjQ5ODQsMjQ5ODgsMjQ5ODksMjQ5OTEsMjQ5OTIsMjQ5OTcsMjUwMDAsMjUwMDIsMjUwMDUsMjUwMTYsMjUwMTcsMjUwMjAsMjUwMjQsMjUwMjUsMjUwMjYsMjUwMzgsMjUwMzksMjUwNDUsMjUwNTIsMjUwNTMsMjUwNTQsMjUwNTUsMjUwNTcsMjUwNTgsMjUwNjMsMjUwNjUsMjUwNjEsMjUwNjgsMjUwNjksMjUwNzEsMjUwODksMjUwOTEsMjUwOTIsMjUwOTUsMjUxMDcsMjUxMDksMjUxMTYsMjUxMjAsMjUxMjIsMjUxMjMsMjUxMjcsMjUxMjksMjUxMzEsMjUxNDUsMjUxNDksMjUxNTQsMjUxNTUsMjUxNTYsMjUxNTgsMjUxNjQsMjUxNjgsMjUxNjksMjUxNzAsMjUxNzIsMjUxNzQsMjUxNzgsMjUxODAsMjUxODgsMjUxOTcsMjUxOTksMjUyMDMsMjUyMTAsMjUyMTMsMjUyMjksMjUyMzAsMjUyMzEsMjUyMzIsMjUyNTQsMjUyNTYsMjUyNjcsMjUyNzAsMjUyNzEsMjUyNzQsMjUyNzgsMjUyNzksMjUyODQsMjUyOTQsMjUzMDEsMjUzMDIsMjUzMDYsMjUzMjIsMjUzMzAsMjUzMzIsMjUzNDAsMjUzNDEsMjUzNDcsMjUzNDgsMjUzNTQsMjUzNTUsMjUzNTcsMjUzNjAsMjUzNjMsMjUzNjYsMjUzNjgsMjUzODUsMjUzODYsMjUzODksMjUzOTcsMjUzOTgsMjU0MDEsMjU0MDQsMjU0MDksMjU0MTAsMjU0MTEsMjU0MTIsMjU0MTQsMjU0MTgsMjU0MTksMjU0MjIsMjU0MjYsMjU0MjcsMjU0MjgsMjU0MzIsMjU0MzUsMjU0NDUsMjU0NDYsMjU0NTIsMjU0NTMsMjU0NTcsMjU0NjAsMjU0NjEsMjU0NjQsMjU0NjgsMjU0NjksMjU0NzEsMjU0NzQsMjU0NzYsMjU0NzksMjU0ODIsMjU0ODgsMjU0OTIsMjU0OTMsMjU0OTcsMjU0OTgsMjU1MDIsMjU1MDgsMjU1MTAsMjU1MTcsMjU1MTgsMjU1MTksMjU1MzMsMjU1MzcsMjU1NDEsMjU1NDQsMjU1NTAsMjU1NTMsMjU1NTUsMjU1NTYsMjU1NTcsMjU1NjQsMjU1NjgsMjU1NzMsMjU1NzgsMjU1ODAsMjU1ODYsMjU1ODcsMjU1ODksMjU1OTIsMjU1OTMsMjU2MDksMjU2MTAsMjU2MTYsMjU2MTgsMjU2MjAsMjU2MjQsMjU2MzAsMjU2MzIsMjU2MzQsMjU2MzYsMjU2MzcsMjU2NDEsMjU2NDIsMjU2NDcsMjU2NDgsMjU2NTMsMjU2NjEsMjU2NjMsMjU2NzUsMjU2NzksMjU2ODEsMjU2ODIsMjU2ODMsMjU2ODQsMjU2OTAsMjU2OTEsMjU2OTIsMjU2OTMsMjU2OTUsMjU2OTYsMjU2OTcsMjU2OTksMjU3MDksMjU3MTUsMjU3MTYsMjU3MjMsMjU3MjUsMjU3MzMsMjU3MzUsMjU3NDMsMjU3NDQsMjU3NDUsMjU3NTIsMjU3NTMsMjU3NTUsMjU3NTcsMjU3NTksMjU3NjEsMjU3NjMsMjU3NjYsMjU3NjgsMjU3NzIsMjU3NzksMjU3ODksMjU3OTAsMjU3OTEsMjU3OTYsMjU4MDEsMjU4MDIsMjU4MDMsMjU4MDQsMjU4MDYsMjU4MDgsMjU4MDksMjU4MTMsMjU4MTUsMjU4MjgsMjU4MjksMjU4MzMsMjU4MzQsMjU4MzcsMjU4NDAsMjU4NDUsMjU4NDcsMjU4NTEsMjU4NTUsMjU4NTcsMjU4NjAsMjU4NjQsMjU4NjUsMjU4NjYsMjU4NzEsMjU4NzUsMjU4NzYsMjU4NzgsMjU4ODEsMjU4ODMsMjU4ODYsMjU4ODcsMjU4OTAsMjU4OTQsMjU4OTcsMjU5MDIsMjU5MDUsMjU5MTQsMjU5MTYsMjU5MTcsMjU5MjMsMjU5MjcsMjU5MjksMjU5MzYsMjU5MzgsMjU5NDAsMjU5NTEsMjU5NTIsMjU5NTksMjU5NjMsMjU5NzgsMjU5ODEsMjU5ODUsMjU5ODksMjU5OTQsMjYwMDIsMjYwMDUsMjYwMDgsMjYwMTMsMjYwMTYsMjYwMTksMjYwMjIsMjYwMzAsMjYwMzQsMjYwMzUsMjYwMzYsMjYwNDcsMjYwNTAsMjYwNTYsMjYwNTcsMjYwNjIsMjYwNjQsMjYwNjgsMjYwNzAsMjYwNzIsMjYwNzksMjYwOTYsMjYwOTgsMjYxMDAsMjYxMDEsMjYxMDUsMjYxMTAsMjYxMTEsMjYxMTIsMjYxMTYsMjYxMjAsMjYxMjEsMjYxMjUsMjYxMjksMjYxMzAsMjYxMzMsMjYxMzQsMjYxNDEsMjYxNDIsMjYxNDUsMjYxNDYsMjYxNDcsMjYxNDgsMjYxNTAsMjYxNTMsMjYxNTQsMjYxNTUsMjYxNTYsMjYxNTgsMjYxNjAsMjYxNjEsMjYxNjMsMjYxNjksMjYxNjcsMjYxNzYsMjYxODEsMjYxODIsMjYxODYsMjYxODgsMjYxOTMsMjYxOTAsMjYxOTksMjYyMDAsMjYyMDEsMjYyMDMsMjYyMDQsMjYyMDgsMjYyMDksMjYzNjMsMjYyMTgsMjYyMTksMjYyMjAsMjYyMzgsMjYyMjcsMjYyMjksMjYyMzksMjYyMzEsMjYyMzIsMjYyMzMsMjYyMzUsMjYyNDAsMjYyMzYsMjYyNTEsMjYyNTIsMjYyNTMsMjYyNTYsMjYyNTgsMjYyNjUsMjYyNjYsMjYyNjcsMjYyNjgsMjYyNzEsMjYyNzIsMjYyNzYsMjYyODUsMjYyODksMjYyOTAsMjYyOTMsMjYyOTksMjYzMDMsMjYzMDQsMjYzMDYsMjYzMDcsMjYzMTIsMjYzMTYsMjYzMTgsMjYzMTksMjYzMjQsMjYzMzEsMjYzMzUsMjYzNDQsMjYzNDcsMjYzNDgsMjYzNTAsMjYzNjIsMjYzNzMsMjYzNzUsMjYzODIsMjYzODcsMjYzOTMsMjYzOTYsMjY0MDAsMjY0MDIsMjY0MTksMjY0MzAsMjY0MzcsMjY0MzksMjY0NDAsMjY0NDQsMjY0NTIsMjY0NTMsMjY0NjEsMjY0NzAsMjY0NzYsMjY0NzgsMjY0ODQsMjY0ODYsMjY0OTEsMjY0OTcsMjY1MDAsMjY1MTAsMjY1MTEsMjY1MTMsMjY1MTUsMjY1MTgsMjY1MjAsMjY1MjEsMjY1MjMsMjY1NDQsMjY1NDUsMjY1NDYsMjY1NDksMjY1NTUsMjY1NTYsMjY1NTcsMjY2MTcsMjY1NjAsMjY1NjIsMjY1NjMsMjY1NjUsMjY1NjgsMjY1NjksMjY1NzgsMjY1ODMsMjY1ODUsMjY1ODgsMjY1OTMsMjY1OTgsMjY2MDgsMjY2MTAsMjY2MTQsMjY2MTUsMjY3MDYsMjY2NDQsMjY2NDksMjY2NTMsMjY2NTUsMjY2NjQsMjY2NjMsMjY2NjgsMjY2NjksMjY2NzEsMjY2NzIsMjY2NzMsMjY2NzUsMjY2ODMsMjY2ODcsMjY2OTIsMjY2OTMsMjY2OTgsMjY3MDAsMjY3MDksMjY3MTEsMjY3MTIsMjY3MTUsMjY3MzEsMjY3MzQsMjY3MzUsMjY3MzYsMjY3MzcsMjY3MzgsMjY3NDEsMjY3NDUsMjY3NDYsMjY3NDcsMjY3NDgsMjY3NTQsMjY3NTYsMjY3NTgsMjY3NjAsMjY3NzQsMjY3NzYsMjY3NzgsMjY3ODAsMjY3ODUsMjY3ODcsMjY3ODksMjY3OTMsMjY3OTQsMjY3OTgsMjY4MDIsMjY4MTEsMjY4MjEsMjY4MjQsMjY4MjgsMjY4MzEsMjY4MzIsMjY4MzMsMjY4MzUsMjY4MzgsMjY4NDEsMjY4NDQsMjY4NDUsMjY4NTMsMjY4NTYsMjY4NTgsMjY4NTksMjY4NjAsMjY4NjEsMjY4NjQsMjY4NjUsMjY4NjksMjY4NzAsMjY4NzUsMjY4NzYsMjY4NzcsMjY4ODYsMjY4ODksMjY4OTAsMjY4OTYsMjY4OTcsMjY4OTksMjY5MDIsMjY5MDMsMjY5MjksMjY5MzEsMjY5MzMsMjY5MzYsMjY5MzksMjY5NDYsMjY5NDksMjY5NTMsMjY5NTgsMjY5NjcsMjY5NzEsMjY5NzksMjY5ODAsMjY5ODEsMjY5ODIsMjY5ODQsMjY5ODUsMjY5ODgsMjY5OTIsMjY5OTMsMjY5OTQsMjcwMDIsMjcwMDMsMjcwMDcsMjcwMDgsMjcwMjEsMjcwMjYsMjcwMzAsMjcwMzIsMjcwNDEsMjcwNDUsMjcwNDYsMjcwNDgsMjcwNTEsMjcwNTMsMjcwNTUsMjcwNjMsMjcwNjQsMjcwNjYsMjcwNjgsMjcwNzcsMjcwODAsMjcwODksMjcwOTQsMjcwOTUsMjcxMDYsMjcxMDksMjcxMTgsMjcxMTksMjcxMjEsMjcxMjMsMjcxMjUsMjcxMzQsMjcxMzYsMjcxMzcsMjcxMzksMjcxNTEsMjcxNTMsMjcxNTcsMjcxNjIsMjcxNjUsMjcxNjgsMjcxNzIsMjcxNzYsMjcxODQsMjcxODYsMjcxODgsMjcxOTEsMjcxOTUsMjcxOTgsMjcxOTksMjcyMDUsMjcyMDYsMjcyMDksMjcyMTAsMjcyMTQsMjcyMTYsMjcyMTcsMjcyMTgsMjcyMjEsMjcyMjIsMjcyMjcsMjcyMzYsMjcyMzksMjcyNDIsMjcyNDksMjcyNTEsMjcyNjIsMjcyNjUsMjcyNjcsMjcyNzAsMjcyNzEsMjcyNzMsMjcyNzUsMjcyODEsMjcyOTEsMjcyOTMsMjcyOTQsMjcyOTUsMjczMDEsMjczMDcsMjczMTEsMjczMTIsMjczMTMsMjczMTYsMjczMjUsMjczMjYsMjczMjcsMjczMzQsMjczMzcsMjczMzYsMjczNDAsMjczNDQsMjczNDgsMjczNDksMjczNTAsMjczNTYsMjczNTcsMjczNjQsMjczNjcsMjczNzIsMjczNzYsMjczNzcsMjczNzgsMjczODgsMjczODksMjczOTQsMjczOTUsMjczOTgsMjczOTksMjc0MDEsMjc0MDcsMjc0MDgsMjc0MDksMjc0MTUsMjc0MTksMjc0MjIsMjc0MjgsMjc0MzIsMjc0MzUsMjc0MzYsMjc0MzksMjc0NDUsMjc0NDYsMjc0NTEsMjc0NTUsMjc0NjIsMjc0NjYsMjc0NjksMjc0NzQsMjc0NzgsMjc0ODAsMjc0ODUsMjc0ODgsMjc0OTUsMjc0OTksMjc1MDIsMjc1MDQsMjc1MDksMjc1MTcsMjc1MTgsMjc1MjIsMjc1MjUsMjc1NDMsMjc1NDcsMjc1NTEsMjc1NTIsMjc1NTQsMjc1NTUsMjc1NjAsMjc1NjEsMjc1NjQsMjc1NjUsMjc1NjYsMjc1NjgsMjc1NzYsMjc1NzcsMjc1ODEsMjc1ODIsMjc1ODcsMjc1ODgsMjc1OTMsMjc1OTYsMjc2MDYsMjc2MTAsMjc2MTcsMjc2MTksMjc2MjIsMjc2MjMsMjc2MzAsMjc2MzMsMjc2MzksMjc2NDEsMjc2NDcsMjc2NTAsMjc2NTIsMjc2NTMsMjc2NTcsMjc2NjEsMjc2NjIsMjc2NjQsMjc2NjYsMjc2NzMsMjc2NzksMjc2ODYsMjc2ODcsMjc2ODgsMjc2OTIsMjc2OTQsMjc2OTksMjc3MDEsMjc3MDIsMjc3MDYsMjc3MDcsMjc3MTEsMjc3MjIsMjc3MjMsMjc3MjUsMjc3MjcsMjc3MzAsMjc3MzIsMjc3MzcsMjc3MzksMjc3NDAsMjc3NTUsMjc3NTcsMjc3NTksMjc3NjQsMjc3NjYsMjc3NjgsMjc3NjksMjc3NzEsMjc3ODEsMjc3ODIsMjc3ODMsMjc3ODUsMjc3OTYsMjc3OTcsMjc3OTksMjc4MDAsMjc4MDQsMjc4MDcsMjc4MjQsMjc4MjYsMjc4MjgsMjc4NDIsMjc4NDYsMjc4NTMsMjc4NTUsMjc4NTYsMjc4NTcsMjc4NTgsMjc4NjAsMjc4NjIsMjc4NjYsMjc4NjgsMjc4NzIsMjc4NzksMjc4ODEsMjc4ODMsMjc4ODQsMjc4ODYsMjc4OTAsMjc4OTIsMjc5MDgsMjc5MTEsMjc5MTQsMjc5MTgsMjc5MTksMjc5MjEsMjc5MjMsMjc5MzAsMjc5NDIsMjc5NDMsMjc5NDQsMjc3NTEsMjc5NTAsMjc5NTEsMjc5NTMsMjc5NjEsMjc5NjQsMjc5NjcsMjc5OTEsMjc5OTgsMjc5OTksMjgwMDEsMjgwMDUsMjgwMDcsMjgwMTUsMjgwMTYsMjgwMjgsMjgwMzQsMjgwMzksMjgwNDksMjgwNTAsMjgwNTIsMjgwNTQsMjgwNTUsMjgwNTYsMjgwNzQsMjgwNzYsMjgwODQsMjgwODcsMjgwODksMjgwOTMsMjgwOTUsMjgxMDAsMjgxMDQsMjgxMDYsMjgxMTAsMjgxMTEsMjgxMTgsMjgxMjMsMjgxMjUsMjgxMjcsMjgxMjgsMjgxMzAsMjgxMzMsMjgxMzcsMjgxNDMsMjgxNDQsMjgxNDgsMjgxNTAsMjgxNTYsMjgxNjAsMjgxNjQsMjgxOTAsMjgxOTQsMjgxOTksMjgyMTAsMjgyMTQsMjgyMTcsMjgyMTksMjgyMjAsMjgyMjgsMjgyMjksMjgyMzIsMjgyMzMsMjgyMzUsMjgyMzksMjgyNDEsMjgyNDIsMjgyNDMsMjgyNDQsMjgyNDcsMjgyNTIsMjgyNTMsMjgyNTQsMjgyNTgsMjgyNTksMjgyNjQsMjgyNzUsMjgyODMsMjgyODUsMjgzMDEsMjgzMDcsMjgzMTMsMjgzMjAsMjgzMjcsMjgzMzMsMjgzMzQsMjgzMzcsMjgzMzksMjgzNDcsMjgzNTEsMjgzNTIsMjgzNTMsMjgzNTUsMjgzNTksMjgzNjAsMjgzNjIsMjgzNjUsMjgzNjYsMjgzNjcsMjgzOTUsMjgzOTcsMjgzOTgsMjg0MDksMjg0MTEsMjg0MTMsMjg0MjAsMjg0MjQsMjg0MjYsMjg0MjgsMjg0MjksMjg0MzgsMjg0NDAsMjg0NDIsMjg0NDMsMjg0NTQsMjg0NTcsMjg0NTgsMjg0NjMsMjg0NjQsMjg0NjcsMjg0NzAsMjg0NzUsMjg0NzYsMjg0NjEsMjg0OTUsMjg0OTcsMjg0OTgsMjg0OTksMjg1MDMsMjg1MDUsMjg1MDYsMjg1MDksMjg1MTAsMjg1MTMsMjg1MTQsMjg1MjAsMjg1MjQsMjg1NDEsMjg1NDIsMjg1NDcsMjg1NTEsMjg1NTIsMjg1NTUsMjg1NTYsMjg1NTcsMjg1NjAsMjg1NjIsMjg1NjMsMjg1NjQsMjg1NjYsMjg1NzAsMjg1NzUsMjg1NzYsMjg1ODEsMjg1ODIsMjg1ODMsMjg1ODQsMjg1OTAsMjg1OTEsMjg1OTIsMjg1OTcsMjg1OTgsMjg2MDQsMjg2MTMsMjg2MTUsMjg2MTYsMjg2MTgsMjg2MzQsMjg2MzgsMjg2NDgsMjg2NDksMjg2NTYsMjg2NjEsMjg2NjUsMjg2NjgsMjg2NjksMjg2NzIsMjg2NzcsMjg2NzgsMjg2NzksMjg2ODUsMjg2OTUsMjg3MDQsMjg3MDcsMjg3MTksMjg3MjQsMjg3MjcsMjg3MjksMjg3MzIsMjg3MzksMjg3NDAsMjg3NDQsMjg3NDUsMjg3NDYsMjg3NDcsMjg3NTYsMjg3NTcsMjg3NjUsMjg3NjYsMjg3NTAsMjg3NzIsMjg3NzMsMjg3ODAsMjg3ODIsMjg3ODksMjg3OTAsMjg3OTgsMjg4MDEsMjg4MDUsMjg4MDYsMjg4MjAsMjg4MjEsMjg4MjIsMjg4MjMsMjg4MjQsMjg4MjcsMjg4MzYsMjg4NDMsMjg4NDgsMjg4NDksMjg4NTIsMjg4NTUsMjg4NzQsMjg4ODEsMjg4ODMsMjg4ODQsMjg4ODUsMjg4ODYsMjg4ODgsMjg4OTIsMjg5MDAsMjg5MjIsMjg5MzEsMjg5MzIsMjg5MzMsMjg5MzQsMjg5MzUsMjg5MzksMjg5NDAsMjg5NDMsMjg5NTgsMjg5NjAsMjg5NzEsMjg5NzMsMjg5NzUsMjg5NzYsMjg5NzcsMjg5ODQsMjg5OTMsMjg5OTcsMjg5OTgsMjg5OTksMjkwMDIsMjkwMDMsMjkwMDgsMjkwMTAsMjkwMTUsMjkwMTgsMjkwMjAsMjkwMjIsMjkwMjQsMjkwMzIsMjkwNDksMjkwNTYsMjkwNjEsMjkwNjMsMjkwNjgsMjkwNzQsMjkwODIsMjkwODMsMjkwODgsMjkwOTAsMjkxMDMsMjkxMDQsMjkxMDYsMjkxMDcsMjkxMTQsMjkxMTksMjkxMjAsMjkxMjEsMjkxMjQsMjkxMzEsMjkxMzIsMjkxMzksMjkxNDIsMjkxNDUsMjkxNDYsMjkxNDgsMjkxNzYsMjkxODIsMjkxODQsMjkxOTEsMjkxOTIsMjkxOTMsMjkyMDMsMjkyMDcsMjkyMTAsMjkyMTMsMjkyMTUsMjkyMjAsMjkyMjcsMjkyMzEsMjkyMzYsMjkyNDAsMjkyNDEsMjkyNDksMjkyNTAsMjkyNTEsMjkyNTMsMjkyNjIsMjkyNjMsMjkyNjQsMjkyNjcsMjkyNjksMjkyNzAsMjkyNzQsMjkyNzYsMjkyNzgsMjkyODAsMjkyODMsMjkyODgsMjkyOTEsMjkyOTQsMjkyOTUsMjkyOTcsMjkzMDMsMjkzMDQsMjkzMDcsMjkzMDgsMjkzMTEsMjkzMTYsMjkzMjEsMjkzMjUsMjkzMjYsMjkzMzEsMjkzMzksMjkzNTIsMjkzNTcsMjkzNTgsMjkzNjEsMjkzNjQsMjkzNzQsMjkzNzcsMjkzODMsMjkzODUsMjkzODgsMjkzOTcsMjkzOTgsMjk0MDAsMjk0MDcsMjk0MTMsMjk0MjcsMjk0MjgsMjk0MzQsMjk0MzUsMjk0MzgsMjk0NDIsMjk0NDQsMjk0NDUsMjk0NDcsMjk0NTEsMjk0NTMsMjk0NTgsMjk0NTksMjk0NjQsMjk0NjUsMjk0NzAsMjk0NzQsMjk0NzYsMjk0NzksMjk0ODAsMjk0ODQsMjk0ODksMjk0OTAsMjk0OTMsMjk0OTgsMjk0OTksMjk1MDEsMjk1MDcsMjk1MTcsMjk1MjAsMjk1MjIsMjk1MjYsMjk1MjgsMjk1MzMsMjk1MzQsMjk1MzUsMjk1MzYsMjk1NDIsMjk1NDMsMjk1NDUsMjk1NDcsMjk1NDgsMjk1NTAsMjk1NTEsMjk1NTMsMjk1NTksMjk1NjEsMjk1NjQsMjk1NjgsMjk1NjksMjk1NzEsMjk1NzMsMjk1NzQsMjk1ODIsMjk1ODQsMjk1ODcsMjk1ODksMjk1OTEsMjk1OTIsMjk1OTYsMjk1OTgsMjk1OTksMjk2MDAsMjk2MDIsMjk2MDUsMjk2MDYsMjk2MTAsMjk2MTEsMjk2MTMsMjk2MjEsMjk2MjMsMjk2MjUsMjk2MjgsMjk2MjksMjk2MzEsMjk2MzcsMjk2MzgsMjk2NDEsMjk2NDMsMjk2NDQsMjk2NDcsMjk2NTAsMjk2NTEsMjk2NTQsMjk2NTcsMjk2NjEsMjk2NjUsMjk2NjcsMjk2NzAsMjk2NzEsMjk2NzMsMjk2ODQsMjk2ODUsMjk2ODcsMjk2ODksMjk2OTAsMjk2OTEsMjk2OTMsMjk2OTUsMjk2OTYsMjk2OTcsMjk3MDAsMjk3MDMsMjk3MDYsMjk3MTMsMjk3MjIsMjk3MjMsMjk3MzIsMjk3MzQsMjk3MzYsMjk3MzcsMjk3MzgsMjk3MzksMjk3NDAsMjk3NDEsMjk3NDIsMjk3NDMsMjk3NDQsMjk3NDUsMjk3NTMsMjk3NjAsMjk3NjMsMjk3NjQsMjk3NjYsMjk3NjcsMjk3NzEsMjk3NzMsMjk3NzcsMjk3NzgsMjk3ODMsMjk3ODksMjk3OTQsMjk3OTgsMjk3OTksMjk4MDAsMjk4MDMsMjk4MDUsMjk4MDYsMjk4MDksMjk4MTAsMjk4MjQsMjk4MjUsMjk4MjksMjk4MzAsMjk4MzEsMjk4MzMsMjk4MzksMjk4NDAsMjk4NDEsMjk4NDIsMjk4NDgsMjk4NDksMjk4NTAsMjk4NTIsMjk4NTUsMjk4NTYsMjk4NTcsMjk4NTksMjk4NjIsMjk4NjQsMjk4NjUsMjk4NjYsMjk4NjcsMjk4NzAsMjk4NzEsMjk4NzMsMjk4NzQsMjk4NzcsMjk4ODEsMjk4ODMsMjk4ODcsMjk4OTYsMjk4OTcsMjk5MDAsMjk5MDQsMjk5MDcsMjk5MTIsMjk5MTQsMjk5MTUsMjk5MTgsMjk5MTksMjk5MjQsMjk5MjgsMjk5MzAsMjk5MzEsMjk5MzUsMjk5NDAsMjk5NDYsMjk5NDcsMjk5NDgsMjk5NTEsMjk5NTgsMjk5NzAsMjk5NzQsMjk5NzUsMjk5ODQsMjk5ODUsMjk5ODgsMjk5OTEsMjk5OTMsMjk5OTQsMjk5OTksMzAwMDYsMzAwMDksMzAwMTMsMzAwMTQsMzAwMTUsMzAwMTYsMzAwMTksMzAwMjMsMzAwMjQsMzAwMzAsMzAwMzIsMzAwMzQsMzAwMzksMzAwNDYsMzAwNDcsMzAwNDksMzAwNjMsMzAwNjUsMzAwNzMsMzAwNzQsMzAwNzUsMzAwNzYsMzAwNzcsMzAwNzgsMzAwODEsMzAwODUsMzAwOTYsMzAwOTgsMzAwOTksMzAxMDEsMzAxMDUsMzAxMDgsMzAxMTQsMzAxMTYsMzAxMzIsMzAxMzgsMzAxNDMsMzAxNDQsMzAxNDUsMzAxNDgsMzAxNTAsMzAxNTYsMzAxNTgsMzAxNTksMzAxNjcsMzAxNzIsMzAxNzUsMzAxNzYsMzAxNzcsMzAxODAsMzAxODMsMzAxODgsMzAxOTAsMzAxOTEsMzAxOTMsMzAyMDEsMzAyMDgsMzAyMTAsMzAyMTEsMzAyMTIsMzAyMTUsMzAyMTYsMzAyMTgsMzAyMjAsMzAyMjMsMzAyMjYsMzAyMjcsMzAyMjksMzAyMzAsMzAyMzMsMzAyMzUsMzAyMzYsMzAyMzcsMzAyMzgsMzAyNDMsMzAyNDUsMzAyNDYsMzAyNDksMzAyNTMsMzAyNTgsMzAyNTksMzAyNjEsMzAyNjQsMzAyNjUsMzAyNjYsMzAyNjgsMzAyODIsMzAyNzIsMzAyNzMsMzAyNzUsMzAyNzYsMzAyNzcsMzAyODEsMzAyODMsMzAyOTMsMzAyOTcsMzAzMDMsMzAzMDgsMzAzMDksMzAzMTcsMzAzMTgsMzAzMTksMzAzMjEsMzAzMjQsMzAzMzcsMzAzNDEsMzAzNDgsMzAzNDksMzAzNTcsMzAzNjMsMzAzNjQsMzAzNjUsMzAzNjcsMzAzNjgsMzAzNzAsMzAzNzEsMzAzNzIsMzAzNzMsMzAzNzQsMzAzNzUsMzAzNzYsMzAzNzgsMzAzODEsMzAzOTcsMzA0MDEsMzA0MDUsMzA0MDksMzA0MTEsMzA0MTIsMzA0MTQsMzA0MjAsMzA0MjUsMzA0MzIsMzA0MzgsMzA0NDAsMzA0NDQsMzA0NDgsMzA0NDksMzA0NTQsMzA0NTcsMzA0NjAsMzA0NjQsMzA0NzAsMzA0NzQsMzA0NzgsMzA0ODIsMzA0ODQsMzA0ODUsMzA0ODcsMzA0ODksMzA0OTAsMzA0OTIsMzA0OTgsMzA1MDQsMzA1MDksMzA1MTAsMzA1MTEsMzA1MTYsMzA1MTcsMzA1MTgsMzA1MjEsMzA1MjUsMzA1MjYsMzA1MzAsMzA1MzMsMzA1MzQsMzA1MzgsMzA1NDEsMzA1NDIsMzA1NDMsMzA1NDYsMzA1NTAsMzA1NTEsMzA1NTYsMzA1NTgsMzA1NTksMzA1NjAsMzA1NjIsMzA1NjQsMzA1NjcsMzA1NzAsMzA1NzIsMzA1NzYsMzA1NzgsMzA1NzksMzA1ODAsMzA1ODYsMzA1ODksMzA1OTIsMzA1OTYsMzA2MDQsMzA2MDUsMzA2MTIsMzA2MTMsMzA2MTQsMzA2MTgsMzA2MjMsMzA2MjYsMzA2MzEsMzA2MzQsMzA2MzgsMzA2MzksMzA2NDEsMzA2NDUsMzA2NTQsMzA2NTksMzA2NjUsMzA2NzMsMzA2NzQsMzA2NzcsMzA2ODEsMzA2ODYsMzA2ODcsMzA2ODgsMzA2OTIsMzA2OTQsMzA2OTgsMzA3MDAsMzA3MDQsMzA3MDUsMzA3MDgsMzA3MTIsMzA3MTUsMzA3MjUsMzA3MjYsMzA3MjksMzA3MzMsMzA3MzQsMzA3MzcsMzA3NDksMzA3NTMsMzA3NTQsMzA3NTUsMzA3NjUsMzA3NjYsMzA3NjgsMzA3NzMsMzA3NzUsMzA3ODcsMzA3ODgsMzA3OTEsMzA3OTIsMzA3OTYsMzA3OTgsMzA4MDIsMzA4MTIsMzA4MTQsMzA4MTYsMzA4MTcsMzA4MTksMzA4MjAsMzA4MjQsMzA4MjYsMzA4MzAsMzA4NDIsMzA4NDYsMzA4NTgsMzA4NjMsMzA4NjgsMzA4NzIsMzA4ODEsMzA4NzcsMzA4NzgsMzA4NzksMzA4ODQsMzA4ODgsMzA4OTIsMzA4OTMsMzA4OTYsMzA4OTcsMzA4OTgsMzA4OTksMzA5MDcsMzA5MDksMzA5MTEsMzA5MTksMzA5MjAsMzA5MjEsMzA5MjQsMzA5MjYsMzA5MzAsMzA5MzEsMzA5MzMsMzA5MzQsMzA5NDgsMzA5MzksMzA5NDMsMzA5NDQsMzA5NDUsMzA5NTAsMzA5NTQsMzA5NjIsMzA5NjMsMzA5NzYsMzA5NjYsMzA5NjcsMzA5NzAsMzA5NzEsMzA5NzUsMzA5ODIsMzA5ODgsMzA5OTIsMzEwMDIsMzEwMDQsMzEwMDYsMzEwMDcsMzEwMDgsMzEwMTMsMzEwMTUsMzEwMTcsMzEwMjEsMzEwMjUsMzEwMjgsMzEwMjksMzEwMzUsMzEwMzcsMzEwMzksMzEwNDQsMzEwNDUsMzEwNDYsMzEwNTAsMzEwNTEsMzEwNTUsMzEwNTcsMzEwNjAsMzEwNjQsMzEwNjcsMzEwNjgsMzEwNzksMzEwODEsMzEwODMsMzEwOTAsMzEwOTcsMzEwOTksMzExMDAsMzExMDIsMzExMTUsMzExMTYsMzExMjEsMzExMjMsMzExMjQsMzExMjUsMzExMjYsMzExMjgsMzExMzEsMzExMzIsMzExMzcsMzExNDQsMzExNDUsMzExNDcsMzExNTEsMzExNTMsMzExNTYsMzExNjAsMzExNjMsMzExNzAsMzExNzIsMzExNzUsMzExNzYsMzExNzgsMzExODMsMzExODgsMzExOTAsMzExOTQsMzExOTcsMzExOTgsMzEyMDAsMzEyMDIsMzEyMDUsMzEyMTAsMzEyMTEsMzEyMTMsMzEyMTcsMzEyMjQsMzEyMjgsMzEyMzQsMzEyMzUsMzEyMzksMzEyNDEsMzEyNDIsMzEyNDQsMzEyNDksMzEyNTMsMzEyNTksMzEyNjIsMzEyNjUsMzEyNzEsMzEyNzUsMzEyNzcsMzEyNzksMzEyODAsMzEyODQsMzEyODUsMzEyODgsMzEyODksMzEyOTAsMzEzMDAsMzEzMDEsMzEzMDMsMzEzMDQsMzEzMDgsMzEzMTcsMzEzMTgsMzEzMjEsMzEzMjQsMzEzMjUsMzEzMjcsMzEzMjgsMzEzMzMsMzEzMzUsMzEzMzgsMzEzNDEsMzEzNDksMzEzNTIsMzEzNTgsMzEzNjAsMzEzNjIsMzEzNjUsMzEzNjYsMzEzNzAsMzEzNzEsMzEzNzYsMzEzNzcsMzEzODAsMzEzOTAsMzEzOTIsMzEzOTUsMzE0MDQsMzE0MTEsMzE0MTMsMzE0MTcsMzE0MTksMzE0MjAsMzE0MzAsMzE0MzMsMzE0MzYsMzE0MzgsMzE0NDEsMzE0NTEsMzE0NjQsMzE0NjUsMzE0NjcsMzE0NjgsMzE0NzMsMzE0NzYsMzE0ODMsMzE0ODUsMzE0ODYsMzE0OTUsMzE1MDgsMzE1MTksMzE1MjMsMzE1MjcsMzE1MjksMzE1MzAsMzE1MzEsMzE1MzMsMzE1MzQsMzE1MzUsMzE1MzYsMzE1MzcsMzE1NDAsMzE1NDksMzE1NTEsMzE1NTIsMzE1NTMsMzE1NTksMzE1NjYsMzE1NzMsMzE1ODQsMzE1ODgsMzE1OTAsMzE1OTMsMzE1OTQsMzE1OTcsMzE1OTksMzE2MDIsMzE2MDMsMzE2MDcsMzE2MjAsMzE2MjUsMzE2MzAsMzE2MzIsMzE2MzMsMzE2MzgsMzE2NDMsMzE2NDYsMzE2NDgsMzE2NTMsMzE2NjAsMzE2NjMsMzE2NjQsMzE2NjYsMzE2NjksMzE2NzAsMzE2NzQsMzE2NzUsMzE2NzYsMzE2NzcsMzE2ODIsMzE2ODUsMzE2ODgsMzE2OTAsMzE3MDAsMzE3MDIsMzE3MDMsMzE3MDUsMzE3MDYsMzE3MDcsMzE3MjAsMzE3MjIsMzE3MzAsMzE3MzIsMzE3MzMsMzE3MzYsMzE3MzcsMzE3MzgsMzE3NDAsMzE3NDIsMzE3NDUsMzE3NDYsMzE3NDcsMzE3NDgsMzE3NTAsMzE3NTMsMzE3NTUsMzE3NTYsMzE3NTgsMzE3NTksMzE3NjksMzE3NzEsMzE3NzYsMzE3ODEsMzE3ODIsMzE3ODQsMzE3ODgsMzE3OTMsMzE3OTUsMzE3OTYsMzE3OTgsMzE4MDEsMzE4MDIsMzE4MTQsMzE4MTgsMzE4MjksMzE4MjUsMzE4MjYsMzE4MjcsMzE4MzMsMzE4MzQsMzE4MzUsMzE4MzYsMzE4MzcsMzE4MzgsMzE4NDEsMzE4NDMsMzE4NDcsMzE4NDksMzE4NTMsMzE4NTQsMzE4NTYsMzE4NTgsMzE4NjUsMzE4NjgsMzE4NjksMzE4NzgsMzE4NzksMzE4ODcsMzE4OTIsMzE5MDIsMzE5MDQsMzE5MTAsMzE5MjAsMzE5MjYsMzE5MjcsMzE5MzAsMzE5MzEsMzE5MzIsMzE5MzUsMzE5NDAsMzE5NDMsMzE5NDQsMzE5NDUsMzE5NDksMzE5NTEsMzE5NTUsMzE5NTYsMzE5NTcsMzE5NTksMzE5NjEsMzE5NjIsMzE5NjUsMzE5NzQsMzE5NzcsMzE5NzksMzE5ODksMzIwMDMsMzIwMDcsMzIwMDgsMzIwMDksMzIwMTUsMzIwMTcsMzIwMTgsMzIwMTksMzIwMjIsMzIwMjksMzIwMzAsMzIwMzUsMzIwMzgsMzIwNDIsMzIwNDUsMzIwNDksMzIwNjAsMzIwNjEsMzIwNjIsMzIwNjQsMzIwNjUsMzIwNzEsMzIwNzIsMzIwNzcsMzIwODEsMzIwODMsMzIwODcsMzIwODksMzIwOTAsMzIwOTIsMzIwOTMsMzIxMDEsMzIxMDMsMzIxMDYsMzIxMTIsMzIxMjAsMzIxMjIsMzIxMjMsMzIxMjcsMzIxMjksMzIxMzAsMzIxMzEsMzIxMzMsMzIxMzQsMzIxMzYsMzIxMzksMzIxNDAsMzIxNDEsMzIxNDUsMzIxNTAsMzIxNTEsMzIxNTcsMzIxNTgsMzIxNjYsMzIxNjcsMzIxNzAsMzIxNzksMzIxODIsMzIxODMsMzIxODUsMzIxOTQsMzIxOTUsMzIxOTYsMzIxOTcsMzIxOTgsMzIyMDQsMzIyMDUsMzIyMDYsMzIyMTUsMzIyMTcsMzIyNTYsMzIyMjYsMzIyMjksMzIyMzAsMzIyMzQsMzIyMzUsMzIyMzcsMzIyNDEsMzIyNDUsMzIyNDYsMzIyNDksMzIyNTAsMzIyNjQsMzIyNzIsMzIyNzMsMzIyNzcsMzIyNzksMzIyODQsMzIyODUsMzIyODgsMzIyOTUsMzIyOTYsMzIzMDAsMzIzMDEsMzIzMDMsMzIzMDcsMzIzMTAsMzIzMTksMzIzMjQsMzIzMjUsMzIzMjcsMzIzMzQsMzIzMzYsMzIzMzgsMzIzNDQsMzIzNTEsMzIzNTMsMzIzNTQsMzIzNTcsMzIzNjMsMzIzNjYsMzIzNjcsMzIzNzEsMzIzNzYsMzIzODIsMzIzODUsMzIzOTAsMzIzOTEsMzIzOTQsMzIzOTcsMzI0MDEsMzI0MDUsMzI0MDgsMzI0MTAsMzI0MTMsMzI0MTQsMzI1NzIsMzI1NzEsMzI1NzMsMzI1NzQsMzI1NzUsMzI1NzksMzI1ODAsMzI1ODMsMzI1OTEsMzI1OTQsMzI1OTUsMzI2MDMsMzI2MDQsMzI2MDUsMzI2MDksMzI2MTEsMzI2MTIsMzI2MTMsMzI2MTQsMzI2MjEsMzI2MjUsMzI2MzcsMzI2MzgsMzI2MzksMzI2NDAsMzI2NTEsMzI2NTMsMzI2NTUsMzI2NTYsMzI2NTcsMzI2NjIsMzI2NjMsMzI2NjgsMzI2NzMsMzI2NzQsMzI2NzgsMzI2ODIsMzI2ODUsMzI2OTIsMzI3MDAsMzI3MDMsMzI3MDQsMzI3MDcsMzI3MTIsMzI3MTgsMzI3MTksMzI3MzEsMzI3MzUsMzI3MzksMzI3NDEsMzI3NDQsMzI3NDgsMzI3NTAsMzI3NTEsMzI3NTQsMzI3NjIsMzI3NjUsMzI3NjYsMzI3NjcsMzI3NzUsMzI3NzYsMzI3NzgsMzI3ODEsMzI3ODIsMzI3ODMsMzI3ODUsMzI3ODcsMzI3ODgsMzI3OTAsMzI3OTcsMzI3OTgsMzI3OTksMzI4MDAsMzI4MDQsMzI4MDYsMzI4MTIsMzI4MTQsMzI4MTYsMzI4MjAsMzI4MjEsMzI4MjMsMzI4MjUsMzI4MjYsMzI4MjgsMzI4MzAsMzI4MzIsMzI4MzYsMzI4NjQsMzI4NjgsMzI4NzAsMzI4NzcsMzI4ODEsMzI4ODUsMzI4OTcsMzI5MDQsMzI5MTAsMzI5MjQsMzI5MjYsMzI5MzQsMzI5MzUsMzI5MzksMzI5NTIsMzI5NTMsMzI5NjgsMzI5NzMsMzI5NzUsMzI5NzgsMzI5ODAsMzI5ODEsMzI5ODMsMzI5ODQsMzI5OTIsMzMwMDUsMzMwMDYsMzMwMDgsMzMwMTAsMzMwMTEsMzMwMTQsMzMwMTcsMzMwMTgsMzMwMjIsMzMwMjcsMzMwMzUsMzMwNDYsMzMwNDcsMzMwNDgsMzMwNTIsMzMwNTQsMzMwNTYsMzMwNjAsMzMwNjMsMzMwNjgsMzMwNzIsMzMwNzcsMzMwODIsMzMwODQsMzMwOTMsMzMwOTUsMzMwOTgsMzMxMDAsMzMxMDYsMzMxMTEsMzMxMjAsMzMxMjEsMzMxMjcsMzMxMjgsMzMxMjksMzMxMzMsMzMxMzUsMzMxNDMsMzMxNTMsMzMxNjgsMzMxNTYsMzMxNTcsMzMxNTgsMzMxNjMsMzMxNjYsMzMxNzQsMzMxNzYsMzMxNzksMzMxODIsMzMxODYsMzMxOTgsMzMyMDIsMzMyMDQsMzMyMTEsMzMyMjcsMzMyMTksMzMyMjEsMzMyMjYsMzMyMzAsMzMyMzEsMzMyMzcsMzMyMzksMzMyNDMsMzMyNDUsMzMyNDYsMzMyNDksMzMyNTIsMzMyNTksMzMyNjAsMzMyNjQsMzMyNjUsMzMyNjYsMzMyNjksMzMyNzAsMzMyNzIsMzMyNzMsMzMyNzcsMzMyNzksMzMyODAsMzMyODMsMzMyOTUsMzMyOTksMzMzMDAsMzMzMDUsMzMzMDYsMzMzMDksMzMzMTMsMzMzMTQsMzMzMjAsMzMzMzAsMzMzMzIsMzMzMzgsMzMzNDcsMzMzNDgsMzMzNDksMzMzNTAsMzMzNTUsMzMzNTgsMzMzNTksMzMzNjEsMzMzNjYsMzMzNzIsMzMzNzYsMzMzNzksMzMzODMsMzMzODksMzMzOTYsMzM0MDMsMzM0MDUsMzM0MDcsMzM0MDgsMzM0MDksMzM0MTEsMzM0MTIsMzM0MTUsMzM0MTcsMzM0MTgsMzM0MjIsMzM0MjUsMzM0MjgsMzM0MzAsMzM0MzIsMzM0MzQsMzM0MzUsMzM0NDAsMzM0NDEsMzM0NDMsMzM0NDQsMzM0NDcsMzM0NDgsMzM0NDksMzM0NTAsMzM0NTQsMzM0NTYsMzM0NTgsMzM0NjAsMzM0NjMsMzM0NjYsMzM0NjgsMzM0NzAsMzM0NzEsMzM0NzgsMzM0ODgsMzM0OTMsMzM0OTgsMzM1MDQsMzM1MDYsMzM1MDgsMzM1MTIsMzM1MTQsMzM1MTcsMzM1MTksMzM1MjYsMzM1MjcsMzM1MzMsMzM1MzQsMzM1MzYsMzM1MzcsMzM1NDMsMzM1NDQsMzM1NDYsMzM1NDcsMzM2MjAsMzM1NjMsMzM1NjUsMzM1NjYsMzM1NjcsMzM1NjksMzM1NzAsMzM1ODAsMzM1ODEsMzM1ODIsMzM1ODQsMzM1ODcsMzM1OTEsMzM1OTQsMzM1OTYsMzM1OTcsMzM2MDIsMzM2MDMsMzM2MDQsMzM2MDcsMzM2MTMsMzM2MTQsMzM2MTcsMzM2MjEsMzM2MjIsMzM2MjMsMzM2NDgsMzM2NTYsMzM2NjEsMzM2NjMsMzM2NjQsMzM2NjYsMzM2NjgsMzM2NzAsMzM2NzcsMzM2ODIsMzM2ODQsMzM2ODUsMzM2ODgsMzM2ODksMzM2OTEsMzM2OTIsMzM2OTMsMzM3MDIsMzM3MDMsMzM3MDUsMzM3MDgsMzM3MjYsMzM3MjcsMzM3MjgsMzM3MzUsMzM3MzcsMzM3NDMsMzM3NDQsMzM3NDUsMzM3NDgsMzM3NTcsMzM2MTksMzM3NjgsMzM3NzAsMzM3ODIsMzM3ODQsMzM3ODUsMzM3ODgsMzM3OTMsMzM3OTgsMzM4MDIsMzM4MDcsMzM4MDksMzM4MTMsMzM4MTcsMzM3MDksMzM4MzksMzM4NDksMzM4NjEsMzM4NjMsMzM4NjQsMzM4NjYsMzM4NjksMzM4NzEsMzM4NzMsMzM4NzQsMzM4NzgsMzM4ODAsMzM4ODEsMzM4ODIsMzM4ODQsMzM4ODgsMzM4OTIsMzM4OTMsMzM4OTUsMzM4OTgsMzM5MDQsMzM5MDcsMzM5MDgsMzM5MTAsMzM5MTIsMzM5MTYsMzM5MTcsMzM5MjEsMzM5MjUsMzM5MzgsMzM5MzksMzM5NDEsMzM5NTAsMzM5NTgsMzM5NjAsMzM5NjEsMzM5NjIsMzM5NjcsMzM5NjksMzM5NzIsMzM5NzgsMzM5ODEsMzM5ODIsMzM5ODQsMzM5ODYsMzM5OTEsMzM5OTIsMzM5OTYsMzM5OTksMzQwMDMsMzQwMTIsMzQwMjMsMzQwMjYsMzQwMzEsMzQwMzIsMzQwMzMsMzQwMzQsMzQwMzksMzQwOTgsMzQwNDIsMzQwNDMsMzQwNDUsMzQwNTAsMzQwNTEsMzQwNTUsMzQwNjAsMzQwNjIsMzQwNjQsMzQwNzYsMzQwNzgsMzQwODIsMzQwODMsMzQwODQsMzQwODUsMzQwODcsMzQwOTAsMzQwOTEsMzQwOTUsMzQwOTksMzQxMDAsMzQxMDIsMzQxMTEsMzQxMTgsMzQxMjcsMzQxMjgsMzQxMjksMzQxMzAsMzQxMzEsMzQxMzQsMzQxMzcsMzQxNDAsMzQxNDEsMzQxNDIsMzQxNDMsMzQxNDQsMzQxNDUsMzQxNDYsMzQxNDgsMzQxNTUsMzQxNTksMzQxNjksMzQxNzAsMzQxNzEsMzQxNzMsMzQxNzUsMzQxNzcsMzQxODEsMzQxODIsMzQxODUsMzQxODcsMzQxODgsMzQxOTEsMzQxOTUsMzQyMDAsMzQyMDUsMzQyMDcsMzQyMDgsMzQyMTAsMzQyMTMsMzQyMTUsMzQyMjgsMzQyMzAsMzQyMzEsMzQyMzIsMzQyMzYsMzQyMzcsMzQyMzgsMzQyMzksMzQyNDIsMzQyNDcsMzQyNTAsMzQyNTEsMzQyNTQsMzQyMjEsMzQyNjQsMzQyNjYsMzQyNzEsMzQyNzIsMzQyNzgsMzQyODAsMzQyODUsMzQyOTEsMzQyOTQsMzQzMDAsMzQzMDMsMzQzMDQsMzQzMDgsMzQzMDksMzQzMTcsMzQzMTgsMzQzMjAsMzQzMjEsMzQzMjIsMzQzMjgsMzQzMjksMzQzMzEsMzQzMzQsMzQzMzcsMzQzNDMsMzQzNDUsMzQzNTgsMzQzNjAsMzQzNjIsMzQzNjQsMzQzNjUsMzQzNjgsMzQzNzAsMzQzNzQsMzQzODYsMzQzODcsMzQzOTAsMzQzOTEsMzQzOTIsMzQzOTMsMzQzOTcsMzQ0MDAsMzQ0MDEsMzQ0MDIsMzQ0MDMsMzQ0MDQsMzQ0MDksMzQ0MTIsMzQ0MTUsMzQ0MjEsMzQ0MjIsMzQ0MjMsMzQ0MjYsMzQ0NDUsMzQ0NDksMzQ0NTQsMzQ0NTYsMzQ0NTgsMzQ0NjAsMzQ0NjUsMzQ0NzAsMzQ0NzEsMzQ0NzIsMzQ0NzcsMzQ0ODEsMzQ0ODMsMzQ0ODQsMzQ0ODUsMzQ0ODcsMzQ0ODgsMzQ0ODksMzQ0OTUsMzQ0OTYsMzQ0OTcsMzQ0OTksMzQ1MDEsMzQ1MTMsMzQ1MTQsMzQ1MTcsMzQ1MTksMzQ1MjIsMzQ1MjQsMzQ1MjgsMzQ1MzEsMzQ1MzMsMzQ1MzUsMzQ0NDAsMzQ1NTQsMzQ1NTYsMzQ1NTcsMzQ1NjQsMzQ1NjUsMzQ1NjcsMzQ1NzEsMzQ1NzQsMzQ1NzUsMzQ1NzYsMzQ1NzksMzQ1ODAsMzQ1ODUsMzQ1OTAsMzQ1OTEsMzQ1OTMsMzQ1OTUsMzQ2MDAsMzQ2MDYsMzQ2MDcsMzQ2MDksMzQ2MTAsMzQ2MTcsMzQ2MTgsMzQ2MjAsMzQ2MjEsMzQ2MjIsMzQ2MjQsMzQ2MjcsMzQ2MjksMzQ2MzcsMzQ2NDgsMzQ2NTMsMzQ2NTcsMzQ2NjAsMzQ2NjEsMzQ2NzEsMzQ2NzMsMzQ2NzQsMzQ2ODMsMzQ2OTEsMzQ2OTIsMzQ2OTMsMzQ2OTQsMzQ2OTUsMzQ2OTYsMzQ2OTcsMzQ2OTksMzQ3MDAsMzQ3MDQsMzQ3MDcsMzQ3MDksMzQ3MTEsMzQ3MTIsMzQ3MTMsMzQ3MTgsMzQ3MjAsMzQ3MjMsMzQ3MjcsMzQ3MzIsMzQ3MzMsMzQ3MzQsMzQ3MzcsMzQ3NDEsMzQ3NTAsMzQ3NTEsMzQ3NTMsMzQ3NjAsMzQ3NjEsMzQ3NjIsMzQ3NjYsMzQ3NzMsMzQ3NzQsMzQ3NzcsMzQ3NzgsMzQ3ODAsMzQ3ODMsMzQ3ODYsMzQ3ODcsMzQ3ODgsMzQ3OTQsMzQ3OTUsMzQ3OTcsMzQ4MDEsMzQ4MDMsMzQ4MDgsMzQ4MTAsMzQ4MTUsMzQ4MTcsMzQ4MTksMzQ4MjIsMzQ4MjUsMzQ4MjYsMzQ4MjcsMzQ4MzIsMzQ4NDEsMzQ4MzQsMzQ4MzUsMzQ4MzYsMzQ4NDAsMzQ4NDIsMzQ4NDMsMzQ4NDQsMzQ4NDYsMzQ4NDcsMzQ4NTYsMzQ4NjEsMzQ4NjIsMzQ4NjQsMzQ4NjYsMzQ4NjksMzQ4NzQsMzQ4NzYsMzQ4ODEsMzQ4ODMsMzQ4ODUsMzQ4ODgsMzQ4ODksMzQ4OTAsMzQ4OTEsMzQ4OTQsMzQ4OTcsMzQ5MDEsMzQ5MDIsMzQ5MDQsMzQ5MDYsMzQ5MDgsMzQ5MTEsMzQ5MTIsMzQ5MTYsMzQ5MjEsMzQ5MjksMzQ5MzcsMzQ5MzksMzQ5NDQsMzQ5NjgsMzQ5NzAsMzQ5NzEsMzQ5NzIsMzQ5NzUsMzQ5NzYsMzQ5ODQsMzQ5ODYsMzUwMDIsMzUwMDUsMzUwMDYsMzUwMDgsMzUwMTgsMzUwMTksMzUwMjAsMzUwMjEsMzUwMjIsMzUwMjUsMzUwMjYsMzUwMjcsMzUwMzUsMzUwMzgsMzUwNDcsMzUwNTUsMzUwNTYsMzUwNTcsMzUwNjEsMzUwNjMsMzUwNzMsMzUwNzgsMzUwODUsMzUwODYsMzUwODcsMzUwOTMsMzUwOTQsMzUwOTYsMzUwOTcsMzUwOTgsMzUxMDAsMzUxMDQsMzUxMTAsMzUxMTEsMzUxMTIsMzUxMjAsMzUxMjEsMzUxMjIsMzUxMjUsMzUxMjksMzUxMzAsMzUxMzQsMzUxMzYsMzUxMzgsMzUxNDEsMzUxNDIsMzUxNDUsMzUxNTEsMzUxNTQsMzUxNTksMzUxNjIsMzUxNjMsMzUxNjQsMzUxNjksMzUxNzAsMzUxNzEsMzUxNzksMzUxODIsMzUxODQsMzUxODcsMzUxODksMzUxOTQsMzUxOTUsMzUxOTYsMzUxOTcsMzUyMDksMzUyMTMsMzUyMTYsMzUyMjAsMzUyMjEsMzUyMjcsMzUyMjgsMzUyMzEsMzUyMzIsMzUyMzcsMzUyNDgsMzUyNTIsMzUyNTMsMzUyNTQsMzUyNTUsMzUyNjAsMzUyODQsMzUyODUsMzUyODYsMzUyODcsMzUyODgsMzUzMDEsMzUzMDUsMzUzMDcsMzUzMDksMzUzMTMsMzUzMTUsMzUzMTgsMzUzMjEsMzUzMjUsMzUzMjcsMzUzMzIsMzUzMzMsMzUzMzUsMzUzNDMsMzUzNDUsMzUzNDYsMzUzNDgsMzUzNDksMzUzNTgsMzUzNjAsMzUzNjIsMzUzNjQsMzUzNjYsMzUzNzEsMzUzNzIsMzUzNzUsMzUzODEsMzUzODMsMzUzODksMzUzOTAsMzUzOTIsMzUzOTUsMzUzOTcsMzUzOTksMzU0MDEsMzU0MDUsMzU0MDYsMzU0MTEsMzU0MTQsMzU0MTUsMzU0MTYsMzU0MjAsMzU0MjEsMzU0MjUsMzU0MjksMzU0MzEsMzU0NDUsMzU0NDYsMzU0NDcsMzU0NDksMzU0NTAsMzU0NTEsMzU0NTQsMzU0NTUsMzU0NTYsMzU0NTksMzU0NjIsMzU0NjcsMzU0NzEsMzU0NzIsMzU0NzQsMzU0NzgsMzU0NzksMzU0ODEsMzU0ODcsMzU0OTUsMzU0OTcsMzU1MDIsMzU1MDMsMzU1MDcsMzU1MTAsMzU1MTEsMzU1MTUsMzU1MTgsMzU1MjMsMzU1MjYsMzU1MjgsMzU1MjksMzU1MzAsMzU1MzcsMzU1MzksMzU1NDAsMzU1NDEsMzU1NDMsMzU1NDksMzU1NTEsMzU1NjQsMzU1NjgsMzU1NzIsMzU1NzMsMzU1NzQsMzU1ODAsMzU1ODMsMzU1ODksMzU1OTAsMzU1OTUsMzU2MDEsMzU2MTIsMzU2MTQsMzU2MTUsMzU1OTQsMzU2MjksMzU2MzIsMzU2MzksMzU2NDQsMzU2NTAsMzU2NTEsMzU2NTIsMzU2NTMsMzU2NTQsMzU2NTYsMzU2NjYsMzU2NjcsMzU2NjgsMzU2NzMsMzU2NjEsMzU2NzgsMzU2ODMsMzU2OTMsMzU3MDIsMzU3MDQsMzU3MDUsMzU3MDgsMzU3MTAsMzU3MTMsMzU3MTYsMzU3MTcsMzU3MjMsMzU3MjUsMzU3MjcsMzU3MzIsMzU3MzMsMzU3NDAsMzU3NDIsMzU3NDMsMzU4OTYsMzU4OTcsMzU5MDEsMzU5MDIsMzU5MDksMzU5MTEsMzU5MTMsMzU5MTUsMzU5MTksMzU5MjEsMzU5MjMsMzU5MjQsMzU5MjcsMzU5MjgsMzU5MzEsMzU5MzMsMzU5MjksMzU5MzksMzU5NDAsMzU5NDIsMzU5NDQsMzU5NDUsMzU5NDksMzU5NTUsMzU5NTcsMzU5NTgsMzU5NjMsMzU5NjYsMzU5NzQsMzU5NzUsMzU5NzksMzU5ODQsMzU5ODYsMzU5ODcsMzU5OTMsMzU5OTUsMzU5OTYsMzYwMDQsMzYwMjUsMzYwMjYsMzYwMzcsMzYwMzgsMzYwNDEsMzYwNDMsMzYwNDcsMzYwNTQsMzYwNTMsMzYwNTcsMzYwNjEsMzYwNjUsMzYwNzIsMzYwNzYsMzYwNzksMzYwODAsMzYwODIsMzYwODUsMzYwODcsMzYwODgsMzYwOTQsMzYwOTUsMzYwOTcsMzYwOTksMzYxMDUsMzYxMTQsMzYxMTksMzYxMjMsMzYxOTcsMzYyMDEsMzYyMDQsMzYyMDYsMzYyMjMsMzYyMjYsMzYyMjgsMzYyMzIsMzYyMzcsMzYyNDAsMzYyNDEsMzYyNDUsMzYyNTQsMzYyNTUsMzYyNTYsMzYyNjIsMzYyNjcsMzYyNjgsMzYyNzEsMzYyNzQsMzYyNzcsMzYyNzksMzYyODEsMzYyODMsMzYyODgsMzYyOTMsMzYyOTQsMzYyOTUsMzYyOTYsMzYyOTgsMzYzMDIsMzYzMDUsMzYzMDgsMzYzMDksMzYzMTEsMzYzMTMsMzYzMjQsMzYzMjUsMzYzMjcsMzYzMzIsMzYzMzYsMzYyODQsMzYzMzcsMzYzMzgsMzYzNDAsMzYzNDksMzYzNTMsMzYzNTYsMzYzNTcsMzYzNTgsMzYzNjMsMzYzNjksMzYzNzIsMzYzNzQsMzYzODQsMzYzODUsMzYzODYsMzYzODcsMzYzOTAsMzYzOTEsMzY0MDEsMzY0MDMsMzY0MDYsMzY0MDcsMzY0MDgsMzY0MDksMzY0MTMsMzY0MTYsMzY0MTcsMzY0MjcsMzY0MjksMzY0MzAsMzY0MzEsMzY0MzYsMzY0NDMsMzY0NDQsMzY0NDUsMzY0NDYsMzY0NDksMzY0NTAsMzY0NTcsMzY0NjAsMzY0NjEsMzY0NjMsMzY0NjQsMzY0NjUsMzY0NzMsMzY0NzQsMzY0NzUsMzY0ODIsMzY0ODMsMzY0ODksMzY0OTYsMzY0OTgsMzY1MDEsMzY1MDYsMzY1MDcsMzY1MDksMzY1MTAsMzY1MTQsMzY1MTksMzY1MjEsMzY1MjUsMzY1MjYsMzY1MzEsMzY1MzMsMzY1MzgsMzY1MzksMzY1NDQsMzY1NDUsMzY1NDcsMzY1NDgsMzY1NTEsMzY1NTksMzY1NjEsMzY1NjQsMzY1NzIsMzY1ODQsMzY1OTAsMzY1OTIsMzY1OTMsMzY1OTksMzY2MDEsMzY2MDIsMzY1ODksMzY2MDgsMzY2MTAsMzY2MTUsMzY2MTYsMzY2MjMsMzY2MjQsMzY2MzAsMzY2MzEsMzY2MzIsMzY2MzgsMzY2NDAsMzY2NDEsMzY2NDMsMzY2NDUsMzY2NDcsMzY2NDgsMzY2NTIsMzY2NTMsMzY2NTQsMzY2NjAsMzY2NjEsMzY2NjIsMzY2NjMsMzY2NjYsMzY2NzIsMzY2NzMsMzY2NzUsMzY2NzksMzY2ODcsMzY2ODksMzY2OTAsMzY2OTEsMzY2OTIsMzY2OTMsMzY2OTYsMzY3MDEsMzY3MDIsMzY3MDksMzY3NjUsMzY3NjgsMzY3NjksMzY3NzIsMzY3NzMsMzY3NzQsMzY3ODksMzY3OTAsMzY3OTIsMzY3OTgsMzY4MDAsMzY4MDEsMzY4MDYsMzY4MTAsMzY4MTEsMzY4MTMsMzY4MTYsMzY4MTgsMzY4MTksMzY4MjEsMzY4MzIsMzY4MzUsMzY4MzYsMzY4NDAsMzY4NDYsMzY4NDksMzY4NTMsMzY4NTQsMzY4NTksMzY4NjIsMzY4NjYsMzY4NjgsMzY4NzIsMzY4NzYsMzY4ODgsMzY4OTEsMzY5MDQsMzY5MDUsMzY5MTEsMzY5MDYsMzY5MDgsMzY5MDksMzY5MTUsMzY5MTYsMzY5MTksMzY5MjcsMzY5MzEsMzY5MzIsMzY5NDAsMzY5NTUsMzY5NTcsMzY5NjIsMzY5NjYsMzY5NjcsMzY5NzIsMzY5NzYsMzY5ODAsMzY5ODUsMzY5OTcsMzcwMDAsMzcwMDMsMzcwMDQsMzcwMDYsMzcwMDgsMzcwMTMsMzcwMTUsMzcwMTYsMzcwMTcsMzcwMTksMzcwMjQsMzcwMjUsMzcwMjYsMzcwMjksMzcwNDAsMzcwNDIsMzcwNDMsMzcwNDQsMzcwNDYsMzcwNTMsMzcwNjgsMzcwNTQsMzcwNTksMzcwNjAsMzcwNjEsMzcwNjMsMzcwNjQsMzcwNzcsMzcwNzksMzcwODAsMzcwODEsMzcwODQsMzcwODUsMzcwODcsMzcwOTMsMzcwNzQsMzcxMTAsMzcwOTksMzcxMDMsMzcxMDQsMzcxMDgsMzcxMTgsMzcxMTksMzcxMjAsMzcxMjQsMzcxMjUsMzcxMjYsMzcxMjgsMzcxMzMsMzcxMzYsMzcxNDAsMzcxNDIsMzcxNDMsMzcxNDQsMzcxNDYsMzcxNDgsMzcxNTAsMzcxNTIsMzcxNTcsMzcxNTQsMzcxNTUsMzcxNTksMzcxNjEsMzcxNjYsMzcxNjcsMzcxNjksMzcxNzIsMzcxNzQsMzcxNzUsMzcxNzcsMzcxNzgsMzcxODAsMzcxODEsMzcxODcsMzcxOTEsMzcxOTIsMzcxOTksMzcyMDMsMzcyMDcsMzcyMDksMzcyMTAsMzcyMTEsMzcyMTcsMzcyMjAsMzcyMjMsMzcyMjksMzcyMzYsMzcyNDEsMzcyNDIsMzcyNDMsMzcyNDksMzcyNTEsMzcyNTMsMzcyNTQsMzcyNTgsMzcyNjIsMzcyNjUsMzcyNjcsMzcyNjgsMzcyNjksMzcyNzIsMzcyNzgsMzcyODEsMzcyODYsMzcyODgsMzcyOTIsMzcyOTMsMzcyOTQsMzcyOTYsMzcyOTcsMzcyOTgsMzcyOTksMzczMDIsMzczMDcsMzczMDgsMzczMDksMzczMTEsMzczMTQsMzczMTUsMzczMTcsMzczMzEsMzczMzIsMzczMzUsMzczMzcsMzczMzgsMzczNDIsMzczNDgsMzczNDksMzczNTMsMzczNTQsMzczNTYsMzczNTcsMzczNTgsMzczNTksMzczNjAsMzczNjEsMzczNjcsMzczNjksMzczNzEsMzczNzMsMzczNzYsMzczNzcsMzczODAsMzczODEsMzczODIsMzczODMsMzczODUsMzczODYsMzczODgsMzczOTIsMzczOTQsMzczOTUsMzczOTgsMzc0MDAsMzc0MDQsMzc0MDUsMzc0MTEsMzc0MTIsMzc0MTMsMzc0MTQsMzc0MTYsMzc0MjIsMzc0MjMsMzc0MjQsMzc0MjcsMzc0MjksMzc0MzAsMzc0MzIsMzc0MzMsMzc0MzQsMzc0MzYsMzc0MzgsMzc0NDAsMzc0NDIsMzc0NDMsMzc0NDYsMzc0NDcsMzc0NTAsMzc0NTMsMzc0NTQsMzc0NTUsMzc0NTcsMzc0NjQsMzc0NjUsMzc0NjgsMzc0NjksMzc0NzIsMzc0NzMsMzc0NzcsMzc0NzksMzc0ODAsMzc0ODEsMzc0ODYsMzc0ODcsMzc0ODgsMzc0OTMsMzc0OTQsMzc0OTUsMzc0OTYsMzc0OTcsMzc0OTksMzc1MDAsMzc1MDEsMzc1MDMsMzc1MTIsMzc1MTMsMzc1MTQsMzc1MTcsMzc1MTgsMzc1MjIsMzc1MjcsMzc1MjksMzc1MzUsMzc1MzYsMzc1NDAsMzc1NDEsMzc1NDMsMzc1NDQsMzc1NDcsMzc1NTEsMzc1NTQsMzc1NTgsMzc1NjAsMzc1NjIsMzc1NjMsMzc1NjQsMzc1NjUsMzc1NjcsMzc1NjgsMzc1NjksMzc1NzAsMzc1NzEsMzc1NzMsMzc1NzQsMzc1NzUsMzc1NzYsMzc1NzksMzc1ODAsMzc1ODEsMzc1ODIsMzc1ODQsMzc1ODcsMzc1ODksMzc1OTEsMzc1OTIsMzc1OTMsMzc1OTYsMzc1OTcsMzc1OTksMzc2MDAsMzc2MDEsMzc2MDMsMzc2MDUsMzc2MDcsMzc2MDgsMzc2MTIsMzc2MTQsMzc2MTYsMzc2MjUsMzc2MjcsMzc2MzEsMzc2MzIsMzc2MzQsMzc2NDAsMzc2NDUsMzc2NDksMzc2NTIsMzc2NTMsMzc2NjAsMzc2NjEsMzc2NjIsMzc2NjMsMzc2NjUsMzc2NjgsMzc2NjksMzc2NzEsMzc2NzMsMzc2NzQsMzc2ODMsMzc2ODQsMzc2ODYsMzc2ODcsMzc3MDMsMzc3MDQsMzc3MDUsMzc3MTIsMzc3MTMsMzc3MTQsMzc3MTcsMzc3MTksMzc3MjAsMzc3MjIsMzc3MjYsMzc3MzIsMzc3MzMsMzc3MzUsMzc3MzcsMzc3MzgsMzc3NDEsMzc3NDMsMzc3NDQsMzc3NDUsMzc3NDcsMzc3NDgsMzc3NTAsMzc3NTQsMzc3NTcsMzc3NTksMzc3NjAsMzc3NjEsMzc3NjIsMzc3NjgsMzc3NzAsMzc3NzEsMzc3NzMsMzc3NzUsMzc3NzgsMzc3ODEsMzc3ODQsMzc3ODcsMzc3OTAsMzc3OTMsMzc3OTUsMzc3OTYsMzc3OTgsMzc4MDAsMzc4MDMsMzc4MTIsMzc4MTMsMzc4MTQsMzc4MTgsMzc4MDEsMzc4MjUsMzc4MjgsMzc4MjksMzc4MzAsMzc4MzEsMzc4MzMsMzc4MzQsMzc4MzUsMzc4MzYsMzc4MzcsMzc4NDMsMzc4NDksMzc4NTIsMzc4NTQsMzc4NTUsMzc4NTgsMzc4NjIsMzc4NjMsMzc4ODEsMzc4NzksMzc4ODAsMzc4ODIsMzc4ODMsMzc4ODUsMzc4ODksMzc4OTAsMzc4OTIsMzc4OTYsMzc4OTcsMzc5MDEsMzc5MDIsMzc5MDMsMzc5MDksMzc5MTAsMzc5MTEsMzc5MTksMzc5MzQsMzc5MzUsMzc5MzcsMzc5MzgsMzc5MzksMzc5NDAsMzc5NDcsMzc5NTEsMzc5NDksMzc5NTUsMzc5NTcsMzc5NjAsMzc5NjIsMzc5NjQsMzc5NzMsMzc5NzcsMzc5ODAsMzc5ODMsMzc5ODUsMzc5ODcsMzc5OTIsMzc5OTUsMzc5OTcsMzc5OTgsMzc5OTksMzgwMDEsMzgwMDIsMzgwMjAsMzgwMTksMzgyNjQsMzgyNjUsMzgyNzAsMzgyNzYsMzgyODAsMzgyODQsMzgyODUsMzgyODYsMzgzMDEsMzgzMDIsMzgzMDMsMzgzMDUsMzgzMTAsMzgzMTMsMzgzMTUsMzgzMTYsMzgzMjQsMzgzMjYsMzgzMzAsMzgzMzMsMzgzMzUsMzgzNDIsMzgzNDQsMzgzNDUsMzgzNDcsMzgzNTIsMzgzNTMsMzgzNTQsMzgzNTUsMzgzNjEsMzgzNjIsMzgzNjUsMzgzNjYsMzgzNjcsMzgzNjgsMzgzNzIsMzgzNzQsMzg0MjksMzg0MzAsMzg0MzQsMzg0MzYsMzg0MzcsMzg0MzgsMzg0NDQsMzg0NDksMzg0NTEsMzg0NTUsMzg0NTYsMzg0NTcsMzg0NTgsMzg0NjAsMzg0NjEsMzg0NjUsMzg0ODIsMzg0ODQsMzg0ODYsMzg0ODcsMzg0ODgsMzg0OTcsMzg1MTAsMzg1MTYsMzg1MjMsMzg1MjQsMzg1MjYsMzg1MjcsMzg1MjksMzg1MzAsMzg1MzEsMzg1MzIsMzg1MzcsMzg1NDUsMzg1NTAsMzg1NTQsMzg1NTcsMzg1NTksMzg1NjQsMzg1NjUsMzg1NjYsMzg1NjksMzg1NzQsMzg1NzUsMzg1NzksMzg1ODYsMzg2MDIsMzg2MTAsMjM5ODYsMzg2MTYsMzg2MTgsMzg2MjEsMzg2MjIsMzg2MjMsMzg2MzMsMzg2MzksMzg2NDEsMzg2NTAsMzg2NTgsMzg2NTksMzg2NjEsMzg2NjUsMzg2ODIsMzg2ODMsMzg2ODUsMzg2ODksMzg2OTAsMzg2OTEsMzg2OTYsMzg3MDUsMzg3MDcsMzg3MjEsMzg3MjMsMzg3MzAsMzg3MzQsMzg3MzUsMzg3NDEsMzg3NDMsMzg3NDQsMzg3NDYsMzg3NDcsMzg3NTUsMzg3NTksMzg3NjIsMzg3NjYsMzg3NzEsMzg3NzQsMzg3NzUsMzg3NzYsMzg3NzksMzg3ODEsMzg3ODMsMzg3ODQsMzg3OTMsMzg4MDUsMzg4MDYsMzg4MDcsMzg4MDksMzg4MTAsMzg4MTQsMzg4MTUsMzg4MTgsMzg4MjgsMzg4MzAsMzg4MzMsMzg4MzQsMzg4MzcsMzg4MzgsMzg4NDAsMzg4NDEsMzg4NDIsMzg4NDQsMzg4NDYsMzg4NDcsMzg4NDksMzg4NTIsMzg4NTMsMzg4NTUsMzg4NTcsMzg4NTgsMzg4NjAsMzg4NjEsMzg4NjIsMzg4NjQsMzg4NjUsMzg4NjgsMzg4NzEsMzg4NzIsMzg4NzMsMzg4NzcsMzg4NzgsMzg4ODAsMzg4NzUsMzg4ODEsMzg4ODQsMzg4OTUsMzg4OTcsMzg5MDAsMzg5MDMsMzg5MDQsMzg5MDYsMzg5MTksMzg5MjIsMzg5MzcsMzg5MjUsMzg5MjYsMzg5MzIsMzg5MzQsMzg5NDAsMzg5NDIsMzg5NDQsMzg5NDcsMzg5NTAsMzg5NTUsMzg5NTgsMzg5NTksMzg5NjAsMzg5NjIsMzg5NjMsMzg5NjUsMzg5NDksMzg5NzQsMzg5ODAsMzg5ODMsMzg5ODYsMzg5OTMsMzg5OTQsMzg5OTUsMzg5OTgsMzg5OTksMzkwMDEsMzkwMDIsMzkwMTAsMzkwMTEsMzkwMTMsMzkwMTQsMzkwMTgsMzkwMjAsMzkwODMsMzkwODUsMzkwODYsMzkwODgsMzkwOTIsMzkwOTUsMzkwOTYsMzkwOTgsMzkwOTksMzkxMDMsMzkxMDYsMzkxMDksMzkxMTIsMzkxMTYsMzkxMzcsMzkxMzksMzkxNDEsMzkxNDIsMzkxNDMsMzkxNDYsMzkxNTUsMzkxNTgsMzkxNzAsMzkxNzUsMzkxNzYsMzkxODUsMzkxODksMzkxOTAsMzkxOTEsMzkxOTQsMzkxOTUsMzkxOTYsMzkxOTksMzkyMDIsMzkyMDYsMzkyMDcsMzkyMTEsMzkyMTcsMzkyMTgsMzkyMTksMzkyMjAsMzkyMjEsMzkyMjUsMzkyMjYsMzkyMjcsMzkyMjgsMzkyMzIsMzkyMzMsMzkyMzgsMzkyMzksMzkyNDAsMzkyNDUsMzkyNDYsMzkyNTIsMzkyNTYsMzkyNTcsMzkyNTksMzkyNjAsMzkyNjIsMzkyNjMsMzkyNjQsMzkzMjMsMzkzMjUsMzkzMjcsMzkzMzQsMzkzNDQsMzkzNDUsMzkzNDYsMzkzNDksMzkzNTMsMzkzNTQsMzkzNTcsMzkzNTksMzkzNjMsMzkzNjksMzkzNzksMzkzODAsMzkzODUsMzkzODYsMzkzODgsMzkzOTAsMzkzOTksMzk0MDIsMzk0MDMsMzk0MDQsMzk0MDgsMzk0MTIsMzk0MTMsMzk0MTcsMzk0MjEsMzk0MjIsMzk0MjYsMzk0MjcsMzk0MjgsMzk0MzUsMzk0MzYsMzk0NDAsMzk0NDEsMzk0NDYsMzk0NTQsMzk0NTYsMzk0NTgsMzk0NTksMzk0NjAsMzk0NjMsMzk0NjksMzk0NzAsMzk0NzUsMzk0NzcsMzk0NzgsMzk0ODAsMzk0OTUsMzk0ODksMzk0OTIsMzk0OTgsMzk0OTksMzk1MDAsMzk1MDIsMzk1MDUsMzk1MDgsMzk1MTAsMzk1MTcsMzk1OTQsMzk1OTYsMzk1OTgsMzk1OTksMzk2MDIsMzk2MDQsMzk2MDUsMzk2MDYsMzk2MDksMzk2MTEsMzk2MTQsMzk2MTUsMzk2MTcsMzk2MTksMzk2MjIsMzk2MjQsMzk2MzAsMzk2MzIsMzk2MzQsMzk2MzcsMzk2MzgsMzk2MzksMzk2NDMsMzk2NDQsMzk2NDgsMzk2NTIsMzk2NTMsMzk2NTUsMzk2NTcsMzk2NjAsMzk2NjYsMzk2NjcsMzk2NjksMzk2NzMsMzk2NzQsMzk2NzcsMzk2NzksMzk2ODAsMzk2ODEsMzk2ODIsMzk2ODMsMzk2ODQsMzk2ODUsMzk2ODgsMzk2ODksMzk2OTEsMzk2OTIsMzk2OTMsMzk2OTQsMzk2OTYsMzk2OTgsMzk3MDIsMzk3MDUsMzk3MDcsMzk3MDgsMzk3MTIsMzk3MTgsMzk3MjMsMzk3MjUsMzk3MzEsMzk3MzIsMzk3MzMsMzk3MzUsMzk3MzcsMzk3MzgsMzk3NDEsMzk3NTIsMzk3NTUsMzk3NTYsMzk3NjUsMzk3NjYsMzk3NjcsMzk3NzEsMzk3NzQsMzk3NzcsMzk3NzksMzk3ODEsMzk3ODIsMzk3ODQsMzk3ODYsMzk3ODcsMzk3ODgsMzk3ODksMzk3OTAsMzk3OTUsMzk3OTcsMzk3OTksMzk4MDAsMzk4MDEsMzk4MDcsMzk4MDgsMzk4MTIsMzk4MTMsMzk4MTQsMzk4MTUsMzk4MTcsMzk4MTgsMzk4MTksMzk4MjEsMzk4MjMsMzk4MjQsMzk4MjgsMzk4MzQsMzk4MzcsMzk4MzgsMzk4NDYsMzk4NDcsMzk4NDksMzk4NTIsMzk4NTYsMzk4NTcsMzk4NTgsMzk4NjMsMzk4NjQsMzk4NjcsMzk4NjgsMzk4NzAsMzk4NzEsMzk4NzMsMzk4NzksMzk4ODAsMzk4ODYsMzk4ODgsMzk4OTUsMzk4OTYsMzk5MDEsMzk5MDMsMzk5MDksMzk5MTEsMzk5MTQsMzk5MTUsMzk5MTksMzk5MjMsMzk5MjcsMzk5MjgsMzk5MjksMzk5MzAsMzk5MzMsMzk5MzUsMzk5MzYsMzk5MzgsMzk5NDcsMzk5NTEsMzk5NTMsMzk5NTgsMzk5NjAsMzk5NjEsMzk5NjIsMzk5NjQsMzk5NjYsMzk5NzAsMzk5NzEsMzk5NzQsMzk5NzUsMzk5NzYsMzk5NzcsMzk5NzgsMzk5ODUsMzk5ODksMzk5OTAsMzk5OTEsMzk5OTcsNDAwMDEsNDAwMDMsNDAwMDQsNDAwMDUsNDAwMDksNDAwMTAsNDAwMTQsNDAwMTUsNDAwMTYsNDAwMTksNDAwMjAsNDAwMjIsNDAwMjQsNDAwMjcsNDAwMjksNDAwMzAsNDAwMzEsNDAwMzUsNDAwNDEsNDAwNDIsNDAwMjgsNDAwNDMsNDAwNDAsNDAwNDYsNDAwNDgsNDAwNTAsNDAwNTMsNDAwNTUsNDAwNTksNDAxNjYsNDAxNzgsNDAxODMsNDAxODUsNDAyMDMsNDAxOTQsNDAyMDksNDAyMTUsNDAyMTYsNDAyMjAsNDAyMjEsNDAyMjIsNDAyMzksNDAyNDAsNDAyNDIsNDAyNDMsNDAyNDQsNDAyNTAsNDAyNTIsNDAyNjEsNDAyNTMsNDAyNTgsNDAyNTksNDAyNjMsNDAyNjYsNDAyNzUsNDAyNzYsNDAyODcsNDAyOTEsNDAyOTAsNDAyOTMsNDAyOTcsNDAyOTgsNDAyOTksNDAzMDQsNDAzMTAsNDAzMTEsNDAzMTUsNDAzMTYsNDAzMTgsNDAzMjMsNDAzMjQsNDAzMjYsNDAzMzAsNDAzMzMsNDAzMzQsNDAzMzgsNDAzMzksNDAzNDEsNDAzNDIsNDAzNDMsNDAzNDQsNDAzNTMsNDAzNjIsNDAzNjQsNDAzNjYsNDAzNjksNDAzNzMsNDAzNzcsNDAzODAsNDAzODMsNDAzODcsNDAzOTEsNDAzOTMsNDAzOTQsNDA0MDQsNDA0MDUsNDA0MDYsNDA0MDcsNDA0MTAsNDA0MTQsNDA0MTUsNDA0MTYsNDA0MjEsNDA0MjMsNDA0MjUsNDA0MjcsNDA0MzAsNDA0MzIsNDA0MzUsNDA0MzYsNDA0NDYsNDA0NTgsNDA0NTAsNDA0NTUsNDA0NjIsNDA0NjQsNDA0NjUsNDA0NjYsNDA0NjksNDA0NzAsNDA0NzMsNDA0NzYsNDA0NzcsNDA1NzAsNDA1NzEsNDA1NzIsNDA1NzYsNDA1NzgsNDA1NzksNDA1ODAsNDA1ODEsNDA1ODMsNDA1OTAsNDA1OTEsNDA1OTgsNDA2MDAsNDA2MDMsNDA2MDYsNDA2MTIsNDA2MTYsNDA2MjAsNDA2MjIsNDA2MjMsNDA2MjQsNDA2MjcsNDA2MjgsNDA2MjksNDA2NDYsNDA2NDgsNDA2NTEsNDA2NjEsNDA2NzEsNDA2NzYsNDA2NzksNDA2ODQsNDA2ODUsNDA2ODYsNDA2ODgsNDA2ODksNDA2OTAsNDA2OTMsNDA2OTYsNDA3MDMsNDA3MDYsNDA3MDcsNDA3MTMsNDA3MTksNDA3MjAsNDA3MjEsNDA3MjIsNDA3MjQsNDA3MjYsNDA3MjcsNDA3MjksNDA3MzAsNDA3MzEsNDA3MzUsNDA3MzgsNDA3NDIsNDA3NDYsNDA3NDcsNDA3NTEsNDA3NTMsNDA3NTQsNDA3NTYsNDA3NTksNDA3NjEsNDA3NjIsNDA3NjQsNDA3NjUsNDA3NjcsNDA3NjksNDA3NzEsNDA3NzIsNDA3NzMsNDA3NzQsNDA3NzUsNDA3ODcsNDA3ODksNDA3OTAsNDA3OTEsNDA3OTIsNDA3OTQsNDA3OTcsNDA3OTgsNDA4MDgsNDA4MDksNDA4MTMsNDA4MTQsNDA4MTUsNDA4MTYsNDA4MTcsNDA4MTksNDA4MjEsNDA4MjYsNDA4MjksNDA4NDcsNDA4NDgsNDA4NDksNDA4NTAsNDA4NTIsNDA4NTQsNDA4NTUsNDA4NjIsNDA4NjUsNDA4NjYsNDA4NjcsNDA4NjksbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsXSxcbiAgXCJpYm04NjZcIjpbMTA0MCwxMDQxLDEwNDIsMTA0MywxMDQ0LDEwNDUsMTA0NiwxMDQ3LDEwNDgsMTA0OSwxMDUwLDEwNTEsMTA1MiwxMDUzLDEwNTQsMTA1NSwxMDU2LDEwNTcsMTA1OCwxMDU5LDEwNjAsMTA2MSwxMDYyLDEwNjMsMTA2NCwxMDY1LDEwNjYsMTA2NywxMDY4LDEwNjksMTA3MCwxMDcxLDEwNzIsMTA3MywxMDc0LDEwNzUsMTA3NiwxMDc3LDEwNzgsMTA3OSwxMDgwLDEwODEsMTA4MiwxMDgzLDEwODQsMTA4NSwxMDg2LDEwODcsOTYxNyw5NjE4LDk2MTksOTQ3NCw5NTA4LDk1NjksOTU3MCw5NTU4LDk1NTcsOTU3MSw5NTUzLDk1NTksOTU2NSw5NTY0LDk1NjMsOTQ4OCw5NDkyLDk1MjQsOTUxNiw5NTAwLDk0NzIsOTUzMiw5NTY2LDk1NjcsOTU2Miw5NTU2LDk1NzcsOTU3NCw5NTY4LDk1NTIsOTU4MCw5NTc1LDk1NzYsOTU3Miw5NTczLDk1NjEsOTU2MCw5NTU0LDk1NTUsOTU3OSw5NTc4LDk0OTYsOTQ4NCw5NjA4LDk2MDQsOTYxMiw5NjE2LDk2MDAsMTA4OCwxMDg5LDEwOTAsMTA5MSwxMDkyLDEwOTMsMTA5NCwxMDk1LDEwOTYsMTA5NywxMDk4LDEwOTksMTEwMCwxMTAxLDExMDIsMTEwMywxMDI1LDExMDUsMTAyOCwxMTA4LDEwMzEsMTExMSwxMDM4LDExMTgsMTc2LDg3MjksMTgzLDg3MzAsODQ3MCwxNjQsOTYzMiwxNjBdLFxuICBcImlzby04ODU5LTJcIjpbMTI4LDEyOSwxMzAsMTMxLDEzMiwxMzMsMTM0LDEzNSwxMzYsMTM3LDEzOCwxMzksMTQwLDE0MSwxNDIsMTQzLDE0NCwxNDUsMTQ2LDE0NywxNDgsMTQ5LDE1MCwxNTEsMTUyLDE1MywxNTQsMTU1LDE1NiwxNTcsMTU4LDE1OSwxNjAsMjYwLDcyOCwzMjEsMTY0LDMxNywzNDYsMTY3LDE2OCwzNTIsMzUwLDM1NiwzNzcsMTczLDM4MSwzNzksMTc2LDI2MSw3MzEsMzIyLDE4MCwzMTgsMzQ3LDcxMSwxODQsMzUzLDM1MSwzNTcsMzc4LDczMywzODIsMzgwLDM0MCwxOTMsMTk0LDI1OCwxOTYsMzEzLDI2MiwxOTksMjY4LDIwMSwyODAsMjAzLDI4MiwyMDUsMjA2LDI3MCwyNzIsMzIzLDMyNywyMTEsMjEyLDMzNiwyMTQsMjE1LDM0NCwzNjYsMjE4LDM2OCwyMjAsMjIxLDM1NCwyMjMsMzQxLDIyNSwyMjYsMjU5LDIyOCwzMTQsMjYzLDIzMSwyNjksMjMzLDI4MSwyMzUsMjgzLDIzNywyMzgsMjcxLDI3MywzMjQsMzI4LDI0MywyNDQsMzM3LDI0NiwyNDcsMzQ1LDM2NywyNTAsMzY5LDI1MiwyNTMsMzU1LDcyOV0sXG4gIFwiaXNvLTg4NTktM1wiOlsxMjgsMTI5LDEzMCwxMzEsMTMyLDEzMywxMzQsMTM1LDEzNiwxMzcsMTM4LDEzOSwxNDAsMTQxLDE0MiwxNDMsMTQ0LDE0NSwxNDYsMTQ3LDE0OCwxNDksMTUwLDE1MSwxNTIsMTUzLDE1NCwxNTUsMTU2LDE1NywxNTgsMTU5LDE2MCwyOTQsNzI4LDE2MywxNjQsbnVsbCwyOTIsMTY3LDE2OCwzMDQsMzUwLDI4NiwzMDgsMTczLG51bGwsMzc5LDE3NiwyOTUsMTc4LDE3OSwxODAsMTgxLDI5MywxODMsMTg0LDMwNSwzNTEsMjg3LDMwOSwxODksbnVsbCwzODAsMTkyLDE5MywxOTQsbnVsbCwxOTYsMjY2LDI2NCwxOTksMjAwLDIwMSwyMDIsMjAzLDIwNCwyMDUsMjA2LDIwNyxudWxsLDIwOSwyMTAsMjExLDIxMiwyODgsMjE0LDIxNSwyODQsMjE3LDIxOCwyMTksMjIwLDM2NCwzNDgsMjIzLDIyNCwyMjUsMjI2LG51bGwsMjI4LDI2NywyNjUsMjMxLDIzMiwyMzMsMjM0LDIzNSwyMzYsMjM3LDIzOCwyMzksbnVsbCwyNDEsMjQyLDI0MywyNDQsMjg5LDI0NiwyNDcsMjg1LDI0OSwyNTAsMjUxLDI1MiwzNjUsMzQ5LDcyOV0sXG4gIFwiaXNvLTg4NTktNFwiOlsxMjgsMTI5LDEzMCwxMzEsMTMyLDEzMywxMzQsMTM1LDEzNiwxMzcsMTM4LDEzOSwxNDAsMTQxLDE0MiwxNDMsMTQ0LDE0NSwxNDYsMTQ3LDE0OCwxNDksMTUwLDE1MSwxNTIsMTUzLDE1NCwxNTUsMTU2LDE1NywxNTgsMTU5LDE2MCwyNjAsMzEyLDM0MiwxNjQsMjk2LDMxNSwxNjcsMTY4LDM1MiwyNzQsMjkwLDM1OCwxNzMsMzgxLDE3NSwxNzYsMjYxLDczMSwzNDMsMTgwLDI5NywzMTYsNzExLDE4NCwzNTMsMjc1LDI5MSwzNTksMzMwLDM4MiwzMzEsMjU2LDE5MywxOTQsMTk1LDE5NiwxOTcsMTk4LDMwMiwyNjgsMjAxLDI4MCwyMDMsMjc4LDIwNSwyMDYsMjk4LDI3MiwzMjUsMzMyLDMxMCwyMTIsMjEzLDIxNCwyMTUsMjE2LDM3MCwyMTgsMjE5LDIyMCwzNjAsMzYyLDIyMywyNTcsMjI1LDIyNiwyMjcsMjI4LDIyOSwyMzAsMzAzLDI2OSwyMzMsMjgxLDIzNSwyNzksMjM3LDIzOCwyOTksMjczLDMyNiwzMzMsMzExLDI0NCwyNDUsMjQ2LDI0NywyNDgsMzcxLDI1MCwyNTEsMjUyLDM2MSwzNjMsNzI5XSxcbiAgXCJpc28tODg1OS01XCI6WzEyOCwxMjksMTMwLDEzMSwxMzIsMTMzLDEzNCwxMzUsMTM2LDEzNywxMzgsMTM5LDE0MCwxNDEsMTQyLDE0MywxNDQsMTQ1LDE0NiwxNDcsMTQ4LDE0OSwxNTAsMTUxLDE1MiwxNTMsMTU0LDE1NSwxNTYsMTU3LDE1OCwxNTksMTYwLDEwMjUsMTAyNiwxMDI3LDEwMjgsMTAyOSwxMDMwLDEwMzEsMTAzMiwxMDMzLDEwMzQsMTAzNSwxMDM2LDE3MywxMDM4LDEwMzksMTA0MCwxMDQxLDEwNDIsMTA0MywxMDQ0LDEwNDUsMTA0NiwxMDQ3LDEwNDgsMTA0OSwxMDUwLDEwNTEsMTA1MiwxMDUzLDEwNTQsMTA1NSwxMDU2LDEwNTcsMTA1OCwxMDU5LDEwNjAsMTA2MSwxMDYyLDEwNjMsMTA2NCwxMDY1LDEwNjYsMTA2NywxMDY4LDEwNjksMTA3MCwxMDcxLDEwNzIsMTA3MywxMDc0LDEwNzUsMTA3NiwxMDc3LDEwNzgsMTA3OSwxMDgwLDEwODEsMTA4MiwxMDgzLDEwODQsMTA4NSwxMDg2LDEwODcsMTA4OCwxMDg5LDEwOTAsMTA5MSwxMDkyLDEwOTMsMTA5NCwxMDk1LDEwOTYsMTA5NywxMDk4LDEwOTksMTEwMCwxMTAxLDExMDIsMTEwMyw4NDcwLDExMDUsMTEwNiwxMTA3LDExMDgsMTEwOSwxMTEwLDExMTEsMTExMiwxMTEzLDExMTQsMTExNSwxMTE2LDE2NywxMTE4LDExMTldLFxuICBcImlzby04ODU5LTZcIjpbMTI4LDEyOSwxMzAsMTMxLDEzMiwxMzMsMTM0LDEzNSwxMzYsMTM3LDEzOCwxMzksMTQwLDE0MSwxNDIsMTQzLDE0NCwxNDUsMTQ2LDE0NywxNDgsMTQ5LDE1MCwxNTEsMTUyLDE1MywxNTQsMTU1LDE1NiwxNTcsMTU4LDE1OSwxNjAsbnVsbCxudWxsLG51bGwsMTY0LG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsMTU0OCwxNzMsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCwxNTYzLG51bGwsbnVsbCxudWxsLDE1NjcsbnVsbCwxNTY5LDE1NzAsMTU3MSwxNTcyLDE1NzMsMTU3NCwxNTc1LDE1NzYsMTU3NywxNTc4LDE1NzksMTU4MCwxNTgxLDE1ODIsMTU4MywxNTg0LDE1ODUsMTU4NiwxNTg3LDE1ODgsMTU4OSwxNTkwLDE1OTEsMTU5MiwxNTkzLDE1OTQsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDE2MDAsMTYwMSwxNjAyLDE2MDMsMTYwNCwxNjA1LDE2MDYsMTYwNywxNjA4LDE2MDksMTYxMCwxNjExLDE2MTIsMTYxMywxNjE0LDE2MTUsMTYxNiwxNjE3LDE2MTgsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbF0sXG4gIFwiaXNvLTg4NTktN1wiOlsxMjgsMTI5LDEzMCwxMzEsMTMyLDEzMywxMzQsMTM1LDEzNiwxMzcsMTM4LDEzOSwxNDAsMTQxLDE0MiwxNDMsMTQ0LDE0NSwxNDYsMTQ3LDE0OCwxNDksMTUwLDE1MSwxNTIsMTUzLDE1NCwxNTUsMTU2LDE1NywxNTgsMTU5LDE2MCw4MjE2LDgyMTcsMTYzLDgzNjQsODM2NywxNjYsMTY3LDE2OCwxNjksODkwLDE3MSwxNzIsMTczLG51bGwsODIxMywxNzYsMTc3LDE3OCwxNzksOTAwLDkwMSw5MDIsMTgzLDkwNCw5MDUsOTA2LDE4Nyw5MDgsMTg5LDkxMCw5MTEsOTEyLDkxMyw5MTQsOTE1LDkxNiw5MTcsOTE4LDkxOSw5MjAsOTIxLDkyMiw5MjMsOTI0LDkyNSw5MjYsOTI3LDkyOCw5MjksbnVsbCw5MzEsOTMyLDkzMyw5MzQsOTM1LDkzNiw5MzcsOTM4LDkzOSw5NDAsOTQxLDk0Miw5NDMsOTQ0LDk0NSw5NDYsOTQ3LDk0OCw5NDksOTUwLDk1MSw5NTIsOTUzLDk1NCw5NTUsOTU2LDk1Nyw5NTgsOTU5LDk2MCw5NjEsOTYyLDk2Myw5NjQsOTY1LDk2Niw5NjcsOTY4LDk2OSw5NzAsOTcxLDk3Miw5NzMsOTc0LG51bGxdLFxuICBcImlzby04ODU5LThcIjpbMTI4LDEyOSwxMzAsMTMxLDEzMiwxMzMsMTM0LDEzNSwxMzYsMTM3LDEzOCwxMzksMTQwLDE0MSwxNDIsMTQzLDE0NCwxNDUsMTQ2LDE0NywxNDgsMTQ5LDE1MCwxNTEsMTUyLDE1MywxNTQsMTU1LDE1NiwxNTcsMTU4LDE1OSwxNjAsbnVsbCwxNjIsMTYzLDE2NCwxNjUsMTY2LDE2NywxNjgsMTY5LDIxNSwxNzEsMTcyLDE3MywxNzQsMTc1LDE3NiwxNzcsMTc4LDE3OSwxODAsMTgxLDE4MiwxODMsMTg0LDE4NSwyNDcsMTg3LDE4OCwxODksMTkwLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCw4MjE1LDE0ODgsMTQ4OSwxNDkwLDE0OTEsMTQ5MiwxNDkzLDE0OTQsMTQ5NSwxNDk2LDE0OTcsMTQ5OCwxNDk5LDE1MDAsMTUwMSwxNTAyLDE1MDMsMTUwNCwxNTA1LDE1MDYsMTUwNywxNTA4LDE1MDksMTUxMCwxNTExLDE1MTIsMTUxMywxNTE0LG51bGwsbnVsbCw4MjA2LDgyMDcsbnVsbF0sXG4gIFwiaXNvLTg4NTktMTBcIjpbMTI4LDEyOSwxMzAsMTMxLDEzMiwxMzMsMTM0LDEzNSwxMzYsMTM3LDEzOCwxMzksMTQwLDE0MSwxNDIsMTQzLDE0NCwxNDUsMTQ2LDE0NywxNDgsMTQ5LDE1MCwxNTEsMTUyLDE1MywxNTQsMTU1LDE1NiwxNTcsMTU4LDE1OSwxNjAsMjYwLDI3NCwyOTAsMjk4LDI5NiwzMTAsMTY3LDMxNSwyNzIsMzUyLDM1OCwzODEsMTczLDM2MiwzMzAsMTc2LDI2MSwyNzUsMjkxLDI5OSwyOTcsMzExLDE4MywzMTYsMjczLDM1MywzNTksMzgyLDgyMTMsMzYzLDMzMSwyNTYsMTkzLDE5NCwxOTUsMTk2LDE5NywxOTgsMzAyLDI2OCwyMDEsMjgwLDIwMywyNzgsMjA1LDIwNiwyMDcsMjA4LDMyNSwzMzIsMjExLDIxMiwyMTMsMjE0LDM2MCwyMTYsMzcwLDIxOCwyMTksMjIwLDIyMSwyMjIsMjIzLDI1NywyMjUsMjI2LDIyNywyMjgsMjI5LDIzMCwzMDMsMjY5LDIzMywyODEsMjM1LDI3OSwyMzcsMjM4LDIzOSwyNDAsMzI2LDMzMywyNDMsMjQ0LDI0NSwyNDYsMzYxLDI0OCwzNzEsMjUwLDI1MSwyNTIsMjUzLDI1NCwzMTJdLFxuICBcImlzby04ODU5LTEzXCI6WzEyOCwxMjksMTMwLDEzMSwxMzIsMTMzLDEzNCwxMzUsMTM2LDEzNywxMzgsMTM5LDE0MCwxNDEsMTQyLDE0MywxNDQsMTQ1LDE0NiwxNDcsMTQ4LDE0OSwxNTAsMTUxLDE1MiwxNTMsMTU0LDE1NSwxNTYsMTU3LDE1OCwxNTksMTYwLDgyMjEsMTYyLDE2MywxNjQsODIyMiwxNjYsMTY3LDIxNiwxNjksMzQyLDE3MSwxNzIsMTczLDE3NCwxOTgsMTc2LDE3NywxNzgsMTc5LDgyMjAsMTgxLDE4MiwxODMsMjQ4LDE4NSwzNDMsMTg3LDE4OCwxODksMTkwLDIzMCwyNjAsMzAyLDI1NiwyNjIsMTk2LDE5NywyODAsMjc0LDI2OCwyMDEsMzc3LDI3OCwyOTAsMzEwLDI5OCwzMTUsMzUyLDMyMywzMjUsMjExLDMzMiwyMTMsMjE0LDIxNSwzNzAsMzIxLDM0NiwzNjIsMjIwLDM3OSwzODEsMjIzLDI2MSwzMDMsMjU3LDI2MywyMjgsMjI5LDI4MSwyNzUsMjY5LDIzMywzNzgsMjc5LDI5MSwzMTEsMjk5LDMxNiwzNTMsMzI0LDMyNiwyNDMsMzMzLDI0NSwyNDYsMjQ3LDM3MSwzMjIsMzQ3LDM2MywyNTIsMzgwLDM4Miw4MjE3XSxcbiAgXCJpc28tODg1OS0xNFwiOlsxMjgsMTI5LDEzMCwxMzEsMTMyLDEzMywxMzQsMTM1LDEzNiwxMzcsMTM4LDEzOSwxNDAsMTQxLDE0MiwxNDMsMTQ0LDE0NSwxNDYsMTQ3LDE0OCwxNDksMTUwLDE1MSwxNTIsMTUzLDE1NCwxNTUsMTU2LDE1NywxNTgsMTU5LDE2MCw3NjgyLDc2ODMsMTYzLDI2NiwyNjcsNzY5MCwxNjcsNzgwOCwxNjksNzgxMCw3NjkxLDc5MjIsMTczLDE3NCwzNzYsNzcxMCw3NzExLDI4OCwyODksNzc0NCw3NzQ1LDE4Miw3NzY2LDc4MDksNzc2Nyw3ODExLDc3NzYsNzkyMyw3ODEyLDc4MTMsNzc3NywxOTIsMTkzLDE5NCwxOTUsMTk2LDE5NywxOTgsMTk5LDIwMCwyMDEsMjAyLDIwMywyMDQsMjA1LDIwNiwyMDcsMzcyLDIwOSwyMTAsMjExLDIxMiwyMTMsMjE0LDc3ODYsMjE2LDIxNywyMTgsMjE5LDIyMCwyMjEsMzc0LDIyMywyMjQsMjI1LDIyNiwyMjcsMjI4LDIyOSwyMzAsMjMxLDIzMiwyMzMsMjM0LDIzNSwyMzYsMjM3LDIzOCwyMzksMzczLDI0MSwyNDIsMjQzLDI0NCwyNDUsMjQ2LDc3ODcsMjQ4LDI0OSwyNTAsMjUxLDI1MiwyNTMsMzc1LDI1NV0sXG4gIFwiaXNvLTg4NTktMTVcIjpbMTI4LDEyOSwxMzAsMTMxLDEzMiwxMzMsMTM0LDEzNSwxMzYsMTM3LDEzOCwxMzksMTQwLDE0MSwxNDIsMTQzLDE0NCwxNDUsMTQ2LDE0NywxNDgsMTQ5LDE1MCwxNTEsMTUyLDE1MywxNTQsMTU1LDE1NiwxNTcsMTU4LDE1OSwxNjAsMTYxLDE2MiwxNjMsODM2NCwxNjUsMzUyLDE2NywzNTMsMTY5LDE3MCwxNzEsMTcyLDE3MywxNzQsMTc1LDE3NiwxNzcsMTc4LDE3OSwzODEsMTgxLDE4MiwxODMsMzgyLDE4NSwxODYsMTg3LDMzOCwzMzksMzc2LDE5MSwxOTIsMTkzLDE5NCwxOTUsMTk2LDE5NywxOTgsMTk5LDIwMCwyMDEsMjAyLDIwMywyMDQsMjA1LDIwNiwyMDcsMjA4LDIwOSwyMTAsMjExLDIxMiwyMTMsMjE0LDIxNSwyMTYsMjE3LDIxOCwyMTksMjIwLDIyMSwyMjIsMjIzLDIyNCwyMjUsMjI2LDIyNywyMjgsMjI5LDIzMCwyMzEsMjMyLDIzMywyMzQsMjM1LDIzNiwyMzcsMjM4LDIzOSwyNDAsMjQxLDI0MiwyNDMsMjQ0LDI0NSwyNDYsMjQ3LDI0OCwyNDksMjUwLDI1MSwyNTIsMjUzLDI1NCwyNTVdLFxuICBcImlzby04ODU5LTE2XCI6WzEyOCwxMjksMTMwLDEzMSwxMzIsMTMzLDEzNCwxMzUsMTM2LDEzNywxMzgsMTM5LDE0MCwxNDEsMTQyLDE0MywxNDQsMTQ1LDE0NiwxNDcsMTQ4LDE0OSwxNTAsMTUxLDE1MiwxNTMsMTU0LDE1NSwxNTYsMTU3LDE1OCwxNTksMTYwLDI2MCwyNjEsMzIxLDgzNjQsODIyMiwzNTIsMTY3LDM1MywxNjksNTM2LDE3MSwzNzcsMTczLDM3OCwzNzksMTc2LDE3NywyNjgsMzIyLDM4MSw4MjIxLDE4MiwxODMsMzgyLDI2OSw1MzcsMTg3LDMzOCwzMzksMzc2LDM4MCwxOTIsMTkzLDE5NCwyNTgsMTk2LDI2MiwxOTgsMTk5LDIwMCwyMDEsMjAyLDIwMywyMDQsMjA1LDIwNiwyMDcsMjcyLDMyMywyMTAsMjExLDIxMiwzMzYsMjE0LDM0NiwzNjgsMjE3LDIxOCwyMTksMjIwLDI4MCw1MzgsMjIzLDIyNCwyMjUsMjI2LDI1OSwyMjgsMjYzLDIzMCwyMzEsMjMyLDIzMywyMzQsMjM1LDIzNiwyMzcsMjM4LDIzOSwyNzMsMzI0LDI0MiwyNDMsMjQ0LDMzNywyNDYsMzQ3LDM2OSwyNDksMjUwLDI1MSwyNTIsMjgxLDUzOSwyNTVdLFxuICBcImtvaTgtclwiOls5NDcyLDk0NzQsOTQ4NCw5NDg4LDk0OTIsOTQ5Niw5NTAwLDk1MDgsOTUxNiw5NTI0LDk1MzIsOTYwMCw5NjA0LDk2MDgsOTYxMiw5NjE2LDk2MTcsOTYxOCw5NjE5LDg5OTIsOTYzMiw4NzI5LDg3MzAsODc3Niw4ODA0LDg4MDUsMTYwLDg5OTMsMTc2LDE3OCwxODMsMjQ3LDk1NTIsOTU1Myw5NTU0LDExMDUsOTU1NSw5NTU2LDk1NTcsOTU1OCw5NTU5LDk1NjAsOTU2MSw5NTYyLDk1NjMsOTU2NCw5NTY1LDk1NjYsOTU2Nyw5NTY4LDk1NjksMTAyNSw5NTcwLDk1NzEsOTU3Miw5NTczLDk1NzQsOTU3NSw5NTc2LDk1NzcsOTU3OCw5NTc5LDk1ODAsMTY5LDExMDIsMTA3MiwxMDczLDEwOTQsMTA3NiwxMDc3LDEwOTIsMTA3NSwxMDkzLDEwODAsMTA4MSwxMDgyLDEwODMsMTA4NCwxMDg1LDEwODYsMTA4NywxMTAzLDEwODgsMTA4OSwxMDkwLDEwOTEsMTA3OCwxMDc0LDExMDAsMTA5OSwxMDc5LDEwOTYsMTEwMSwxMDk3LDEwOTUsMTA5OCwxMDcwLDEwNDAsMTA0MSwxMDYyLDEwNDQsMTA0NSwxMDYwLDEwNDMsMTA2MSwxMDQ4LDEwNDksMTA1MCwxMDUxLDEwNTIsMTA1MywxMDU0LDEwNTUsMTA3MSwxMDU2LDEwNTcsMTA1OCwxMDU5LDEwNDYsMTA0MiwxMDY4LDEwNjcsMTA0NywxMDY0LDEwNjksMTA2NSwxMDYzLDEwNjZdLFxuICBcImtvaTgtdVwiOls5NDcyLDk0NzQsOTQ4NCw5NDg4LDk0OTIsOTQ5Niw5NTAwLDk1MDgsOTUxNiw5NTI0LDk1MzIsOTYwMCw5NjA0LDk2MDgsOTYxMiw5NjE2LDk2MTcsOTYxOCw5NjE5LDg5OTIsOTYzMiw4NzI5LDg3MzAsODc3Niw4ODA0LDg4MDUsMTYwLDg5OTMsMTc2LDE3OCwxODMsMjQ3LDk1NTIsOTU1Myw5NTU0LDExMDUsMTEwOCw5NTU2LDExMTAsMTExMSw5NTU5LDk1NjAsOTU2MSw5NTYyLDk1NjMsMTE2OSwxMTE4LDk1NjYsOTU2Nyw5NTY4LDk1NjksMTAyNSwxMDI4LDk1NzEsMTAzMCwxMDMxLDk1NzQsOTU3NSw5NTc2LDk1NzcsOTU3OCwxMTY4LDEwMzgsMTY5LDExMDIsMTA3MiwxMDczLDEwOTQsMTA3NiwxMDc3LDEwOTIsMTA3NSwxMDkzLDEwODAsMTA4MSwxMDgyLDEwODMsMTA4NCwxMDg1LDEwODYsMTA4NywxMTAzLDEwODgsMTA4OSwxMDkwLDEwOTEsMTA3OCwxMDc0LDExMDAsMTA5OSwxMDc5LDEwOTYsMTEwMSwxMDk3LDEwOTUsMTA5OCwxMDcwLDEwNDAsMTA0MSwxMDYyLDEwNDQsMTA0NSwxMDYwLDEwNDMsMTA2MSwxMDQ4LDEwNDksMTA1MCwxMDUxLDEwNTIsMTA1MywxMDU0LDEwNTUsMTA3MSwxMDU2LDEwNTcsMTA1OCwxMDU5LDEwNDYsMTA0MiwxMDY4LDEwNjcsMTA0NywxMDY0LDEwNjksMTA2NSwxMDYzLDEwNjZdLFxuICBcIm1hY2ludG9zaFwiOlsxOTYsMTk3LDE5OSwyMDEsMjA5LDIxNCwyMjAsMjI1LDIyNCwyMjYsMjI4LDIyNywyMjksMjMxLDIzMywyMzIsMjM0LDIzNSwyMzcsMjM2LDIzOCwyMzksMjQxLDI0MywyNDIsMjQ0LDI0NiwyNDUsMjUwLDI0OSwyNTEsMjUyLDgyMjQsMTc2LDE2MiwxNjMsMTY3LDgyMjYsMTgyLDIyMywxNzQsMTY5LDg0ODIsMTgwLDE2OCw4ODAwLDE5OCwyMTYsODczNCwxNzcsODgwNCw4ODA1LDE2NSwxODEsODcwNiw4NzIxLDg3MTksOTYwLDg3NDcsMTcwLDE4Niw5MzcsMjMwLDI0OCwxOTEsMTYxLDE3Miw4NzMwLDQwMiw4Nzc2LDg3MTAsMTcxLDE4Nyw4MjMwLDE2MCwxOTIsMTk1LDIxMywzMzgsMzM5LDgyMTEsODIxMiw4MjIwLDgyMjEsODIxNiw4MjE3LDI0Nyw5Njc0LDI1NSwzNzYsODI2MCw4MzY0LDgyNDksODI1MCw2NDI1Nyw2NDI1OCw4MjI1LDE4Myw4MjE4LDgyMjIsODI0MCwxOTQsMjAyLDE5MywyMDMsMjAwLDIwNSwyMDYsMjA3LDIwNCwyMTEsMjEyLDYzNzQzLDIxMCwyMTgsMjE5LDIxNywzMDUsNzEwLDczMiwxNzUsNzI4LDcyOSw3MzAsMTg0LDczMyw3MzEsNzExXSxcbiAgXCJ3aW5kb3dzLTg3NFwiOls4MzY0LDEyOSwxMzAsMTMxLDEzMiw4MjMwLDEzNCwxMzUsMTM2LDEzNywxMzgsMTM5LDE0MCwxNDEsMTQyLDE0MywxNDQsODIxNiw4MjE3LDgyMjAsODIyMSw4MjI2LDgyMTEsODIxMiwxNTIsMTUzLDE1NCwxNTUsMTU2LDE1NywxNTgsMTU5LDE2MCwzNTg1LDM1ODYsMzU4NywzNTg4LDM1ODksMzU5MCwzNTkxLDM1OTIsMzU5MywzNTk0LDM1OTUsMzU5NiwzNTk3LDM1OTgsMzU5OSwzNjAwLDM2MDEsMzYwMiwzNjAzLDM2MDQsMzYwNSwzNjA2LDM2MDcsMzYwOCwzNjA5LDM2MTAsMzYxMSwzNjEyLDM2MTMsMzYxNCwzNjE1LDM2MTYsMzYxNywzNjE4LDM2MTksMzYyMCwzNjIxLDM2MjIsMzYyMywzNjI0LDM2MjUsMzYyNiwzNjI3LDM2MjgsMzYyOSwzNjMwLDM2MzEsMzYzMiwzNjMzLDM2MzQsMzYzNSwzNjM2LDM2MzcsMzYzOCwzNjM5LDM2NDAsMzY0MSwzNjQyLG51bGwsbnVsbCxudWxsLG51bGwsMzY0NywzNjQ4LDM2NDksMzY1MCwzNjUxLDM2NTIsMzY1MywzNjU0LDM2NTUsMzY1NiwzNjU3LDM2NTgsMzY1OSwzNjYwLDM2NjEsMzY2MiwzNjYzLDM2NjQsMzY2NSwzNjY2LDM2NjcsMzY2OCwzNjY5LDM2NzAsMzY3MSwzNjcyLDM2NzMsMzY3NCwzNjc1LG51bGwsbnVsbCxudWxsLG51bGxdLFxuICBcIndpbmRvd3MtMTI1MFwiOls4MzY0LDEyOSw4MjE4LDEzMSw4MjIyLDgyMzAsODIyNCw4MjI1LDEzNiw4MjQwLDM1Miw4MjQ5LDM0NiwzNTYsMzgxLDM3NywxNDQsODIxNiw4MjE3LDgyMjAsODIyMSw4MjI2LDgyMTEsODIxMiwxNTIsODQ4MiwzNTMsODI1MCwzNDcsMzU3LDM4MiwzNzgsMTYwLDcxMSw3MjgsMzIxLDE2NCwyNjAsMTY2LDE2NywxNjgsMTY5LDM1MCwxNzEsMTcyLDE3MywxNzQsMzc5LDE3NiwxNzcsNzMxLDMyMiwxODAsMTgxLDE4MiwxODMsMTg0LDI2MSwzNTEsMTg3LDMxNyw3MzMsMzE4LDM4MCwzNDAsMTkzLDE5NCwyNTgsMTk2LDMxMywyNjIsMTk5LDI2OCwyMDEsMjgwLDIwMywyODIsMjA1LDIwNiwyNzAsMjcyLDMyMywzMjcsMjExLDIxMiwzMzYsMjE0LDIxNSwzNDQsMzY2LDIxOCwzNjgsMjIwLDIyMSwzNTQsMjIzLDM0MSwyMjUsMjI2LDI1OSwyMjgsMzE0LDI2MywyMzEsMjY5LDIzMywyODEsMjM1LDI4MywyMzcsMjM4LDI3MSwyNzMsMzI0LDMyOCwyNDMsMjQ0LDMzNywyNDYsMjQ3LDM0NSwzNjcsMjUwLDM2OSwyNTIsMjUzLDM1NSw3MjldLFxuICBcIndpbmRvd3MtMTI1MVwiOlsxMDI2LDEwMjcsODIxOCwxMTA3LDgyMjIsODIzMCw4MjI0LDgyMjUsODM2NCw4MjQwLDEwMzMsODI0OSwxMDM0LDEwMzYsMTAzNSwxMDM5LDExMDYsODIxNiw4MjE3LDgyMjAsODIyMSw4MjI2LDgyMTEsODIxMiwxNTIsODQ4MiwxMTEzLDgyNTAsMTExNCwxMTE2LDExMTUsMTExOSwxNjAsMTAzOCwxMTE4LDEwMzIsMTY0LDExNjgsMTY2LDE2NywxMDI1LDE2OSwxMDI4LDE3MSwxNzIsMTczLDE3NCwxMDMxLDE3NiwxNzcsMTAzMCwxMTEwLDExNjksMTgxLDE4MiwxODMsMTEwNSw4NDcwLDExMDgsMTg3LDExMTIsMTAyOSwxMTA5LDExMTEsMTA0MCwxMDQxLDEwNDIsMTA0MywxMDQ0LDEwNDUsMTA0NiwxMDQ3LDEwNDgsMTA0OSwxMDUwLDEwNTEsMTA1MiwxMDUzLDEwNTQsMTA1NSwxMDU2LDEwNTcsMTA1OCwxMDU5LDEwNjAsMTA2MSwxMDYyLDEwNjMsMTA2NCwxMDY1LDEwNjYsMTA2NywxMDY4LDEwNjksMTA3MCwxMDcxLDEwNzIsMTA3MywxMDc0LDEwNzUsMTA3NiwxMDc3LDEwNzgsMTA3OSwxMDgwLDEwODEsMTA4MiwxMDgzLDEwODQsMTA4NSwxMDg2LDEwODcsMTA4OCwxMDg5LDEwOTAsMTA5MSwxMDkyLDEwOTMsMTA5NCwxMDk1LDEwOTYsMTA5NywxMDk4LDEwOTksMTEwMCwxMTAxLDExMDIsMTEwM10sXG4gIFwid2luZG93cy0xMjUyXCI6WzgzNjQsMTI5LDgyMTgsNDAyLDgyMjIsODIzMCw4MjI0LDgyMjUsNzEwLDgyNDAsMzUyLDgyNDksMzM4LDE0MSwzODEsMTQzLDE0NCw4MjE2LDgyMTcsODIyMCw4MjIxLDgyMjYsODIxMSw4MjEyLDczMiw4NDgyLDM1Myw4MjUwLDMzOSwxNTcsMzgyLDM3NiwxNjAsMTYxLDE2MiwxNjMsMTY0LDE2NSwxNjYsMTY3LDE2OCwxNjksMTcwLDE3MSwxNzIsMTczLDE3NCwxNzUsMTc2LDE3NywxNzgsMTc5LDE4MCwxODEsMTgyLDE4MywxODQsMTg1LDE4NiwxODcsMTg4LDE4OSwxOTAsMTkxLDE5MiwxOTMsMTk0LDE5NSwxOTYsMTk3LDE5OCwxOTksMjAwLDIwMSwyMDIsMjAzLDIwNCwyMDUsMjA2LDIwNywyMDgsMjA5LDIxMCwyMTEsMjEyLDIxMywyMTQsMjE1LDIxNiwyMTcsMjE4LDIxOSwyMjAsMjIxLDIyMiwyMjMsMjI0LDIyNSwyMjYsMjI3LDIyOCwyMjksMjMwLDIzMSwyMzIsMjMzLDIzNCwyMzUsMjM2LDIzNywyMzgsMjM5LDI0MCwyNDEsMjQyLDI0MywyNDQsMjQ1LDI0NiwyNDcsMjQ4LDI0OSwyNTAsMjUxLDI1MiwyNTMsMjU0LDI1NV0sXG4gIFwid2luZG93cy0xMjUzXCI6WzgzNjQsMTI5LDgyMTgsNDAyLDgyMjIsODIzMCw4MjI0LDgyMjUsMTM2LDgyNDAsMTM4LDgyNDksMTQwLDE0MSwxNDIsMTQzLDE0NCw4MjE2LDgyMTcsODIyMCw4MjIxLDgyMjYsODIxMSw4MjEyLDE1Miw4NDgyLDE1NCw4MjUwLDE1NiwxNTcsMTU4LDE1OSwxNjAsOTAxLDkwMiwxNjMsMTY0LDE2NSwxNjYsMTY3LDE2OCwxNjksbnVsbCwxNzEsMTcyLDE3MywxNzQsODIxMywxNzYsMTc3LDE3OCwxNzksOTAwLDE4MSwxODIsMTgzLDkwNCw5MDUsOTA2LDE4Nyw5MDgsMTg5LDkxMCw5MTEsOTEyLDkxMyw5MTQsOTE1LDkxNiw5MTcsOTE4LDkxOSw5MjAsOTIxLDkyMiw5MjMsOTI0LDkyNSw5MjYsOTI3LDkyOCw5MjksbnVsbCw5MzEsOTMyLDkzMyw5MzQsOTM1LDkzNiw5MzcsOTM4LDkzOSw5NDAsOTQxLDk0Miw5NDMsOTQ0LDk0NSw5NDYsOTQ3LDk0OCw5NDksOTUwLDk1MSw5NTIsOTUzLDk1NCw5NTUsOTU2LDk1Nyw5NTgsOTU5LDk2MCw5NjEsOTYyLDk2Myw5NjQsOTY1LDk2Niw5NjcsOTY4LDk2OSw5NzAsOTcxLDk3Miw5NzMsOTc0LG51bGxdLFxuICBcIndpbmRvd3MtMTI1NFwiOls4MzY0LDEyOSw4MjE4LDQwMiw4MjIyLDgyMzAsODIyNCw4MjI1LDcxMCw4MjQwLDM1Miw4MjQ5LDMzOCwxNDEsMTQyLDE0MywxNDQsODIxNiw4MjE3LDgyMjAsODIyMSw4MjI2LDgyMTEsODIxMiw3MzIsODQ4MiwzNTMsODI1MCwzMzksMTU3LDE1OCwzNzYsMTYwLDE2MSwxNjIsMTYzLDE2NCwxNjUsMTY2LDE2NywxNjgsMTY5LDE3MCwxNzEsMTcyLDE3MywxNzQsMTc1LDE3NiwxNzcsMTc4LDE3OSwxODAsMTgxLDE4MiwxODMsMTg0LDE4NSwxODYsMTg3LDE4OCwxODksMTkwLDE5MSwxOTIsMTkzLDE5NCwxOTUsMTk2LDE5NywxOTgsMTk5LDIwMCwyMDEsMjAyLDIwMywyMDQsMjA1LDIwNiwyMDcsMjg2LDIwOSwyMTAsMjExLDIxMiwyMTMsMjE0LDIxNSwyMTYsMjE3LDIxOCwyMTksMjIwLDMwNCwzNTAsMjIzLDIyNCwyMjUsMjI2LDIyNywyMjgsMjI5LDIzMCwyMzEsMjMyLDIzMywyMzQsMjM1LDIzNiwyMzcsMjM4LDIzOSwyODcsMjQxLDI0MiwyNDMsMjQ0LDI0NSwyNDYsMjQ3LDI0OCwyNDksMjUwLDI1MSwyNTIsMzA1LDM1MSwyNTVdLFxuICBcIndpbmRvd3MtMTI1NVwiOls4MzY0LDEyOSw4MjE4LDQwMiw4MjIyLDgyMzAsODIyNCw4MjI1LDcxMCw4MjQwLDEzOCw4MjQ5LDE0MCwxNDEsMTQyLDE0MywxNDQsODIxNiw4MjE3LDgyMjAsODIyMSw4MjI2LDgyMTEsODIxMiw3MzIsODQ4MiwxNTQsODI1MCwxNTYsMTU3LDE1OCwxNTksMTYwLDE2MSwxNjIsMTYzLDgzNjIsMTY1LDE2NiwxNjcsMTY4LDE2OSwyMTUsMTcxLDE3MiwxNzMsMTc0LDE3NSwxNzYsMTc3LDE3OCwxNzksMTgwLDE4MSwxODIsMTgzLDE4NCwxODUsMjQ3LDE4NywxODgsMTg5LDE5MCwxOTEsMTQ1NiwxNDU3LDE0NTgsMTQ1OSwxNDYwLDE0NjEsMTQ2MiwxNDYzLDE0NjQsMTQ2NSwxNDY2LDE0NjcsMTQ2OCwxNDY5LDE0NzAsMTQ3MSwxNDcyLDE0NzMsMTQ3NCwxNDc1LDE1MjAsMTUyMSwxNTIyLDE1MjMsMTUyNCxudWxsLG51bGwsbnVsbCxudWxsLG51bGwsbnVsbCxudWxsLDE0ODgsMTQ4OSwxNDkwLDE0OTEsMTQ5MiwxNDkzLDE0OTQsMTQ5NSwxNDk2LDE0OTcsMTQ5OCwxNDk5LDE1MDAsMTUwMSwxNTAyLDE1MDMsMTUwNCwxNTA1LDE1MDYsMTUwNywxNTA4LDE1MDksMTUxMCwxNTExLDE1MTIsMTUxMywxNTE0LG51bGwsbnVsbCw4MjA2LDgyMDcsbnVsbF0sXG4gIFwid2luZG93cy0xMjU2XCI6WzgzNjQsMTY2Miw4MjE4LDQwMiw4MjIyLDgyMzAsODIyNCw4MjI1LDcxMCw4MjQwLDE2NTcsODI0OSwzMzgsMTY3MCwxNjg4LDE2NzIsMTcxMSw4MjE2LDgyMTcsODIyMCw4MjIxLDgyMjYsODIxMSw4MjEyLDE3MDUsODQ4MiwxNjgxLDgyNTAsMzM5LDgyMDQsODIwNSwxNzIyLDE2MCwxNTQ4LDE2MiwxNjMsMTY0LDE2NSwxNjYsMTY3LDE2OCwxNjksMTcyNiwxNzEsMTcyLDE3MywxNzQsMTc1LDE3NiwxNzcsMTc4LDE3OSwxODAsMTgxLDE4MiwxODMsMTg0LDE4NSwxNTYzLDE4NywxODgsMTg5LDE5MCwxNTY3LDE3MjksMTU2OSwxNTcwLDE1NzEsMTU3MiwxNTczLDE1NzQsMTU3NSwxNTc2LDE1NzcsMTU3OCwxNTc5LDE1ODAsMTU4MSwxNTgyLDE1ODMsMTU4NCwxNTg1LDE1ODYsMTU4NywxNTg4LDE1ODksMTU5MCwyMTUsMTU5MSwxNTkyLDE1OTMsMTU5NCwxNjAwLDE2MDEsMTYwMiwxNjAzLDIyNCwxNjA0LDIyNiwxNjA1LDE2MDYsMTYwNywxNjA4LDIzMSwyMzIsMjMzLDIzNCwyMzUsMTYwOSwxNjEwLDIzOCwyMzksMTYxMSwxNjEyLDE2MTMsMTYxNCwyNDQsMTYxNSwxNjE2LDI0NywxNjE3LDI0OSwxNjE4LDI1MSwyNTIsODIwNiw4MjA3LDE3NDZdLFxuICBcIndpbmRvd3MtMTI1N1wiOls4MzY0LDEyOSw4MjE4LDEzMSw4MjIyLDgyMzAsODIyNCw4MjI1LDEzNiw4MjQwLDEzOCw4MjQ5LDE0MCwxNjgsNzExLDE4NCwxNDQsODIxNiw4MjE3LDgyMjAsODIyMSw4MjI2LDgyMTEsODIxMiwxNTIsODQ4MiwxNTQsODI1MCwxNTYsMTc1LDczMSwxNTksMTYwLG51bGwsMTYyLDE2MywxNjQsbnVsbCwxNjYsMTY3LDIxNiwxNjksMzQyLDE3MSwxNzIsMTczLDE3NCwxOTgsMTc2LDE3NywxNzgsMTc5LDE4MCwxODEsMTgyLDE4MywyNDgsMTg1LDM0MywxODcsMTg4LDE4OSwxOTAsMjMwLDI2MCwzMDIsMjU2LDI2MiwxOTYsMTk3LDI4MCwyNzQsMjY4LDIwMSwzNzcsMjc4LDI5MCwzMTAsMjk4LDMxNSwzNTIsMzIzLDMyNSwyMTEsMzMyLDIxMywyMTQsMjE1LDM3MCwzMjEsMzQ2LDM2MiwyMjAsMzc5LDM4MSwyMjMsMjYxLDMwMywyNTcsMjYzLDIyOCwyMjksMjgxLDI3NSwyNjksMjMzLDM3OCwyNzksMjkxLDMxMSwyOTksMzE2LDM1MywzMjQsMzI2LDI0MywzMzMsMjQ1LDI0NiwyNDcsMzcxLDMyMiwzNDcsMzYzLDI1MiwzODAsMzgyLDcyOV0sXG4gIFwid2luZG93cy0xMjU4XCI6WzgzNjQsMTI5LDgyMTgsNDAyLDgyMjIsODIzMCw4MjI0LDgyMjUsNzEwLDgyNDAsMTM4LDgyNDksMzM4LDE0MSwxNDIsMTQzLDE0NCw4MjE2LDgyMTcsODIyMCw4MjIxLDgyMjYsODIxMSw4MjEyLDczMiw4NDgyLDE1NCw4MjUwLDMzOSwxNTcsMTU4LDM3NiwxNjAsMTYxLDE2MiwxNjMsMTY0LDE2NSwxNjYsMTY3LDE2OCwxNjksMTcwLDE3MSwxNzIsMTczLDE3NCwxNzUsMTc2LDE3NywxNzgsMTc5LDE4MCwxODEsMTgyLDE4MywxODQsMTg1LDE4NiwxODcsMTg4LDE4OSwxOTAsMTkxLDE5MiwxOTMsMTk0LDI1OCwxOTYsMTk3LDE5OCwxOTksMjAwLDIwMSwyMDIsMjAzLDc2OCwyMDUsMjA2LDIwNywyNzIsMjA5LDc3NywyMTEsMjEyLDQxNiwyMTQsMjE1LDIxNiwyMTcsMjE4LDIxOSwyMjAsNDMxLDc3MSwyMjMsMjI0LDIyNSwyMjYsMjU5LDIyOCwyMjksMjMwLDIzMSwyMzIsMjMzLDIzNCwyMzUsNzY5LDIzNywyMzgsMjM5LDI3MywyNDEsODAzLDI0MywyNDQsNDE3LDI0NiwyNDcsMjQ4LDI0OSwyNTAsMjUxLDI1Miw0MzIsODM2MywyNTVdLFxuICBcIngtbWFjLWN5cmlsbGljXCI6WzEwNDAsMTA0MSwxMDQyLDEwNDMsMTA0NCwxMDQ1LDEwNDYsMTA0NywxMDQ4LDEwNDksMTA1MCwxMDUxLDEwNTIsMTA1MywxMDU0LDEwNTUsMTA1NiwxMDU3LDEwNTgsMTA1OSwxMDYwLDEwNjEsMTA2MiwxMDYzLDEwNjQsMTA2NSwxMDY2LDEwNjcsMTA2OCwxMDY5LDEwNzAsMTA3MSw4MjI0LDE3NiwxMTY4LDE2MywxNjcsODIyNiwxODIsMTAzMCwxNzQsMTY5LDg0ODIsMTAyNiwxMTA2LDg4MDAsMTAyNywxMTA3LDg3MzQsMTc3LDg4MDQsODgwNSwxMTEwLDE4MSwxMTY5LDEwMzIsMTAyOCwxMTA4LDEwMzEsMTExMSwxMDMzLDExMTMsMTAzNCwxMTE0LDExMTIsMTAyOSwxNzIsODczMCw0MDIsODc3Niw4NzEwLDE3MSwxODcsODIzMCwxNjAsMTAzNSwxMTE1LDEwMzYsMTExNiwxMTA5LDgyMTEsODIxMiw4MjIwLDgyMjEsODIxNiw4MjE3LDI0Nyw4MjIyLDEwMzgsMTExOCwxMDM5LDExMTksODQ3MCwxMDI1LDExMDUsMTEwMywxMDcyLDEwNzMsMTA3NCwxMDc1LDEwNzYsMTA3NywxMDc4LDEwNzksMTA4MCwxMDgxLDEwODIsMTA4MywxMDg0LDEwODUsMTA4NiwxMDg3LDEwODgsMTA4OSwxMDkwLDEwOTEsMTA5MiwxMDkzLDEwOTQsMTA5NSwxMDk2LDEwOTcsMTA5OCwxMDk5LDExMDAsMTEwMSwxMTAyLDgzNjRdXG59O1xuXG4vLyBGb3Igc3RyaWN0IGVudmlyb25tZW50cyB3aGVyZSBgdGhpc2AgaW5zaWRlIHRoZSBnbG9iYWwgc2NvcGVcbi8vIGlzIGB1bmRlZmluZWRgLCB0YWtlIGEgcHVyZSBvYmplY3QgaW5zdGVhZFxufSh0aGlzIHx8IHt9KSk7IiwiLy8gVGhpcyBpcyBmcmVlIGFuZCB1bmVuY3VtYmVyZWQgc29mdHdhcmUgcmVsZWFzZWQgaW50byB0aGUgcHVibGljIGRvbWFpbi5cbi8vIFNlZSBMSUNFTlNFLm1kIGZvciBtb3JlIGluZm9ybWF0aW9uLlxuXG4vKipcbiAqIEBmaWxlb3ZlcnZpZXcgR2xvYmFsIHx0aGlzfCByZXF1aXJlZCBmb3IgcmVzb2x2aW5nIGluZGV4ZXMgaW4gbm9kZS5cbiAqIEBzdXBwcmVzcyB7Z2xvYmFsVGhpc31cbiAqL1xuKGZ1bmN0aW9uKGdsb2JhbCkge1xuICAndXNlIHN0cmljdCc7XG5cbiAgLy8gSWYgd2UncmUgaW4gbm9kZSByZXF1aXJlIGVuY29kaW5nLWluZGV4ZXMgYW5kIGF0dGFjaCBpdCB0byB0aGUgZ2xvYmFsLlxuICBpZiAodHlwZW9mIG1vZHVsZSAhPT0gXCJ1bmRlZmluZWRcIiAmJiBtb2R1bGUuZXhwb3J0cyAmJlxuICAgICFnbG9iYWxbXCJlbmNvZGluZy1pbmRleGVzXCJdKSB7XG4gICAgZ2xvYmFsW1wiZW5jb2RpbmctaW5kZXhlc1wiXSA9XG4gICAgICByZXF1aXJlKFwiLi9lbmNvZGluZy1pbmRleGVzLmpzXCIpW1wiZW5jb2RpbmctaW5kZXhlc1wiXTtcbiAgfVxuXG4gIC8vXG4gIC8vIFV0aWxpdGllc1xuICAvL1xuXG4gIC8qKlxuICAgKiBAcGFyYW0ge251bWJlcn0gYSBUaGUgbnVtYmVyIHRvIHRlc3QuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBtaW4gVGhlIG1pbmltdW0gdmFsdWUgaW4gdGhlIHJhbmdlLCBpbmNsdXNpdmUuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBtYXggVGhlIG1heGltdW0gdmFsdWUgaW4gdGhlIHJhbmdlLCBpbmNsdXNpdmUuXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgYSA+PSBtaW4gYW5kIGEgPD0gbWF4LlxuICAgKi9cbiAgZnVuY3Rpb24gaW5SYW5nZShhLCBtaW4sIG1heCkge1xuICAgIHJldHVybiBtaW4gPD0gYSAmJiBhIDw9IG1heDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0geyFBcnJheS48Kj59IGFycmF5IFRoZSBhcnJheSB0byBjaGVjay5cbiAgICogQHBhcmFtIHsqfSBpdGVtIFRoZSBpdGVtIHRvIGxvb2sgZm9yIGluIHRoZSBhcnJheS5cbiAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgaXRlbSBhcHBlYXJzIGluIHRoZSBhcnJheS5cbiAgICovXG4gIGZ1bmN0aW9uIGluY2x1ZGVzKGFycmF5LCBpdGVtKSB7XG4gICAgcmV0dXJuIGFycmF5LmluZGV4T2YoaXRlbSkgIT09IC0xO1xuICB9XG5cbiAgdmFyIGZsb29yID0gTWF0aC5mbG9vcjtcblxuICAvKipcbiAgICogQHBhcmFtIHsqfSBvXG4gICAqIEByZXR1cm4ge09iamVjdH1cbiAgICovXG4gIGZ1bmN0aW9uIFRvRGljdGlvbmFyeShvKSB7XG4gICAgaWYgKG8gPT09IHVuZGVmaW5lZCkgcmV0dXJuIHt9O1xuICAgIGlmIChvID09PSBPYmplY3QobykpIHJldHVybiBvO1xuICAgIHRocm93IFR5cGVFcnJvcignQ291bGQgbm90IGNvbnZlcnQgYXJndW1lbnQgdG8gZGljdGlvbmFyeScpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmcgSW5wdXQgc3RyaW5nIG9mIFVURi0xNiBjb2RlIHVuaXRzLlxuICAgKiBAcmV0dXJuIHshQXJyYXkuPG51bWJlcj59IENvZGUgcG9pbnRzLlxuICAgKi9cbiAgZnVuY3Rpb24gc3RyaW5nVG9Db2RlUG9pbnRzKHN0cmluZykge1xuICAgIC8vIGh0dHBzOi8vaGV5Y2FtLmdpdGh1Yi5pby93ZWJpZGwvI2Rmbi1vYnRhaW4tdW5pY29kZVxuXG4gICAgLy8gMS4gTGV0IFMgYmUgdGhlIERPTVN0cmluZyB2YWx1ZS5cbiAgICB2YXIgcyA9IFN0cmluZyhzdHJpbmcpO1xuXG4gICAgLy8gMi4gTGV0IG4gYmUgdGhlIGxlbmd0aCBvZiBTLlxuICAgIHZhciBuID0gcy5sZW5ndGg7XG5cbiAgICAvLyAzLiBJbml0aWFsaXplIGkgdG8gMC5cbiAgICB2YXIgaSA9IDA7XG5cbiAgICAvLyA0LiBJbml0aWFsaXplIFUgdG8gYmUgYW4gZW1wdHkgc2VxdWVuY2Ugb2YgVW5pY29kZSBjaGFyYWN0ZXJzLlxuICAgIHZhciB1ID0gW107XG5cbiAgICAvLyA1LiBXaGlsZSBpIDwgbjpcbiAgICB3aGlsZSAoaSA8IG4pIHtcblxuICAgICAgLy8gMS4gTGV0IGMgYmUgdGhlIGNvZGUgdW5pdCBpbiBTIGF0IGluZGV4IGkuXG4gICAgICB2YXIgYyA9IHMuY2hhckNvZGVBdChpKTtcblxuICAgICAgLy8gMi4gRGVwZW5kaW5nIG9uIHRoZSB2YWx1ZSBvZiBjOlxuXG4gICAgICAvLyBjIDwgMHhEODAwIG9yIGMgPiAweERGRkZcbiAgICAgIGlmIChjIDwgMHhEODAwIHx8IGMgPiAweERGRkYpIHtcbiAgICAgICAgLy8gQXBwZW5kIHRvIFUgdGhlIFVuaWNvZGUgY2hhcmFjdGVyIHdpdGggY29kZSBwb2ludCBjLlxuICAgICAgICB1LnB1c2goYyk7XG4gICAgICB9XG5cbiAgICAgIC8vIDB4REMwMCDiiaQgYyDiiaQgMHhERkZGXG4gICAgICBlbHNlIGlmICgweERDMDAgPD0gYyAmJiBjIDw9IDB4REZGRikge1xuICAgICAgICAvLyBBcHBlbmQgdG8gVSBhIFUrRkZGRCBSRVBMQUNFTUVOVCBDSEFSQUNURVIuXG4gICAgICAgIHUucHVzaCgweEZGRkQpO1xuICAgICAgfVxuXG4gICAgICAvLyAweEQ4MDAg4omkIGMg4omkIDB4REJGRlxuICAgICAgZWxzZSBpZiAoMHhEODAwIDw9IGMgJiYgYyA8PSAweERCRkYpIHtcbiAgICAgICAgLy8gMS4gSWYgaSA9IG7iiJIxLCB0aGVuIGFwcGVuZCB0byBVIGEgVStGRkZEIFJFUExBQ0VNRU5UXG4gICAgICAgIC8vIENIQVJBQ1RFUi5cbiAgICAgICAgaWYgKGkgPT09IG4gLSAxKSB7XG4gICAgICAgICAgdS5wdXNoKDB4RkZGRCk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gMi4gT3RoZXJ3aXNlLCBpIDwgbuKIkjE6XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgIC8vIDEuIExldCBkIGJlIHRoZSBjb2RlIHVuaXQgaW4gUyBhdCBpbmRleCBpKzEuXG4gICAgICAgICAgdmFyIGQgPSBzLmNoYXJDb2RlQXQoaSArIDEpO1xuXG4gICAgICAgICAgLy8gMi4gSWYgMHhEQzAwIOKJpCBkIOKJpCAweERGRkYsIHRoZW46XG4gICAgICAgICAgaWYgKDB4REMwMCA8PSBkICYmIGQgPD0gMHhERkZGKSB7XG4gICAgICAgICAgICAvLyAxLiBMZXQgYSBiZSBjICYgMHgzRkYuXG4gICAgICAgICAgICB2YXIgYSA9IGMgJiAweDNGRjtcblxuICAgICAgICAgICAgLy8gMi4gTGV0IGIgYmUgZCAmIDB4M0ZGLlxuICAgICAgICAgICAgdmFyIGIgPSBkICYgMHgzRkY7XG5cbiAgICAgICAgICAgIC8vIDMuIEFwcGVuZCB0byBVIHRoZSBVbmljb2RlIGNoYXJhY3RlciB3aXRoIGNvZGUgcG9pbnRcbiAgICAgICAgICAgIC8vIDJeMTYrMl4xMCphK2IuXG4gICAgICAgICAgICB1LnB1c2goMHgxMDAwMCArIChhIDw8IDEwKSArIGIpO1xuXG4gICAgICAgICAgICAvLyA0LiBTZXQgaSB0byBpKzEuXG4gICAgICAgICAgICBpICs9IDE7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgLy8gMy4gT3RoZXJ3aXNlLCBkIDwgMHhEQzAwIG9yIGQgPiAweERGRkYuIEFwcGVuZCB0byBVIGFcbiAgICAgICAgICAvLyBVK0ZGRkQgUkVQTEFDRU1FTlQgQ0hBUkFDVEVSLlxuICAgICAgICAgIGVsc2UgIHtcbiAgICAgICAgICAgIHUucHVzaCgweEZGRkQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyAzLiBTZXQgaSB0byBpKzEuXG4gICAgICBpICs9IDE7XG4gICAgfVxuXG4gICAgLy8gNi4gUmV0dXJuIFUuXG4gICAgcmV0dXJuIHU7XG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHshQXJyYXkuPG51bWJlcj59IGNvZGVfcG9pbnRzIEFycmF5IG9mIGNvZGUgcG9pbnRzLlxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IHN0cmluZyBTdHJpbmcgb2YgVVRGLTE2IGNvZGUgdW5pdHMuXG4gICAqL1xuICBmdW5jdGlvbiBjb2RlUG9pbnRzVG9TdHJpbmcoY29kZV9wb2ludHMpIHtcbiAgICB2YXIgcyA9ICcnO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY29kZV9wb2ludHMubGVuZ3RoOyArK2kpIHtcbiAgICAgIHZhciBjcCA9IGNvZGVfcG9pbnRzW2ldO1xuICAgICAgaWYgKGNwIDw9IDB4RkZGRikge1xuICAgICAgICBzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoY3ApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY3AgLT0gMHgxMDAwMDtcbiAgICAgICAgcyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKChjcCA+PiAxMCkgKyAweEQ4MDAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoY3AgJiAweDNGRikgKyAweERDMDApO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcztcbiAgfVxuXG5cbiAgLy9cbiAgLy8gSW1wbGVtZW50YXRpb24gb2YgRW5jb2Rpbmcgc3BlY2lmaWNhdGlvblxuICAvLyBodHRwczovL2VuY29kaW5nLnNwZWMud2hhdHdnLm9yZy9cbiAgLy9cblxuICAvL1xuICAvLyA0LiBUZXJtaW5vbG9neVxuICAvL1xuXG4gIC8qKlxuICAgKiBBbiBBU0NJSSBieXRlIGlzIGEgYnl0ZSBpbiB0aGUgcmFuZ2UgMHgwMCB0byAweDdGLCBpbmNsdXNpdmUuXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBhIFRoZSBudW1iZXIgdG8gdGVzdC5cbiAgICogQHJldHVybiB7Ym9vbGVhbn0gVHJ1ZSBpZiBhIGlzIGluIHRoZSByYW5nZSAweDAwIHRvIDB4N0YsIGluY2x1c2l2ZS5cbiAgICovXG4gIGZ1bmN0aW9uIGlzQVNDSUlCeXRlKGEpIHtcbiAgICByZXR1cm4gMHgwMCA8PSBhICYmIGEgPD0gMHg3RjtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbiBBU0NJSSBjb2RlIHBvaW50IGlzIGEgY29kZSBwb2ludCBpbiB0aGUgcmFuZ2UgVSswMDAwIHRvXG4gICAqIFUrMDA3RiwgaW5jbHVzaXZlLlxuICAgKi9cbiAgdmFyIGlzQVNDSUlDb2RlUG9pbnQgPSBpc0FTQ0lJQnl0ZTtcblxuXG4gIC8qKlxuICAgKiBFbmQtb2Ytc3RyZWFtIGlzIGEgc3BlY2lhbCB0b2tlbiB0aGF0IHNpZ25pZmllcyBubyBtb3JlIHRva2Vuc1xuICAgKiBhcmUgaW4gdGhlIHN0cmVhbS5cbiAgICogQGNvbnN0XG4gICAqLyB2YXIgZW5kX29mX3N0cmVhbSA9IC0xO1xuXG4gIC8qKlxuICAgKiBBIHN0cmVhbSByZXByZXNlbnRzIGFuIG9yZGVyZWQgc2VxdWVuY2Ugb2YgdG9rZW5zLlxuICAgKlxuICAgKiBAY29uc3RydWN0b3JcbiAgICogQHBhcmFtIHshKEFycmF5LjxudW1iZXI+fFVpbnQ4QXJyYXkpfSB0b2tlbnMgQXJyYXkgb2YgdG9rZW5zIHRoYXQgcHJvdmlkZVxuICAgKiB0aGUgc3RyZWFtLlxuICAgKi9cbiAgZnVuY3Rpb24gU3RyZWFtKHRva2Vucykge1xuICAgIC8qKiBAdHlwZSB7IUFycmF5LjxudW1iZXI+fSAqL1xuICAgIHRoaXMudG9rZW5zID0gW10uc2xpY2UuY2FsbCh0b2tlbnMpO1xuICAgIC8vIFJldmVyc2VkIGFzIHB1c2gvcG9wIGlzIG1vcmUgZWZmaWNpZW50IHRoYW4gc2hpZnQvdW5zaGlmdC5cbiAgICB0aGlzLnRva2Vucy5yZXZlcnNlKCk7XG4gIH1cblxuICBTdHJlYW0ucHJvdG90eXBlID0ge1xuICAgIC8qKlxuICAgICAqIEByZXR1cm4ge2Jvb2xlYW59IFRydWUgaWYgZW5kLW9mLXN0cmVhbSBoYXMgYmVlbiBoaXQuXG4gICAgICovXG4gICAgZW5kT2ZTdHJlYW06IGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuICF0aGlzLnRva2Vucy5sZW5ndGg7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFdoZW4gYSB0b2tlbiBpcyByZWFkIGZyb20gYSBzdHJlYW0sIHRoZSBmaXJzdCB0b2tlbiBpbiB0aGVcbiAgICAgKiBzdHJlYW0gbXVzdCBiZSByZXR1cm5lZCBhbmQgc3Vic2VxdWVudGx5IHJlbW92ZWQsIGFuZFxuICAgICAqIGVuZC1vZi1zdHJlYW0gbXVzdCBiZSByZXR1cm5lZCBvdGhlcndpc2UuXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIHtudW1iZXJ9IEdldCB0aGUgbmV4dCB0b2tlbiBmcm9tIHRoZSBzdHJlYW0sIG9yXG4gICAgICogZW5kX29mX3N0cmVhbS5cbiAgICAgKi9cbiAgICAgcmVhZDogZnVuY3Rpb24oKSB7XG4gICAgICBpZiAoIXRoaXMudG9rZW5zLmxlbmd0aClcbiAgICAgICAgcmV0dXJuIGVuZF9vZl9zdHJlYW07XG4gICAgICAgcmV0dXJuIHRoaXMudG9rZW5zLnBvcCgpO1xuICAgICB9LFxuXG4gICAgLyoqXG4gICAgICogV2hlbiBvbmUgb3IgbW9yZSB0b2tlbnMgYXJlIHByZXBlbmRlZCB0byBhIHN0cmVhbSwgdGhvc2UgdG9rZW5zXG4gICAgICogbXVzdCBiZSBpbnNlcnRlZCwgaW4gZ2l2ZW4gb3JkZXIsIGJlZm9yZSB0aGUgZmlyc3QgdG9rZW4gaW4gdGhlXG4gICAgICogc3RyZWFtLlxuICAgICAqXG4gICAgICogQHBhcmFtIHsobnVtYmVyfCFBcnJheS48bnVtYmVyPil9IHRva2VuIFRoZSB0b2tlbihzKSB0byBwcmVwZW5kIHRvIHRoZVxuICAgICAqIHN0cmVhbS5cbiAgICAgKi9cbiAgICBwcmVwZW5kOiBmdW5jdGlvbih0b2tlbikge1xuICAgICAgaWYgKEFycmF5LmlzQXJyYXkodG9rZW4pKSB7XG4gICAgICAgIHZhciB0b2tlbnMgPSAvKipAdHlwZSB7IUFycmF5LjxudW1iZXI+fSovKHRva2VuKTtcbiAgICAgICAgd2hpbGUgKHRva2Vucy5sZW5ndGgpXG4gICAgICAgICAgdGhpcy50b2tlbnMucHVzaCh0b2tlbnMucG9wKCkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy50b2tlbnMucHVzaCh0b2tlbik7XG4gICAgICB9XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFdoZW4gb25lIG9yIG1vcmUgdG9rZW5zIGFyZSBwdXNoZWQgdG8gYSBzdHJlYW0sIHRob3NlIHRva2Vuc1xuICAgICAqIG11c3QgYmUgaW5zZXJ0ZWQsIGluIGdpdmVuIG9yZGVyLCBhZnRlciB0aGUgbGFzdCB0b2tlbiBpbiB0aGVcbiAgICAgKiBzdHJlYW0uXG4gICAgICpcbiAgICAgKiBAcGFyYW0geyhudW1iZXJ8IUFycmF5LjxudW1iZXI+KX0gdG9rZW4gVGhlIHRva2VucyhzKSB0byBwdXNoIHRvIHRoZVxuICAgICAqIHN0cmVhbS5cbiAgICAgKi9cbiAgICBwdXNoOiBmdW5jdGlvbih0b2tlbikge1xuICAgICAgaWYgKEFycmF5LmlzQXJyYXkodG9rZW4pKSB7XG4gICAgICAgIHZhciB0b2tlbnMgPSAvKipAdHlwZSB7IUFycmF5LjxudW1iZXI+fSovKHRva2VuKTtcbiAgICAgICAgd2hpbGUgKHRva2Vucy5sZW5ndGgpXG4gICAgICAgICAgdGhpcy50b2tlbnMudW5zaGlmdCh0b2tlbnMuc2hpZnQoKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnRva2Vucy51bnNoaWZ0KHRva2VuKTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgLy9cbiAgLy8gNS4gRW5jb2RpbmdzXG4gIC8vXG5cbiAgLy8gNS4xIEVuY29kZXJzIGFuZCBkZWNvZGVyc1xuXG4gIC8qKiBAY29uc3QgKi9cbiAgdmFyIGZpbmlzaGVkID0gLTE7XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gZmF0YWwgSWYgdHJ1ZSwgZGVjb2RpbmcgZXJyb3JzIHJhaXNlIGFuIGV4Y2VwdGlvbi5cbiAgICogQHBhcmFtIHtudW1iZXI9fSBvcHRfY29kZV9wb2ludCBPdmVycmlkZSB0aGUgc3RhbmRhcmQgZmFsbGJhY2sgY29kZSBwb2ludC5cbiAgICogQHJldHVybiB7bnVtYmVyfSBUaGUgY29kZSBwb2ludCB0byBpbnNlcnQgb24gYSBkZWNvZGluZyBlcnJvci5cbiAgICovXG4gIGZ1bmN0aW9uIGRlY29kZXJFcnJvcihmYXRhbCwgb3B0X2NvZGVfcG9pbnQpIHtcbiAgICBpZiAoZmF0YWwpXG4gICAgICB0aHJvdyBUeXBlRXJyb3IoJ0RlY29kZXIgZXJyb3InKTtcbiAgICByZXR1cm4gb3B0X2NvZGVfcG9pbnQgfHwgMHhGRkZEO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBjb2RlX3BvaW50IFRoZSBjb2RlIHBvaW50IHRoYXQgY291bGQgbm90IGJlIGVuY29kZWQuXG4gICAqIEByZXR1cm4ge251bWJlcn0gQWx3YXlzIHRocm93cywgbm8gdmFsdWUgaXMgYWN0dWFsbHkgcmV0dXJuZWQuXG4gICAqL1xuICBmdW5jdGlvbiBlbmNvZGVyRXJyb3IoY29kZV9wb2ludCkge1xuICAgIHRocm93IFR5cGVFcnJvcignVGhlIGNvZGUgcG9pbnQgJyArIGNvZGVfcG9pbnQgKyAnIGNvdWxkIG5vdCBiZSBlbmNvZGVkLicpO1xuICB9XG5cbiAgLyoqIEBpbnRlcmZhY2UgKi9cbiAgZnVuY3Rpb24gRGVjb2RlcigpIHt9XG4gIERlY29kZXIucHJvdG90eXBlID0ge1xuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7U3RyZWFtfSBzdHJlYW0gVGhlIHN0cmVhbSBvZiBieXRlcyBiZWluZyBkZWNvZGVkLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBiaXRlIFRoZSBuZXh0IGJ5dGUgcmVhZCBmcm9tIHRoZSBzdHJlYW0uXG4gICAgICogQHJldHVybiB7PyhudW1iZXJ8IUFycmF5LjxudW1iZXI+KX0gVGhlIG5leHQgY29kZSBwb2ludChzKVxuICAgICAqICAgICBkZWNvZGVkLCBvciBudWxsIGlmIG5vdCBlbm91Z2ggZGF0YSBleGlzdHMgaW4gdGhlIGlucHV0XG4gICAgICogICAgIHN0cmVhbSB0byBkZWNvZGUgYSBjb21wbGV0ZSBjb2RlIHBvaW50LCBvciB8ZmluaXNoZWR8LlxuICAgICAqL1xuICAgIGhhbmRsZXI6IGZ1bmN0aW9uKHN0cmVhbSwgYml0ZSkge31cbiAgfTtcblxuICAvKiogQGludGVyZmFjZSAqL1xuICBmdW5jdGlvbiBFbmNvZGVyKCkge31cbiAgRW5jb2Rlci5wcm90b3R5cGUgPSB7XG4gICAgLyoqXG4gICAgICogQHBhcmFtIHtTdHJlYW19IHN0cmVhbSBUaGUgc3RyZWFtIG9mIGNvZGUgcG9pbnRzIGJlaW5nIGVuY29kZWQuXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGNvZGVfcG9pbnQgTmV4dCBjb2RlIHBvaW50IHJlYWQgZnJvbSB0aGUgc3RyZWFtLlxuICAgICAqIEByZXR1cm4geyhudW1iZXJ8IUFycmF5LjxudW1iZXI+KX0gQnl0ZShzKSB0byBlbWl0LCBvciB8ZmluaXNoZWR8LlxuICAgICAqL1xuICAgIGhhbmRsZXI6IGZ1bmN0aW9uKHN0cmVhbSwgY29kZV9wb2ludCkge31cbiAgfTtcblxuICAvLyA1LjIgTmFtZXMgYW5kIGxhYmVsc1xuXG4gIC8vIFRPRE86IERlZmluZSBAdHlwZWRlZiBmb3IgRW5jb2Rpbmc6IHtuYW1lOnN0cmluZyxsYWJlbHM6QXJyYXkuPHN0cmluZz59XG4gIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9nb29nbGUvY2xvc3VyZS1jb21waWxlci9pc3N1ZXMvMjQ3XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBsYWJlbCBUaGUgZW5jb2RpbmcgbGFiZWwuXG4gICAqIEByZXR1cm4gez97bmFtZTpzdHJpbmcsbGFiZWxzOkFycmF5LjxzdHJpbmc+fX1cbiAgICovXG4gIGZ1bmN0aW9uIGdldEVuY29kaW5nKGxhYmVsKSB7XG4gICAgLy8gMS4gUmVtb3ZlIGFueSBsZWFkaW5nIGFuZCB0cmFpbGluZyBBU0NJSSB3aGl0ZXNwYWNlIGZyb20gbGFiZWwuXG4gICAgbGFiZWwgPSBTdHJpbmcobGFiZWwpLnRyaW0oKS50b0xvd2VyQ2FzZSgpO1xuXG4gICAgLy8gMi4gSWYgbGFiZWwgaXMgYW4gQVNDSUkgY2FzZS1pbnNlbnNpdGl2ZSBtYXRjaCBmb3IgYW55IG9mIHRoZVxuICAgIC8vIGxhYmVscyBsaXN0ZWQgaW4gdGhlIHRhYmxlIGJlbG93LCByZXR1cm4gdGhlIGNvcnJlc3BvbmRpbmdcbiAgICAvLyBlbmNvZGluZywgYW5kIGZhaWx1cmUgb3RoZXJ3aXNlLlxuICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwobGFiZWxfdG9fZW5jb2RpbmcsIGxhYmVsKSkge1xuICAgICAgcmV0dXJuIGxhYmVsX3RvX2VuY29kaW5nW2xhYmVsXTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvKipcbiAgICogRW5jb2RpbmdzIHRhYmxlOiBodHRwczovL2VuY29kaW5nLnNwZWMud2hhdHdnLm9yZy9lbmNvZGluZ3MuanNvblxuICAgKiBAY29uc3RcbiAgICogQHR5cGUgeyFBcnJheS48e1xuICAgKiAgICAgICAgICBoZWFkaW5nOiBzdHJpbmcsXG4gICAqICAgICAgICAgIGVuY29kaW5nczogQXJyYXkuPHtuYW1lOnN0cmluZyxsYWJlbHM6QXJyYXkuPHN0cmluZz59PlxuICAgKiAgICAgICAgfT59XG4gICAqL1xuICB2YXIgZW5jb2RpbmdzID0gW1xuICAgIHtcbiAgICAgIFwiZW5jb2RpbmdzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibGFiZWxzXCI6IFtcbiAgICAgICAgICAgIFwidW5pY29kZS0xLTEtdXRmLThcIixcbiAgICAgICAgICAgIFwidXRmLThcIixcbiAgICAgICAgICAgIFwidXRmOFwiXG4gICAgICAgICAgXSxcbiAgICAgICAgICBcIm5hbWVcIjogXCJVVEYtOFwiXG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImhlYWRpbmdcIjogXCJUaGUgRW5jb2RpbmdcIlxuICAgIH0sXG4gICAge1xuICAgICAgXCJlbmNvZGluZ3NcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJsYWJlbHNcIjogW1xuICAgICAgICAgICAgXCI4NjZcIixcbiAgICAgICAgICAgIFwiY3A4NjZcIixcbiAgICAgICAgICAgIFwiY3NpYm04NjZcIixcbiAgICAgICAgICAgIFwiaWJtODY2XCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIFwibmFtZVwiOiBcIklCTTg2NlwiXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcImxhYmVsc1wiOiBbXG4gICAgICAgICAgICBcImNzaXNvbGF0aW4yXCIsXG4gICAgICAgICAgICBcImlzby04ODU5LTJcIixcbiAgICAgICAgICAgIFwiaXNvLWlyLTEwMVwiLFxuICAgICAgICAgICAgXCJpc284ODU5LTJcIixcbiAgICAgICAgICAgIFwiaXNvODg1OTJcIixcbiAgICAgICAgICAgIFwiaXNvXzg4NTktMlwiLFxuICAgICAgICAgICAgXCJpc29fODg1OS0yOjE5ODdcIixcbiAgICAgICAgICAgIFwibDJcIixcbiAgICAgICAgICAgIFwibGF0aW4yXCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIFwibmFtZVwiOiBcIklTTy04ODU5LTJcIlxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJsYWJlbHNcIjogW1xuICAgICAgICAgICAgXCJjc2lzb2xhdGluM1wiLFxuICAgICAgICAgICAgXCJpc28tODg1OS0zXCIsXG4gICAgICAgICAgICBcImlzby1pci0xMDlcIixcbiAgICAgICAgICAgIFwiaXNvODg1OS0zXCIsXG4gICAgICAgICAgICBcImlzbzg4NTkzXCIsXG4gICAgICAgICAgICBcImlzb184ODU5LTNcIixcbiAgICAgICAgICAgIFwiaXNvXzg4NTktMzoxOTg4XCIsXG4gICAgICAgICAgICBcImwzXCIsXG4gICAgICAgICAgICBcImxhdGluM1wiXG4gICAgICAgICAgXSxcbiAgICAgICAgICBcIm5hbWVcIjogXCJJU08tODg1OS0zXCJcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibGFiZWxzXCI6IFtcbiAgICAgICAgICAgIFwiY3Npc29sYXRpbjRcIixcbiAgICAgICAgICAgIFwiaXNvLTg4NTktNFwiLFxuICAgICAgICAgICAgXCJpc28taXItMTEwXCIsXG4gICAgICAgICAgICBcImlzbzg4NTktNFwiLFxuICAgICAgICAgICAgXCJpc284ODU5NFwiLFxuICAgICAgICAgICAgXCJpc29fODg1OS00XCIsXG4gICAgICAgICAgICBcImlzb184ODU5LTQ6MTk4OFwiLFxuICAgICAgICAgICAgXCJsNFwiLFxuICAgICAgICAgICAgXCJsYXRpbjRcIlxuICAgICAgICAgIF0sXG4gICAgICAgICAgXCJuYW1lXCI6IFwiSVNPLTg4NTktNFwiXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcImxhYmVsc1wiOiBbXG4gICAgICAgICAgICBcImNzaXNvbGF0aW5jeXJpbGxpY1wiLFxuICAgICAgICAgICAgXCJjeXJpbGxpY1wiLFxuICAgICAgICAgICAgXCJpc28tODg1OS01XCIsXG4gICAgICAgICAgICBcImlzby1pci0xNDRcIixcbiAgICAgICAgICAgIFwiaXNvODg1OS01XCIsXG4gICAgICAgICAgICBcImlzbzg4NTk1XCIsXG4gICAgICAgICAgICBcImlzb184ODU5LTVcIixcbiAgICAgICAgICAgIFwiaXNvXzg4NTktNToxOTg4XCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIFwibmFtZVwiOiBcIklTTy04ODU5LTVcIlxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJsYWJlbHNcIjogW1xuICAgICAgICAgICAgXCJhcmFiaWNcIixcbiAgICAgICAgICAgIFwiYXNtby03MDhcIixcbiAgICAgICAgICAgIFwiY3Npc284ODU5NmVcIixcbiAgICAgICAgICAgIFwiY3Npc284ODU5NmlcIixcbiAgICAgICAgICAgIFwiY3Npc29sYXRpbmFyYWJpY1wiLFxuICAgICAgICAgICAgXCJlY21hLTExNFwiLFxuICAgICAgICAgICAgXCJpc28tODg1OS02XCIsXG4gICAgICAgICAgICBcImlzby04ODU5LTYtZVwiLFxuICAgICAgICAgICAgXCJpc28tODg1OS02LWlcIixcbiAgICAgICAgICAgIFwiaXNvLWlyLTEyN1wiLFxuICAgICAgICAgICAgXCJpc284ODU5LTZcIixcbiAgICAgICAgICAgIFwiaXNvODg1OTZcIixcbiAgICAgICAgICAgIFwiaXNvXzg4NTktNlwiLFxuICAgICAgICAgICAgXCJpc29fODg1OS02OjE5ODdcIlxuICAgICAgICAgIF0sXG4gICAgICAgICAgXCJuYW1lXCI6IFwiSVNPLTg4NTktNlwiXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcImxhYmVsc1wiOiBbXG4gICAgICAgICAgICBcImNzaXNvbGF0aW5ncmVla1wiLFxuICAgICAgICAgICAgXCJlY21hLTExOFwiLFxuICAgICAgICAgICAgXCJlbG90XzkyOFwiLFxuICAgICAgICAgICAgXCJncmVla1wiLFxuICAgICAgICAgICAgXCJncmVlazhcIixcbiAgICAgICAgICAgIFwiaXNvLTg4NTktN1wiLFxuICAgICAgICAgICAgXCJpc28taXItMTI2XCIsXG4gICAgICAgICAgICBcImlzbzg4NTktN1wiLFxuICAgICAgICAgICAgXCJpc284ODU5N1wiLFxuICAgICAgICAgICAgXCJpc29fODg1OS03XCIsXG4gICAgICAgICAgICBcImlzb184ODU5LTc6MTk4N1wiLFxuICAgICAgICAgICAgXCJzdW5fZXVfZ3JlZWtcIlxuICAgICAgICAgIF0sXG4gICAgICAgICAgXCJuYW1lXCI6IFwiSVNPLTg4NTktN1wiXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcImxhYmVsc1wiOiBbXG4gICAgICAgICAgICBcImNzaXNvODg1OThlXCIsXG4gICAgICAgICAgICBcImNzaXNvbGF0aW5oZWJyZXdcIixcbiAgICAgICAgICAgIFwiaGVicmV3XCIsXG4gICAgICAgICAgICBcImlzby04ODU5LThcIixcbiAgICAgICAgICAgIFwiaXNvLTg4NTktOC1lXCIsXG4gICAgICAgICAgICBcImlzby1pci0xMzhcIixcbiAgICAgICAgICAgIFwiaXNvODg1OS04XCIsXG4gICAgICAgICAgICBcImlzbzg4NTk4XCIsXG4gICAgICAgICAgICBcImlzb184ODU5LThcIixcbiAgICAgICAgICAgIFwiaXNvXzg4NTktODoxOTg4XCIsXG4gICAgICAgICAgICBcInZpc3VhbFwiXG4gICAgICAgICAgXSxcbiAgICAgICAgICBcIm5hbWVcIjogXCJJU08tODg1OS04XCJcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibGFiZWxzXCI6IFtcbiAgICAgICAgICAgIFwiY3Npc284ODU5OGlcIixcbiAgICAgICAgICAgIFwiaXNvLTg4NTktOC1pXCIsXG4gICAgICAgICAgICBcImxvZ2ljYWxcIlxuICAgICAgICAgIF0sXG4gICAgICAgICAgXCJuYW1lXCI6IFwiSVNPLTg4NTktOC1JXCJcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibGFiZWxzXCI6IFtcbiAgICAgICAgICAgIFwiY3Npc29sYXRpbjZcIixcbiAgICAgICAgICAgIFwiaXNvLTg4NTktMTBcIixcbiAgICAgICAgICAgIFwiaXNvLWlyLTE1N1wiLFxuICAgICAgICAgICAgXCJpc284ODU5LTEwXCIsXG4gICAgICAgICAgICBcImlzbzg4NTkxMFwiLFxuICAgICAgICAgICAgXCJsNlwiLFxuICAgICAgICAgICAgXCJsYXRpbjZcIlxuICAgICAgICAgIF0sXG4gICAgICAgICAgXCJuYW1lXCI6IFwiSVNPLTg4NTktMTBcIlxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJsYWJlbHNcIjogW1xuICAgICAgICAgICAgXCJpc28tODg1OS0xM1wiLFxuICAgICAgICAgICAgXCJpc284ODU5LTEzXCIsXG4gICAgICAgICAgICBcImlzbzg4NTkxM1wiXG4gICAgICAgICAgXSxcbiAgICAgICAgICBcIm5hbWVcIjogXCJJU08tODg1OS0xM1wiXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcImxhYmVsc1wiOiBbXG4gICAgICAgICAgICBcImlzby04ODU5LTE0XCIsXG4gICAgICAgICAgICBcImlzbzg4NTktMTRcIixcbiAgICAgICAgICAgIFwiaXNvODg1OTE0XCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIFwibmFtZVwiOiBcIklTTy04ODU5LTE0XCJcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibGFiZWxzXCI6IFtcbiAgICAgICAgICAgIFwiY3Npc29sYXRpbjlcIixcbiAgICAgICAgICAgIFwiaXNvLTg4NTktMTVcIixcbiAgICAgICAgICAgIFwiaXNvODg1OS0xNVwiLFxuICAgICAgICAgICAgXCJpc284ODU5MTVcIixcbiAgICAgICAgICAgIFwiaXNvXzg4NTktMTVcIixcbiAgICAgICAgICAgIFwibDlcIlxuICAgICAgICAgIF0sXG4gICAgICAgICAgXCJuYW1lXCI6IFwiSVNPLTg4NTktMTVcIlxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJsYWJlbHNcIjogW1xuICAgICAgICAgICAgXCJpc28tODg1OS0xNlwiXG4gICAgICAgICAgXSxcbiAgICAgICAgICBcIm5hbWVcIjogXCJJU08tODg1OS0xNlwiXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcImxhYmVsc1wiOiBbXG4gICAgICAgICAgICBcImNza29pOHJcIixcbiAgICAgICAgICAgIFwia29pXCIsXG4gICAgICAgICAgICBcImtvaThcIixcbiAgICAgICAgICAgIFwia29pOC1yXCIsXG4gICAgICAgICAgICBcImtvaThfclwiXG4gICAgICAgICAgXSxcbiAgICAgICAgICBcIm5hbWVcIjogXCJLT0k4LVJcIlxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJsYWJlbHNcIjogW1xuICAgICAgICAgICAgXCJrb2k4LXJ1XCIsXG4gICAgICAgICAgICBcImtvaTgtdVwiXG4gICAgICAgICAgXSxcbiAgICAgICAgICBcIm5hbWVcIjogXCJLT0k4LVVcIlxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJsYWJlbHNcIjogW1xuICAgICAgICAgICAgXCJjc21hY2ludG9zaFwiLFxuICAgICAgICAgICAgXCJtYWNcIixcbiAgICAgICAgICAgIFwibWFjaW50b3NoXCIsXG4gICAgICAgICAgICBcIngtbWFjLXJvbWFuXCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIFwibmFtZVwiOiBcIm1hY2ludG9zaFwiXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcImxhYmVsc1wiOiBbXG4gICAgICAgICAgICBcImRvcy04NzRcIixcbiAgICAgICAgICAgIFwiaXNvLTg4NTktMTFcIixcbiAgICAgICAgICAgIFwiaXNvODg1OS0xMVwiLFxuICAgICAgICAgICAgXCJpc284ODU5MTFcIixcbiAgICAgICAgICAgIFwidGlzLTYyMFwiLFxuICAgICAgICAgICAgXCJ3aW5kb3dzLTg3NFwiXG4gICAgICAgICAgXSxcbiAgICAgICAgICBcIm5hbWVcIjogXCJ3aW5kb3dzLTg3NFwiXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcImxhYmVsc1wiOiBbXG4gICAgICAgICAgICBcImNwMTI1MFwiLFxuICAgICAgICAgICAgXCJ3aW5kb3dzLTEyNTBcIixcbiAgICAgICAgICAgIFwieC1jcDEyNTBcIlxuICAgICAgICAgIF0sXG4gICAgICAgICAgXCJuYW1lXCI6IFwid2luZG93cy0xMjUwXCJcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibGFiZWxzXCI6IFtcbiAgICAgICAgICAgIFwiY3AxMjUxXCIsXG4gICAgICAgICAgICBcIndpbmRvd3MtMTI1MVwiLFxuICAgICAgICAgICAgXCJ4LWNwMTI1MVwiXG4gICAgICAgICAgXSxcbiAgICAgICAgICBcIm5hbWVcIjogXCJ3aW5kb3dzLTEyNTFcIlxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJsYWJlbHNcIjogW1xuICAgICAgICAgICAgXCJhbnNpX3gzLjQtMTk2OFwiLFxuICAgICAgICAgICAgXCJhc2NpaVwiLFxuICAgICAgICAgICAgXCJjcDEyNTJcIixcbiAgICAgICAgICAgIFwiY3A4MTlcIixcbiAgICAgICAgICAgIFwiY3Npc29sYXRpbjFcIixcbiAgICAgICAgICAgIFwiaWJtODE5XCIsXG4gICAgICAgICAgICBcImlzby04ODU5LTFcIixcbiAgICAgICAgICAgIFwiaXNvLWlyLTEwMFwiLFxuICAgICAgICAgICAgXCJpc284ODU5LTFcIixcbiAgICAgICAgICAgIFwiaXNvODg1OTFcIixcbiAgICAgICAgICAgIFwiaXNvXzg4NTktMVwiLFxuICAgICAgICAgICAgXCJpc29fODg1OS0xOjE5ODdcIixcbiAgICAgICAgICAgIFwibDFcIixcbiAgICAgICAgICAgIFwibGF0aW4xXCIsXG4gICAgICAgICAgICBcInVzLWFzY2lpXCIsXG4gICAgICAgICAgICBcIndpbmRvd3MtMTI1MlwiLFxuICAgICAgICAgICAgXCJ4LWNwMTI1MlwiXG4gICAgICAgICAgXSxcbiAgICAgICAgICBcIm5hbWVcIjogXCJ3aW5kb3dzLTEyNTJcIlxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJsYWJlbHNcIjogW1xuICAgICAgICAgICAgXCJjcDEyNTNcIixcbiAgICAgICAgICAgIFwid2luZG93cy0xMjUzXCIsXG4gICAgICAgICAgICBcIngtY3AxMjUzXCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIFwibmFtZVwiOiBcIndpbmRvd3MtMTI1M1wiXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcImxhYmVsc1wiOiBbXG4gICAgICAgICAgICBcImNwMTI1NFwiLFxuICAgICAgICAgICAgXCJjc2lzb2xhdGluNVwiLFxuICAgICAgICAgICAgXCJpc28tODg1OS05XCIsXG4gICAgICAgICAgICBcImlzby1pci0xNDhcIixcbiAgICAgICAgICAgIFwiaXNvODg1OS05XCIsXG4gICAgICAgICAgICBcImlzbzg4NTk5XCIsXG4gICAgICAgICAgICBcImlzb184ODU5LTlcIixcbiAgICAgICAgICAgIFwiaXNvXzg4NTktOToxOTg5XCIsXG4gICAgICAgICAgICBcImw1XCIsXG4gICAgICAgICAgICBcImxhdGluNVwiLFxuICAgICAgICAgICAgXCJ3aW5kb3dzLTEyNTRcIixcbiAgICAgICAgICAgIFwieC1jcDEyNTRcIlxuICAgICAgICAgIF0sXG4gICAgICAgICAgXCJuYW1lXCI6IFwid2luZG93cy0xMjU0XCJcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibGFiZWxzXCI6IFtcbiAgICAgICAgICAgIFwiY3AxMjU1XCIsXG4gICAgICAgICAgICBcIndpbmRvd3MtMTI1NVwiLFxuICAgICAgICAgICAgXCJ4LWNwMTI1NVwiXG4gICAgICAgICAgXSxcbiAgICAgICAgICBcIm5hbWVcIjogXCJ3aW5kb3dzLTEyNTVcIlxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJsYWJlbHNcIjogW1xuICAgICAgICAgICAgXCJjcDEyNTZcIixcbiAgICAgICAgICAgIFwid2luZG93cy0xMjU2XCIsXG4gICAgICAgICAgICBcIngtY3AxMjU2XCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIFwibmFtZVwiOiBcIndpbmRvd3MtMTI1NlwiXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcImxhYmVsc1wiOiBbXG4gICAgICAgICAgICBcImNwMTI1N1wiLFxuICAgICAgICAgICAgXCJ3aW5kb3dzLTEyNTdcIixcbiAgICAgICAgICAgIFwieC1jcDEyNTdcIlxuICAgICAgICAgIF0sXG4gICAgICAgICAgXCJuYW1lXCI6IFwid2luZG93cy0xMjU3XCJcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibGFiZWxzXCI6IFtcbiAgICAgICAgICAgIFwiY3AxMjU4XCIsXG4gICAgICAgICAgICBcIndpbmRvd3MtMTI1OFwiLFxuICAgICAgICAgICAgXCJ4LWNwMTI1OFwiXG4gICAgICAgICAgXSxcbiAgICAgICAgICBcIm5hbWVcIjogXCJ3aW5kb3dzLTEyNThcIlxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJsYWJlbHNcIjogW1xuICAgICAgICAgICAgXCJ4LW1hYy1jeXJpbGxpY1wiLFxuICAgICAgICAgICAgXCJ4LW1hYy11a3JhaW5pYW5cIlxuICAgICAgICAgIF0sXG4gICAgICAgICAgXCJuYW1lXCI6IFwieC1tYWMtY3lyaWxsaWNcIlxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJoZWFkaW5nXCI6IFwiTGVnYWN5IHNpbmdsZS1ieXRlIGVuY29kaW5nc1wiXG4gICAgfSxcbiAgICB7XG4gICAgICBcImVuY29kaW5nc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcImxhYmVsc1wiOiBbXG4gICAgICAgICAgICBcImNoaW5lc2VcIixcbiAgICAgICAgICAgIFwiY3NnYjIzMTJcIixcbiAgICAgICAgICAgIFwiY3Npc281OGdiMjMxMjgwXCIsXG4gICAgICAgICAgICBcImdiMjMxMlwiLFxuICAgICAgICAgICAgXCJnYl8yMzEyXCIsXG4gICAgICAgICAgICBcImdiXzIzMTItODBcIixcbiAgICAgICAgICAgIFwiZ2JrXCIsXG4gICAgICAgICAgICBcImlzby1pci01OFwiLFxuICAgICAgICAgICAgXCJ4LWdia1wiXG4gICAgICAgICAgXSxcbiAgICAgICAgICBcIm5hbWVcIjogXCJHQktcIlxuICAgICAgICB9LFxuICAgICAgICB7XG4gICAgICAgICAgXCJsYWJlbHNcIjogW1xuICAgICAgICAgICAgXCJnYjE4MDMwXCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIFwibmFtZVwiOiBcImdiMTgwMzBcIlxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJoZWFkaW5nXCI6IFwiTGVnYWN5IG11bHRpLWJ5dGUgQ2hpbmVzZSAoc2ltcGxpZmllZCkgZW5jb2RpbmdzXCJcbiAgICB9LFxuICAgIHtcbiAgICAgIFwiZW5jb2RpbmdzXCI6IFtcbiAgICAgICAge1xuICAgICAgICAgIFwibGFiZWxzXCI6IFtcbiAgICAgICAgICAgIFwiYmlnNVwiLFxuICAgICAgICAgICAgXCJiaWc1LWhrc2NzXCIsXG4gICAgICAgICAgICBcImNuLWJpZzVcIixcbiAgICAgICAgICAgIFwiY3NiaWc1XCIsXG4gICAgICAgICAgICBcIngteC1iaWc1XCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIFwibmFtZVwiOiBcIkJpZzVcIlxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJoZWFkaW5nXCI6IFwiTGVnYWN5IG11bHRpLWJ5dGUgQ2hpbmVzZSAodHJhZGl0aW9uYWwpIGVuY29kaW5nc1wiXG4gICAgfSxcbiAgICB7XG4gICAgICBcImVuY29kaW5nc1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBcImxhYmVsc1wiOiBbXG4gICAgICAgICAgICBcImNzZXVjcGtkZm10amFwYW5lc2VcIixcbiAgICAgICAgICAgIFwiZXVjLWpwXCIsXG4gICAgICAgICAgICBcIngtZXVjLWpwXCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIFwibmFtZVwiOiBcIkVVQy1KUFwiXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcImxhYmVsc1wiOiBbXG4gICAgICAgICAgICBcImNzaXNvMjAyMmpwXCIsXG4gICAgICAgICAgICBcImlzby0yMDIyLWpwXCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIFwibmFtZVwiOiBcIklTTy0yMDIyLUpQXCJcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibGFiZWxzXCI6IFtcbiAgICAgICAgICAgIFwiY3NzaGlmdGppc1wiLFxuICAgICAgICAgICAgXCJtczkzMlwiLFxuICAgICAgICAgICAgXCJtc19rYW5qaVwiLFxuICAgICAgICAgICAgXCJzaGlmdC1qaXNcIixcbiAgICAgICAgICAgIFwic2hpZnRfamlzXCIsXG4gICAgICAgICAgICBcInNqaXNcIixcbiAgICAgICAgICAgIFwid2luZG93cy0zMWpcIixcbiAgICAgICAgICAgIFwieC1zamlzXCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIFwibmFtZVwiOiBcIlNoaWZ0X0pJU1wiXG4gICAgICAgIH1cbiAgICAgIF0sXG4gICAgICBcImhlYWRpbmdcIjogXCJMZWdhY3kgbXVsdGktYnl0ZSBKYXBhbmVzZSBlbmNvZGluZ3NcIlxuICAgIH0sXG4gICAge1xuICAgICAgXCJlbmNvZGluZ3NcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJsYWJlbHNcIjogW1xuICAgICAgICAgICAgXCJjc2V1Y2tyXCIsXG4gICAgICAgICAgICBcImNza3NjNTYwMTE5ODdcIixcbiAgICAgICAgICAgIFwiZXVjLWtyXCIsXG4gICAgICAgICAgICBcImlzby1pci0xNDlcIixcbiAgICAgICAgICAgIFwia29yZWFuXCIsXG4gICAgICAgICAgICBcImtzX2NfNTYwMS0xOTg3XCIsXG4gICAgICAgICAgICBcImtzX2NfNTYwMS0xOTg5XCIsXG4gICAgICAgICAgICBcImtzYzU2MDFcIixcbiAgICAgICAgICAgIFwia3NjXzU2MDFcIixcbiAgICAgICAgICAgIFwid2luZG93cy05NDlcIlxuICAgICAgICAgIF0sXG4gICAgICAgICAgXCJuYW1lXCI6IFwiRVVDLUtSXCJcbiAgICAgICAgfVxuICAgICAgXSxcbiAgICAgIFwiaGVhZGluZ1wiOiBcIkxlZ2FjeSBtdWx0aS1ieXRlIEtvcmVhbiBlbmNvZGluZ3NcIlxuICAgIH0sXG4gICAge1xuICAgICAgXCJlbmNvZGluZ3NcIjogW1xuICAgICAgICB7XG4gICAgICAgICAgXCJsYWJlbHNcIjogW1xuICAgICAgICAgICAgXCJjc2lzbzIwMjJrclwiLFxuICAgICAgICAgICAgXCJoei1nYi0yMzEyXCIsXG4gICAgICAgICAgICBcImlzby0yMDIyLWNuXCIsXG4gICAgICAgICAgICBcImlzby0yMDIyLWNuLWV4dFwiLFxuICAgICAgICAgICAgXCJpc28tMjAyMi1rclwiXG4gICAgICAgICAgXSxcbiAgICAgICAgICBcIm5hbWVcIjogXCJyZXBsYWNlbWVudFwiXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBcImxhYmVsc1wiOiBbXG4gICAgICAgICAgICBcInV0Zi0xNmJlXCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIFwibmFtZVwiOiBcIlVURi0xNkJFXCJcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibGFiZWxzXCI6IFtcbiAgICAgICAgICAgIFwidXRmLTE2XCIsXG4gICAgICAgICAgICBcInV0Zi0xNmxlXCJcbiAgICAgICAgICBdLFxuICAgICAgICAgIFwibmFtZVwiOiBcIlVURi0xNkxFXCJcbiAgICAgICAgfSxcbiAgICAgICAge1xuICAgICAgICAgIFwibGFiZWxzXCI6IFtcbiAgICAgICAgICAgIFwieC11c2VyLWRlZmluZWRcIlxuICAgICAgICAgIF0sXG4gICAgICAgICAgXCJuYW1lXCI6IFwieC11c2VyLWRlZmluZWRcIlxuICAgICAgICB9XG4gICAgICBdLFxuICAgICAgXCJoZWFkaW5nXCI6IFwiTGVnYWN5IG1pc2NlbGxhbmVvdXMgZW5jb2RpbmdzXCJcbiAgICB9XG4gIF07XG5cbiAgLy8gTGFiZWwgdG8gZW5jb2RpbmcgcmVnaXN0cnkuXG4gIC8qKiBAdHlwZSB7T2JqZWN0LjxzdHJpbmcse25hbWU6c3RyaW5nLGxhYmVsczpBcnJheS48c3RyaW5nPn0+fSAqL1xuICB2YXIgbGFiZWxfdG9fZW5jb2RpbmcgPSB7fTtcbiAgZW5jb2RpbmdzLmZvckVhY2goZnVuY3Rpb24oY2F0ZWdvcnkpIHtcbiAgICBjYXRlZ29yeS5lbmNvZGluZ3MuZm9yRWFjaChmdW5jdGlvbihlbmNvZGluZykge1xuICAgICAgZW5jb2RpbmcubGFiZWxzLmZvckVhY2goZnVuY3Rpb24obGFiZWwpIHtcbiAgICAgICAgbGFiZWxfdG9fZW5jb2RpbmdbbGFiZWxdID0gZW5jb2Rpbmc7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgLy8gUmVnaXN0cnkgb2Ygb2YgZW5jb2Rlci9kZWNvZGVyIGZhY3RvcmllcywgYnkgZW5jb2RpbmcgbmFtZS5cbiAgLyoqIEB0eXBlIHtPYmplY3QuPHN0cmluZywgZnVuY3Rpb24oe2ZhdGFsOmJvb2xlYW59KTogRW5jb2Rlcj59ICovXG4gIHZhciBlbmNvZGVycyA9IHt9O1xuICAvKiogQHR5cGUge09iamVjdC48c3RyaW5nLCBmdW5jdGlvbih7ZmF0YWw6Ym9vbGVhbn0pOiBEZWNvZGVyPn0gKi9cbiAgdmFyIGRlY29kZXJzID0ge307XG5cbiAgLy9cbiAgLy8gNi4gSW5kZXhlc1xuICAvL1xuXG4gIC8qKlxuICAgKiBAcGFyYW0ge251bWJlcn0gcG9pbnRlciBUaGUgfHBvaW50ZXJ8IHRvIHNlYXJjaCBmb3IuXG4gICAqIEBwYXJhbSB7KCFBcnJheS48P251bWJlcj58dW5kZWZpbmVkKX0gaW5kZXggVGhlIHxpbmRleHwgdG8gc2VhcmNoIHdpdGhpbi5cbiAgICogQHJldHVybiB7P251bWJlcn0gVGhlIGNvZGUgcG9pbnQgY29ycmVzcG9uZGluZyB0byB8cG9pbnRlcnwgaW4gfGluZGV4fCxcbiAgICogICAgIG9yIG51bGwgaWYgfGNvZGUgcG9pbnR8IGlzIG5vdCBpbiB8aW5kZXh8LlxuICAgKi9cbiAgZnVuY3Rpb24gaW5kZXhDb2RlUG9pbnRGb3IocG9pbnRlciwgaW5kZXgpIHtcbiAgICBpZiAoIWluZGV4KSByZXR1cm4gbnVsbDtcbiAgICByZXR1cm4gaW5kZXhbcG9pbnRlcl0gfHwgbnVsbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge251bWJlcn0gY29kZV9wb2ludCBUaGUgfGNvZGUgcG9pbnR8IHRvIHNlYXJjaCBmb3IuXG4gICAqIEBwYXJhbSB7IUFycmF5Ljw/bnVtYmVyPn0gaW5kZXggVGhlIHxpbmRleHwgdG8gc2VhcmNoIHdpdGhpbi5cbiAgICogQHJldHVybiB7P251bWJlcn0gVGhlIGZpcnN0IHBvaW50ZXIgY29ycmVzcG9uZGluZyB0byB8Y29kZSBwb2ludHwgaW5cbiAgICogICAgIHxpbmRleHwsIG9yIG51bGwgaWYgfGNvZGUgcG9pbnR8IGlzIG5vdCBpbiB8aW5kZXh8LlxuICAgKi9cbiAgZnVuY3Rpb24gaW5kZXhQb2ludGVyRm9yKGNvZGVfcG9pbnQsIGluZGV4KSB7XG4gICAgdmFyIHBvaW50ZXIgPSBpbmRleC5pbmRleE9mKGNvZGVfcG9pbnQpO1xuICAgIHJldHVybiBwb2ludGVyID09PSAtMSA/IG51bGwgOiBwb2ludGVyO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lIE5hbWUgb2YgdGhlIGluZGV4LlxuICAgKiBAcmV0dXJuIHsoIUFycmF5LjxudW1iZXI+fCFBcnJheS48QXJyYXkuPG51bWJlcj4+KX1cbiAgICogICovXG4gIGZ1bmN0aW9uIGluZGV4KG5hbWUpIHtcbiAgICBpZiAoISgnZW5jb2RpbmctaW5kZXhlcycgaW4gZ2xvYmFsKSkge1xuICAgICAgdGhyb3cgRXJyb3IoXCJJbmRleGVzIG1pc3NpbmcuXCIgK1xuICAgICAgICAgICAgICAgICAgXCIgRGlkIHlvdSBmb3JnZXQgdG8gaW5jbHVkZSBlbmNvZGluZy1pbmRleGVzLmpzIGZpcnN0P1wiKTtcbiAgICB9XG4gICAgcmV0dXJuIGdsb2JhbFsnZW5jb2RpbmctaW5kZXhlcyddW25hbWVdO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBwb2ludGVyIFRoZSB8cG9pbnRlcnwgdG8gc2VhcmNoIGZvciBpbiB0aGUgZ2IxODAzMCBpbmRleC5cbiAgICogQHJldHVybiB7P251bWJlcn0gVGhlIGNvZGUgcG9pbnQgY29ycmVzcG9uZGluZyB0byB8cG9pbnRlcnwgaW4gfGluZGV4fCxcbiAgICogICAgIG9yIG51bGwgaWYgfGNvZGUgcG9pbnR8IGlzIG5vdCBpbiB0aGUgZ2IxODAzMCBpbmRleC5cbiAgICovXG4gIGZ1bmN0aW9uIGluZGV4R0IxODAzMFJhbmdlc0NvZGVQb2ludEZvcihwb2ludGVyKSB7XG4gICAgLy8gMS4gSWYgcG9pbnRlciBpcyBncmVhdGVyIHRoYW4gMzk0MTkgYW5kIGxlc3MgdGhhbiAxODkwMDAsIG9yXG4gICAgLy8gcG9pbnRlciBpcyBncmVhdGVyIHRoYW4gMTIzNzU3NSwgcmV0dXJuIG51bGwuXG4gICAgaWYgKChwb2ludGVyID4gMzk0MTkgJiYgcG9pbnRlciA8IDE4OTAwMCkgfHwgKHBvaW50ZXIgPiAxMjM3NTc1KSlcbiAgICAgIHJldHVybiBudWxsO1xuXG4gICAgLy8gMi4gSWYgcG9pbnRlciBpcyA3NDU3LCByZXR1cm4gY29kZSBwb2ludCBVK0U3QzcuXG4gICAgaWYgKHBvaW50ZXIgPT09IDc0NTcpIHJldHVybiAweEU3Qzc7XG5cbiAgICAvLyAzLiBMZXQgb2Zmc2V0IGJlIHRoZSBsYXN0IHBvaW50ZXIgaW4gaW5kZXggZ2IxODAzMCByYW5nZXMgdGhhdFxuICAgIC8vIGlzIGVxdWFsIHRvIG9yIGxlc3MgdGhhbiBwb2ludGVyIGFuZCBsZXQgY29kZSBwb2ludCBvZmZzZXQgYmVcbiAgICAvLyBpdHMgY29ycmVzcG9uZGluZyBjb2RlIHBvaW50LlxuICAgIHZhciBvZmZzZXQgPSAwO1xuICAgIHZhciBjb2RlX3BvaW50X29mZnNldCA9IDA7XG4gICAgdmFyIGlkeCA9IGluZGV4KCdnYjE4MDMwLXJhbmdlcycpO1xuICAgIHZhciBpO1xuICAgIGZvciAoaSA9IDA7IGkgPCBpZHgubGVuZ3RoOyArK2kpIHtcbiAgICAgIC8qKiBAdHlwZSB7IUFycmF5LjxudW1iZXI+fSAqL1xuICAgICAgdmFyIGVudHJ5ID0gaWR4W2ldO1xuICAgICAgaWYgKGVudHJ5WzBdIDw9IHBvaW50ZXIpIHtcbiAgICAgICAgb2Zmc2V0ID0gZW50cnlbMF07XG4gICAgICAgIGNvZGVfcG9pbnRfb2Zmc2V0ID0gZW50cnlbMV07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyA0LiBSZXR1cm4gYSBjb2RlIHBvaW50IHdob3NlIHZhbHVlIGlzIGNvZGUgcG9pbnQgb2Zmc2V0ICtcbiAgICAvLyBwb2ludGVyIOKIkiBvZmZzZXQuXG4gICAgcmV0dXJuIGNvZGVfcG9pbnRfb2Zmc2V0ICsgcG9pbnRlciAtIG9mZnNldDtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge251bWJlcn0gY29kZV9wb2ludCBUaGUgfGNvZGUgcG9pbnR8IHRvIGxvY2F0ZSBpbiB0aGUgZ2IxODAzMCBpbmRleC5cbiAgICogQHJldHVybiB7bnVtYmVyfSBUaGUgZmlyc3QgcG9pbnRlciBjb3JyZXNwb25kaW5nIHRvIHxjb2RlIHBvaW50fCBpbiB0aGVcbiAgICogICAgIGdiMTgwMzAgaW5kZXguXG4gICAqL1xuICBmdW5jdGlvbiBpbmRleEdCMTgwMzBSYW5nZXNQb2ludGVyRm9yKGNvZGVfcG9pbnQpIHtcbiAgICAvLyAxLiBJZiBjb2RlIHBvaW50IGlzIFUrRTdDNywgcmV0dXJuIHBvaW50ZXIgNzQ1Ny5cbiAgICBpZiAoY29kZV9wb2ludCA9PT0gMHhFN0M3KSByZXR1cm4gNzQ1NztcblxuICAgIC8vIDIuIExldCBvZmZzZXQgYmUgdGhlIGxhc3QgY29kZSBwb2ludCBpbiBpbmRleCBnYjE4MDMwIHJhbmdlc1xuICAgIC8vIHRoYXQgaXMgZXF1YWwgdG8gb3IgbGVzcyB0aGFuIGNvZGUgcG9pbnQgYW5kIGxldCBwb2ludGVyIG9mZnNldFxuICAgIC8vIGJlIGl0cyBjb3JyZXNwb25kaW5nIHBvaW50ZXIuXG4gICAgdmFyIG9mZnNldCA9IDA7XG4gICAgdmFyIHBvaW50ZXJfb2Zmc2V0ID0gMDtcbiAgICB2YXIgaWR4ID0gaW5kZXgoJ2diMTgwMzAtcmFuZ2VzJyk7XG4gICAgdmFyIGk7XG4gICAgZm9yIChpID0gMDsgaSA8IGlkeC5sZW5ndGg7ICsraSkge1xuICAgICAgLyoqIEB0eXBlIHshQXJyYXkuPG51bWJlcj59ICovXG4gICAgICB2YXIgZW50cnkgPSBpZHhbaV07XG4gICAgICBpZiAoZW50cnlbMV0gPD0gY29kZV9wb2ludCkge1xuICAgICAgICBvZmZzZXQgPSBlbnRyeVsxXTtcbiAgICAgICAgcG9pbnRlcl9vZmZzZXQgPSBlbnRyeVswXTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIDMuIFJldHVybiBhIHBvaW50ZXIgd2hvc2UgdmFsdWUgaXMgcG9pbnRlciBvZmZzZXQgKyBjb2RlIHBvaW50XG4gICAgLy8g4oiSIG9mZnNldC5cbiAgICByZXR1cm4gcG9pbnRlcl9vZmZzZXQgKyBjb2RlX3BvaW50IC0gb2Zmc2V0O1xuICB9XG5cbiAgLyoqXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBjb2RlX3BvaW50IFRoZSB8Y29kZV9wb2ludHwgdG8gc2VhcmNoIGZvciBpbiB0aGUgU2hpZnRfSklTXG4gICAqICAgICBpbmRleC5cbiAgICogQHJldHVybiB7P251bWJlcn0gVGhlIGNvZGUgcG9pbnQgY29ycmVzcG9uZGluZyB0byB8cG9pbnRlcnwgaW4gfGluZGV4fCxcbiAgICogICAgIG9yIG51bGwgaWYgfGNvZGUgcG9pbnR8IGlzIG5vdCBpbiB0aGUgU2hpZnRfSklTIGluZGV4LlxuICAgKi9cbiAgZnVuY3Rpb24gaW5kZXhTaGlmdEpJU1BvaW50ZXJGb3IoY29kZV9wb2ludCkge1xuICAgIC8vIDEuIExldCBpbmRleCBiZSBpbmRleCBqaXMwMjA4IGV4Y2x1ZGluZyBhbGwgZW50cmllcyB3aG9zZVxuICAgIC8vIHBvaW50ZXIgaXMgaW4gdGhlIHJhbmdlIDgyNzIgdG8gODgzNSwgaW5jbHVzaXZlLlxuICAgIHNoaWZ0X2ppc19pbmRleCA9IHNoaWZ0X2ppc19pbmRleCB8fFxuICAgICAgaW5kZXgoJ2ppczAyMDgnKS5tYXAoZnVuY3Rpb24oY29kZV9wb2ludCwgcG9pbnRlcikge1xuICAgICAgICByZXR1cm4gaW5SYW5nZShwb2ludGVyLCA4MjcyLCA4ODM1KSA/IG51bGwgOiBjb2RlX3BvaW50O1xuICAgICAgfSk7XG4gICAgdmFyIGluZGV4XyA9IHNoaWZ0X2ppc19pbmRleDtcblxuICAgIC8vIDIuIFJldHVybiB0aGUgaW5kZXggcG9pbnRlciBmb3IgY29kZSBwb2ludCBpbiBpbmRleC5cbiAgICByZXR1cm4gaW5kZXhfLmluZGV4T2YoY29kZV9wb2ludCk7XG4gIH1cbiAgdmFyIHNoaWZ0X2ppc19pbmRleDtcblxuICAvKipcbiAgICogQHBhcmFtIHtudW1iZXJ9IGNvZGVfcG9pbnQgVGhlIHxjb2RlX3BvaW50fCB0byBzZWFyY2ggZm9yIGluIHRoZSBiaWc1XG4gICAqICAgICBpbmRleC5cbiAgICogQHJldHVybiB7P251bWJlcn0gVGhlIGNvZGUgcG9pbnQgY29ycmVzcG9uZGluZyB0byB8cG9pbnRlcnwgaW4gfGluZGV4fCxcbiAgICogICAgIG9yIG51bGwgaWYgfGNvZGUgcG9pbnR8IGlzIG5vdCBpbiB0aGUgYmlnNSBpbmRleC5cbiAgICovXG4gIGZ1bmN0aW9uIGluZGV4QmlnNVBvaW50ZXJGb3IoY29kZV9wb2ludCkge1xuICAgIC8vIDEuIExldCBpbmRleCBiZSBpbmRleCBCaWc1IGV4Y2x1ZGluZyBhbGwgZW50cmllcyB3aG9zZSBwb2ludGVyXG4gICAgYmlnNV9pbmRleF9ub19oa3NjcyA9IGJpZzVfaW5kZXhfbm9faGtzY3MgfHxcbiAgICAgIGluZGV4KCdiaWc1JykubWFwKGZ1bmN0aW9uKGNvZGVfcG9pbnQsIHBvaW50ZXIpIHtcbiAgICAgICAgcmV0dXJuIChwb2ludGVyIDwgKDB4QTEgLSAweDgxKSAqIDE1NykgPyBudWxsIDogY29kZV9wb2ludDtcbiAgICAgIH0pO1xuICAgIHZhciBpbmRleF8gPSBiaWc1X2luZGV4X25vX2hrc2NzO1xuXG4gICAgLy8gMi4gSWYgY29kZSBwb2ludCBpcyBVKzI1NTAsIFUrMjU1RSwgVSsyNTYxLCBVKzI1NkEsIFUrNTM0MSwgb3JcbiAgICAvLyBVKzUzNDUsIHJldHVybiB0aGUgbGFzdCBwb2ludGVyIGNvcnJlc3BvbmRpbmcgdG8gY29kZSBwb2ludCBpblxuICAgIC8vIGluZGV4LlxuICAgIGlmIChjb2RlX3BvaW50ID09PSAweDI1NTAgfHwgY29kZV9wb2ludCA9PT0gMHgyNTVFIHx8XG4gICAgICAgIGNvZGVfcG9pbnQgPT09IDB4MjU2MSB8fCBjb2RlX3BvaW50ID09PSAweDI1NkEgfHxcbiAgICAgICAgY29kZV9wb2ludCA9PT0gMHg1MzQxIHx8IGNvZGVfcG9pbnQgPT09IDB4NTM0NSkge1xuICAgICAgcmV0dXJuIGluZGV4Xy5sYXN0SW5kZXhPZihjb2RlX3BvaW50KTtcbiAgICB9XG5cbiAgICAvLyAzLiBSZXR1cm4gdGhlIGluZGV4IHBvaW50ZXIgZm9yIGNvZGUgcG9pbnQgaW4gaW5kZXguXG4gICAgcmV0dXJuIGluZGV4UG9pbnRlckZvcihjb2RlX3BvaW50LCBpbmRleF8pO1xuICB9XG4gIHZhciBiaWc1X2luZGV4X25vX2hrc2NzO1xuXG4gIC8vXG4gIC8vIDguIEFQSVxuICAvL1xuXG4gIC8qKiBAY29uc3QgKi8gdmFyIERFRkFVTFRfRU5DT0RJTkcgPSAndXRmLTgnO1xuXG4gIC8vIDguMSBJbnRlcmZhY2UgVGV4dERlY29kZXJcblxuICAvKipcbiAgICogQGNvbnN0cnVjdG9yXG4gICAqIEBwYXJhbSB7c3RyaW5nPX0gbGFiZWwgVGhlIGxhYmVsIG9mIHRoZSBlbmNvZGluZztcbiAgICogICAgIGRlZmF1bHRzIHRvICd1dGYtOCcuXG4gICAqIEBwYXJhbSB7T2JqZWN0PX0gb3B0aW9uc1xuICAgKi9cbiAgZnVuY3Rpb24gVGV4dERlY29kZXIobGFiZWwsIG9wdGlvbnMpIHtcbiAgICAvLyBXZWIgSURMIGNvbnZlbnRpb25zXG4gICAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIFRleHREZWNvZGVyKSlcbiAgICAgIHRocm93IFR5cGVFcnJvcignQ2FsbGVkIGFzIGEgZnVuY3Rpb24uIERpZCB5b3UgZm9yZ2V0IFxcJ25ld1xcJz8nKTtcbiAgICBsYWJlbCA9IGxhYmVsICE9PSB1bmRlZmluZWQgPyBTdHJpbmcobGFiZWwpIDogREVGQVVMVF9FTkNPRElORztcbiAgICBvcHRpb25zID0gVG9EaWN0aW9uYXJ5KG9wdGlvbnMpO1xuXG4gICAgLy8gQSBUZXh0RGVjb2RlciBvYmplY3QgaGFzIGFuIGFzc29jaWF0ZWQgZW5jb2RpbmcsIGRlY29kZXIsXG4gICAgLy8gc3RyZWFtLCBpZ25vcmUgQk9NIGZsYWcgKGluaXRpYWxseSB1bnNldCksIEJPTSBzZWVuIGZsYWdcbiAgICAvLyAoaW5pdGlhbGx5IHVuc2V0KSwgZXJyb3IgbW9kZSAoaW5pdGlhbGx5IHJlcGxhY2VtZW50KSwgYW5kIGRvXG4gICAgLy8gbm90IGZsdXNoIGZsYWcgKGluaXRpYWxseSB1bnNldCkuXG5cbiAgICAvKiogQHByaXZhdGUgKi9cbiAgICB0aGlzLl9lbmNvZGluZyA9IG51bGw7XG4gICAgLyoqIEBwcml2YXRlIEB0eXBlIHs/RGVjb2Rlcn0gKi9cbiAgICB0aGlzLl9kZWNvZGVyID0gbnVsbDtcbiAgICAvKiogQHByaXZhdGUgQHR5cGUge2Jvb2xlYW59ICovXG4gICAgdGhpcy5faWdub3JlQk9NID0gZmFsc2U7XG4gICAgLyoqIEBwcml2YXRlIEB0eXBlIHtib29sZWFufSAqL1xuICAgIHRoaXMuX0JPTXNlZW4gPSBmYWxzZTtcbiAgICAvKiogQHByaXZhdGUgQHR5cGUge3N0cmluZ30gKi9cbiAgICB0aGlzLl9lcnJvcl9tb2RlID0gJ3JlcGxhY2VtZW50JztcbiAgICAvKiogQHByaXZhdGUgQHR5cGUge2Jvb2xlYW59ICovXG4gICAgdGhpcy5fZG9fbm90X2ZsdXNoID0gZmFsc2U7XG5cblxuICAgIC8vIDEuIExldCBlbmNvZGluZyBiZSB0aGUgcmVzdWx0IG9mIGdldHRpbmcgYW4gZW5jb2RpbmcgZnJvbVxuICAgIC8vIGxhYmVsLlxuICAgIHZhciBlbmNvZGluZyA9IGdldEVuY29kaW5nKGxhYmVsKTtcblxuICAgIC8vIDIuIElmIGVuY29kaW5nIGlzIGZhaWx1cmUgb3IgcmVwbGFjZW1lbnQsIHRocm93IGEgUmFuZ2VFcnJvci5cbiAgICBpZiAoZW5jb2RpbmcgPT09IG51bGwgfHwgZW5jb2RpbmcubmFtZSA9PT0gJ3JlcGxhY2VtZW50JylcbiAgICAgIHRocm93IFJhbmdlRXJyb3IoJ1Vua25vd24gZW5jb2Rpbmc6ICcgKyBsYWJlbCk7XG4gICAgaWYgKCFkZWNvZGVyc1tlbmNvZGluZy5uYW1lXSkge1xuICAgICAgdGhyb3cgRXJyb3IoJ0RlY29kZXIgbm90IHByZXNlbnQuJyArXG4gICAgICAgICAgICAgICAgICAnIERpZCB5b3UgZm9yZ2V0IHRvIGluY2x1ZGUgZW5jb2RpbmctaW5kZXhlcy5qcyBmaXJzdD8nKTtcbiAgICB9XG5cbiAgICAvLyAzLiBMZXQgZGVjIGJlIGEgbmV3IFRleHREZWNvZGVyIG9iamVjdC5cbiAgICB2YXIgZGVjID0gdGhpcztcblxuICAgIC8vIDQuIFNldCBkZWMncyBlbmNvZGluZyB0byBlbmNvZGluZy5cbiAgICBkZWMuX2VuY29kaW5nID0gZW5jb2Rpbmc7XG5cbiAgICAvLyA1LiBJZiBvcHRpb25zJ3MgZmF0YWwgbWVtYmVyIGlzIHRydWUsIHNldCBkZWMncyBlcnJvciBtb2RlIHRvXG4gICAgLy8gZmF0YWwuXG4gICAgaWYgKEJvb2xlYW4ob3B0aW9uc1snZmF0YWwnXSkpXG4gICAgICBkZWMuX2Vycm9yX21vZGUgPSAnZmF0YWwnO1xuXG4gICAgLy8gNi4gSWYgb3B0aW9ucydzIGlnbm9yZUJPTSBtZW1iZXIgaXMgdHJ1ZSwgc2V0IGRlYydzIGlnbm9yZSBCT01cbiAgICAvLyBmbGFnLlxuICAgIGlmIChCb29sZWFuKG9wdGlvbnNbJ2lnbm9yZUJPTSddKSlcbiAgICAgIGRlYy5faWdub3JlQk9NID0gdHJ1ZTtcblxuICAgIC8vIEZvciBwcmUtRVM1IHJ1bnRpbWVzOlxuICAgIGlmICghT2JqZWN0LmRlZmluZVByb3BlcnR5KSB7XG4gICAgICB0aGlzLmVuY29kaW5nID0gZGVjLl9lbmNvZGluZy5uYW1lLnRvTG93ZXJDYXNlKCk7XG4gICAgICB0aGlzLmZhdGFsID0gZGVjLl9lcnJvcl9tb2RlID09PSAnZmF0YWwnO1xuICAgICAgdGhpcy5pZ25vcmVCT00gPSBkZWMuX2lnbm9yZUJPTTtcbiAgICB9XG5cbiAgICAvLyA3LiBSZXR1cm4gZGVjLlxuICAgIHJldHVybiBkZWM7XG4gIH1cblxuICBpZiAoT2JqZWN0LmRlZmluZVByb3BlcnR5KSB7XG4gICAgLy8gVGhlIGVuY29kaW5nIGF0dHJpYnV0ZSdzIGdldHRlciBtdXN0IHJldHVybiBlbmNvZGluZydzIG5hbWUuXG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFRleHREZWNvZGVyLnByb3RvdHlwZSwgJ2VuY29kaW5nJywge1xuICAgICAgLyoqIEB0aGlzIHtUZXh0RGVjb2Rlcn0gKi9cbiAgICAgIGdldDogZnVuY3Rpb24oKSB7IHJldHVybiB0aGlzLl9lbmNvZGluZy5uYW1lLnRvTG93ZXJDYXNlKCk7IH1cbiAgICB9KTtcblxuICAgIC8vIFRoZSBmYXRhbCBhdHRyaWJ1dGUncyBnZXR0ZXIgbXVzdCByZXR1cm4gdHJ1ZSBpZiBlcnJvciBtb2RlXG4gICAgLy8gaXMgZmF0YWwsIGFuZCBmYWxzZSBvdGhlcndpc2UuXG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KFRleHREZWNvZGVyLnByb3RvdHlwZSwgJ2ZhdGFsJywge1xuICAgICAgLyoqIEB0aGlzIHtUZXh0RGVjb2Rlcn0gKi9cbiAgICAgIGdldDogZnVuY3Rpb24oKSB7IHJldHVybiB0aGlzLl9lcnJvcl9tb2RlID09PSAnZmF0YWwnOyB9XG4gICAgfSk7XG5cbiAgICAvLyBUaGUgaWdub3JlQk9NIGF0dHJpYnV0ZSdzIGdldHRlciBtdXN0IHJldHVybiB0cnVlIGlmIGlnbm9yZVxuICAgIC8vIEJPTSBmbGFnIGlzIHNldCwgYW5kIGZhbHNlIG90aGVyd2lzZS5cbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkoVGV4dERlY29kZXIucHJvdG90eXBlLCAnaWdub3JlQk9NJywge1xuICAgICAgLyoqIEB0aGlzIHtUZXh0RGVjb2Rlcn0gKi9cbiAgICAgIGdldDogZnVuY3Rpb24oKSB7IHJldHVybiB0aGlzLl9pZ25vcmVCT007IH1cbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcGFyYW0ge0J1ZmZlclNvdXJjZT19IGlucHV0IFRoZSBidWZmZXIgb2YgYnl0ZXMgdG8gZGVjb2RlLlxuICAgKiBAcGFyYW0ge09iamVjdD19IG9wdGlvbnNcbiAgICogQHJldHVybiB7c3RyaW5nfSBUaGUgZGVjb2RlZCBzdHJpbmcuXG4gICAqL1xuICBUZXh0RGVjb2Rlci5wcm90b3R5cGUuZGVjb2RlID0gZnVuY3Rpb24gZGVjb2RlKGlucHV0LCBvcHRpb25zKSB7XG4gICAgdmFyIGJ5dGVzO1xuICAgIGlmICh0eXBlb2YgaW5wdXQgPT09ICdvYmplY3QnICYmIGlucHV0IGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHtcbiAgICAgIGJ5dGVzID0gbmV3IFVpbnQ4QXJyYXkoaW5wdXQpO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIGlucHV0ID09PSAnb2JqZWN0JyAmJiAnYnVmZmVyJyBpbiBpbnB1dCAmJlxuICAgICAgICAgICAgICAgaW5wdXQuYnVmZmVyIGluc3RhbmNlb2YgQXJyYXlCdWZmZXIpIHtcbiAgICAgIGJ5dGVzID0gbmV3IFVpbnQ4QXJyYXkoaW5wdXQuYnVmZmVyLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnB1dC5ieXRlT2Zmc2V0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnB1dC5ieXRlTGVuZ3RoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgYnl0ZXMgPSBuZXcgVWludDhBcnJheSgwKTtcbiAgICB9XG5cbiAgICBvcHRpb25zID0gVG9EaWN0aW9uYXJ5KG9wdGlvbnMpO1xuXG4gICAgLy8gMS4gSWYgdGhlIGRvIG5vdCBmbHVzaCBmbGFnIGlzIHVuc2V0LCBzZXQgZGVjb2RlciB0byBhIG5ld1xuICAgIC8vIGVuY29kaW5nJ3MgZGVjb2Rlciwgc2V0IHN0cmVhbSB0byBhIG5ldyBzdHJlYW0sIGFuZCB1bnNldCB0aGVcbiAgICAvLyBCT00gc2VlbiBmbGFnLlxuICAgIGlmICghdGhpcy5fZG9fbm90X2ZsdXNoKSB7XG4gICAgICB0aGlzLl9kZWNvZGVyID0gZGVjb2RlcnNbdGhpcy5fZW5jb2RpbmcubmFtZV0oe1xuICAgICAgICBmYXRhbDogdGhpcy5fZXJyb3JfbW9kZSA9PT0gJ2ZhdGFsJ30pO1xuICAgICAgdGhpcy5fQk9Nc2VlbiA9IGZhbHNlO1xuICAgIH1cblxuICAgIC8vIDIuIElmIG9wdGlvbnMncyBzdHJlYW0gaXMgdHJ1ZSwgc2V0IHRoZSBkbyBub3QgZmx1c2ggZmxhZywgYW5kXG4gICAgLy8gdW5zZXQgdGhlIGRvIG5vdCBmbHVzaCBmbGFnIG90aGVyd2lzZS5cbiAgICB0aGlzLl9kb19ub3RfZmx1c2ggPSBCb29sZWFuKG9wdGlvbnNbJ3N0cmVhbSddKTtcblxuICAgIC8vIDMuIElmIGlucHV0IGlzIGdpdmVuLCBwdXNoIGEgY29weSBvZiBpbnB1dCB0byBzdHJlYW0uXG4gICAgLy8gVE9ETzogQWxpZ24gd2l0aCBzcGVjIGFsZ29yaXRobSAtIG1haW50YWluIHN0cmVhbSBvbiBpbnN0YW5jZS5cbiAgICB2YXIgaW5wdXRfc3RyZWFtID0gbmV3IFN0cmVhbShieXRlcyk7XG5cbiAgICAvLyA0LiBMZXQgb3V0cHV0IGJlIGEgbmV3IHN0cmVhbS5cbiAgICB2YXIgb3V0cHV0ID0gW107XG5cbiAgICAvKiogQHR5cGUgez8obnVtYmVyfCFBcnJheS48bnVtYmVyPil9ICovXG4gICAgdmFyIHJlc3VsdDtcblxuICAgIC8vIDUuIFdoaWxlIHRydWU6XG4gICAgd2hpbGUgKHRydWUpIHtcbiAgICAgIC8vIDEuIExldCB0b2tlbiBiZSB0aGUgcmVzdWx0IG9mIHJlYWRpbmcgZnJvbSBzdHJlYW0uXG4gICAgICB2YXIgdG9rZW4gPSBpbnB1dF9zdHJlYW0ucmVhZCgpO1xuXG4gICAgICAvLyAyLiBJZiB0b2tlbiBpcyBlbmQtb2Ytc3RyZWFtIGFuZCB0aGUgZG8gbm90IGZsdXNoIGZsYWcgaXNcbiAgICAgIC8vIHNldCwgcmV0dXJuIG91dHB1dCwgc2VyaWFsaXplZC5cbiAgICAgIC8vIFRPRE86IEFsaWduIHdpdGggc3BlYyBhbGdvcml0aG0uXG4gICAgICBpZiAodG9rZW4gPT09IGVuZF9vZl9zdHJlYW0pXG4gICAgICAgIGJyZWFrO1xuXG4gICAgICAvLyAzLiBPdGhlcndpc2UsIHJ1biB0aGVzZSBzdWJzdWJzdGVwczpcblxuICAgICAgLy8gMS4gTGV0IHJlc3VsdCBiZSB0aGUgcmVzdWx0IG9mIHByb2Nlc3NpbmcgdG9rZW4gZm9yIGRlY29kZXIsXG4gICAgICAvLyBzdHJlYW0sIG91dHB1dCwgYW5kIGVycm9yIG1vZGUuXG4gICAgICByZXN1bHQgPSB0aGlzLl9kZWNvZGVyLmhhbmRsZXIoaW5wdXRfc3RyZWFtLCB0b2tlbik7XG5cbiAgICAgIC8vIDIuIElmIHJlc3VsdCBpcyBmaW5pc2hlZCwgcmV0dXJuIG91dHB1dCwgc2VyaWFsaXplZC5cbiAgICAgIGlmIChyZXN1bHQgPT09IGZpbmlzaGVkKVxuICAgICAgICBicmVhaztcblxuICAgICAgaWYgKHJlc3VsdCAhPT0gbnVsbCkge1xuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShyZXN1bHQpKVxuICAgICAgICAgIG91dHB1dC5wdXNoLmFwcGx5KG91dHB1dCwgLyoqQHR5cGUgeyFBcnJheS48bnVtYmVyPn0qLyhyZXN1bHQpKTtcbiAgICAgICAgZWxzZVxuICAgICAgICAgIG91dHB1dC5wdXNoKHJlc3VsdCk7XG4gICAgICB9XG5cbiAgICAgIC8vIDMuIE90aGVyd2lzZSwgaWYgcmVzdWx0IGlzIGVycm9yLCB0aHJvdyBhIFR5cGVFcnJvci5cbiAgICAgIC8vIChUaHJvd24gaW4gaGFuZGxlcilcblxuICAgICAgLy8gNC4gT3RoZXJ3aXNlLCBkbyBub3RoaW5nLlxuICAgIH1cbiAgICAvLyBUT0RPOiBBbGlnbiB3aXRoIHNwZWMgYWxnb3JpdGhtLlxuICAgIGlmICghdGhpcy5fZG9fbm90X2ZsdXNoKSB7XG4gICAgICBkbyB7XG4gICAgICAgIHJlc3VsdCA9IHRoaXMuX2RlY29kZXIuaGFuZGxlcihpbnB1dF9zdHJlYW0sIGlucHV0X3N0cmVhbS5yZWFkKCkpO1xuICAgICAgICBpZiAocmVzdWx0ID09PSBmaW5pc2hlZClcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgaWYgKHJlc3VsdCA9PT0gbnVsbClcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkocmVzdWx0KSlcbiAgICAgICAgICBvdXRwdXQucHVzaC5hcHBseShvdXRwdXQsIC8qKkB0eXBlIHshQXJyYXkuPG51bWJlcj59Ki8ocmVzdWx0KSk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICBvdXRwdXQucHVzaChyZXN1bHQpO1xuICAgICAgfSB3aGlsZSAoIWlucHV0X3N0cmVhbS5lbmRPZlN0cmVhbSgpKTtcbiAgICAgIHRoaXMuX2RlY29kZXIgPSBudWxsO1xuICAgIH1cblxuICAgIC8vIEEgVGV4dERlY29kZXIgb2JqZWN0IGFsc28gaGFzIGFuIGFzc29jaWF0ZWQgc2VyaWFsaXplIHN0cmVhbVxuICAgIC8vIGFsZ29yaXRobS4uLlxuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7IUFycmF5LjxudW1iZXI+fSBzdHJlYW1cbiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9XG4gICAgICogQHRoaXMge1RleHREZWNvZGVyfVxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHNlcmlhbGl6ZVN0cmVhbShzdHJlYW0pIHtcbiAgICAgIC8vIDEuIExldCB0b2tlbiBiZSB0aGUgcmVzdWx0IG9mIHJlYWRpbmcgZnJvbSBzdHJlYW0uXG4gICAgICAvLyAoRG9uZSBpbi1wbGFjZSBvbiBhcnJheSwgcmF0aGVyIHRoYW4gYXMgYSBzdHJlYW0pXG5cbiAgICAgIC8vIDIuIElmIGVuY29kaW5nIGlzIFVURi04LCBVVEYtMTZCRSwgb3IgVVRGLTE2TEUsIGFuZCBpZ25vcmVcbiAgICAgIC8vIEJPTSBmbGFnIGFuZCBCT00gc2VlbiBmbGFnIGFyZSB1bnNldCwgcnVuIHRoZXNlIHN1YnN1YnN0ZXBzOlxuICAgICAgaWYgKGluY2x1ZGVzKFsnVVRGLTgnLCAnVVRGLTE2TEUnLCAnVVRGLTE2QkUnXSwgdGhpcy5fZW5jb2RpbmcubmFtZSkgJiZcbiAgICAgICAgICAhdGhpcy5faWdub3JlQk9NICYmICF0aGlzLl9CT01zZWVuKSB7XG4gICAgICAgIGlmIChzdHJlYW0ubGVuZ3RoID4gMCAmJiBzdHJlYW1bMF0gPT09IDB4RkVGRikge1xuICAgICAgICAgIC8vIDEuIElmIHRva2VuIGlzIFUrRkVGRiwgc2V0IEJPTSBzZWVuIGZsYWcuXG4gICAgICAgICAgdGhpcy5fQk9Nc2VlbiA9IHRydWU7XG4gICAgICAgICAgc3RyZWFtLnNoaWZ0KCk7XG4gICAgICAgIH0gZWxzZSBpZiAoc3RyZWFtLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAvLyAyLiBPdGhlcndpc2UsIGlmIHRva2VuIGlzIG5vdCBlbmQtb2Ytc3RyZWFtLCBzZXQgQk9NIHNlZW5cbiAgICAgICAgICAvLyBmbGFnIGFuZCBhcHBlbmQgdG9rZW4gdG8gc3RyZWFtLlxuICAgICAgICAgIHRoaXMuX0JPTXNlZW4gPSB0cnVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIDMuIE90aGVyd2lzZSwgaWYgdG9rZW4gaXMgbm90IGVuZC1vZi1zdHJlYW0sIGFwcGVuZCB0b2tlblxuICAgICAgICAgIC8vIHRvIG91dHB1dC5cbiAgICAgICAgICAvLyAobm8tb3ApXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIC8vIDQuIE90aGVyd2lzZSwgcmV0dXJuIG91dHB1dC5cbiAgICAgIHJldHVybiBjb2RlUG9pbnRzVG9TdHJpbmcoc3RyZWFtKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc2VyaWFsaXplU3RyZWFtLmNhbGwodGhpcywgb3V0cHV0KTtcbiAgfTtcblxuICAvLyA4LjIgSW50ZXJmYWNlIFRleHRFbmNvZGVyXG5cbiAgLyoqXG4gICAqIEBjb25zdHJ1Y3RvclxuICAgKiBAcGFyYW0ge3N0cmluZz19IGxhYmVsIFRoZSBsYWJlbCBvZiB0aGUgZW5jb2RpbmcuIE5PTlNUQU5EQVJELlxuICAgKiBAcGFyYW0ge09iamVjdD19IG9wdGlvbnMgTk9OU1RBTkRBUkQuXG4gICAqL1xuICBmdW5jdGlvbiBUZXh0RW5jb2RlcihsYWJlbCwgb3B0aW9ucykge1xuICAgIC8vIFdlYiBJREwgY29udmVudGlvbnNcbiAgICBpZiAoISh0aGlzIGluc3RhbmNlb2YgVGV4dEVuY29kZXIpKVxuICAgICAgdGhyb3cgVHlwZUVycm9yKCdDYWxsZWQgYXMgYSBmdW5jdGlvbi4gRGlkIHlvdSBmb3JnZXQgXFwnbmV3XFwnPycpO1xuICAgIG9wdGlvbnMgPSBUb0RpY3Rpb25hcnkob3B0aW9ucyk7XG5cbiAgICAvLyBBIFRleHRFbmNvZGVyIG9iamVjdCBoYXMgYW4gYXNzb2NpYXRlZCBlbmNvZGluZyBhbmQgZW5jb2Rlci5cblxuICAgIC8qKiBAcHJpdmF0ZSAqL1xuICAgIHRoaXMuX2VuY29kaW5nID0gbnVsbDtcbiAgICAvKiogQHByaXZhdGUgQHR5cGUgez9FbmNvZGVyfSAqL1xuICAgIHRoaXMuX2VuY29kZXIgPSBudWxsO1xuXG4gICAgLy8gTm9uLXN0YW5kYXJkXG4gICAgLyoqIEBwcml2YXRlIEB0eXBlIHtib29sZWFufSAqL1xuICAgIHRoaXMuX2RvX25vdF9mbHVzaCA9IGZhbHNlO1xuICAgIC8qKiBAcHJpdmF0ZSBAdHlwZSB7c3RyaW5nfSAqL1xuICAgIHRoaXMuX2ZhdGFsID0gQm9vbGVhbihvcHRpb25zWydmYXRhbCddKSA/ICdmYXRhbCcgOiAncmVwbGFjZW1lbnQnO1xuXG4gICAgLy8gMS4gTGV0IGVuYyBiZSBhIG5ldyBUZXh0RW5jb2RlciBvYmplY3QuXG4gICAgdmFyIGVuYyA9IHRoaXM7XG5cbiAgICAvLyAyLiBTZXQgZW5jJ3MgZW5jb2RpbmcgdG8gVVRGLTgncyBlbmNvZGVyLlxuICAgIGlmIChCb29sZWFuKG9wdGlvbnNbJ05PTlNUQU5EQVJEX2FsbG93TGVnYWN5RW5jb2RpbmcnXSkpIHtcbiAgICAgIC8vIE5PTlNUQU5EQVJEIGJlaGF2aW9yLlxuICAgICAgbGFiZWwgPSBsYWJlbCAhPT0gdW5kZWZpbmVkID8gU3RyaW5nKGxhYmVsKSA6IERFRkFVTFRfRU5DT0RJTkc7XG4gICAgICB2YXIgZW5jb2RpbmcgPSBnZXRFbmNvZGluZyhsYWJlbCk7XG4gICAgICBpZiAoZW5jb2RpbmcgPT09IG51bGwgfHwgZW5jb2RpbmcubmFtZSA9PT0gJ3JlcGxhY2VtZW50JylcbiAgICAgICAgdGhyb3cgUmFuZ2VFcnJvcignVW5rbm93biBlbmNvZGluZzogJyArIGxhYmVsKTtcbiAgICAgIGlmICghZW5jb2RlcnNbZW5jb2RpbmcubmFtZV0pIHtcbiAgICAgICAgdGhyb3cgRXJyb3IoJ0VuY29kZXIgbm90IHByZXNlbnQuJyArXG4gICAgICAgICAgICAgICAgICAgICcgRGlkIHlvdSBmb3JnZXQgdG8gaW5jbHVkZSBlbmNvZGluZy1pbmRleGVzLmpzIGZpcnN0PycpO1xuICAgICAgfVxuICAgICAgZW5jLl9lbmNvZGluZyA9IGVuY29kaW5nO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBTdGFuZGFyZCBiZWhhdmlvci5cbiAgICAgIGVuYy5fZW5jb2RpbmcgPSBnZXRFbmNvZGluZygndXRmLTgnKTtcblxuICAgICAgaWYgKGxhYmVsICE9PSB1bmRlZmluZWQgJiYgJ2NvbnNvbGUnIGluIGdsb2JhbCkge1xuICAgICAgICBjb25zb2xlLndhcm4oJ1RleHRFbmNvZGVyIGNvbnN0cnVjdG9yIGNhbGxlZCB3aXRoIGVuY29kaW5nIGxhYmVsLCAnXG4gICAgICAgICAgICAgICAgICAgICArICd3aGljaCBpcyBpZ25vcmVkLicpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEZvciBwcmUtRVM1IHJ1bnRpbWVzOlxuICAgIGlmICghT2JqZWN0LmRlZmluZVByb3BlcnR5KVxuICAgICAgdGhpcy5lbmNvZGluZyA9IGVuYy5fZW5jb2RpbmcubmFtZS50b0xvd2VyQ2FzZSgpO1xuXG4gICAgLy8gMy4gUmV0dXJuIGVuYy5cbiAgICByZXR1cm4gZW5jO1xuICB9XG5cbiAgaWYgKE9iamVjdC5kZWZpbmVQcm9wZXJ0eSkge1xuICAgIC8vIFRoZSBlbmNvZGluZyBhdHRyaWJ1dGUncyBnZXR0ZXIgbXVzdCByZXR1cm4gZW5jb2RpbmcncyBuYW1lLlxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShUZXh0RW5jb2Rlci5wcm90b3R5cGUsICdlbmNvZGluZycsIHtcbiAgICAgIC8qKiBAdGhpcyB7VGV4dEVuY29kZXJ9ICovXG4gICAgICBnZXQ6IGZ1bmN0aW9uKCkgeyByZXR1cm4gdGhpcy5fZW5jb2RpbmcubmFtZS50b0xvd2VyQ2FzZSgpOyB9XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQHBhcmFtIHtzdHJpbmc9fSBvcHRfc3RyaW5nIFRoZSBzdHJpbmcgdG8gZW5jb2RlLlxuICAgKiBAcGFyYW0ge09iamVjdD19IG9wdGlvbnNcbiAgICogQHJldHVybiB7IVVpbnQ4QXJyYXl9IEVuY29kZWQgYnl0ZXMsIGFzIGEgVWludDhBcnJheS5cbiAgICovXG4gIFRleHRFbmNvZGVyLnByb3RvdHlwZS5lbmNvZGUgPSBmdW5jdGlvbiBlbmNvZGUob3B0X3N0cmluZywgb3B0aW9ucykge1xuICAgIG9wdF9zdHJpbmcgPSBvcHRfc3RyaW5nID09PSB1bmRlZmluZWQgPyAnJyA6IFN0cmluZyhvcHRfc3RyaW5nKTtcbiAgICBvcHRpb25zID0gVG9EaWN0aW9uYXJ5KG9wdGlvbnMpO1xuXG4gICAgLy8gTk9URTogVGhpcyBvcHRpb24gaXMgbm9uc3RhbmRhcmQuIE5vbmUgb2YgdGhlIGVuY29kaW5nc1xuICAgIC8vIHBlcm1pdHRlZCBmb3IgZW5jb2RpbmcgKGkuZS4gVVRGLTgsIFVURi0xNikgYXJlIHN0YXRlZnVsIHdoZW5cbiAgICAvLyB0aGUgaW5wdXQgaXMgYSBVU1ZTdHJpbmcgc28gc3RyZWFtaW5nIGlzIG5vdCBuZWNlc3NhcnkuXG4gICAgaWYgKCF0aGlzLl9kb19ub3RfZmx1c2gpXG4gICAgICB0aGlzLl9lbmNvZGVyID0gZW5jb2RlcnNbdGhpcy5fZW5jb2RpbmcubmFtZV0oe1xuICAgICAgICBmYXRhbDogdGhpcy5fZmF0YWwgPT09ICdmYXRhbCd9KTtcbiAgICB0aGlzLl9kb19ub3RfZmx1c2ggPSBCb29sZWFuKG9wdGlvbnNbJ3N0cmVhbSddKTtcblxuICAgIC8vIDEuIENvbnZlcnQgaW5wdXQgdG8gYSBzdHJlYW0uXG4gICAgdmFyIGlucHV0ID0gbmV3IFN0cmVhbShzdHJpbmdUb0NvZGVQb2ludHMob3B0X3N0cmluZykpO1xuXG4gICAgLy8gMi4gTGV0IG91dHB1dCBiZSBhIG5ldyBzdHJlYW1cbiAgICB2YXIgb3V0cHV0ID0gW107XG5cbiAgICAvKiogQHR5cGUgez8obnVtYmVyfCFBcnJheS48bnVtYmVyPil9ICovXG4gICAgdmFyIHJlc3VsdDtcbiAgICAvLyAzLiBXaGlsZSB0cnVlLCBydW4gdGhlc2Ugc3Vic3RlcHM6XG4gICAgd2hpbGUgKHRydWUpIHtcbiAgICAgIC8vIDEuIExldCB0b2tlbiBiZSB0aGUgcmVzdWx0IG9mIHJlYWRpbmcgZnJvbSBpbnB1dC5cbiAgICAgIHZhciB0b2tlbiA9IGlucHV0LnJlYWQoKTtcbiAgICAgIGlmICh0b2tlbiA9PT0gZW5kX29mX3N0cmVhbSlcbiAgICAgICAgYnJlYWs7XG4gICAgICAvLyAyLiBMZXQgcmVzdWx0IGJlIHRoZSByZXN1bHQgb2YgcHJvY2Vzc2luZyB0b2tlbiBmb3IgZW5jb2RlcixcbiAgICAgIC8vIGlucHV0LCBvdXRwdXQuXG4gICAgICByZXN1bHQgPSB0aGlzLl9lbmNvZGVyLmhhbmRsZXIoaW5wdXQsIHRva2VuKTtcbiAgICAgIGlmIChyZXN1bHQgPT09IGZpbmlzaGVkKVxuICAgICAgICBicmVhaztcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KHJlc3VsdCkpXG4gICAgICAgIG91dHB1dC5wdXNoLmFwcGx5KG91dHB1dCwgLyoqQHR5cGUgeyFBcnJheS48bnVtYmVyPn0qLyhyZXN1bHQpKTtcbiAgICAgIGVsc2VcbiAgICAgICAgb3V0cHV0LnB1c2gocmVzdWx0KTtcbiAgICB9XG4gICAgLy8gVE9ETzogQWxpZ24gd2l0aCBzcGVjIGFsZ29yaXRobS5cbiAgICBpZiAoIXRoaXMuX2RvX25vdF9mbHVzaCkge1xuICAgICAgd2hpbGUgKHRydWUpIHtcbiAgICAgICAgcmVzdWx0ID0gdGhpcy5fZW5jb2Rlci5oYW5kbGVyKGlucHV0LCBpbnB1dC5yZWFkKCkpO1xuICAgICAgICBpZiAocmVzdWx0ID09PSBmaW5pc2hlZClcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkocmVzdWx0KSlcbiAgICAgICAgICBvdXRwdXQucHVzaC5hcHBseShvdXRwdXQsIC8qKkB0eXBlIHshQXJyYXkuPG51bWJlcj59Ki8ocmVzdWx0KSk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICBvdXRwdXQucHVzaChyZXN1bHQpO1xuICAgICAgfVxuICAgICAgdGhpcy5fZW5jb2RlciA9IG51bGw7XG4gICAgfVxuICAgIC8vIDMuIElmIHJlc3VsdCBpcyBmaW5pc2hlZCwgY29udmVydCBvdXRwdXQgaW50byBhIGJ5dGUgc2VxdWVuY2UsXG4gICAgLy8gYW5kIHRoZW4gcmV0dXJuIGEgVWludDhBcnJheSBvYmplY3Qgd3JhcHBpbmcgYW4gQXJyYXlCdWZmZXJcbiAgICAvLyBjb250YWluaW5nIG91dHB1dC5cbiAgICByZXR1cm4gbmV3IFVpbnQ4QXJyYXkob3V0cHV0KTtcbiAgfTtcblxuXG4gIC8vXG4gIC8vIDkuIFRoZSBlbmNvZGluZ1xuICAvL1xuXG4gIC8vIDkuMSB1dGYtOFxuXG4gIC8vIDkuMS4xIHV0Zi04IGRlY29kZXJcbiAgLyoqXG4gICAqIEBjb25zdHJ1Y3RvclxuICAgKiBAaW1wbGVtZW50cyB7RGVjb2Rlcn1cbiAgICogQHBhcmFtIHt7ZmF0YWw6IGJvb2xlYW59fSBvcHRpb25zXG4gICAqL1xuICBmdW5jdGlvbiBVVEY4RGVjb2RlcihvcHRpb25zKSB7XG4gICAgdmFyIGZhdGFsID0gb3B0aW9ucy5mYXRhbDtcblxuICAgIC8vIHV0Zi04J3MgZGVjb2RlcidzIGhhcyBhbiBhc3NvY2lhdGVkIHV0Zi04IGNvZGUgcG9pbnQsIHV0Zi04XG4gICAgLy8gYnl0ZXMgc2VlbiwgYW5kIHV0Zi04IGJ5dGVzIG5lZWRlZCAoYWxsIGluaXRpYWxseSAwKSwgYSB1dGYtOFxuICAgIC8vIGxvd2VyIGJvdW5kYXJ5IChpbml0aWFsbHkgMHg4MCksIGFuZCBhIHV0Zi04IHVwcGVyIGJvdW5kYXJ5XG4gICAgLy8gKGluaXRpYWxseSAweEJGKS5cbiAgICB2YXIgLyoqIEB0eXBlIHtudW1iZXJ9ICovIHV0ZjhfY29kZV9wb2ludCA9IDAsXG4gICAgICAgIC8qKiBAdHlwZSB7bnVtYmVyfSAqLyB1dGY4X2J5dGVzX3NlZW4gPSAwLFxuICAgICAgICAvKiogQHR5cGUge251bWJlcn0gKi8gdXRmOF9ieXRlc19uZWVkZWQgPSAwLFxuICAgICAgICAvKiogQHR5cGUge251bWJlcn0gKi8gdXRmOF9sb3dlcl9ib3VuZGFyeSA9IDB4ODAsXG4gICAgICAgIC8qKiBAdHlwZSB7bnVtYmVyfSAqLyB1dGY4X3VwcGVyX2JvdW5kYXJ5ID0gMHhCRjtcblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7U3RyZWFtfSBzdHJlYW0gVGhlIHN0cmVhbSBvZiBieXRlcyBiZWluZyBkZWNvZGVkLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBiaXRlIFRoZSBuZXh0IGJ5dGUgcmVhZCBmcm9tIHRoZSBzdHJlYW0uXG4gICAgICogQHJldHVybiB7PyhudW1iZXJ8IUFycmF5LjxudW1iZXI+KX0gVGhlIG5leHQgY29kZSBwb2ludChzKVxuICAgICAqICAgICBkZWNvZGVkLCBvciBudWxsIGlmIG5vdCBlbm91Z2ggZGF0YSBleGlzdHMgaW4gdGhlIGlucHV0XG4gICAgICogICAgIHN0cmVhbSB0byBkZWNvZGUgYSBjb21wbGV0ZSBjb2RlIHBvaW50LlxuICAgICAqL1xuICAgIHRoaXMuaGFuZGxlciA9IGZ1bmN0aW9uKHN0cmVhbSwgYml0ZSkge1xuICAgICAgLy8gMS4gSWYgYnl0ZSBpcyBlbmQtb2Ytc3RyZWFtIGFuZCB1dGYtOCBieXRlcyBuZWVkZWQgaXMgbm90IDAsXG4gICAgICAvLyBzZXQgdXRmLTggYnl0ZXMgbmVlZGVkIHRvIDAgYW5kIHJldHVybiBlcnJvci5cbiAgICAgIGlmIChiaXRlID09PSBlbmRfb2Zfc3RyZWFtICYmIHV0ZjhfYnl0ZXNfbmVlZGVkICE9PSAwKSB7XG4gICAgICAgIHV0ZjhfYnl0ZXNfbmVlZGVkID0gMDtcbiAgICAgICAgcmV0dXJuIGRlY29kZXJFcnJvcihmYXRhbCk7XG4gICAgICB9XG5cbiAgICAgIC8vIDIuIElmIGJ5dGUgaXMgZW5kLW9mLXN0cmVhbSwgcmV0dXJuIGZpbmlzaGVkLlxuICAgICAgaWYgKGJpdGUgPT09IGVuZF9vZl9zdHJlYW0pXG4gICAgICAgIHJldHVybiBmaW5pc2hlZDtcblxuICAgICAgLy8gMy4gSWYgdXRmLTggYnl0ZXMgbmVlZGVkIGlzIDAsIGJhc2VkIG9uIGJ5dGU6XG4gICAgICBpZiAodXRmOF9ieXRlc19uZWVkZWQgPT09IDApIHtcblxuICAgICAgICAvLyAweDAwIHRvIDB4N0ZcbiAgICAgICAgaWYgKGluUmFuZ2UoYml0ZSwgMHgwMCwgMHg3RikpIHtcbiAgICAgICAgICAvLyBSZXR1cm4gYSBjb2RlIHBvaW50IHdob3NlIHZhbHVlIGlzIGJ5dGUuXG4gICAgICAgICAgcmV0dXJuIGJpdGU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyAweEMyIHRvIDB4REZcbiAgICAgICAgZWxzZSBpZiAoaW5SYW5nZShiaXRlLCAweEMyLCAweERGKSkge1xuICAgICAgICAgIC8vIDEuIFNldCB1dGYtOCBieXRlcyBuZWVkZWQgdG8gMS5cbiAgICAgICAgICB1dGY4X2J5dGVzX25lZWRlZCA9IDE7XG5cbiAgICAgICAgICAvLyAyLiBTZXQgVVRGLTggY29kZSBwb2ludCB0byBieXRlICYgMHgxRi5cbiAgICAgICAgICB1dGY4X2NvZGVfcG9pbnQgPSBiaXRlICYgMHgxRjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIDB4RTAgdG8gMHhFRlxuICAgICAgICBlbHNlIGlmIChpblJhbmdlKGJpdGUsIDB4RTAsIDB4RUYpKSB7XG4gICAgICAgICAgLy8gMS4gSWYgYnl0ZSBpcyAweEUwLCBzZXQgdXRmLTggbG93ZXIgYm91bmRhcnkgdG8gMHhBMC5cbiAgICAgICAgICBpZiAoYml0ZSA9PT0gMHhFMClcbiAgICAgICAgICAgIHV0ZjhfbG93ZXJfYm91bmRhcnkgPSAweEEwO1xuICAgICAgICAgIC8vIDIuIElmIGJ5dGUgaXMgMHhFRCwgc2V0IHV0Zi04IHVwcGVyIGJvdW5kYXJ5IHRvIDB4OUYuXG4gICAgICAgICAgaWYgKGJpdGUgPT09IDB4RUQpXG4gICAgICAgICAgICB1dGY4X3VwcGVyX2JvdW5kYXJ5ID0gMHg5RjtcbiAgICAgICAgICAvLyAzLiBTZXQgdXRmLTggYnl0ZXMgbmVlZGVkIHRvIDIuXG4gICAgICAgICAgdXRmOF9ieXRlc19uZWVkZWQgPSAyO1xuICAgICAgICAgIC8vIDQuIFNldCBVVEYtOCBjb2RlIHBvaW50IHRvIGJ5dGUgJiAweEYuXG4gICAgICAgICAgdXRmOF9jb2RlX3BvaW50ID0gYml0ZSAmIDB4RjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIDB4RjAgdG8gMHhGNFxuICAgICAgICBlbHNlIGlmIChpblJhbmdlKGJpdGUsIDB4RjAsIDB4RjQpKSB7XG4gICAgICAgICAgLy8gMS4gSWYgYnl0ZSBpcyAweEYwLCBzZXQgdXRmLTggbG93ZXIgYm91bmRhcnkgdG8gMHg5MC5cbiAgICAgICAgICBpZiAoYml0ZSA9PT0gMHhGMClcbiAgICAgICAgICAgIHV0ZjhfbG93ZXJfYm91bmRhcnkgPSAweDkwO1xuICAgICAgICAgIC8vIDIuIElmIGJ5dGUgaXMgMHhGNCwgc2V0IHV0Zi04IHVwcGVyIGJvdW5kYXJ5IHRvIDB4OEYuXG4gICAgICAgICAgaWYgKGJpdGUgPT09IDB4RjQpXG4gICAgICAgICAgICB1dGY4X3VwcGVyX2JvdW5kYXJ5ID0gMHg4RjtcbiAgICAgICAgICAvLyAzLiBTZXQgdXRmLTggYnl0ZXMgbmVlZGVkIHRvIDMuXG4gICAgICAgICAgdXRmOF9ieXRlc19uZWVkZWQgPSAzO1xuICAgICAgICAgIC8vIDQuIFNldCBVVEYtOCBjb2RlIHBvaW50IHRvIGJ5dGUgJiAweDcuXG4gICAgICAgICAgdXRmOF9jb2RlX3BvaW50ID0gYml0ZSAmIDB4NztcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE90aGVyd2lzZVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAvLyBSZXR1cm4gZXJyb3IuXG4gICAgICAgICAgcmV0dXJuIGRlY29kZXJFcnJvcihmYXRhbCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBSZXR1cm4gY29udGludWUuXG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICAvLyA0LiBJZiBieXRlIGlzIG5vdCBpbiB0aGUgcmFuZ2UgdXRmLTggbG93ZXIgYm91bmRhcnkgdG8gdXRmLThcbiAgICAgIC8vIHVwcGVyIGJvdW5kYXJ5LCBpbmNsdXNpdmUsIHJ1biB0aGVzZSBzdWJzdGVwczpcbiAgICAgIGlmICghaW5SYW5nZShiaXRlLCB1dGY4X2xvd2VyX2JvdW5kYXJ5LCB1dGY4X3VwcGVyX2JvdW5kYXJ5KSkge1xuXG4gICAgICAgIC8vIDEuIFNldCB1dGYtOCBjb2RlIHBvaW50LCB1dGYtOCBieXRlcyBuZWVkZWQsIGFuZCB1dGYtOFxuICAgICAgICAvLyBieXRlcyBzZWVuIHRvIDAsIHNldCB1dGYtOCBsb3dlciBib3VuZGFyeSB0byAweDgwLCBhbmQgc2V0XG4gICAgICAgIC8vIHV0Zi04IHVwcGVyIGJvdW5kYXJ5IHRvIDB4QkYuXG4gICAgICAgIHV0ZjhfY29kZV9wb2ludCA9IHV0ZjhfYnl0ZXNfbmVlZGVkID0gdXRmOF9ieXRlc19zZWVuID0gMDtcbiAgICAgICAgdXRmOF9sb3dlcl9ib3VuZGFyeSA9IDB4ODA7XG4gICAgICAgIHV0ZjhfdXBwZXJfYm91bmRhcnkgPSAweEJGO1xuXG4gICAgICAgIC8vIDIuIFByZXBlbmQgYnl0ZSB0byBzdHJlYW0uXG4gICAgICAgIHN0cmVhbS5wcmVwZW5kKGJpdGUpO1xuXG4gICAgICAgIC8vIDMuIFJldHVybiBlcnJvci5cbiAgICAgICAgcmV0dXJuIGRlY29kZXJFcnJvcihmYXRhbCk7XG4gICAgICB9XG5cbiAgICAgIC8vIDUuIFNldCB1dGYtOCBsb3dlciBib3VuZGFyeSB0byAweDgwIGFuZCB1dGYtOCB1cHBlciBib3VuZGFyeVxuICAgICAgLy8gdG8gMHhCRi5cbiAgICAgIHV0ZjhfbG93ZXJfYm91bmRhcnkgPSAweDgwO1xuICAgICAgdXRmOF91cHBlcl9ib3VuZGFyeSA9IDB4QkY7XG5cbiAgICAgIC8vIDYuIFNldCBVVEYtOCBjb2RlIHBvaW50IHRvIChVVEYtOCBjb2RlIHBvaW50IDw8IDYpIHwgKGJ5dGUgJlxuICAgICAgLy8gMHgzRilcbiAgICAgIHV0ZjhfY29kZV9wb2ludCA9ICh1dGY4X2NvZGVfcG9pbnQgPDwgNikgfCAoYml0ZSAmIDB4M0YpO1xuXG4gICAgICAvLyA3LiBJbmNyZWFzZSB1dGYtOCBieXRlcyBzZWVuIGJ5IG9uZS5cbiAgICAgIHV0ZjhfYnl0ZXNfc2VlbiArPSAxO1xuXG4gICAgICAvLyA4LiBJZiB1dGYtOCBieXRlcyBzZWVuIGlzIG5vdCBlcXVhbCB0byB1dGYtOCBieXRlcyBuZWVkZWQsXG4gICAgICAvLyBjb250aW51ZS5cbiAgICAgIGlmICh1dGY4X2J5dGVzX3NlZW4gIT09IHV0ZjhfYnl0ZXNfbmVlZGVkKVxuICAgICAgICByZXR1cm4gbnVsbDtcblxuICAgICAgLy8gOS4gTGV0IGNvZGUgcG9pbnQgYmUgdXRmLTggY29kZSBwb2ludC5cbiAgICAgIHZhciBjb2RlX3BvaW50ID0gdXRmOF9jb2RlX3BvaW50O1xuXG4gICAgICAvLyAxMC4gU2V0IHV0Zi04IGNvZGUgcG9pbnQsIHV0Zi04IGJ5dGVzIG5lZWRlZCwgYW5kIHV0Zi04IGJ5dGVzXG4gICAgICAvLyBzZWVuIHRvIDAuXG4gICAgICB1dGY4X2NvZGVfcG9pbnQgPSB1dGY4X2J5dGVzX25lZWRlZCA9IHV0ZjhfYnl0ZXNfc2VlbiA9IDA7XG5cbiAgICAgIC8vIDExLiBSZXR1cm4gYSBjb2RlIHBvaW50IHdob3NlIHZhbHVlIGlzIGNvZGUgcG9pbnQuXG4gICAgICByZXR1cm4gY29kZV9wb2ludDtcbiAgICB9O1xuICB9XG5cbiAgLy8gOS4xLjIgdXRmLTggZW5jb2RlclxuICAvKipcbiAgICogQGNvbnN0cnVjdG9yXG4gICAqIEBpbXBsZW1lbnRzIHtFbmNvZGVyfVxuICAgKiBAcGFyYW0ge3tmYXRhbDogYm9vbGVhbn19IG9wdGlvbnNcbiAgICovXG4gIGZ1bmN0aW9uIFVURjhFbmNvZGVyKG9wdGlvbnMpIHtcbiAgICB2YXIgZmF0YWwgPSBvcHRpb25zLmZhdGFsO1xuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7U3RyZWFtfSBzdHJlYW0gSW5wdXQgc3RyZWFtLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBjb2RlX3BvaW50IE5leHQgY29kZSBwb2ludCByZWFkIGZyb20gdGhlIHN0cmVhbS5cbiAgICAgKiBAcmV0dXJuIHsobnVtYmVyfCFBcnJheS48bnVtYmVyPil9IEJ5dGUocykgdG8gZW1pdC5cbiAgICAgKi9cbiAgICB0aGlzLmhhbmRsZXIgPSBmdW5jdGlvbihzdHJlYW0sIGNvZGVfcG9pbnQpIHtcbiAgICAgIC8vIDEuIElmIGNvZGUgcG9pbnQgaXMgZW5kLW9mLXN0cmVhbSwgcmV0dXJuIGZpbmlzaGVkLlxuICAgICAgaWYgKGNvZGVfcG9pbnQgPT09IGVuZF9vZl9zdHJlYW0pXG4gICAgICAgIHJldHVybiBmaW5pc2hlZDtcblxuICAgICAgLy8gMi4gSWYgY29kZSBwb2ludCBpcyBhbiBBU0NJSSBjb2RlIHBvaW50LCByZXR1cm4gYSBieXRlIHdob3NlXG4gICAgICAvLyB2YWx1ZSBpcyBjb2RlIHBvaW50LlxuICAgICAgaWYgKGlzQVNDSUlDb2RlUG9pbnQoY29kZV9wb2ludCkpXG4gICAgICAgIHJldHVybiBjb2RlX3BvaW50O1xuXG4gICAgICAvLyAzLiBTZXQgY291bnQgYW5kIG9mZnNldCBiYXNlZCBvbiB0aGUgcmFuZ2UgY29kZSBwb2ludCBpcyBpbjpcbiAgICAgIHZhciBjb3VudCwgb2Zmc2V0O1xuICAgICAgLy8gVSswMDgwIHRvIFUrMDdGRiwgaW5jbHVzaXZlOlxuICAgICAgaWYgKGluUmFuZ2UoY29kZV9wb2ludCwgMHgwMDgwLCAweDA3RkYpKSB7XG4gICAgICAgIC8vIDEgYW5kIDB4QzBcbiAgICAgICAgY291bnQgPSAxO1xuICAgICAgICBvZmZzZXQgPSAweEMwO1xuICAgICAgfVxuICAgICAgLy8gVSswODAwIHRvIFUrRkZGRiwgaW5jbHVzaXZlOlxuICAgICAgZWxzZSBpZiAoaW5SYW5nZShjb2RlX3BvaW50LCAweDA4MDAsIDB4RkZGRikpIHtcbiAgICAgICAgLy8gMiBhbmQgMHhFMFxuICAgICAgICBjb3VudCA9IDI7XG4gICAgICAgIG9mZnNldCA9IDB4RTA7XG4gICAgICB9XG4gICAgICAvLyBVKzEwMDAwIHRvIFUrMTBGRkZGLCBpbmNsdXNpdmU6XG4gICAgICBlbHNlIGlmIChpblJhbmdlKGNvZGVfcG9pbnQsIDB4MTAwMDAsIDB4MTBGRkZGKSkge1xuICAgICAgICAvLyAzIGFuZCAweEYwXG4gICAgICAgIGNvdW50ID0gMztcbiAgICAgICAgb2Zmc2V0ID0gMHhGMDtcbiAgICAgIH1cblxuICAgICAgLy8gNC4gTGV0IGJ5dGVzIGJlIGEgYnl0ZSBzZXF1ZW5jZSB3aG9zZSBmaXJzdCBieXRlIGlzIChjb2RlXG4gICAgICAvLyBwb2ludCA+PiAoNiDDlyBjb3VudCkpICsgb2Zmc2V0LlxuICAgICAgdmFyIGJ5dGVzID0gWyhjb2RlX3BvaW50ID4+ICg2ICogY291bnQpKSArIG9mZnNldF07XG5cbiAgICAgIC8vIDUuIFJ1biB0aGVzZSBzdWJzdGVwcyB3aGlsZSBjb3VudCBpcyBncmVhdGVyIHRoYW4gMDpcbiAgICAgIHdoaWxlIChjb3VudCA+IDApIHtcblxuICAgICAgICAvLyAxLiBTZXQgdGVtcCB0byBjb2RlIHBvaW50ID4+ICg2IMOXIChjb3VudCDiiJIgMSkpLlxuICAgICAgICB2YXIgdGVtcCA9IGNvZGVfcG9pbnQgPj4gKDYgKiAoY291bnQgLSAxKSk7XG5cbiAgICAgICAgLy8gMi4gQXBwZW5kIHRvIGJ5dGVzIDB4ODAgfCAodGVtcCAmIDB4M0YpLlxuICAgICAgICBieXRlcy5wdXNoKDB4ODAgfCAodGVtcCAmIDB4M0YpKTtcblxuICAgICAgICAvLyAzLiBEZWNyZWFzZSBjb3VudCBieSBvbmUuXG4gICAgICAgIGNvdW50IC09IDE7XG4gICAgICB9XG5cbiAgICAgIC8vIDYuIFJldHVybiBieXRlcyBieXRlcywgaW4gb3JkZXIuXG4gICAgICByZXR1cm4gYnl0ZXM7XG4gICAgfTtcbiAgfVxuXG4gIC8qKiBAcGFyYW0ge3tmYXRhbDogYm9vbGVhbn19IG9wdGlvbnMgKi9cbiAgZW5jb2RlcnNbJ1VURi04J10gPSBmdW5jdGlvbihvcHRpb25zKSB7XG4gICAgcmV0dXJuIG5ldyBVVEY4RW5jb2RlcihvcHRpb25zKTtcbiAgfTtcbiAgLyoqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9ucyAqL1xuICBkZWNvZGVyc1snVVRGLTgnXSA9IGZ1bmN0aW9uKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IFVURjhEZWNvZGVyKG9wdGlvbnMpO1xuICB9O1xuXG4gIC8vXG4gIC8vIDEwLiBMZWdhY3kgc2luZ2xlLWJ5dGUgZW5jb2RpbmdzXG4gIC8vXG5cbiAgLy8gMTAuMSBzaW5nbGUtYnl0ZSBkZWNvZGVyXG4gIC8qKlxuICAgKiBAY29uc3RydWN0b3JcbiAgICogQGltcGxlbWVudHMge0RlY29kZXJ9XG4gICAqIEBwYXJhbSB7IUFycmF5LjxudW1iZXI+fSBpbmRleCBUaGUgZW5jb2RpbmcgaW5kZXguXG4gICAqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9uc1xuICAgKi9cbiAgZnVuY3Rpb24gU2luZ2xlQnl0ZURlY29kZXIoaW5kZXgsIG9wdGlvbnMpIHtcbiAgICB2YXIgZmF0YWwgPSBvcHRpb25zLmZhdGFsO1xuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7U3RyZWFtfSBzdHJlYW0gVGhlIHN0cmVhbSBvZiBieXRlcyBiZWluZyBkZWNvZGVkLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBiaXRlIFRoZSBuZXh0IGJ5dGUgcmVhZCBmcm9tIHRoZSBzdHJlYW0uXG4gICAgICogQHJldHVybiB7PyhudW1iZXJ8IUFycmF5LjxudW1iZXI+KX0gVGhlIG5leHQgY29kZSBwb2ludChzKVxuICAgICAqICAgICBkZWNvZGVkLCBvciBudWxsIGlmIG5vdCBlbm91Z2ggZGF0YSBleGlzdHMgaW4gdGhlIGlucHV0XG4gICAgICogICAgIHN0cmVhbSB0byBkZWNvZGUgYSBjb21wbGV0ZSBjb2RlIHBvaW50LlxuICAgICAqL1xuICAgIHRoaXMuaGFuZGxlciA9IGZ1bmN0aW9uKHN0cmVhbSwgYml0ZSkge1xuICAgICAgLy8gMS4gSWYgYnl0ZSBpcyBlbmQtb2Ytc3RyZWFtLCByZXR1cm4gZmluaXNoZWQuXG4gICAgICBpZiAoYml0ZSA9PT0gZW5kX29mX3N0cmVhbSlcbiAgICAgICAgcmV0dXJuIGZpbmlzaGVkO1xuXG4gICAgICAvLyAyLiBJZiBieXRlIGlzIGFuIEFTQ0lJIGJ5dGUsIHJldHVybiBhIGNvZGUgcG9pbnQgd2hvc2UgdmFsdWVcbiAgICAgIC8vIGlzIGJ5dGUuXG4gICAgICBpZiAoaXNBU0NJSUJ5dGUoYml0ZSkpXG4gICAgICAgIHJldHVybiBiaXRlO1xuXG4gICAgICAvLyAzLiBMZXQgY29kZSBwb2ludCBiZSB0aGUgaW5kZXggY29kZSBwb2ludCBmb3IgYnl0ZSDiiJIgMHg4MCBpblxuICAgICAgLy8gaW5kZXggc2luZ2xlLWJ5dGUuXG4gICAgICB2YXIgY29kZV9wb2ludCA9IGluZGV4W2JpdGUgLSAweDgwXTtcblxuICAgICAgLy8gNC4gSWYgY29kZSBwb2ludCBpcyBudWxsLCByZXR1cm4gZXJyb3IuXG4gICAgICBpZiAoY29kZV9wb2ludCA9PT0gbnVsbClcbiAgICAgICAgcmV0dXJuIGRlY29kZXJFcnJvcihmYXRhbCk7XG5cbiAgICAgIC8vIDUuIFJldHVybiBhIGNvZGUgcG9pbnQgd2hvc2UgdmFsdWUgaXMgY29kZSBwb2ludC5cbiAgICAgIHJldHVybiBjb2RlX3BvaW50O1xuICAgIH07XG4gIH1cblxuICAvLyAxMC4yIHNpbmdsZS1ieXRlIGVuY29kZXJcbiAgLyoqXG4gICAqIEBjb25zdHJ1Y3RvclxuICAgKiBAaW1wbGVtZW50cyB7RW5jb2Rlcn1cbiAgICogQHBhcmFtIHshQXJyYXkuPD9udW1iZXI+fSBpbmRleCBUaGUgZW5jb2RpbmcgaW5kZXguXG4gICAqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9uc1xuICAgKi9cbiAgZnVuY3Rpb24gU2luZ2xlQnl0ZUVuY29kZXIoaW5kZXgsIG9wdGlvbnMpIHtcbiAgICB2YXIgZmF0YWwgPSBvcHRpb25zLmZhdGFsO1xuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7U3RyZWFtfSBzdHJlYW0gSW5wdXQgc3RyZWFtLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBjb2RlX3BvaW50IE5leHQgY29kZSBwb2ludCByZWFkIGZyb20gdGhlIHN0cmVhbS5cbiAgICAgKiBAcmV0dXJuIHsobnVtYmVyfCFBcnJheS48bnVtYmVyPil9IEJ5dGUocykgdG8gZW1pdC5cbiAgICAgKi9cbiAgICB0aGlzLmhhbmRsZXIgPSBmdW5jdGlvbihzdHJlYW0sIGNvZGVfcG9pbnQpIHtcbiAgICAgIC8vIDEuIElmIGNvZGUgcG9pbnQgaXMgZW5kLW9mLXN0cmVhbSwgcmV0dXJuIGZpbmlzaGVkLlxuICAgICAgaWYgKGNvZGVfcG9pbnQgPT09IGVuZF9vZl9zdHJlYW0pXG4gICAgICAgIHJldHVybiBmaW5pc2hlZDtcblxuICAgICAgLy8gMi4gSWYgY29kZSBwb2ludCBpcyBhbiBBU0NJSSBjb2RlIHBvaW50LCByZXR1cm4gYSBieXRlIHdob3NlXG4gICAgICAvLyB2YWx1ZSBpcyBjb2RlIHBvaW50LlxuICAgICAgaWYgKGlzQVNDSUlDb2RlUG9pbnQoY29kZV9wb2ludCkpXG4gICAgICAgIHJldHVybiBjb2RlX3BvaW50O1xuXG4gICAgICAvLyAzLiBMZXQgcG9pbnRlciBiZSB0aGUgaW5kZXggcG9pbnRlciBmb3IgY29kZSBwb2ludCBpbiBpbmRleFxuICAgICAgLy8gc2luZ2xlLWJ5dGUuXG4gICAgICB2YXIgcG9pbnRlciA9IGluZGV4UG9pbnRlckZvcihjb2RlX3BvaW50LCBpbmRleCk7XG5cbiAgICAgIC8vIDQuIElmIHBvaW50ZXIgaXMgbnVsbCwgcmV0dXJuIGVycm9yIHdpdGggY29kZSBwb2ludC5cbiAgICAgIGlmIChwb2ludGVyID09PSBudWxsKVxuICAgICAgICBlbmNvZGVyRXJyb3IoY29kZV9wb2ludCk7XG5cbiAgICAgIC8vIDUuIFJldHVybiBhIGJ5dGUgd2hvc2UgdmFsdWUgaXMgcG9pbnRlciArIDB4ODAuXG4gICAgICByZXR1cm4gcG9pbnRlciArIDB4ODA7XG4gICAgfTtcbiAgfVxuXG4gIChmdW5jdGlvbigpIHtcbiAgICBpZiAoISgnZW5jb2RpbmctaW5kZXhlcycgaW4gZ2xvYmFsKSlcbiAgICAgIHJldHVybjtcbiAgICBlbmNvZGluZ3MuZm9yRWFjaChmdW5jdGlvbihjYXRlZ29yeSkge1xuICAgICAgaWYgKGNhdGVnb3J5LmhlYWRpbmcgIT09ICdMZWdhY3kgc2luZ2xlLWJ5dGUgZW5jb2RpbmdzJylcbiAgICAgICAgcmV0dXJuO1xuICAgICAgY2F0ZWdvcnkuZW5jb2RpbmdzLmZvckVhY2goZnVuY3Rpb24oZW5jb2RpbmcpIHtcbiAgICAgICAgdmFyIG5hbWUgPSBlbmNvZGluZy5uYW1lO1xuICAgICAgICB2YXIgaWR4ID0gaW5kZXgobmFtZS50b0xvd2VyQ2FzZSgpKTtcbiAgICAgICAgLyoqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9ucyAqL1xuICAgICAgICBkZWNvZGVyc1tuYW1lXSA9IGZ1bmN0aW9uKG9wdGlvbnMpIHtcbiAgICAgICAgICByZXR1cm4gbmV3IFNpbmdsZUJ5dGVEZWNvZGVyKGlkeCwgb3B0aW9ucyk7XG4gICAgICAgIH07XG4gICAgICAgIC8qKiBAcGFyYW0ge3tmYXRhbDogYm9vbGVhbn19IG9wdGlvbnMgKi9cbiAgICAgICAgZW5jb2RlcnNbbmFtZV0gPSBmdW5jdGlvbihvcHRpb25zKSB7XG4gICAgICAgICAgcmV0dXJuIG5ldyBTaW5nbGVCeXRlRW5jb2RlcihpZHgsIG9wdGlvbnMpO1xuICAgICAgICB9O1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH0oKSk7XG5cbiAgLy9cbiAgLy8gMTEuIExlZ2FjeSBtdWx0aS1ieXRlIENoaW5lc2UgKHNpbXBsaWZpZWQpIGVuY29kaW5nc1xuICAvL1xuXG4gIC8vIDExLjEgZ2JrXG5cbiAgLy8gMTEuMS4xIGdiayBkZWNvZGVyXG4gIC8vIGdiaydzIGRlY29kZXIgaXMgZ2IxODAzMCdzIGRlY29kZXIuXG4gIC8qKiBAcGFyYW0ge3tmYXRhbDogYm9vbGVhbn19IG9wdGlvbnMgKi9cbiAgZGVjb2RlcnNbJ0dCSyddID0gZnVuY3Rpb24ob3B0aW9ucykge1xuICAgIHJldHVybiBuZXcgR0IxODAzMERlY29kZXIob3B0aW9ucyk7XG4gIH07XG5cbiAgLy8gMTEuMS4yIGdiayBlbmNvZGVyXG4gIC8vIGdiaydzIGVuY29kZXIgaXMgZ2IxODAzMCdzIGVuY29kZXIgd2l0aCBpdHMgZ2JrIGZsYWcgc2V0LlxuICAvKiogQHBhcmFtIHt7ZmF0YWw6IGJvb2xlYW59fSBvcHRpb25zICovXG4gIGVuY29kZXJzWydHQksnXSA9IGZ1bmN0aW9uKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IEdCMTgwMzBFbmNvZGVyKG9wdGlvbnMsIHRydWUpO1xuICB9O1xuXG4gIC8vIDExLjIgZ2IxODAzMFxuXG4gIC8vIDExLjIuMSBnYjE4MDMwIGRlY29kZXJcbiAgLyoqXG4gICAqIEBjb25zdHJ1Y3RvclxuICAgKiBAaW1wbGVtZW50cyB7RGVjb2Rlcn1cbiAgICogQHBhcmFtIHt7ZmF0YWw6IGJvb2xlYW59fSBvcHRpb25zXG4gICAqL1xuICBmdW5jdGlvbiBHQjE4MDMwRGVjb2RlcihvcHRpb25zKSB7XG4gICAgdmFyIGZhdGFsID0gb3B0aW9ucy5mYXRhbDtcbiAgICAvLyBnYjE4MDMwJ3MgZGVjb2RlciBoYXMgYW4gYXNzb2NpYXRlZCBnYjE4MDMwIGZpcnN0LCBnYjE4MDMwXG4gICAgLy8gc2Vjb25kLCBhbmQgZ2IxODAzMCB0aGlyZCAoYWxsIGluaXRpYWxseSAweDAwKS5cbiAgICB2YXIgLyoqIEB0eXBlIHtudW1iZXJ9ICovIGdiMTgwMzBfZmlyc3QgPSAweDAwLFxuICAgICAgICAvKiogQHR5cGUge251bWJlcn0gKi8gZ2IxODAzMF9zZWNvbmQgPSAweDAwLFxuICAgICAgICAvKiogQHR5cGUge251bWJlcn0gKi8gZ2IxODAzMF90aGlyZCA9IDB4MDA7XG4gICAgLyoqXG4gICAgICogQHBhcmFtIHtTdHJlYW19IHN0cmVhbSBUaGUgc3RyZWFtIG9mIGJ5dGVzIGJlaW5nIGRlY29kZWQuXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGJpdGUgVGhlIG5leHQgYnl0ZSByZWFkIGZyb20gdGhlIHN0cmVhbS5cbiAgICAgKiBAcmV0dXJuIHs/KG51bWJlcnwhQXJyYXkuPG51bWJlcj4pfSBUaGUgbmV4dCBjb2RlIHBvaW50KHMpXG4gICAgICogICAgIGRlY29kZWQsIG9yIG51bGwgaWYgbm90IGVub3VnaCBkYXRhIGV4aXN0cyBpbiB0aGUgaW5wdXRcbiAgICAgKiAgICAgc3RyZWFtIHRvIGRlY29kZSBhIGNvbXBsZXRlIGNvZGUgcG9pbnQuXG4gICAgICovXG4gICAgdGhpcy5oYW5kbGVyID0gZnVuY3Rpb24oc3RyZWFtLCBiaXRlKSB7XG4gICAgICAvLyAxLiBJZiBieXRlIGlzIGVuZC1vZi1zdHJlYW0gYW5kIGdiMTgwMzAgZmlyc3QsIGdiMTgwMzBcbiAgICAgIC8vIHNlY29uZCwgYW5kIGdiMTgwMzAgdGhpcmQgYXJlIDB4MDAsIHJldHVybiBmaW5pc2hlZC5cbiAgICAgIGlmIChiaXRlID09PSBlbmRfb2Zfc3RyZWFtICYmIGdiMTgwMzBfZmlyc3QgPT09IDB4MDAgJiZcbiAgICAgICAgICBnYjE4MDMwX3NlY29uZCA9PT0gMHgwMCAmJiBnYjE4MDMwX3RoaXJkID09PSAweDAwKSB7XG4gICAgICAgIHJldHVybiBmaW5pc2hlZDtcbiAgICAgIH1cbiAgICAgIC8vIDIuIElmIGJ5dGUgaXMgZW5kLW9mLXN0cmVhbSwgYW5kIGdiMTgwMzAgZmlyc3QsIGdiMTgwMzBcbiAgICAgIC8vIHNlY29uZCwgb3IgZ2IxODAzMCB0aGlyZCBpcyBub3QgMHgwMCwgc2V0IGdiMTgwMzAgZmlyc3QsXG4gICAgICAvLyBnYjE4MDMwIHNlY29uZCwgYW5kIGdiMTgwMzAgdGhpcmQgdG8gMHgwMCwgYW5kIHJldHVybiBlcnJvci5cbiAgICAgIGlmIChiaXRlID09PSBlbmRfb2Zfc3RyZWFtICYmXG4gICAgICAgICAgKGdiMTgwMzBfZmlyc3QgIT09IDB4MDAgfHwgZ2IxODAzMF9zZWNvbmQgIT09IDB4MDAgfHxcbiAgICAgICAgICAgZ2IxODAzMF90aGlyZCAhPT0gMHgwMCkpIHtcbiAgICAgICAgZ2IxODAzMF9maXJzdCA9IDB4MDA7XG4gICAgICAgIGdiMTgwMzBfc2Vjb25kID0gMHgwMDtcbiAgICAgICAgZ2IxODAzMF90aGlyZCA9IDB4MDA7XG4gICAgICAgIGRlY29kZXJFcnJvcihmYXRhbCk7XG4gICAgICB9XG4gICAgICB2YXIgY29kZV9wb2ludDtcbiAgICAgIC8vIDMuIElmIGdiMTgwMzAgdGhpcmQgaXMgbm90IDB4MDAsIHJ1biB0aGVzZSBzdWJzdGVwczpcbiAgICAgIGlmIChnYjE4MDMwX3RoaXJkICE9PSAweDAwKSB7XG4gICAgICAgIC8vIDEuIExldCBjb2RlIHBvaW50IGJlIG51bGwuXG4gICAgICAgIGNvZGVfcG9pbnQgPSBudWxsO1xuICAgICAgICAvLyAyLiBJZiBieXRlIGlzIGluIHRoZSByYW5nZSAweDMwIHRvIDB4MzksIGluY2x1c2l2ZSwgc2V0XG4gICAgICAgIC8vIGNvZGUgcG9pbnQgdG8gdGhlIGluZGV4IGdiMTgwMzAgcmFuZ2VzIGNvZGUgcG9pbnQgZm9yXG4gICAgICAgIC8vICgoKGdiMTgwMzAgZmlyc3Qg4oiSIDB4ODEpIMOXIDEwICsgZ2IxODAzMCBzZWNvbmQg4oiSIDB4MzApIMOXXG4gICAgICAgIC8vIDEyNiArIGdiMTgwMzAgdGhpcmQg4oiSIDB4ODEpIMOXIDEwICsgYnl0ZSDiiJIgMHgzMC5cbiAgICAgICAgaWYgKGluUmFuZ2UoYml0ZSwgMHgzMCwgMHgzOSkpIHtcbiAgICAgICAgICBjb2RlX3BvaW50ID0gaW5kZXhHQjE4MDMwUmFuZ2VzQ29kZVBvaW50Rm9yKFxuICAgICAgICAgICAgICAoKChnYjE4MDMwX2ZpcnN0IC0gMHg4MSkgKiAxMCArIGdiMTgwMzBfc2Vjb25kIC0gMHgzMCkgKiAxMjYgK1xuICAgICAgICAgICAgICAgZ2IxODAzMF90aGlyZCAtIDB4ODEpICogMTAgKyBiaXRlIC0gMHgzMCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyAzLiBMZXQgYnVmZmVyIGJlIGEgYnl0ZSBzZXF1ZW5jZSBjb25zaXN0aW5nIG9mIGdiMTgwMzBcbiAgICAgICAgLy8gc2Vjb25kLCBnYjE4MDMwIHRoaXJkLCBhbmQgYnl0ZSwgaW4gb3JkZXIuXG4gICAgICAgIHZhciBidWZmZXIgPSBbZ2IxODAzMF9zZWNvbmQsIGdiMTgwMzBfdGhpcmQsIGJpdGVdO1xuXG4gICAgICAgIC8vIDQuIFNldCBnYjE4MDMwIGZpcnN0LCBnYjE4MDMwIHNlY29uZCwgYW5kIGdiMTgwMzAgdGhpcmQgdG9cbiAgICAgICAgLy8gMHgwMC5cbiAgICAgICAgZ2IxODAzMF9maXJzdCA9IDB4MDA7XG4gICAgICAgIGdiMTgwMzBfc2Vjb25kID0gMHgwMDtcbiAgICAgICAgZ2IxODAzMF90aGlyZCA9IDB4MDA7XG5cbiAgICAgICAgLy8gNS4gSWYgY29kZSBwb2ludCBpcyBudWxsLCBwcmVwZW5kIGJ1ZmZlciB0byBzdHJlYW0gYW5kXG4gICAgICAgIC8vIHJldHVybiBlcnJvci5cbiAgICAgICAgaWYgKGNvZGVfcG9pbnQgPT09IG51bGwpIHtcbiAgICAgICAgICBzdHJlYW0ucHJlcGVuZChidWZmZXIpO1xuICAgICAgICAgIHJldHVybiBkZWNvZGVyRXJyb3IoZmF0YWwpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gNi4gUmV0dXJuIGEgY29kZSBwb2ludCB3aG9zZSB2YWx1ZSBpcyBjb2RlIHBvaW50LlxuICAgICAgICByZXR1cm4gY29kZV9wb2ludDtcbiAgICAgIH1cblxuICAgICAgLy8gNC4gSWYgZ2IxODAzMCBzZWNvbmQgaXMgbm90IDB4MDAsIHJ1biB0aGVzZSBzdWJzdGVwczpcbiAgICAgIGlmIChnYjE4MDMwX3NlY29uZCAhPT0gMHgwMCkge1xuXG4gICAgICAgIC8vIDEuIElmIGJ5dGUgaXMgaW4gdGhlIHJhbmdlIDB4ODEgdG8gMHhGRSwgaW5jbHVzaXZlLCBzZXRcbiAgICAgICAgLy8gZ2IxODAzMCB0aGlyZCB0byBieXRlIGFuZCByZXR1cm4gY29udGludWUuXG4gICAgICAgIGlmIChpblJhbmdlKGJpdGUsIDB4ODEsIDB4RkUpKSB7XG4gICAgICAgICAgZ2IxODAzMF90aGlyZCA9IGJpdGU7XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICAvLyAyLiBQcmVwZW5kIGdiMTgwMzAgc2Vjb25kIGZvbGxvd2VkIGJ5IGJ5dGUgdG8gc3RyZWFtLCBzZXRcbiAgICAgICAgLy8gZ2IxODAzMCBmaXJzdCBhbmQgZ2IxODAzMCBzZWNvbmQgdG8gMHgwMCwgYW5kIHJldHVybiBlcnJvci5cbiAgICAgICAgc3RyZWFtLnByZXBlbmQoW2diMTgwMzBfc2Vjb25kLCBiaXRlXSk7XG4gICAgICAgIGdiMTgwMzBfZmlyc3QgPSAweDAwO1xuICAgICAgICBnYjE4MDMwX3NlY29uZCA9IDB4MDA7XG4gICAgICAgIHJldHVybiBkZWNvZGVyRXJyb3IoZmF0YWwpO1xuICAgICAgfVxuXG4gICAgICAvLyA1LiBJZiBnYjE4MDMwIGZpcnN0IGlzIG5vdCAweDAwLCBydW4gdGhlc2Ugc3Vic3RlcHM6XG4gICAgICBpZiAoZ2IxODAzMF9maXJzdCAhPT0gMHgwMCkge1xuXG4gICAgICAgIC8vIDEuIElmIGJ5dGUgaXMgaW4gdGhlIHJhbmdlIDB4MzAgdG8gMHgzOSwgaW5jbHVzaXZlLCBzZXRcbiAgICAgICAgLy8gZ2IxODAzMCBzZWNvbmQgdG8gYnl0ZSBhbmQgcmV0dXJuIGNvbnRpbnVlLlxuICAgICAgICBpZiAoaW5SYW5nZShiaXRlLCAweDMwLCAweDM5KSkge1xuICAgICAgICAgIGdiMTgwMzBfc2Vjb25kID0gYml0ZTtcbiAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIDIuIExldCBsZWFkIGJlIGdiMTgwMzAgZmlyc3QsIGxldCBwb2ludGVyIGJlIG51bGwsIGFuZCBzZXRcbiAgICAgICAgLy8gZ2IxODAzMCBmaXJzdCB0byAweDAwLlxuICAgICAgICB2YXIgbGVhZCA9IGdiMTgwMzBfZmlyc3Q7XG4gICAgICAgIHZhciBwb2ludGVyID0gbnVsbDtcbiAgICAgICAgZ2IxODAzMF9maXJzdCA9IDB4MDA7XG5cbiAgICAgICAgLy8gMy4gTGV0IG9mZnNldCBiZSAweDQwIGlmIGJ5dGUgaXMgbGVzcyB0aGFuIDB4N0YgYW5kIDB4NDFcbiAgICAgICAgLy8gb3RoZXJ3aXNlLlxuICAgICAgICB2YXIgb2Zmc2V0ID0gYml0ZSA8IDB4N0YgPyAweDQwIDogMHg0MTtcblxuICAgICAgICAvLyA0LiBJZiBieXRlIGlzIGluIHRoZSByYW5nZSAweDQwIHRvIDB4N0UsIGluY2x1c2l2ZSwgb3IgMHg4MFxuICAgICAgICAvLyB0byAweEZFLCBpbmNsdXNpdmUsIHNldCBwb2ludGVyIHRvIChsZWFkIOKIkiAweDgxKSDDlyAxOTAgK1xuICAgICAgICAvLyAoYnl0ZSDiiJIgb2Zmc2V0KS5cbiAgICAgICAgaWYgKGluUmFuZ2UoYml0ZSwgMHg0MCwgMHg3RSkgfHwgaW5SYW5nZShiaXRlLCAweDgwLCAweEZFKSlcbiAgICAgICAgICBwb2ludGVyID0gKGxlYWQgLSAweDgxKSAqIDE5MCArIChiaXRlIC0gb2Zmc2V0KTtcblxuICAgICAgICAvLyA1LiBMZXQgY29kZSBwb2ludCBiZSBudWxsIGlmIHBvaW50ZXIgaXMgbnVsbCBhbmQgdGhlIGluZGV4XG4gICAgICAgIC8vIGNvZGUgcG9pbnQgZm9yIHBvaW50ZXIgaW4gaW5kZXggZ2IxODAzMCBvdGhlcndpc2UuXG4gICAgICAgIGNvZGVfcG9pbnQgPSBwb2ludGVyID09PSBudWxsID8gbnVsbCA6XG4gICAgICAgICAgICBpbmRleENvZGVQb2ludEZvcihwb2ludGVyLCBpbmRleCgnZ2IxODAzMCcpKTtcblxuICAgICAgICAvLyA2LiBJZiBjb2RlIHBvaW50IGlzIG51bGwgYW5kIGJ5dGUgaXMgYW4gQVNDSUkgYnl0ZSwgcHJlcGVuZFxuICAgICAgICAvLyBieXRlIHRvIHN0cmVhbS5cbiAgICAgICAgaWYgKGNvZGVfcG9pbnQgPT09IG51bGwgJiYgaXNBU0NJSUJ5dGUoYml0ZSkpXG4gICAgICAgICAgc3RyZWFtLnByZXBlbmQoYml0ZSk7XG5cbiAgICAgICAgLy8gNy4gSWYgY29kZSBwb2ludCBpcyBudWxsLCByZXR1cm4gZXJyb3IuXG4gICAgICAgIGlmIChjb2RlX3BvaW50ID09PSBudWxsKVxuICAgICAgICAgIHJldHVybiBkZWNvZGVyRXJyb3IoZmF0YWwpO1xuXG4gICAgICAgIC8vIDguIFJldHVybiBhIGNvZGUgcG9pbnQgd2hvc2UgdmFsdWUgaXMgY29kZSBwb2ludC5cbiAgICAgICAgcmV0dXJuIGNvZGVfcG9pbnQ7XG4gICAgICB9XG5cbiAgICAgIC8vIDYuIElmIGJ5dGUgaXMgYW4gQVNDSUkgYnl0ZSwgcmV0dXJuIGEgY29kZSBwb2ludCB3aG9zZSB2YWx1ZVxuICAgICAgLy8gaXMgYnl0ZS5cbiAgICAgIGlmIChpc0FTQ0lJQnl0ZShiaXRlKSlcbiAgICAgICAgcmV0dXJuIGJpdGU7XG5cbiAgICAgIC8vIDcuIElmIGJ5dGUgaXMgMHg4MCwgcmV0dXJuIGNvZGUgcG9pbnQgVSsyMEFDLlxuICAgICAgaWYgKGJpdGUgPT09IDB4ODApXG4gICAgICAgIHJldHVybiAweDIwQUM7XG5cbiAgICAgIC8vIDguIElmIGJ5dGUgaXMgaW4gdGhlIHJhbmdlIDB4ODEgdG8gMHhGRSwgaW5jbHVzaXZlLCBzZXRcbiAgICAgIC8vIGdiMTgwMzAgZmlyc3QgdG8gYnl0ZSBhbmQgcmV0dXJuIGNvbnRpbnVlLlxuICAgICAgaWYgKGluUmFuZ2UoYml0ZSwgMHg4MSwgMHhGRSkpIHtcbiAgICAgICAgZ2IxODAzMF9maXJzdCA9IGJpdGU7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICAvLyA5LiBSZXR1cm4gZXJyb3IuXG4gICAgICByZXR1cm4gZGVjb2RlckVycm9yKGZhdGFsKTtcbiAgICB9O1xuICB9XG5cbiAgLy8gMTEuMi4yIGdiMTgwMzAgZW5jb2RlclxuICAvKipcbiAgICogQGNvbnN0cnVjdG9yXG4gICAqIEBpbXBsZW1lbnRzIHtFbmNvZGVyfVxuICAgKiBAcGFyYW0ge3tmYXRhbDogYm9vbGVhbn19IG9wdGlvbnNcbiAgICogQHBhcmFtIHtib29sZWFuPX0gZ2JrX2ZsYWdcbiAgICovXG4gIGZ1bmN0aW9uIEdCMTgwMzBFbmNvZGVyKG9wdGlvbnMsIGdia19mbGFnKSB7XG4gICAgdmFyIGZhdGFsID0gb3B0aW9ucy5mYXRhbDtcbiAgICAvLyBnYjE4MDMwJ3MgZGVjb2RlciBoYXMgYW4gYXNzb2NpYXRlZCBnYmsgZmxhZyAoaW5pdGlhbGx5IHVuc2V0KS5cbiAgICAvKipcbiAgICAgKiBAcGFyYW0ge1N0cmVhbX0gc3RyZWFtIElucHV0IHN0cmVhbS5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gY29kZV9wb2ludCBOZXh0IGNvZGUgcG9pbnQgcmVhZCBmcm9tIHRoZSBzdHJlYW0uXG4gICAgICogQHJldHVybiB7KG51bWJlcnwhQXJyYXkuPG51bWJlcj4pfSBCeXRlKHMpIHRvIGVtaXQuXG4gICAgICovXG4gICAgdGhpcy5oYW5kbGVyID0gZnVuY3Rpb24oc3RyZWFtLCBjb2RlX3BvaW50KSB7XG4gICAgICAvLyAxLiBJZiBjb2RlIHBvaW50IGlzIGVuZC1vZi1zdHJlYW0sIHJldHVybiBmaW5pc2hlZC5cbiAgICAgIGlmIChjb2RlX3BvaW50ID09PSBlbmRfb2Zfc3RyZWFtKVxuICAgICAgICByZXR1cm4gZmluaXNoZWQ7XG5cbiAgICAgIC8vIDIuIElmIGNvZGUgcG9pbnQgaXMgYW4gQVNDSUkgY29kZSBwb2ludCwgcmV0dXJuIGEgYnl0ZSB3aG9zZVxuICAgICAgLy8gdmFsdWUgaXMgY29kZSBwb2ludC5cbiAgICAgIGlmIChpc0FTQ0lJQ29kZVBvaW50KGNvZGVfcG9pbnQpKVxuICAgICAgICByZXR1cm4gY29kZV9wb2ludDtcblxuICAgICAgLy8gMy4gSWYgY29kZSBwb2ludCBpcyBVK0U1RTUsIHJldHVybiBlcnJvciB3aXRoIGNvZGUgcG9pbnQuXG4gICAgICBpZiAoY29kZV9wb2ludCA9PT0gMHhFNUU1KVxuICAgICAgICByZXR1cm4gZW5jb2RlckVycm9yKGNvZGVfcG9pbnQpO1xuXG4gICAgICAvLyA0LiBJZiB0aGUgZ2JrIGZsYWcgaXMgc2V0IGFuZCBjb2RlIHBvaW50IGlzIFUrMjBBQywgcmV0dXJuXG4gICAgICAvLyBieXRlIDB4ODAuXG4gICAgICBpZiAoZ2JrX2ZsYWcgJiYgY29kZV9wb2ludCA9PT0gMHgyMEFDKVxuICAgICAgICByZXR1cm4gMHg4MDtcblxuICAgICAgLy8gNS4gTGV0IHBvaW50ZXIgYmUgdGhlIGluZGV4IHBvaW50ZXIgZm9yIGNvZGUgcG9pbnQgaW4gaW5kZXhcbiAgICAgIC8vIGdiMTgwMzAuXG4gICAgICB2YXIgcG9pbnRlciA9IGluZGV4UG9pbnRlckZvcihjb2RlX3BvaW50LCBpbmRleCgnZ2IxODAzMCcpKTtcblxuICAgICAgLy8gNi4gSWYgcG9pbnRlciBpcyBub3QgbnVsbCwgcnVuIHRoZXNlIHN1YnN0ZXBzOlxuICAgICAgaWYgKHBvaW50ZXIgIT09IG51bGwpIHtcblxuICAgICAgICAvLyAxLiBMZXQgbGVhZCBiZSBmbG9vcihwb2ludGVyIC8gMTkwKSArIDB4ODEuXG4gICAgICAgIHZhciBsZWFkID0gZmxvb3IocG9pbnRlciAvIDE5MCkgKyAweDgxO1xuXG4gICAgICAgIC8vIDIuIExldCB0cmFpbCBiZSBwb2ludGVyICUgMTkwLlxuICAgICAgICB2YXIgdHJhaWwgPSBwb2ludGVyICUgMTkwO1xuXG4gICAgICAgIC8vIDMuIExldCBvZmZzZXQgYmUgMHg0MCBpZiB0cmFpbCBpcyBsZXNzIHRoYW4gMHgzRiBhbmQgMHg0MSBvdGhlcndpc2UuXG4gICAgICAgIHZhciBvZmZzZXQgPSB0cmFpbCA8IDB4M0YgPyAweDQwIDogMHg0MTtcblxuICAgICAgICAvLyA0LiBSZXR1cm4gdHdvIGJ5dGVzIHdob3NlIHZhbHVlcyBhcmUgbGVhZCBhbmQgdHJhaWwgKyBvZmZzZXQuXG4gICAgICAgIHJldHVybiBbbGVhZCwgdHJhaWwgKyBvZmZzZXRdO1xuICAgICAgfVxuXG4gICAgICAvLyA3LiBJZiBnYmsgZmxhZyBpcyBzZXQsIHJldHVybiBlcnJvciB3aXRoIGNvZGUgcG9pbnQuXG4gICAgICBpZiAoZ2JrX2ZsYWcpXG4gICAgICAgIHJldHVybiBlbmNvZGVyRXJyb3IoY29kZV9wb2ludCk7XG5cbiAgICAgIC8vIDguIFNldCBwb2ludGVyIHRvIHRoZSBpbmRleCBnYjE4MDMwIHJhbmdlcyBwb2ludGVyIGZvciBjb2RlXG4gICAgICAvLyBwb2ludC5cbiAgICAgIHBvaW50ZXIgPSBpbmRleEdCMTgwMzBSYW5nZXNQb2ludGVyRm9yKGNvZGVfcG9pbnQpO1xuXG4gICAgICAvLyA5LiBMZXQgYnl0ZTEgYmUgZmxvb3IocG9pbnRlciAvIDEwIC8gMTI2IC8gMTApLlxuICAgICAgdmFyIGJ5dGUxID0gZmxvb3IocG9pbnRlciAvIDEwIC8gMTI2IC8gMTApO1xuXG4gICAgICAvLyAxMC4gU2V0IHBvaW50ZXIgdG8gcG9pbnRlciDiiJIgYnl0ZTEgw5cgMTAgw5cgMTI2IMOXIDEwLlxuICAgICAgcG9pbnRlciA9IHBvaW50ZXIgLSBieXRlMSAqIDEwICogMTI2ICogMTA7XG5cbiAgICAgIC8vIDExLiBMZXQgYnl0ZTIgYmUgZmxvb3IocG9pbnRlciAvIDEwIC8gMTI2KS5cbiAgICAgIHZhciBieXRlMiA9IGZsb29yKHBvaW50ZXIgLyAxMCAvIDEyNik7XG5cbiAgICAgIC8vIDEyLiBTZXQgcG9pbnRlciB0byBwb2ludGVyIOKIkiBieXRlMiDDlyAxMCDDlyAxMjYuXG4gICAgICBwb2ludGVyID0gcG9pbnRlciAtIGJ5dGUyICogMTAgKiAxMjY7XG5cbiAgICAgIC8vIDEzLiBMZXQgYnl0ZTMgYmUgZmxvb3IocG9pbnRlciAvIDEwKS5cbiAgICAgIHZhciBieXRlMyA9IGZsb29yKHBvaW50ZXIgLyAxMCk7XG5cbiAgICAgIC8vIDE0LiBMZXQgYnl0ZTQgYmUgcG9pbnRlciDiiJIgYnl0ZTMgw5cgMTAuXG4gICAgICB2YXIgYnl0ZTQgPSBwb2ludGVyIC0gYnl0ZTMgKiAxMDtcblxuICAgICAgLy8gMTUuIFJldHVybiBmb3VyIGJ5dGVzIHdob3NlIHZhbHVlcyBhcmUgYnl0ZTEgKyAweDgxLCBieXRlMiArXG4gICAgICAvLyAweDMwLCBieXRlMyArIDB4ODEsIGJ5dGU0ICsgMHgzMC5cbiAgICAgIHJldHVybiBbYnl0ZTEgKyAweDgxLFxuICAgICAgICAgICAgICBieXRlMiArIDB4MzAsXG4gICAgICAgICAgICAgIGJ5dGUzICsgMHg4MSxcbiAgICAgICAgICAgICAgYnl0ZTQgKyAweDMwXTtcbiAgICB9O1xuICB9XG5cbiAgLyoqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9ucyAqL1xuICBlbmNvZGVyc1snZ2IxODAzMCddID0gZnVuY3Rpb24ob3B0aW9ucykge1xuICAgIHJldHVybiBuZXcgR0IxODAzMEVuY29kZXIob3B0aW9ucyk7XG4gIH07XG4gIC8qKiBAcGFyYW0ge3tmYXRhbDogYm9vbGVhbn19IG9wdGlvbnMgKi9cbiAgZGVjb2RlcnNbJ2diMTgwMzAnXSA9IGZ1bmN0aW9uKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IEdCMTgwMzBEZWNvZGVyKG9wdGlvbnMpO1xuICB9O1xuXG5cbiAgLy9cbiAgLy8gMTIuIExlZ2FjeSBtdWx0aS1ieXRlIENoaW5lc2UgKHRyYWRpdGlvbmFsKSBlbmNvZGluZ3NcbiAgLy9cblxuICAvLyAxMi4xIEJpZzVcblxuICAvLyAxMi4xLjEgQmlnNSBkZWNvZGVyXG4gIC8qKlxuICAgKiBAY29uc3RydWN0b3JcbiAgICogQGltcGxlbWVudHMge0RlY29kZXJ9XG4gICAqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9uc1xuICAgKi9cbiAgZnVuY3Rpb24gQmlnNURlY29kZXIob3B0aW9ucykge1xuICAgIHZhciBmYXRhbCA9IG9wdGlvbnMuZmF0YWw7XG4gICAgLy8gQmlnNSdzIGRlY29kZXIgaGFzIGFuIGFzc29jaWF0ZWQgQmlnNSBsZWFkIChpbml0aWFsbHkgMHgwMCkuXG4gICAgdmFyIC8qKiBAdHlwZSB7bnVtYmVyfSAqLyBCaWc1X2xlYWQgPSAweDAwO1xuXG4gICAgLyoqXG4gICAgICogQHBhcmFtIHtTdHJlYW19IHN0cmVhbSBUaGUgc3RyZWFtIG9mIGJ5dGVzIGJlaW5nIGRlY29kZWQuXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGJpdGUgVGhlIG5leHQgYnl0ZSByZWFkIGZyb20gdGhlIHN0cmVhbS5cbiAgICAgKiBAcmV0dXJuIHs/KG51bWJlcnwhQXJyYXkuPG51bWJlcj4pfSBUaGUgbmV4dCBjb2RlIHBvaW50KHMpXG4gICAgICogICAgIGRlY29kZWQsIG9yIG51bGwgaWYgbm90IGVub3VnaCBkYXRhIGV4aXN0cyBpbiB0aGUgaW5wdXRcbiAgICAgKiAgICAgc3RyZWFtIHRvIGRlY29kZSBhIGNvbXBsZXRlIGNvZGUgcG9pbnQuXG4gICAgICovXG4gICAgdGhpcy5oYW5kbGVyID0gZnVuY3Rpb24oc3RyZWFtLCBiaXRlKSB7XG4gICAgICAvLyAxLiBJZiBieXRlIGlzIGVuZC1vZi1zdHJlYW0gYW5kIEJpZzUgbGVhZCBpcyBub3QgMHgwMCwgc2V0XG4gICAgICAvLyBCaWc1IGxlYWQgdG8gMHgwMCBhbmQgcmV0dXJuIGVycm9yLlxuICAgICAgaWYgKGJpdGUgPT09IGVuZF9vZl9zdHJlYW0gJiYgQmlnNV9sZWFkICE9PSAweDAwKSB7XG4gICAgICAgIEJpZzVfbGVhZCA9IDB4MDA7XG4gICAgICAgIHJldHVybiBkZWNvZGVyRXJyb3IoZmF0YWwpO1xuICAgICAgfVxuXG4gICAgICAvLyAyLiBJZiBieXRlIGlzIGVuZC1vZi1zdHJlYW0gYW5kIEJpZzUgbGVhZCBpcyAweDAwLCByZXR1cm5cbiAgICAgIC8vIGZpbmlzaGVkLlxuICAgICAgaWYgKGJpdGUgPT09IGVuZF9vZl9zdHJlYW0gJiYgQmlnNV9sZWFkID09PSAweDAwKVxuICAgICAgICByZXR1cm4gZmluaXNoZWQ7XG5cbiAgICAgIC8vIDMuIElmIEJpZzUgbGVhZCBpcyBub3QgMHgwMCwgbGV0IGxlYWQgYmUgQmlnNSBsZWFkLCBsZXRcbiAgICAgIC8vIHBvaW50ZXIgYmUgbnVsbCwgc2V0IEJpZzUgbGVhZCB0byAweDAwLCBhbmQgdGhlbiBydW4gdGhlc2VcbiAgICAgIC8vIHN1YnN0ZXBzOlxuICAgICAgaWYgKEJpZzVfbGVhZCAhPT0gMHgwMCkge1xuICAgICAgICB2YXIgbGVhZCA9IEJpZzVfbGVhZDtcbiAgICAgICAgdmFyIHBvaW50ZXIgPSBudWxsO1xuICAgICAgICBCaWc1X2xlYWQgPSAweDAwO1xuXG4gICAgICAgIC8vIDEuIExldCBvZmZzZXQgYmUgMHg0MCBpZiBieXRlIGlzIGxlc3MgdGhhbiAweDdGIGFuZCAweDYyXG4gICAgICAgIC8vIG90aGVyd2lzZS5cbiAgICAgICAgdmFyIG9mZnNldCA9IGJpdGUgPCAweDdGID8gMHg0MCA6IDB4NjI7XG5cbiAgICAgICAgLy8gMi4gSWYgYnl0ZSBpcyBpbiB0aGUgcmFuZ2UgMHg0MCB0byAweDdFLCBpbmNsdXNpdmUsIG9yIDB4QTFcbiAgICAgICAgLy8gdG8gMHhGRSwgaW5jbHVzaXZlLCBzZXQgcG9pbnRlciB0byAobGVhZCDiiJIgMHg4MSkgw5cgMTU3ICtcbiAgICAgICAgLy8gKGJ5dGUg4oiSIG9mZnNldCkuXG4gICAgICAgIGlmIChpblJhbmdlKGJpdGUsIDB4NDAsIDB4N0UpIHx8IGluUmFuZ2UoYml0ZSwgMHhBMSwgMHhGRSkpXG4gICAgICAgICAgcG9pbnRlciA9IChsZWFkIC0gMHg4MSkgKiAxNTcgKyAoYml0ZSAtIG9mZnNldCk7XG5cbiAgICAgICAgLy8gMy4gSWYgdGhlcmUgaXMgYSByb3cgaW4gdGhlIHRhYmxlIGJlbG93IHdob3NlIGZpcnN0IGNvbHVtblxuICAgICAgICAvLyBpcyBwb2ludGVyLCByZXR1cm4gdGhlIHR3byBjb2RlIHBvaW50cyBsaXN0ZWQgaW4gaXRzIHNlY29uZFxuICAgICAgICAvLyBjb2x1bW5cbiAgICAgICAgLy8gUG9pbnRlciB8IENvZGUgcG9pbnRzXG4gICAgICAgIC8vIC0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tXG4gICAgICAgIC8vIDExMzMgICAgfCBVKzAwQ0EgVSswMzA0XG4gICAgICAgIC8vIDExMzUgICAgfCBVKzAwQ0EgVSswMzBDXG4gICAgICAgIC8vIDExNjQgICAgfCBVKzAwRUEgVSswMzA0XG4gICAgICAgIC8vIDExNjYgICAgfCBVKzAwRUEgVSswMzBDXG4gICAgICAgIHN3aXRjaCAocG9pbnRlcikge1xuICAgICAgICAgIGNhc2UgMTEzMzogcmV0dXJuIFsweDAwQ0EsIDB4MDMwNF07XG4gICAgICAgICAgY2FzZSAxMTM1OiByZXR1cm4gWzB4MDBDQSwgMHgwMzBDXTtcbiAgICAgICAgICBjYXNlIDExNjQ6IHJldHVybiBbMHgwMEVBLCAweDAzMDRdO1xuICAgICAgICAgIGNhc2UgMTE2NjogcmV0dXJuIFsweDAwRUEsIDB4MDMwQ107XG4gICAgICAgIH1cblxuICAgICAgICAvLyA0LiBMZXQgY29kZSBwb2ludCBiZSBudWxsIGlmIHBvaW50ZXIgaXMgbnVsbCBhbmQgdGhlIGluZGV4XG4gICAgICAgIC8vIGNvZGUgcG9pbnQgZm9yIHBvaW50ZXIgaW4gaW5kZXggQmlnNSBvdGhlcndpc2UuXG4gICAgICAgIHZhciBjb2RlX3BvaW50ID0gKHBvaW50ZXIgPT09IG51bGwpID8gbnVsbCA6XG4gICAgICAgICAgICBpbmRleENvZGVQb2ludEZvcihwb2ludGVyLCBpbmRleCgnYmlnNScpKTtcblxuICAgICAgICAvLyA1LiBJZiBjb2RlIHBvaW50IGlzIG51bGwgYW5kIGJ5dGUgaXMgYW4gQVNDSUkgYnl0ZSwgcHJlcGVuZFxuICAgICAgICAvLyBieXRlIHRvIHN0cmVhbS5cbiAgICAgICAgaWYgKGNvZGVfcG9pbnQgPT09IG51bGwgJiYgaXNBU0NJSUJ5dGUoYml0ZSkpXG4gICAgICAgICAgc3RyZWFtLnByZXBlbmQoYml0ZSk7XG5cbiAgICAgICAgLy8gNi4gSWYgY29kZSBwb2ludCBpcyBudWxsLCByZXR1cm4gZXJyb3IuXG4gICAgICAgIGlmIChjb2RlX3BvaW50ID09PSBudWxsKVxuICAgICAgICAgIHJldHVybiBkZWNvZGVyRXJyb3IoZmF0YWwpO1xuXG4gICAgICAgIC8vIDcuIFJldHVybiBhIGNvZGUgcG9pbnQgd2hvc2UgdmFsdWUgaXMgY29kZSBwb2ludC5cbiAgICAgICAgcmV0dXJuIGNvZGVfcG9pbnQ7XG4gICAgICB9XG5cbiAgICAgIC8vIDQuIElmIGJ5dGUgaXMgYW4gQVNDSUkgYnl0ZSwgcmV0dXJuIGEgY29kZSBwb2ludCB3aG9zZSB2YWx1ZVxuICAgICAgLy8gaXMgYnl0ZS5cbiAgICAgIGlmIChpc0FTQ0lJQnl0ZShiaXRlKSlcbiAgICAgICAgcmV0dXJuIGJpdGU7XG5cbiAgICAgIC8vIDUuIElmIGJ5dGUgaXMgaW4gdGhlIHJhbmdlIDB4ODEgdG8gMHhGRSwgaW5jbHVzaXZlLCBzZXQgQmlnNVxuICAgICAgLy8gbGVhZCB0byBieXRlIGFuZCByZXR1cm4gY29udGludWUuXG4gICAgICBpZiAoaW5SYW5nZShiaXRlLCAweDgxLCAweEZFKSkge1xuICAgICAgICBCaWc1X2xlYWQgPSBiaXRlO1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cblxuICAgICAgLy8gNi4gUmV0dXJuIGVycm9yLlxuICAgICAgcmV0dXJuIGRlY29kZXJFcnJvcihmYXRhbCk7XG4gICAgfTtcbiAgfVxuXG4gIC8vIDEyLjEuMiBCaWc1IGVuY29kZXJcbiAgLyoqXG4gICAqIEBjb25zdHJ1Y3RvclxuICAgKiBAaW1wbGVtZW50cyB7RW5jb2Rlcn1cbiAgICogQHBhcmFtIHt7ZmF0YWw6IGJvb2xlYW59fSBvcHRpb25zXG4gICAqL1xuICBmdW5jdGlvbiBCaWc1RW5jb2RlcihvcHRpb25zKSB7XG4gICAgdmFyIGZhdGFsID0gb3B0aW9ucy5mYXRhbDtcbiAgICAvKipcbiAgICAgKiBAcGFyYW0ge1N0cmVhbX0gc3RyZWFtIElucHV0IHN0cmVhbS5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gY29kZV9wb2ludCBOZXh0IGNvZGUgcG9pbnQgcmVhZCBmcm9tIHRoZSBzdHJlYW0uXG4gICAgICogQHJldHVybiB7KG51bWJlcnwhQXJyYXkuPG51bWJlcj4pfSBCeXRlKHMpIHRvIGVtaXQuXG4gICAgICovXG4gICAgdGhpcy5oYW5kbGVyID0gZnVuY3Rpb24oc3RyZWFtLCBjb2RlX3BvaW50KSB7XG4gICAgICAvLyAxLiBJZiBjb2RlIHBvaW50IGlzIGVuZC1vZi1zdHJlYW0sIHJldHVybiBmaW5pc2hlZC5cbiAgICAgIGlmIChjb2RlX3BvaW50ID09PSBlbmRfb2Zfc3RyZWFtKVxuICAgICAgICByZXR1cm4gZmluaXNoZWQ7XG5cbiAgICAgIC8vIDIuIElmIGNvZGUgcG9pbnQgaXMgYW4gQVNDSUkgY29kZSBwb2ludCwgcmV0dXJuIGEgYnl0ZSB3aG9zZVxuICAgICAgLy8gdmFsdWUgaXMgY29kZSBwb2ludC5cbiAgICAgIGlmIChpc0FTQ0lJQ29kZVBvaW50KGNvZGVfcG9pbnQpKVxuICAgICAgICByZXR1cm4gY29kZV9wb2ludDtcblxuICAgICAgLy8gMy4gTGV0IHBvaW50ZXIgYmUgdGhlIGluZGV4IEJpZzUgcG9pbnRlciBmb3IgY29kZSBwb2ludC5cbiAgICAgIHZhciBwb2ludGVyID0gaW5kZXhCaWc1UG9pbnRlckZvcihjb2RlX3BvaW50KTtcblxuICAgICAgLy8gNC4gSWYgcG9pbnRlciBpcyBudWxsLCByZXR1cm4gZXJyb3Igd2l0aCBjb2RlIHBvaW50LlxuICAgICAgaWYgKHBvaW50ZXIgPT09IG51bGwpXG4gICAgICAgIHJldHVybiBlbmNvZGVyRXJyb3IoY29kZV9wb2ludCk7XG5cbiAgICAgIC8vIDUuIExldCBsZWFkIGJlIGZsb29yKHBvaW50ZXIgLyAxNTcpICsgMHg4MS5cbiAgICAgIHZhciBsZWFkID0gZmxvb3IocG9pbnRlciAvIDE1NykgKyAweDgxO1xuXG4gICAgICAvLyA2LiBJZiBsZWFkIGlzIGxlc3MgdGhhbiAweEExLCByZXR1cm4gZXJyb3Igd2l0aCBjb2RlIHBvaW50LlxuICAgICAgaWYgKGxlYWQgPCAweEExKVxuICAgICAgICByZXR1cm4gZW5jb2RlckVycm9yKGNvZGVfcG9pbnQpO1xuXG4gICAgICAvLyA3LiBMZXQgdHJhaWwgYmUgcG9pbnRlciAlIDE1Ny5cbiAgICAgIHZhciB0cmFpbCA9IHBvaW50ZXIgJSAxNTc7XG5cbiAgICAgIC8vIDguIExldCBvZmZzZXQgYmUgMHg0MCBpZiB0cmFpbCBpcyBsZXNzIHRoYW4gMHgzRiBhbmQgMHg2MlxuICAgICAgLy8gb3RoZXJ3aXNlLlxuICAgICAgdmFyIG9mZnNldCA9IHRyYWlsIDwgMHgzRiA/IDB4NDAgOiAweDYyO1xuXG4gICAgICAvLyBSZXR1cm4gdHdvIGJ5dGVzIHdob3NlIHZhbHVlcyBhcmUgbGVhZCBhbmQgdHJhaWwgKyBvZmZzZXQuXG4gICAgICByZXR1cm4gW2xlYWQsIHRyYWlsICsgb2Zmc2V0XTtcbiAgICB9O1xuICB9XG5cbiAgLyoqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9ucyAqL1xuICBlbmNvZGVyc1snQmlnNSddID0gZnVuY3Rpb24ob3B0aW9ucykge1xuICAgIHJldHVybiBuZXcgQmlnNUVuY29kZXIob3B0aW9ucyk7XG4gIH07XG4gIC8qKiBAcGFyYW0ge3tmYXRhbDogYm9vbGVhbn19IG9wdGlvbnMgKi9cbiAgZGVjb2RlcnNbJ0JpZzUnXSA9IGZ1bmN0aW9uKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IEJpZzVEZWNvZGVyKG9wdGlvbnMpO1xuICB9O1xuXG5cbiAgLy9cbiAgLy8gMTMuIExlZ2FjeSBtdWx0aS1ieXRlIEphcGFuZXNlIGVuY29kaW5nc1xuICAvL1xuXG4gIC8vIDEzLjEgZXVjLWpwXG5cbiAgLy8gMTMuMS4xIGV1Yy1qcCBkZWNvZGVyXG4gIC8qKlxuICAgKiBAY29uc3RydWN0b3JcbiAgICogQGltcGxlbWVudHMge0RlY29kZXJ9XG4gICAqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9uc1xuICAgKi9cbiAgZnVuY3Rpb24gRVVDSlBEZWNvZGVyKG9wdGlvbnMpIHtcbiAgICB2YXIgZmF0YWwgPSBvcHRpb25zLmZhdGFsO1xuXG4gICAgLy8gZXVjLWpwJ3MgZGVjb2RlciBoYXMgYW4gYXNzb2NpYXRlZCBldWMtanAgamlzMDIxMiBmbGFnXG4gICAgLy8gKGluaXRpYWxseSB1bnNldCkgYW5kIGV1Yy1qcCBsZWFkIChpbml0aWFsbHkgMHgwMCkuXG4gICAgdmFyIC8qKiBAdHlwZSB7Ym9vbGVhbn0gKi8gZXVjanBfamlzMDIxMl9mbGFnID0gZmFsc2UsXG4gICAgICAgIC8qKiBAdHlwZSB7bnVtYmVyfSAqLyBldWNqcF9sZWFkID0gMHgwMDtcblxuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7U3RyZWFtfSBzdHJlYW0gVGhlIHN0cmVhbSBvZiBieXRlcyBiZWluZyBkZWNvZGVkLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBiaXRlIFRoZSBuZXh0IGJ5dGUgcmVhZCBmcm9tIHRoZSBzdHJlYW0uXG4gICAgICogQHJldHVybiB7PyhudW1iZXJ8IUFycmF5LjxudW1iZXI+KX0gVGhlIG5leHQgY29kZSBwb2ludChzKVxuICAgICAqICAgICBkZWNvZGVkLCBvciBudWxsIGlmIG5vdCBlbm91Z2ggZGF0YSBleGlzdHMgaW4gdGhlIGlucHV0XG4gICAgICogICAgIHN0cmVhbSB0byBkZWNvZGUgYSBjb21wbGV0ZSBjb2RlIHBvaW50LlxuICAgICAqL1xuICAgIHRoaXMuaGFuZGxlciA9IGZ1bmN0aW9uKHN0cmVhbSwgYml0ZSkge1xuICAgICAgLy8gMS4gSWYgYnl0ZSBpcyBlbmQtb2Ytc3RyZWFtIGFuZCBldWMtanAgbGVhZCBpcyBub3QgMHgwMCwgc2V0XG4gICAgICAvLyBldWMtanAgbGVhZCB0byAweDAwLCBhbmQgcmV0dXJuIGVycm9yLlxuICAgICAgaWYgKGJpdGUgPT09IGVuZF9vZl9zdHJlYW0gJiYgZXVjanBfbGVhZCAhPT0gMHgwMCkge1xuICAgICAgICBldWNqcF9sZWFkID0gMHgwMDtcbiAgICAgICAgcmV0dXJuIGRlY29kZXJFcnJvcihmYXRhbCk7XG4gICAgICB9XG5cbiAgICAgIC8vIDIuIElmIGJ5dGUgaXMgZW5kLW9mLXN0cmVhbSBhbmQgZXVjLWpwIGxlYWQgaXMgMHgwMCwgcmV0dXJuXG4gICAgICAvLyBmaW5pc2hlZC5cbiAgICAgIGlmIChiaXRlID09PSBlbmRfb2Zfc3RyZWFtICYmIGV1Y2pwX2xlYWQgPT09IDB4MDApXG4gICAgICAgIHJldHVybiBmaW5pc2hlZDtcblxuICAgICAgLy8gMy4gSWYgZXVjLWpwIGxlYWQgaXMgMHg4RSBhbmQgYnl0ZSBpcyBpbiB0aGUgcmFuZ2UgMHhBMSB0b1xuICAgICAgLy8gMHhERiwgaW5jbHVzaXZlLCBzZXQgZXVjLWpwIGxlYWQgdG8gMHgwMCBhbmQgcmV0dXJuIGEgY29kZVxuICAgICAgLy8gcG9pbnQgd2hvc2UgdmFsdWUgaXMgMHhGRjYxIOKIkiAweEExICsgYnl0ZS5cbiAgICAgIGlmIChldWNqcF9sZWFkID09PSAweDhFICYmIGluUmFuZ2UoYml0ZSwgMHhBMSwgMHhERikpIHtcbiAgICAgICAgZXVjanBfbGVhZCA9IDB4MDA7XG4gICAgICAgIHJldHVybiAweEZGNjEgLSAweEExICsgYml0ZTtcbiAgICAgIH1cblxuICAgICAgLy8gNC4gSWYgZXVjLWpwIGxlYWQgaXMgMHg4RiBhbmQgYnl0ZSBpcyBpbiB0aGUgcmFuZ2UgMHhBMSB0b1xuICAgICAgLy8gMHhGRSwgaW5jbHVzaXZlLCBzZXQgdGhlIGV1Yy1qcCBqaXMwMjEyIGZsYWcsIHNldCBldWMtanAgbGVhZFxuICAgICAgLy8gdG8gYnl0ZSwgYW5kIHJldHVybiBjb250aW51ZS5cbiAgICAgIGlmIChldWNqcF9sZWFkID09PSAweDhGICYmIGluUmFuZ2UoYml0ZSwgMHhBMSwgMHhGRSkpIHtcbiAgICAgICAgZXVjanBfamlzMDIxMl9mbGFnID0gdHJ1ZTtcbiAgICAgICAgZXVjanBfbGVhZCA9IGJpdGU7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICAvLyA1LiBJZiBldWMtanAgbGVhZCBpcyBub3QgMHgwMCwgbGV0IGxlYWQgYmUgZXVjLWpwIGxlYWQsIHNldFxuICAgICAgLy8gZXVjLWpwIGxlYWQgdG8gMHgwMCwgYW5kIHJ1biB0aGVzZSBzdWJzdGVwczpcbiAgICAgIGlmIChldWNqcF9sZWFkICE9PSAweDAwKSB7XG4gICAgICAgIHZhciBsZWFkID0gZXVjanBfbGVhZDtcbiAgICAgICAgZXVjanBfbGVhZCA9IDB4MDA7XG5cbiAgICAgICAgLy8gMS4gTGV0IGNvZGUgcG9pbnQgYmUgbnVsbC5cbiAgICAgICAgdmFyIGNvZGVfcG9pbnQgPSBudWxsO1xuXG4gICAgICAgIC8vIDIuIElmIGxlYWQgYW5kIGJ5dGUgYXJlIGJvdGggaW4gdGhlIHJhbmdlIDB4QTEgdG8gMHhGRSxcbiAgICAgICAgLy8gaW5jbHVzaXZlLCBzZXQgY29kZSBwb2ludCB0byB0aGUgaW5kZXggY29kZSBwb2ludCBmb3IgKGxlYWRcbiAgICAgICAgLy8g4oiSIDB4QTEpIMOXIDk0ICsgYnl0ZSDiiJIgMHhBMSBpbiBpbmRleCBqaXMwMjA4IGlmIHRoZSBldWMtanBcbiAgICAgICAgLy8gamlzMDIxMiBmbGFnIGlzIHVuc2V0IGFuZCBpbiBpbmRleCBqaXMwMjEyIG90aGVyd2lzZS5cbiAgICAgICAgaWYgKGluUmFuZ2UobGVhZCwgMHhBMSwgMHhGRSkgJiYgaW5SYW5nZShiaXRlLCAweEExLCAweEZFKSkge1xuICAgICAgICAgIGNvZGVfcG9pbnQgPSBpbmRleENvZGVQb2ludEZvcihcbiAgICAgICAgICAgIChsZWFkIC0gMHhBMSkgKiA5NCArIChiaXRlIC0gMHhBMSksXG4gICAgICAgICAgICBpbmRleCghZXVjanBfamlzMDIxMl9mbGFnID8gJ2ppczAyMDgnIDogJ2ppczAyMTInKSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyAzLiBVbnNldCB0aGUgZXVjLWpwIGppczAyMTIgZmxhZy5cbiAgICAgICAgZXVjanBfamlzMDIxMl9mbGFnID0gZmFsc2U7XG5cbiAgICAgICAgLy8gNC4gSWYgYnl0ZSBpcyBub3QgaW4gdGhlIHJhbmdlIDB4QTEgdG8gMHhGRSwgaW5jbHVzaXZlLFxuICAgICAgICAvLyBwcmVwZW5kIGJ5dGUgdG8gc3RyZWFtLlxuICAgICAgICBpZiAoIWluUmFuZ2UoYml0ZSwgMHhBMSwgMHhGRSkpXG4gICAgICAgICAgc3RyZWFtLnByZXBlbmQoYml0ZSk7XG5cbiAgICAgICAgLy8gNS4gSWYgY29kZSBwb2ludCBpcyBudWxsLCByZXR1cm4gZXJyb3IuXG4gICAgICAgIGlmIChjb2RlX3BvaW50ID09PSBudWxsKVxuICAgICAgICAgIHJldHVybiBkZWNvZGVyRXJyb3IoZmF0YWwpO1xuXG4gICAgICAgIC8vIDYuIFJldHVybiBhIGNvZGUgcG9pbnQgd2hvc2UgdmFsdWUgaXMgY29kZSBwb2ludC5cbiAgICAgICAgcmV0dXJuIGNvZGVfcG9pbnQ7XG4gICAgICB9XG5cbiAgICAgIC8vIDYuIElmIGJ5dGUgaXMgYW4gQVNDSUkgYnl0ZSwgcmV0dXJuIGEgY29kZSBwb2ludCB3aG9zZSB2YWx1ZVxuICAgICAgLy8gaXMgYnl0ZS5cbiAgICAgIGlmIChpc0FTQ0lJQnl0ZShiaXRlKSlcbiAgICAgICAgcmV0dXJuIGJpdGU7XG5cbiAgICAgIC8vIDcuIElmIGJ5dGUgaXMgMHg4RSwgMHg4Riwgb3IgaW4gdGhlIHJhbmdlIDB4QTEgdG8gMHhGRSxcbiAgICAgIC8vIGluY2x1c2l2ZSwgc2V0IGV1Yy1qcCBsZWFkIHRvIGJ5dGUgYW5kIHJldHVybiBjb250aW51ZS5cbiAgICAgIGlmIChiaXRlID09PSAweDhFIHx8IGJpdGUgPT09IDB4OEYgfHwgaW5SYW5nZShiaXRlLCAweEExLCAweEZFKSkge1xuICAgICAgICBldWNqcF9sZWFkID0gYml0ZTtcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICB9XG5cbiAgICAgIC8vIDguIFJldHVybiBlcnJvci5cbiAgICAgIHJldHVybiBkZWNvZGVyRXJyb3IoZmF0YWwpO1xuICAgIH07XG4gIH1cblxuICAvLyAxMy4xLjIgZXVjLWpwIGVuY29kZXJcbiAgLyoqXG4gICAqIEBjb25zdHJ1Y3RvclxuICAgKiBAaW1wbGVtZW50cyB7RW5jb2Rlcn1cbiAgICogQHBhcmFtIHt7ZmF0YWw6IGJvb2xlYW59fSBvcHRpb25zXG4gICAqL1xuICBmdW5jdGlvbiBFVUNKUEVuY29kZXIob3B0aW9ucykge1xuICAgIHZhciBmYXRhbCA9IG9wdGlvbnMuZmF0YWw7XG4gICAgLyoqXG4gICAgICogQHBhcmFtIHtTdHJlYW19IHN0cmVhbSBJbnB1dCBzdHJlYW0uXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGNvZGVfcG9pbnQgTmV4dCBjb2RlIHBvaW50IHJlYWQgZnJvbSB0aGUgc3RyZWFtLlxuICAgICAqIEByZXR1cm4geyhudW1iZXJ8IUFycmF5LjxudW1iZXI+KX0gQnl0ZShzKSB0byBlbWl0LlxuICAgICAqL1xuICAgIHRoaXMuaGFuZGxlciA9IGZ1bmN0aW9uKHN0cmVhbSwgY29kZV9wb2ludCkge1xuICAgICAgLy8gMS4gSWYgY29kZSBwb2ludCBpcyBlbmQtb2Ytc3RyZWFtLCByZXR1cm4gZmluaXNoZWQuXG4gICAgICBpZiAoY29kZV9wb2ludCA9PT0gZW5kX29mX3N0cmVhbSlcbiAgICAgICAgcmV0dXJuIGZpbmlzaGVkO1xuXG4gICAgICAvLyAyLiBJZiBjb2RlIHBvaW50IGlzIGFuIEFTQ0lJIGNvZGUgcG9pbnQsIHJldHVybiBhIGJ5dGUgd2hvc2VcbiAgICAgIC8vIHZhbHVlIGlzIGNvZGUgcG9pbnQuXG4gICAgICBpZiAoaXNBU0NJSUNvZGVQb2ludChjb2RlX3BvaW50KSlcbiAgICAgICAgcmV0dXJuIGNvZGVfcG9pbnQ7XG5cbiAgICAgIC8vIDMuIElmIGNvZGUgcG9pbnQgaXMgVSswMEE1LCByZXR1cm4gYnl0ZSAweDVDLlxuICAgICAgaWYgKGNvZGVfcG9pbnQgPT09IDB4MDBBNSlcbiAgICAgICAgcmV0dXJuIDB4NUM7XG5cbiAgICAgIC8vIDQuIElmIGNvZGUgcG9pbnQgaXMgVSsyMDNFLCByZXR1cm4gYnl0ZSAweDdFLlxuICAgICAgaWYgKGNvZGVfcG9pbnQgPT09IDB4MjAzRSlcbiAgICAgICAgcmV0dXJuIDB4N0U7XG5cbiAgICAgIC8vIDUuIElmIGNvZGUgcG9pbnQgaXMgaW4gdGhlIHJhbmdlIFUrRkY2MSB0byBVK0ZGOUYsIGluY2x1c2l2ZSxcbiAgICAgIC8vIHJldHVybiB0d28gYnl0ZXMgd2hvc2UgdmFsdWVzIGFyZSAweDhFIGFuZCBjb2RlIHBvaW50IOKIklxuICAgICAgLy8gMHhGRjYxICsgMHhBMS5cbiAgICAgIGlmIChpblJhbmdlKGNvZGVfcG9pbnQsIDB4RkY2MSwgMHhGRjlGKSlcbiAgICAgICAgcmV0dXJuIFsweDhFLCBjb2RlX3BvaW50IC0gMHhGRjYxICsgMHhBMV07XG5cbiAgICAgIC8vIDYuIElmIGNvZGUgcG9pbnQgaXMgVSsyMjEyLCBzZXQgaXQgdG8gVStGRjBELlxuICAgICAgaWYgKGNvZGVfcG9pbnQgPT09IDB4MjIxMilcbiAgICAgICAgY29kZV9wb2ludCA9IDB4RkYwRDtcblxuICAgICAgLy8gNy4gTGV0IHBvaW50ZXIgYmUgdGhlIGluZGV4IHBvaW50ZXIgZm9yIGNvZGUgcG9pbnQgaW4gaW5kZXhcbiAgICAgIC8vIGppczAyMDguXG4gICAgICB2YXIgcG9pbnRlciA9IGluZGV4UG9pbnRlckZvcihjb2RlX3BvaW50LCBpbmRleCgnamlzMDIwOCcpKTtcblxuICAgICAgLy8gOC4gSWYgcG9pbnRlciBpcyBudWxsLCByZXR1cm4gZXJyb3Igd2l0aCBjb2RlIHBvaW50LlxuICAgICAgaWYgKHBvaW50ZXIgPT09IG51bGwpXG4gICAgICAgIHJldHVybiBlbmNvZGVyRXJyb3IoY29kZV9wb2ludCk7XG5cbiAgICAgIC8vIDkuIExldCBsZWFkIGJlIGZsb29yKHBvaW50ZXIgLyA5NCkgKyAweEExLlxuICAgICAgdmFyIGxlYWQgPSBmbG9vcihwb2ludGVyIC8gOTQpICsgMHhBMTtcblxuICAgICAgLy8gMTAuIExldCB0cmFpbCBiZSBwb2ludGVyICUgOTQgKyAweEExLlxuICAgICAgdmFyIHRyYWlsID0gcG9pbnRlciAlIDk0ICsgMHhBMTtcblxuICAgICAgLy8gMTEuIFJldHVybiB0d28gYnl0ZXMgd2hvc2UgdmFsdWVzIGFyZSBsZWFkIGFuZCB0cmFpbC5cbiAgICAgIHJldHVybiBbbGVhZCwgdHJhaWxdO1xuICAgIH07XG4gIH1cblxuICAvKiogQHBhcmFtIHt7ZmF0YWw6IGJvb2xlYW59fSBvcHRpb25zICovXG4gIGVuY29kZXJzWydFVUMtSlAnXSA9IGZ1bmN0aW9uKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IEVVQ0pQRW5jb2RlcihvcHRpb25zKTtcbiAgfTtcbiAgLyoqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9ucyAqL1xuICBkZWNvZGVyc1snRVVDLUpQJ10gPSBmdW5jdGlvbihvcHRpb25zKSB7XG4gICAgcmV0dXJuIG5ldyBFVUNKUERlY29kZXIob3B0aW9ucyk7XG4gIH07XG5cbiAgLy8gMTMuMiBpc28tMjAyMi1qcFxuXG4gIC8vIDEzLjIuMSBpc28tMjAyMi1qcCBkZWNvZGVyXG4gIC8qKlxuICAgKiBAY29uc3RydWN0b3JcbiAgICogQGltcGxlbWVudHMge0RlY29kZXJ9XG4gICAqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9uc1xuICAgKi9cbiAgZnVuY3Rpb24gSVNPMjAyMkpQRGVjb2RlcihvcHRpb25zKSB7XG4gICAgdmFyIGZhdGFsID0gb3B0aW9ucy5mYXRhbDtcbiAgICAvKiogQGVudW0gKi9cbiAgICB2YXIgc3RhdGVzID0ge1xuICAgICAgQVNDSUk6IDAsXG4gICAgICBSb21hbjogMSxcbiAgICAgIEthdGFrYW5hOiAyLFxuICAgICAgTGVhZEJ5dGU6IDMsXG4gICAgICBUcmFpbEJ5dGU6IDQsXG4gICAgICBFc2NhcGVTdGFydDogNSxcbiAgICAgIEVzY2FwZTogNlxuICAgIH07XG4gICAgLy8gaXNvLTIwMjItanAncyBkZWNvZGVyIGhhcyBhbiBhc3NvY2lhdGVkIGlzby0yMDIyLWpwIGRlY29kZXJcbiAgICAvLyBzdGF0ZSAoaW5pdGlhbGx5IEFTQ0lJKSwgaXNvLTIwMjItanAgZGVjb2RlciBvdXRwdXQgc3RhdGVcbiAgICAvLyAoaW5pdGlhbGx5IEFTQ0lJKSwgaXNvLTIwMjItanAgbGVhZCAoaW5pdGlhbGx5IDB4MDApLCBhbmRcbiAgICAvLyBpc28tMjAyMi1qcCBvdXRwdXQgZmxhZyAoaW5pdGlhbGx5IHVuc2V0KS5cbiAgICB2YXIgLyoqIEB0eXBlIHtudW1iZXJ9ICovIGlzbzIwMjJqcF9kZWNvZGVyX3N0YXRlID0gc3RhdGVzLkFTQ0lJLFxuICAgICAgICAvKiogQHR5cGUge251bWJlcn0gKi8gaXNvMjAyMmpwX2RlY29kZXJfb3V0cHV0X3N0YXRlID0gc3RhdGVzLkFTQ0lJLFxuICAgICAgICAvKiogQHR5cGUge251bWJlcn0gKi8gaXNvMjAyMmpwX2xlYWQgPSAweDAwLFxuICAgICAgICAvKiogQHR5cGUge2Jvb2xlYW59ICovIGlzbzIwMjJqcF9vdXRwdXRfZmxhZyA9IGZhbHNlO1xuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7U3RyZWFtfSBzdHJlYW0gVGhlIHN0cmVhbSBvZiBieXRlcyBiZWluZyBkZWNvZGVkLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBiaXRlIFRoZSBuZXh0IGJ5dGUgcmVhZCBmcm9tIHRoZSBzdHJlYW0uXG4gICAgICogQHJldHVybiB7PyhudW1iZXJ8IUFycmF5LjxudW1iZXI+KX0gVGhlIG5leHQgY29kZSBwb2ludChzKVxuICAgICAqICAgICBkZWNvZGVkLCBvciBudWxsIGlmIG5vdCBlbm91Z2ggZGF0YSBleGlzdHMgaW4gdGhlIGlucHV0XG4gICAgICogICAgIHN0cmVhbSB0byBkZWNvZGUgYSBjb21wbGV0ZSBjb2RlIHBvaW50LlxuICAgICAqL1xuICAgIHRoaXMuaGFuZGxlciA9IGZ1bmN0aW9uKHN0cmVhbSwgYml0ZSkge1xuICAgICAgLy8gc3dpdGNoaW5nIG9uIGlzby0yMDIyLWpwIGRlY29kZXIgc3RhdGU6XG4gICAgICBzd2l0Y2ggKGlzbzIwMjJqcF9kZWNvZGVyX3N0YXRlKSB7XG4gICAgICBkZWZhdWx0OlxuICAgICAgY2FzZSBzdGF0ZXMuQVNDSUk6XG4gICAgICAgIC8vIEFTQ0lJXG4gICAgICAgIC8vIEJhc2VkIG9uIGJ5dGU6XG5cbiAgICAgICAgLy8gMHgxQlxuICAgICAgICBpZiAoYml0ZSA9PT0gMHgxQikge1xuICAgICAgICAgIC8vIFNldCBpc28tMjAyMi1qcCBkZWNvZGVyIHN0YXRlIHRvIGVzY2FwZSBzdGFydCBhbmQgcmV0dXJuXG4gICAgICAgICAgLy8gY29udGludWUuXG4gICAgICAgICAgaXNvMjAyMmpwX2RlY29kZXJfc3RhdGUgPSBzdGF0ZXMuRXNjYXBlU3RhcnQ7XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICAvLyAweDAwIHRvIDB4N0YsIGV4Y2x1ZGluZyAweDBFLCAweDBGLCBhbmQgMHgxQlxuICAgICAgICBpZiAoaW5SYW5nZShiaXRlLCAweDAwLCAweDdGKSAmJiBiaXRlICE9PSAweDBFXG4gICAgICAgICAgICAmJiBiaXRlICE9PSAweDBGICYmIGJpdGUgIT09IDB4MUIpIHtcbiAgICAgICAgICAvLyBVbnNldCB0aGUgaXNvLTIwMjItanAgb3V0cHV0IGZsYWcgYW5kIHJldHVybiBhIGNvZGUgcG9pbnRcbiAgICAgICAgICAvLyB3aG9zZSB2YWx1ZSBpcyBieXRlLlxuICAgICAgICAgIGlzbzIwMjJqcF9vdXRwdXRfZmxhZyA9IGZhbHNlO1xuICAgICAgICAgIHJldHVybiBiaXRlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZW5kLW9mLXN0cmVhbVxuICAgICAgICBpZiAoYml0ZSA9PT0gZW5kX29mX3N0cmVhbSkge1xuICAgICAgICAgIC8vIFJldHVybiBmaW5pc2hlZC5cbiAgICAgICAgICByZXR1cm4gZmluaXNoZWQ7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBPdGhlcndpc2VcbiAgICAgICAgLy8gVW5zZXQgdGhlIGlzby0yMDIyLWpwIG91dHB1dCBmbGFnIGFuZCByZXR1cm4gZXJyb3IuXG4gICAgICAgIGlzbzIwMjJqcF9vdXRwdXRfZmxhZyA9IGZhbHNlO1xuICAgICAgICByZXR1cm4gZGVjb2RlckVycm9yKGZhdGFsKTtcblxuICAgICAgY2FzZSBzdGF0ZXMuUm9tYW46XG4gICAgICAgIC8vIFJvbWFuXG4gICAgICAgIC8vIEJhc2VkIG9uIGJ5dGU6XG5cbiAgICAgICAgLy8gMHgxQlxuICAgICAgICBpZiAoYml0ZSA9PT0gMHgxQikge1xuICAgICAgICAgIC8vIFNldCBpc28tMjAyMi1qcCBkZWNvZGVyIHN0YXRlIHRvIGVzY2FwZSBzdGFydCBhbmQgcmV0dXJuXG4gICAgICAgICAgLy8gY29udGludWUuXG4gICAgICAgICAgaXNvMjAyMmpwX2RlY29kZXJfc3RhdGUgPSBzdGF0ZXMuRXNjYXBlU3RhcnQ7XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICAvLyAweDVDXG4gICAgICAgIGlmIChiaXRlID09PSAweDVDKSB7XG4gICAgICAgICAgLy8gVW5zZXQgdGhlIGlzby0yMDIyLWpwIG91dHB1dCBmbGFnIGFuZCByZXR1cm4gY29kZSBwb2ludFxuICAgICAgICAgIC8vIFUrMDBBNS5cbiAgICAgICAgICBpc28yMDIyanBfb3V0cHV0X2ZsYWcgPSBmYWxzZTtcbiAgICAgICAgICByZXR1cm4gMHgwMEE1O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gMHg3RVxuICAgICAgICBpZiAoYml0ZSA9PT0gMHg3RSkge1xuICAgICAgICAgIC8vIFVuc2V0IHRoZSBpc28tMjAyMi1qcCBvdXRwdXQgZmxhZyBhbmQgcmV0dXJuIGNvZGUgcG9pbnRcbiAgICAgICAgICAvLyBVKzIwM0UuXG4gICAgICAgICAgaXNvMjAyMmpwX291dHB1dF9mbGFnID0gZmFsc2U7XG4gICAgICAgICAgcmV0dXJuIDB4MjAzRTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIDB4MDAgdG8gMHg3RiwgZXhjbHVkaW5nIDB4MEUsIDB4MEYsIDB4MUIsIDB4NUMsIGFuZCAweDdFXG4gICAgICAgIGlmIChpblJhbmdlKGJpdGUsIDB4MDAsIDB4N0YpICYmIGJpdGUgIT09IDB4MEUgJiYgYml0ZSAhPT0gMHgwRlxuICAgICAgICAgICAgJiYgYml0ZSAhPT0gMHgxQiAmJiBiaXRlICE9PSAweDVDICYmIGJpdGUgIT09IDB4N0UpIHtcbiAgICAgICAgICAvLyBVbnNldCB0aGUgaXNvLTIwMjItanAgb3V0cHV0IGZsYWcgYW5kIHJldHVybiBhIGNvZGUgcG9pbnRcbiAgICAgICAgICAvLyB3aG9zZSB2YWx1ZSBpcyBieXRlLlxuICAgICAgICAgIGlzbzIwMjJqcF9vdXRwdXRfZmxhZyA9IGZhbHNlO1xuICAgICAgICAgIHJldHVybiBiaXRlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZW5kLW9mLXN0cmVhbVxuICAgICAgICBpZiAoYml0ZSA9PT0gZW5kX29mX3N0cmVhbSkge1xuICAgICAgICAgIC8vIFJldHVybiBmaW5pc2hlZC5cbiAgICAgICAgICByZXR1cm4gZmluaXNoZWQ7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBPdGhlcndpc2VcbiAgICAgICAgLy8gVW5zZXQgdGhlIGlzby0yMDIyLWpwIG91dHB1dCBmbGFnIGFuZCByZXR1cm4gZXJyb3IuXG4gICAgICAgIGlzbzIwMjJqcF9vdXRwdXRfZmxhZyA9IGZhbHNlO1xuICAgICAgICByZXR1cm4gZGVjb2RlckVycm9yKGZhdGFsKTtcblxuICAgICAgY2FzZSBzdGF0ZXMuS2F0YWthbmE6XG4gICAgICAgIC8vIEthdGFrYW5hXG4gICAgICAgIC8vIEJhc2VkIG9uIGJ5dGU6XG5cbiAgICAgICAgLy8gMHgxQlxuICAgICAgICBpZiAoYml0ZSA9PT0gMHgxQikge1xuICAgICAgICAgIC8vIFNldCBpc28tMjAyMi1qcCBkZWNvZGVyIHN0YXRlIHRvIGVzY2FwZSBzdGFydCBhbmQgcmV0dXJuXG4gICAgICAgICAgLy8gY29udGludWUuXG4gICAgICAgICAgaXNvMjAyMmpwX2RlY29kZXJfc3RhdGUgPSBzdGF0ZXMuRXNjYXBlU3RhcnQ7XG4gICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICAvLyAweDIxIHRvIDB4NUZcbiAgICAgICAgaWYgKGluUmFuZ2UoYml0ZSwgMHgyMSwgMHg1RikpIHtcbiAgICAgICAgICAvLyBVbnNldCB0aGUgaXNvLTIwMjItanAgb3V0cHV0IGZsYWcgYW5kIHJldHVybiBhIGNvZGUgcG9pbnRcbiAgICAgICAgICAvLyB3aG9zZSB2YWx1ZSBpcyAweEZGNjEg4oiSIDB4MjEgKyBieXRlLlxuICAgICAgICAgIGlzbzIwMjJqcF9vdXRwdXRfZmxhZyA9IGZhbHNlO1xuICAgICAgICAgIHJldHVybiAweEZGNjEgLSAweDIxICsgYml0ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGVuZC1vZi1zdHJlYW1cbiAgICAgICAgaWYgKGJpdGUgPT09IGVuZF9vZl9zdHJlYW0pIHtcbiAgICAgICAgICAvLyBSZXR1cm4gZmluaXNoZWQuXG4gICAgICAgICAgcmV0dXJuIGZpbmlzaGVkO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gT3RoZXJ3aXNlXG4gICAgICAgIC8vIFVuc2V0IHRoZSBpc28tMjAyMi1qcCBvdXRwdXQgZmxhZyBhbmQgcmV0dXJuIGVycm9yLlxuICAgICAgICBpc28yMDIyanBfb3V0cHV0X2ZsYWcgPSBmYWxzZTtcbiAgICAgICAgcmV0dXJuIGRlY29kZXJFcnJvcihmYXRhbCk7XG5cbiAgICAgIGNhc2Ugc3RhdGVzLkxlYWRCeXRlOlxuICAgICAgICAvLyBMZWFkIGJ5dGVcbiAgICAgICAgLy8gQmFzZWQgb24gYnl0ZTpcblxuICAgICAgICAvLyAweDFCXG4gICAgICAgIGlmIChiaXRlID09PSAweDFCKSB7XG4gICAgICAgICAgLy8gU2V0IGlzby0yMDIyLWpwIGRlY29kZXIgc3RhdGUgdG8gZXNjYXBlIHN0YXJ0IGFuZCByZXR1cm5cbiAgICAgICAgICAvLyBjb250aW51ZS5cbiAgICAgICAgICBpc28yMDIyanBfZGVjb2Rlcl9zdGF0ZSA9IHN0YXRlcy5Fc2NhcGVTdGFydDtcbiAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIDB4MjEgdG8gMHg3RVxuICAgICAgICBpZiAoaW5SYW5nZShiaXRlLCAweDIxLCAweDdFKSkge1xuICAgICAgICAgIC8vIFVuc2V0IHRoZSBpc28tMjAyMi1qcCBvdXRwdXQgZmxhZywgc2V0IGlzby0yMDIyLWpwIGxlYWRcbiAgICAgICAgICAvLyB0byBieXRlLCBpc28tMjAyMi1qcCBkZWNvZGVyIHN0YXRlIHRvIHRyYWlsIGJ5dGUsIGFuZFxuICAgICAgICAgIC8vIHJldHVybiBjb250aW51ZS5cbiAgICAgICAgICBpc28yMDIyanBfb3V0cHV0X2ZsYWcgPSBmYWxzZTtcbiAgICAgICAgICBpc28yMDIyanBfbGVhZCA9IGJpdGU7XG4gICAgICAgICAgaXNvMjAyMmpwX2RlY29kZXJfc3RhdGUgPSBzdGF0ZXMuVHJhaWxCeXRlO1xuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZW5kLW9mLXN0cmVhbVxuICAgICAgICBpZiAoYml0ZSA9PT0gZW5kX29mX3N0cmVhbSkge1xuICAgICAgICAgIC8vIFJldHVybiBmaW5pc2hlZC5cbiAgICAgICAgICByZXR1cm4gZmluaXNoZWQ7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBPdGhlcndpc2VcbiAgICAgICAgLy8gVW5zZXQgdGhlIGlzby0yMDIyLWpwIG91dHB1dCBmbGFnIGFuZCByZXR1cm4gZXJyb3IuXG4gICAgICAgIGlzbzIwMjJqcF9vdXRwdXRfZmxhZyA9IGZhbHNlO1xuICAgICAgICByZXR1cm4gZGVjb2RlckVycm9yKGZhdGFsKTtcblxuICAgICAgY2FzZSBzdGF0ZXMuVHJhaWxCeXRlOlxuICAgICAgICAvLyBUcmFpbCBieXRlXG4gICAgICAgIC8vIEJhc2VkIG9uIGJ5dGU6XG5cbiAgICAgICAgLy8gMHgxQlxuICAgICAgICBpZiAoYml0ZSA9PT0gMHgxQikge1xuICAgICAgICAgIC8vIFNldCBpc28tMjAyMi1qcCBkZWNvZGVyIHN0YXRlIHRvIGVzY2FwZSBzdGFydCBhbmQgcmV0dXJuXG4gICAgICAgICAgLy8gY29udGludWUuXG4gICAgICAgICAgaXNvMjAyMmpwX2RlY29kZXJfc3RhdGUgPSBzdGF0ZXMuRXNjYXBlU3RhcnQ7XG4gICAgICAgICAgcmV0dXJuIGRlY29kZXJFcnJvcihmYXRhbCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyAweDIxIHRvIDB4N0VcbiAgICAgICAgaWYgKGluUmFuZ2UoYml0ZSwgMHgyMSwgMHg3RSkpIHtcbiAgICAgICAgICAvLyAxLiBTZXQgdGhlIGlzby0yMDIyLWpwIGRlY29kZXIgc3RhdGUgdG8gbGVhZCBieXRlLlxuICAgICAgICAgIGlzbzIwMjJqcF9kZWNvZGVyX3N0YXRlID0gc3RhdGVzLkxlYWRCeXRlO1xuXG4gICAgICAgICAgLy8gMi4gTGV0IHBvaW50ZXIgYmUgKGlzby0yMDIyLWpwIGxlYWQg4oiSIDB4MjEpIMOXIDk0ICsgYnl0ZSDiiJIgMHgyMS5cbiAgICAgICAgICB2YXIgcG9pbnRlciA9IChpc28yMDIyanBfbGVhZCAtIDB4MjEpICogOTQgKyBiaXRlIC0gMHgyMTtcblxuICAgICAgICAgIC8vIDMuIExldCBjb2RlIHBvaW50IGJlIHRoZSBpbmRleCBjb2RlIHBvaW50IGZvciBwb2ludGVyIGluXG4gICAgICAgICAgLy8gaW5kZXggamlzMDIwOC5cbiAgICAgICAgICB2YXIgY29kZV9wb2ludCA9IGluZGV4Q29kZVBvaW50Rm9yKHBvaW50ZXIsIGluZGV4KCdqaXMwMjA4JykpO1xuXG4gICAgICAgICAgLy8gNC4gSWYgY29kZSBwb2ludCBpcyBudWxsLCByZXR1cm4gZXJyb3IuXG4gICAgICAgICAgaWYgKGNvZGVfcG9pbnQgPT09IG51bGwpXG4gICAgICAgICAgICByZXR1cm4gZGVjb2RlckVycm9yKGZhdGFsKTtcblxuICAgICAgICAgIC8vIDUuIFJldHVybiBhIGNvZGUgcG9pbnQgd2hvc2UgdmFsdWUgaXMgY29kZSBwb2ludC5cbiAgICAgICAgICByZXR1cm4gY29kZV9wb2ludDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGVuZC1vZi1zdHJlYW1cbiAgICAgICAgaWYgKGJpdGUgPT09IGVuZF9vZl9zdHJlYW0pIHtcbiAgICAgICAgICAvLyBTZXQgdGhlIGlzby0yMDIyLWpwIGRlY29kZXIgc3RhdGUgdG8gbGVhZCBieXRlLCBwcmVwZW5kXG4gICAgICAgICAgLy8gYnl0ZSB0byBzdHJlYW0sIGFuZCByZXR1cm4gZXJyb3IuXG4gICAgICAgICAgaXNvMjAyMmpwX2RlY29kZXJfc3RhdGUgPSBzdGF0ZXMuTGVhZEJ5dGU7XG4gICAgICAgICAgc3RyZWFtLnByZXBlbmQoYml0ZSk7XG4gICAgICAgICAgcmV0dXJuIGRlY29kZXJFcnJvcihmYXRhbCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBPdGhlcndpc2VcbiAgICAgICAgLy8gU2V0IGlzby0yMDIyLWpwIGRlY29kZXIgc3RhdGUgdG8gbGVhZCBieXRlIGFuZCByZXR1cm5cbiAgICAgICAgLy8gZXJyb3IuXG4gICAgICAgIGlzbzIwMjJqcF9kZWNvZGVyX3N0YXRlID0gc3RhdGVzLkxlYWRCeXRlO1xuICAgICAgICByZXR1cm4gZGVjb2RlckVycm9yKGZhdGFsKTtcblxuICAgICAgY2FzZSBzdGF0ZXMuRXNjYXBlU3RhcnQ6XG4gICAgICAgIC8vIEVzY2FwZSBzdGFydFxuXG4gICAgICAgIC8vIDEuIElmIGJ5dGUgaXMgZWl0aGVyIDB4MjQgb3IgMHgyOCwgc2V0IGlzby0yMDIyLWpwIGxlYWQgdG9cbiAgICAgICAgLy8gYnl0ZSwgaXNvLTIwMjItanAgZGVjb2RlciBzdGF0ZSB0byBlc2NhcGUsIGFuZCByZXR1cm5cbiAgICAgICAgLy8gY29udGludWUuXG4gICAgICAgIGlmIChiaXRlID09PSAweDI0IHx8IGJpdGUgPT09IDB4MjgpIHtcbiAgICAgICAgICBpc28yMDIyanBfbGVhZCA9IGJpdGU7XG4gICAgICAgICAgaXNvMjAyMmpwX2RlY29kZXJfc3RhdGUgPSBzdGF0ZXMuRXNjYXBlO1xuICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gMi4gUHJlcGVuZCBieXRlIHRvIHN0cmVhbS5cbiAgICAgICAgc3RyZWFtLnByZXBlbmQoYml0ZSk7XG5cbiAgICAgICAgLy8gMy4gVW5zZXQgdGhlIGlzby0yMDIyLWpwIG91dHB1dCBmbGFnLCBzZXQgaXNvLTIwMjItanBcbiAgICAgICAgLy8gZGVjb2RlciBzdGF0ZSB0byBpc28tMjAyMi1qcCBkZWNvZGVyIG91dHB1dCBzdGF0ZSwgYW5kXG4gICAgICAgIC8vIHJldHVybiBlcnJvci5cbiAgICAgICAgaXNvMjAyMmpwX291dHB1dF9mbGFnID0gZmFsc2U7XG4gICAgICAgIGlzbzIwMjJqcF9kZWNvZGVyX3N0YXRlID0gaXNvMjAyMmpwX2RlY29kZXJfb3V0cHV0X3N0YXRlO1xuICAgICAgICByZXR1cm4gZGVjb2RlckVycm9yKGZhdGFsKTtcblxuICAgICAgY2FzZSBzdGF0ZXMuRXNjYXBlOlxuICAgICAgICAvLyBFc2NhcGVcblxuICAgICAgICAvLyAxLiBMZXQgbGVhZCBiZSBpc28tMjAyMi1qcCBsZWFkIGFuZCBzZXQgaXNvLTIwMjItanAgbGVhZCB0b1xuICAgICAgICAvLyAweDAwLlxuICAgICAgICB2YXIgbGVhZCA9IGlzbzIwMjJqcF9sZWFkO1xuICAgICAgICBpc28yMDIyanBfbGVhZCA9IDB4MDA7XG5cbiAgICAgICAgLy8gMi4gTGV0IHN0YXRlIGJlIG51bGwuXG4gICAgICAgIHZhciBzdGF0ZSA9IG51bGw7XG5cbiAgICAgICAgLy8gMy4gSWYgbGVhZCBpcyAweDI4IGFuZCBieXRlIGlzIDB4NDIsIHNldCBzdGF0ZSB0byBBU0NJSS5cbiAgICAgICAgaWYgKGxlYWQgPT09IDB4MjggJiYgYml0ZSA9PT0gMHg0MilcbiAgICAgICAgICBzdGF0ZSA9IHN0YXRlcy5BU0NJSTtcblxuICAgICAgICAvLyA0LiBJZiBsZWFkIGlzIDB4MjggYW5kIGJ5dGUgaXMgMHg0QSwgc2V0IHN0YXRlIHRvIFJvbWFuLlxuICAgICAgICBpZiAobGVhZCA9PT0gMHgyOCAmJiBiaXRlID09PSAweDRBKVxuICAgICAgICAgIHN0YXRlID0gc3RhdGVzLlJvbWFuO1xuXG4gICAgICAgIC8vIDUuIElmIGxlYWQgaXMgMHgyOCBhbmQgYnl0ZSBpcyAweDQ5LCBzZXQgc3RhdGUgdG8gS2F0YWthbmEuXG4gICAgICAgIGlmIChsZWFkID09PSAweDI4ICYmIGJpdGUgPT09IDB4NDkpXG4gICAgICAgICAgc3RhdGUgPSBzdGF0ZXMuS2F0YWthbmE7XG5cbiAgICAgICAgLy8gNi4gSWYgbGVhZCBpcyAweDI0IGFuZCBieXRlIGlzIGVpdGhlciAweDQwIG9yIDB4NDIsIHNldFxuICAgICAgICAvLyBzdGF0ZSB0byBsZWFkIGJ5dGUuXG4gICAgICAgIGlmIChsZWFkID09PSAweDI0ICYmIChiaXRlID09PSAweDQwIHx8IGJpdGUgPT09IDB4NDIpKVxuICAgICAgICAgIHN0YXRlID0gc3RhdGVzLkxlYWRCeXRlO1xuXG4gICAgICAgIC8vIDcuIElmIHN0YXRlIGlzIG5vbi1udWxsLCBydW4gdGhlc2Ugc3Vic3RlcHM6XG4gICAgICAgIGlmIChzdGF0ZSAhPT0gbnVsbCkge1xuICAgICAgICAgIC8vIDEuIFNldCBpc28tMjAyMi1qcCBkZWNvZGVyIHN0YXRlIGFuZCBpc28tMjAyMi1qcCBkZWNvZGVyXG4gICAgICAgICAgLy8gb3V0cHV0IHN0YXRlIHRvIHN0YXRlcy5cbiAgICAgICAgICBpc28yMDIyanBfZGVjb2Rlcl9zdGF0ZSA9IGlzbzIwMjJqcF9kZWNvZGVyX3N0YXRlID0gc3RhdGU7XG5cbiAgICAgICAgICAvLyAyLiBMZXQgb3V0cHV0IGZsYWcgYmUgdGhlIGlzby0yMDIyLWpwIG91dHB1dCBmbGFnLlxuICAgICAgICAgIHZhciBvdXRwdXRfZmxhZyA9IGlzbzIwMjJqcF9vdXRwdXRfZmxhZztcblxuICAgICAgICAgIC8vIDMuIFNldCB0aGUgaXNvLTIwMjItanAgb3V0cHV0IGZsYWcuXG4gICAgICAgICAgaXNvMjAyMmpwX291dHB1dF9mbGFnID0gdHJ1ZTtcblxuICAgICAgICAgIC8vIDQuIFJldHVybiBjb250aW51ZSwgaWYgb3V0cHV0IGZsYWcgaXMgdW5zZXQsIGFuZCBlcnJvclxuICAgICAgICAgIC8vIG90aGVyd2lzZS5cbiAgICAgICAgICByZXR1cm4gIW91dHB1dF9mbGFnID8gbnVsbCA6IGRlY29kZXJFcnJvcihmYXRhbCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyA4LiBQcmVwZW5kIGxlYWQgYW5kIGJ5dGUgdG8gc3RyZWFtLlxuICAgICAgICBzdHJlYW0ucHJlcGVuZChbbGVhZCwgYml0ZV0pO1xuXG4gICAgICAgIC8vIDkuIFVuc2V0IHRoZSBpc28tMjAyMi1qcCBvdXRwdXQgZmxhZywgc2V0IGlzby0yMDIyLWpwXG4gICAgICAgIC8vIGRlY29kZXIgc3RhdGUgdG8gaXNvLTIwMjItanAgZGVjb2RlciBvdXRwdXQgc3RhdGUgYW5kXG4gICAgICAgIC8vIHJldHVybiBlcnJvci5cbiAgICAgICAgaXNvMjAyMmpwX291dHB1dF9mbGFnID0gZmFsc2U7XG4gICAgICAgIGlzbzIwMjJqcF9kZWNvZGVyX3N0YXRlID0gaXNvMjAyMmpwX2RlY29kZXJfb3V0cHV0X3N0YXRlO1xuICAgICAgICByZXR1cm4gZGVjb2RlckVycm9yKGZhdGFsKTtcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgLy8gMTMuMi4yIGlzby0yMDIyLWpwIGVuY29kZXJcbiAgLyoqXG4gICAqIEBjb25zdHJ1Y3RvclxuICAgKiBAaW1wbGVtZW50cyB7RW5jb2Rlcn1cbiAgICogQHBhcmFtIHt7ZmF0YWw6IGJvb2xlYW59fSBvcHRpb25zXG4gICAqL1xuICBmdW5jdGlvbiBJU08yMDIySlBFbmNvZGVyKG9wdGlvbnMpIHtcbiAgICB2YXIgZmF0YWwgPSBvcHRpb25zLmZhdGFsO1xuICAgIC8vIGlzby0yMDIyLWpwJ3MgZW5jb2RlciBoYXMgYW4gYXNzb2NpYXRlZCBpc28tMjAyMi1qcCBlbmNvZGVyXG4gICAgLy8gc3RhdGUgd2hpY2ggaXMgb25lIG9mIEFTQ0lJLCBSb21hbiwgYW5kIGppczAyMDggKGluaXRpYWxseVxuICAgIC8vIEFTQ0lJKS5cbiAgICAvKiogQGVudW0gKi9cbiAgICB2YXIgc3RhdGVzID0ge1xuICAgICAgQVNDSUk6IDAsXG4gICAgICBSb21hbjogMSxcbiAgICAgIGppczAyMDg6IDJcbiAgICB9O1xuICAgIHZhciAvKiogQHR5cGUge251bWJlcn0gKi8gaXNvMjAyMmpwX3N0YXRlID0gc3RhdGVzLkFTQ0lJO1xuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7U3RyZWFtfSBzdHJlYW0gSW5wdXQgc3RyZWFtLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBjb2RlX3BvaW50IE5leHQgY29kZSBwb2ludCByZWFkIGZyb20gdGhlIHN0cmVhbS5cbiAgICAgKiBAcmV0dXJuIHsobnVtYmVyfCFBcnJheS48bnVtYmVyPil9IEJ5dGUocykgdG8gZW1pdC5cbiAgICAgKi9cbiAgICB0aGlzLmhhbmRsZXIgPSBmdW5jdGlvbihzdHJlYW0sIGNvZGVfcG9pbnQpIHtcbiAgICAgIC8vIDEuIElmIGNvZGUgcG9pbnQgaXMgZW5kLW9mLXN0cmVhbSBhbmQgaXNvLTIwMjItanAgZW5jb2RlclxuICAgICAgLy8gc3RhdGUgaXMgbm90IEFTQ0lJLCBwcmVwZW5kIGNvZGUgcG9pbnQgdG8gc3RyZWFtLCBzZXRcbiAgICAgIC8vIGlzby0yMDIyLWpwIGVuY29kZXIgc3RhdGUgdG8gQVNDSUksIGFuZCByZXR1cm4gdGhyZWUgYnl0ZXNcbiAgICAgIC8vIDB4MUIgMHgyOCAweDQyLlxuICAgICAgaWYgKGNvZGVfcG9pbnQgPT09IGVuZF9vZl9zdHJlYW0gJiZcbiAgICAgICAgICBpc28yMDIyanBfc3RhdGUgIT09IHN0YXRlcy5BU0NJSSkge1xuICAgICAgICBzdHJlYW0ucHJlcGVuZChjb2RlX3BvaW50KTtcbiAgICAgICAgaXNvMjAyMmpwX3N0YXRlID0gc3RhdGVzLkFTQ0lJO1xuICAgICAgICByZXR1cm4gWzB4MUIsIDB4MjgsIDB4NDJdO1xuICAgICAgfVxuXG4gICAgICAvLyAyLiBJZiBjb2RlIHBvaW50IGlzIGVuZC1vZi1zdHJlYW0gYW5kIGlzby0yMDIyLWpwIGVuY29kZXJcbiAgICAgIC8vIHN0YXRlIGlzIEFTQ0lJLCByZXR1cm4gZmluaXNoZWQuXG4gICAgICBpZiAoY29kZV9wb2ludCA9PT0gZW5kX29mX3N0cmVhbSAmJiBpc28yMDIyanBfc3RhdGUgPT09IHN0YXRlcy5BU0NJSSlcbiAgICAgICAgcmV0dXJuIGZpbmlzaGVkO1xuXG4gICAgICAvLyAzLiBJZiBJU08tMjAyMi1KUCBlbmNvZGVyIHN0YXRlIGlzIEFTQ0lJIG9yIFJvbWFuLCBhbmQgY29kZVxuICAgICAgLy8gcG9pbnQgaXMgVSswMDBFLCBVKzAwMEYsIG9yIFUrMDAxQiwgcmV0dXJuIGVycm9yIHdpdGggVStGRkZELlxuICAgICAgaWYgKChpc28yMDIyanBfc3RhdGUgPT09IHN0YXRlcy5BU0NJSSB8fFxuICAgICAgICAgICBpc28yMDIyanBfc3RhdGUgPT09IHN0YXRlcy5Sb21hbikgJiZcbiAgICAgICAgICAoY29kZV9wb2ludCA9PT0gMHgwMDBFIHx8IGNvZGVfcG9pbnQgPT09IDB4MDAwRiB8fFxuICAgICAgICAgICBjb2RlX3BvaW50ID09PSAweDAwMUIpKSB7XG4gICAgICAgIHJldHVybiBlbmNvZGVyRXJyb3IoMHhGRkZEKTtcbiAgICAgIH1cblxuICAgICAgLy8gNC4gSWYgaXNvLTIwMjItanAgZW5jb2RlciBzdGF0ZSBpcyBBU0NJSSBhbmQgY29kZSBwb2ludCBpcyBhblxuICAgICAgLy8gQVNDSUkgY29kZSBwb2ludCwgcmV0dXJuIGEgYnl0ZSB3aG9zZSB2YWx1ZSBpcyBjb2RlIHBvaW50LlxuICAgICAgaWYgKGlzbzIwMjJqcF9zdGF0ZSA9PT0gc3RhdGVzLkFTQ0lJICYmXG4gICAgICAgICAgaXNBU0NJSUNvZGVQb2ludChjb2RlX3BvaW50KSlcbiAgICAgICAgcmV0dXJuIGNvZGVfcG9pbnQ7XG5cbiAgICAgIC8vIDUuIElmIGlzby0yMDIyLWpwIGVuY29kZXIgc3RhdGUgaXMgUm9tYW4gYW5kIGNvZGUgcG9pbnQgaXMgYW5cbiAgICAgIC8vIEFTQ0lJIGNvZGUgcG9pbnQsIGV4Y2x1ZGluZyBVKzAwNUMgYW5kIFUrMDA3RSwgb3IgaXMgVSswMEE1XG4gICAgICAvLyBvciBVKzIwM0UsIHJ1biB0aGVzZSBzdWJzdGVwczpcbiAgICAgIGlmIChpc28yMDIyanBfc3RhdGUgPT09IHN0YXRlcy5Sb21hbiAmJlxuICAgICAgICAgICgoaXNBU0NJSUNvZGVQb2ludChjb2RlX3BvaW50KSAmJlxuICAgICAgICAgICBjb2RlX3BvaW50ICE9PSAweDAwNUMgJiYgY29kZV9wb2ludCAhPT0gMHgwMDdFKSB8fFxuICAgICAgICAgIChjb2RlX3BvaW50ID09IDB4MDBBNSB8fCBjb2RlX3BvaW50ID09IDB4MjAzRSkpKSB7XG5cbiAgICAgICAgLy8gMS4gSWYgY29kZSBwb2ludCBpcyBhbiBBU0NJSSBjb2RlIHBvaW50LCByZXR1cm4gYSBieXRlXG4gICAgICAgIC8vIHdob3NlIHZhbHVlIGlzIGNvZGUgcG9pbnQuXG4gICAgICAgIGlmIChpc0FTQ0lJQ29kZVBvaW50KGNvZGVfcG9pbnQpKVxuICAgICAgICAgIHJldHVybiBjb2RlX3BvaW50O1xuXG4gICAgICAgIC8vIDIuIElmIGNvZGUgcG9pbnQgaXMgVSswMEE1LCByZXR1cm4gYnl0ZSAweDVDLlxuICAgICAgICBpZiAoY29kZV9wb2ludCA9PT0gMHgwMEE1KVxuICAgICAgICAgIHJldHVybiAweDVDO1xuXG4gICAgICAgIC8vIDMuIElmIGNvZGUgcG9pbnQgaXMgVSsyMDNFLCByZXR1cm4gYnl0ZSAweDdFLlxuICAgICAgICBpZiAoY29kZV9wb2ludCA9PT0gMHgyMDNFKVxuICAgICAgICAgIHJldHVybiAweDdFO1xuICAgICAgfVxuXG4gICAgICAvLyA2LiBJZiBjb2RlIHBvaW50IGlzIGFuIEFTQ0lJIGNvZGUgcG9pbnQsIGFuZCBpc28tMjAyMi1qcFxuICAgICAgLy8gZW5jb2RlciBzdGF0ZSBpcyBub3QgQVNDSUksIHByZXBlbmQgY29kZSBwb2ludCB0byBzdHJlYW0sIHNldFxuICAgICAgLy8gaXNvLTIwMjItanAgZW5jb2RlciBzdGF0ZSB0byBBU0NJSSwgYW5kIHJldHVybiB0aHJlZSBieXRlc1xuICAgICAgLy8gMHgxQiAweDI4IDB4NDIuXG4gICAgICBpZiAoaXNBU0NJSUNvZGVQb2ludChjb2RlX3BvaW50KSAmJlxuICAgICAgICAgIGlzbzIwMjJqcF9zdGF0ZSAhPT0gc3RhdGVzLkFTQ0lJKSB7XG4gICAgICAgIHN0cmVhbS5wcmVwZW5kKGNvZGVfcG9pbnQpO1xuICAgICAgICBpc28yMDIyanBfc3RhdGUgPSBzdGF0ZXMuQVNDSUk7XG4gICAgICAgIHJldHVybiBbMHgxQiwgMHgyOCwgMHg0Ml07XG4gICAgICB9XG5cbiAgICAgIC8vIDcuIElmIGNvZGUgcG9pbnQgaXMgZWl0aGVyIFUrMDBBNSBvciBVKzIwM0UsIGFuZCBpc28tMjAyMi1qcFxuICAgICAgLy8gZW5jb2RlciBzdGF0ZSBpcyBub3QgUm9tYW4sIHByZXBlbmQgY29kZSBwb2ludCB0byBzdHJlYW0sIHNldFxuICAgICAgLy8gaXNvLTIwMjItanAgZW5jb2RlciBzdGF0ZSB0byBSb21hbiwgYW5kIHJldHVybiB0aHJlZSBieXRlc1xuICAgICAgLy8gMHgxQiAweDI4IDB4NEEuXG4gICAgICBpZiAoKGNvZGVfcG9pbnQgPT09IDB4MDBBNSB8fCBjb2RlX3BvaW50ID09PSAweDIwM0UpICYmXG4gICAgICAgICAgaXNvMjAyMmpwX3N0YXRlICE9PSBzdGF0ZXMuUm9tYW4pIHtcbiAgICAgICAgc3RyZWFtLnByZXBlbmQoY29kZV9wb2ludCk7XG4gICAgICAgIGlzbzIwMjJqcF9zdGF0ZSA9IHN0YXRlcy5Sb21hbjtcbiAgICAgICAgcmV0dXJuIFsweDFCLCAweDI4LCAweDRBXTtcbiAgICAgIH1cblxuICAgICAgLy8gOC4gSWYgY29kZSBwb2ludCBpcyBVKzIyMTIsIHNldCBpdCB0byBVK0ZGMEQuXG4gICAgICBpZiAoY29kZV9wb2ludCA9PT0gMHgyMjEyKVxuICAgICAgICBjb2RlX3BvaW50ID0gMHhGRjBEO1xuXG4gICAgICAvLyA5LiBMZXQgcG9pbnRlciBiZSB0aGUgaW5kZXggcG9pbnRlciBmb3IgY29kZSBwb2ludCBpbiBpbmRleFxuICAgICAgLy8gamlzMDIwOC5cbiAgICAgIHZhciBwb2ludGVyID0gaW5kZXhQb2ludGVyRm9yKGNvZGVfcG9pbnQsIGluZGV4KCdqaXMwMjA4JykpO1xuXG4gICAgICAvLyAxMC4gSWYgcG9pbnRlciBpcyBudWxsLCByZXR1cm4gZXJyb3Igd2l0aCBjb2RlIHBvaW50LlxuICAgICAgaWYgKHBvaW50ZXIgPT09IG51bGwpXG4gICAgICAgIHJldHVybiBlbmNvZGVyRXJyb3IoY29kZV9wb2ludCk7XG5cbiAgICAgIC8vIDExLiBJZiBpc28tMjAyMi1qcCBlbmNvZGVyIHN0YXRlIGlzIG5vdCBqaXMwMjA4LCBwcmVwZW5kIGNvZGVcbiAgICAgIC8vIHBvaW50IHRvIHN0cmVhbSwgc2V0IGlzby0yMDIyLWpwIGVuY29kZXIgc3RhdGUgdG8gamlzMDIwOCxcbiAgICAgIC8vIGFuZCByZXR1cm4gdGhyZWUgYnl0ZXMgMHgxQiAweDI0IDB4NDIuXG4gICAgICBpZiAoaXNvMjAyMmpwX3N0YXRlICE9PSBzdGF0ZXMuamlzMDIwOCkge1xuICAgICAgICBzdHJlYW0ucHJlcGVuZChjb2RlX3BvaW50KTtcbiAgICAgICAgaXNvMjAyMmpwX3N0YXRlID0gc3RhdGVzLmppczAyMDg7XG4gICAgICAgIHJldHVybiBbMHgxQiwgMHgyNCwgMHg0Ml07XG4gICAgICB9XG5cbiAgICAgIC8vIDEyLiBMZXQgbGVhZCBiZSBmbG9vcihwb2ludGVyIC8gOTQpICsgMHgyMS5cbiAgICAgIHZhciBsZWFkID0gZmxvb3IocG9pbnRlciAvIDk0KSArIDB4MjE7XG5cbiAgICAgIC8vIDEzLiBMZXQgdHJhaWwgYmUgcG9pbnRlciAlIDk0ICsgMHgyMS5cbiAgICAgIHZhciB0cmFpbCA9IHBvaW50ZXIgJSA5NCArIDB4MjE7XG5cbiAgICAgIC8vIDE0LiBSZXR1cm4gdHdvIGJ5dGVzIHdob3NlIHZhbHVlcyBhcmUgbGVhZCBhbmQgdHJhaWwuXG4gICAgICByZXR1cm4gW2xlYWQsIHRyYWlsXTtcbiAgICB9O1xuICB9XG5cbiAgLyoqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9ucyAqL1xuICBlbmNvZGVyc1snSVNPLTIwMjItSlAnXSA9IGZ1bmN0aW9uKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IElTTzIwMjJKUEVuY29kZXIob3B0aW9ucyk7XG4gIH07XG4gIC8qKiBAcGFyYW0ge3tmYXRhbDogYm9vbGVhbn19IG9wdGlvbnMgKi9cbiAgZGVjb2RlcnNbJ0lTTy0yMDIyLUpQJ10gPSBmdW5jdGlvbihvcHRpb25zKSB7XG4gICAgcmV0dXJuIG5ldyBJU08yMDIySlBEZWNvZGVyKG9wdGlvbnMpO1xuICB9O1xuXG4gIC8vIDEzLjMgU2hpZnRfSklTXG5cbiAgLy8gMTMuMy4xIFNoaWZ0X0pJUyBkZWNvZGVyXG4gIC8qKlxuICAgKiBAY29uc3RydWN0b3JcbiAgICogQGltcGxlbWVudHMge0RlY29kZXJ9XG4gICAqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9uc1xuICAgKi9cbiAgZnVuY3Rpb24gU2hpZnRKSVNEZWNvZGVyKG9wdGlvbnMpIHtcbiAgICB2YXIgZmF0YWwgPSBvcHRpb25zLmZhdGFsO1xuICAgIC8vIFNoaWZ0X0pJUydzIGRlY29kZXIgaGFzIGFuIGFzc29jaWF0ZWQgU2hpZnRfSklTIGxlYWQgKGluaXRpYWxseVxuICAgIC8vIDB4MDApLlxuICAgIHZhciAvKiogQHR5cGUge251bWJlcn0gKi8gU2hpZnRfSklTX2xlYWQgPSAweDAwO1xuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7U3RyZWFtfSBzdHJlYW0gVGhlIHN0cmVhbSBvZiBieXRlcyBiZWluZyBkZWNvZGVkLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBiaXRlIFRoZSBuZXh0IGJ5dGUgcmVhZCBmcm9tIHRoZSBzdHJlYW0uXG4gICAgICogQHJldHVybiB7PyhudW1iZXJ8IUFycmF5LjxudW1iZXI+KX0gVGhlIG5leHQgY29kZSBwb2ludChzKVxuICAgICAqICAgICBkZWNvZGVkLCBvciBudWxsIGlmIG5vdCBlbm91Z2ggZGF0YSBleGlzdHMgaW4gdGhlIGlucHV0XG4gICAgICogICAgIHN0cmVhbSB0byBkZWNvZGUgYSBjb21wbGV0ZSBjb2RlIHBvaW50LlxuICAgICAqL1xuICAgIHRoaXMuaGFuZGxlciA9IGZ1bmN0aW9uKHN0cmVhbSwgYml0ZSkge1xuICAgICAgLy8gMS4gSWYgYnl0ZSBpcyBlbmQtb2Ytc3RyZWFtIGFuZCBTaGlmdF9KSVMgbGVhZCBpcyBub3QgMHgwMCxcbiAgICAgIC8vIHNldCBTaGlmdF9KSVMgbGVhZCB0byAweDAwIGFuZCByZXR1cm4gZXJyb3IuXG4gICAgICBpZiAoYml0ZSA9PT0gZW5kX29mX3N0cmVhbSAmJiBTaGlmdF9KSVNfbGVhZCAhPT0gMHgwMCkge1xuICAgICAgICBTaGlmdF9KSVNfbGVhZCA9IDB4MDA7XG4gICAgICAgIHJldHVybiBkZWNvZGVyRXJyb3IoZmF0YWwpO1xuICAgICAgfVxuXG4gICAgICAvLyAyLiBJZiBieXRlIGlzIGVuZC1vZi1zdHJlYW0gYW5kIFNoaWZ0X0pJUyBsZWFkIGlzIDB4MDAsXG4gICAgICAvLyByZXR1cm4gZmluaXNoZWQuXG4gICAgICBpZiAoYml0ZSA9PT0gZW5kX29mX3N0cmVhbSAmJiBTaGlmdF9KSVNfbGVhZCA9PT0gMHgwMClcbiAgICAgICAgcmV0dXJuIGZpbmlzaGVkO1xuXG4gICAgICAvLyAzLiBJZiBTaGlmdF9KSVMgbGVhZCBpcyBub3QgMHgwMCwgbGV0IGxlYWQgYmUgU2hpZnRfSklTIGxlYWQsXG4gICAgICAvLyBsZXQgcG9pbnRlciBiZSBudWxsLCBzZXQgU2hpZnRfSklTIGxlYWQgdG8gMHgwMCwgYW5kIHRoZW4gcnVuXG4gICAgICAvLyB0aGVzZSBzdWJzdGVwczpcbiAgICAgIGlmIChTaGlmdF9KSVNfbGVhZCAhPT0gMHgwMCkge1xuICAgICAgICB2YXIgbGVhZCA9IFNoaWZ0X0pJU19sZWFkO1xuICAgICAgICB2YXIgcG9pbnRlciA9IG51bGw7XG4gICAgICAgIFNoaWZ0X0pJU19sZWFkID0gMHgwMDtcblxuICAgICAgICAvLyAxLiBMZXQgb2Zmc2V0IGJlIDB4NDAsIGlmIGJ5dGUgaXMgbGVzcyB0aGFuIDB4N0YsIGFuZCAweDQxXG4gICAgICAgIC8vIG90aGVyd2lzZS5cbiAgICAgICAgdmFyIG9mZnNldCA9IChiaXRlIDwgMHg3RikgPyAweDQwIDogMHg0MTtcblxuICAgICAgICAvLyAyLiBMZXQgbGVhZCBvZmZzZXQgYmUgMHg4MSwgaWYgbGVhZCBpcyBsZXNzIHRoYW4gMHhBMCwgYW5kXG4gICAgICAgIC8vIDB4QzEgb3RoZXJ3aXNlLlxuICAgICAgICB2YXIgbGVhZF9vZmZzZXQgPSAobGVhZCA8IDB4QTApID8gMHg4MSA6IDB4QzE7XG5cbiAgICAgICAgLy8gMy4gSWYgYnl0ZSBpcyBpbiB0aGUgcmFuZ2UgMHg0MCB0byAweDdFLCBpbmNsdXNpdmUsIG9yIDB4ODBcbiAgICAgICAgLy8gdG8gMHhGQywgaW5jbHVzaXZlLCBzZXQgcG9pbnRlciB0byAobGVhZCDiiJIgbGVhZCBvZmZzZXQpIMOXXG4gICAgICAgIC8vIDE4OCArIGJ5dGUg4oiSIG9mZnNldC5cbiAgICAgICAgaWYgKGluUmFuZ2UoYml0ZSwgMHg0MCwgMHg3RSkgfHwgaW5SYW5nZShiaXRlLCAweDgwLCAweEZDKSlcbiAgICAgICAgICBwb2ludGVyID0gKGxlYWQgLSBsZWFkX29mZnNldCkgKiAxODggKyBiaXRlIC0gb2Zmc2V0O1xuXG4gICAgICAgIC8vIDQuIElmIHBvaW50ZXIgaXMgaW4gdGhlIHJhbmdlIDg4MzYgdG8gMTA3MTUsIGluY2x1c2l2ZSxcbiAgICAgICAgLy8gcmV0dXJuIGEgY29kZSBwb2ludCB3aG9zZSB2YWx1ZSBpcyAweEUwMDAg4oiSIDg4MzYgKyBwb2ludGVyLlxuICAgICAgICBpZiAoaW5SYW5nZShwb2ludGVyLCA4ODM2LCAxMDcxNSkpXG4gICAgICAgICAgcmV0dXJuIDB4RTAwMCAtIDg4MzYgKyBwb2ludGVyO1xuXG4gICAgICAgIC8vIDUuIExldCBjb2RlIHBvaW50IGJlIG51bGwsIGlmIHBvaW50ZXIgaXMgbnVsbCwgYW5kIHRoZVxuICAgICAgICAvLyBpbmRleCBjb2RlIHBvaW50IGZvciBwb2ludGVyIGluIGluZGV4IGppczAyMDggb3RoZXJ3aXNlLlxuICAgICAgICB2YXIgY29kZV9wb2ludCA9IChwb2ludGVyID09PSBudWxsKSA/IG51bGwgOlxuICAgICAgICAgICAgICBpbmRleENvZGVQb2ludEZvcihwb2ludGVyLCBpbmRleCgnamlzMDIwOCcpKTtcblxuICAgICAgICAvLyA2LiBJZiBjb2RlIHBvaW50IGlzIG51bGwgYW5kIGJ5dGUgaXMgYW4gQVNDSUkgYnl0ZSwgcHJlcGVuZFxuICAgICAgICAvLyBieXRlIHRvIHN0cmVhbS5cbiAgICAgICAgaWYgKGNvZGVfcG9pbnQgPT09IG51bGwgJiYgaXNBU0NJSUJ5dGUoYml0ZSkpXG4gICAgICAgICAgc3RyZWFtLnByZXBlbmQoYml0ZSk7XG5cbiAgICAgICAgLy8gNy4gSWYgY29kZSBwb2ludCBpcyBudWxsLCByZXR1cm4gZXJyb3IuXG4gICAgICAgIGlmIChjb2RlX3BvaW50ID09PSBudWxsKVxuICAgICAgICAgIHJldHVybiBkZWNvZGVyRXJyb3IoZmF0YWwpO1xuXG4gICAgICAgIC8vIDguIFJldHVybiBhIGNvZGUgcG9pbnQgd2hvc2UgdmFsdWUgaXMgY29kZSBwb2ludC5cbiAgICAgICAgcmV0dXJuIGNvZGVfcG9pbnQ7XG4gICAgICB9XG5cbiAgICAgIC8vIDQuIElmIGJ5dGUgaXMgYW4gQVNDSUkgYnl0ZSBvciAweDgwLCByZXR1cm4gYSBjb2RlIHBvaW50XG4gICAgICAvLyB3aG9zZSB2YWx1ZSBpcyBieXRlLlxuICAgICAgaWYgKGlzQVNDSUlCeXRlKGJpdGUpIHx8IGJpdGUgPT09IDB4ODApXG4gICAgICAgIHJldHVybiBiaXRlO1xuXG4gICAgICAvLyA1LiBJZiBieXRlIGlzIGluIHRoZSByYW5nZSAweEExIHRvIDB4REYsIGluY2x1c2l2ZSwgcmV0dXJuIGFcbiAgICAgIC8vIGNvZGUgcG9pbnQgd2hvc2UgdmFsdWUgaXMgMHhGRjYxIOKIkiAweEExICsgYnl0ZS5cbiAgICAgIGlmIChpblJhbmdlKGJpdGUsIDB4QTEsIDB4REYpKVxuICAgICAgICByZXR1cm4gMHhGRjYxIC0gMHhBMSArIGJpdGU7XG5cbiAgICAgIC8vIDYuIElmIGJ5dGUgaXMgaW4gdGhlIHJhbmdlIDB4ODEgdG8gMHg5RiwgaW5jbHVzaXZlLCBvciAweEUwXG4gICAgICAvLyB0byAweEZDLCBpbmNsdXNpdmUsIHNldCBTaGlmdF9KSVMgbGVhZCB0byBieXRlIGFuZCByZXR1cm5cbiAgICAgIC8vIGNvbnRpbnVlLlxuICAgICAgaWYgKGluUmFuZ2UoYml0ZSwgMHg4MSwgMHg5RikgfHwgaW5SYW5nZShiaXRlLCAweEUwLCAweEZDKSkge1xuICAgICAgICBTaGlmdF9KSVNfbGVhZCA9IGJpdGU7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICAvLyA3LiBSZXR1cm4gZXJyb3IuXG4gICAgICByZXR1cm4gZGVjb2RlckVycm9yKGZhdGFsKTtcbiAgICB9O1xuICB9XG5cbiAgLy8gMTMuMy4yIFNoaWZ0X0pJUyBlbmNvZGVyXG4gIC8qKlxuICAgKiBAY29uc3RydWN0b3JcbiAgICogQGltcGxlbWVudHMge0VuY29kZXJ9XG4gICAqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9uc1xuICAgKi9cbiAgZnVuY3Rpb24gU2hpZnRKSVNFbmNvZGVyKG9wdGlvbnMpIHtcbiAgICB2YXIgZmF0YWwgPSBvcHRpb25zLmZhdGFsO1xuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7U3RyZWFtfSBzdHJlYW0gSW5wdXQgc3RyZWFtLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBjb2RlX3BvaW50IE5leHQgY29kZSBwb2ludCByZWFkIGZyb20gdGhlIHN0cmVhbS5cbiAgICAgKiBAcmV0dXJuIHsobnVtYmVyfCFBcnJheS48bnVtYmVyPil9IEJ5dGUocykgdG8gZW1pdC5cbiAgICAgKi9cbiAgICB0aGlzLmhhbmRsZXIgPSBmdW5jdGlvbihzdHJlYW0sIGNvZGVfcG9pbnQpIHtcbiAgICAgIC8vIDEuIElmIGNvZGUgcG9pbnQgaXMgZW5kLW9mLXN0cmVhbSwgcmV0dXJuIGZpbmlzaGVkLlxuICAgICAgaWYgKGNvZGVfcG9pbnQgPT09IGVuZF9vZl9zdHJlYW0pXG4gICAgICAgIHJldHVybiBmaW5pc2hlZDtcblxuICAgICAgLy8gMi4gSWYgY29kZSBwb2ludCBpcyBhbiBBU0NJSSBjb2RlIHBvaW50IG9yIFUrMDA4MCwgcmV0dXJuIGFcbiAgICAgIC8vIGJ5dGUgd2hvc2UgdmFsdWUgaXMgY29kZSBwb2ludC5cbiAgICAgIGlmIChpc0FTQ0lJQ29kZVBvaW50KGNvZGVfcG9pbnQpIHx8IGNvZGVfcG9pbnQgPT09IDB4MDA4MClcbiAgICAgICAgcmV0dXJuIGNvZGVfcG9pbnQ7XG5cbiAgICAgIC8vIDMuIElmIGNvZGUgcG9pbnQgaXMgVSswMEE1LCByZXR1cm4gYnl0ZSAweDVDLlxuICAgICAgaWYgKGNvZGVfcG9pbnQgPT09IDB4MDBBNSlcbiAgICAgICAgcmV0dXJuIDB4NUM7XG5cbiAgICAgIC8vIDQuIElmIGNvZGUgcG9pbnQgaXMgVSsyMDNFLCByZXR1cm4gYnl0ZSAweDdFLlxuICAgICAgaWYgKGNvZGVfcG9pbnQgPT09IDB4MjAzRSlcbiAgICAgICAgcmV0dXJuIDB4N0U7XG5cbiAgICAgIC8vIDUuIElmIGNvZGUgcG9pbnQgaXMgaW4gdGhlIHJhbmdlIFUrRkY2MSB0byBVK0ZGOUYsIGluY2x1c2l2ZSxcbiAgICAgIC8vIHJldHVybiBhIGJ5dGUgd2hvc2UgdmFsdWUgaXMgY29kZSBwb2ludCDiiJIgMHhGRjYxICsgMHhBMS5cbiAgICAgIGlmIChpblJhbmdlKGNvZGVfcG9pbnQsIDB4RkY2MSwgMHhGRjlGKSlcbiAgICAgICAgcmV0dXJuIGNvZGVfcG9pbnQgLSAweEZGNjEgKyAweEExO1xuXG4gICAgICAvLyA2LiBJZiBjb2RlIHBvaW50IGlzIFUrMjIxMiwgc2V0IGl0IHRvIFUrRkYwRC5cbiAgICAgIGlmIChjb2RlX3BvaW50ID09PSAweDIyMTIpXG4gICAgICAgIGNvZGVfcG9pbnQgPSAweEZGMEQ7XG5cbiAgICAgIC8vIDcuIExldCBwb2ludGVyIGJlIHRoZSBpbmRleCBTaGlmdF9KSVMgcG9pbnRlciBmb3IgY29kZSBwb2ludC5cbiAgICAgIHZhciBwb2ludGVyID0gaW5kZXhTaGlmdEpJU1BvaW50ZXJGb3IoY29kZV9wb2ludCk7XG5cbiAgICAgIC8vIDguIElmIHBvaW50ZXIgaXMgbnVsbCwgcmV0dXJuIGVycm9yIHdpdGggY29kZSBwb2ludC5cbiAgICAgIGlmIChwb2ludGVyID09PSBudWxsKVxuICAgICAgICByZXR1cm4gZW5jb2RlckVycm9yKGNvZGVfcG9pbnQpO1xuXG4gICAgICAvLyA5LiBMZXQgbGVhZCBiZSBmbG9vcihwb2ludGVyIC8gMTg4KS5cbiAgICAgIHZhciBsZWFkID0gZmxvb3IocG9pbnRlciAvIDE4OCk7XG5cbiAgICAgIC8vIDEwLiBMZXQgbGVhZCBvZmZzZXQgYmUgMHg4MSwgaWYgbGVhZCBpcyBsZXNzIHRoYW4gMHgxRiwgYW5kXG4gICAgICAvLyAweEMxIG90aGVyd2lzZS5cbiAgICAgIHZhciBsZWFkX29mZnNldCA9IChsZWFkIDwgMHgxRikgPyAweDgxIDogMHhDMTtcblxuICAgICAgLy8gMTEuIExldCB0cmFpbCBiZSBwb2ludGVyICUgMTg4LlxuICAgICAgdmFyIHRyYWlsID0gcG9pbnRlciAlIDE4ODtcblxuICAgICAgLy8gMTIuIExldCBvZmZzZXQgYmUgMHg0MCwgaWYgdHJhaWwgaXMgbGVzcyB0aGFuIDB4M0YsIGFuZCAweDQxXG4gICAgICAvLyBvdGhlcndpc2UuXG4gICAgICB2YXIgb2Zmc2V0ID0gKHRyYWlsIDwgMHgzRikgPyAweDQwIDogMHg0MTtcblxuICAgICAgLy8gMTMuIFJldHVybiB0d28gYnl0ZXMgd2hvc2UgdmFsdWVzIGFyZSBsZWFkICsgbGVhZCBvZmZzZXQgYW5kXG4gICAgICAvLyB0cmFpbCArIG9mZnNldC5cbiAgICAgIHJldHVybiBbbGVhZCArIGxlYWRfb2Zmc2V0LCB0cmFpbCArIG9mZnNldF07XG4gICAgfTtcbiAgfVxuXG4gIC8qKiBAcGFyYW0ge3tmYXRhbDogYm9vbGVhbn19IG9wdGlvbnMgKi9cbiAgZW5jb2RlcnNbJ1NoaWZ0X0pJUyddID0gZnVuY3Rpb24ob3B0aW9ucykge1xuICAgIHJldHVybiBuZXcgU2hpZnRKSVNFbmNvZGVyKG9wdGlvbnMpO1xuICB9O1xuICAvKiogQHBhcmFtIHt7ZmF0YWw6IGJvb2xlYW59fSBvcHRpb25zICovXG4gIGRlY29kZXJzWydTaGlmdF9KSVMnXSA9IGZ1bmN0aW9uKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IFNoaWZ0SklTRGVjb2RlcihvcHRpb25zKTtcbiAgfTtcblxuICAvL1xuICAvLyAxNC4gTGVnYWN5IG11bHRpLWJ5dGUgS29yZWFuIGVuY29kaW5nc1xuICAvL1xuXG4gIC8vIDE0LjEgZXVjLWtyXG5cbiAgLy8gMTQuMS4xIGV1Yy1rciBkZWNvZGVyXG4gIC8qKlxuICAgKiBAY29uc3RydWN0b3JcbiAgICogQGltcGxlbWVudHMge0RlY29kZXJ9XG4gICAqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9uc1xuICAgKi9cbiAgZnVuY3Rpb24gRVVDS1JEZWNvZGVyKG9wdGlvbnMpIHtcbiAgICB2YXIgZmF0YWwgPSBvcHRpb25zLmZhdGFsO1xuXG4gICAgLy8gZXVjLWtyJ3MgZGVjb2RlciBoYXMgYW4gYXNzb2NpYXRlZCBldWMta3IgbGVhZCAoaW5pdGlhbGx5IDB4MDApLlxuICAgIHZhciAvKiogQHR5cGUge251bWJlcn0gKi8gZXVja3JfbGVhZCA9IDB4MDA7XG4gICAgLyoqXG4gICAgICogQHBhcmFtIHtTdHJlYW19IHN0cmVhbSBUaGUgc3RyZWFtIG9mIGJ5dGVzIGJlaW5nIGRlY29kZWQuXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGJpdGUgVGhlIG5leHQgYnl0ZSByZWFkIGZyb20gdGhlIHN0cmVhbS5cbiAgICAgKiBAcmV0dXJuIHs/KG51bWJlcnwhQXJyYXkuPG51bWJlcj4pfSBUaGUgbmV4dCBjb2RlIHBvaW50KHMpXG4gICAgICogICAgIGRlY29kZWQsIG9yIG51bGwgaWYgbm90IGVub3VnaCBkYXRhIGV4aXN0cyBpbiB0aGUgaW5wdXRcbiAgICAgKiAgICAgc3RyZWFtIHRvIGRlY29kZSBhIGNvbXBsZXRlIGNvZGUgcG9pbnQuXG4gICAgICovXG4gICAgdGhpcy5oYW5kbGVyID0gZnVuY3Rpb24oc3RyZWFtLCBiaXRlKSB7XG4gICAgICAvLyAxLiBJZiBieXRlIGlzIGVuZC1vZi1zdHJlYW0gYW5kIGV1Yy1rciBsZWFkIGlzIG5vdCAweDAwLCBzZXRcbiAgICAgIC8vIGV1Yy1rciBsZWFkIHRvIDB4MDAgYW5kIHJldHVybiBlcnJvci5cbiAgICAgIGlmIChiaXRlID09PSBlbmRfb2Zfc3RyZWFtICYmIGV1Y2tyX2xlYWQgIT09IDApIHtcbiAgICAgICAgZXVja3JfbGVhZCA9IDB4MDA7XG4gICAgICAgIHJldHVybiBkZWNvZGVyRXJyb3IoZmF0YWwpO1xuICAgICAgfVxuXG4gICAgICAvLyAyLiBJZiBieXRlIGlzIGVuZC1vZi1zdHJlYW0gYW5kIGV1Yy1rciBsZWFkIGlzIDB4MDAsIHJldHVyblxuICAgICAgLy8gZmluaXNoZWQuXG4gICAgICBpZiAoYml0ZSA9PT0gZW5kX29mX3N0cmVhbSAmJiBldWNrcl9sZWFkID09PSAwKVxuICAgICAgICByZXR1cm4gZmluaXNoZWQ7XG5cbiAgICAgIC8vIDMuIElmIGV1Yy1rciBsZWFkIGlzIG5vdCAweDAwLCBsZXQgbGVhZCBiZSBldWMta3IgbGVhZCwgbGV0XG4gICAgICAvLyBwb2ludGVyIGJlIG51bGwsIHNldCBldWMta3IgbGVhZCB0byAweDAwLCBhbmQgdGhlbiBydW4gdGhlc2VcbiAgICAgIC8vIHN1YnN0ZXBzOlxuICAgICAgaWYgKGV1Y2tyX2xlYWQgIT09IDB4MDApIHtcbiAgICAgICAgdmFyIGxlYWQgPSBldWNrcl9sZWFkO1xuICAgICAgICB2YXIgcG9pbnRlciA9IG51bGw7XG4gICAgICAgIGV1Y2tyX2xlYWQgPSAweDAwO1xuXG4gICAgICAgIC8vIDEuIElmIGJ5dGUgaXMgaW4gdGhlIHJhbmdlIDB4NDEgdG8gMHhGRSwgaW5jbHVzaXZlLCBzZXRcbiAgICAgICAgLy8gcG9pbnRlciB0byAobGVhZCDiiJIgMHg4MSkgw5cgMTkwICsgKGJ5dGUg4oiSIDB4NDEpLlxuICAgICAgICBpZiAoaW5SYW5nZShiaXRlLCAweDQxLCAweEZFKSlcbiAgICAgICAgICBwb2ludGVyID0gKGxlYWQgLSAweDgxKSAqIDE5MCArIChiaXRlIC0gMHg0MSk7XG5cbiAgICAgICAgLy8gMi4gTGV0IGNvZGUgcG9pbnQgYmUgbnVsbCwgaWYgcG9pbnRlciBpcyBudWxsLCBhbmQgdGhlXG4gICAgICAgIC8vIGluZGV4IGNvZGUgcG9pbnQgZm9yIHBvaW50ZXIgaW4gaW5kZXggZXVjLWtyIG90aGVyd2lzZS5cbiAgICAgICAgdmFyIGNvZGVfcG9pbnQgPSAocG9pbnRlciA9PT0gbnVsbClcbiAgICAgICAgICAgICAgPyBudWxsIDogaW5kZXhDb2RlUG9pbnRGb3IocG9pbnRlciwgaW5kZXgoJ2V1Yy1rcicpKTtcblxuICAgICAgICAvLyAzLiBJZiBjb2RlIHBvaW50IGlzIG51bGwgYW5kIGJ5dGUgaXMgYW4gQVNDSUkgYnl0ZSwgcHJlcGVuZFxuICAgICAgICAvLyBieXRlIHRvIHN0cmVhbS5cbiAgICAgICAgaWYgKHBvaW50ZXIgPT09IG51bGwgJiYgaXNBU0NJSUJ5dGUoYml0ZSkpXG4gICAgICAgICAgc3RyZWFtLnByZXBlbmQoYml0ZSk7XG5cbiAgICAgICAgLy8gNC4gSWYgY29kZSBwb2ludCBpcyBudWxsLCByZXR1cm4gZXJyb3IuXG4gICAgICAgIGlmIChjb2RlX3BvaW50ID09PSBudWxsKVxuICAgICAgICAgIHJldHVybiBkZWNvZGVyRXJyb3IoZmF0YWwpO1xuXG4gICAgICAgIC8vIDUuIFJldHVybiBhIGNvZGUgcG9pbnQgd2hvc2UgdmFsdWUgaXMgY29kZSBwb2ludC5cbiAgICAgICAgcmV0dXJuIGNvZGVfcG9pbnQ7XG4gICAgICB9XG5cbiAgICAgIC8vIDQuIElmIGJ5dGUgaXMgYW4gQVNDSUkgYnl0ZSwgcmV0dXJuIGEgY29kZSBwb2ludCB3aG9zZSB2YWx1ZVxuICAgICAgLy8gaXMgYnl0ZS5cbiAgICAgIGlmIChpc0FTQ0lJQnl0ZShiaXRlKSlcbiAgICAgICAgcmV0dXJuIGJpdGU7XG5cbiAgICAgIC8vIDUuIElmIGJ5dGUgaXMgaW4gdGhlIHJhbmdlIDB4ODEgdG8gMHhGRSwgaW5jbHVzaXZlLCBzZXRcbiAgICAgIC8vIGV1Yy1rciBsZWFkIHRvIGJ5dGUgYW5kIHJldHVybiBjb250aW51ZS5cbiAgICAgIGlmIChpblJhbmdlKGJpdGUsIDB4ODEsIDB4RkUpKSB7XG4gICAgICAgIGV1Y2tyX2xlYWQgPSBiaXRlO1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cblxuICAgICAgLy8gNi4gUmV0dXJuIGVycm9yLlxuICAgICAgcmV0dXJuIGRlY29kZXJFcnJvcihmYXRhbCk7XG4gICAgfTtcbiAgfVxuXG4gIC8vIDE0LjEuMiBldWMta3IgZW5jb2RlclxuICAvKipcbiAgICogQGNvbnN0cnVjdG9yXG4gICAqIEBpbXBsZW1lbnRzIHtFbmNvZGVyfVxuICAgKiBAcGFyYW0ge3tmYXRhbDogYm9vbGVhbn19IG9wdGlvbnNcbiAgICovXG4gIGZ1bmN0aW9uIEVVQ0tSRW5jb2RlcihvcHRpb25zKSB7XG4gICAgdmFyIGZhdGFsID0gb3B0aW9ucy5mYXRhbDtcbiAgICAvKipcbiAgICAgKiBAcGFyYW0ge1N0cmVhbX0gc3RyZWFtIElucHV0IHN0cmVhbS5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gY29kZV9wb2ludCBOZXh0IGNvZGUgcG9pbnQgcmVhZCBmcm9tIHRoZSBzdHJlYW0uXG4gICAgICogQHJldHVybiB7KG51bWJlcnwhQXJyYXkuPG51bWJlcj4pfSBCeXRlKHMpIHRvIGVtaXQuXG4gICAgICovXG4gICAgdGhpcy5oYW5kbGVyID0gZnVuY3Rpb24oc3RyZWFtLCBjb2RlX3BvaW50KSB7XG4gICAgICAvLyAxLiBJZiBjb2RlIHBvaW50IGlzIGVuZC1vZi1zdHJlYW0sIHJldHVybiBmaW5pc2hlZC5cbiAgICAgIGlmIChjb2RlX3BvaW50ID09PSBlbmRfb2Zfc3RyZWFtKVxuICAgICAgICByZXR1cm4gZmluaXNoZWQ7XG5cbiAgICAgIC8vIDIuIElmIGNvZGUgcG9pbnQgaXMgYW4gQVNDSUkgY29kZSBwb2ludCwgcmV0dXJuIGEgYnl0ZSB3aG9zZVxuICAgICAgLy8gdmFsdWUgaXMgY29kZSBwb2ludC5cbiAgICAgIGlmIChpc0FTQ0lJQ29kZVBvaW50KGNvZGVfcG9pbnQpKVxuICAgICAgICByZXR1cm4gY29kZV9wb2ludDtcblxuICAgICAgLy8gMy4gTGV0IHBvaW50ZXIgYmUgdGhlIGluZGV4IHBvaW50ZXIgZm9yIGNvZGUgcG9pbnQgaW4gaW5kZXhcbiAgICAgIC8vIGV1Yy1rci5cbiAgICAgIHZhciBwb2ludGVyID0gaW5kZXhQb2ludGVyRm9yKGNvZGVfcG9pbnQsIGluZGV4KCdldWMta3InKSk7XG5cbiAgICAgIC8vIDQuIElmIHBvaW50ZXIgaXMgbnVsbCwgcmV0dXJuIGVycm9yIHdpdGggY29kZSBwb2ludC5cbiAgICAgIGlmIChwb2ludGVyID09PSBudWxsKVxuICAgICAgICByZXR1cm4gZW5jb2RlckVycm9yKGNvZGVfcG9pbnQpO1xuXG4gICAgICAvLyA1LiBMZXQgbGVhZCBiZSBmbG9vcihwb2ludGVyIC8gMTkwKSArIDB4ODEuXG4gICAgICB2YXIgbGVhZCA9IGZsb29yKHBvaW50ZXIgLyAxOTApICsgMHg4MTtcblxuICAgICAgLy8gNi4gTGV0IHRyYWlsIGJlIHBvaW50ZXIgJSAxOTAgKyAweDQxLlxuICAgICAgdmFyIHRyYWlsID0gKHBvaW50ZXIgJSAxOTApICsgMHg0MTtcblxuICAgICAgLy8gNy4gUmV0dXJuIHR3byBieXRlcyB3aG9zZSB2YWx1ZXMgYXJlIGxlYWQgYW5kIHRyYWlsLlxuICAgICAgcmV0dXJuIFtsZWFkLCB0cmFpbF07XG4gICAgfTtcbiAgfVxuXG4gIC8qKiBAcGFyYW0ge3tmYXRhbDogYm9vbGVhbn19IG9wdGlvbnMgKi9cbiAgZW5jb2RlcnNbJ0VVQy1LUiddID0gZnVuY3Rpb24ob3B0aW9ucykge1xuICAgIHJldHVybiBuZXcgRVVDS1JFbmNvZGVyKG9wdGlvbnMpO1xuICB9O1xuICAvKiogQHBhcmFtIHt7ZmF0YWw6IGJvb2xlYW59fSBvcHRpb25zICovXG4gIGRlY29kZXJzWydFVUMtS1InXSA9IGZ1bmN0aW9uKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IEVVQ0tSRGVjb2RlcihvcHRpb25zKTtcbiAgfTtcblxuXG4gIC8vXG4gIC8vIDE1LiBMZWdhY3kgbWlzY2VsbGFuZW91cyBlbmNvZGluZ3NcbiAgLy9cblxuICAvLyAxNS4xIHJlcGxhY2VtZW50XG5cbiAgLy8gTm90IG5lZWRlZCAtIEFQSSB0aHJvd3MgUmFuZ2VFcnJvclxuXG4gIC8vIDE1LjIgQ29tbW9uIGluZnJhc3RydWN0dXJlIGZvciB1dGYtMTZiZSBhbmQgdXRmLTE2bGVcblxuICAvKipcbiAgICogQHBhcmFtIHtudW1iZXJ9IGNvZGVfdW5pdFxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHV0ZjE2YmVcbiAgICogQHJldHVybiB7IUFycmF5LjxudW1iZXI+fSBieXRlc1xuICAgKi9cbiAgZnVuY3Rpb24gY29udmVydENvZGVVbml0VG9CeXRlcyhjb2RlX3VuaXQsIHV0ZjE2YmUpIHtcbiAgICAvLyAxLiBMZXQgYnl0ZTEgYmUgY29kZSB1bml0ID4+IDguXG4gICAgdmFyIGJ5dGUxID0gY29kZV91bml0ID4+IDg7XG5cbiAgICAvLyAyLiBMZXQgYnl0ZTIgYmUgY29kZSB1bml0ICYgMHgwMEZGLlxuICAgIHZhciBieXRlMiA9IGNvZGVfdW5pdCAmIDB4MDBGRjtcblxuICAgIC8vIDMuIFRoZW4gcmV0dXJuIHRoZSBieXRlcyBpbiBvcmRlcjpcbiAgICAgICAgLy8gdXRmLTE2YmUgZmxhZyBpcyBzZXQ6IGJ5dGUxLCB0aGVuIGJ5dGUyLlxuICAgIGlmICh1dGYxNmJlKVxuICAgICAgcmV0dXJuIFtieXRlMSwgYnl0ZTJdO1xuICAgIC8vIHV0Zi0xNmJlIGZsYWcgaXMgdW5zZXQ6IGJ5dGUyLCB0aGVuIGJ5dGUxLlxuICAgIHJldHVybiBbYnl0ZTIsIGJ5dGUxXTtcbiAgfVxuXG4gIC8vIDE1LjIuMSBzaGFyZWQgdXRmLTE2IGRlY29kZXJcbiAgLyoqXG4gICAqIEBjb25zdHJ1Y3RvclxuICAgKiBAaW1wbGVtZW50cyB7RGVjb2Rlcn1cbiAgICogQHBhcmFtIHtib29sZWFufSB1dGYxNl9iZSBUcnVlIGlmIGJpZy1lbmRpYW4sIGZhbHNlIGlmIGxpdHRsZS1lbmRpYW4uXG4gICAqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9uc1xuICAgKi9cbiAgZnVuY3Rpb24gVVRGMTZEZWNvZGVyKHV0ZjE2X2JlLCBvcHRpb25zKSB7XG4gICAgdmFyIGZhdGFsID0gb3B0aW9ucy5mYXRhbDtcbiAgICB2YXIgLyoqIEB0eXBlIHs/bnVtYmVyfSAqLyB1dGYxNl9sZWFkX2J5dGUgPSBudWxsLFxuICAgICAgICAvKiogQHR5cGUgez9udW1iZXJ9ICovIHV0ZjE2X2xlYWRfc3Vycm9nYXRlID0gbnVsbDtcbiAgICAvKipcbiAgICAgKiBAcGFyYW0ge1N0cmVhbX0gc3RyZWFtIFRoZSBzdHJlYW0gb2YgYnl0ZXMgYmVpbmcgZGVjb2RlZC5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gYml0ZSBUaGUgbmV4dCBieXRlIHJlYWQgZnJvbSB0aGUgc3RyZWFtLlxuICAgICAqIEByZXR1cm4gez8obnVtYmVyfCFBcnJheS48bnVtYmVyPil9IFRoZSBuZXh0IGNvZGUgcG9pbnQocylcbiAgICAgKiAgICAgZGVjb2RlZCwgb3IgbnVsbCBpZiBub3QgZW5vdWdoIGRhdGEgZXhpc3RzIGluIHRoZSBpbnB1dFxuICAgICAqICAgICBzdHJlYW0gdG8gZGVjb2RlIGEgY29tcGxldGUgY29kZSBwb2ludC5cbiAgICAgKi9cbiAgICB0aGlzLmhhbmRsZXIgPSBmdW5jdGlvbihzdHJlYW0sIGJpdGUpIHtcbiAgICAgIC8vIDEuIElmIGJ5dGUgaXMgZW5kLW9mLXN0cmVhbSBhbmQgZWl0aGVyIHV0Zi0xNiBsZWFkIGJ5dGUgb3JcbiAgICAgIC8vIHV0Zi0xNiBsZWFkIHN1cnJvZ2F0ZSBpcyBub3QgbnVsbCwgc2V0IHV0Zi0xNiBsZWFkIGJ5dGUgYW5kXG4gICAgICAvLyB1dGYtMTYgbGVhZCBzdXJyb2dhdGUgdG8gbnVsbCwgYW5kIHJldHVybiBlcnJvci5cbiAgICAgIGlmIChiaXRlID09PSBlbmRfb2Zfc3RyZWFtICYmICh1dGYxNl9sZWFkX2J5dGUgIT09IG51bGwgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXRmMTZfbGVhZF9zdXJyb2dhdGUgIT09IG51bGwpKSB7XG4gICAgICAgIHJldHVybiBkZWNvZGVyRXJyb3IoZmF0YWwpO1xuICAgICAgfVxuXG4gICAgICAvLyAyLiBJZiBieXRlIGlzIGVuZC1vZi1zdHJlYW0gYW5kIHV0Zi0xNiBsZWFkIGJ5dGUgYW5kIHV0Zi0xNlxuICAgICAgLy8gbGVhZCBzdXJyb2dhdGUgYXJlIG51bGwsIHJldHVybiBmaW5pc2hlZC5cbiAgICAgIGlmIChiaXRlID09PSBlbmRfb2Zfc3RyZWFtICYmIHV0ZjE2X2xlYWRfYnl0ZSA9PT0gbnVsbCAmJlxuICAgICAgICAgIHV0ZjE2X2xlYWRfc3Vycm9nYXRlID09PSBudWxsKSB7XG4gICAgICAgIHJldHVybiBmaW5pc2hlZDtcbiAgICAgIH1cblxuICAgICAgLy8gMy4gSWYgdXRmLTE2IGxlYWQgYnl0ZSBpcyBudWxsLCBzZXQgdXRmLTE2IGxlYWQgYnl0ZSB0byBieXRlXG4gICAgICAvLyBhbmQgcmV0dXJuIGNvbnRpbnVlLlxuICAgICAgaWYgKHV0ZjE2X2xlYWRfYnl0ZSA9PT0gbnVsbCkge1xuICAgICAgICB1dGYxNl9sZWFkX2J5dGUgPSBiaXRlO1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cblxuICAgICAgLy8gNC4gTGV0IGNvZGUgdW5pdCBiZSB0aGUgcmVzdWx0IG9mOlxuICAgICAgdmFyIGNvZGVfdW5pdDtcbiAgICAgIGlmICh1dGYxNl9iZSkge1xuICAgICAgICAvLyB1dGYtMTZiZSBkZWNvZGVyIGZsYWcgaXMgc2V0XG4gICAgICAgIC8vICAgKHV0Zi0xNiBsZWFkIGJ5dGUgPDwgOCkgKyBieXRlLlxuICAgICAgICBjb2RlX3VuaXQgPSAodXRmMTZfbGVhZF9ieXRlIDw8IDgpICsgYml0ZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIHV0Zi0xNmJlIGRlY29kZXIgZmxhZyBpcyB1bnNldFxuICAgICAgICAvLyAgIChieXRlIDw8IDgpICsgdXRmLTE2IGxlYWQgYnl0ZS5cbiAgICAgICAgY29kZV91bml0ID0gKGJpdGUgPDwgOCkgKyB1dGYxNl9sZWFkX2J5dGU7XG4gICAgICB9XG4gICAgICAvLyBUaGVuIHNldCB1dGYtMTYgbGVhZCBieXRlIHRvIG51bGwuXG4gICAgICB1dGYxNl9sZWFkX2J5dGUgPSBudWxsO1xuXG4gICAgICAvLyA1LiBJZiB1dGYtMTYgbGVhZCBzdXJyb2dhdGUgaXMgbm90IG51bGwsIGxldCBsZWFkIHN1cnJvZ2F0ZVxuICAgICAgLy8gYmUgdXRmLTE2IGxlYWQgc3Vycm9nYXRlLCBzZXQgdXRmLTE2IGxlYWQgc3Vycm9nYXRlIHRvIG51bGwsXG4gICAgICAvLyBhbmQgdGhlbiBydW4gdGhlc2Ugc3Vic3RlcHM6XG4gICAgICBpZiAodXRmMTZfbGVhZF9zdXJyb2dhdGUgIT09IG51bGwpIHtcbiAgICAgICAgdmFyIGxlYWRfc3Vycm9nYXRlID0gdXRmMTZfbGVhZF9zdXJyb2dhdGU7XG4gICAgICAgIHV0ZjE2X2xlYWRfc3Vycm9nYXRlID0gbnVsbDtcblxuICAgICAgICAvLyAxLiBJZiBjb2RlIHVuaXQgaXMgaW4gdGhlIHJhbmdlIFUrREMwMCB0byBVK0RGRkYsXG4gICAgICAgIC8vIGluY2x1c2l2ZSwgcmV0dXJuIGEgY29kZSBwb2ludCB3aG9zZSB2YWx1ZSBpcyAweDEwMDAwICtcbiAgICAgICAgLy8gKChsZWFkIHN1cnJvZ2F0ZSDiiJIgMHhEODAwKSA8PCAxMCkgKyAoY29kZSB1bml0IOKIkiAweERDMDApLlxuICAgICAgICBpZiAoaW5SYW5nZShjb2RlX3VuaXQsIDB4REMwMCwgMHhERkZGKSkge1xuICAgICAgICAgIHJldHVybiAweDEwMDAwICsgKGxlYWRfc3Vycm9nYXRlIC0gMHhEODAwKSAqIDB4NDAwICtcbiAgICAgICAgICAgICAgKGNvZGVfdW5pdCAtIDB4REMwMCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyAyLiBQcmVwZW5kIHRoZSBzZXF1ZW5jZSByZXN1bHRpbmcgb2YgY29udmVydGluZyBjb2RlIHVuaXRcbiAgICAgICAgLy8gdG8gYnl0ZXMgdXNpbmcgdXRmLTE2YmUgZGVjb2RlciBmbGFnIHRvIHN0cmVhbSBhbmQgcmV0dXJuXG4gICAgICAgIC8vIGVycm9yLlxuICAgICAgICBzdHJlYW0ucHJlcGVuZChjb252ZXJ0Q29kZVVuaXRUb0J5dGVzKGNvZGVfdW5pdCwgdXRmMTZfYmUpKTtcbiAgICAgICAgcmV0dXJuIGRlY29kZXJFcnJvcihmYXRhbCk7XG4gICAgICB9XG5cbiAgICAgIC8vIDYuIElmIGNvZGUgdW5pdCBpcyBpbiB0aGUgcmFuZ2UgVStEODAwIHRvIFUrREJGRiwgaW5jbHVzaXZlLFxuICAgICAgLy8gc2V0IHV0Zi0xNiBsZWFkIHN1cnJvZ2F0ZSB0byBjb2RlIHVuaXQgYW5kIHJldHVybiBjb250aW51ZS5cbiAgICAgIGlmIChpblJhbmdlKGNvZGVfdW5pdCwgMHhEODAwLCAweERCRkYpKSB7XG4gICAgICAgIHV0ZjE2X2xlYWRfc3Vycm9nYXRlID0gY29kZV91bml0O1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cblxuICAgICAgLy8gNy4gSWYgY29kZSB1bml0IGlzIGluIHRoZSByYW5nZSBVK0RDMDAgdG8gVStERkZGLCBpbmNsdXNpdmUsXG4gICAgICAvLyByZXR1cm4gZXJyb3IuXG4gICAgICBpZiAoaW5SYW5nZShjb2RlX3VuaXQsIDB4REMwMCwgMHhERkZGKSlcbiAgICAgICAgcmV0dXJuIGRlY29kZXJFcnJvcihmYXRhbCk7XG5cbiAgICAgIC8vIDguIFJldHVybiBjb2RlIHBvaW50IGNvZGUgdW5pdC5cbiAgICAgIHJldHVybiBjb2RlX3VuaXQ7XG4gICAgfTtcbiAgfVxuXG4gIC8vIDE1LjIuMiBzaGFyZWQgdXRmLTE2IGVuY29kZXJcbiAgLyoqXG4gICAqIEBjb25zdHJ1Y3RvclxuICAgKiBAaW1wbGVtZW50cyB7RW5jb2Rlcn1cbiAgICogQHBhcmFtIHtib29sZWFufSB1dGYxNl9iZSBUcnVlIGlmIGJpZy1lbmRpYW4sIGZhbHNlIGlmIGxpdHRsZS1lbmRpYW4uXG4gICAqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9uc1xuICAgKi9cbiAgZnVuY3Rpb24gVVRGMTZFbmNvZGVyKHV0ZjE2X2JlLCBvcHRpb25zKSB7XG4gICAgdmFyIGZhdGFsID0gb3B0aW9ucy5mYXRhbDtcbiAgICAvKipcbiAgICAgKiBAcGFyYW0ge1N0cmVhbX0gc3RyZWFtIElucHV0IHN0cmVhbS5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gY29kZV9wb2ludCBOZXh0IGNvZGUgcG9pbnQgcmVhZCBmcm9tIHRoZSBzdHJlYW0uXG4gICAgICogQHJldHVybiB7KG51bWJlcnwhQXJyYXkuPG51bWJlcj4pfSBCeXRlKHMpIHRvIGVtaXQuXG4gICAgICovXG4gICAgdGhpcy5oYW5kbGVyID0gZnVuY3Rpb24oc3RyZWFtLCBjb2RlX3BvaW50KSB7XG4gICAgICAvLyAxLiBJZiBjb2RlIHBvaW50IGlzIGVuZC1vZi1zdHJlYW0sIHJldHVybiBmaW5pc2hlZC5cbiAgICAgIGlmIChjb2RlX3BvaW50ID09PSBlbmRfb2Zfc3RyZWFtKVxuICAgICAgICByZXR1cm4gZmluaXNoZWQ7XG5cbiAgICAgIC8vIDIuIElmIGNvZGUgcG9pbnQgaXMgaW4gdGhlIHJhbmdlIFUrMDAwMCB0byBVK0ZGRkYsIGluY2x1c2l2ZSxcbiAgICAgIC8vIHJldHVybiB0aGUgc2VxdWVuY2UgcmVzdWx0aW5nIG9mIGNvbnZlcnRpbmcgY29kZSBwb2ludCB0b1xuICAgICAgLy8gYnl0ZXMgdXNpbmcgdXRmLTE2YmUgZW5jb2RlciBmbGFnLlxuICAgICAgaWYgKGluUmFuZ2UoY29kZV9wb2ludCwgMHgwMDAwLCAweEZGRkYpKVxuICAgICAgICByZXR1cm4gY29udmVydENvZGVVbml0VG9CeXRlcyhjb2RlX3BvaW50LCB1dGYxNl9iZSk7XG5cbiAgICAgIC8vIDMuIExldCBsZWFkIGJlICgoY29kZSBwb2ludCDiiJIgMHgxMDAwMCkgPj4gMTApICsgMHhEODAwLFxuICAgICAgLy8gY29udmVydGVkIHRvIGJ5dGVzIHVzaW5nIHV0Zi0xNmJlIGVuY29kZXIgZmxhZy5cbiAgICAgIHZhciBsZWFkID0gY29udmVydENvZGVVbml0VG9CeXRlcyhcbiAgICAgICAgKChjb2RlX3BvaW50IC0gMHgxMDAwMCkgPj4gMTApICsgMHhEODAwLCB1dGYxNl9iZSk7XG5cbiAgICAgIC8vIDQuIExldCB0cmFpbCBiZSAoKGNvZGUgcG9pbnQg4oiSIDB4MTAwMDApICYgMHgzRkYpICsgMHhEQzAwLFxuICAgICAgLy8gY29udmVydGVkIHRvIGJ5dGVzIHVzaW5nIHV0Zi0xNmJlIGVuY29kZXIgZmxhZy5cbiAgICAgIHZhciB0cmFpbCA9IGNvbnZlcnRDb2RlVW5pdFRvQnl0ZXMoXG4gICAgICAgICgoY29kZV9wb2ludCAtIDB4MTAwMDApICYgMHgzRkYpICsgMHhEQzAwLCB1dGYxNl9iZSk7XG5cbiAgICAgIC8vIDUuIFJldHVybiBhIGJ5dGUgc2VxdWVuY2Ugb2YgbGVhZCBmb2xsb3dlZCBieSB0cmFpbC5cbiAgICAgIHJldHVybiBsZWFkLmNvbmNhdCh0cmFpbCk7XG4gICAgfTtcbiAgfVxuXG4gIC8vIDE1LjMgdXRmLTE2YmVcbiAgLy8gMTUuMy4xIHV0Zi0xNmJlIGRlY29kZXJcbiAgLyoqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9ucyAqL1xuICBlbmNvZGVyc1snVVRGLTE2QkUnXSA9IGZ1bmN0aW9uKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IFVURjE2RW5jb2Rlcih0cnVlLCBvcHRpb25zKTtcbiAgfTtcbiAgLy8gMTUuMy4yIHV0Zi0xNmJlIGVuY29kZXJcbiAgLyoqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9ucyAqL1xuICBkZWNvZGVyc1snVVRGLTE2QkUnXSA9IGZ1bmN0aW9uKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IFVURjE2RGVjb2Rlcih0cnVlLCBvcHRpb25zKTtcbiAgfTtcblxuICAvLyAxNS40IHV0Zi0xNmxlXG4gIC8vIDE1LjQuMSB1dGYtMTZsZSBkZWNvZGVyXG4gIC8qKiBAcGFyYW0ge3tmYXRhbDogYm9vbGVhbn19IG9wdGlvbnMgKi9cbiAgZW5jb2RlcnNbJ1VURi0xNkxFJ10gPSBmdW5jdGlvbihvcHRpb25zKSB7XG4gICAgcmV0dXJuIG5ldyBVVEYxNkVuY29kZXIoZmFsc2UsIG9wdGlvbnMpO1xuICB9O1xuICAvLyAxNS40LjIgdXRmLTE2bGUgZW5jb2RlclxuICAvKiogQHBhcmFtIHt7ZmF0YWw6IGJvb2xlYW59fSBvcHRpb25zICovXG4gIGRlY29kZXJzWydVVEYtMTZMRSddID0gZnVuY3Rpb24ob3B0aW9ucykge1xuICAgIHJldHVybiBuZXcgVVRGMTZEZWNvZGVyKGZhbHNlLCBvcHRpb25zKTtcbiAgfTtcblxuICAvLyAxNS41IHgtdXNlci1kZWZpbmVkXG5cbiAgLy8gMTUuNS4xIHgtdXNlci1kZWZpbmVkIGRlY29kZXJcbiAgLyoqXG4gICAqIEBjb25zdHJ1Y3RvclxuICAgKiBAaW1wbGVtZW50cyB7RGVjb2Rlcn1cbiAgICogQHBhcmFtIHt7ZmF0YWw6IGJvb2xlYW59fSBvcHRpb25zXG4gICAqL1xuICBmdW5jdGlvbiBYVXNlckRlZmluZWREZWNvZGVyKG9wdGlvbnMpIHtcbiAgICB2YXIgZmF0YWwgPSBvcHRpb25zLmZhdGFsO1xuICAgIC8qKlxuICAgICAqIEBwYXJhbSB7U3RyZWFtfSBzdHJlYW0gVGhlIHN0cmVhbSBvZiBieXRlcyBiZWluZyBkZWNvZGVkLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBiaXRlIFRoZSBuZXh0IGJ5dGUgcmVhZCBmcm9tIHRoZSBzdHJlYW0uXG4gICAgICogQHJldHVybiB7PyhudW1iZXJ8IUFycmF5LjxudW1iZXI+KX0gVGhlIG5leHQgY29kZSBwb2ludChzKVxuICAgICAqICAgICBkZWNvZGVkLCBvciBudWxsIGlmIG5vdCBlbm91Z2ggZGF0YSBleGlzdHMgaW4gdGhlIGlucHV0XG4gICAgICogICAgIHN0cmVhbSB0byBkZWNvZGUgYSBjb21wbGV0ZSBjb2RlIHBvaW50LlxuICAgICAqL1xuICAgIHRoaXMuaGFuZGxlciA9IGZ1bmN0aW9uKHN0cmVhbSwgYml0ZSkge1xuICAgICAgLy8gMS4gSWYgYnl0ZSBpcyBlbmQtb2Ytc3RyZWFtLCByZXR1cm4gZmluaXNoZWQuXG4gICAgICBpZiAoYml0ZSA9PT0gZW5kX29mX3N0cmVhbSlcbiAgICAgICAgcmV0dXJuIGZpbmlzaGVkO1xuXG4gICAgICAvLyAyLiBJZiBieXRlIGlzIGFuIEFTQ0lJIGJ5dGUsIHJldHVybiBhIGNvZGUgcG9pbnQgd2hvc2UgdmFsdWVcbiAgICAgIC8vIGlzIGJ5dGUuXG4gICAgICBpZiAoaXNBU0NJSUJ5dGUoYml0ZSkpXG4gICAgICAgIHJldHVybiBiaXRlO1xuXG4gICAgICAvLyAzLiBSZXR1cm4gYSBjb2RlIHBvaW50IHdob3NlIHZhbHVlIGlzIDB4Rjc4MCArIGJ5dGUg4oiSIDB4ODAuXG4gICAgICByZXR1cm4gMHhGNzgwICsgYml0ZSAtIDB4ODA7XG4gICAgfTtcbiAgfVxuXG4gIC8vIDE1LjUuMiB4LXVzZXItZGVmaW5lZCBlbmNvZGVyXG4gIC8qKlxuICAgKiBAY29uc3RydWN0b3JcbiAgICogQGltcGxlbWVudHMge0VuY29kZXJ9XG4gICAqIEBwYXJhbSB7e2ZhdGFsOiBib29sZWFufX0gb3B0aW9uc1xuICAgKi9cbiAgZnVuY3Rpb24gWFVzZXJEZWZpbmVkRW5jb2RlcihvcHRpb25zKSB7XG4gICAgdmFyIGZhdGFsID0gb3B0aW9ucy5mYXRhbDtcbiAgICAvKipcbiAgICAgKiBAcGFyYW0ge1N0cmVhbX0gc3RyZWFtIElucHV0IHN0cmVhbS5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gY29kZV9wb2ludCBOZXh0IGNvZGUgcG9pbnQgcmVhZCBmcm9tIHRoZSBzdHJlYW0uXG4gICAgICogQHJldHVybiB7KG51bWJlcnwhQXJyYXkuPG51bWJlcj4pfSBCeXRlKHMpIHRvIGVtaXQuXG4gICAgICovXG4gICAgdGhpcy5oYW5kbGVyID0gZnVuY3Rpb24oc3RyZWFtLCBjb2RlX3BvaW50KSB7XG4gICAgICAvLyAxLklmIGNvZGUgcG9pbnQgaXMgZW5kLW9mLXN0cmVhbSwgcmV0dXJuIGZpbmlzaGVkLlxuICAgICAgaWYgKGNvZGVfcG9pbnQgPT09IGVuZF9vZl9zdHJlYW0pXG4gICAgICAgIHJldHVybiBmaW5pc2hlZDtcblxuICAgICAgLy8gMi4gSWYgY29kZSBwb2ludCBpcyBhbiBBU0NJSSBjb2RlIHBvaW50LCByZXR1cm4gYSBieXRlIHdob3NlXG4gICAgICAvLyB2YWx1ZSBpcyBjb2RlIHBvaW50LlxuICAgICAgaWYgKGlzQVNDSUlDb2RlUG9pbnQoY29kZV9wb2ludCkpXG4gICAgICAgIHJldHVybiBjb2RlX3BvaW50O1xuXG4gICAgICAvLyAzLiBJZiBjb2RlIHBvaW50IGlzIGluIHRoZSByYW5nZSBVK0Y3ODAgdG8gVStGN0ZGLCBpbmNsdXNpdmUsXG4gICAgICAvLyByZXR1cm4gYSBieXRlIHdob3NlIHZhbHVlIGlzIGNvZGUgcG9pbnQg4oiSIDB4Rjc4MCArIDB4ODAuXG4gICAgICBpZiAoaW5SYW5nZShjb2RlX3BvaW50LCAweEY3ODAsIDB4RjdGRikpXG4gICAgICAgIHJldHVybiBjb2RlX3BvaW50IC0gMHhGNzgwICsgMHg4MDtcblxuICAgICAgLy8gNC4gUmV0dXJuIGVycm9yIHdpdGggY29kZSBwb2ludC5cbiAgICAgIHJldHVybiBlbmNvZGVyRXJyb3IoY29kZV9wb2ludCk7XG4gICAgfTtcbiAgfVxuXG4gIC8qKiBAcGFyYW0ge3tmYXRhbDogYm9vbGVhbn19IG9wdGlvbnMgKi9cbiAgZW5jb2RlcnNbJ3gtdXNlci1kZWZpbmVkJ10gPSBmdW5jdGlvbihvcHRpb25zKSB7XG4gICAgcmV0dXJuIG5ldyBYVXNlckRlZmluZWRFbmNvZGVyKG9wdGlvbnMpO1xuICB9O1xuICAvKiogQHBhcmFtIHt7ZmF0YWw6IGJvb2xlYW59fSBvcHRpb25zICovXG4gIGRlY29kZXJzWyd4LXVzZXItZGVmaW5lZCddID0gZnVuY3Rpb24ob3B0aW9ucykge1xuICAgIHJldHVybiBuZXcgWFVzZXJEZWZpbmVkRGVjb2RlcihvcHRpb25zKTtcbiAgfTtcblxuICBpZiAoIWdsb2JhbFsnVGV4dEVuY29kZXInXSlcbiAgICBnbG9iYWxbJ1RleHRFbmNvZGVyJ10gPSBUZXh0RW5jb2RlcjtcbiAgaWYgKCFnbG9iYWxbJ1RleHREZWNvZGVyJ10pXG4gICAgZ2xvYmFsWydUZXh0RGVjb2RlciddID0gVGV4dERlY29kZXI7XG5cbiAgaWYgKHR5cGVvZiBtb2R1bGUgIT09IFwidW5kZWZpbmVkXCIgJiYgbW9kdWxlLmV4cG9ydHMpIHtcbiAgICBtb2R1bGUuZXhwb3J0cyA9IHtcbiAgICAgIFRleHRFbmNvZGVyOiBnbG9iYWxbJ1RleHRFbmNvZGVyJ10sXG4gICAgICBUZXh0RGVjb2RlcjogZ2xvYmFsWydUZXh0RGVjb2RlciddLFxuICAgICAgRW5jb2RpbmdJbmRleGVzOiBnbG9iYWxbXCJlbmNvZGluZy1pbmRleGVzXCJdXG4gICAgfTtcbiAgfVxuXG4vLyBGb3Igc3RyaWN0IGVudmlyb25tZW50cyB3aGVyZSBgdGhpc2AgaW5zaWRlIHRoZSBnbG9iYWwgc2NvcGVcbi8vIGlzIGB1bmRlZmluZWRgLCB0YWtlIGEgcHVyZSBvYmplY3QgaW5zdGVhZFxufSh0aGlzIHx8IHt9KSk7IiwiJ3VzZSBzdHJpY3QnO1xuLyogIVxuICogdHlwZS1kZXRlY3RcbiAqIENvcHlyaWdodChjKSAyMDEzIGpha2UgbHVlciA8amFrZUBhbG9naWNhbHBhcmFkb3guY29tPlxuICogTUlUIExpY2Vuc2VkXG4gKi9cbnZhciBwcm9taXNlRXhpc3RzID0gdHlwZW9mIFByb21pc2UgPT09ICdmdW5jdGlvbic7XG52YXIgZ2xvYmFsT2JqZWN0ID0gdHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgPyB3aW5kb3cgOiB0eXBlb2YgZ2xvYmFsICE9PSAndW5kZWZpbmVkJyA/IGdsb2JhbCA6IHNlbGY7IC8vIGVzbGludC1kaXNhYmxlLWxpbmVcbnZhciBpc0RvbSA9ICdsb2NhdGlvbicgaW4gZ2xvYmFsT2JqZWN0ICYmICdkb2N1bWVudCcgaW4gZ2xvYmFsT2JqZWN0O1xudmFyIHN5bWJvbEV4aXN0cyA9IHR5cGVvZiBTeW1ib2wgIT09ICd1bmRlZmluZWQnO1xudmFyIG1hcEV4aXN0cyA9IHR5cGVvZiBNYXAgIT09ICd1bmRlZmluZWQnO1xudmFyIHNldEV4aXN0cyA9IHR5cGVvZiBTZXQgIT09ICd1bmRlZmluZWQnO1xudmFyIHdlYWtNYXBFeGlzdHMgPSB0eXBlb2YgV2Vha01hcCAhPT0gJ3VuZGVmaW5lZCc7XG52YXIgd2Vha1NldEV4aXN0cyA9IHR5cGVvZiBXZWFrU2V0ICE9PSAndW5kZWZpbmVkJztcbnZhciBkYXRhVmlld0V4aXN0cyA9IHR5cGVvZiBEYXRhVmlldyAhPT0gJ3VuZGVmaW5lZCc7XG52YXIgc3ltYm9sSXRlcmF0b3JFeGlzdHMgPSBzeW1ib2xFeGlzdHMgJiYgdHlwZW9mIFN5bWJvbC5pdGVyYXRvciAhPT0gJ3VuZGVmaW5lZCc7XG52YXIgc3ltYm9sVG9TdHJpbmdUYWdFeGlzdHMgPSBzeW1ib2xFeGlzdHMgJiYgdHlwZW9mIFN5bWJvbC50b1N0cmluZ1RhZyAhPT0gJ3VuZGVmaW5lZCc7XG52YXIgc2V0RW50cmllc0V4aXN0cyA9IHNldEV4aXN0cyAmJiB0eXBlb2YgU2V0LnByb3RvdHlwZS5lbnRyaWVzID09PSAnZnVuY3Rpb24nO1xudmFyIG1hcEVudHJpZXNFeGlzdHMgPSBtYXBFeGlzdHMgJiYgdHlwZW9mIE1hcC5wcm90b3R5cGUuZW50cmllcyA9PT0gJ2Z1bmN0aW9uJztcbnZhciBzZXRJdGVyYXRvclByb3RvdHlwZSA9IHNldEVudHJpZXNFeGlzdHMgJiYgT2JqZWN0LmdldFByb3RvdHlwZU9mKG5ldyBTZXQoKS5lbnRyaWVzKCkpO1xudmFyIG1hcEl0ZXJhdG9yUHJvdG90eXBlID0gbWFwRW50cmllc0V4aXN0cyAmJiBPYmplY3QuZ2V0UHJvdG90eXBlT2YobmV3IE1hcCgpLmVudHJpZXMoKSk7XG52YXIgYXJyYXlJdGVyYXRvckV4aXN0cyA9IHN5bWJvbEl0ZXJhdG9yRXhpc3RzICYmIHR5cGVvZiBBcnJheS5wcm90b3R5cGVbU3ltYm9sLml0ZXJhdG9yXSA9PT0gJ2Z1bmN0aW9uJztcbnZhciBhcnJheUl0ZXJhdG9yUHJvdG90eXBlID0gYXJyYXlJdGVyYXRvckV4aXN0cyAmJiBPYmplY3QuZ2V0UHJvdG90eXBlT2YoW11bU3ltYm9sLml0ZXJhdG9yXSgpKTtcbnZhciBzdHJpbmdJdGVyYXRvckV4aXN0cyA9IHN5bWJvbEl0ZXJhdG9yRXhpc3RzICYmIHR5cGVvZiBBcnJheS5wcm90b3R5cGVbU3ltYm9sLml0ZXJhdG9yXSA9PT0gJ2Z1bmN0aW9uJztcbnZhciBzdHJpbmdJdGVyYXRvclByb3RvdHlwZSA9IHN0cmluZ0l0ZXJhdG9yRXhpc3RzICYmIE9iamVjdC5nZXRQcm90b3R5cGVPZignJ1tTeW1ib2wuaXRlcmF0b3JdKCkpO1xudmFyIHRvU3RyaW5nTGVmdFNsaWNlTGVuZ3RoID0gODtcbnZhciB0b1N0cmluZ1JpZ2h0U2xpY2VMZW5ndGggPSAtMTtcbi8qKlxuICogIyMjIHR5cGVPZiAob2JqKVxuICpcbiAqIFVzZXMgYE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmdgIHRvIGRldGVybWluZSB0aGUgdHlwZSBvZiBhbiBvYmplY3QsXG4gKiBub3JtYWxpc2luZyBiZWhhdmlvdXIgYWNyb3NzIGVuZ2luZSB2ZXJzaW9ucyAmIHdlbGwgb3B0aW1pc2VkLlxuICpcbiAqIEBwYXJhbSB7TWl4ZWR9IG9iamVjdFxuICogQHJldHVybiB7U3RyaW5nfSBvYmplY3QgdHlwZVxuICogQGFwaSBwdWJsaWNcbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiB0eXBlRGV0ZWN0KG9iaikge1xuICAvKiAhIFNwZWVkIG9wdGltaXNhdGlvblxuICAgKiBQcmU6XG4gICAqICAgc3RyaW5nIGxpdGVyYWwgICAgIHggMywwMzksMDM1IG9wcy9zZWMgwrExLjYyJSAoNzggcnVucyBzYW1wbGVkKVxuICAgKiAgIGJvb2xlYW4gbGl0ZXJhbCAgICB4IDEsNDI0LDEzOCBvcHMvc2VjIMKxNC41NCUgKDc1IHJ1bnMgc2FtcGxlZClcbiAgICogICBudW1iZXIgbGl0ZXJhbCAgICAgeCAxLDY1MywxNTMgb3BzL3NlYyDCsTEuOTElICg4MiBydW5zIHNhbXBsZWQpXG4gICAqICAgdW5kZWZpbmVkICAgICAgICAgIHggOSw5NzgsNjYwIG9wcy9zZWMgwrExLjkyJSAoNzUgcnVucyBzYW1wbGVkKVxuICAgKiAgIGZ1bmN0aW9uICAgICAgICAgICB4IDIsNTU2LDc2OSBvcHMvc2VjIMKxMS43MyUgKDc3IHJ1bnMgc2FtcGxlZClcbiAgICogUG9zdDpcbiAgICogICBzdHJpbmcgbGl0ZXJhbCAgICAgeCAzOCw1NjQsNzk2IG9wcy9zZWMgwrExLjE1JSAoNzkgcnVucyBzYW1wbGVkKVxuICAgKiAgIGJvb2xlYW4gbGl0ZXJhbCAgICB4IDMxLDE0OCw5NDAgb3BzL3NlYyDCsTEuMTAlICg3OSBydW5zIHNhbXBsZWQpXG4gICAqICAgbnVtYmVyIGxpdGVyYWwgICAgIHggMzIsNjc5LDMzMCBvcHMvc2VjIMKxMS45MCUgKDc4IHJ1bnMgc2FtcGxlZClcbiAgICogICB1bmRlZmluZWQgICAgICAgICAgeCAzMiwzNjMsMzY4IG9wcy9zZWMgwrExLjA3JSAoODIgcnVucyBzYW1wbGVkKVxuICAgKiAgIGZ1bmN0aW9uICAgICAgICAgICB4IDMxLDI5Niw4NzAgb3BzL3NlYyDCsTAuOTYlICg4MyBydW5zIHNhbXBsZWQpXG4gICAqL1xuICB2YXIgdHlwZW9mT2JqID0gdHlwZW9mIG9iajtcbiAgaWYgKHR5cGVvZk9iaiAhPT0gJ29iamVjdCcpIHtcbiAgICByZXR1cm4gdHlwZW9mT2JqO1xuICB9XG5cbiAgLyogISBTcGVlZCBvcHRpbWlzYXRpb25cbiAgICogUHJlOlxuICAgKiAgIG51bGwgICAgICAgICAgICAgICB4IDI4LDY0NSw3NjUgb3BzL3NlYyDCsTEuMTclICg4MiBydW5zIHNhbXBsZWQpXG4gICAqIFBvc3Q6XG4gICAqICAgbnVsbCAgICAgICAgICAgICAgIHggMzYsNDI4LDk2MiBvcHMvc2VjIMKxMS4zNyUgKDg0IHJ1bnMgc2FtcGxlZClcbiAgICovXG4gIGlmIChvYmogPT09IG51bGwpIHtcbiAgICByZXR1cm4gJ251bGwnO1xuICB9XG5cbiAgLyogISBTcGVjIENvbmZvcm1hbmNlXG4gICAqIFRlc3Q6IGBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwod2luZG93KWBgXG4gICAqICAtIE5vZGUgPT09IFwiW29iamVjdCBnbG9iYWxdXCJcbiAgICogIC0gQ2hyb21lID09PSBcIltvYmplY3QgZ2xvYmFsXVwiXG4gICAqICAtIEZpcmVmb3ggPT09IFwiW29iamVjdCBXaW5kb3ddXCJcbiAgICogIC0gUGhhbnRvbUpTID09PSBcIltvYmplY3QgV2luZG93XVwiXG4gICAqICAtIFNhZmFyaSA9PT0gXCJbb2JqZWN0IFdpbmRvd11cIlxuICAgKiAgLSBJRSAxMSA9PT0gXCJbb2JqZWN0IFdpbmRvd11cIlxuICAgKiAgLSBJRSBFZGdlID09PSBcIltvYmplY3QgV2luZG93XVwiXG4gICAqIFRlc3Q6IGBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwodGhpcylgYFxuICAgKiAgLSBDaHJvbWUgV29ya2VyID09PSBcIltvYmplY3QgZ2xvYmFsXVwiXG4gICAqICAtIEZpcmVmb3ggV29ya2VyID09PSBcIltvYmplY3QgRGVkaWNhdGVkV29ya2VyR2xvYmFsU2NvcGVdXCJcbiAgICogIC0gU2FmYXJpIFdvcmtlciA9PT0gXCJbb2JqZWN0IERlZGljYXRlZFdvcmtlckdsb2JhbFNjb3BlXVwiXG4gICAqICAtIElFIDExIFdvcmtlciA9PT0gXCJbb2JqZWN0IFdvcmtlckdsb2JhbFNjb3BlXVwiXG4gICAqICAtIElFIEVkZ2UgV29ya2VyID09PSBcIltvYmplY3QgV29ya2VyR2xvYmFsU2NvcGVdXCJcbiAgICovXG4gIGlmIChvYmogPT09IGdsb2JhbE9iamVjdCkge1xuICAgIHJldHVybiAnZ2xvYmFsJztcbiAgfVxuXG4gIC8qICEgU3BlZWQgb3B0aW1pc2F0aW9uXG4gICAqIFByZTpcbiAgICogICBhcnJheSBsaXRlcmFsICAgICAgeCAyLDg4OCwzNTIgb3BzL3NlYyDCsTAuNjclICg4MiBydW5zIHNhbXBsZWQpXG4gICAqIFBvc3Q6XG4gICAqICAgYXJyYXkgbGl0ZXJhbCAgICAgIHggMjIsNDc5LDY1MCBvcHMvc2VjIMKxMC45NiUgKDgxIHJ1bnMgc2FtcGxlZClcbiAgICovXG4gIGlmIChBcnJheS5pc0FycmF5KG9iaikpIHtcbiAgICByZXR1cm4gJ0FycmF5JztcbiAgfVxuXG4gIGlmIChpc0RvbSkge1xuICAgIC8qICEgU3BlYyBDb25mb3JtYW5jZVxuICAgICAqIChodHRwczovL2h0bWwuc3BlYy53aGF0d2cub3JnL211bHRpcGFnZS9icm93c2Vycy5odG1sI2xvY2F0aW9uKVxuICAgICAqIFdoYXRXRyBIVE1MJDcuNy4zIC0gVGhlIGBMb2NhdGlvbmAgaW50ZXJmYWNlXG4gICAgICogVGVzdDogYE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh3aW5kb3cubG9jYXRpb24pYGBcbiAgICAgKiAgLSBJRSA8PTExID09PSBcIltvYmplY3QgT2JqZWN0XVwiXG4gICAgICogIC0gSUUgRWRnZSA8PTEzID09PSBcIltvYmplY3QgT2JqZWN0XVwiXG4gICAgICovXG4gICAgaWYgKG9iaiA9PT0gZ2xvYmFsT2JqZWN0LmxvY2F0aW9uKSB7XG4gICAgICByZXR1cm4gJ0xvY2F0aW9uJztcbiAgICB9XG5cbiAgICAvKiAhIFNwZWMgQ29uZm9ybWFuY2VcbiAgICAgKiAoaHR0cHM6Ly9odG1sLnNwZWMud2hhdHdnLm9yZy8jZG9jdW1lbnQpXG4gICAgICogV2hhdFdHIEhUTUwkMy4xLjEgLSBUaGUgYERvY3VtZW50YCBvYmplY3RcbiAgICAgKiBOb3RlOiBNb3N0IGJyb3dzZXJzIGN1cnJlbnRseSBhZGhlciB0byB0aGUgVzNDIERPTSBMZXZlbCAyIHNwZWNcbiAgICAgKiAgICAgICAoaHR0cHM6Ly93d3cudzMub3JnL1RSL0RPTS1MZXZlbC0yLUhUTUwvaHRtbC5odG1sI0lELTI2ODA5MjY4KVxuICAgICAqICAgICAgIHdoaWNoIHN1Z2dlc3RzIHRoYXQgYnJvd3NlcnMgc2hvdWxkIHVzZSBIVE1MVGFibGVDZWxsRWxlbWVudCBmb3JcbiAgICAgKiAgICAgICBib3RoIFREIGFuZCBUSCBlbGVtZW50cy4gV2hhdFdHIHNlcGFyYXRlcyB0aGVzZS5cbiAgICAgKiAgICAgICBXaGF0V0cgSFRNTCBzdGF0ZXM6XG4gICAgICogICAgICAgICA+IEZvciBoaXN0b3JpY2FsIHJlYXNvbnMsIFdpbmRvdyBvYmplY3RzIG11c3QgYWxzbyBoYXZlIGFcbiAgICAgKiAgICAgICAgID4gd3JpdGFibGUsIGNvbmZpZ3VyYWJsZSwgbm9uLWVudW1lcmFibGUgcHJvcGVydHkgbmFtZWRcbiAgICAgKiAgICAgICAgID4gSFRNTERvY3VtZW50IHdob3NlIHZhbHVlIGlzIHRoZSBEb2N1bWVudCBpbnRlcmZhY2Ugb2JqZWN0LlxuICAgICAqIFRlc3Q6IGBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoZG9jdW1lbnQpYGBcbiAgICAgKiAgLSBDaHJvbWUgPT09IFwiW29iamVjdCBIVE1MRG9jdW1lbnRdXCJcbiAgICAgKiAgLSBGaXJlZm94ID09PSBcIltvYmplY3QgSFRNTERvY3VtZW50XVwiXG4gICAgICogIC0gU2FmYXJpID09PSBcIltvYmplY3QgSFRNTERvY3VtZW50XVwiXG4gICAgICogIC0gSUUgPD0xMCA9PT0gXCJbb2JqZWN0IERvY3VtZW50XVwiXG4gICAgICogIC0gSUUgMTEgPT09IFwiW29iamVjdCBIVE1MRG9jdW1lbnRdXCJcbiAgICAgKiAgLSBJRSBFZGdlIDw9MTMgPT09IFwiW29iamVjdCBIVE1MRG9jdW1lbnRdXCJcbiAgICAgKi9cbiAgICBpZiAob2JqID09PSBnbG9iYWxPYmplY3QuZG9jdW1lbnQpIHtcbiAgICAgIHJldHVybiAnRG9jdW1lbnQnO1xuICAgIH1cblxuICAgIC8qICEgU3BlYyBDb25mb3JtYW5jZVxuICAgICAqIChodHRwczovL2h0bWwuc3BlYy53aGF0d2cub3JnL211bHRpcGFnZS93ZWJhcHBhcGlzLmh0bWwjbWltZXR5cGVhcnJheSlcbiAgICAgKiBXaGF0V0cgSFRNTCQ4LjYuMS41IC0gUGx1Z2lucyAtIEludGVyZmFjZSBNaW1lVHlwZUFycmF5XG4gICAgICogVGVzdDogYE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChuYXZpZ2F0b3IubWltZVR5cGVzKWBgXG4gICAgICogIC0gSUUgPD0xMCA9PT0gXCJbb2JqZWN0IE1TTWltZVR5cGVzQ29sbGVjdGlvbl1cIlxuICAgICAqL1xuICAgIGlmIChvYmogPT09IChnbG9iYWxPYmplY3QubmF2aWdhdG9yIHx8IHt9KS5taW1lVHlwZXMpIHtcbiAgICAgIHJldHVybiAnTWltZVR5cGVBcnJheSc7XG4gICAgfVxuXG4gICAgLyogISBTcGVjIENvbmZvcm1hbmNlXG4gICAgICogKGh0dHBzOi8vaHRtbC5zcGVjLndoYXR3Zy5vcmcvbXVsdGlwYWdlL3dlYmFwcGFwaXMuaHRtbCNwbHVnaW5hcnJheSlcbiAgICAgKiBXaGF0V0cgSFRNTCQ4LjYuMS41IC0gUGx1Z2lucyAtIEludGVyZmFjZSBQbHVnaW5BcnJheVxuICAgICAqIFRlc3Q6IGBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwobmF2aWdhdG9yLnBsdWdpbnMpYGBcbiAgICAgKiAgLSBJRSA8PTEwID09PSBcIltvYmplY3QgTVNQbHVnaW5zQ29sbGVjdGlvbl1cIlxuICAgICAqL1xuICAgIGlmIChvYmogPT09IChnbG9iYWxPYmplY3QubmF2aWdhdG9yIHx8IHt9KS5wbHVnaW5zKSB7XG4gICAgICByZXR1cm4gJ1BsdWdpbkFycmF5JztcbiAgICB9XG5cbiAgICAvKiAhIFNwZWMgQ29uZm9ybWFuY2VcbiAgICAgKiAoaHR0cHM6Ly9odG1sLnNwZWMud2hhdHdnLm9yZy9tdWx0aXBhZ2Uvd2ViYXBwYXBpcy5odG1sI3BsdWdpbmFycmF5KVxuICAgICAqIFdoYXRXRyBIVE1MJDQuNC40IC0gVGhlIGBibG9ja3F1b3RlYCBlbGVtZW50IC0gSW50ZXJmYWNlIGBIVE1MUXVvdGVFbGVtZW50YFxuICAgICAqIFRlc3Q6IGBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYmxvY2txdW90ZScpKWBgXG4gICAgICogIC0gSUUgPD0xMCA9PT0gXCJbb2JqZWN0IEhUTUxCbG9ja0VsZW1lbnRdXCJcbiAgICAgKi9cbiAgICBpZiAob2JqIGluc3RhbmNlb2YgSFRNTEVsZW1lbnQgJiYgb2JqLnRhZ05hbWUgPT09ICdCTE9DS1FVT1RFJykge1xuICAgICAgcmV0dXJuICdIVE1MUXVvdGVFbGVtZW50JztcbiAgICB9XG5cbiAgICAvKiAhIFNwZWMgQ29uZm9ybWFuY2VcbiAgICAgKiAoaHR0cHM6Ly9odG1sLnNwZWMud2hhdHdnLm9yZy8jaHRtbHRhYmxlZGF0YWNlbGxlbGVtZW50KVxuICAgICAqIFdoYXRXRyBIVE1MJDQuOS45IC0gVGhlIGB0ZGAgZWxlbWVudCAtIEludGVyZmFjZSBgSFRNTFRhYmxlRGF0YUNlbGxFbGVtZW50YFxuICAgICAqIE5vdGU6IE1vc3QgYnJvd3NlcnMgY3VycmVudGx5IGFkaGVyIHRvIHRoZSBXM0MgRE9NIExldmVsIDIgc3BlY1xuICAgICAqICAgICAgIChodHRwczovL3d3dy53My5vcmcvVFIvRE9NLUxldmVsLTItSFRNTC9odG1sLmh0bWwjSUQtODI5MTUwNzUpXG4gICAgICogICAgICAgd2hpY2ggc3VnZ2VzdHMgdGhhdCBicm93c2VycyBzaG91bGQgdXNlIEhUTUxUYWJsZUNlbGxFbGVtZW50IGZvclxuICAgICAqICAgICAgIGJvdGggVEQgYW5kIFRIIGVsZW1lbnRzLiBXaGF0V0cgc2VwYXJhdGVzIHRoZXNlLlxuICAgICAqIFRlc3Q6IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChkb2N1bWVudC5jcmVhdGVFbGVtZW50KCd0ZCcpKVxuICAgICAqICAtIENocm9tZSA9PT0gXCJbb2JqZWN0IEhUTUxUYWJsZUNlbGxFbGVtZW50XVwiXG4gICAgICogIC0gRmlyZWZveCA9PT0gXCJbb2JqZWN0IEhUTUxUYWJsZUNlbGxFbGVtZW50XVwiXG4gICAgICogIC0gU2FmYXJpID09PSBcIltvYmplY3QgSFRNTFRhYmxlQ2VsbEVsZW1lbnRdXCJcbiAgICAgKi9cbiAgICBpZiAob2JqIGluc3RhbmNlb2YgSFRNTEVsZW1lbnQgJiYgb2JqLnRhZ05hbWUgPT09ICdURCcpIHtcbiAgICAgIHJldHVybiAnSFRNTFRhYmxlRGF0YUNlbGxFbGVtZW50JztcbiAgICB9XG5cbiAgICAvKiAhIFNwZWMgQ29uZm9ybWFuY2VcbiAgICAgKiAoaHR0cHM6Ly9odG1sLnNwZWMud2hhdHdnLm9yZy8jaHRtbHRhYmxlaGVhZGVyY2VsbGVsZW1lbnQpXG4gICAgICogV2hhdFdHIEhUTUwkNC45LjkgLSBUaGUgYHRkYCBlbGVtZW50IC0gSW50ZXJmYWNlIGBIVE1MVGFibGVIZWFkZXJDZWxsRWxlbWVudGBcbiAgICAgKiBOb3RlOiBNb3N0IGJyb3dzZXJzIGN1cnJlbnRseSBhZGhlciB0byB0aGUgVzNDIERPTSBMZXZlbCAyIHNwZWNcbiAgICAgKiAgICAgICAoaHR0cHM6Ly93d3cudzMub3JnL1RSL0RPTS1MZXZlbC0yLUhUTUwvaHRtbC5odG1sI0lELTgyOTE1MDc1KVxuICAgICAqICAgICAgIHdoaWNoIHN1Z2dlc3RzIHRoYXQgYnJvd3NlcnMgc2hvdWxkIHVzZSBIVE1MVGFibGVDZWxsRWxlbWVudCBmb3JcbiAgICAgKiAgICAgICBib3RoIFREIGFuZCBUSCBlbGVtZW50cy4gV2hhdFdHIHNlcGFyYXRlcyB0aGVzZS5cbiAgICAgKiBUZXN0OiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndGgnKSlcbiAgICAgKiAgLSBDaHJvbWUgPT09IFwiW29iamVjdCBIVE1MVGFibGVDZWxsRWxlbWVudF1cIlxuICAgICAqICAtIEZpcmVmb3ggPT09IFwiW29iamVjdCBIVE1MVGFibGVDZWxsRWxlbWVudF1cIlxuICAgICAqICAtIFNhZmFyaSA9PT0gXCJbb2JqZWN0IEhUTUxUYWJsZUNlbGxFbGVtZW50XVwiXG4gICAgICovXG4gICAgaWYgKG9iaiBpbnN0YW5jZW9mIEhUTUxFbGVtZW50ICYmIG9iai50YWdOYW1lID09PSAnVEgnKSB7XG4gICAgICByZXR1cm4gJ0hUTUxUYWJsZUhlYWRlckNlbGxFbGVtZW50JztcbiAgICB9XG4gIH1cblxuICAvKiAhIFNwZWVkIG9wdGltaXNhdGlvblxuICAqIFByZTpcbiAgKiAgIEZsb2F0NjRBcnJheSAgICAgICB4IDYyNSw2NDQgb3BzL3NlYyDCsTEuNTglICg4MCBydW5zIHNhbXBsZWQpXG4gICogICBGbG9hdDMyQXJyYXkgICAgICAgeCAxLDI3OSw4NTIgb3BzL3NlYyDCsTIuOTElICg3NyBydW5zIHNhbXBsZWQpXG4gICogICBVaW50MzJBcnJheSAgICAgICAgeCAxLDE3OCwxODUgb3BzL3NlYyDCsTEuOTUlICg4MyBydW5zIHNhbXBsZWQpXG4gICogICBVaW50MTZBcnJheSAgICAgICAgeCAxLDAwOCwzODAgb3BzL3NlYyDCsTIuMjUlICg4MCBydW5zIHNhbXBsZWQpXG4gICogICBVaW50OEFycmF5ICAgICAgICAgeCAxLDEyOCwwNDAgb3BzL3NlYyDCsTIuMTElICg4MSBydW5zIHNhbXBsZWQpXG4gICogICBJbnQzMkFycmF5ICAgICAgICAgeCAxLDE3MCwxMTkgb3BzL3NlYyDCsTIuODglICg4MCBydW5zIHNhbXBsZWQpXG4gICogICBJbnQxNkFycmF5ICAgICAgICAgeCAxLDE3NiwzNDggb3BzL3NlYyDCsTUuNzklICg4NiBydW5zIHNhbXBsZWQpXG4gICogICBJbnQ4QXJyYXkgICAgICAgICAgeCAxLDA1OCw3MDcgb3BzL3NlYyDCsTQuOTQlICg3NyBydW5zIHNhbXBsZWQpXG4gICogICBVaW50OENsYW1wZWRBcnJheSAgeCAxLDExMCw2MzMgb3BzL3NlYyDCsTQuMjAlICg4MCBydW5zIHNhbXBsZWQpXG4gICogUG9zdDpcbiAgKiAgIEZsb2F0NjRBcnJheSAgICAgICB4IDcsMTA1LDY3MSBvcHMvc2VjIMKxMTMuNDclICg2NCBydW5zIHNhbXBsZWQpXG4gICogICBGbG9hdDMyQXJyYXkgICAgICAgeCA1LDg4Nyw5MTIgb3BzL3NlYyDCsTEuNDYlICg4MiBydW5zIHNhbXBsZWQpXG4gICogICBVaW50MzJBcnJheSAgICAgICAgeCA2LDQ5MSw2NjEgb3BzL3NlYyDCsTEuNzYlICg3OSBydW5zIHNhbXBsZWQpXG4gICogICBVaW50MTZBcnJheSAgICAgICAgeCA2LDU1OSw3OTUgb3BzL3NlYyDCsTEuNjclICg4MiBydW5zIHNhbXBsZWQpXG4gICogICBVaW50OEFycmF5ICAgICAgICAgeCA2LDQ2Myw5NjYgb3BzL3NlYyDCsTEuNDMlICg4NSBydW5zIHNhbXBsZWQpXG4gICogICBJbnQzMkFycmF5ICAgICAgICAgeCA1LDY0MSw4NDEgb3BzL3NlYyDCsTMuNDklICg4MSBydW5zIHNhbXBsZWQpXG4gICogICBJbnQxNkFycmF5ICAgICAgICAgeCA2LDU4Myw1MTEgb3BzL3NlYyDCsTEuOTglICg4MCBydW5zIHNhbXBsZWQpXG4gICogICBJbnQ4QXJyYXkgICAgICAgICAgeCA2LDYwNiwwNzggb3BzL3NlYyDCsTEuNzQlICg4MSBydW5zIHNhbXBsZWQpXG4gICogICBVaW50OENsYW1wZWRBcnJheSAgeCA2LDYwMiwyMjQgb3BzL3NlYyDCsTEuNzclICg4MyBydW5zIHNhbXBsZWQpXG4gICovXG4gIHZhciBzdHJpbmdUYWcgPSAoc3ltYm9sVG9TdHJpbmdUYWdFeGlzdHMgJiYgb2JqW1N5bWJvbC50b1N0cmluZ1RhZ10pO1xuICBpZiAodHlwZW9mIHN0cmluZ1RhZyA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gc3RyaW5nVGFnO1xuICB9XG5cbiAgdmFyIG9ialByb3RvdHlwZSA9IE9iamVjdC5nZXRQcm90b3R5cGVPZihvYmopO1xuICAvKiAhIFNwZWVkIG9wdGltaXNhdGlvblxuICAqIFByZTpcbiAgKiAgIHJlZ2V4IGxpdGVyYWwgICAgICB4IDEsNzcyLDM4NSBvcHMvc2VjIMKxMS44NSUgKDc3IHJ1bnMgc2FtcGxlZClcbiAgKiAgIHJlZ2V4IGNvbnN0cnVjdG9yICB4IDIsMTQzLDYzNCBvcHMvc2VjIMKxMi40NiUgKDc4IHJ1bnMgc2FtcGxlZClcbiAgKiBQb3N0OlxuICAqICAgcmVnZXggbGl0ZXJhbCAgICAgIHggMyw5MjgsMDA5IG9wcy9zZWMgwrEwLjY1JSAoNzggcnVucyBzYW1wbGVkKVxuICAqICAgcmVnZXggY29uc3RydWN0b3IgIHggMyw5MzEsMTA4IG9wcy9zZWMgwrEwLjU4JSAoODQgcnVucyBzYW1wbGVkKVxuICAqL1xuICBpZiAob2JqUHJvdG90eXBlID09PSBSZWdFeHAucHJvdG90eXBlKSB7XG4gICAgcmV0dXJuICdSZWdFeHAnO1xuICB9XG5cbiAgLyogISBTcGVlZCBvcHRpbWlzYXRpb25cbiAgKiBQcmU6XG4gICogICBkYXRlICAgICAgICAgICAgICAgeCAyLDEzMCwwNzQgb3BzL3NlYyDCsTQuNDIlICg2OCBydW5zIHNhbXBsZWQpXG4gICogUG9zdDpcbiAgKiAgIGRhdGUgICAgICAgICAgICAgICB4IDMsOTUzLDc3OSBvcHMvc2VjIMKxMS4zNSUgKDc3IHJ1bnMgc2FtcGxlZClcbiAgKi9cbiAgaWYgKG9ialByb3RvdHlwZSA9PT0gRGF0ZS5wcm90b3R5cGUpIHtcbiAgICByZXR1cm4gJ0RhdGUnO1xuICB9XG5cbiAgLyogISBTcGVjIENvbmZvcm1hbmNlXG4gICAqIChodHRwOi8vd3d3LmVjbWEtaW50ZXJuYXRpb25hbC5vcmcvZWNtYS0yNjIvNi4wL2luZGV4Lmh0bWwjc2VjLXByb21pc2UucHJvdG90eXBlLUBAdG9zdHJpbmd0YWcpXG4gICAqIEVTNiQyNS40LjUuNCAtIFByb21pc2UucHJvdG90eXBlW0BAdG9TdHJpbmdUYWddIHNob3VsZCBiZSBcIlByb21pc2VcIjpcbiAgICogVGVzdDogYE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChQcm9taXNlLnJlc29sdmUoKSlgYFxuICAgKiAgLSBDaHJvbWUgPD00NyA9PT0gXCJbb2JqZWN0IE9iamVjdF1cIlxuICAgKiAgLSBFZGdlIDw9MjAgPT09IFwiW29iamVjdCBPYmplY3RdXCJcbiAgICogIC0gRmlyZWZveCAyOS1MYXRlc3QgPT09IFwiW29iamVjdCBQcm9taXNlXVwiXG4gICAqICAtIFNhZmFyaSA3LjEtTGF0ZXN0ID09PSBcIltvYmplY3QgUHJvbWlzZV1cIlxuICAgKi9cbiAgaWYgKHByb21pc2VFeGlzdHMgJiYgb2JqUHJvdG90eXBlID09PSBQcm9taXNlLnByb3RvdHlwZSkge1xuICAgIHJldHVybiAnUHJvbWlzZSc7XG4gIH1cblxuICAvKiAhIFNwZWVkIG9wdGltaXNhdGlvblxuICAqIFByZTpcbiAgKiAgIHNldCAgICAgICAgICAgICAgICB4IDIsMjIyLDE4NiBvcHMvc2VjIMKxMS4zMSUgKDgyIHJ1bnMgc2FtcGxlZClcbiAgKiBQb3N0OlxuICAqICAgc2V0ICAgICAgICAgICAgICAgIHggNCw1NDUsODc5IG9wcy9zZWMgwrExLjEzJSAoODMgcnVucyBzYW1wbGVkKVxuICAqL1xuICBpZiAoc2V0RXhpc3RzICYmIG9ialByb3RvdHlwZSA9PT0gU2V0LnByb3RvdHlwZSkge1xuICAgIHJldHVybiAnU2V0JztcbiAgfVxuXG4gIC8qICEgU3BlZWQgb3B0aW1pc2F0aW9uXG4gICogUHJlOlxuICAqICAgbWFwICAgICAgICAgICAgICAgIHggMiwzOTYsODQyIG9wcy9zZWMgwrExLjU5JSAoODEgcnVucyBzYW1wbGVkKVxuICAqIFBvc3Q6XG4gICogICBtYXAgICAgICAgICAgICAgICAgeCA0LDE4Myw5NDUgb3BzL3NlYyDCsTYuNTklICg4MiBydW5zIHNhbXBsZWQpXG4gICovXG4gIGlmIChtYXBFeGlzdHMgJiYgb2JqUHJvdG90eXBlID09PSBNYXAucHJvdG90eXBlKSB7XG4gICAgcmV0dXJuICdNYXAnO1xuICB9XG5cbiAgLyogISBTcGVlZCBvcHRpbWlzYXRpb25cbiAgKiBQcmU6XG4gICogICB3ZWFrc2V0ICAgICAgICAgICAgeCAxLDMyMywyMjAgb3BzL3NlYyDCsTIuMTclICg3NiBydW5zIHNhbXBsZWQpXG4gICogUG9zdDpcbiAgKiAgIHdlYWtzZXQgICAgICAgICAgICB4IDQsMjM3LDUxMCBvcHMvc2VjIMKxMi4wMSUgKDc3IHJ1bnMgc2FtcGxlZClcbiAgKi9cbiAgaWYgKHdlYWtTZXRFeGlzdHMgJiYgb2JqUHJvdG90eXBlID09PSBXZWFrU2V0LnByb3RvdHlwZSkge1xuICAgIHJldHVybiAnV2Vha1NldCc7XG4gIH1cblxuICAvKiAhIFNwZWVkIG9wdGltaXNhdGlvblxuICAqIFByZTpcbiAgKiAgIHdlYWttYXAgICAgICAgICAgICB4IDEsNTAwLDI2MCBvcHMvc2VjIMKxMi4wMiUgKDc4IHJ1bnMgc2FtcGxlZClcbiAgKiBQb3N0OlxuICAqICAgd2Vha21hcCAgICAgICAgICAgIHggMyw4ODEsMzg0IG9wcy9zZWMgwrExLjQ1JSAoODIgcnVucyBzYW1wbGVkKVxuICAqL1xuICBpZiAod2Vha01hcEV4aXN0cyAmJiBvYmpQcm90b3R5cGUgPT09IFdlYWtNYXAucHJvdG90eXBlKSB7XG4gICAgcmV0dXJuICdXZWFrTWFwJztcbiAgfVxuXG4gIC8qICEgU3BlYyBDb25mb3JtYW5jZVxuICAgKiAoaHR0cDovL3d3dy5lY21hLWludGVybmF0aW9uYWwub3JnL2VjbWEtMjYyLzYuMC9pbmRleC5odG1sI3NlYy1kYXRhdmlldy5wcm90b3R5cGUtQEB0b3N0cmluZ3RhZylcbiAgICogRVM2JDI0LjIuNC4yMSAtIERhdGFWaWV3LnByb3RvdHlwZVtAQHRvU3RyaW5nVGFnXSBzaG91bGQgYmUgXCJEYXRhVmlld1wiOlxuICAgKiBUZXN0OiBgT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG5ldyBEYXRhVmlldyhuZXcgQXJyYXlCdWZmZXIoMSkpKWBgXG4gICAqICAtIEVkZ2UgPD0xMyA9PT0gXCJbb2JqZWN0IE9iamVjdF1cIlxuICAgKi9cbiAgaWYgKGRhdGFWaWV3RXhpc3RzICYmIG9ialByb3RvdHlwZSA9PT0gRGF0YVZpZXcucHJvdG90eXBlKSB7XG4gICAgcmV0dXJuICdEYXRhVmlldyc7XG4gIH1cblxuICAvKiAhIFNwZWMgQ29uZm9ybWFuY2VcbiAgICogKGh0dHA6Ly93d3cuZWNtYS1pbnRlcm5hdGlvbmFsLm9yZy9lY21hLTI2Mi82LjAvaW5kZXguaHRtbCNzZWMtJW1hcGl0ZXJhdG9ycHJvdG90eXBlJS1AQHRvc3RyaW5ndGFnKVxuICAgKiBFUzYkMjMuMS41LjIuMiAtICVNYXBJdGVyYXRvclByb3RvdHlwZSVbQEB0b1N0cmluZ1RhZ10gc2hvdWxkIGJlIFwiTWFwIEl0ZXJhdG9yXCI6XG4gICAqIFRlc3Q6IGBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwobmV3IE1hcCgpLmVudHJpZXMoKSlgYFxuICAgKiAgLSBFZGdlIDw9MTMgPT09IFwiW29iamVjdCBPYmplY3RdXCJcbiAgICovXG4gIGlmIChtYXBFeGlzdHMgJiYgb2JqUHJvdG90eXBlID09PSBtYXBJdGVyYXRvclByb3RvdHlwZSkge1xuICAgIHJldHVybiAnTWFwIEl0ZXJhdG9yJztcbiAgfVxuXG4gIC8qICEgU3BlYyBDb25mb3JtYW5jZVxuICAgKiAoaHR0cDovL3d3dy5lY21hLWludGVybmF0aW9uYWwub3JnL2VjbWEtMjYyLzYuMC9pbmRleC5odG1sI3NlYy0lc2V0aXRlcmF0b3Jwcm90b3R5cGUlLUBAdG9zdHJpbmd0YWcpXG4gICAqIEVTNiQyMy4yLjUuMi4yIC0gJVNldEl0ZXJhdG9yUHJvdG90eXBlJVtAQHRvU3RyaW5nVGFnXSBzaG91bGQgYmUgXCJTZXQgSXRlcmF0b3JcIjpcbiAgICogVGVzdDogYE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChuZXcgU2V0KCkuZW50cmllcygpKWBgXG4gICAqICAtIEVkZ2UgPD0xMyA9PT0gXCJbb2JqZWN0IE9iamVjdF1cIlxuICAgKi9cbiAgaWYgKHNldEV4aXN0cyAmJiBvYmpQcm90b3R5cGUgPT09IHNldEl0ZXJhdG9yUHJvdG90eXBlKSB7XG4gICAgcmV0dXJuICdTZXQgSXRlcmF0b3InO1xuICB9XG5cbiAgLyogISBTcGVjIENvbmZvcm1hbmNlXG4gICAqIChodHRwOi8vd3d3LmVjbWEtaW50ZXJuYXRpb25hbC5vcmcvZWNtYS0yNjIvNi4wL2luZGV4Lmh0bWwjc2VjLSVhcnJheWl0ZXJhdG9ycHJvdG90eXBlJS1AQHRvc3RyaW5ndGFnKVxuICAgKiBFUzYkMjIuMS41LjIuMiAtICVBcnJheUl0ZXJhdG9yUHJvdG90eXBlJVtAQHRvU3RyaW5nVGFnXSBzaG91bGQgYmUgXCJBcnJheSBJdGVyYXRvclwiOlxuICAgKiBUZXN0OiBgT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKFtdW1N5bWJvbC5pdGVyYXRvcl0oKSlgYFxuICAgKiAgLSBFZGdlIDw9MTMgPT09IFwiW29iamVjdCBPYmplY3RdXCJcbiAgICovXG4gIGlmIChhcnJheUl0ZXJhdG9yRXhpc3RzICYmIG9ialByb3RvdHlwZSA9PT0gYXJyYXlJdGVyYXRvclByb3RvdHlwZSkge1xuICAgIHJldHVybiAnQXJyYXkgSXRlcmF0b3InO1xuICB9XG5cbiAgLyogISBTcGVjIENvbmZvcm1hbmNlXG4gICAqIChodHRwOi8vd3d3LmVjbWEtaW50ZXJuYXRpb25hbC5vcmcvZWNtYS0yNjIvNi4wL2luZGV4Lmh0bWwjc2VjLSVzdHJpbmdpdGVyYXRvcnByb3RvdHlwZSUtQEB0b3N0cmluZ3RhZylcbiAgICogRVM2JDIxLjEuNS4yLjIgLSAlU3RyaW5nSXRlcmF0b3JQcm90b3R5cGUlW0BAdG9TdHJpbmdUYWddIHNob3VsZCBiZSBcIlN0cmluZyBJdGVyYXRvclwiOlxuICAgKiBUZXN0OiBgT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKCcnW1N5bWJvbC5pdGVyYXRvcl0oKSlgYFxuICAgKiAgLSBFZGdlIDw9MTMgPT09IFwiW29iamVjdCBPYmplY3RdXCJcbiAgICovXG4gIGlmIChzdHJpbmdJdGVyYXRvckV4aXN0cyAmJiBvYmpQcm90b3R5cGUgPT09IHN0cmluZ0l0ZXJhdG9yUHJvdG90eXBlKSB7XG4gICAgcmV0dXJuICdTdHJpbmcgSXRlcmF0b3InO1xuICB9XG5cbiAgLyogISBTcGVlZCBvcHRpbWlzYXRpb25cbiAgKiBQcmU6XG4gICogICBvYmplY3QgZnJvbSBudWxsICAgeCAyLDQyNCwzMjAgb3BzL3NlYyDCsTEuNjclICg3NiBydW5zIHNhbXBsZWQpXG4gICogUG9zdDpcbiAgKiAgIG9iamVjdCBmcm9tIG51bGwgICB4IDUsODM4LDAwMCBvcHMvc2VjIMKxMC45OSUgKDg0IHJ1bnMgc2FtcGxlZClcbiAgKi9cbiAgaWYgKG9ialByb3RvdHlwZSA9PT0gbnVsbCkge1xuICAgIHJldHVybiAnT2JqZWN0JztcbiAgfVxuXG4gIHJldHVybiBPYmplY3RcbiAgICAucHJvdG90eXBlXG4gICAgLnRvU3RyaW5nXG4gICAgLmNhbGwob2JqKVxuICAgIC5zbGljZSh0b1N0cmluZ0xlZnRTbGljZUxlbmd0aCwgdG9TdHJpbmdSaWdodFNsaWNlTGVuZ3RoKTtcbn07XG5cbm1vZHVsZS5leHBvcnRzLnR5cGVEZXRlY3QgPSBtb2R1bGUuZXhwb3J0cztcbiJdfQ==
diff --git a/src/tests/tests/background.js b/src/tests/tests/background.js
new file mode 100644
index 0000000..149db42
--- /dev/null
+++ b/src/tests/tests/background.js
@@ -0,0 +1,467 @@
+/* globals badger:false */
+
+(function () {
+
+const DNT_COMPLIANT_DOMAIN = 'eff.org',
+ DNT_DOMAINS = [
+ DNT_COMPLIANT_DOMAIN,
+ 'dnt2.example',
+ 'dnt3.example',
+ 'dnt4.example',
+ 'dnt5.example',
+ ],
+ POLICY_URL = chrome.runtime.getURL('data/dnt-policy.txt');
+
+let utils = require('utils'),
+ constants = require('constants'),
+ migrations = require('migrations').Migrations,
+ mdfp = require('multiDomainFP');
+
+let clock,
+ server,
+ xhrSpy,
+ dnt_policy_txt;
+
+function setupBadgerStorage(badger) {
+ // add foo.com, allowed as seen tracking on only one site
+ badger.storage.action_map.setItem('foo.com', {
+ dnt: false,
+ heuristicAction: constants.ALLOW,
+ nextUpdateTime: 100,
+ userAction: ""
+ });
+ badger.storage.snitch_map.setItem('foo.com', ['a.co']);
+
+ // add sub.bar.com,
+ // blocked after having been recorded tracking on three sites
+ badger.storage.action_map.setItem('bar.com', {
+ dnt: false,
+ heuristicAction: constants.BLOCK,
+ nextUpdateTime: 100,
+ userAction: ""
+ });
+ badger.storage.action_map.setItem('sub.bar.com', {
+ dnt: false,
+ heuristicAction: constants.BLOCK,
+ nextUpdateTime: 100,
+ userAction: ""
+ });
+ badger.storage.snitch_map.setItem('bar.com', ['a.co', 'b.co', 'c.co']);
+}
+
+QUnit.module("Background", {
+ before: (assert) => {
+ let done = assert.async();
+
+ // fetch locally stored DNT policy
+ utils.xhrRequest(POLICY_URL, function (err, data) {
+ dnt_policy_txt = data;
+
+ // set up fake server to simulate XMLHttpRequests
+ server = sinon.fakeServer.create({
+ respondImmediately: true
+ });
+ DNT_DOMAINS.forEach(domain => {
+ server.respondWith(
+ "GET",
+ "https://" + domain + "/.well-known/dnt-policy.txt",
+ [200, {}, dnt_policy_txt]
+ );
+ });
+
+ // set up fake timers to simulate window.setTimeout and co.
+ clock = sinon.useFakeTimers(+new Date());
+
+ done();
+ });
+ },
+
+ beforeEach: (/*assert*/) => {
+ // spy on utils.xhrRequest
+ xhrSpy = sinon.spy(utils, "xhrRequest");
+ },
+
+ afterEach: (/*assert*/) => {
+ // reset call counts, etc. after each test
+ utils.xhrRequest.restore();
+ },
+
+ after: (/*assert*/) => {
+ clock.restore();
+ server.restore();
+ }
+});
+
+QUnit.test("DNT policy checking", (assert) => {
+ const NUM_TESTS = 2,
+ done = assert.async(NUM_TESTS);
+
+ assert.expect(NUM_TESTS);
+
+ badger.checkForDNTPolicy(DNT_COMPLIANT_DOMAIN, function (successStatus) {
+ assert.ok(successStatus, "Domain returns good DNT policy");
+ done();
+ });
+
+ badger.checkForDNTPolicy('ecorp.example', function (successStatus) {
+ assert.notOk(successStatus, "Domain returns 200 but no valid policy");
+ done();
+ });
+
+ // advance the clock enough to trigger all rate-limited calls
+ clock.tick(constants.DNT_POLICY_CHECK_INTERVAL * NUM_TESTS);
+});
+
+QUnit.test("Several checks for same domain resolve to one XHR", (assert) => {
+ const NUM_CHECKS = 5;
+
+ // set recheck time to now
+ badger.storage.touchDNTRecheckTime(DNT_COMPLIANT_DOMAIN, +new Date());
+
+ for (let i = 0; i < NUM_CHECKS; i++) {
+ badger.checkForDNTPolicy(DNT_COMPLIANT_DOMAIN);
+ }
+
+ // advance the clock
+ clock.tick(constants.DNT_POLICY_CHECK_INTERVAL * NUM_CHECKS);
+
+ assert.equal(xhrSpy.callCount, 1, "XHR method gets called exactly once");
+ assert.equal(
+ xhrSpy.getCall(0).args[0],
+ "https://" + DNT_COMPLIANT_DOMAIN + "/.well-known/dnt-policy.txt",
+ "XHR method gets called with expected DNT URL"
+ );
+});
+
+QUnit.test("DNT checking is rate limited", (assert) => {
+ const NUM_TESTS = DNT_DOMAINS.length;
+
+ let done = assert.async(NUM_TESTS);
+
+ assert.expect(NUM_TESTS);
+
+ for (let i = 0; i < NUM_TESTS; i++) {
+ badger.checkForDNTPolicy(
+ DNT_DOMAINS[i],
+ function () { // eslint-disable-line no-loop-func
+ assert.equal(xhrSpy.callCount, i+1);
+ clock.tick(constants.DNT_POLICY_CHECK_INTERVAL);
+ done();
+ }
+ );
+ }
+});
+
+QUnit.test("DNT checking obeys user setting", (assert) => {
+ const NUM_TESTS = DNT_DOMAINS.length;
+
+ let done = assert.async(NUM_TESTS);
+ let old_dnt_check_func = badger.isCheckingDNTPolicyEnabled;
+
+ assert.expect(NUM_TESTS);
+ badger.isCheckingDNTPolicyEnabled = () => false;
+
+ for (let i = 0; i < NUM_TESTS; i++) {
+ badger.checkForDNTPolicy(DNT_DOMAINS[i]);
+ clock.tick(constants.DNT_POLICY_CHECK_INTERVAL);
+ assert.equal(xhrSpy.callCount, 0);
+ done();
+ }
+
+ badger.isCheckingDNTPolicyEnabled = old_dnt_check_func;
+});
+
+// test #1972
+QUnit.test("mergeUserData does not unblock formerly blocked domains", (assert) => {
+ setupBadgerStorage(badger);
+
+ const SITE_DOMAINS = ['a.co', 'b.co', 'c.co'],
+ USER_DATA = {
+ action_map: {
+ 'foo.com': {
+ dnt: false,
+ heuristicAction: constants.BLOCK,
+ nextUpdateTime: 100,
+ userAction: ""
+ }
+ },
+ snitch_map: {
+ 'foo.com': SITE_DOMAINS
+ },
+ settings_map: {
+ migrationLevel: 0
+ }
+ };
+
+ badger.mergeUserData(USER_DATA);
+
+ assert.equal(
+ badger.storage.action_map.getItem('foo.com').heuristicAction,
+ constants.BLOCK,
+ "foo.com was blocked"
+ );
+ assert.deepEqual(
+ badger.storage.snitch_map.getItem('foo.com'),
+ SITE_DOMAINS,
+ "snitch map was migrated"
+ );
+
+ badger.runMigrations();
+
+ assert.equal(
+ badger.storage.action_map.getItem('foo.com').heuristicAction,
+ constants.BLOCK,
+ "foo.com is still blocked after running migrations"
+ );
+});
+
+QUnit.test("user-blocked domains keep their tracking history", (assert) => {
+ const SITE_DOMAINS = ['a.co', 'b.co'],
+ USER_DATA = {
+ action_map: {
+ 'foo.com': {
+ dnt: false,
+ heuristicAction: constants.ALLOW,
+ nextUpdateTime: 100,
+ userAction: constants.USER_BLOCK
+ }
+ },
+ snitch_map: {
+ 'foo.com': SITE_DOMAINS
+ }
+ };
+
+ badger.mergeUserData(USER_DATA);
+
+ assert.equal(
+ badger.storage.getAction('foo.com'),
+ constants.USER_BLOCK,
+ "foo.com was blocked"
+ );
+ assert.deepEqual(
+ badger.storage.snitch_map.getItem('foo.com'),
+ SITE_DOMAINS,
+ "snitch map was migrated"
+ );
+});
+
+QUnit.test("merging snitch maps results in a blocked domain", (assert) => {
+ setupBadgerStorage(badger);
+
+ // https://github.com/EFForg/privacybadger/pull/2082#issuecomment-401942070
+ const USER_DATA = {
+ action_map: {
+ 'foo.com': {
+ dnt: false,
+ heuristicAction: constants.ALLOW,
+ nextUpdateTime: 100,
+ userAction: ""
+ }
+ },
+ snitch_map: {'foo.com': ['b.co', 'c.co']},
+ };
+
+ badger.mergeUserData(USER_DATA);
+
+ assert.equal(
+ badger.storage.action_map.getItem('foo.com').heuristicAction,
+ constants.BLOCK,
+ "foo.com was blocked"
+ );
+ assert.deepEqual(
+ badger.storage.snitch_map.getItem('foo.com'),
+ ['a.co', 'b.co', 'c.co'],
+ "snitch map was combined"
+ );
+});
+
+QUnit.test("subdomain that is not blocked does not override subdomain that is", (assert) => {
+ setupBadgerStorage(badger);
+
+ const USER_DATA = {
+ action_map: {
+ 'sub.bar.com': {
+ dnt: false,
+ heuristicAction: constants.ALLOW,
+ nextUpdateTime: 100,
+ userAction: ""
+ }
+ },
+ snitch_map: {'bar.com': ['a.co']}
+ };
+
+ badger.mergeUserData(USER_DATA);
+
+ assert.equal(
+ badger.storage.action_map.getItem('sub.bar.com').heuristicAction,
+ constants.BLOCK,
+ "sub.bar.com is still blocked"
+ );
+ assert.deepEqual(
+ badger.storage.snitch_map.getItem('bar.com'),
+ ['a.co', 'b.co', 'c.co'],
+ "snitch map was preserved"
+ );
+});
+
+QUnit.test("subdomains on the yellowlist are preserved", (assert) => {
+ const DOMAIN = "example.com",
+ SUBDOMAIN = "cdn.example.com",
+ USER_DATA = {
+ action_map: {
+ [DOMAIN]: {
+ dnt: false,
+ heuristicAction: constants.BLOCK,
+ nextUpdateTime: 100,
+ userAction: ''
+ },
+ [SUBDOMAIN]: {
+ dnt: false,
+ heuristicAction: constants.ALLOW,
+ nextUpdateTime: 0,
+ userAction: ''
+ }
+ },
+ snitch_map: {
+ [DOMAIN]: ['a.co', 'b.co', 'c.co'],
+ }
+ };
+
+ const actionMap = badger.storage.getStore('action_map'),
+ snitchMap = badger.storage.getStore('snitch_map');
+
+ // merge in a blocked parent domain and a subdomain
+ badger.mergeUserData(USER_DATA);
+
+ assert.notOk(actionMap.getItem(SUBDOMAIN),
+ SUBDOMAIN + " should have been discarded during merge"
+ );
+
+ // clean up
+ actionMap.deleteItem(DOMAIN);
+ actionMap.deleteItem(SUBDOMAIN);
+ snitchMap.deleteItem(DOMAIN);
+
+ // now add subdomain to yellowlist
+ badger.storage.getStore('cookieblock_list')
+ .setItem(SUBDOMAIN, true);
+
+ // and do the merge again
+ badger.mergeUserData(USER_DATA);
+
+ assert.ok(actionMap.getItem(SUBDOMAIN),
+ SUBDOMAIN + " should be present in action_map"
+ );
+ assert.equal(
+ actionMap.getItem(SUBDOMAIN).heuristicAction,
+ constants.COOKIEBLOCK,
+ SUBDOMAIN + " should be cookieblocked"
+ );
+});
+
+QUnit.test("forgetFirstPartySnitches migration properly handles snitch entries with no MDFP entries", (assert) => {
+ const actionMap = badger.storage.getStore('action_map'),
+ snitchMap = badger.storage.getStore('snitch_map');
+
+ let snitchNoMDFP = {
+ 'amazon.com': ['amazonads.com', 'amazing.com', 'amazonrainforest.com']
+ };
+
+ let actionNoMDFP = {
+ 'amazon.com': {
+ heuristicAction: "cookieblock",
+ userAction: "",
+ dnt: false,
+ nextUpdateTime: 0,
+ }
+ };
+
+ snitchMap.updateObject(snitchNoMDFP);
+ actionMap.updateObject(actionNoMDFP);
+ migrations.forgetFirstPartySnitches(badger);
+
+ assert.deepEqual(
+ actionMap.getItem('amazon.com'),
+ actionNoMDFP['amazon.com'],
+ "action map preserved for domain with no MDFP snitch entries"
+ );
+
+ assert.deepEqual(
+ snitchMap.getItem('amazon.com'),
+ snitchNoMDFP['amazon.com'],
+ "snitch map entry with no MDFP domains remains the same after migration runs"
+ );
+});
+
+QUnit.test("forgetFirstPartySnitches migration properly handles snitch entries with some MDFP entries", (assert) => {
+ const actionMap = badger.storage.getStore('action_map'),
+ snitchMap = badger.storage.getStore('snitch_map');
+
+ let snitchSomeMDFP = {
+ 'amazon.com': ['amazon.ca', 'amazon.co.jp', 'amazing.com']
+ };
+
+ let actionSomeMDFP = {
+ 'amazon.com': {
+ heuristicAction: "cookieblock",
+ userAction: "",
+ dnt: false,
+ nextUpdateTime: 0,
+ }
+ };
+
+ snitchMap.updateObject(snitchSomeMDFP);
+ actionMap.updateObject(actionSomeMDFP);
+ migrations.forgetFirstPartySnitches(badger);
+
+ assert.equal(
+ badger.storage.getAction('amazon.com'),
+ constants.ALLOW,
+ "Action downgraded for partial MDFP domain"
+ );
+
+ assert.deepEqual(snitchMap.getItem('amazon.com'),
+ ["amazing.com"],
+ 'forget first party migration properly removes MDFP domains and leaves regular domains');
+});
+
+QUnit.test("forgetFirstPartySnitches migration properly handles snitch entries with all MDFP entries", (assert) => {
+ const actionMap = badger.storage.getStore('action_map'),
+ snitchMap = badger.storage.getStore('snitch_map');
+
+ let snitchAllMDFP = {
+ 'amazon.com': ['amazon.ca', 'amazon.co.jp', 'amazon.es']
+ };
+
+ let actionAllMDFP = {
+ 'amazon.com': {
+ heuristicAction: "cookieblock",
+ userAction: "",
+ dnt: false,
+ nextUpdateTime: 0,
+ }
+ };
+
+ // confirm all entries are MDFP
+ snitchAllMDFP["amazon.com"].forEach((domain) => {
+ assert.ok(
+ mdfp.isMultiDomainFirstParty('amazon.com', domain),
+ domain + " is indeed MDFP to amazon.com"
+ );
+ });
+
+ snitchMap.updateObject(snitchAllMDFP);
+ actionMap.updateObject(actionAllMDFP);
+ migrations.forgetFirstPartySnitches(badger);
+
+ assert.notOk(snitchMap.getItem('amazon.com'),
+ 'forget first party migration properly removes a snitch map entry with all MDFP domains attributed to it');
+
+ assert.equal(
+ badger.storage.getAction('amazon.com'),
+ constants.NO_TRACKING,
+ "Action downgraded for all MDFP domain"
+ );
+});
+
+}());
diff --git a/src/tests/tests/baseDomain.js b/src/tests/tests/baseDomain.js
new file mode 100644
index 0000000..b39d757
--- /dev/null
+++ b/src/tests/tests/baseDomain.js
@@ -0,0 +1,255 @@
+/* * This file is part of Adblock Plus <http://adblockplus.org/>, * Copyright (C) 2006-2013 Eyeo GmbH *
+ * Adblock Plus 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.
+ *
+ * Adblock Plus 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 Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* global
+extractHostFromURL:false,
+getBaseDomain: false,
+ipAddressToNumber: false,
+isPrivateDomain:false,
+isThirdParty:false,
+URI:false,
+*/
+
+(function () {
+
+QUnit.module("URL/host tools");
+
+QUnit.test("Host name extraction", function (assert) {
+ var tests = [
+ [null, ""],
+ ["/foo/bar", ""],
+ ["http://example.com/", "example.com"],
+ ["http://example.com:8000/", "example.com"],
+ ["http://foo:bar@example.com:8000/foo:bar/bas", "example.com"],
+ ["ftp://example.com/", "example.com"],
+ ["http://1.2.3.4:8000/", "1.2.3.4"],
+ ["http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]/", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"],
+ ["http://[2001::7334]:8000/test@foo.example.com/bar", "2001::7334"],
+ ];
+
+ for (var i = 0; i < tests.length; i++) {
+ assert.equal(extractHostFromURL(tests[i][0]), tests[i][1], tests[i][0]);
+ }
+});
+
+QUnit.test("Invalid URI recognition", function (assert) {
+ var tests = [
+ null,
+ "",
+ "http:",
+ "http:foo.bar/",
+ "http://foo.bar"
+ ];
+ for (var i = 0; i < tests.length; i++) {
+ assert.raises(function() { // eslint-disable-line no-loop-func
+ return new URI(tests[i]);
+ }, Error, "Invalid URI recognition.");
+ }
+});
+
+QUnit.test("URI parsing", function (assert) {
+ var tests = [
+ ["http://example.com/", {
+ scheme: "http",
+ host: "example.com",
+ asciiHost: "example.com",
+ hostPort: "example.com",
+ port: -1,
+ path: "/",
+ prePath: "http://example.com"
+ }],
+ ["http://example.com:8000/", {
+ scheme: "http",
+ host: "example.com",
+ asciiHost: "example.com",
+ hostPort: "example.com:8000",
+ port: 8000,
+ path: "/",
+ prePath: "http://example.com:8000"
+ }],
+ ["http://foo:bar@\u0440\u043E\u0441\u0441\u0438\u044F.\u0440\u0444:8000/foo:bar/bas", {
+ scheme: "http",
+ host: "\u0440\u043E\u0441\u0441\u0438\u044F.\u0440\u0444",
+ asciiHost: "xn--h1alffa9f.xn--p1ai",
+ hostPort: "\u0440\u043E\u0441\u0441\u0438\u044F.\u0440\u0444:8000",
+ port: 8000,
+ path: "/foo:bar/bas",
+ prePath: "http://foo:bar@\u0440\u043E\u0441\u0441\u0438\u044F.\u0440\u0444:8000"
+ }],
+ ["ftp://m\xFCller.de/", {
+ scheme: "ftp",
+ host: "m\xFCller.de",
+ asciiHost: "xn--mller-kva.de",
+ hostPort: "m\xFCller.de",
+ port: -1,
+ path: "/",
+ prePath: "ftp://m\xFCller.de"
+ }],
+ ["http://1.2.3.4:8000/", {
+ scheme: "http",
+ host: "1.2.3.4",
+ asciiHost: "1.2.3.4",
+ hostPort: "1.2.3.4:8000",
+ port: 8000,
+ path: "/",
+ prePath: "http://1.2.3.4:8000"
+ }],
+ ["http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]/", {
+ scheme: "http",
+ host: "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
+ asciiHost: "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
+ hostPort: "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]",
+ port: -1,
+ path: "/",
+ prePath: "http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]"
+ }],
+ ["http://[2001::7334]:8000/test@foo.example.com/bar", {
+ scheme: "http",
+ host: "2001::7334",
+ asciiHost: "2001::7334",
+ hostPort: "[2001::7334]:8000",
+ port: 8000,
+ path: "/test@foo.example.com/bar",
+ prePath: "http://[2001::7334]:8000"
+ }],
+ ["filesystem:http://example.com/temporary/myfile.png", {
+ scheme: "filesystem:http",
+ host: "example.com",
+ asciiHost: "example.com",
+ hostPort: "example.com",
+ port: -1,
+ path: "/temporary/myfile.png",
+ prePath: "filesystem:http://example.com"
+ }],
+ ["blob:https://www.daringgourmet.com/69587cd0-01e1-417b-819d-8e2ecbefc1f9", {
+ scheme: "blob:https",
+ host: "www.daringgourmet.com",
+ asciiHost: "www.daringgourmet.com",
+ hostPort: "www.daringgourmet.com",
+ port: -1,
+ path: "/69587cd0-01e1-417b-819d-8e2ecbefc1f9",
+ prePath: "blob:https://www.daringgourmet.com"
+ }],
+ ];
+
+ for (var i = 0; i < tests.length; i++) {
+ var url = tests[i][0];
+ var uri = new URI(url);
+ assert.equal(uri.spec, url, "URI(" + url + ").spec");
+ for (var k in tests[i][1]) {
+ assert.equal(uri[k], tests[i][1][k], "URI(" + url + ")." + k);
+ }
+ }
+});
+
+QUnit.test("Determining base domain", function (assert) {
+ var tests = [
+ ["com", "com"],
+ ["example.com", "example.com"],
+ ["www.example.com", "example.com"],
+ ["www.example.com.", "example.com"],
+ ["www.example.co.uk", "example.co.uk"],
+ ["www.example.co.uk.", "example.co.uk"],
+ ["www.example.bl.uk", "bl.uk"],
+ ["foo.bar.example.co.uk", "example.co.uk"],
+ ["1.2.3.4.com", "4.com"],
+ ["1.2.3.4.bg", "3.4.bg"],
+ ["1.2.3.4", "1.2.3.4"],
+ ["1.2.0x3.0x4", "1.2.0x3.0x4"],
+ ["1.2.3", "2.3"],
+ ["1.2.0x3g.0x4", "0x3g.0x4"],
+ ["2001:0db8:85a3:0000:0000:8a2e:0370:7334", "2001:0db8:85a3:0000:0000:8a2e:0370:7334"],
+ ["2001::7334", "2001::7334"],
+ ["::ffff:1.2.3.4", "::ffff:1.2.3.4"],
+ ["foo.bar.2001::7334", "bar.2001::7334"],
+ ["test.xn--e1aybc.xn--p1ai", "тест.рф"],
+ ];
+
+ for (var i = 0; i < tests.length; i++) {
+ assert.equal(getBaseDomain(tests[i][0]), tests[i][1], tests[i][0]);
+ }
+});
+
+QUnit.test("Converting IP address to number checks", function (assert) {
+ var testResults = {
+ "127.0.0.1": 2130706433,
+ "8.8.8.8": 134744072,
+ "192.168.0.1": 3232235521,
+ "256.0.0.1": 0,
+ "privacybadger.org": 0,
+ };
+
+ for (var ip in testResults) {
+ // Ignore object properties.
+ if (!testResults.hasOwnProperty(ip)) {
+ continue;
+ }
+
+ assert.equal(ipAddressToNumber(ip), testResults[ip], ip);
+ }
+});
+
+QUnit.test("Private domain checks", function (assert) {
+ var testResults = {
+ localhost: true,
+ "126.0.0.13": false,
+ "127.0.0.1": true,
+ "128.0.2.27": false,
+ "9.4.201.150": false,
+ "10.3.0.99": true,
+ "11.240.84.107": false,
+ "171.20.103.65": false,
+ "172.15.2.0": false,
+ "172.16.25.30": true,
+ "172.31.16.2": true,
+ "172.32.3.4": false,
+ "173.28.86.211": false,
+ "191.168.33.41": false,
+ "192.167.101.111": false,
+ "192.168.1.5": true,
+ "192.169.204.154": false,
+ "193.168.28.139": false,
+ "privacybadger.org": false,
+ };
+
+ for (var domain in testResults) {
+ // Ignore object properties.
+ if (!testResults.hasOwnProperty(domain)) {
+ continue;
+ }
+
+ assert.equal(isPrivateDomain(domain), testResults[domain], domain);
+ }
+});
+
+QUnit.test("Third party checks", function (assert) {
+ var tests = [
+ ["foo", "foo", false],
+ ["foo", "bar", true],
+ ["foo.com", "bar.com", true],
+ ["foo.com", "foo.com", false],
+ ["foo.com", "www.foo.com", false],
+ ["foo.example.com", "bar.example.com", false],
+ ["foo.uk", "bar.uk", true],
+ ["foo.co.uk", "bar.co.uk", true],
+ ["foo.example.co.uk", "bar.example.co.uk", false],
+ ["1.2.3.4", "2.2.3.4", true],
+ ];
+
+ for (var i = 0; i < tests.length; i++) {
+ assert.equal(isThirdParty(tests[i][0], tests[i][1]), tests[i][2], tests[i][0] + " and " + tests[i][1]);
+ }
+});
+
+}());
diff --git a/src/tests/tests/firstparties.js b/src/tests/tests/firstparties.js
new file mode 100644
index 0000000..3560e04
--- /dev/null
+++ b/src/tests/tests/firstparties.js
@@ -0,0 +1,167 @@
+(function () {
+
+let destination = 'https://the.beach/';
+let fb_wrap = 'https://facebook.com/l.php?u=' + destination;
+let fb_xss = 'https://facebook.com/l.php?u=javascript://bad.site/%250Aalert(1)';
+let g_wrap = 'https://www.google.com/url?q=' + destination;
+let g_ping = '/url?url=' + destination;
+
+function makeLink(href) {
+ let element = document.createElement('a');
+ element.href = href;
+ element.rel = '';
+ return element;
+}
+
+function stub(elts, selector) {
+ document.querySelectorAllBefore = document.querySelectorAll;
+ window.setIntervalBefore = window.setInterval;
+ chrome.runtime.sendMessageBefore = chrome.runtime.sendMessage;
+
+ // Stub querySelectorAll so that any selector that includes `selector` will
+ // match all the elements in `elts`.
+ document.querySelectorAll = function (query) {
+ if (query.includes(selector)) {
+ return elts;
+ } else {
+ return document.querySelectorAllBefore(query);
+ }
+ };
+
+ // Stub runtime.sendMessage so that it returns `true` in response to the
+ // `checkEnabled` query.
+ chrome.runtime.sendMessage = function (message, callback) {
+ if (message.type == "checkEnabled") {
+ callback(true);
+ } else {
+ chrome.runtime.sendMessageBefore(message, callback);
+ }
+ };
+ window.setInterval = function () {};
+
+}
+
+function unstub() {
+ document.querySelectorAll = document.querySelectorAllBefore;
+ window.setInterval = window.setIntervalBefore;
+ chrome.runtime.sendMessage = chrome.runtime.sendMessageBefore;
+}
+
+QUnit.module('First parties');
+
+QUnit.test('facebook script unwraps valid links', (assert) => {
+ const NUM_CHECKS = 4,
+ done = assert.async();
+ assert.expect(NUM_CHECKS);
+
+ let fixture = document.getElementById('qunit-fixture');
+ let good_link = makeLink(fb_wrap);
+ let bad_link = makeLink(fb_xss);
+
+ // create first-party utility script
+ let util_script = document.createElement('script');
+ util_script.src = '../js/firstparties/lib/utils.js';
+
+ // create the content script
+ let fb_script = document.createElement('script');
+ fb_script.src = '../js/firstparties/facebook.js';
+ fb_script.onload = function() {
+ assert.equal(good_link.href, destination, 'unwrapped good link');
+ assert.ok(good_link.rel.includes('noreferrer'),
+ 'added noreferrer to good link');
+
+ assert.equal(bad_link.href, fb_xss, 'did not unwrap the XSS link');
+ assert.notOk(bad_link.rel.includes('noreferrer'),
+ 'did not change rel of XSS link');
+
+ unstub();
+ done();
+ };
+
+ // after the utility script has finished loading, add the content script
+ util_script.onload = function() {
+ fixture.append(fb_script);
+ };
+
+ stub([good_link, bad_link], '/l.php?');
+ fixture.appendChild(good_link);
+ fixture.appendChild(bad_link);
+ fixture.appendChild(util_script);
+});
+
+
+QUnit.test('google shim link unwrapping', (assert) => {
+ const NUM_CHECKS = 2,
+ done = assert.async();
+ assert.expect(NUM_CHECKS);
+
+ let fixture = document.getElementById('qunit-fixture');
+ let shim_link = makeLink(g_wrap);
+
+ // create first-party utility script
+ let util_script = document.createElement('script');
+ util_script.src = '../js/firstparties/lib/utils.js';
+
+ // create the content script
+ let g_script = document.createElement('script');
+ g_script.src = '../js/firstparties/google-static.js';
+ g_script.onload = function() {
+ assert.equal(shim_link.href, destination, 'unwrapped shim link');
+ assert.ok(shim_link.rel.includes('noreferrer'),
+ 'added noreferrer to shim link');
+
+ unstub();
+ done();
+ };
+
+ // after the utility script has finished loading, add the content script
+ util_script.onload = function() {
+ fixture.append(g_script);
+ };
+
+ stub([shim_link], '/url?');
+ fixture.appendChild(shim_link);
+ fixture.appendChild(util_script);
+});
+
+
+QUnit.test('google search de-instrumentation', (assert) => {
+ const NUM_CHECKS = 3,
+ done = assert.async();
+ assert.expect(NUM_CHECKS);
+
+ let fixture = document.getElementById('qunit-fixture');
+ let ff_link = makeLink(destination);
+ ff_link.onmousedown = 'return rwt(this, foobar);';
+ let chrome_link = makeLink(destination);
+ chrome_link.ping = g_ping;
+
+ // create first-party utility script
+ let util_script = document.createElement('script');
+ util_script.src = '../js/firstparties/lib/utils.js';
+
+ // create the content script
+ let g_script = document.createElement('script');
+ g_script.src = '../js/firstparties/google-search.js';
+ g_script.onload = function() {
+ assert.notOk(ff_link.onmousedown, 'removed mouseDown event from ff link');
+ assert.ok(ff_link.rel.includes('noreferrer'), 'added noreferrer to link');
+
+ assert.notOk(chrome_link.ping, 'removed ping attr from chrome link');
+
+ unstub();
+ done();
+ };
+
+ // after the utility script has finished loading, add the content script
+ util_script.onload = function() {
+ fixture.append(g_script);
+ };
+
+ stub([ff_link, chrome_link], 'onmousedown^=');
+ fixture.appendChild(ff_link);
+ fixture.appendChild(chrome_link);
+ fixture.appendChild(util_script);
+});
+
+}());
diff --git a/src/tests/tests/heuristic.js b/src/tests/tests/heuristic.js
new file mode 100644
index 0000000..0eed2bb
--- /dev/null
+++ b/src/tests/tests/heuristic.js
@@ -0,0 +1,165 @@
+(function () {
+
+let hb = require('heuristicblocking');
+
+let chromeDetails = {
+ frameId: 35,
+ method: "GET",
+ requestHeaders: [
+ {
+ name: "User-Agent",
+ value: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"
+ }, {
+ name: "Accept",
+ value: "*/*"
+ }, {
+ name: "Referer",
+ value: "http://eff-tracker-test.s3-website-us-west-2.amazonaws.com/third-party.html"
+ }, {
+ name: "Accept-Encoding",
+ value: "gzip, deflate, sdch"
+ }, {
+ name: "Accept-Language",
+ value: "en-US,en;q=0.8"
+ }, {
+ name: "Cookie",
+ value: "thirdpartytest=1234567890"
+ }
+ ],
+ requestId: "502",
+ tabId: 15,
+ timeStamp: 1490117784939.147,
+ type: "script",
+ url: "http://eff-tracker-test.s3-website-us-west-2.amazonaws.com/third-party.js"
+};
+const CHROME_COOKIE_INDEX = chromeDetails.requestHeaders.findIndex(
+ i => i.name == "Cookie"
+);
+
+let firefoxDetails = {
+ requestId: "13",
+ url: "http://eff-tracker-test.s3-website-us-west-2.amazonaws.com/third-party.js",
+ originUrl: "http://eff-tracker-test.s3-website-us-west-2.amazonaws.com/third-party.html",
+ method: "GET",
+ type: "script",
+ timeStamp: 1490118778473,
+ frameId: 4294967303,
+ tabId: 2,
+ requestHeaders: [
+ {
+ name: "host",
+ value: "eff-tracker-test.s3-website-us-west-2.amazonaws.com"
+ }, {
+ name: "user-agent",
+ value: "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0"
+ }, {
+ name: "accept",
+ value: "*/*"
+ }, {
+ name: "accept-language",
+ value: "en-US,en;q=0.5"
+ }, {
+ name: "accept-encoding",
+ value: "gzip, deflate"
+ }, {
+ name: "referer",
+ value: "http://eff-tracker-test.s3-website-us-west-2.amazonaws.com/third-party.html"
+ }, {
+ name: "cookie",
+ value: "thirdpartytest=1234567890"
+ }, {
+ name: "connection",
+ value: "keep-alive"
+ }
+ ]
+};
+
+QUnit.module("Heuristic", {
+ before: (/*assert*/) => {
+ },
+
+ beforeEach: (/*assert*/) => {
+ },
+
+ afterEach: (/*assert*/) => {
+ },
+
+ after: (/*assert*/) => {
+ }
+});
+
+QUnit.test("HTTP cookie tracking detection", (assert) => {
+ let details = JSON.parse(JSON.stringify(chromeDetails));
+
+ // remove cookie header
+ let cookieHeader = details.requestHeaders.splice(CHROME_COOKIE_INDEX, 1);
+ assert.notOk(hb.hasCookieTracking(details), "No cookie header");
+
+ // restore it
+ details.requestHeaders.push(cookieHeader[0]);
+ assert.ok(hb.hasCookieTracking(details), "High-entropy cookie header");
+
+ // set it to a low-entropy value
+ details.requestHeaders[CHROME_COOKIE_INDEX] = {
+ name: "Cookie",
+ value: "key=ab"
+ };
+ assert.notOk(hb.hasCookieTracking(details), "Low-entropy cookie header");
+
+ // check when individual entropy is low but overall entropy is over threshold
+ // add another low entropy cookie
+ details.requestHeaders.push({
+ name: "Cookie",
+ value: "key=ab"
+ });
+ assert.ok(hb.hasCookieTracking(details),
+ "Two low-entropy cookies combine to cross tracking threshold");
+});
+
+QUnit.test("HTTP header names are case-insensitive", (assert) => {
+ assert.ok(
+ hb.hasCookieTracking(chromeDetails),
+ "Cookie tracking detected with capitalized (Chrome) headers"
+ );
+ assert.ok(
+ hb.hasCookieTracking(firefoxDetails),
+ "Cookie tracking detected with lowercase (Firefox) headers"
+ );
+});
+
+QUnit.test("Cookie attributes shouldn't add to entropy", (assert) => {
+ let ATTR_COOKIES = [
+ 'test-cookie=true; Expires=Thu, 01-Jan-1970 00:00:01 GMT; Path=/; Domain=.parrable.com',
+ '__usd_latimes.com=; expires=Wed, 03-May-2017 01:20:20 GMT; domain=.go.sonobi.com; path=/',
+ 'ses55=; Domain=.rubiconproject.com; Path=/; Expires=Wed, 03-May-2017 11:59:59 GMT; Max-Age=38407',
+ 'vf=5;Version=1;Comment=;Domain=.contextweb.com;Path=/;Max-Age=9583',
+ 'PUBMDCID=2; domain=pubmatic.com; expires=Tue, 01-Aug-2017 01:20:21 GMT; path=/',
+ 'tc=; path=/; Max-Age=31536000; expires=Thu, 03 May 2018 01:20:21 GMT',
+ 'uid=; path=/; expires=Wed, 03 May 2017 01:20:31 GMT; domain=medium.com; secure; httponly',
+ ];
+
+ let details = JSON.parse(JSON.stringify(chromeDetails));
+ for (let i = 0; i < ATTR_COOKIES.length; i++) {
+ details.requestHeaders[CHROME_COOKIE_INDEX].value = ATTR_COOKIES[i];
+ assert.notOk(hb.hasCookieTracking(details),
+ "cookie attributes test #" + i);
+ }
+});
+
+QUnit.test("CloudFlare cookies should get ignored", (assert) => {
+ let CLOUDFLARE_COOKIES = [
+ '__cfduid=d3c728f97e01b1ab6969828f24b42ab111493693758',
+ '__cfduid=d9758e8613dd4acbba3248dde15e74f8d1493774432; expires=Thu, 03-May-18 01:20:32 GMT; path=/; domain=.medium.com; HttpOnly',
+ '__cfduid=de8a1734f91060dba20e2833705018b911493771353; expires=Thu, 03-May-18 02:25:53 GMT; path=/; domain=.fightforthefuture.org; HttpOnly',
+ '__cfduid=d712bcfe8e20469cc4b9129a4ab89b7501576598707; expires=Thu, 16-Jan-20 16:05:07 GMT; path=/; domain=.githack.com; HttpOnly; SameSite=Lax',
+ ];
+
+ let details = JSON.parse(JSON.stringify(chromeDetails));
+ for (let i = 0; i < CLOUDFLARE_COOKIES.length; i++) {
+ details.requestHeaders[CHROME_COOKIE_INDEX].value = CLOUDFLARE_COOKIES[i];
+ assert.notOk(hb.hasCookieTracking(details),
+ "CloudFlare cookie test #" + i);
+ }
+});
+
+}());
diff --git a/src/tests/tests/htmlutils.js b/src/tests/tests/htmlutils.js
new file mode 100644
index 0000000..5ff0d89
--- /dev/null
+++ b/src/tests/tests/htmlutils.js
@@ -0,0 +1,241 @@
+(function () {
+
+QUnit.module("HTML Utils");
+
+let constants = require('constants'),
+ htmlUtils = require("htmlutils").htmlUtils;
+
+QUnit.test("getActionDescription", (assert) => {
+ // Test parameters
+ const getMessage = chrome.i18n.getMessage,
+ origin = "pbtest.org";
+ const tests = [
+ {
+ action: "block",
+ origin,
+ expectedResult: getMessage('badger_status_block', origin)
+ },
+ {
+ action: "cookieblock",
+ origin,
+ expectedResult: getMessage('badger_status_cookieblock', origin)
+ },
+ {
+ action: "allow",
+ origin,
+ expectedResult: getMessage('badger_status_allow', origin)
+ },
+ {
+ action: "dnt",
+ origin,
+ expectedResult: getMessage('dnt_tooltip')
+ },
+ ];
+
+ // Run each test.
+ for (let i = 0; i < tests.length; i++) {
+ const test = tests[i],
+ message = `Inputs: '${test.action}' and '${test.origin}'`;
+
+ assert.equal(
+ htmlUtils.getActionDescription(test.action, test.origin),
+ test.expectedResult,
+ message
+ );
+ }
+});
+
+QUnit.test("getToggleHtml", function (assert) {
+ // Test parameters
+ const origin = "pbtest.org";
+ const tests = [
+ {
+ action: constants.BLOCK,
+ expectedResult: constants.BLOCK,
+ },
+ {
+ action: constants.COOKIEBLOCK,
+ expectedResult: constants.COOKIEBLOCK,
+ },
+ {
+ action: constants.ALLOW,
+ expectedResult: constants.ALLOW,
+ },
+ {
+ action: constants.DNT,
+ expectedResult: constants.ALLOW,
+ },
+ ];
+
+ // Run each test.
+ for (let test of tests) {
+ let message = `Inputs: '${origin}' and '${test.action}'`;
+ let html = htmlUtils.getToggleHtml(origin, test.action);
+ let input_val = $('input[name="' + origin + '"]:checked', html).val();
+ assert.equal(input_val, test.expectedResult, message);
+ }
+});
+
+QUnit.test("getOriginHtml", function (assert) {
+ // Test parameters
+ var tests = [
+ {
+ existingHtml: '<div id="existinghtml"></div>',
+ origin: "pbtest.org",
+ action: constants.ALLOW,
+ },
+ {
+ existingHtml: '<div id="existinghtml"></div>',
+ origin: "pbtest.org",
+ action: constants.DNT,
+ },
+ ];
+
+ // Run each test.
+ for (var i = 0; i < tests.length; i++) {
+ var existingHtml = tests[i].existingHtml;
+ var origin = tests[i].origin;
+ var action = tests[i].action;
+
+ var htmlResult = existingHtml + htmlUtils.getOriginHtml(origin, action);
+
+ // Make sure existing HTML is present.
+ var existingHtmlExists = htmlResult.indexOf(existingHtml) > -1;
+ assert.ok(existingHtmlExists, "Existing HTML should be present");
+
+ // Make sure origin is set.
+ var originDataExists = htmlResult.indexOf('data-origin="' + origin + '"') > -1;
+ assert.ok(originDataExists, "Origin should be set");
+
+ // Check for presence of DNT content.
+ var dntExists = htmlResult.indexOf('id="dnt-compliant"') > -1;
+ assert.equal(dntExists, action == constants.DNT,
+ "DNT div should " + (dntExists ? "" : "not ") + "be present");
+ }
+});
+
+QUnit.test("makeSortable", (assert) => {
+ const tests = [
+ ["bbc.co.uk", "bbc."],
+ ["s3.amazonaws.com", "s3."],
+ ["01234.global.ssl.fastly.net", "01234."],
+ ["api.nextgen.guardianapps.co.uk", "guardianapps.nextgen.api"],
+ ["localhost", "localhost."],
+ ["127.0.0.1", "127.0.0.1."],
+ ];
+ tests.forEach((test) => {
+ assert.equal(
+ htmlUtils.makeSortable(test[0]),
+ test[1],
+ test[0]
+ );
+ });
+});
+
+QUnit.test("sortDomains", (assert) => {
+ const DOMAINS = [
+ "ajax.cloudflare.com",
+ "betrad.com",
+ "c.betrad.com",
+ "cloudflare.com",
+ "condenastdigital.com",
+ "weather.com"
+ ];
+ const tests = [
+ {
+ msg: "disquscdn.com was getting sorted with the Cs",
+ domains: [
+ "a.disquscdn.com",
+ "caradvice.disqus.com",
+ "carscoop.disqus.com",
+ "c.disquscdn.com",
+ "celebstoner.disqus.com",
+ "changemon.disqus.com",
+ "disqusads.com",
+ "disquscdn.com",
+ "disqus.com",
+ "uploads.disquscdn.com",
+ "wired.disqus.com",
+ ],
+ expected: [
+ "disqus.com",
+ "caradvice.disqus.com",
+ "carscoop.disqus.com",
+ "celebstoner.disqus.com",
+ "changemon.disqus.com",
+ "wired.disqus.com",
+ "disqusads.com",
+ "disquscdn.com",
+ "a.disquscdn.com",
+ "c.disquscdn.com",
+ "uploads.disquscdn.com",
+ ]
+ },
+ {
+ msg: "bbc.co.uk was getting sorted with the Cs",
+ domains: DOMAINS.concat([
+ "baidu.com",
+ "bbc.co.uk",
+ "static.bbc.co.uk",
+ ]),
+ expected: [
+ "baidu.com",
+ "bbc.co.uk",
+ "static.bbc.co.uk",
+ "betrad.com",
+ "c.betrad.com",
+ "cloudflare.com",
+ "ajax.cloudflare.com",
+ "condenastdigital.com",
+ "weather.com",
+ ]
+ },
+ {
+ msg: "googleapis.com is a PSL TLD",
+ domains: DOMAINS.concat([
+ "ajax.googleapis.com",
+ "maps.googleapis.com",
+ "google.com",
+ ]),
+ expected: [
+ "ajax.googleapis.com",
+ "betrad.com",
+ "c.betrad.com",
+ "cloudflare.com",
+ "ajax.cloudflare.com",
+ "condenastdigital.com",
+ "google.com",
+ "maps.googleapis.com",
+ "weather.com",
+ ]
+ },
+ {
+ msg: "non-TLD addresses",
+ domains: DOMAINS.concat([
+ "localhost",
+ "127.0.0.1",
+ ]),
+ expected: [
+ "127.0.0.1",
+ "betrad.com",
+ "c.betrad.com",
+ "cloudflare.com",
+ "ajax.cloudflare.com",
+ "condenastdigital.com",
+ "localhost",
+ "weather.com",
+ ]
+ },
+
+ ];
+
+ tests.forEach((test) => {
+ assert.deepEqual(
+ htmlUtils.sortDomains(test.domains),
+ test.expected,
+ test.msg
+ );
+ });
+});
+
+}());
diff --git a/src/tests/tests/multiDomainFirstParties.js b/src/tests/tests/multiDomainFirstParties.js
new file mode 100644
index 0000000..4961b03
--- /dev/null
+++ b/src/tests/tests/multiDomainFirstParties.js
@@ -0,0 +1,73 @@
+(function () {
+
+QUnit.module("Multi-domain first parties");
+
+let mdfp = require('multiDomainFP');
+
+QUnit.test('isMultiDomainFirstParty test', function (assert) {
+ let testData = [
+ ['foo.bar', 'yep.com', 'maybe.idk'],
+ ['related.com', 'larry.com'],
+ ];
+
+ let isMdfp = mdfp.makeIsMultiDomainFirstParty(mdfp.makeDomainLookup(testData));
+
+ assert.ok(
+ isMdfp('yep.com', 'maybe.idk'),
+ "these are related domains according to test data"
+ );
+ assert.ok(
+ isMdfp('maybe.idk', 'yep.com'),
+ "the domains are related regardless of ordering"
+ );
+ assert.ok(
+ isMdfp('related.com', 'larry.com'),
+ "these should also be related domains, from a different set in test data"
+ );
+ assert.notOk(
+ isMdfp('yep.com', 'related.com'),
+ "these domains are both present in test data but should not be related"
+ );
+ assert.notOk(
+ isMdfp('larry.com', 'yep.com'),
+ "these domains are also both present but should be unrelated"
+ );
+ assert.notOk(
+ isMdfp('yep.com', 'google.com'),
+ "one of these domains is not in test data"
+ );
+ assert.notOk(
+ isMdfp('reddit.com', 'eff.org'),
+ "both domains are not in test data"
+ );
+});
+
+// "lint" our MDFP definitions to avoid accidentally adding PSL domains
+// for example:
+// https://github.com/EFForg/privacybadger/pull/1550#pullrequestreview-54480652
+QUnit.test('MDFP domains are all base domains', (assert) => {
+ for (let group of mdfp.multiDomainFirstPartiesArray) {
+ for (let domain of group) {
+ assert.ok(
+ window.getBaseDomain('fakesubdomain.' + domain) == domain,
+ domain + ' is a base domain (eTLD+1)'
+ );
+ }
+ }
+});
+
+// lint for duplicates
+QUnit.test('MDFP domains do not contain duplicates', (assert) => {
+ let domains = new Set();
+ for (let group of mdfp.multiDomainFirstPartiesArray) {
+ for (let domain of group) {
+ assert.notOk(
+ domains.has(domain),
+ domain + ' does not appear more than once'
+ );
+ domains.add(domain);
+ }
+ }
+});
+
+}());
diff --git a/src/tests/tests/options.js b/src/tests/tests/options.js
new file mode 100644
index 0000000..2abeba8
--- /dev/null
+++ b/src/tests/tests/options.js
@@ -0,0 +1,105 @@
+(function () {
+
+QUnit.module("Options page utils");
+
+let { getOriginsArray } = require("optionslib");
+
+QUnit.test("getOriginsArray", (assert) => {
+ const origins = {
+ "allowed.com": "allow",
+ "blocked.org": "block",
+ "alsoblocked.org": "block",
+ "cookieblocked.biz": "cookieblock",
+ "UserAllowed.net": "user_allow",
+ "uuuserblocked.nyc": "user_block",
+ "dntDomain.co.uk": "dnt",
+ "another.allowed.domain.example": "allow",
+ };
+ const originsSansAllowed = _.reduce(
+ origins, (memo, val, key) => {
+ if (val != "allow") {
+ memo[key] = val;
+ }
+ return memo;
+ }, {}
+ );
+
+ const tests = [
+ {
+ msg: "Empty, no filters",
+ args: [{},],
+ expected: []
+ },
+ {
+ msg: "No filters (allowed domains are filtered out)",
+ args: [origins,],
+ expected: Object.keys(originsSansAllowed)
+ },
+ {
+ msg: "Not-yet-blocked domains are shown",
+ args: [origins, null, null, null, true],
+ expected: Object.keys(origins)
+ },
+ {
+ msg: "Type filter",
+ args: [origins, "", "user"],
+ expected: ["UserAllowed.net", "uuuserblocked.nyc"]
+ },
+ {
+ msg: "Status filter",
+ args: [origins, "", "", "allow"],
+ expected: ["UserAllowed.net", "dntDomain.co.uk"]
+ },
+ {
+ msg: "Text filter",
+ args: [origins, ".org"],
+ expected: ["blocked.org", "alsoblocked.org"]
+ },
+ {
+ msg: "Text filter and domain case insensitivity",
+ args: [origins, "uSER"],
+ expected: ["UserAllowed.net", "uuuserblocked.nyc"]
+ },
+ {
+ msg: "Text filter with extra space",
+ args: [origins, " .org"],
+ expected: ["blocked.org", "alsoblocked.org"]
+ },
+ {
+ msg: "Negative text filter",
+ args: [origins, "-.org"],
+ expected: [
+ "cookieblocked.biz",
+ "UserAllowed.net",
+ "uuuserblocked.nyc",
+ "dntDomain.co.uk",
+ ]
+ },
+ {
+ msg: "Multiple negative text filter",
+ args: [origins, "-.net -cookie -.co.uk"],
+ expected: ["blocked.org", "alsoblocked.org", "uuuserblocked.nyc"]
+ },
+ {
+ msg: "Multiple text filters",
+ args: [origins, " -also .biz .org "],
+ expected: ["blocked.org", "cookieblocked.biz"]
+ },
+ {
+ msg: "All filters together",
+ args: [origins, ".net", "user", "allow", true],
+ expected: ["UserAllowed.net"]
+ },
+ ];
+
+ tests.forEach((test) => {
+ assert.deepEqual(
+ getOriginsArray.apply(window, test.args),
+ test.expected,
+ test.msg
+ );
+ });
+
+});
+
+}());
diff --git a/src/tests/tests/storage.js b/src/tests/tests/storage.js
new file mode 100644
index 0000000..cb4042d
--- /dev/null
+++ b/src/tests/tests/storage.js
@@ -0,0 +1,638 @@
+/* globals badger:false, constants:false */
+
+(function () {
+
+const DOMAIN = "example.com",
+ SUBDOMAIN = "widgets." + DOMAIN,
+ SUBSUBDOMAIN = "cdn." + SUBDOMAIN;
+
+let storage = badger.storage,
+ actionMap,
+ snitchMap;
+
+QUnit.module("Storage", {
+ before: (assert) => {
+ // can't initialize globally above
+ // as they get initialized too early when run by Selenium
+ actionMap = storage.getStore('action_map');
+ snitchMap = storage.getStore('snitch_map');
+
+ assert.notOk(actionMap.getItem(DOMAIN),
+ "test domain is not yet in action_map");
+ assert.notOk(snitchMap.getItem(DOMAIN),
+ "test domain is not yet in snitch_map");
+ }
+});
+
+QUnit.test("testGetBadgerStorage", function (assert) {
+ assert.ok(actionMap.updateObject instanceof Function, "actionMap is a pbstorage");
+});
+
+QUnit.test("test BadgerStorage methods", function (assert) {
+ actionMap.setItem('foo', 'bar');
+ assert.equal(actionMap.getItem('foo'), 'bar');
+ assert.ok(actionMap.hasItem('foo'));
+ actionMap.deleteItem('foo');
+ assert.notOk(actionMap.hasItem('foo'));
+});
+
+QUnit.test("test user override of default action for domain", function (assert) {
+ badger.saveAction("allow", "pbtest.org");
+ assert.equal(storage.getAction("pbtest.org"), constants.USER_ALLOW);
+ badger.saveAction("block", "pbtest.org");
+ assert.equal(storage.getAction("pbtest.org"), constants.USER_BLOCK);
+ badger.saveAction("allow", "pbtest.org");
+ assert.equal(storage.getAction("pbtest.org"), constants.USER_ALLOW);
+ storage.revertUserAction("pbtest.org");
+ assert.equal(storage.getAction("pbtest.org"), constants.NO_TRACKING);
+});
+
+QUnit.test("settings map merging", (assert) => {
+ let settings_map = storage.getStore('settings_map');
+
+ // overwrite settings with test values
+ settings_map.setItem('disabledSites', ['example.com']);
+ settings_map.setItem('showCounter', true);
+
+ // merge settings
+ settings_map.merge({
+ disabledSites: ['www.nytimes.com'],
+ showCounter: false,
+ });
+
+ // verify
+ assert.deepEqual(
+ settings_map.getItem('disabledSites'),
+ ['example.com', 'www.nytimes.com'],
+ "disabled site lists are combined when merging settings"
+ );
+ assert.ok(!settings_map.getItem('showCounter'), "other settings are overwritten");
+});
+
+// previously:
+// https://github.com/EFForg/privacybadger/pull/1911#issuecomment-379896911
+QUnit.test("action map merge copies/breaks references", (assert) => {
+ let data = {
+ dnt: false,
+ heuristicAction: '',
+ nextUpdateTime: 100,
+ userAction: 'user_block'
+ };
+
+ actionMap.merge({[DOMAIN]: data});
+ assert.deepEqual(
+ actionMap.getItem(DOMAIN),
+ data,
+ "test domain was imported");
+
+ // set a property on the original object
+ data.userAction = "user_allow";
+
+ // this should not affect data in storage
+ assert.equal(actionMap.getItem(DOMAIN).userAction,
+ "user_block",
+ "already imported data should be left alone " +
+ "when modifying object used for import");
+});
+
+QUnit.test("action map merge only updates user action", (assert) => {
+ actionMap.setItem(DOMAIN,
+ {dnt: false, heuristicAction: '', nextUpdateTime: 100, userAction: ''});
+ assert.equal(actionMap.getItem(DOMAIN).nextUpdateTime, 100);
+
+ let newValue = {dnt: true, heuristicAction: constants.BLOCK,
+ nextUpdateTime: 99, userAction: constants.USER_BLOCK};
+ actionMap.merge({[DOMAIN]: newValue});
+ assert.equal(actionMap.getItem(DOMAIN).userAction,
+ constants.USER_BLOCK,
+ "userAction should be merged if it's set");
+ assert.equal(actionMap.getItem(DOMAIN).heuristicAction, '',
+ 'heuristicAction should never be overwritten');
+
+ newValue.userAction = '';
+ actionMap.merge({[DOMAIN]: newValue});
+ assert.equal(actionMap.getItem(DOMAIN).userAction,
+ constants.USER_BLOCK,
+ 'blank userAction should not overwrite anything');
+});
+
+QUnit.test("action map merge creates new entry if necessary", (assert) => {
+ assert.notOk(actionMap.hasItem('newsite.com'));
+
+ let newValue = {dnt: false, heuristicAction: constants.BLOCK,
+ nextUpdateTime: 100, userAction: ''};
+ actionMap.merge({'newsite.com': newValue});
+ assert.notOk(actionMap.hasItem('newsite.com'),
+ 'action map entry should not be created for heuristicAction alone');
+
+ newValue.userAction = constants.USER_BLOCK;
+ actionMap.merge({'newsite.com': newValue});
+ assert.ok(actionMap.hasItem('newsite.com'),
+ 'action map entry should be created if userAction is set');
+
+ actionMap.deleteItem('newsite.com');
+
+ newValue.userAction = '';
+ newValue.dnt = true;
+ actionMap.merge({'newsite.com': newValue});
+ assert.ok(actionMap.hasItem('newsite.com'),
+ 'action map entry should be created if DNT is set');
+});
+
+QUnit.test("action map merge updates with latest DNT info", (assert) => {
+ actionMap.setItem(DOMAIN,
+ {dnt: false, heuristicAction: '', nextUpdateTime: 100, userAction: ''});
+
+ // DNT should not be merged if nextUpdateTime is earlier
+ let newValue = {dnt: true, heuristicAction: '', nextUpdateTime: 99, userAction: ''};
+ actionMap.merge({[DOMAIN]: newValue});
+ assert.equal(actionMap.getItem(DOMAIN).nextUpdateTime, 100,
+ 'nextUpdateTime should not be changed to an earlier time');
+ assert.notOk(actionMap.getItem(DOMAIN).dnt,
+ 'DNT value should not be updated by out-of-date information');
+
+ // DNT should be merged if it's more up-to-date
+ newValue.nextUpdateTime = 101;
+ actionMap.merge({[DOMAIN]: newValue});
+ assert.equal(actionMap.getItem(DOMAIN).nextUpdateTime, 101,
+ 'nextUpdateTime should be updated to later time');
+ assert.ok(actionMap.getItem(DOMAIN).dnt,
+ 'DNT value should be updated with more recent information');
+});
+
+QUnit.test("action map merge handles missing nextUpdateTime", (assert) => {
+ let newValue = {
+ dnt: true,
+ heuristicAction: '',
+ userAction: ''
+ };
+
+ assert.notOk(newValue.hasOwnProperty('nextUpdateTime'),
+ "nextUpdateTime is indeed missing from the import");
+
+ // new DNT domain should be imported
+ actionMap.merge({[DOMAIN]: newValue});
+ assert.deepEqual(
+ actionMap.getItem(DOMAIN),
+ Object.assign({ nextUpdateTime: 0 }, newValue),
+ "test domain was imported and nextUpdateTime got initialized");
+
+ // existing DNT domain should be left alone
+ // as we don't know how fresh the import is
+ newValue.dnt = false;
+ actionMap.merge({[DOMAIN]: newValue});
+ assert.ok(actionMap.getItem(DOMAIN).dnt,
+ "existing data should be left alone " +
+ "when unable to determine recency of new data");
+
+ // now set the timestamp and try again
+ newValue.nextUpdateTime = 200;
+ actionMap.merge({[DOMAIN]: newValue});
+ assert.notOk(actionMap.getItem(DOMAIN).dnt,
+ "DNT got overriden now that new data seems fresher");
+});
+
+QUnit.test("action map merge handles missing userAction", (assert) => {
+ let newValue = {
+ heuristicAction: 'allow',
+ dnt: true,
+ nextUpdateTime: 100
+ };
+
+ // import and check that userAction got initialized
+ actionMap.merge({[DOMAIN]: newValue});
+ assert.deepEqual(
+ actionMap.getItem(DOMAIN),
+ Object.assign({ userAction: '' }, newValue),
+ "test domain was imported and userAction got initialized");
+});
+
+QUnit.test("action map merge handles missing dnt", (assert) => {
+ let newValue = {
+ heuristicAction: 'block',
+ userAction: 'user_allow'
+ };
+
+ // import and check that userAction got initialized
+ actionMap.merge({[DOMAIN]: newValue});
+ assert.deepEqual(
+ actionMap.getItem(DOMAIN),
+ Object.assign({ dnt: false, nextUpdateTime: 0 }, newValue),
+ "test domain was imported and DNT got initialized");
+});
+
+QUnit.test("action map merge handles subdomains correctly", (assert) => {
+ actionMap.setItem('testsite.com',
+ {dnt: false, heuristicAction: '', nextUpdateTime: 100, userAction: ''});
+
+ let newValue = {dnt: true, heuristicAction: '', nextUpdateTime: 100, userAction: ''};
+
+ actionMap.merge({'s1.testsite.com': newValue});
+ assert.ok(actionMap.hasItem('s1.testsite.com'),
+ 'Subdomains should be merged if they honor DNT');
+
+ newValue.dnt = false;
+ actionMap.merge({'s2.testsite.com': newValue});
+ assert.notOk(actionMap.hasItem('s2.testsite.com'),
+ "Subdomains should not be merged if they don't honor DNT");
+});
+
+QUnit.test("snitch map merging", (assert) => {
+ snitchMap.merge({[DOMAIN]: ['firstparty.org']});
+ assert.ok(snitchMap.getItem(DOMAIN).indexOf('firstparty.org') > -1);
+
+ // Check to make sure existing and new domain are present
+ snitchMap.merge({[DOMAIN]: ['firstparty2.org']});
+ assert.ok(snitchMap.getItem(DOMAIN).indexOf('firstparty.org') > -1);
+ assert.ok(snitchMap.getItem(DOMAIN).indexOf('firstparty2.org') > -1);
+
+ // Verify 'block' status is triggered once TRACKING_THRESHOLD is hit
+ assert.equal(actionMap.getItem(DOMAIN).heuristicAction, "allow");
+ snitchMap.merge({[DOMAIN]: ["firstparty3.org"]});
+ assert.equal(actionMap.getItem(DOMAIN).heuristicAction, "block");
+});
+
+QUnit.test("blocking cascades", (assert) => {
+ // mark domain for blocking
+ storage.setupHeuristicAction(DOMAIN, constants.BLOCK);
+
+ // check domain itself
+ assert.equal(
+ storage.getAction(DOMAIN),
+ constants.BLOCK,
+ "domain is marked for blocking directly"
+ );
+ assert.equal(
+ storage.getBestAction(DOMAIN),
+ constants.BLOCK,
+ "domain is marked for blocking"
+ );
+
+ // check that subdomain inherits blocking
+ assert.equal(
+ storage.getAction(SUBDOMAIN),
+ constants.NO_TRACKING,
+ "subdomain is not marked for blocking directly"
+ );
+ assert.equal(
+ storage.getBestAction(SUBDOMAIN),
+ constants.BLOCK,
+ "subdomain is marked for blocking (via parent domain)"
+ );
+
+ // check that subsubdomain inherits blocking
+ assert.equal(
+ storage.getAction(SUBSUBDOMAIN),
+ constants.NO_TRACKING,
+ "subsubdomain is not marked for blocking directly"
+ );
+ assert.equal(
+ storage.getBestAction(SUBSUBDOMAIN),
+ constants.BLOCK,
+ "subsubdomain is marked for blocking (via grandparent domain)"
+ );
+});
+
+QUnit.test("DNT does not cascade", (assert) => {
+ storage.setupDNT(DOMAIN);
+
+ // check domain itself
+ assert.equal(
+ storage.getAction(DOMAIN),
+ constants.DNT,
+ "domain is marked as DNT directly"
+ );
+ assert.equal(
+ storage.getBestAction(DOMAIN),
+ constants.DNT,
+ "domain is marked as DNT"
+ );
+
+ // check that subdomain does not inherit DNT
+ assert.equal(
+ storage.getAction(SUBDOMAIN),
+ constants.NO_TRACKING,
+ "subdomain is not marked as DNT directly"
+ );
+ assert.equal(
+ storage.getBestAction(SUBDOMAIN),
+ constants.NO_TRACKING,
+ "subdomain is not marked as DNT (via parent domain)"
+ );
+});
+
+QUnit.test("DNT does not return as an action if user has chosen not to", (assert) => {
+ let settings_map = storage.getStore('settings_map');
+ settings_map.setItem("checkForDNTPolicy", false);
+ storage.setupDNT(DOMAIN);
+
+ assert.equal(
+ storage.getAction(DOMAIN),
+ constants.NO_TRACKING,
+ "domain is marked as DNT directly, but returns as NO_TRACKING because user has disabled DNT"
+ );
+ assert.equal(
+ storage.getBestAction(DOMAIN),
+ constants.NO_TRACKING,
+ "domain is marked as DNT, but returns as NO_TRACKING because user has disabled DNT"
+ );
+});
+
+QUnit.test("blocking still cascades after domain declares DNT", (assert) => {
+ storage.setupHeuristicAction(DOMAIN, constants.BLOCK);
+ storage.setupDNT(DOMAIN);
+
+ // check domain itself
+ assert.equal(
+ storage.getAction(DOMAIN, true),
+ constants.BLOCK,
+ "domain is marked for blocking directly"
+ );
+ assert.equal(
+ storage.getBestAction(DOMAIN),
+ constants.DNT,
+ "domain is marked as DNT"
+ );
+
+ // check that subdomain inherits blocking
+ assert.equal(
+ storage.getAction(SUBDOMAIN),
+ constants.NO_TRACKING,
+ "subdomain is not marked for blocking directly"
+ );
+ assert.equal(
+ storage.getBestAction(SUBDOMAIN),
+ constants.BLOCK,
+ "subdomain is marked for blocking (via parent domain)"
+ );
+});
+
+QUnit.test("cascading doesn't work the other way", (assert) => {
+ // mark subdomain for blocking
+ storage.setupHeuristicAction(SUBDOMAIN, constants.BLOCK);
+
+ // check subdomain itself
+ assert.equal(
+ storage.getAction(SUBDOMAIN),
+ constants.BLOCK,
+ "subdomain is marked for blocking directly"
+ );
+ assert.equal(
+ storage.getBestAction(SUBDOMAIN),
+ constants.BLOCK,
+ "subdomain is marked for blocking"
+ );
+
+ // check that parent domain does not inherit blocking
+ assert.equal(
+ storage.getAction(DOMAIN),
+ constants.NO_TRACKING,
+ "domain is not marked for blocking directly"
+ );
+ assert.equal(
+ storage.getBestAction(DOMAIN),
+ constants.NO_TRACKING,
+ "domain is not marked for blocking"
+ );
+});
+
+QUnit.test("blocking overrules allowing", (assert) => {
+ // mark domain for blocking
+ storage.setupHeuristicAction(DOMAIN, constants.BLOCK);
+ // mark subsubdomain as "allow" (not-yet-over-the-threshold tracker)
+ storage.setupHeuristicAction(SUBSUBDOMAIN, constants.ALLOW);
+
+ // check domain itself
+ assert.equal(
+ storage.getAction(DOMAIN),
+ constants.BLOCK,
+ "domain is marked for blocking directly"
+ );
+ assert.equal(
+ storage.getBestAction(DOMAIN),
+ constants.BLOCK,
+ "domain is marked for blocking"
+ );
+
+ // check that subsubdomain inherits blocking
+ assert.equal(
+ storage.getAction(SUBSUBDOMAIN),
+ constants.ALLOW,
+ "subdomain is marked as 'allow' directly"
+ );
+ assert.equal(
+ storage.getBestAction(SUBSUBDOMAIN),
+ constants.BLOCK,
+ "subsubdomain is marked for blocking (via grandparent domain)"
+ );
+});
+
+QUnit.test("cookieblocking overrules blocking", (assert) => {
+ // mark domain for cookieblocking
+ storage.setupHeuristicAction(DOMAIN, constants.COOKIEBLOCK);
+ // mark subdomain for blocking
+ storage.setupHeuristicAction(SUBDOMAIN, constants.BLOCK);
+
+ // check domain itself
+ assert.equal(
+ storage.getAction(DOMAIN),
+ constants.COOKIEBLOCK,
+ "domain is marked for cookieblocking directly"
+ );
+ assert.equal(
+ storage.getBestAction(DOMAIN),
+ constants.COOKIEBLOCK,
+ "domain is marked for cookieblocking"
+ );
+
+ // check that subdomain inherits cookieblocking
+ assert.equal(
+ storage.getAction(SUBDOMAIN),
+ constants.BLOCK,
+ "subdomain is marked for blocking directly"
+ );
+ assert.equal(
+ storage.getBestAction(SUBDOMAIN),
+ constants.COOKIEBLOCK,
+ "subdomain is marked for cookieblocking (via parent domain)"
+ );
+});
+
+QUnit.test("user actions overrule everything else", (assert) => {
+ storage.setupUserAction(DOMAIN, constants.USER_BLOCK);
+ storage.setupHeuristicAction(SUBDOMAIN, constants.COOKIEBLOCK);
+ storage.setupDNT(SUBSUBDOMAIN);
+
+ // check domain itself
+ assert.equal(
+ storage.getAction(DOMAIN),
+ constants.USER_BLOCK,
+ "domain is marked as userblock directly"
+ );
+ assert.equal(
+ storage.getBestAction(DOMAIN),
+ constants.USER_BLOCK,
+ "domain is marked as userblock"
+ );
+
+ // check subdomain
+ assert.equal(
+ storage.getAction(SUBDOMAIN),
+ constants.COOKIEBLOCK,
+ "subdomain is marked for cookie blocking directly"
+ );
+ assert.equal(
+ storage.getBestAction(SUBDOMAIN),
+ constants.USER_BLOCK,
+ "subdomain is marked as userblock"
+ );
+
+ // check subsubdomain
+ assert.equal(
+ storage.getAction(SUBSUBDOMAIN),
+ constants.DNT,
+ "subsubdomain is marked as DNT directly"
+ );
+ assert.equal(
+ storage.getBestAction(SUBSUBDOMAIN),
+ constants.USER_BLOCK,
+ "subsubdomain is marked as userblock"
+ );
+});
+
+// all three user actions are equally important
+// but the one closest to the FQDN being checked should win
+QUnit.test("specificity of rules of equal priority", (assert) => {
+ storage.setupUserAction(DOMAIN, constants.USER_BLOCK);
+ storage.setupUserAction(SUBDOMAIN, constants.USER_ALLOW);
+ storage.setupUserAction(SUBSUBDOMAIN, constants.USER_COOKIEBLOCK);
+
+ // check domain itself
+ assert.equal(
+ storage.getAction(DOMAIN),
+ constants.USER_BLOCK,
+ "domain is marked as userblock directly"
+ );
+ assert.equal(
+ storage.getBestAction(DOMAIN),
+ constants.USER_BLOCK,
+ "domain is marked as userblock"
+ );
+
+ // check subdomain
+ assert.equal(
+ storage.getAction(SUBDOMAIN),
+ constants.USER_ALLOW,
+ "subdomain is marked as userallow directly"
+ );
+ assert.equal(
+ storage.getBestAction(SUBDOMAIN),
+ constants.USER_ALLOW,
+ "subdomain is marked as userallow"
+ );
+
+ // check subsubdomain
+ assert.equal(
+ storage.getAction(SUBSUBDOMAIN),
+ constants.USER_COOKIEBLOCK,
+ "subsubdomain is marked as usercookieblock directly"
+ );
+ assert.equal(
+ storage.getBestAction(SUBSUBDOMAIN),
+ constants.USER_COOKIEBLOCK,
+ "subsubdomain is marked as usercookieblock"
+ );
+});
+
+QUnit.test("unexpected heuristic actions are ignored", (assert) => {
+ storage.setupHeuristicAction(DOMAIN, "foo");
+ storage.setupHeuristicAction(SUBDOMAIN, constants.ALLOW);
+ storage.setupHeuristicAction(SUBSUBDOMAIN, "bar");
+
+ // check domain itself
+ assert.equal(
+ storage.getAction(DOMAIN),
+ "foo",
+ "domain is marked as 'foo' directly"
+ );
+ assert.equal(
+ storage.getBestAction(DOMAIN),
+ constants.NO_TRACKING,
+ "best action for domain is 'no tracking'"
+ );
+
+ // check subdomain
+ assert.equal(
+ storage.getAction(SUBDOMAIN),
+ constants.ALLOW,
+ "subdomain is marked as 'allow' directly"
+ );
+ assert.equal(
+ storage.getBestAction(SUBDOMAIN),
+ constants.ALLOW,
+ "best action for subdomain is 'allow'"
+ );
+
+ // check subsubdomain
+ assert.equal(
+ storage.getAction(SUBSUBDOMAIN),
+ "bar",
+ "subsubdomain is marked as 'bar' directly"
+ );
+ assert.equal(
+ storage.getBestAction(SUBSUBDOMAIN),
+ constants.ALLOW,
+ "best action for subsubdomain is 'allow'"
+ );
+});
+
+function checkCookieblocking(assert) {
+ assert.equal(
+ storage.getBestAction(SUBDOMAIN),
+ constants.NO_TRACKING,
+ "subdomain is not yet (cookie)blocked"
+ );
+ assert.ok(
+ storage.wouldGetCookieblocked(SUBDOMAIN),
+ "subdomain would get cookieblocked if blocked"
+ );
+
+ // block the subdomain
+ badger.heuristicBlocking.blocklistOrigin(DOMAIN, SUBDOMAIN);
+
+ assert.equal(
+ storage.getBestAction(SUBDOMAIN),
+ constants.COOKIEBLOCK,
+ "subdomain is cookieblocked"
+ );
+ assert.ok(
+ storage.wouldGetCookieblocked(SUBDOMAIN),
+ "subdomain would get/is cookieblocked"
+ );
+}
+
+QUnit.test("checking cookieblock potential for yellowlisted subdomain", (assert) => {
+ assert.notOk(
+ storage.wouldGetCookieblocked(SUBDOMAIN),
+ "subdomain wouldn't get cookieblocked if blocked"
+ );
+
+ // add subdomain to yellowlist
+ storage.getStore('cookieblock_list').setItem(SUBDOMAIN, true);
+
+ checkCookieblocking(assert);
+});
+
+QUnit.test("checking cookieblock potential for subdomain with yellowlisted base domain", (assert) => {
+ assert.notOk(
+ storage.wouldGetCookieblocked(SUBDOMAIN),
+ "subdomain wouldn't get cookieblocked if blocked"
+ );
+
+ // add base domain to yellowlist
+ storage.getStore('cookieblock_list').setItem(DOMAIN, true);
+
+ checkCookieblocking(assert);
+});
+
+}());
diff --git a/src/tests/tests/tabData.js b/src/tests/tests/tabData.js
new file mode 100644
index 0000000..c578cd1
--- /dev/null
+++ b/src/tests/tests/tabData.js
@@ -0,0 +1,310 @@
+/* globals badger:false */
+
+(function () {
+
+let constants = require('constants');
+
+QUnit.module("tabData", {
+ beforeEach: function () {
+
+ this.SITE_URL = "http://example.com/";
+ this.tabId = 9999;
+
+ badger.recordFrame(this.tabId, 0, this.SITE_URL);
+
+ // stub chrome.tabs.get manually as we have some sort of issue stubbing with Sinon in Firefox
+ this.chromeTabsGet = chrome.tabs.get;
+ chrome.tabs.get = (tab_id, callback) => {
+ return callback({
+ active: true
+ });
+ };
+ },
+
+ afterEach: function () {
+ chrome.tabs.get = this.chromeTabsGet;
+ delete badger.tabData[this.tabId];
+ }
+},
+function() {
+ QUnit.module("logThirdPartyOriginOnTab", {
+ beforeEach: function () {
+ this.clock = sinon.useFakeTimers();
+ sinon.stub(chrome.browserAction, "setBadgeText");
+ },
+ afterEach: function () {
+ chrome.browserAction.setBadgeText.restore();
+ this.clock.restore();
+ },
+ });
+
+ QUnit.test("logging blocked domain", function (assert) {
+ const DOMAIN = "example.com";
+
+ assert.equal(
+ badger.getTrackerCount(this.tabId), 0, "count starts at zero"
+ );
+
+ // set up domain blocking (used by getTrackerCount)
+ badger.storage.setupHeuristicAction(DOMAIN, constants.BLOCK);
+
+ // log blocked domain
+ badger.logThirdPartyOriginOnTab(this.tabId, DOMAIN, constants.BLOCK);
+ this.clock.tick(1);
+ assert.equal(
+ badger.getTrackerCount(this.tabId), 1, "count gets incremented"
+ );
+ assert.ok(
+ chrome.browserAction.setBadgeText.calledOnce,
+ "updateBadge gets called when we see a blocked domain"
+ );
+ assert.ok(chrome.browserAction.setBadgeText.calledWithExactly({
+ tabId: this.tabId,
+ text: "1"
+ }), "setBadgeText was called with expected args");
+ });
+
+ QUnit.test("logging unblocked domain", function (assert) {
+ badger.logThirdPartyOriginOnTab(this.tabId, "example.com", constants.ALLOW);
+ this.clock.tick(1);
+ assert.equal(
+ badger.getTrackerCount(this.tabId), 0, "count stays at zero"
+ );
+ assert.ok(
+ chrome.browserAction.setBadgeText.notCalled,
+ "updateBadge does not get called when we see a hasn't-decided-yet-to-block domain"
+ );
+ });
+
+ QUnit.test("logging DNT-compliant domain", function (assert) {
+ badger.logThirdPartyOriginOnTab(this.tabId, "example.com", constants.DNT);
+ this.clock.tick(1);
+ assert.equal(
+ badger.getTrackerCount(this.tabId), 0, "count stays at zero"
+ );
+ assert.ok(
+ chrome.browserAction.setBadgeText.notCalled,
+ "updateBadge does not get called when we see a DNT-compliant domain"
+ );
+ });
+
+ QUnit.test("logging as unblocked then as blocked", function (assert) {
+ const DOMAIN = "example.com";
+
+ // log unblocked domain
+ badger.logThirdPartyOriginOnTab(this.tabId, DOMAIN, constants.ALLOW);
+ this.clock.tick(1);
+
+ // set up domain blocking (used by getTrackerCount)
+ badger.storage.setupHeuristicAction(DOMAIN, constants.BLOCK);
+
+ // log the same domain, this time as blocked
+ badger.logThirdPartyOriginOnTab(this.tabId, DOMAIN, constants.BLOCK);
+ this.clock.tick(1);
+ assert.equal(
+ badger.getTrackerCount(this.tabId), 1, "count gets incremented"
+ );
+ assert.equal(
+ chrome.browserAction.setBadgeText.callCount,
+ "1",
+ "updateBadge gets called when we see a blocked domain"
+ );
+ assert.ok(chrome.browserAction.setBadgeText.calledWithExactly({
+ tabId: this.tabId,
+ text: "1"
+ }), "setBadgeText was called with expected args");
+ });
+
+ QUnit.test("logging blocked domain twice", function (assert) {
+ const DOMAIN = "example.com";
+
+ // set up domain blocking (used by getTrackerCount)
+ badger.storage.setupHeuristicAction(DOMAIN, constants.BLOCK);
+
+ // log blocked domain
+ badger.logThirdPartyOriginOnTab(this.tabId, DOMAIN, constants.BLOCK);
+ this.clock.tick(1);
+ assert.equal(
+ badger.getTrackerCount(this.tabId), 1, "count gets incremented"
+ );
+ assert.ok(
+ chrome.browserAction.setBadgeText.calledOnce,
+ "updateBadge gets called when we see a blocked domain"
+ );
+ assert.ok(chrome.browserAction.setBadgeText.calledWithExactly({
+ tabId: this.tabId,
+ text: "1"
+ }), "setBadgeText was called with expected args");
+
+ // log the same blocked domain again
+ badger.logThirdPartyOriginOnTab(this.tabId, DOMAIN, constants.BLOCK);
+ this.clock.tick(1);
+ assert.equal(
+ badger.getTrackerCount(this.tabId),
+ 1,
+ "count does not get incremented"
+ );
+ assert.ok(
+ chrome.browserAction.setBadgeText.calledOnce,
+ "updateBadge not called when we see the same blocked domain again"
+ );
+ });
+
+ QUnit.test("logging 2x unblocked then 2x blocked", function (assert) {
+ const DOMAIN = "example.com";
+
+ // log unblocked domain twice
+ badger.logThirdPartyOriginOnTab(this.tabId, DOMAIN, constants.ALLOW);
+ this.clock.tick(1);
+ badger.logThirdPartyOriginOnTab(this.tabId, DOMAIN, constants.ALLOW);
+ this.clock.tick(1);
+
+ // set up domain blocking (used by getTrackerCount)
+ badger.storage.setupHeuristicAction(DOMAIN, constants.BLOCK);
+
+ // log blocked domain
+ badger.logThirdPartyOriginOnTab(this.tabId, DOMAIN, constants.BLOCK);
+ this.clock.tick(1);
+ assert.equal(
+ badger.getTrackerCount(this.tabId), 1, "count gets incremented"
+ );
+ assert.ok(
+ chrome.browserAction.setBadgeText.calledOnce,
+ "updateBadge gets called when we see a blocked domain"
+ );
+ assert.deepEqual(chrome.browserAction.setBadgeText.getCall(0).args[0], {
+ tabId: this.tabId,
+ text: "1"
+ }, "setBadgeText was called with expected args");
+
+ // log the same blocked domain again
+ badger.logThirdPartyOriginOnTab(this.tabId, DOMAIN, constants.BLOCK);
+ this.clock.tick(1);
+ assert.equal(
+ badger.getTrackerCount(this.tabId),
+ 1,
+ "count does not get incremented"
+ );
+ assert.ok(
+ chrome.browserAction.setBadgeText.calledOnce,
+ "updateBadge not called when we see the same blocked domain again"
+ );
+ });
+
+ QUnit.test("logging cookieblocked domain", function (assert) {
+ const DOMAIN = "example.com";
+
+ // set up domain blocking (used by getTrackerCount)
+ badger.storage.setupHeuristicAction(DOMAIN, constants.COOKIEBLOCK);
+
+ // log cookieblocked domain
+ badger.logThirdPartyOriginOnTab(this.tabId, DOMAIN, constants.COOKIEBLOCK);
+ this.clock.tick(1);
+ assert.equal(
+ badger.getTrackerCount(this.tabId), 1, "count gets incremented"
+ );
+ assert.ok(
+ chrome.browserAction.setBadgeText.calledOnce,
+ "updateBadge gets called when we see a cookieblocked domain"
+ );
+ assert.ok(chrome.browserAction.setBadgeText.calledWithExactly({
+ tabId: this.tabId,
+ text: "1"
+ }), "setBadgeText was called with expected args");
+ });
+
+ QUnit.test("logging several domains", function (assert) {
+ const DOMAIN1 = "example.com",
+ DOMAIN2 = "example.net";
+
+ // set up domain blocking (used by getTrackerCount)
+ badger.storage.setupHeuristicAction(DOMAIN1, constants.BLOCK);
+ badger.storage.setupHeuristicAction(DOMAIN2, constants.COOKIEBLOCK);
+
+ // log blocked domain
+ badger.logThirdPartyOriginOnTab(this.tabId, DOMAIN1, constants.BLOCK);
+ this.clock.tick(1);
+ assert.equal(
+ badger.getTrackerCount(this.tabId), 1, "count gets incremented"
+ );
+ assert.ok(
+ chrome.browserAction.setBadgeText.calledOnce,
+ "updateBadge gets called when we see a blocked domain"
+ );
+ assert.ok(chrome.browserAction.setBadgeText.calledWithExactly({
+ tabId: this.tabId,
+ text: "1"
+ }), "setBadgeText was called with expected args");
+
+ // log cookieblocked domain
+ badger.logThirdPartyOriginOnTab(this.tabId, DOMAIN2, constants.COOKIEBLOCK);
+ this.clock.tick(1);
+ assert.equal(
+ badger.getTrackerCount(this.tabId), 2, "count gets incremented again"
+ );
+ assert.ok(
+ chrome.browserAction.setBadgeText.calledTwice,
+ "updateBadge gets called when we see a cookieblocked domain"
+ );
+ assert.ok(chrome.browserAction.setBadgeText.calledWithExactly({
+ tabId: this.tabId,
+ text: "2"
+ }), "setBadgeText was called with expected args");
+ });
+
+ QUnit.module('updateBadge', {
+ beforeEach: function() {
+ this.setBadgeText = sinon.stub(chrome.browserAction, "setBadgeText");
+
+ // another Firefox workaround: setBadgeText gets stubbed fine but setBadgeBackgroundColor doesn't
+ this.setBadgeBackgroundColor = chrome.browserAction.setBadgeBackgroundColor;
+ },
+ afterEach: function() {
+ this.setBadgeText.restore();
+ chrome.browserAction.setBadgeBackgroundColor = this.setBadgeBackgroundColor;
+ },
+ });
+
+ QUnit.test("disabled", function(assert) {
+ let done = assert.async(2),
+ called = false;
+
+ badger.disablePrivacyBadgerForOrigin(window.extractHostFromURL(this.SITE_URL));
+
+ this.setBadgeText.callsFake((obj) => {
+ assert.deepEqual(obj, {tabId: this.tabId, text: ''});
+ done();
+ });
+ chrome.browserAction.setBadgeBackgroundColor = () => {called = true;};
+
+ badger.updateBadge(this.tabId);
+
+ assert.notOk(called, "setBadgeBackgroundColor does not get called");
+
+ done();
+ });
+
+ QUnit.test("numblocked zero", function(assert) {
+ let done = assert.async(2),
+ called = false;
+
+ this.setBadgeText.callsFake((obj) => {
+ assert.deepEqual(
+ obj,
+ {tabId: this.tabId, text: ""},
+ "setBadgeText called with expected args"
+ );
+ done();
+ });
+ chrome.browserAction.setBadgeBackgroundColor = () => {called = true;};
+
+ badger.updateBadge(this.tabId);
+
+ assert.notOk(called, "setBadgeBackgroundColor does not get called");
+
+ done();
+ });
+
+});
+
+}());
diff --git a/src/tests/tests/utils.js b/src/tests/tests/utils.js
new file mode 100644
index 0000000..c884374
--- /dev/null
+++ b/src/tests/tests/utils.js
@@ -0,0 +1,550 @@
+/* globals badger:false */
+
+(function() {
+
+QUnit.module("Utils");
+
+var utils = require('utils');
+var getSurrogateURI = require('surrogates').getSurrogateURI;
+
+QUnit.test("explodeSubdomains", function (assert) {
+ var fqdn = "test.what.yea.eff.org";
+ var subs = utils.explodeSubdomains(fqdn);
+ assert.equal(subs.length, 4);
+ assert.equal(subs[0], fqdn);
+ assert.equal(subs[3], "eff.org");
+});
+
+QUnit.test("xhrRequest", function (assert) {
+ // set up fake server to simulate XMLHttpRequests
+ let server = sinon.fakeServer.create({
+ respondImmediately: true
+ });
+ server.respondWith("GET", "https://www.eff.org/files/badgertest.txt",
+ [200, {}, "test passed\n"]);
+
+ let done = assert.async();
+ assert.expect(4);
+
+ utils.xhrRequest("https://www.eff.org/files/badgertest.txt", function (err1, resp) {
+ assert.strictEqual(err1, null, "there was no error");
+ assert.equal(resp, "test passed\n", "got expected response text");
+
+ utils.xhrRequest("https://www.eff.org/nonexistent-page", function(err2/*, resp*/) {
+ assert.ok(err2, "there was an error");
+ assert.equal(err2.status, 404, "error was 404");
+
+ server.restore();
+ done();
+ });
+ });
+});
+
+QUnit.test("isPrivacyBadgerEnabled basic tests", function (assert) {
+ assert.ok(badger.isPrivacyBadgerEnabled("example.com"),
+ "Domain starts out as enabled.");
+
+ badger.disablePrivacyBadgerForOrigin("example.com");
+ assert.notOk(badger.isPrivacyBadgerEnabled("example.com"),
+ "Disabling the domain works.");
+
+ badger.enablePrivacyBadgerForOrigin("example.com");
+ assert.ok(badger.isPrivacyBadgerEnabled("example.com"),
+ "Re-enabling the domain works.");
+});
+
+QUnit.test("isPrivacyBadgerEnabled wildcard tests", function (assert) {
+ badger.disablePrivacyBadgerForOrigin('*.mail.example.com');
+ assert.ok(
+ badger.isPrivacyBadgerEnabled('www.example.com'),
+ "Ignores cases without as many subdomains as the wildcard."
+ );
+ assert.ok(
+ badger.isPrivacyBadgerEnabled('web.stuff.example.com'),
+ "Ignores cases where subdomains do not match the wildcard."
+ );
+ assert.notOk(
+ badger.isPrivacyBadgerEnabled('web.mail.example.com'),
+ "Website matches wildcard pattern."
+ );
+ assert.notOk(
+ badger.isPrivacyBadgerEnabled('stuff.fakedomain.web.mail.example.com'),
+ "Wildcard catches all prefacing subdomains."
+ );
+ assert.ok(
+ badger.isPrivacyBadgerEnabled('mail.example.com'),
+ "Checks against URLs that lack a starting dot."
+ );
+
+ const PSL_TLD = "example.googlecode.com";
+ assert.equal(window.getBaseDomain(PSL_TLD), PSL_TLD,
+ PSL_TLD + " is a PSL TLD");
+ badger.disablePrivacyBadgerForOrigin('*.googlecode.com');
+ assert.notOk(badger.isPrivacyBadgerEnabled(PSL_TLD),
+ "PSL TLDs work with wildcards as expected.");
+});
+
+QUnit.test("disable/enable privacy badger for origin", function (assert) {
+ function parsed() {
+ return badger.storage.getStore('settings_map').getItem('disabledSites');
+ }
+
+ let origLength = parsed() && parsed().length || 0;
+
+ badger.disablePrivacyBadgerForOrigin('foo.com');
+ assert.ok(parsed().length == (origLength + 1), "one more disabled site");
+
+ badger.enablePrivacyBadgerForOrigin('foo.com');
+ assert.ok(parsed().length == origLength, "one less disabled site");
+});
+
+QUnit.test("surrogate script URL lookups", function (assert) {
+ const NOOP = function () {};
+ const surrogatedb = require('surrogatedb');
+ const SURROGATE_PREFIX = 'data:application/javascript;base64,';
+ const GA_JS_TESTS = [
+ {
+ url: 'http://www.google-analytics.com/ga.js',
+ msg: "Google Analytics ga.js http URL should match"
+ },
+ {
+ url: 'https://www.google-analytics.com/ga.js',
+ msg: "Google Analytics ga.js https URL should match"
+ },
+ {
+ url: 'https://www.google-analytics.com/ga.js?foo=bar',
+ msg: "Google Analytics ga.js querystring URL should match"
+ },
+ ];
+ const NYT_SCRIPT_PATH = '/assets/homepage/20160920-111441/js/foundation/lib/framework.js';
+ const NYT_URL = 'https://a1.nyt.com' + NYT_SCRIPT_PATH;
+
+ let ga_js_surrogate;
+
+ for (let i = 0; i < GA_JS_TESTS.length; i++) {
+ ga_js_surrogate = getSurrogateURI(
+ GA_JS_TESTS[i].url,
+ 'www.google-analytics.com'
+ );
+ assert.ok(ga_js_surrogate, GA_JS_TESTS[i].msg);
+ }
+
+ assert.ok(
+ ga_js_surrogate.startsWith(SURROGATE_PREFIX),
+ "The returned ga.js surrogate is a base64-encoded JavaScript data URI"
+ );
+
+ // test negative match
+ assert.notOk(
+ getSurrogateURI(NYT_URL, window.extractHostFromURL(NYT_URL)),
+ "New York Times script URL should not match any surrogates"
+ );
+
+ // test surrogate suffix token response contents
+ surrogatedb.hostnames[window.extractHostFromURL(NYT_URL)] = [
+ NYT_SCRIPT_PATH
+ ];
+ surrogatedb.surrogates[NYT_SCRIPT_PATH] = NOOP;
+ assert.equal(
+ getSurrogateURI(NYT_URL, window.extractHostFromURL(NYT_URL)),
+ SURROGATE_PREFIX + btoa(NOOP),
+ "New York Times script URL should now match the noop surrogate"
+ );
+
+ // set up test data for wildcard token tests
+ surrogatedb.hostnames['cdn.example.com'] = 'noop';
+ surrogatedb.surrogates.noop = NOOP;
+
+ // test wildcard tokens
+ for (let i = 0; i < 25; i++) {
+ let url = 'http://cdn.example.com/' + _.sample(
+ 'abcdefghijklmnopqrstuvwxyz0123456789'.split(''),
+ _.random(5, 15)
+ ).join('');
+
+ assert.equal(
+ getSurrogateURI(url, window.extractHostFromURL(url)),
+ SURROGATE_PREFIX + btoa(NOOP),
+ "A wildcard token should match all URLs for the hostname: " + url
+ );
+ }
+});
+
+QUnit.test("rateLimit", (assert) => {
+ const INTERVAL = 100,
+ NUM_TESTS = 5;
+
+ let clock = sinon.useFakeTimers(+new Date());
+
+ let callback = sinon.spy(function (password, i) {
+ // check args
+ assert.equal(password, "qwerty",
+ "rateLimit should preserve args");
+ assert.equal(i + 1, callback.callCount,
+ "rateLimit should preserve args and call order");
+
+ // check context
+ assert.ok(this.foo == "bar", "rateLimit should preserve context");
+ });
+
+ let fn = utils.rateLimit(callback, INTERVAL, {foo:"bar"});
+
+ for (let i = 0; i < NUM_TESTS; i++) {
+ fn("qwerty", i);
+ }
+
+ for (let i = 0; i < NUM_TESTS; i++) {
+ // check rate limiting
+ assert.equal(callback.callCount, i + 1,
+ "rateLimit should allow only one call per interval");
+
+ // advance the clock
+ clock.tick(INTERVAL);
+ }
+
+ clock.restore();
+});
+
+// the following cookie parsing tests are derived from
+// https://github.com/jshttp/cookie/blob/81bd3c77db6a8dcb23567de94b3beaef6c03e97a/test/parse.js
+QUnit.test("cookie parsing", function (assert) {
+
+ assert.deepEqual(utils.parseCookie('foo=bar'), { foo: 'bar' },
+ "simple cookie");
+
+ assert.deepEqual(
+ utils.parseCookie('foo=bar;bar=123'),
+ {
+ foo: 'bar',
+ bar: '123'
+ },
+ "simple cookie with two values"
+ );
+
+ assert.deepEqual(
+ utils.parseCookie('FOO = bar; baz = raz'),
+ {
+ FOO: 'bar',
+ baz: 'raz'
+ },
+ "ignore spaces"
+ );
+
+ assert.deepEqual(
+ utils.parseCookie('foo="bar=123456789&name=Magic+Mouse"'),
+ { foo: 'bar=123456789&name=Magic+Mouse' },
+ "escaped value"
+ );
+
+ assert.deepEqual(
+ utils.parseCookie('email=%20%22%2c%3b%2f'),
+ { email: ' ",;/' },
+ "encoded value"
+ );
+
+ assert.deepEqual(
+ utils.parseCookie('foo=%1;bar=bar'),
+ {
+ foo: '%1',
+ bar: 'bar'
+ },
+ "ignore escaping error and return original value"
+ );
+
+ assert.deepEqual(
+ utils.parseCookie('foo=%1;bar=bar;HttpOnly;Secure', { skipNonValues: true }),
+ {
+ foo: '%1',
+ bar: 'bar'
+ },
+ "ignore non values"
+ );
+
+ assert.deepEqual(
+ utils.parseCookie('priority=true; expires=Wed, 29 Jan 2014 17:43:25 GMT; Path=/'),
+ {
+ priority: 'true',
+ expires: 'Wed, 29 Jan 2014 17:43:25 GMT',
+ Path: '/'
+ },
+ "dates"
+ );
+
+ assert.deepEqual(
+ utils.parseCookie('foo=%1;bar=bar;foo=boo', { noOverwrite: true}),
+ {
+ foo: '%1',
+ bar: 'bar'
+ },
+ "duplicate names #1"
+ );
+
+ assert.deepEqual(
+ utils.parseCookie('foo=false;bar=bar;foo=true', { noOverwrite: true}),
+ {
+ foo: 'false',
+ bar: 'bar'
+ },
+ "duplicate names #2"
+ );
+
+ assert.deepEqual(
+ utils.parseCookie('foo=;bar=bar;foo=boo', { noOverwrite: true}),
+ {
+ foo: '',
+ bar: 'bar'
+ },
+ "duplicate names #3"
+ );
+
+ // SameSite attribute
+ let SAMESITE_COOKIE = 'abc=123; path=/; domain=.githack.com; HttpOnly; SameSite=Lax';
+ assert.deepEqual(
+ utils.parseCookie(SAMESITE_COOKIE),
+ {
+ abc: '123',
+ SameSite: 'Lax',
+ path: '/',
+ domain: '.githack.com',
+ HttpOnly: '',
+ },
+ "SameSite is parsed"
+ );
+ assert.deepEqual(
+ utils.parseCookie(SAMESITE_COOKIE, { skipAttributes: true }),
+ { abc: '123' },
+ "SameSite is ignored when ignoring attributes"
+ );
+
+});
+
+QUnit.test("cookie parsing (legacy Firefox add-on)", function (assert) {
+ // raw cookies (input)
+ let optimizelyCookie = 'optimizelyEndUserId=oeu1394241144653r0.538161732205'+
+ '5392; optimizelySegments=%7B%22237061344%22%3A%22none%22%2C%22237321400%'+
+ '22%3A%22ff%22%2C%22237335298%22%3A%22search%22%2C%22237485170%22%3A%22fa'+
+ 'lse%22%7D; optimizelyBuckets=%7B%7D';
+ let googleCookie = 'PREF=ID=d93d4e842d10e12a:U=3838eaea5cd40d37:FF=0:TM=139'+
+ '4232126:LM=1394235924:S=rKP367ac3aAdDzAS; NID=67=VwhHOGQunRmNsm9WwJyK571'+
+ 'OGqb3RtvUmH987K5DXFgKFAxFwafA_5VPF5_bsjhrCoM0BjyQdxyL2b-qs9b-fmYCQ_1Uqjt'+
+ 'qTeidAJBnc2ecjewJia6saHrcJ6yOVVgv';
+ let hackpadCookie = 'acctIds=%5B%22mIqZhIPMu7j%22%2C%221394477194%22%2C%22u'+
+ 'T/ayZECO0g/+hHtQnjrdEZivWA%3D%22%5D; expires=Wed, 01-Jan-3000 08:00:01 G'+
+ 'MT; domain=.hackpad.com; path=/; secure; httponly\nacctIds=%5B%22mIqZhIP'+
+ 'Mu7j%22%2C%221394477194%22%2C%22uT/ayZECO0g/+hHtQnjrdEZivWA%3D%22%5D; ex'+
+ 'pires=Wed, 01-Jan-3000 08:00:00 GMT; domain=.hackpad.com; path=/; secure'+
+ '; httponly\n1ASIE=T; expires=Wed, 01-Jan-3000 08:00:00 GMT; domain=hackp'+
+ 'ad.com; path=/\nPUAS3=3186efa7f8bca99c; expires=Wed, 01-Jan-3000 08:00:0'+
+ '0 GMT; path=/; secure; httponly';
+ let emptyCookie = '';
+ let testCookie = ' notacookiestring; abc=123 ';
+
+ // parsed cookies (expected output)
+ let COOKIES = {};
+ COOKIES[optimizelyCookie] = {
+ optimizelyEndUserId: 'oeu1394241144653r0.5381617322055392',
+ optimizelySegments: '%7B%22237061344%22%3A%22none%22%2C%22237321400%2' +
+ '2%3A%22ff%22%2C%22237335298%22%3A%22search%22%2C%22237485170%22%3A%2' +
+ '2false%22%7D',
+ optimizelyBuckets: '%7B%7D'
+ };
+ COOKIES[emptyCookie] = {};
+ COOKIES[testCookie] = {abc: '123'};
+ COOKIES[googleCookie] = {
+ PREF: 'ID=d93d4e842d10e12a:U=3838eaea5cd40d37:FF=0:TM=1394232126:LM=1'+
+ '394235924:S=rKP367ac3aAdDzAS',
+ NID: '67=VwhHOGQunRmNsm9WwJyK571OGqb3RtvUmH987K5DXFgKFAxFwafA_5VPF5_b'+
+ 'sjhrCoM0BjyQdxyL2b-qs9b-fmYCQ_1UqjtqTeidAJBnc2ecjewJia6saHrcJ6yOVVgv'
+ };
+ COOKIES[hackpadCookie] = {
+ acctIds: '%5B%22mIqZhIPMu7j%22%2C%221394477194%22%2C%22uT/ayZECO0g/+h'+
+ 'HtQnjrdEZivWA%3D%22%5D',
+ PUAS3: '3186efa7f8bca99c',
+ '1ASIE': 'T'
+ };
+
+ // compare actual to expected
+ let test_number = 0;
+ for (let cookieString in COOKIES) {
+ if (COOKIES.hasOwnProperty(cookieString)) {
+ test_number++;
+
+ let expected = COOKIES[cookieString];
+
+ let actual = utils.parseCookie(
+ cookieString, {
+ noDecode: true,
+ skipAttributes: true,
+ skipNonValues: true
+ }
+ );
+
+ assert.deepEqual(actual, expected, "cookie test #" + test_number);
+ }
+ }
+});
+
+// the following cookie parsing tests are derived from
+// https://github.com/yui/yui3/blob/25264e3629b1c07fb779d203c4a25c0879ec862c/src/cookie/tests/cookie-tests.js
+QUnit.test("cookie parsing (YUI3)", function (assert) {
+
+ let cookieString = "a=b";
+ let cookies = utils.parseCookie(cookieString);
+ assert.ok(cookies.hasOwnProperty("a"), "Cookie 'a' is present.");
+ assert.equal(cookies.a, "b", "Cookie 'a' should have value 'b'.");
+
+ cookieString = "12345=b";
+ cookies = utils.parseCookie(cookieString);
+ assert.ok(cookies.hasOwnProperty("12345"), "Cookie '12345' is present.");
+ assert.equal(cookies["12345"], "b", "Cookie '12345' should have value 'b'.");
+
+ cookieString = "a=b; c=d; e=f; g=h";
+ cookies = utils.parseCookie(cookieString);
+ assert.ok(cookies.hasOwnProperty("a"), "Cookie 'a' is present.");
+ assert.ok(cookies.hasOwnProperty("c"), "Cookie 'c' is present.");
+ assert.ok(cookies.hasOwnProperty("e"), "Cookie 'e' is present.");
+ assert.ok(cookies.hasOwnProperty("g"), "Cookie 'g' is present.");
+ assert.equal(cookies.a, "b", "Cookie 'a' should have value 'b'.");
+ assert.equal(cookies.c, "d", "Cookie 'c' should have value 'd'.");
+ assert.equal(cookies.e, "f", "Cookie 'e' should have value 'f'.");
+ assert.equal(cookies.g, "h", "Cookie 'g' should have value 'h'.");
+
+ cookieString = "name=Nicholas%20Zakas; title=front%20end%20engineer";
+ cookies = utils.parseCookie(cookieString);
+ assert.ok(cookies.hasOwnProperty("name"), "Cookie 'name' is present.");
+ assert.ok(cookies.hasOwnProperty("title"), "Cookie 'title' is present.");
+ assert.equal(cookies.name, "Nicholas Zakas", "Cookie 'name' should have value 'Nicholas Zakas'.");
+ assert.equal(cookies.title, "front end engineer", "Cookie 'title' should have value 'front end engineer'.");
+
+ cookieString = "B=2nk0a3t3lj7cr&b=3&s=13; LYC=l_v=2&l_lv=10&l_l=94ddoa70d&l_s=qz54t4qwrsqquyv51w0z4xxwtx31x1t0&l_lid=146p1u6&l_r=4q&l_lc=0_0_0_0_0&l_mpr=50_0_0&l_um=0_0_1_0_0;YMRAD=1215072198*0_0_7318647_1_0_40123839_1; l%5FPD3=840";
+ cookies = utils.parseCookie(cookieString);
+ assert.ok(cookies.hasOwnProperty("B"), "Cookie 'B' is present.");
+ assert.ok(cookies.hasOwnProperty("LYC"), "Cookie 'LYC' is present.");
+ assert.ok(cookies.hasOwnProperty("l_PD3"), "Cookie 'l_PD3' is present.");
+
+ let cookieName = "something[1]";
+ let cookieValue = "123";
+ cookieString = encodeURIComponent(cookieName) + "=" + encodeURIComponent(cookieValue);
+ cookies = utils.parseCookie(cookieString);
+ assert.ok(cookies.hasOwnProperty(cookieName), "Cookie '" + cookieName + "' is present.");
+ assert.equal(cookies[cookieName], cookieValue, "Cookie value for '" + cookieName + "' is " + cookieValue + ".");
+
+ cookieString = "SESSION=27bedbdf3d35252d0db07f34d81dcca6; STATS=OK; SCREEN=1280x1024; undefined; ys-bottom-preview=o%3Aheight%3Dn%253A389";
+ cookies = utils.parseCookie(cookieString);
+ assert.ok(cookies.hasOwnProperty("SCREEN"), "Cookie 'SCREEN' is present.");
+ assert.ok(cookies.hasOwnProperty("STATS"), "Cookie 'STATS' is present.");
+ assert.ok(cookies.hasOwnProperty("SESSION"), "Cookie 'SESSION' is present.");
+ assert.ok(cookies.hasOwnProperty("ys-bottom-preview"), "Cookie 'ys-bottom-preview' is present.");
+ assert.ok(cookies.hasOwnProperty("undefined"), "Cookie 'undefined' is present.");
+
+ // Tests that cookie parsing deals with cookies that contain an invalid
+ // encoding. It shouldn't error, but should treat the cookie as if it
+ // doesn't exist (return null).
+ cookieString = "DetailInfoList=CPN03022194=@|@=CPN03#|#%B4%EB%C3%B5%C7%D8%BC%F6%BF%E5%C0%E5#|#1016026000#|#%BD%C5%C8%E6%B5%BF#|##|#";
+ cookies = utils.parseCookie(cookieString, { skipInvalid: true });
+ assert.equal(cookies.DetailInfoList, null, "Cookie 'DetailInfoList' should not have a value.");
+
+ // Tests that a Boolean cookie, one without an equals sign of value,
+ // is represented as an empty string.
+ cookieString = "info";
+ cookies = utils.parseCookie(cookieString);
+ assert.equal(cookies.info, "", "Cookie 'info' should be an empty string.");
+
+ cookieString = "name=Nicholas%20Zakas; hash=a=b&c=d&e=f&g=h; title=front%20end%20engineer";
+ cookies = utils.parseCookie(cookieString);
+ assert.ok(cookies.hasOwnProperty("name"), "Cookie 'name' is present.");
+ assert.ok(cookies.hasOwnProperty("hash"), "Cookie 'hash' is present.");
+ assert.ok(cookies.hasOwnProperty("title"), "Cookie 'title' is present.");
+ assert.equal(cookies.name, "Nicholas Zakas", "Cookie 'name' should have value 'Nicholas Zakas'.");
+ assert.equal(cookies.hash, "a=b&c=d&e=f&g=h", "Cookie 'hash' should have value 'a=b&c=d&e=f&g=h'.");
+ assert.equal(cookies.title, "front end engineer", "Cookie 'title' should have value 'front end engineer'.");
+
+});
+
+QUnit.test("getHostFromDomainInput", assert => {
+ assert.equal(
+ utils.getHostFromDomainInput("www.spiegel.de"),
+ "www.spiegel.de",
+ "Valid domains are accepted"
+ );
+
+ assert.equal(
+ utils.getHostFromDomainInput("http://www.spiegel.de/"),
+ "www.spiegel.de",
+ "URLs get transformed into domains"
+ );
+
+ assert.equal(
+ utils.getHostFromDomainInput("http://www.spiegel.de"),
+ "www.spiegel.de",
+ "Trailing slashes are not required"
+ );
+
+ assert.equal(
+ utils.getHostFromDomainInput("@"),
+ false,
+ "Valid URIs with empty hosts are rejected."
+ );
+});
+
+// used in pixel tracking heuristic, given a string the estimateMaxEntropy function
+// will return the estimated entropy value from it, based on logic parsing the string's length,
+// and classes of character complication included in the string
+QUnit.test("estimateMaxEntropy", assert => {
+ assert.equal(
+ utils.estimateMaxEntropy("google.com/analytics.google/analytics.google/google.com/analytics.google/analytics.google/google.com/analytics.google/analytics.google/google.com/analytics.google/analytics.google/google.com/analytics.google/analytics.google/google.com/analytics.google/anal"),
+ 257,
+ "returns length of string if it's above 256 (MAX_LS_LEN_FOR_ENTROPY_EST)"
+ );
+
+ assert.equal(
+ utils.estimateMaxEntropy("googlecomanalytics"),
+ utils.estimateMaxEntropy("GOOGLECOMANALYTICS"),
+ "if the same string is all lower case or all upper case, the returned estimated entropy value is the same"
+ );
+
+ assert.notEqual(
+ utils.estimateMaxEntropy('analytics.GOOGLE1234_'),
+ utils.estimateMaxEntropy('ANALYTICS.google1234'),
+ "two nearly identical strings of mixed character classes and different cases will return different values"
+ );
+
+ assert.notEqual(
+ utils.estimateMaxEntropy('google.com/analytics'),
+ utils.estimateMaxEntropy('0191/_-goo~le9x+xzxo'),
+ "strings of the same length but from different character classes will estimate different entropy values"
+ );
+
+ assert.equal(
+ utils.estimateMaxEntropy("google.com/0191/_-google/analytics.fizz?buzz=foobar"),
+ 320.55551316197466,
+ "entropy for complex string of varying character classes is correctly estimated"
+ );
+
+ assert.equal(
+ utils.estimateMaxEntropy("03899029.01_293"),
+ 49.82892142331044,
+ "entropy for string from the common classes of characters is correctly estimated"
+ );
+
+ assert.equal(
+ utils.estimateMaxEntropy("fizzBUZZ012345"),
+ 84,
+ "entropy for string from the case-insensitive class of characters is correctly estimated"
+ );
+
+ assert.equal(
+ utils.estimateMaxEntropy("fizz/buzz+fizzy~buzzy%"),
+ 142.82076811925285,
+ "entropy for string from the case-sensitive class of characters is correctly estimated"
+ );
+
+ assert.equal(
+ utils.estimateMaxEntropy("1280x720") < 32,
+ true,
+ "resolution strings with 'x' char from SEPS class are correctly estimated as low entropy"
+ );
+
+});
+
+})();
diff --git a/src/tests/tests/yellowlist.js b/src/tests/tests/yellowlist.js
new file mode 100644
index 0000000..43fa869
--- /dev/null
+++ b/src/tests/tests/yellowlist.js
@@ -0,0 +1,424 @@
+/* globals badger:false */
+
+(function () {
+
+function get_ylist() {
+ return badger.storage.getStore('cookieblock_list').getItemClones();
+}
+
+let constants = require('constants');
+
+// fake server to simulate XMLHttpRequests
+let server;
+
+QUnit.module("Yellowlist", (hooks) => {
+ hooks.before((/*assert*/) => {
+ server = sinon.fakeServer.create({
+ respondImmediately: true
+ });
+ });
+
+ hooks.after((/*assert*/) => {
+ server.restore();
+ });
+
+ QUnit.test("Updating to a valid list", (assert) => {
+ let done = assert.async();
+ assert.expect(3);
+
+ let ylist = get_ylist();
+ assert.ok(!!Object.keys(ylist).length, "yellowlist is not empty");
+
+ // remove a domain
+ let removed_domain = Object.keys(ylist)[0];
+ delete ylist[removed_domain];
+
+ // add a domain
+ const NEW_YLIST_DOMAIN = "widgets.example.com";
+ ylist[NEW_YLIST_DOMAIN] = true;
+
+ // respond with the modified list
+ server.respondWith("GET", constants.YELLOWLIST_URL,
+ [200, {}, Object.keys(ylist).join("\n")]);
+
+ badger.updateYellowlist(function (err) {
+ assert.notOk(err, "callback status indicates success");
+ assert.deepEqual(get_ylist(), ylist, "list got updated");
+ done();
+ });
+ });
+
+ QUnit.test("Updating receives a blank response", (assert) => {
+ let done = assert.async();
+ assert.expect(3);
+
+ let ylist = get_ylist();
+ assert.ok(!!Object.keys(ylist).length, "yellowlist is not empty");
+
+ // respond with no content
+ server.respondWith("GET", constants.YELLOWLIST_URL,
+ [200, {}, ""]);
+
+ badger.updateYellowlist(function (err) {
+ assert.ok(err, "callback status indicates failure");
+ assert.deepEqual(get_ylist(), ylist, "list did not get updated");
+ done();
+ });
+ });
+
+ QUnit.test("Updating receives an invalid response", (assert) => {
+ let BAD_RESPONSES = [
+ "page not found",
+ "page\nnot\nfound",
+ "pagenotfound",
+ "eff.org\n...\n",
+ "...eff.org...",
+ "<html><body>eff.org</body></html>",
+ ];
+
+ let done = assert.async(BAD_RESPONSES.length);
+ assert.expect(1 + (2 * BAD_RESPONSES.length));
+
+ let ylist = get_ylist();
+ assert.ok(!!Object.keys(ylist).length, "yellowlist is not empty");
+
+ BAD_RESPONSES.forEach(response => {
+ // respond with stuff that may look like the yellowlist but is not
+ server.respondWith("GET", constants.YELLOWLIST_URL,
+ [200, {}, response]);
+
+ badger.updateYellowlist(function (err) {
+ assert.ok(err,
+ "callback status indicates failure for " + JSON.stringify(response));
+ assert.deepEqual(get_ylist(), ylist,
+ "list did not get updated for " + JSON.stringify(response));
+ done();
+ });
+ });
+ });
+
+ QUnit.test("Updating gets a server error", (assert) => {
+ let done = assert.async();
+ assert.expect(1);
+
+ // respond with a 404 error
+ server.respondWith("GET", constants.YELLOWLIST_URL,
+ [404, {}, "page not found"]);
+
+ badger.updateYellowlist(function (err) {
+ assert.ok(err, "callback status indicates failure");
+ done();
+ });
+ });
+
+ QUnit.test("added domains get cookieblocked", (assert) => {
+ const DOMAIN = "example.com";
+
+ let done = assert.async();
+ assert.expect(2);
+
+ // mark domain for blocking
+ badger.storage.setupHeuristicAction(DOMAIN, constants.BLOCK);
+
+ // respond with this domain added
+ let ylist = get_ylist();
+ ylist[DOMAIN] = true;
+ server.respondWith("GET", constants.YELLOWLIST_URL,
+ [200, {}, Object.keys(ylist).join("\n")]);
+
+ // update yellowlist
+ badger.updateYellowlist(function (err) {
+ assert.notOk(err, "callback status indicates success");
+
+ // check that the domain got cookieblocked
+ assert.equal(
+ badger.storage.getAction(DOMAIN),
+ constants.COOKIEBLOCK,
+ "domain is marked for cookieblocking"
+ );
+
+ done();
+ });
+ });
+
+ QUnit.test("Reapplying yellowlist updates", (assert) => {
+ // these are all on the yellowlist
+ let DOMAINS = [
+ // domain, action
+ ["books.google.com", null], // null means do not record
+ ["clients6.google.com", ""],
+ ["storage.googleapis.com", constants.BLOCK],
+ ];
+
+ // set up test data
+ for (let i = 0; i < DOMAINS.length; i++) {
+ let [domain, action] = DOMAINS[i];
+ if (action !== null) {
+ // record the domain with specified action
+ badger.storage.setupHeuristicAction(domain, action);
+
+ // block the base domain
+ badger.storage.setupHeuristicAction(
+ window.getBaseDomain(domain), constants.BLOCK);
+ }
+ }
+
+ // (re)apply yellowlist updates
+ require("migrations").Migrations.reapplyYellowlist(badger);
+
+ // all test domains should be now set to "cookieblock"
+ for (let i = 0; i < DOMAINS.length; i++) {
+ let [domain,] = DOMAINS[i];
+ assert.equal(
+ badger.storage.getBestAction(domain),
+ constants.COOKIEBLOCK,
+ domain + " is cookieblocked"
+ );
+ }
+ });
+
+ QUnit.module("Removing domains", () => {
+ let TESTS = [
+ {
+ name: "Basic scenario",
+ domains: {
+ 'example.com': {
+ yellowlist: true,
+ remove: true,
+ initial: constants.COOKIEBLOCK,
+ expected: constants.BLOCK,
+ expectedBest: constants.BLOCK
+ },
+ }
+ },
+
+ {
+ name: "Parent is on yellowlist",
+ domains: {
+ 'widgets.example.com': {
+ yellowlist: true,
+ initial: constants.COOKIEBLOCK
+ },
+ 'cdn.widgets.example.com': {
+ yellowlist: true,
+ remove: true,
+ initial: constants.COOKIEBLOCK,
+ expected: constants.COOKIEBLOCK,
+ expectedBest: constants.COOKIEBLOCK
+ },
+ }
+ },
+
+ // scenario from https://github.com/EFForg/privacybadger/issues/1474
+ {
+ name: "Parent is on yellowlist and is a PSL TLD (not in action map)",
+ domains: {
+ 'googleapis.com': {
+ yellowlist: true,
+ expected: constants.NO_TRACKING,
+ expectedBest: constants.NO_TRACKING,
+ },
+ 'ajax.googleapis.com': {
+ yellowlist: true,
+ remove: true,
+ initial: constants.COOKIEBLOCK,
+ expected: constants.COOKIEBLOCK,
+ expectedBest: constants.COOKIEBLOCK
+ },
+ }
+ },
+
+ {
+ name: "Child is on yellowlist",
+ domains: {
+ 'widgets.example.com': {
+ yellowlist: true,
+ remove: true,
+ initial: constants.COOKIEBLOCK,
+ expected: constants.BLOCK,
+ expectedBest: constants.BLOCK
+ },
+ 'cdn.widgets.example.com': {
+ yellowlist: true,
+ expected: constants.COOKIEBLOCK,
+ expectedBest: constants.COOKIEBLOCK
+ },
+ }
+ },
+
+ {
+ name: "Removing parent blocks subdomains",
+ domains: {
+ // parent domain is yellowlisted and cookieblocked
+ 'example.com': {
+ yellowlist: true,
+ remove: true,
+ initial: constants.COOKIEBLOCK,
+ expected: constants.BLOCK,
+ expectedBest: constants.BLOCK
+ },
+ // non-yellowlisted subdomain
+ 'cdn1.example.com': {
+ initial: constants.COOKIEBLOCK,
+ expected: constants.BLOCK,
+ expectedBest: constants.BLOCK
+ },
+ // another non-yellowlisted subdomain
+ 'cdn2.example.com': {
+ initial: constants.COOKIEBLOCK,
+ expected: constants.BLOCK,
+ expectedBest: constants.BLOCK
+ },
+ }
+ },
+
+ {
+ name: "Parent is blocked",
+ domains: {
+ 'example.com': {
+ initial: constants.BLOCK,
+ },
+ // removing from yellowlist will get this blocked
+ 'www.example.com': {
+ yellowlist: true,
+ remove: true,
+ initial: constants.COOKIEBLOCK,
+ expected: constants.BLOCK,
+ expectedBest: constants.BLOCK
+ },
+ // removing from yellowlist will get this blocked
+ 's-static.ak.example.com': {
+ yellowlist: true,
+ remove: true,
+ initial: constants.COOKIEBLOCK,
+ expected: constants.BLOCK,
+ expectedBest: constants.BLOCK
+ },
+ // yellowlisted and cookieblocked, should stay the same
+ 'video.example.com': {
+ yellowlist: true,
+ initial: constants.COOKIEBLOCK,
+ expected: constants.COOKIEBLOCK,
+ expectedBest: constants.COOKIEBLOCK
+ },
+ // non-tracking, should stay the same
+ 'ampcid.example.com': {
+ initial: "",
+ expected: constants.NO_TRACKING,
+ expectedBest: constants.BLOCK
+ },
+ }
+ },
+
+ // scenario from https://github.com/EFForg/privacybadger/issues/1474:
+ // using endsWith() and removing "" blocked all domains in action map
+ // that were also on the yellowlist, regardless of their status
+ {
+ name: "Removing blank domain does not block entire yellowlist",
+ domains: {
+ '': {
+ yellowlist: true,
+ remove: true
+ },
+ // on yellowlist and in action map as non-tracking
+ 'avatars0.example.com': {
+ yellowlist: true,
+ initial: "",
+ expected: constants.NO_TRACKING,
+ expectedBest: constants.NO_TRACKING
+ },
+ // on yellowlist and in action map but not yet blocked
+ 'api.example.net': {
+ yellowlist: true,
+ initial: constants.ALLOW,
+ expected: constants.ALLOW,
+ expectedBest: constants.ALLOW
+ }
+ }
+ }
+ ];
+
+ QUnit.test("googleapis.com is still a PSL TLD", (assert) => {
+ assert.notEqual(
+ window.getBaseDomain("ajax.googleapis.com"),
+ "googleapis.com",
+ "PSL yellowlist test depends on googleapis.com remaining a PSL TLD"
+ );
+ });
+
+ TESTS.forEach(test => {
+ QUnit.test(test.name, (assert) => {
+
+ let done = assert.async();
+
+ // to get num. of assertions, tally the expected/expectedBest props,
+ // and add one for the yellowlist update assertion
+ assert.expect(1 + Object.keys(test.domains).reduce((memo, domain) => {
+ let data = test.domains[domain];
+ if (data.hasOwnProperty('expected')) {
+ memo++;
+ }
+ if (data.hasOwnProperty('expectedBest')) {
+ memo++;
+ }
+ return memo;
+ }, 0));
+
+ let ylistStorage = badger.storage.getStore('cookieblock_list');
+
+ // set up cookieblocking
+ for (let domain in test.domains) {
+ let conf = test.domains[domain];
+ if (conf.yellowlist) {
+ ylistStorage.setItem(domain, true);
+ }
+ if (conf.hasOwnProperty("initial")) {
+ badger.storage.setupHeuristicAction(domain, conf.initial);
+ }
+ }
+
+ // update the yellowlist making sure removed domains aren't on it
+ const ylist = ylistStorage.getItemClones();
+ for (let domain in test.domains) {
+ if (test.domains[domain].remove) {
+ delete ylist[domain];
+ }
+ }
+ server.respondWith("GET", constants.YELLOWLIST_URL,
+ [200, {}, Object.keys(ylist).join("\n")]);
+
+ badger.updateYellowlist(err => {
+ assert.notOk(err, "callback status indicates success");
+
+ for (let domain in test.domains) {
+ let expected, data = test.domains[domain];
+
+ if (data.hasOwnProperty('expected')) {
+ expected = data.expected;
+ assert.equal(
+ badger.storage.getAction(domain),
+ expected,
+ `action on ${domain} should be "${expected}"`
+ );
+ }
+
+ if (data.hasOwnProperty('expectedBest')) {
+ expected = data.expectedBest;
+ assert.equal(
+ badger.storage.getBestAction(domain),
+ expected,
+ `best action for ${domain} should be "${expected}"`
+ );
+ }
+ }
+
+ done();
+ });
+
+ });
+ });
+ });
+
+});
+
+}());
diff --git a/tests/requirements.txt b/tests/requirements.txt
new file mode 100644
index 0000000..8a2509d
--- /dev/null
+++ b/tests/requirements.txt
@@ -0,0 +1,3 @@
+selenium
+xvfbwrapper
+pytest
diff --git a/tests/selenium/.flake8 b/tests/selenium/.flake8
new file mode 100644
index 0000000..2a1147a
--- /dev/null
+++ b/tests/selenium/.flake8
@@ -0,0 +1,2 @@
+[flake8]
+ignore = E501, E731
diff --git a/tests/selenium/breakage_test.py b/tests/selenium/breakage_test.py
new file mode 100644
index 0000000..2970610
--- /dev/null
+++ b/tests/selenium/breakage_test.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+import unittest
+import pbtest
+from selenium.webdriver.support.ui import WebDriverWait
+from selenium.webdriver.support import expected_conditions as EC
+
+
+class BreakageTest(pbtest.PBSeleniumTest):
+ """Make sure the extension doesn't break common sites and use cases.
+ e.g. we should be able to load a website, search on Google.
+ TODO: Add tests to simulate most common web use cases:
+ e.g. play Youtube videos, login to popular services, tweet some text,
+ add Reddit comments etc."""
+
+ def test_should_load_eff_org(self):
+ self.load_url("https://www.eff.org")
+ WebDriverWait(self.driver, 10).until(
+ EC.title_contains("Electronic Frontier Foundation"))
+
+ def test_should_search_google(self):
+ self.load_url("https://www.google.com/")
+ qry_el = self.driver.find_element_by_name("q")
+ qry_el.send_keys("EFF") # search term
+ qry_el.submit()
+ WebDriverWait(self.driver, 10).until(EC.title_contains("EFF"))
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/selenium/clobbering_test.py b/tests/selenium/clobbering_test.py
new file mode 100644
index 0000000..724b83b
--- /dev/null
+++ b/tests/selenium/clobbering_test.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+import unittest
+
+import pbtest
+
+
+class ClobberingTest(pbtest.PBSeleniumTest):
+ def test_localstorage_clobbering(self):
+ LOCALSTORAGE_TESTS = [
+ # (test result element ID, expected stored, expected empty)
+ ('get-item', "qwerty", "null"),
+ ('get-property', "asdf", "undefined"),
+ ('get-item-proto', "qwerty", "null"),
+ ('get-item-srcdoc', "qwerty", "null"),
+ ('get-property-srcdoc', "asdf", "undefined"),
+ ('get-item-frames', "qwerty", "null"),
+ ('get-property-frames', "asdf", "undefined"),
+ ]
+ # page loads a frame that writes to and reads from localStorage
+ # TODO remove delays from fixture once race condition (https://crbug.com/478183) is fixed
+ FIXTURE_URL = "https://privacybadger-tests.eff.org/html/clobbering.html"
+ FRAME_DOMAIN = "efforg.github.io"
+
+ # first allow localStorage to be set
+ self.load_url(FIXTURE_URL)
+ self.wait_for_and_switch_to_frame('iframe')
+ for selector, expected, _ in LOCALSTORAGE_TESTS:
+ # wait for each test to run
+ self.wait_for_script(
+ "return document.getElementById('%s')"
+ ".textContent != '...';" % selector,
+ timeout=2,
+ message=(
+ "Timed out waiting for localStorage (%s) to finish ... "
+ "This probably means the fixture "
+ "errored out somewhere." % selector
+ )
+ )
+ self.assertEqual(
+ self.txt_by_css("#" + selector), expected,
+ "localStorage (%s) was not read successfully"
+ "for some reason" % selector
+ )
+
+ # mark the frame domain for cookieblocking
+ self.cookieblock_domain(FRAME_DOMAIN)
+
+ # now rerun and check results for various localStorage access tests
+ self.load_url(FIXTURE_URL)
+ self.wait_for_and_switch_to_frame('iframe')
+ for selector, _, expected in LOCALSTORAGE_TESTS:
+ # wait for each test to run
+ self.wait_for_script(
+ "return document.getElementById('%s')"
+ ".textContent != '...';" % selector,
+ timeout=2,
+ message=(
+ "Timed out waiting for localStorage (%s) to finish ... "
+ "This probably means the fixture "
+ "errored out somewhere." % selector
+ )
+ )
+ self.assertEqual(
+ self.txt_by_css("#" + selector), expected,
+ "localStorage (%s) was read despite cookieblocking" % selector
+ )
+
+ def test_referrer_header(self):
+ FIXTURE_URL = (
+ "https://efforg.github.io/privacybadger-test-fixtures/html/"
+ "referrer.html"
+ )
+ THIRD_PARTY_DOMAIN = "httpbin.org"
+
+ def verify_referrer_header(expected, failure_message):
+ self.load_url(FIXTURE_URL)
+ self.wait_for_script(
+ "return document.getElementById('referrer').textContent != '';")
+ referrer = self.txt_by_css("#referrer")
+ self.assertEqual(referrer[0:8], "Referer=", "Unexpected page output")
+ self.assertEqual(referrer[8:], expected, failure_message)
+
+ # verify base case
+ verify_referrer_header(
+ FIXTURE_URL,
+ "Unexpected default referrer header"
+ )
+
+ # cookieblock the domain fetched by the fixture
+ self.cookieblock_domain(THIRD_PARTY_DOMAIN)
+
+ # recheck what the referrer header looks like now after cookieblocking
+ verify_referrer_header(
+ "https://efforg.github.io/",
+ "Referrer header does not appear to be origin-only"
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/selenium/cookie_test.py b/tests/selenium/cookie_test.py
new file mode 100644
index 0000000..93e70af
--- /dev/null
+++ b/tests/selenium/cookie_test.py
@@ -0,0 +1,163 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+import unittest
+
+import pbtest
+
+from popup_test import get_domain_slider_state
+
+
+class CookieTest(pbtest.PBSeleniumTest):
+ """Basic test to make sure the PB doesn't mess up with the cookies."""
+
+ def assert_pass_opera_cookie_test(self, url, test_name):
+ self.load_url(url)
+ self.assertEqual("PASS", self.txt_by_css("#result"),
+ "Cookie test failed: %s" % test_name)
+
+ def test_should_pass_std_cookie_test(self):
+ self.assert_pass_opera_cookie_test((
+ "https://efforg.github.io/privacybadger-test-fixtures/html/"
+ "first_party_cookie.html"
+ ), "Set 1st party cookie")
+
+ def test_cookie_tracker_detection(self):
+ """Tests basic cookie tracking. The tracking site has no DNT file,
+ and gets blocked by PB.
+
+ Visits three sites, all of which have an iframe that points to a fourth site
+ that reads and writes a cookie. The third party cookie will be picked up by
+ PB after each of the site loads, but no action will be taken. Then the first
+ site will be reloaded, and the UI will show the third party domain as blocked."""
+
+ SITE1_URL = "https://ddrybktjfxh4.cloudfront.net/"
+ SITE2_URL = "https://d3syxqe9po5ji0.cloudfront.net/"
+ SITE3_URL = "https://d3b37ucnz1m2l2.cloudfront.net/"
+
+ THIRD_PARTY_DOMAIN = "efforg.github.io"
+
+ # enable local learning
+ self.load_url(self.options_url)
+ self.wait_for_script("return window.OPTIONS_INITIALIZED")
+ self.find_el_by_css('#local-learning-checkbox').click()
+
+ # remove pre-trained domains
+ self.js(
+ "chrome.extension.getBackgroundPage()."
+ "badger.storage.clearTrackerData();"
+ )
+
+ # load the first site with the third party code that reads and writes a cookie
+ self.load_url(SITE1_URL)
+ self.load_pb_ui(SITE1_URL)
+ # TODO it takes another visit (or a page reload)
+ # TODO to show the domain as not-yet-blocked-but-tracking?
+ #self.assertIn(THIRD_PARTY_DOMAIN, self.notYetBlocked)
+ self.close_window_with_url(SITE1_URL)
+
+ # go to second site
+ self.load_url(SITE2_URL)
+ self.load_pb_ui(SITE2_URL)
+ self.assertIn(THIRD_PARTY_DOMAIN, self.notYetBlocked)
+ self.close_window_with_url(SITE2_URL)
+
+ # go to third site
+ self.load_url(SITE3_URL)
+ self.load_pb_ui(SITE3_URL)
+ self.assertIn(THIRD_PARTY_DOMAIN, self.notYetBlocked)
+ self.close_window_with_url(SITE3_URL)
+
+ # revisiting the first site should cause
+ # the third-party domain to be blocked
+ self.load_url(SITE1_URL)
+ self.load_pb_ui(SITE1_URL)
+ self.assertIn(THIRD_PARTY_DOMAIN, self.blocked)
+
+ def load_pb_ui(self, target_url):
+ """Show the PB popup as a new tab.
+
+ If Selenium would let us just programmatically launch an extension from its icon,
+ we wouldn't need this method. Alas it will not.
+
+ But! We can open a new tab and set the url to the extension's popup html page and
+ test away. That's how most devs test extensions. But**2!! PB's popup code uses
+ the current tab's url to report the current tracker status. And since we changed
+ the current tab's url when we loaded the popup as a tab, the popup loses all the
+ blocker status information from the original tab.
+
+ The workaround is to execute a new convenience function in the popup codebase that
+ looks for a given url in the tabs and, if it finds a match, refreshes the popup
+ with the associated tabid. Then the correct status information will be displayed
+ in the popup."""
+
+ self.open_window()
+ self.load_url(self.popup_url)
+
+ # get the popup populated with status information for the correct url
+ self.switch_to_window_with_url(self.popup_url)
+ self.js("""
+/**
+ * if the query url pattern matches a tab, switch the module's tab object to that tab
+ */
+(function (url) {
+ chrome.tabs.query({url}, function (tabs) {
+ if (!tabs || !tabs.length) {
+ return;
+ }
+ chrome.runtime.sendMessage({
+ type: "getPopupData",
+ tabId: tabs[0].id,
+ tabUrl: tabs[0].url
+ }, (response) => {
+ setPopupData(response);
+ refreshPopup();
+ window.DONE_REFRESHING = true;
+ });
+ });
+}(arguments[0]));""", target_url)
+
+ # wait for popup to be ready
+ self.wait_for_script(
+ "return typeof window.DONE_REFRESHING != 'undefined' &&"
+ "window.POPUP_INITIALIZED &&"
+ "window.SLIDERS_DONE"
+ )
+
+ self.get_tracker_state()
+
+ def get_tracker_state(self):
+ """Parse the UI to group all third party origins into their respective action states."""
+ self.notYetBlocked = {}
+ self.cookieBlocked = {}
+ self.blocked = {}
+
+ self.driver.switch_to.window(self.driver.current_window_handle)
+
+ domain_divs = self.driver.find_elements_by_css_selector(
+ "#blockedResourcesInner > div.clicker[data-origin]")
+ for div in domain_divs:
+ origin = div.get_attribute('data-origin')
+
+ # assert that this origin is never duplicated in the UI
+ self.assertNotIn(origin, self.notYetBlocked)
+ self.assertNotIn(origin, self.cookieBlocked)
+ self.assertNotIn(origin, self.blocked)
+
+ # get slider state for given origin
+ action_type = get_domain_slider_state(self.driver, origin)
+
+ # non-tracking domains are hidden by default
+ # so if we see a slider set to "allow",
+ # it must be in the tracking-but-not-yet-blocked section
+ if action_type == 'allow':
+ self.notYetBlocked[origin] = True
+ elif action_type == 'cookieblock':
+ self.cookieBlocked[origin] = True
+ elif action_type == 'block':
+ self.blocked[origin] = True
+ else:
+ self.fail("what is this?!? %s" % action_type)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/selenium/dnt_test.py b/tests/selenium/dnt_test.py
new file mode 100644
index 0000000..fb3fdf8
--- /dev/null
+++ b/tests/selenium/dnt_test.py
@@ -0,0 +1,324 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+import json
+import unittest
+
+import pbtest
+
+from functools import partial
+
+from selenium.common.exceptions import NoSuchElementException
+
+from pbtest import retry_until
+
+
+class DntTest(pbtest.PBSeleniumTest):
+ """Tests to make sure DNT policy checking works as expected."""
+
+ CHECK_FOR_DNT_POLICY_JS = (
+ "chrome.extension.getBackgroundPage()."
+ "badger.checkForDNTPolicy("
+ " arguments[0],"
+ " r => window.DNT_CHECK_RESULT = r"
+ ");"
+ )
+
+ # TODO switch to non-delayed version
+ # https://gist.github.com/ghostwords/9fc6900566a2f93edd8e4a1e48bbaa28
+ # once race condition (https://crbug.com/478183) is fixed
+ NAVIGATOR_DNT_TEST_URL = (
+ "https://efforg.github.io/privacybadger-test-fixtures/html/"
+ "navigator_donottrack_delayed.html"
+ )
+
+ def get_first_party_headers(self, url):
+ self.load_url(url)
+
+ text = self.driver.find_element_by_tag_name('body').text
+
+ try:
+ headers = json.loads(text)['headers']
+ except ValueError:
+ print("\nFailed to parse JSON from {}".format(repr(text)))
+ return None
+
+ return headers
+
+ def domain_was_recorded(self, domain):
+ return self.js(
+ "return (Object.keys("
+ " chrome.extension.getBackgroundPage()."
+ " badger.storage.action_map.getItemClones()"
+ ").indexOf(arguments[0]) != -1);",
+ domain
+ )
+
+ def domain_was_detected(self, domain):
+ return self.js(
+ "return (Object.keys(chrome.extension.getBackgroundPage().badger.tabData).some(tab_id => {"
+ " let origins = chrome.extension.getBackgroundPage().badger.tabData[tab_id].origins;"
+ " return origins.hasOwnProperty(arguments[0]);"
+ "}));",
+ domain
+ )
+
+ def domain_was_blocked(self, domain):
+ return self.js(
+ "return (Object.keys(chrome.extension.getBackgroundPage().badger.tabData).some(tab_id => {"
+ " let origins = chrome.extension.getBackgroundPage().badger.tabData[tab_id].origins;"
+ " return ("
+ " origins.hasOwnProperty(arguments[0]) &&"
+ " chrome.extension.getBackgroundPage().constants.BLOCKED_ACTIONS.has(origins[arguments[0]])"
+ " );"
+ "}));",
+ domain
+ )
+
+ @pbtest.repeat_if_failed(3)
+ def test_dnt_policy_check_should_happen_for_blocked_domains(self):
+ PAGE_URL = (
+ "https://efforg.github.io/privacybadger-test-fixtures/html/"
+ "dnt.html"
+ )
+ DNT_DOMAIN = "www.eff.org"
+
+ # mark a DNT-compliant domain for blocking
+ self.block_domain(DNT_DOMAIN)
+
+ # visit a page that loads a resource from that DNT-compliant domain
+ self.open_window()
+ self.load_url(PAGE_URL)
+
+ # switch back to Badger's options page
+ self.switch_to_window_with_url(self.options_url)
+
+ # verify that the domain is blocked
+ self.assertTrue(self.domain_was_detected(DNT_DOMAIN),
+ msg="Domain should have been detected.")
+ self.assertTrue(self.domain_was_blocked(DNT_DOMAIN),
+ msg="DNT-compliant resource should have been blocked at first.")
+
+ def reload_and_see_if_unblocked():
+ # switch back to the page with the DNT-compliant resource
+ self.switch_to_window_with_url(PAGE_URL)
+
+ # reload it
+ self.load_url(PAGE_URL)
+
+ # switch back to Badger's options page
+ self.switch_to_window_with_url(self.options_url)
+
+ return (
+ self.domain_was_detected(DNT_DOMAIN) and
+ self.domain_was_blocked(DNT_DOMAIN)
+ )
+
+ # verify that the domain is allowed
+ was_blocked = retry_until(
+ reload_and_see_if_unblocked,
+ tester=lambda x: not x,
+ msg="Waiting a bit for DNT check to complete and retrying ...")
+
+ self.assertFalse(was_blocked,
+ msg="DNT-compliant resource should have gotten unblocked.")
+
+ def test_dnt_policy_check_should_not_set_cookies(self):
+ TEST_DOMAIN = "dnt-test.trackersimulator.org"
+ TEST_URL = "https://{}/".format(TEST_DOMAIN)
+
+ # verify that the domain itself doesn't set cookies
+ self.load_url(TEST_URL)
+ self.assertEqual(len(self.driver.get_cookies()), 0,
+ "No cookies initially")
+
+ # directly visit a DNT policy URL known to set cookies
+ self.load_url(TEST_URL + ".well-known/dnt-policy.txt")
+ self.assertEqual(len(self.driver.get_cookies()), 1,
+ "DNT policy URL set a cookie")
+
+ # verify we got a cookie
+ self.load_url(TEST_URL)
+ self.assertEqual(len(self.driver.get_cookies()), 1,
+ "We still have just one cookie")
+
+ # clear cookies and verify
+ self.driver.delete_all_cookies()
+ self.load_url(TEST_URL)
+ self.assertEqual(len(self.driver.get_cookies()), 0,
+ "No cookies again")
+
+ self.load_url(self.options_url)
+ # perform a DNT policy check
+ self.js(DntTest.CHECK_FOR_DNT_POLICY_JS, TEST_DOMAIN)
+ # wait until checkForDNTPolicy completed
+ self.wait_for_script("return window.DNT_CHECK_RESULT === false")
+
+ # check that we didn't get cookied by the DNT URL
+ self.load_url(TEST_URL)
+ self.assertEqual(len(self.driver.get_cookies()), 0,
+ "Shouldn't have any cookies after the DNT check")
+
+ def test_dnt_policy_check_should_not_send_cookies(self):
+ TEST_DOMAIN = "dnt-request-cookies-test.trackersimulator.org"
+ TEST_URL = "https://{}/".format(TEST_DOMAIN)
+
+ # directly visit a DNT policy URL known to set cookies
+ self.load_url(TEST_URL + ".well-known/dnt-policy.txt")
+ self.assertEqual(len(self.driver.get_cookies()), 1,
+ "DNT policy URL set a cookie")
+
+ # how to check we didn't send a cookie along with request?
+ # the DNT policy URL used by this test returns "cookies=X"
+ # where X is the number of cookies it got
+ # MEGAHACK: make sha1 of "cookies=0" a valid DNT hash
+ self.load_url(self.options_url)
+ self.js(
+ "chrome.extension.getBackgroundPage()."
+ "badger.storage.updateDntHashes({"
+ " 'cookies=0 test policy': 'f63ee614ebd77f8634b92633c6bb809a64b9a3d7'"
+ "});"
+ )
+
+ # perform a DNT policy check
+ self.js(DntTest.CHECK_FOR_DNT_POLICY_JS, TEST_DOMAIN)
+ # wait until checkForDNTPolicy completed
+ self.wait_for_script("return typeof window.DNT_CHECK_RESULT != 'undefined';")
+ # get the result
+ result = self.js("return window.DNT_CHECK_RESULT;")
+ self.assertTrue(result, "No cookies were sent")
+
+ def test_should_not_record_nontracking_domains(self):
+ FIXTURE_URL = (
+ "https://efforg.github.io/privacybadger-test-fixtures/html/"
+ "recording_nontracking_domains.html"
+ )
+ TRACKING_DOMAIN = "dnt-request-cookies-test.trackersimulator.org"
+ NON_TRACKING_DOMAIN = "www.eff.org"
+
+ # clear pre-trained/seed tracker data
+ self.load_url(self.options_url)
+ self.js("chrome.extension.getBackgroundPage().badger.storage.clearTrackerData();")
+
+ # enable local learning
+ self.wait_for_script("return window.OPTIONS_INITIALIZED")
+ self.find_el_by_css('#local-learning-checkbox').click()
+
+ # visit a page containing two third-party resources,
+ # one from a cookie-tracking domain
+ # and one from a non-tracking domain
+ self.load_url(FIXTURE_URL)
+
+ # verify both domains are present on the page
+ try:
+ selector = "iframe[src*='%s']" % TRACKING_DOMAIN
+ self.driver.find_element_by_css_selector(selector)
+ except NoSuchElementException:
+ self.fail("Unable to find the tracking domain on the page")
+ try:
+ selector = "img[src*='%s']" % NON_TRACKING_DOMAIN
+ self.driver.find_element_by_css_selector(selector)
+ except NoSuchElementException:
+ self.fail("Unable to find the non-tracking domain on the page")
+
+ self.load_url(self.options_url)
+
+ # verify that the cookie-tracking domain was recorded
+ self.assertTrue(
+ self.domain_was_recorded(TRACKING_DOMAIN),
+ "Tracking domain should have gotten recorded"
+ )
+
+ # verify that the non-tracking domain was not recorded
+ self.assertFalse(
+ self.domain_was_recorded(NON_TRACKING_DOMAIN),
+ "Non-tracking domain should not have gotten recorded"
+ )
+
+ def test_first_party_dnt_header(self):
+ TEST_URL = "https://httpbin.org/get"
+ headers = retry_until(partial(self.get_first_party_headers, TEST_URL),
+ times=8)
+ self.assertTrue(headers is not None, "It seems we failed to get headers")
+ self.assertIn('Dnt', headers, "DNT header should have been present")
+ self.assertIn('Sec-Gpc', headers, "GPC header should have been present")
+ self.assertEqual(headers['Dnt'], "1",
+ 'DNT header should have been set to "1"')
+ self.assertEqual(headers['Sec-Gpc'], "1",
+ 'Sec-Gpc header should have been set to "1"')
+
+ def test_no_dnt_header_when_disabled_on_site(self):
+ TEST_URL = "https://httpbin.org/get"
+ self.disable_badger_on_site(TEST_URL)
+ headers = retry_until(partial(self.get_first_party_headers, TEST_URL),
+ times=8)
+ self.assertTrue(headers is not None, "It seems we failed to get headers")
+ self.assertNotIn('Dnt', headers, "DNT header should have been missing")
+ self.assertNotIn('Sec-Gpc', headers, "GPC header should have been missing")
+
+ def test_no_dnt_header_when_dnt_disabled(self):
+ TEST_URL = "https://httpbin.org/get"
+
+ self.load_url(self.options_url)
+ self.wait_for_script("return window.OPTIONS_INITIALIZED")
+ self.find_el_by_css('#enable_dnt_checkbox').click()
+
+ headers = retry_until(partial(self.get_first_party_headers, TEST_URL),
+ times=8)
+ self.assertTrue(headers is not None, "It seems we failed to get headers")
+ self.assertNotIn('Dnt', headers, "DNT header should have been missing")
+ self.assertNotIn('Sec-Gpc', headers, "GPC header should have been missing")
+
+ def test_navigator_object(self):
+ self.load_url(DntTest.NAVIGATOR_DNT_TEST_URL, wait_for_body_text=True)
+
+ self.assertEqual(
+ self.driver.find_element_by_tag_name('body').text,
+ 'no tracking (navigator.doNotTrack="1")',
+ "navigator.DoNotTrack should have been set to \"1\""
+ )
+ self.assertEqual(
+ self.js("return navigator.globalPrivacyControl"),
+ "1",
+ "navigator.globalPrivacyControl should have been set to \"1\""
+ )
+
+ def test_navigator_unmodified_when_disabled_on_site(self):
+ self.disable_badger_on_site(DntTest.NAVIGATOR_DNT_TEST_URL)
+
+ self.load_url(DntTest.NAVIGATOR_DNT_TEST_URL, wait_for_body_text=True)
+
+ # navigator.doNotTrack defaults to null in Chrome, "unspecified" in Firefox
+ self.assertEqual(
+ self.driver.find_element_by_tag_name('body').text[0:5],
+ 'unset',
+ "navigator.DoNotTrack should have been left unset"
+ )
+ self.assertEqual(
+ self.js("return navigator.globalPrivacyControl"),
+ None,
+ "navigator.globalPrivacyControl should have been left unset"
+ )
+
+ def test_navigator_unmodified_when_dnt_disabled(self):
+ self.load_url(self.options_url)
+ self.wait_for_script("return window.OPTIONS_INITIALIZED")
+ self.find_el_by_css('#enable_dnt_checkbox').click()
+
+ self.load_url(DntTest.NAVIGATOR_DNT_TEST_URL, wait_for_body_text=True)
+
+ # navigator.doNotTrack defaults to null in Chrome, "unspecified" in Firefox
+ self.assertEqual(
+ self.driver.find_element_by_tag_name('body').text[0:5],
+ 'unset',
+ "navigator.DoNotTrack should have been left unset"
+ )
+ self.assertEqual(
+ self.js("return navigator.globalPrivacyControl"),
+ None,
+ "navigator.globalPrivacyControl should have been left unset"
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/selenium/fingerprinting_test.py b/tests/selenium/fingerprinting_test.py
new file mode 100644
index 0000000..0fadd2b
--- /dev/null
+++ b/tests/selenium/fingerprinting_test.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+import unittest
+
+import pbtest
+
+from functools import partial
+
+from pbtest import retry_until
+
+
+class FingerprintingTest(pbtest.PBSeleniumTest):
+ """Tests to make sure fingerprinting detection works as expected."""
+
+ def detected_fingerprinting(self, domain):
+ return self.js("""let tracker_origin = window.getBaseDomain("{}");
+let tabData = chrome.extension.getBackgroundPage().badger.tabData;
+return (
+ Object.keys(tabData).some(tab_id => {{
+ let fpData = tabData[tab_id].fpData;
+ return fpData &&
+ fpData.hasOwnProperty(tracker_origin) &&
+ fpData[tracker_origin].canvas &&
+ fpData[tracker_origin].canvas.fingerprinting === true;
+ }})
+);""".format(domain))
+
+ def detected_tracking(self, domain, page_url):
+ return self.js("""let tracker_origin = window.getBaseDomain("{}"),
+ site_origin = window.getBaseDomain((new URI("{}")).host),
+ map = chrome.extension.getBackgroundPage().badger.storage.snitch_map.getItemClones();
+
+return (
+ map.hasOwnProperty(tracker_origin) &&
+ map[tracker_origin].indexOf(site_origin) != -1
+);""".format(domain, page_url))
+
+ def get_fillText_source(self):
+ return self.js("""
+ const canvas = document.getElementById("writetome");
+ const ctx = canvas.getContext("2d");
+ return ctx.fillText.toString();
+ """)
+
+ def setUp(self):
+ # enable local learning
+ self.load_url(self.options_url)
+ self.wait_for_script("return window.OPTIONS_INITIALIZED")
+ self.find_el_by_css('#local-learning-checkbox').click()
+
+ # TODO can fail because our content script runs too late: https://crbug.com/478183
+ @pbtest.repeat_if_failed(3)
+ def test_canvas_fingerprinting_detection(self):
+ FIXTURE_URL = (
+ "https://efforg.github.io/privacybadger-test-fixtures/html/"
+ "fingerprinting.html"
+ )
+ FINGERPRINTING_DOMAIN = "cdn.jsdelivr.net"
+
+ # clear pre-trained/seed tracker data
+ self.load_url(self.options_url)
+ self.js("chrome.extension.getBackgroundPage().badger.storage.clearTrackerData();")
+
+ # visit the page
+ self.load_url(FIXTURE_URL)
+
+ # now open a new window (to avoid clearing badger.tabData)
+ # and verify results
+ self.open_window()
+
+ # check that we detected the fingerprinting domain as a tracker
+ self.load_url(self.options_url)
+ # TODO unnecessary retrying?
+ self.assertTrue(
+ retry_until(partial(self.detected_tracking, FINGERPRINTING_DOMAIN, FIXTURE_URL)),
+ "Canvas fingerprinting resource was detected as a tracker.")
+
+ # check that we detected canvas fingerprinting
+ self.assertTrue(
+ self.detected_fingerprinting(FINGERPRINTING_DOMAIN),
+ "Canvas fingerprinting resource was detected as a fingerprinter."
+ )
+
+ # Privacy Badger overrides a few functions on canvas contexts to check for fingerprinting.
+ # In previous versions, it would restore the native function after a single call. Unfortunately,
+ # this would wipe out polyfills that had also overridden the same functions, such as the very
+ # popular "hidpi-canvas-polyfill".
+ def test_canvas_polyfill_clobbering(self):
+ FIXTURE_URL = (
+ "https://efforg.github.io/privacybadger-test-fixtures/html/"
+ "fingerprinting_canvas_hidpi.html"
+ )
+
+ # visit the page
+ self.load_url(FIXTURE_URL)
+
+ # check that we did not restore the native function (should be hipdi polyfill)
+ self.assertNotIn("[native code]", self.get_fillText_source(),
+ "Canvas context fillText is not native version (polyfill has been retained)."
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/selenium/options_test.py b/tests/selenium/options_test.py
new file mode 100644
index 0000000..ce95588
--- /dev/null
+++ b/tests/selenium/options_test.py
@@ -0,0 +1,327 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+import time
+import unittest
+
+import pbtest
+
+from selenium.common.exceptions import (
+ ElementNotInteractableException,
+ ElementNotVisibleException,
+ NoSuchElementException,
+ TimeoutException,
+)
+from selenium.webdriver.common.action_chains import ActionChains
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support import expected_conditions as EC
+from selenium.webdriver.support.ui import WebDriverWait
+
+
+class OptionsTest(pbtest.PBSeleniumTest):
+ """Make sure the options page works correctly."""
+
+ def assert_slider_state(self, origin, action, failure_msg):
+ clicker = self.driver.find_element_by_css_selector(
+ 'div[data-origin="{}"]'.format(origin))
+ self.assertEqual(
+ clicker.get_attribute("class"),
+ "clicker userset",
+ failure_msg
+ )
+
+ switches_div = clicker.find_element_by_css_selector(".switch-container")
+ self.assertEqual(
+ switches_div.get_attribute("class"),
+ "switch-container " + action,
+ failure_msg
+ )
+
+ def find_origin_by_xpath(self, origin):
+ origins = self.driver.find_element_by_id("blockedResourcesInner")
+ return origins.find_element_by_xpath((
+ './/div[@data-origin="{origin}"]'
+ # test that "origin" is one of the classes on the element:
+ # https://stackoverflow.com/a/1390680
+ '//div[contains(concat(" ", normalize-space(@class), " "), " origin ")]'
+ '//span[text()="{origin}"]'
+ ).format(origin=origin))
+
+ def select_domain_list_tab(self):
+ self.find_el_by_css('a[href="#tab-tracking-domains"]').click()
+ try:
+ self.driver.find_element_by_id('show-tracking-domains-checkbox').click()
+ except (ElementNotInteractableException, ElementNotVisibleException):
+ # The list will be loaded directly if we're opening the tab for the second time in this test
+ pass
+
+ def select_manage_data_tab(self):
+ self.find_el_by_css('a[href="#tab-manage-data"]').click()
+
+ def check_tracker_messages(self, error_message, many, none):
+ self.assertEqual(many,
+ self.driver.find_element_by_id("options_domain_list_trackers").is_displayed(), error_message)
+ self.assertEqual(none,
+ self.driver.find_element_by_id("options_domain_list_no_trackers").is_displayed(), error_message)
+
+ def load_options_page(self):
+ self.load_url(self.options_url)
+ self.wait_for_script("return window.OPTIONS_INITIALIZED")
+
+ def clear_seed_data(self):
+ """Clear the seed dataset to make test checks easier"""
+ self.load_options_page()
+ self.js("chrome.extension.getBackgroundPage().badger.storage.clearTrackerData();")
+
+ def add_test_origin(self, origin, action):
+ """Add given origin to backend storage."""
+ self.load_options_page()
+ self.js((
+ "chrome.extension.getBackgroundPage()"
+ ".badger.storage.setupHeuristicAction('{}', '{}');"
+ ).format(origin, action))
+
+ def user_overwrite(self, origin, action):
+ # Get the slider that corresponds to this radio button
+ origin_div = self.find_el_by_css('div[data-origin="' + origin + '"]')
+ slider = origin_div.find_element_by_css_selector('.switch-toggle')
+
+ # Click on the correct place over the slider to block this origin
+ click_action = ActionChains(self.driver)
+ if action == 'block':
+ # Top left (+2px)
+ click_action.move_to_element_with_offset(slider, 2, 2)
+ if action == 'cookieblock':
+ # Top middle
+ click_action.move_to_element_with_offset(slider, slider.size['width']/2, 2)
+ if action == 'allow':
+ # Top right
+ click_action.move_to_element_with_offset(slider, slider.size['width']-2, 2)
+ click_action.click()
+ click_action.perform()
+
+ def test_page_title(self):
+ self.load_options_page()
+ localized_title = self.js('return chrome.i18n.getMessage("options_title")')
+ try:
+ WebDriverWait(self.driver, 3).until(
+ EC.title_contains(localized_title))
+ except TimeoutException:
+ self.fail("Unexpected title for the Options page. Got (%s),"
+ " expected (%s)"
+ % (self.driver.title, localized_title))
+
+ def test_added_origin_display(self):
+ """Ensure origin and tracker message is displayed when there is 1 origin."""
+ self.clear_seed_data()
+
+ self.add_test_origin("pbtest.org", "block")
+
+ self.load_options_page()
+ self.select_domain_list_tab()
+
+ error_message = "The 'multiple tracker' message should be displayed after adding an origin"
+ self.check_tracker_messages(error_message, many=True, none=False)
+
+ try:
+ self.find_origin_by_xpath("pbtest.org")
+ except NoSuchElementException:
+ self.fail("Tracking origin is not displayed")
+
+ def test_added_multiple_origins_display(self):
+ """Ensure origin and tracker count is displayed when there are multiple origins."""
+ self.clear_seed_data()
+
+ self.add_test_origin("pbtest.org", "block")
+ self.add_test_origin("pbtest1.org", "block")
+
+ self.load_options_page()
+ self.select_domain_list_tab()
+
+ error_message = "The 'multiple tracker' message should be displayed after adding 2 origins"
+ self.check_tracker_messages(error_message, many=True, none=False)
+
+ # check tracker count
+ self.assertEqual(
+ self.driver.find_element_by_id("options_domain_list_trackers").text,
+ "Privacy Badger has decided to block 2 potential tracking domains so far",
+ "Origin tracker count should be 2 after adding origin"
+ )
+
+ # Check those origins are displayed.
+ try:
+ self.find_origin_by_xpath("pbtest.org")
+ self.find_origin_by_xpath("pbtest1.org")
+ except NoSuchElementException:
+ self.fail("Tracking origin is not displayed")
+
+ def test_removed_origin_display(self):
+ """Ensure origin is removed properly."""
+ self.clear_seed_data()
+ self.add_test_origin("pbtest.org", "block")
+
+ self.load_options_page()
+ self.select_domain_list_tab()
+
+ # Remove displayed origin.
+ remove_origin_element = self.find_el_by_xpath(
+ './/div[@data-origin="pbtest.org"]'
+ '//a[@class="removeOrigin"]')
+ remove_origin_element.click()
+
+ # Make sure the alert is present. Otherwise we get intermittent errors.
+ WebDriverWait(self.driver, 3).until(EC.alert_is_present())
+ self.driver.switch_to.alert.accept()
+
+ # Check that only the 'no trackers' message is displayed.
+ try:
+ WebDriverWait(self.driver, 5).until(
+ EC.visibility_of_element_located((By.ID, "options_domain_list_no_trackers")))
+ except TimeoutException:
+ self.fail("There should be a 'no trackers' message after deleting origin")
+
+ error_message = "Only the 'no trackers' message should be displayed before adding an origin"
+ self.assertFalse(
+ self.driver.find_element_by_id(
+ "options_domain_list_trackers").is_displayed(), error_message)
+
+ # Check that no origins are displayed.
+ try:
+ origins = self.driver.find_element_by_id("blockedResourcesInner")
+ except NoSuchElementException:
+ origins = None
+ error_message = "Origin should not be displayed after removal"
+ self.assertIsNone(origins, error_message)
+
+ def test_reset_data(self):
+ self.load_options_page()
+ self.select_domain_list_tab()
+
+ # make sure the default tracker list includes many trackers
+ error_message = "By default, the tracker list should contain many trackers"
+ self.check_tracker_messages(error_message, many=True, none=False)
+
+ # get the number of trackers in the seed data
+ default_summary_text = self.driver.find_element_by_id("options_domain_list_trackers").text
+
+ # Click on the "remove all data" button to empty the tracker lists, and
+ # click "OK" in the popup that ensues
+ self.select_manage_data_tab()
+ self.driver.find_element_by_id('removeAllData').click()
+ self.driver.switch_to.alert.accept()
+ time.sleep(1) # wait for page to reload
+
+ # now make sure the tracker list is empty
+ self.select_domain_list_tab()
+ error_message = "No trackers should be displayed after removing all data"
+ self.check_tracker_messages(error_message, many=False, none=True)
+
+ # add new blocked domains
+ self.add_test_origin("pbtest.org", "block")
+ self.add_test_origin("pbtest1.org", "block")
+
+ # reload the options page
+ self.load_options_page()
+ self.select_domain_list_tab()
+
+ # make sure only two trackers are displayed now
+ self.assertEqual(
+ self.driver.find_element_by_id("options_domain_list_trackers").text,
+ "Privacy Badger has decided to block 2 potential tracking domains so far",
+ "Origin tracker count should be 2 after clearing and adding origins"
+ )
+
+ # click the "reset data" button to restore seed data and get rid of the
+ # domains we learned
+ self.select_manage_data_tab()
+ self.driver.find_element_by_id('resetData').click()
+ self.driver.switch_to.alert.accept()
+ time.sleep(1)
+
+ # make sure the same number of trackers are displayed as by default
+ self.select_domain_list_tab()
+ error_message = "After resetting data, tracker count should return to default"
+ self.assertEqual(self.driver.find_element_by_id("options_domain_list_trackers").text,
+ default_summary_text, error_message)
+
+ def tracking_user_overwrite(self, original_action, overwrite_action):
+ """Ensure preferences are persisted when a user overwrites pb's default behaviour for an origin."""
+ self.clear_seed_data()
+ self.add_test_origin("pbtest.org", original_action)
+
+ self.load_options_page()
+ self.wait_for_script("return window.OPTIONS_INITIALIZED")
+ # enable learning to reveal the show-not-yet-blocked checkbox
+ self.find_el_by_css('#local-learning-checkbox').click()
+ self.select_domain_list_tab()
+ self.find_el_by_css('#tracking-domains-show-not-yet-blocked').click()
+ # wait for sliders to finish rendering
+ self.wait_for_script("return window.SLIDERS_DONE")
+
+ # Change user preferences
+ self.user_overwrite("pbtest.org", overwrite_action)
+
+ # Re-open the tab
+ self.load_options_page()
+ self.select_domain_list_tab()
+ self.find_el_by_css('#tracking-domains-show-not-yet-blocked').click()
+ # wait for sliders to finish rendering
+ self.wait_for_script("return window.SLIDERS_DONE")
+
+ # Check the user preferences for the origins are still displayed
+ failure_msg = (
+ "Origin should be displayed as {} after user overwrite of "
+ "PB's decision to {}".format(overwrite_action, original_action)
+ )
+ self.assert_slider_state("pbtest.org", overwrite_action, failure_msg)
+
+ def test_tracking_user_overwrite_allowed_block(self):
+ self.tracking_user_overwrite('allow', 'block')
+
+ def test_tracking_user_overwrite_allowed_cookieblock(self):
+ self.tracking_user_overwrite('allow', 'cookieblock')
+
+ def test_tracking_user_overwrite_cookieblocked_allow(self):
+ self.tracking_user_overwrite('cookieblock', 'allow')
+
+ def test_tracking_user_overwrite_cookieblocked_block(self):
+ self.tracking_user_overwrite('cookieblock', 'block')
+
+ def test_tracking_user_overwrite_blocked_allow(self):
+ self.tracking_user_overwrite('block', 'allow')
+
+ def test_tracking_user_overwrite_blocked_cookieblock(self):
+ self.tracking_user_overwrite('block', 'cookieblock')
+
+ # early-warning check for the open_in_tab attribute of options_ui
+ # https://github.com/EFForg/privacybadger/pull/1775#pullrequestreview-76940251
+ def test_options_ui_open_in_tab(self):
+ # open options page manually, keeping the new user intro page
+ self.open_window()
+ self.load_options_page()
+
+ # switch to new user intro page
+ self.switch_to_window_with_url(self.first_run_url)
+
+ # save open windows
+ handles_before = set(self.driver.window_handles)
+
+ # open options page using dedicated chrome API
+ self.js("chrome.runtime.openOptionsPage();")
+
+ # if we switched to the previously manually opened options page, all good
+ # if we haven't, this must mean options_ui's open_in_tab no longer works
+ new_handles = set(self.driver.window_handles).difference(handles_before)
+ num_newly_opened_windows = len(new_handles)
+
+ if num_newly_opened_windows:
+ self.driver.switch_to.window(new_handles.pop())
+
+ self.assertEqual(num_newly_opened_windows, 0,
+ "Expected to switch to existing options page, "
+ "opened a new page ({}) instead: {}".format(
+ self.driver.title, self.driver.current_url))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/selenium/pbtest.py b/tests/selenium/pbtest.py
new file mode 100644
index 0000000..b502b4b
--- /dev/null
+++ b/tests/selenium/pbtest.py
@@ -0,0 +1,498 @@
+# -*- coding: UTF-8 -*-
+
+import json
+import os
+import subprocess
+import tempfile
+import time
+import unittest
+
+from contextlib import contextmanager
+from functools import wraps
+from shutil import copytree
+
+from selenium import webdriver
+from selenium.common.exceptions import (
+ NoSuchWindowException,
+ TimeoutException,
+ WebDriverException,
+)
+from selenium.webdriver.chrome.options import Options as ChromeOptions
+from selenium.webdriver.firefox.options import Options as FirefoxOptions
+from selenium.webdriver.support.ui import WebDriverWait
+from selenium.webdriver.support import expected_conditions as EC
+from selenium.webdriver.common.by import By
+
+try:
+ from xvfbwrapper import Xvfb
+except ImportError:
+ print("\n\nxvfbwrapper Python package import failed")
+ print("headless mode (ENABLE_XVFB=1) is not supported")
+
+
+SEL_DEFAULT_WAIT_TIMEOUT = 30
+
+BROWSER_TYPES = ['chrome', 'firefox']
+BROWSER_NAMES = ['google-chrome', 'google-chrome-stable', 'google-chrome-beta', 'firefox']
+
+parse_stdout = lambda res: res.strip().decode('utf-8')
+
+run_shell_command = lambda command: parse_stdout(subprocess.check_output(command))
+
+GIT_ROOT = run_shell_command(['git', 'rev-parse', '--show-toplevel'])
+
+
+class WindowNotFoundException(Exception):
+ pass
+
+
+def unix_which(command, silent=False):
+ try:
+ return run_shell_command(['which', command])
+ except subprocess.CalledProcessError as e:
+ if silent:
+ return None
+ raise e
+
+
+def get_browser_type(string):
+ for t in BROWSER_TYPES:
+ if t in string.lower():
+ return t
+ raise ValueError("couldn't get browser type from %s" % string)
+
+
+def get_browser_name(string):
+ if ('/' in string) or ('\\' in string): # it's a path
+ return os.path.basename(string)
+
+ # it's a browser type
+ for bn in BROWSER_NAMES:
+ if string in bn and unix_which(bn, silent=True):
+ return os.path.basename(unix_which(bn))
+ raise ValueError('Could not get browser name from %s' % string)
+
+
+class Shim:
+ _browser_msg = '''BROWSER should be one of:
+* /path/to/a/browser
+* a browser executable name so we can find the browser with "which $BROWSER"
+* something from BROWSER_TYPES
+'''
+ __doc__ = 'Chooses the correct driver and extension_url based on the BROWSER environment\nvariable. ' + _browser_msg
+
+ def __init__(self):
+ print("\n\nConfiguring the test run ...")
+
+ browser = os.environ.get('BROWSER')
+
+ # get browser_path and browser_type first
+ if browser is None:
+ raise ValueError("The BROWSER environment variable is not set. " + self._browser_msg)
+
+ if ("/" in browser) or ("\\" in browser): # path to a browser binary
+ self.browser_path = browser
+ self.browser_type = get_browser_type(self.browser_path)
+ elif unix_which(browser, silent=True): # executable browser name like 'google-chrome-stable'
+ self.browser_path = unix_which(browser)
+ self.browser_type = get_browser_type(browser)
+ elif get_browser_type(browser): # browser type like 'firefox' or 'chrome'
+ bname = get_browser_name(browser)
+ self.browser_path = unix_which(bname)
+ self.browser_type = browser
+ else:
+ raise ValueError("could not infer BROWSER from %s" % browser)
+
+ self.extension_path = os.path.join(GIT_ROOT, 'src')
+
+ if self.browser_type == 'chrome':
+ # this extension ID and the "key" property in manifest.json
+ # must both be derived from the same private key
+ self.info = {
+ 'extension_id': 'mcgekeccgjgcmhnhbabplanchdogjcnh'
+ }
+ self.manager = self.chrome_manager
+ self.base_url = 'chrome-extension://%s/' % self.info['extension_id']
+
+ # make extension ID constant across runs
+ self.fix_chrome_extension_id()
+
+ elif self.browser_type == 'firefox':
+ self.info = {
+ 'extension_id': 'jid1-MnnxcxisBPnSXQ@jetpack',
+ 'uuid': 'd56a5b99-51b6-4e83-ab23-796216679614'
+ }
+ self.manager = self.firefox_manager
+ self.base_url = 'moz-extension://%s/' % self.info['uuid']
+
+ print('\nUsing browser path: %s\nwith browser type: %s\nand extension path: %s\n' % (
+ self.browser_path, self.browser_type, self.extension_path))
+
+ def fix_chrome_extension_id(self):
+ # create temp directory
+ self.tmp_dir = tempfile.TemporaryDirectory()
+ new_extension_path = os.path.join(self.tmp_dir.name, "src")
+
+ # copy extension sources there
+ copytree(self.extension_path, new_extension_path)
+
+ # update manifest.json
+ manifest_path = os.path.join(new_extension_path, "manifest.json")
+ with open(manifest_path, "r") as f:
+ manifest = json.load(f)
+ # this key and the extension ID must both be derived from the same private key
+ manifest['key'] = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArMdgFkGsm7nOBr/9qkx8XEcmYSu1VkIXXK94oXLz1VKGB0o2MN+mXL/Dsllgkh61LZgK/gVuFFk89e/d6Vlsp9IpKLANuHgyS98FKx1+3sUoMujue+hyxulEGxXXJKXhk0kGxWdE0IDOamFYpF7Yk0K8Myd/JW1U2XOoOqJRZ7HR6is1W6iO/4IIL2/j3MUioVqu5ClT78+fE/Fn9b/DfzdX7RxMNza9UTiY+JCtkRTmm4ci4wtU1lxHuVmWiaS45xLbHphQr3fpemDlyTmaVoE59qG5SZZzvl6rwDah06dH01YGSzUF1ezM2IvY9ee1nMSHEadQRQ2sNduNZWC9gwIDAQAB" # noqa:E501 pylint:disable=line-too-long
+ with open(manifest_path, "w") as f:
+ json.dump(manifest, f)
+
+ # update self.extension_path
+ self.extension_path = new_extension_path
+
+ @property
+ def wants_xvfb(self):
+ if self.on_travis or bool(int(os.environ.get('ENABLE_XVFB', 0))):
+ try:
+ Xvfb
+ except NameError:
+ print("\nHeadless mode not supported: install xvfbwrapper first")
+ return False
+ return True
+ return False
+
+ @property
+ def on_travis(self):
+ if "TRAVIS" in os.environ:
+ return True
+ return False
+
+ @contextmanager
+ def chrome_manager(self):
+ opts = ChromeOptions()
+ if self.on_travis: # github.com/travis-ci/travis-ci/issues/938
+ opts.add_argument("--no-sandbox")
+ opts.add_argument("--load-extension=" + self.extension_path)
+ opts.binary_location = self.browser_path
+ opts.add_experimental_option("prefs", {"profile.block_third_party_cookies": False})
+
+ # TODO not yet in Firefox (w/o hacks anyway):
+ # https://github.com/mozilla/geckodriver/issues/284#issuecomment-456073771
+ opts.set_capability("loggingPrefs", {'browser': 'ALL'})
+
+ for i in range(5):
+ try:
+ driver = webdriver.Chrome(options=opts)
+ except WebDriverException as e:
+ if i == 0: print("")
+ print("Chrome WebDriver initialization failed:")
+ print(str(e) + "Retrying ...")
+ else:
+ break
+
+ try:
+ yield driver
+ finally:
+ driver.quit()
+
+ @contextmanager
+ def firefox_manager(self):
+ ffp = webdriver.FirefoxProfile()
+ # make extension ID constant across runs
+ ffp.set_preference('extensions.webextensions.uuids', '{"%s": "%s"}' %
+ (self.info['extension_id'], self.info['uuid']))
+
+ for i in range(5):
+ try:
+ opts = FirefoxOptions()
+ # to produce a trace-level geckodriver.log,
+ # remove the service_log_path argument to Firefox()
+ # and uncomment the line below
+ #opts.log.level = "trace"
+ driver = webdriver.Firefox(
+ firefox_profile=ffp,
+ firefox_binary=self.browser_path,
+ options=opts,
+ service_log_path=os.path.devnull)
+ except WebDriverException as e:
+ if i == 0: print("")
+ print("Firefox WebDriver initialization failed:")
+ print(str(e) + "Retrying ...")
+ else:
+ break
+
+ driver.install_addon(self.extension_path, temporary=True)
+
+ try:
+ yield driver
+ finally:
+ driver.quit()
+
+
+shim = Shim() # create the browser shim
+
+
+def if_firefox(wrapper):
+ '''
+ A test decorator that applies the function `wrapper` to the test if the
+ browser is firefox. Ex:
+
+ @if_firefox(unittest.skip("broken on ff"))
+ def test_stuff(self):
+ ...
+ '''
+ def test_catcher(test):
+ if shim.browser_type == 'firefox':
+ return wraps(test)(wrapper)(test)
+ return test
+
+ return test_catcher
+
+
+def retry_until(fun, tester=None, times=5, msg="Waiting a bit and retrying ..."):
+ """
+ Execute function `fun` until either its return is truthy
+ (or if `tester` is set, until the result of calling `tester` with `fun`'s return is truthy),
+ or it gets executed X times, where X = `times` + 1.
+ """
+ for i in range(times):
+ result = fun()
+
+ if tester is not None:
+ if tester(result):
+ break
+ elif result:
+ break
+
+ if i == 0:
+ print("")
+ print(msg)
+
+ time.sleep(2 ** i)
+
+ return result
+
+
+attempts = {} # used to count test retries
+def repeat_if_failed(ntimes): # noqa
+ '''
+ A decorator that retries the test if it fails `ntimes`. The TestCase must
+ be used on a subclass of unittest.TestCase. NB: this just registers function
+ to be retried. The try/except logic is in PBSeleniumTest.run.
+ '''
+ def test_catcher(test):
+ attempts[test.__name__] = ntimes
+
+ @wraps(test)
+ def caught(*args, **kwargs):
+ return test(*args, **kwargs)
+ return caught
+ return test_catcher
+
+
+class PBSeleniumTest(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ cls.manager = shim.manager
+ cls.base_url = shim.base_url
+ cls.wants_xvfb = shim.wants_xvfb
+ if cls.wants_xvfb:
+ cls.vdisplay = Xvfb(width=1280, height=720)
+ cls.vdisplay.start()
+
+ # setting DBUS_SESSION_BUS_ADDRESS to nonsense prevents frequent
+ # hangs of chromedriver (possibly due to crbug.com/309093)
+ os.environ["DBUS_SESSION_BUS_ADDRESS"] = "/dev/null"
+ cls.proj_root = GIT_ROOT
+
+ @classmethod
+ def tearDownClass(cls):
+ if cls.wants_xvfb:
+ cls.vdisplay.stop()
+
+ def init(self, driver):
+ self.driver = driver
+ self.js = self.driver.execute_script
+ self.bg_url = self.base_url + "_generated_background_page.html"
+ self.options_url = self.base_url + "skin/options.html"
+ self.popup_url = self.base_url + "skin/popup.html"
+ self.first_run_url = self.base_url + "skin/firstRun.html"
+ self.test_url = self.base_url + "tests/index.html"
+
+ def run(self, result=None):
+ nretries = attempts.get(result.name, 1)
+ for i in range(nretries):
+ try:
+ with self.manager() as driver:
+ self.init(driver)
+
+ # wait for Badger's storage, listeners, ...
+ self.load_url(self.options_url)
+ self.wait_for_script(
+ "return chrome.extension.getBackgroundPage()."
+ "badger.INITIALIZED"
+ )
+
+ driver.close()
+ if driver.window_handles:
+ driver.switch_to.window(driver.window_handles[0])
+
+ super(PBSeleniumTest, self).run(result)
+
+ # retry test magic
+ if result.name in attempts and result._excinfo: # pylint:disable=protected-access
+ raise Exception(result._excinfo.pop()) # pylint:disable=protected-access
+
+ break
+
+ except Exception:
+ if i == nretries - 1:
+ raise
+
+ wait_secs = 2 ** i
+ print('\nRetrying {} after {} seconds ...'.format(
+ result, wait_secs))
+ time.sleep(wait_secs)
+ continue
+
+ def open_window(self):
+ if self.driver.current_url.startswith("moz-extension://"):
+ # work around https://bugzilla.mozilla.org/show_bug.cgi?id=1491443
+ self.wait_for_script("return typeof chrome != 'undefined' && chrome && chrome.extension")
+ self.js(
+ "delete window.__new_window_created;"
+ "chrome.windows.create({}, function () {"
+ "window.__new_window_created = true;"
+ "});"
+ )
+ self.wait_for_script("return window.__new_window_created")
+ else:
+ self.js('window.open()')
+
+ self.driver.switch_to.window(self.driver.window_handles[-1])
+
+ def load_url(self, url, wait_for_body_text=False, retries=5):
+ """Load a URL and wait before returning."""
+ for i in range(retries):
+ try:
+ self.driver.get(url)
+ break
+ except TimeoutException as e:
+ if i < retries - 1:
+ time.sleep(2 ** i)
+ continue
+ raise e
+ # work around geckodriver/marionette/Firefox timeout handling,
+ # for example: https://travis-ci.org/EFForg/privacybadger/jobs/389429089
+ except WebDriverException as e:
+ if str(e).startswith("Reached error page") and i < retries - 1:
+ time.sleep(2 ** i)
+ continue
+ raise e
+ self.driver.switch_to.window(self.driver.current_window_handle)
+
+ if wait_for_body_text:
+ retry_until(
+ lambda: self.driver.find_element_by_tag_name('body').text,
+ msg="Waiting for document.body.textContent to get populated ..."
+ )
+
+ def txt_by_css(self, css_selector, timeout=SEL_DEFAULT_WAIT_TIMEOUT):
+ """Find an element by CSS selector and return its text."""
+ return self.find_el_by_css(
+ css_selector, visible_only=False, timeout=timeout).text
+
+ def find_el_by_css(self, css_selector, visible_only=True, timeout=SEL_DEFAULT_WAIT_TIMEOUT):
+ condition = (
+ EC.visibility_of_element_located if visible_only
+ else EC.presence_of_element_located
+ )
+ return WebDriverWait(self.driver, timeout).until(
+ condition((By.CSS_SELECTOR, css_selector)))
+
+ def find_el_by_xpath(self, xpath, timeout=SEL_DEFAULT_WAIT_TIMEOUT):
+ return WebDriverWait(self.driver, timeout).until(
+ EC.visibility_of_element_located((By.XPATH, xpath)))
+
+ def wait_for_script(
+ self,
+ script,
+ *script_args,
+ timeout=SEL_DEFAULT_WAIT_TIMEOUT,
+ message="Timed out waiting for execute_script to eval to True"
+ ):
+ """Variant of self.js that executes script continuously until it
+ returns True."""
+ return WebDriverWait(self.driver, timeout).until(
+ lambda driver: driver.execute_script(script, *script_args),
+ message
+ )
+
+ def wait_for_text(self, selector, text, timeout=SEL_DEFAULT_WAIT_TIMEOUT):
+ return WebDriverWait(self.driver, timeout).until(
+ EC.text_to_be_present_in_element(
+ (By.CSS_SELECTOR, selector), text))
+
+ def wait_for_and_switch_to_frame(self, selector, timeout=SEL_DEFAULT_WAIT_TIMEOUT):
+ return WebDriverWait(self.driver, timeout).until(
+ EC.frame_to_be_available_and_switch_to_it(
+ (By.CSS_SELECTOR, selector)))
+
+ def switch_to_window_with_url(self, url, max_tries=5):
+ """Point the driver to the first window that matches this url."""
+
+ for _ in range(max_tries):
+ for w in self.driver.window_handles:
+ try:
+ self.driver.switch_to.window(w)
+ if self.driver.current_url != url:
+ continue
+ except NoSuchWindowException:
+ pass
+ else:
+ return
+
+ time.sleep(1)
+
+ raise WindowNotFoundException("Failed to find window for " + url)
+
+
+ def close_window_with_url(self, url, max_tries=5):
+ self.switch_to_window_with_url(url, max_tries)
+
+ if len(self.driver.window_handles) == 1:
+ # open another window to avoid implicit session deletion
+ self.open_window()
+ self.switch_to_window_with_url(url, max_tries)
+
+ self.driver.close()
+ self.driver.switch_to.window(self.driver.window_handles[0])
+
+ def block_domain(self, domain):
+ self.load_url(self.options_url)
+ self.js((
+ "(function (domain) {"
+ " let bg = chrome.extension.getBackgroundPage();"
+ " let base_domain = window.getBaseDomain(domain);"
+ " bg.badger.heuristicBlocking.blocklistOrigin(domain, base_domain);"
+ "}(arguments[0]));"
+ ), domain)
+
+ def cookieblock_domain(self, domain):
+ self.load_url(self.options_url)
+ self.js((
+ "(function (domain) {"
+ " let bg = chrome.extension.getBackgroundPage();"
+ " bg.badger.storage.setupHeuristicAction(domain, bg.constants.COOKIEBLOCK);"
+ "}(arguments[0]));"
+ ), domain)
+
+ def disable_badger_on_site(self, url):
+ self.load_url(self.options_url)
+ self.wait_for_script("return window.OPTIONS_INITIALIZED")
+ self.find_el_by_css('a[href="#tab-allowlist"]').click()
+ self.driver.find_element_by_id('new-disabled-site-input').send_keys(url)
+ self.driver.find_element_by_css_selector('#add-disabled-site').click()
+
+ @property
+ def logs(self):
+ # TODO not yet in Firefox
+ return [log.get('message') for log in self.driver.get_log('browser')]
diff --git a/tests/selenium/pbtest_org_test.py b/tests/selenium/pbtest_org_test.py
new file mode 100644
index 0000000..df381d9
--- /dev/null
+++ b/tests/selenium/pbtest_org_test.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+import pbtest
+import unittest
+
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support.ui import WebDriverWait
+from selenium.webdriver.support import expected_conditions as EC
+
+# where to run the acceptance tests
+PBTEST_ORG_URL = "https://pbtest.org/tracker"
+
+# the id of the element where test results are reported
+PBTEST_ORG_TEST_RESULTS_TABLE_ID = "results"
+
+# unicode characters we look in the results to tell if a test passed or failed
+PASS = u'Pass'
+FAIL = u'Fail'
+
+
+class PBTestDotOrgTest(pbtest.PBSeleniumTest):
+ """Run the pbtest.org website acceptance tests. Loads the pbtest.org test
+ suite and assert that none of the tests failed or are 'undefined'."""
+
+ @unittest.skip("Until we understand and fix the intermittent pbtest.org failures.")
+ #@pbtest.repeat_if_failed(5) # TODO doesn't work with unittest.skip above
+ def test_should_pass_pbtest_org_suite(self):
+ driver = self.driver
+ driver.delete_all_cookies()
+ results = {'passed': [], 'failed': [], 'undefined': []}
+ self.load_url(PBTEST_ORG_URL)
+ WebDriverWait(driver, 100).until(
+ EC.presence_of_element_located((
+ By.XPATH,
+ "//*[@id='buttons'][contains(@style, 'display: block')]")))
+ for el in driver.find_elements_by_class_name('complimentary_text'):
+ if not el.is_displayed():
+ continue
+
+ test_text = el.find_element_by_xpath('../..').text
+ if PASS in el.text:
+ results['passed'].append(test_text)
+ elif FAIL in el.text:
+ results['failed'].append(test_text)
+ elif u'undefined' in el.text:
+ results['undefined'].append(test_text)
+ else:
+ raise ValueError("Malformed test result")
+
+ # now we have all the completed test results.
+ # print a summary
+ print("\npbtest_org test results: %d passed, %d failed, %d undefined" %
+ (len(results['passed']), len(results['failed']),
+ len(results['undefined'])))
+ failed_tests = ([t for t in results['failed']] +
+ [t for t in results['undefined']])
+
+ firefox_failures = [u'Does Privacy Badger Honor the Cookie Block List \u2717 Fail']
+ # ignore this failure on firefox
+ if pbtest.shim.browser_type == 'firefox' and failed_tests == firefox_failures:
+ return
+
+ fail_msg = "%d tests failed:\n * %s" % (
+ len(failed_tests),
+ "\n * ".join(failed_tests).replace(u'\u2717', 'x'),
+ )
+ self.assertTrue(len(failed_tests) == 0, msg=fail_msg)
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/selenium/popup_test.py b/tests/selenium/popup_test.py
new file mode 100644
index 0000000..e11701c
--- /dev/null
+++ b/tests/selenium/popup_test.py
@@ -0,0 +1,361 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+import time
+import unittest
+
+import pbtest
+
+from selenium.common.exceptions import TimeoutException
+from selenium.webdriver.common.by import By
+from selenium.webdriver.support import expected_conditions
+from selenium.webdriver.support.ui import WebDriverWait
+
+
+def get_domain_slider_state(driver, domain):
+ label = driver.find_element_by_css_selector(
+ 'input[name="{}"][checked]'.format(domain))
+ return label.get_attribute('value')
+
+
+class PopupTest(pbtest.PBSeleniumTest):
+ """Make sure the popup works correctly."""
+
+ def clear_seed_data(self):
+ self.load_url(self.options_url)
+ self.js("chrome.extension.getBackgroundPage().badger.storage.clearTrackerData();")
+
+ def wait_for_page_to_start_loading(self, url, timeout=20):
+ """Wait until the title element is present. Use it to work around
+ Firefox not updating self.driver.current_url fast enough."""
+ try:
+ WebDriverWait(self.driver, timeout).until(
+ expected_conditions.presence_of_element_located(
+ (By.CSS_SELECTOR, "title")))
+ except TimeoutException:
+ # TODO debug info
+ print("\n")
+ print("driver.current_url=" + self.driver.current_url)
+ print()
+ print(self.driver.page_source[:5000])
+ print("...\n")
+
+ self.fail("Timed out waiting for %s to start loading" % url)
+
+ def open_popup(self, show_nag=False, origins=None):
+ """Open popup and optionally close overlay."""
+
+ DUMMY_PAGE_URL = "https://efforg.github.io/privacybadger-test-fixtures/"
+
+ # hack to get tabData populated for the popup's tab
+ # to get the popup shown for regular pages
+ # as opposed to special (no-tabData) browser pages
+ self.open_window()
+ self.load_url(DUMMY_PAGE_URL)
+
+ self.open_window()
+ self.load_url(self.popup_url)
+ self.wait_for_script("return window.POPUP_INITIALIZED")
+
+ # override tab ID (to get regular page popup instead of
+ # special browser page popup),
+ # optionally set the domains the popup should report,
+ # optionally ask for the new user welcome page reminder
+ popup_js = (
+ "(function (origins, show_nag, DUMMY_PAGE_URL) {"
+ "chrome.tabs.query({ url: DUMMY_PAGE_URL }, (tabs) => {"
+ " chrome.runtime.sendMessage({"
+ " type: 'getPopupData',"
+ " tabId: tabs[0].id"
+ " }, (response) => {"
+ " response.seenComic = !show_nag;"
+ " response.origins = origins;"
+ " setPopupData(response);"
+ " refreshPopup();"
+ " showNagMaybe();"
+ " window.DONE_REFRESHING = true;"
+ " });"
+ "});"
+ "}(arguments[0], arguments[1], arguments[2]));"
+ )
+ self.js(popup_js, origins if origins else {}, show_nag, DUMMY_PAGE_URL)
+ # wait until the async getTab function is done
+ self.wait_for_script(
+ "return typeof window.DONE_REFRESHING != 'undefined'",
+ timeout=5,
+ message="Timed out waiting for getTab() to complete."
+ )
+
+ # wait for any sliders to finish rendering
+ self.wait_for_script("return window.SLIDERS_DONE")
+
+ def get_enable_button(self):
+ """Get enable button on popup."""
+ return self.driver.find_element_by_id("activate_site_btn")
+
+ def get_disable_button(self):
+ """Get disable button on popup."""
+ return self.driver.find_element_by_id("deactivate_site_btn")
+
+ def test_welcome_page_reminder_overlay(self):
+ """Ensure overlay links to new user welcome page."""
+
+ # first close the welcome page if already open
+ try:
+ self.close_window_with_url(self.first_run_url, max_tries=1)
+ except pbtest.WindowNotFoundException:
+ pass
+
+ self.open_popup(show_nag=True)
+ self.driver.find_element_by_id("intro-reminder-btn").click()
+
+ # Look for first run page and return if found.
+ self.switch_to_window_with_url(self.first_run_url)
+
+ def test_help_button(self):
+ """Ensure FAQ website is opened when help button is clicked."""
+
+ FAQ_URL = "https://privacybadger.org/#faq"
+
+ try:
+ self.switch_to_window_with_url(FAQ_URL, max_tries=1)
+ except pbtest.WindowNotFoundException:
+ pass
+ else:
+ self.fail("FAQ should not already be open")
+
+ self.open_popup()
+ self.driver.find_element_by_id("help").click()
+
+ self.switch_to_window_with_url(FAQ_URL)
+
+ def test_options_button(self):
+ """Ensure options page is opened when button is clicked."""
+ self.open_popup()
+ self.driver.find_element_by_id("options").click()
+ self.switch_to_window_with_url(self.options_url)
+
+ @pbtest.repeat_if_failed(5)
+ def test_trackers_link(self):
+ """Ensure trackers link opens EFF website."""
+
+ EFF_URL = "https://privacybadger.org/#What-is-a-third-party-tracker"
+
+ self.open_popup()
+
+ # Get all possible tracker links (none, one, multiple)
+ trackers_links = self.driver.find_elements_by_css_selector("#pbInstructions a")
+ if not trackers_links:
+ self.fail("Unable to find trackers link on popup")
+
+ # Get the one that's displayed on the page that this test is using
+ for link in trackers_links:
+ if link.is_displayed():
+ trackers_link = link
+
+ trackers_link.click()
+
+ # Make sure EFF website not opened in same window.
+ if self.driver.current_url != self.popup_url:
+ self.fail("EFF website not opened in new window")
+
+ # Look for EFF website and return if found.
+ self.switch_to_window_with_url(EFF_URL)
+
+ self.wait_for_page_to_start_loading(EFF_URL)
+
+ self.assertEqual(self.driver.current_url, EFF_URL,
+ "EFF website should open after clicking trackers link on popup")
+
+ # Verify EFF website contains the linked anchor element.
+ faq_selector = 'a[href="{}"]'.format(EFF_URL[EFF_URL.index('#'):])
+ try:
+ WebDriverWait(self.driver, pbtest.SEL_DEFAULT_WAIT_TIMEOUT).until(
+ expected_conditions.presence_of_element_located(
+ (By.CSS_SELECTOR, faq_selector)))
+ except TimeoutException:
+ self.fail("Unable to find expected element ({}) on EFF website".format(faq_selector))
+
+ def test_toggling_sliders(self):
+ """Ensure toggling sliders is persisted."""
+ self.clear_seed_data()
+
+ # enable learning to show not-yet-blocked domains in popup
+ self.wait_for_script("return window.OPTIONS_INITIALIZED")
+ self.find_el_by_css('#local-learning-checkbox').click()
+
+ DOMAIN = "example.com"
+ DOMAIN_ID = DOMAIN.replace(".", "-")
+
+ self.open_popup(origins={DOMAIN:"allow"})
+
+ # click input with JavaScript to avoid "Element ... is not clickable" /
+ # "Other element would receive the click" Selenium limitation
+ self.js("$('#block-{}').click()".format(DOMAIN_ID))
+
+ # retrieve the new action
+ self.load_url(self.options_url)
+ self.wait_for_script("return window.OPTIONS_INITIALIZED")
+ self.find_el_by_css('a[href="#tab-tracking-domains"]').click()
+ new_action = get_domain_slider_state(self.driver, DOMAIN)
+
+ self.assertEqual(new_action, "block",
+ "The domain should be blocked on options page.")
+
+ # test toggling some more
+ self.open_popup(origins={DOMAIN:"user_block"})
+
+ self.assertTrue(
+ self.driver.find_element_by_id("block-" + DOMAIN_ID).is_selected(),
+ "The domain should be shown as blocked in popup."
+ )
+
+ # change to "cookieblock"
+ self.js("$('#cookieblock-{}').click()".format(DOMAIN_ID))
+ # change again to "block"
+ self.js("$('#block-{}').click()".format(DOMAIN_ID))
+
+ # retrieve the new action
+ self.load_url(self.options_url)
+ self.wait_for_script("return window.OPTIONS_INITIALIZED")
+ self.find_el_by_css('a[href="#tab-tracking-domains"]').click()
+ new_action = get_domain_slider_state(self.driver, DOMAIN)
+
+ self.assertEqual(new_action, "block",
+ "The domain should still be blocked on options page.")
+
+ def test_reverting_control(self):
+ """Test restoring control of a domain to Privacy Badger."""
+ self.clear_seed_data()
+
+ DOMAIN = "example.com"
+ DOMAIN_ID = DOMAIN.replace(".", "-")
+
+ # record the domain as cookieblocked by Badger
+ self.cookieblock_domain(DOMAIN)
+
+ self.open_popup(origins={DOMAIN:"cookieblock"})
+
+ # set the domain to user control
+ # click input with JavaScript to avoid "Element ... is not clickable" /
+ # "Other element would receive the click" Selenium limitation
+ self.js("$('#block-{}').click()".format(DOMAIN_ID))
+
+ # restore control to Badger
+ self.driver.find_element_by_css_selector(
+ 'div[data-origin="{}"] a.honeybadgerPowered'.format(DOMAIN)
+ ).click()
+
+ # get back to a valid window handle as the window just got closed
+ self.driver.switch_to.window(self.driver.window_handles[0])
+
+ # verify the domain is no longer user controlled
+ self.load_url(self.options_url)
+ self.wait_for_script("return window.OPTIONS_INITIALIZED")
+ self.find_el_by_css('a[href="#tab-tracking-domains"]').click()
+
+ # assert the action is not what we manually clicked
+ action = get_domain_slider_state(self.driver, DOMAIN)
+ self.assertEqual(action, "cookieblock",
+ "Domain's action should have been restored.")
+
+ # assert the undo arrow is not displayed
+ self.driver.find_element_by_css_selector('a[href="#tab-tracking-domains"]').click()
+ self.driver.find_element_by_id('show-tracking-domains-checkbox').click()
+ self.assertFalse(
+ self.driver.find_element_by_css_selector(
+ 'div[data-origin="{}"] a.honeybadgerPowered'.format(DOMAIN)
+ ).is_displayed(),
+ "Undo arrow should not be displayed."
+ )
+
+ def test_disable_enable_buttons(self):
+ """Ensure disable/enable buttons change popup state."""
+
+ DISPLAYED_ERROR = " should not be displayed on popup"
+ NOT_DISPLAYED_ERROR = " should be displayed on popup"
+
+ self.open_popup()
+
+ self.get_disable_button().click()
+
+ # get back to a valid window handle as the window just got closed
+ self.driver.switch_to.window(self.driver.window_handles[0])
+ self.open_popup()
+
+ # Check that popup state changed after disabling.
+ disable_button = self.get_disable_button()
+ self.assertFalse(disable_button.is_displayed(),
+ "Disable button" + DISPLAYED_ERROR)
+ enable_button = self.get_enable_button()
+ self.assertTrue(enable_button.is_displayed(),
+ "Enable button" + NOT_DISPLAYED_ERROR)
+
+ enable_button.click()
+
+ self.driver.switch_to.window(self.driver.window_handles[0])
+ self.open_popup()
+
+ # Check that popup state changed after re-enabling.
+ disable_button = self.get_disable_button()
+ self.assertTrue(disable_button.is_displayed(),
+ "Disable button" + NOT_DISPLAYED_ERROR)
+ enable_button = self.get_enable_button()
+ self.assertFalse(enable_button.is_displayed(),
+ "Enable button" + DISPLAYED_ERROR)
+
+ def test_error_button(self):
+ """Ensure error button opens report error overlay."""
+ self.open_popup()
+
+ # TODO: selenium firefox has a bug where is_displayed() is always True
+ # for these elements. But we should use is_displayed when this is fixed.
+ #overlay_input = self.driver.find_element_by_id("error_input")
+ #self.assertTrue(overlay_input.is_displayed(), "User input" + error_message)
+
+ # assert error reporting menu is not open
+ self.assertTrue(len(self.driver.find_elements_by_class_name('active')) == 0,
+ 'error reporting should not be open')
+
+ # Click error button to open overlay for reporting sites.
+ error_button = self.driver.find_element_by_id("error")
+ error_button.click()
+ time.sleep(1)
+
+ # check error is open
+ self.assertTrue(len(self.driver.find_elements_by_class_name('active')) == 1,
+ 'error reporting should be open')
+
+ overlay_close = self.driver.find_element_by_id("report_close")
+ overlay_close.click()
+ time.sleep(1)
+ self.assertTrue(len(self.driver.find_elements_by_class_name('active')) == 0,
+ 'error reporting should be closed again')
+
+ @pbtest.repeat_if_failed(5)
+ def test_donate_button(self):
+ """Ensure donate button opens EFF website."""
+
+ EFF_URL = "https://supporters.eff.org/donate/support-privacy-badger"
+
+ self.open_popup()
+
+ donate_button = self.driver.find_element_by_id("donate")
+
+ donate_button.click()
+
+ # Make sure EFF website not opened in same window.
+ if self.driver.current_url != self.popup_url:
+ self.fail("EFF website not opened in new window")
+
+ # Look for EFF website and return if found.
+ self.switch_to_window_with_url(EFF_URL)
+
+ self.wait_for_page_to_start_loading(EFF_URL)
+
+ self.assertEqual(self.driver.current_url, EFF_URL,
+ "EFF website should open after clicking donate button on popup")
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/selenium/qunit_test.py b/tests/selenium/qunit_test.py
new file mode 100644
index 0000000..f6afa4a
--- /dev/null
+++ b/tests/selenium/qunit_test.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+import unittest
+
+import pbtest
+
+from selenium.common.exceptions import TimeoutException
+
+
+class QUnitTest(pbtest.PBSeleniumTest):
+
+ def test_run_qunit_tests(self):
+ self.load_url(self.test_url)
+
+ try:
+ # this text appears when tests finish running
+ self.txt_by_css(
+ "#qunit-testresult-display > span.total",
+ timeout=120
+ )
+ except TimeoutException as exc:
+ self.fail("Cannot find the results of QUnit tests %s" % exc)
+
+ print("\nQUnit summary:")
+ print(self.txt_by_css("#qunit-testresult-display"))
+
+ failed_test_els = self.driver.find_elements_by_css_selector(
+ ".fail .test-name"
+ )
+ fail_msg = "The following QUnit tests failed:\n * {}".format(
+ "\n * ".join([el.text for el in failed_test_els])
+ )
+
+ self.assertTrue(len(failed_test_els) == 0, msg=fail_msg)
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/selenium/service_workers_test.py b/tests/selenium/service_workers_test.py
new file mode 100644
index 0000000..00da1f5
--- /dev/null
+++ b/tests/selenium/service_workers_test.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+import unittest
+
+import pbtest
+
+
+class ServiceWorkersTest(pbtest.PBSeleniumTest):
+ """Verifies interaction with sites that use Service Worker caches"""
+
+ def get_tab_data_domains(self):
+ domains = self.js(
+ "let tabData = chrome.extension.getBackgroundPage().badger.tabData;"
+ "return (Object.keys(tabData).map(tab_id => {"
+ " return tabData[tab_id].frames[0].host;"
+ "}));"
+ )
+ return domains
+
+ def test_returning_to_sw_cached_page(self):
+ FIXTURE_URL = (
+ "https://efforg.github.io/privacybadger-test-fixtures/html/"
+ "service_workers.html"
+ )
+
+ # visit the Service Worker page to activate the worker
+ self.load_url(FIXTURE_URL)
+
+ # Service Workers are off by default in Firefox 60 ESR
+ if not self.js("return 'serviceWorker' in navigator;"):
+ self.skipTest("Service Workers are disabled")
+
+ # wait for the worker to initialize its cache
+ self.wait_for_script("return window.WORKER_READY;")
+
+ # visit a different site (doesn't matter what it is,
+ # just needs to be an http site with a different domain)
+ self.load_url("https://dnt-test.trackersimulator.org/")
+
+ # return to the SW page
+ self.driver.back()
+
+ # now open a new window (to avoid clearing badger.tabData)
+ # and verify results
+ self.open_window()
+ self.load_url(self.options_url)
+ domains = self.get_tab_data_domains()
+ self.assertIn("efforg.github.io", domains,
+ "SW page URL was not correctly attributed")
+ self.assertEqual(len(domains), 1,
+ "tabData contains an unexpected number of entries")
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/selenium/storage_test.py b/tests/selenium/storage_test.py
new file mode 100644
index 0000000..d8e6c64
--- /dev/null
+++ b/tests/selenium/storage_test.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+import unittest
+import pbtest
+from time import sleep
+
+# time to wait for loading privacy policy from eff.org
+POLICY_DOWNLOAD_TIMEOUT = 20
+PB_POLICY_HASH_LEN = 40 # https://www.eff.org/files/dnt-policies.json
+
+
+class StorageTest(pbtest.PBSeleniumTest):
+ """Privacy Badger storage initialization tests."""
+
+ def check_policy_download(self):
+ timeout = POLICY_DOWNLOAD_TIMEOUT
+ dnt_hashes_not_empty = (
+ "return ("
+ "chrome.extension.getBackgroundPage()."
+ "badger.storage.getStore('dnt_hashes') != {}"
+ ")"
+ )
+ # give updatePrivacyPolicyHashes() some time to download the policy hash
+ while (timeout > 0 and not self.js(dnt_hashes_not_empty)):
+ sleep(1)
+ timeout -= 1
+
+ # make sure we didn't time out
+ self.assertGreater(timeout, 0, "Timed out waiting for DNT hashes")
+ # now check the downloaded policy hash
+ get_dnt_hashes = (
+ "return ("
+ "chrome.extension.getBackgroundPage()."
+ "badger.storage.getStore('dnt_hashes')."
+ "getItemClones()"
+ ")"
+ )
+ policy_hashes = self.js(get_dnt_hashes)
+ for policy_hash in policy_hashes.keys():
+ self.assertEqual(PB_POLICY_HASH_LEN, len(policy_hash))
+
+ def test_should_init_storage_entries(self):
+ self.load_url(self.options_url)
+
+ self.check_policy_download()
+ self.assertEqual(
+ self.js(
+ "return chrome.extension.getBackgroundPage()."
+ "constants.YELLOWLIST_URL"
+ ),
+ "https://www.eff.org/files/cookieblocklist_new.txt"
+ )
+
+ disabled_sites = self.js(
+ "return chrome.extension.getBackgroundPage()."
+ "badger.getSettings().getItem('disabledSites')"
+ )
+ self.assertFalse(
+ len(disabled_sites),
+ "Shouldn't have any disabledSites after installation"
+ )
+
+ self.assertTrue(self.js(
+ "return chrome.extension.getBackgroundPage()."
+ "badger.getSettings().getItem('checkForDNTPolicy')"
+ ), "Should start with DNT policy enabled")
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/selenium/super_cookie_test.py b/tests/selenium/super_cookie_test.py
new file mode 100644
index 0000000..de6c5dd
--- /dev/null
+++ b/tests/selenium/super_cookie_test.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+import unittest
+
+import pbtest
+
+from functools import partial
+
+
+class SupercookieTest(pbtest.PBSeleniumTest):
+ """Make sure we detect potential supercookies. """
+
+ def get_snitch_map_for(self, origin):
+ self.open_window() # don't replace the test page to allow for retrying
+ self.load_url(self.options_url)
+
+ CHECK_SNITCH_MAP_JS = (
+ "return chrome.extension.getBackgroundPage()"
+ ".badger.storage.getStore('snitch_map')"
+ ".getItemClones()[arguments[0]];"
+ )
+
+ return self.js(CHECK_SNITCH_MAP_JS, origin)
+
+ def setUp(self):
+ # enable local learning
+ self.load_url(self.options_url)
+ self.wait_for_script("return window.OPTIONS_INITIALIZED")
+ self.find_el_by_css('#local-learning-checkbox').click()
+
+ # test for https://github.com/EFForg/privacybadger/pull/1403
+ # TODO remove retrying entire test after we revert 879a74f807999a2135e4d48bb5efbd8a1beff4f8
+ @pbtest.repeat_if_failed(5)
+ def test_async_tracking_attribution_bug(self):
+ FIRST_PARTY_BASE = "eff.org"
+ THIRD_PARTY_BASE = "efforg.github.io"
+
+ self.load_url((
+ "https://privacybadger-tests.{}/html/"
+ "async_localstorage_attribution_bug.html"
+ ).format(FIRST_PARTY_BASE))
+
+ # the above HTML page reloads itself furiously to trigger our bug
+ # we need to wait for it to finish reloading
+ self.wait_for_script("return window.DONE_RELOADING === true")
+
+ # the HTML page contains:
+
+ # an iframe from THIRD_PARTY_BASE that writes to localStorage
+ self.assertEqual(
+ pbtest.retry_until(partial(self.get_snitch_map_for, THIRD_PARTY_BASE)),
+ [FIRST_PARTY_BASE],
+ msg="Frame sets localStorage but was not flagged as a tracker.")
+
+ # and an image from raw.githubusercontent.com that doesn't do any tracking
+ self.assertFalse(self.get_snitch_map_for("raw.githubusercontent.com"),
+ msg="Image is not a tracker but was flagged as one.")
+
+
+ def test_should_detect_ls_of_third_party_frame(self):
+ FIRST_PARTY_BASE = "eff.org"
+ THIRD_PARTY_BASE = "efforg.github.io"
+
+ self.assertFalse(self.get_snitch_map_for(THIRD_PARTY_BASE))
+
+ self.load_url((
+ "https://privacybadger-tests.{}/html/"
+ "localstorage.html"
+ ).format(FIRST_PARTY_BASE))
+
+ # TODO We get some intermittent failures for this test.
+ # It seems we sometimes miss the setting of localStorage items
+ # because the script runs after we already checked what's in localStorage.
+ # We can work around this race condition by reloading the page.
+ self.driver.refresh()
+
+ self.assertEqual(
+ pbtest.retry_until(partial(self.get_snitch_map_for, THIRD_PARTY_BASE), times=3),
+ [FIRST_PARTY_BASE]
+ )
+
+ def test_should_not_detect_low_entropy_ls_of_third_party_frame(self):
+ FIRST_PARTY_BASE = "eff.org"
+ THIRD_PARTY_BASE = "efforg.github.io"
+ self.assertFalse(self.get_snitch_map_for(THIRD_PARTY_BASE))
+ self.load_url((
+ "https://privacybadger-tests.{}/html/"
+ "localstorage_low_entropy.html"
+ ).format(FIRST_PARTY_BASE))
+ self.driver.refresh()
+ self.assertFalse(self.get_snitch_map_for(THIRD_PARTY_BASE))
+
+ def test_should_not_detect_first_party_ls(self):
+ BASE_DOMAIN = "efforg.github.io"
+ self.load_url((
+ "https://{}/privacybadger-test-fixtures/html/"
+ "localstorage/set_ls.html"
+ ).format(BASE_DOMAIN))
+ self.driver.refresh()
+ self.assertFalse(self.get_snitch_map_for(BASE_DOMAIN))
+
+ def test_should_not_detect_ls_of_third_party_script(self):
+ FIRST_PARTY_BASE = "eff.org"
+ THIRD_PARTY_BASE = "efforg.github.io"
+
+ # a third-party script included by the top page (not a 3rd party frame)
+ self.load_url((
+ "https://privacybadger-tests.{}/html/"
+ "localstorage_from_third_party_script.html"
+ ).format(FIRST_PARTY_BASE))
+
+ self.driver.refresh()
+
+ self.assertFalse(self.get_snitch_map_for(FIRST_PARTY_BASE))
+ self.assertFalse(self.get_snitch_map_for(THIRD_PARTY_BASE))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/selenium/surrogates_test.py b/tests/selenium/surrogates_test.py
new file mode 100644
index 0000000..eff654f
--- /dev/null
+++ b/tests/selenium/surrogates_test.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+import unittest
+import pbtest
+
+from selenium.common.exceptions import TimeoutException
+
+from pbtest import retry_until
+
+
+class SurrogatesTest(pbtest.PBSeleniumTest):
+ """Integration tests to verify surrogate script functionality."""
+
+ FIXTURE_URL = (
+ "https://efforg.github.io/privacybadger-test-fixtures/html/"
+ "ga_surrogate.html"
+ )
+
+ def load_ga_js_test_page(self, timeout=12):
+ self.load_url(SurrogatesTest.FIXTURE_URL)
+ try:
+ self.wait_for_and_switch_to_frame('iframe', timeout=timeout)
+ self.wait_for_text('h1', "It worked!", timeout=timeout)
+ return True
+ except TimeoutException:
+ return False
+
+ def test_ga_js_surrogate(self):
+ # clear pre-trained/seed tracker data
+ self.load_url(self.options_url)
+ self.js("chrome.extension.getBackgroundPage().badger.storage.clearTrackerData();")
+
+ # verify the surrogate is present
+ self.load_url(self.options_url)
+ self.assertTrue(self.js(
+ "let bg = chrome.extension.getBackgroundPage();"
+ "const sdb = bg.require('surrogatedb');"
+ "return sdb.hostnames.hasOwnProperty('www.google-analytics.com');"
+ ), "Surrogate is missing but should be present.")
+
+ # verify site loads
+ self.assertTrue(
+ self.load_ga_js_test_page(),
+ "Page failed to load even before we did anything."
+ )
+
+ # block ga.js (known to break the site)
+ self.block_domain("www.google-analytics.com")
+ # back up the surrogate definition before removing it
+ ga_backup = self.js(
+ "let bg = chrome.extension.getBackgroundPage();"
+ "const sdb = bg.require('surrogatedb');"
+ "return JSON.stringify(sdb.hostnames['www.google-analytics.com']);"
+ )
+ # now remove the surrogate
+ self.js(
+ "let bg = chrome.extension.getBackgroundPage();"
+ "const sdb = bg.require('surrogatedb');"
+ "delete sdb.hostnames['www.google-analytics.com'];"
+ )
+
+ # wait until this happens
+ self.wait_for_script(
+ "let bg = chrome.extension.getBackgroundPage();"
+ "const sdb = bg.require('surrogatedb');"
+ "return !sdb.hostnames.hasOwnProperty('www.google-analytics.com');",
+ timeout=5,
+ message="Timed out waiting for surrogate to get removed."
+ )
+
+ # verify site breaks
+ self.assertFalse(
+ self.load_ga_js_test_page(),
+ "Page loaded successfully when it should have failed."
+ )
+
+ # re-enable surrogate
+ self.open_window()
+ self.load_url(self.options_url)
+ self.js(
+ "let bg = chrome.extension.getBackgroundPage();"
+ "const sdb = bg.require('surrogatedb');"
+ "sdb.hostnames['www.google-analytics.com'] = JSON.parse('%s');" % ga_backup
+ )
+
+ # wait until this happens
+ self.wait_for_script(
+ "let bg = chrome.extension.getBackgroundPage();"
+ "const sdb = bg.require('surrogatedb');"
+ "return sdb.hostnames.hasOwnProperty('www.google-analytics.com');",
+ timeout=5,
+ message="Timed out waiting for surrogate to get readded."
+ )
+
+ # verify site loads again
+ self.assertTrue(
+ retry_until(self.load_ga_js_test_page),
+ "Page failed to load after surrogation."
+ )
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/selenium/website_testbed/first-party.html b/tests/selenium/website_testbed/first-party.html
new file mode 100644
index 0000000..13713c4
--- /dev/null
+++ b/tests/selenium/website_testbed/first-party.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <script src=first-party.js></script>
+ </head>
+ <body>
+ <p>Welcome to the cookie tracker test site. I'm creating a localcookie for this domain.
+ </p>
+ <button id="newwindowbutton" class="button" onClick="window.open();">Click this button to open a new window</button>
+ <p>I feel like iframing in a third party website:</p>
+ <iframe src="https://efforg.github.io/privacybadger-test-fixtures/html/cookie_frame.html" width="200" height="200">where's my iframe?</iframe>
+ </body>
+</html>
diff --git a/tests/selenium/website_testbed/first-party.js b/tests/selenium/website_testbed/first-party.js
new file mode 100644
index 0000000..7fdebe8
--- /dev/null
+++ b/tests/selenium/website_testbed/first-party.js
@@ -0,0 +1,25 @@
+function setExpire() {
+ var now = new Date();
+ var time = now.getTime();
+ var expireTime = time + 864000;
+ now.setTime(expireTime);
+ return ";expires=" + now.toGMTString();
+}
+
+function setPath() {
+ return ";path=/";
+}
+
+function setSameSite() {
+ return ";SameSite=None;Secure";
+}
+
+function updateCookie() {
+ var oldcookie = document.cookie;
+ var val = "1234567890";
+ console.log("read cookie: " + oldcookie);
+ document.cookie = "localtest=" + encodeURIComponent(val) + setExpire() + setPath() + setSameSite();
+ console.log("updating cookie to:" + document.cookie);
+}
+
+updateCookie();
diff --git a/tests/selenium/widgets_test.py b/tests/selenium/widgets_test.py
new file mode 100644
index 0000000..d8bc2b5
--- /dev/null
+++ b/tests/selenium/widgets_test.py
@@ -0,0 +1,344 @@
+#!/usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+import unittest
+
+import pbtest
+
+from time import sleep
+
+from selenium.common.exceptions import (
+ NoSuchElementException,
+ StaleElementReferenceException,
+ TimeoutException
+)
+from selenium.webdriver.common.keys import Keys
+
+
+class WidgetsTest(pbtest.PBSeleniumTest):
+
+ FIXTURES_URL = "https://efforg.github.io/privacybadger-test-fixtures/html/"
+ BASIC_FIXTURE_URL = FIXTURES_URL + "widget_basic.html"
+ DYNAMIC_FIXTURE_URL = FIXTURES_URL + "widget_dynamic.html"
+ THIRD_PARTY_DOMAIN = "privacybadger-tests.eff.org"
+ TYPE3_WIDGET_NAME = "Type 3 Widget"
+ TYPE4_WIDGET_NAME = "Type 4 Widget"
+ TYPE4_WIDGET_CLASS = "pb-type4-test-widget"
+
+ def setUp(self):
+ self.set_up_widgets()
+
+ def set_up_widgets(self):
+ """Reinitializes Privacy Badger's widget replacement definitions."""
+
+ widgetsJson = {
+ self.TYPE3_WIDGET_NAME: {
+ "domain": self.THIRD_PARTY_DOMAIN,
+ "buttonSelectors": [
+ "iframe#pb-type3-test-widget"
+ ],
+ "replacementButton": {
+ "unblockDomains": [
+ self.THIRD_PARTY_DOMAIN
+ ],
+ "type": 3
+ }
+ },
+ self.TYPE4_WIDGET_NAME: {
+ "domains": [
+ self.THIRD_PARTY_DOMAIN
+ ],
+ "buttonSelectors": [
+ "div." + self.TYPE4_WIDGET_CLASS
+ ],
+ "scriptSelectors": [
+ "script." + self.TYPE4_WIDGET_CLASS
+ ],
+ "replacementButton": {
+ "unblockDomains": [
+ self.THIRD_PARTY_DOMAIN
+ ],
+ "type": 4
+ }
+ }
+ }
+
+ # reinitialize widgets using above JSON
+ self.load_url(self.options_url)
+ self.js((
+ "(function (widgetsJson) {"
+ " let bg = chrome.extension.getBackgroundPage();"
+ " bg.badger.widgetList = bg.widgetLoader.initializeWidgets(widgetsJson);"
+ "}(arguments[0]));"
+ ), widgetsJson)
+
+ def switch_to_frame(self, selector):
+ self.wait_for_and_switch_to_frame(selector, timeout=1)
+
+ def assert_widget(self, kind="type3"):
+ if kind == "type3":
+ self._assert_type3_widget()
+ elif kind == "type4":
+ self._assert_type4_widget()
+ else:
+ self.fail("Unknown widget type")
+
+ def _assert_type3_widget(self):
+ try:
+ self.switch_to_frame('iframe[src]')
+ except (StaleElementReferenceException, TimeoutException):
+ self.fail("Unable to find widget frame")
+
+ try:
+ self.wait_for_text('body', "Hello world!")
+ except TimeoutException:
+ self.fail("Unable to find expected widget text")
+
+ self.driver.switch_to.default_content()
+
+ def _assert_type4_widget(self):
+ try:
+ self.wait_for_text('div.' + self.TYPE4_WIDGET_CLASS,
+ "A third-party widget script was here")
+ except TimeoutException:
+ self.fail("Unable to find expected widget output")
+
+ def assert_replacement(self, widget_name=None):
+ if not widget_name:
+ widget_name = self.TYPE3_WIDGET_NAME
+
+ try:
+ self.switch_to_frame('iframe[srcdoc*="{}"]'.format(widget_name))
+ except (StaleElementReferenceException, TimeoutException):
+ self.fail("Unable to find widget placeholder frame")
+
+ try:
+ self.find_el_by_css("button[id^='btn-once-']")
+ self.find_el_by_css("button[id^='btn-site-']")
+ except TimeoutException:
+ self.fail("Unable to find expected widget placeholder buttons")
+
+ self.driver.switch_to.default_content()
+
+ def assert_widget_blocked(self):
+ try:
+ self.switch_to_frame('iframe[src]')
+ except TimeoutException:
+ self.fail("Widget frame should still be here")
+
+ self.assertFalse(
+ self.txt_by_css('body'), "Widget frame should be empty")
+
+ self.driver.switch_to.default_content()
+
+ def assert_no_widget(self):
+ try:
+ self.switch_to_frame('iframe[src]')
+ self.fail("Widget frame should be missing")
+ except TimeoutException:
+ pass
+ self.driver.switch_to.default_content()
+
+ def assert_no_replacement(self, widget_name=None):
+ if not widget_name:
+ widget_name = self.TYPE3_WIDGET_NAME
+ try:
+ self.switch_to_frame('iframe[srcdoc*="{}"]'.format(widget_name))
+ self.fail("Widget placeholder frame should be missing")
+ except TimeoutException:
+ pass
+ self.driver.switch_to.default_content()
+
+ def activate_widget(self, widget_name=None, once=True):
+ if not widget_name:
+ widget_name = self.TYPE3_WIDGET_NAME
+ id_prefix = 'btn-once' if once else 'btn-site'
+ self.switch_to_frame('iframe[srcdoc*="{}"]'.format(widget_name))
+ self.find_el_by_css("button[id^='%s']" % id_prefix).click()
+ self.driver.switch_to.default_content()
+
+ def test_replacement_basic(self):
+ # visit the basic widget fixture
+ self.load_url(self.BASIC_FIXTURE_URL)
+ # verify the widget is present
+ self.assert_widget()
+
+ # block the test widget's domain
+ self.block_domain(self.THIRD_PARTY_DOMAIN)
+
+ # revisit the fixture
+ self.load_url(self.BASIC_FIXTURE_URL)
+ # verify the widget got replaced
+ self.assert_replacement()
+
+ def test_replacement_dynamic(self):
+ # visit the dynamic widget fixture
+ self.load_url(self.DYNAMIC_FIXTURE_URL)
+ # verify the widget is initially missing
+ self.assert_no_widget()
+
+ # verify the widget shows up once you click on the trigger element
+ self.find_el_by_css('#widget-trigger').click()
+ self.assert_widget()
+
+ # block the test widget's domain
+ self.block_domain(self.THIRD_PARTY_DOMAIN)
+
+ # revisit the fixture
+ self.load_url(self.DYNAMIC_FIXTURE_URL)
+ # click on the trigger element
+ self.find_el_by_css('#widget-trigger').click()
+ # verify the widget got replaced
+ self.assert_replacement()
+
+ def test_activation(self):
+ self.block_domain(self.THIRD_PARTY_DOMAIN)
+ self.load_url(self.BASIC_FIXTURE_URL)
+ self.assert_replacement()
+
+ # click the "allow once" button
+ self.activate_widget()
+
+ # verify the original widget is restored
+ self.assert_widget()
+
+ # verify the type 4 widget is still replaced
+ try:
+ self.driver.find_element_by_css_selector(
+ 'div.' + self.TYPE4_WIDGET_CLASS)
+ self.fail("Widget output container div should be missing")
+ except NoSuchElementException:
+ pass
+ self.assert_replacement(self.TYPE4_WIDGET_NAME)
+
+ self.activate_widget(self.TYPE4_WIDGET_NAME)
+
+ # assert all script attributes were copied
+ script_el = self.driver.find_element_by_css_selector(
+ 'script.' + self.TYPE4_WIDGET_CLASS)
+ self.assertEqual(script_el.get_attribute('async'), "true")
+ self.assertEqual(script_el.get_attribute('data-foo'), "bar")
+
+ self.assert_widget("type4")
+
+ def test_activation_site(self):
+ self.block_domain(self.THIRD_PARTY_DOMAIN)
+ self.load_url(self.BASIC_FIXTURE_URL)
+ self.assert_replacement()
+
+ # click the "allow once" button
+ self.activate_widget()
+
+ # verify the original widget is restored
+ self.assert_widget()
+
+ # open a new window (to get around widget activation caching)
+ self.open_window()
+ self.load_url(self.BASIC_FIXTURE_URL)
+
+ # verify the widget got replaced
+ self.assert_replacement()
+
+ # click the "allow on site" button
+ self.activate_widget(once=False)
+
+ # verify the original widget is restored
+ self.assert_widget()
+
+ # open a new window (to get around widget activation caching)
+ self.open_window()
+ self.load_url(self.BASIC_FIXTURE_URL)
+
+ # verify basic widget is neither replaced nor blocked
+ self.assert_no_replacement()
+ self.assert_widget()
+
+ def test_disabling_site(self):
+ self.block_domain(self.THIRD_PARTY_DOMAIN)
+
+ self.disable_badger_on_site(self.BASIC_FIXTURE_URL)
+
+ # verify basic widget is neither replaced nor blocked
+ self.load_url(self.BASIC_FIXTURE_URL)
+ self.assert_no_replacement()
+ self.assert_widget()
+ # type 4 replacement should also be missing
+ self.assert_no_replacement(self.TYPE4_WIDGET_NAME)
+ # while the type 4 widget script should have executed
+ self.assert_widget("type4")
+
+ # verify dynamic widget is neither replaced nor blocked
+ self.load_url(self.DYNAMIC_FIXTURE_URL)
+ self.find_el_by_css('#widget-trigger').click()
+ self.assert_no_replacement()
+ self.assert_widget()
+
+ def test_disabling_all_replacement(self):
+ self.block_domain(self.THIRD_PARTY_DOMAIN)
+
+ # disable widget replacement
+ self.load_url(self.options_url)
+ self.wait_for_script("return window.OPTIONS_INITIALIZED")
+ self.find_el_by_css('a[href="#tab-manage-widgets"]').click()
+ self.driver.find_element_by_id('replace-widgets-checkbox').click()
+
+ # verify basic widget is no longer replaced
+ self.load_url(self.BASIC_FIXTURE_URL)
+ self.assert_no_replacement()
+ self.assert_widget_blocked()
+ # type 4 replacement should also be missing
+ self.assert_no_replacement(self.TYPE4_WIDGET_NAME)
+ # type 4 widget should also have gotten blocked
+ try:
+ widget_div = self.driver.find_element_by_css_selector(
+ 'div.pb-type4-test-widget')
+ except NoSuchElementException:
+ self.fail("Widget div should still be here")
+ # check the div's text a few times to make sure it stays empty
+ for _ in range(3):
+ self.assertFalse(widget_div.text,
+ "Widget output container should remain empty")
+ sleep(1)
+
+ # verify dynamic widget is no longer replaced
+ self.load_url(self.DYNAMIC_FIXTURE_URL)
+ self.find_el_by_css('#widget-trigger').click()
+ self.assert_no_replacement()
+ self.assert_widget_blocked()
+
+ def test_disabling_replacement_for_one_widget(self):
+ self.block_domain(self.THIRD_PARTY_DOMAIN)
+
+ # add the widget to the list of exceptions
+ self.load_url(self.options_url)
+ self.wait_for_script("return window.OPTIONS_INITIALIZED")
+ self.find_el_by_css('a[href="#tab-manage-widgets"]').click()
+ self.find_el_by_css('input[type="search"]').send_keys(
+ self.TYPE3_WIDGET_NAME, Keys.ENTER)
+
+ # verify basic widget is no longer replaced
+ self.load_url(self.BASIC_FIXTURE_URL)
+ self.assert_no_replacement()
+ self.assert_widget_blocked()
+ # verify the type 4 widget is still replaced
+ self.assert_replacement(self.TYPE4_WIDGET_NAME)
+
+ # verify dynamic widget is no longer replaced
+ self.load_url(self.DYNAMIC_FIXTURE_URL)
+ self.find_el_by_css('#widget-trigger').click()
+ self.assert_no_replacement()
+ self.assert_widget_blocked()
+
+ def test_no_replacement_when_cookieblocked(self):
+ self.cookieblock_domain(self.THIRD_PARTY_DOMAIN)
+ self.load_url(self.BASIC_FIXTURE_URL)
+
+ self.assert_no_replacement()
+ self.assert_no_replacement(self.TYPE4_WIDGET_NAME)
+
+ self.assert_widget()
+ self.assert_widget("type4")
+
+
+if __name__ == "__main__":
+ unittest.main()