Repository: darkreader/darkreader
Pull request #1983 (2020-02-10 15:09:05)

[NO-JIRA] Dynamic theme - Amazon image rounded corners
For the most part, this seems to help more than it hinders. I could try targetting specific image classnames, but given the size of the site I think this might be a better appraoch.

![Screenshot 2020-02-10 at 15 04 59](https://user-images.githubusercontent.com/30267516/74161605-1a742700-4c17-11ea-9884-6db67338ef63.png)

![Screenshot 2020-02-10 at 15 07 00](https://user-images.githubusercontent.com/30267516/74161610-1b0cbd80-4c17-11ea-9e69-c0b66dbef4f0.png)

![Screenshot 2020-02-10 at 15 05 09](https://user-images.githubusercontent.com/30267516/74161598-1811cd00-4c17-11ea-8883-25ec3f26a8b5.png)


georgegillams: Might do a follow up for the amazon CTAs 👍 
Myshor: sites included in file must be ordered alphabetically. Move your fix higher:
![image](https://user-images.githubusercontent.com/56877029/74428829-0bc98200-4e5a-11ea-8d6f-c4626794a1b6.png)

alexanderby: Hi @georgegillams, please fix the alphabetical order.
georgegillams: Sorry for the delay @Myshor and @alexanderby. All fixed now

Patch:
diff --git a/.eslintrc.js b/.eslintrc.js
index 7d1fb0c1..b6f98a3e 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -8,6 +8,10 @@ module.exports = {
         'indent': ['error', 4, {
             'SwitchCase': 1,
         }],
+        'keyword-spacing': ['error', {
+            after: true,
+            before: true,
+        }],
         'object-curly-spacing': ['error', 'never'],
         'no-multi-spaces': 'error',
         'no-trailing-spaces': 'error',
@@ -15,11 +19,15 @@ module.exports = {
         'semi': ['error', 'always'],
         'space-before-function-paren': ['error', {
             anonymous: 'always',
-            named: 'never',
             asyncArrow: 'always',
+            named: 'never',
         }],
         'space-in-parens': ['error', 'never'],
         'spaced-comment': ['error', 'always', {exceptions: ['-']}],
+        'quotes': ['error', 'single', {
+            allowTemplateLiterals: true,
+            avoidEscape: true,
+        }],
         '@typescript-eslint/camelcase': 'off',
         '@typescript-eslint/explicit-function-return-type': 'off',
         '@typescript-eslint/explicit-member-accessibility': 'off',
diff --git a/.github/ISSUE_TEMPLATE/broken-website.md b/.github/ISSUE_TEMPLATE/broken-website.md
new file mode 100644
index 00000000..e92c6a1c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/broken-website.md
@@ -0,0 +1,40 @@
+---
+name: Broken website
+about: Creates a broken website report about Darkreader
+title: "[Broken Website] "
+labels: Broken Website
+assignees: ''
+
+---
+
+<!--
+Thank you for taking the time to report a broken website.
+Please make sure there is no existing issue about this broken website.
+-->
+
+**Website**
+Give the link to the website
+
+**How to Reproduce**
+Steps to reproduce the behavior:
+An example for this is
+> 1. Go to x site
+> 2. Hover over x button
+> 3. See that when hovering it isn't changing colors
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Actual behavior**
+A clear and concise description of what actual happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**System info:**
+ - OS: [e.g. Windows, MacOS, Linux]
+ - Browser [e.g. chrome, safari]
+ - Darkreader Version [e.g. 4.9.4]
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 00000000..2cfbf370
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,37 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: "[BUG]"
+labels: bug
+assignees: ''
+
+---
+
+<!--
+Thank you for taking the time to report a bug.
+Please make sure there is no existing issue about this kind of bug.
+-->
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+> Go to '...'
+> Click on '....'
+> Scroll down to '....'
+> See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**System Information:**
+ - OS: [e.g. iOS]
+ - Browser [e.g. chrome, safari]
+ - Version [e.g. 22]
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 00000000..1e60b680
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,21 @@
+---
+name: Feature request
+about: Suggest a new Feature for Darkreader
+title: "[Feature Request]"
+labels: enhancement
+assignees: ''
+
+---
+<!--
+Thank you for taking the time to suggest a feature request.
+Please make sure there is no existing issue about this kind of feature.
+-->
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/README.md b/README.md
index 9ade59df..37166ec2 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,6 @@
 # Dark Reader for Google Chrome and Mozilla Firefox
+[![Build Status](https://travis-ci.org/darkreader/darkreader.svg?branch=master)](https://travis-ci.org/darkreader/darkreader)
+
 ![Dark Reader screenshot](https://lh3.googleusercontent.com/tTJIIIAqfJWymqPM9LAmivl11kWmF-XXLABues4OwfjOED_ntsJZdLY0VTG0XFCW0W_wYSll7Q=w640-h400-e365)
 
 This extension **inverts brightness** of web pages and aims to **reduce eyestrain** while browsing the web.
@@ -149,11 +151,9 @@ This will generate `build.zip` for use in Chromium browsers and `build-firefox.x
 ## Using for a website
 
 You can use Dark Reader to enable dark mode on your website.
-Install the package from NPM (`npm install darkreader`)
-or include the script via a CDN such as:
-
-- [https://unpkg.com/](https://unpkg.com/) | [https://unpkg.com/darkreader/](https://unpkg.com/darkreader/) | [Direct link](https://unpkg.com/darkreader)
-- [https://www.jsdelivr.com/](https://www.jsdelivr.com/) | [https://www.jsdelivr.com/package/npm/darkreader](https://www.jsdelivr.com/package/npm/darkreader) | [Direct link](https://cdn.jsdelivr.net/npm/darkreader/darkreader.min.js)
+- Install the package from NPM (`npm install darkreader`)
+- or build from the source code (`npm run api`)
+- or include the script via a CDN such as [unpkg](https://unpkg.com/darkreader/) or [jsDelivr](https://www.jsdelivr.com/package/npm/darkreader)
 
 Then use the following API
 ```javascript
diff --git a/package-lock.json b/package-lock.json
index 2255f268..8aaddeed 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "darkreader",
-  "version": "4.9.4",
+  "version": "4.9.7",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -66,12 +66,12 @@
       }
     },
     "@babel/generator": {
-      "version": "7.9.4",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.4.tgz",
-      "integrity": "sha512-rjP8ahaDy/ouhrvCoU1E5mqaitWrxwuNGU+dy1EpaoK48jZay4MdkskKGIMHLZNewg8sAsqpGSREJwP0zH3YQA==",
+      "version": "7.9.5",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.5.tgz",
+      "integrity": "sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.9.0",
+        "@babel/types": "^7.9.5",
         "jsesc": "^2.5.1",
         "lodash": "^4.17.13",
         "source-map": "^0.5.0"
@@ -86,14 +86,14 @@
       }
     },
     "@babel/helper-function-name": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz",
-      "integrity": "sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA==",
+      "version": "7.9.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz",
+      "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==",
       "dev": true,
       "requires": {
         "@babel/helper-get-function-arity": "^7.8.3",
         "@babel/template": "^7.8.3",
-        "@babel/types": "^7.8.3"
+        "@babel/types": "^7.9.5"
       }
     },
     "@babel/helper-get-function-arity": {
@@ -185,9 +185,9 @@
       }
     },
     "@babel/helper-validator-identifier": {
-      "version": "7.9.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz",
-      "integrity": "sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw==",
+      "version": "7.9.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz",
+      "integrity": "sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g==",
       "dev": true
     },
     "@babel/helpers": {
@@ -218,6 +218,15 @@
       "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==",
       "dev": true
     },
+    "@babel/plugin-syntax-async-generators": {
+      "version": "7.8.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
+      "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
     "@babel/plugin-syntax-bigint": {
       "version": "7.8.3",
       "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz",
@@ -227,6 +236,51 @@
         "@babel/helper-plugin-utils": "^7.8.0"
       }
     },
+    "@babel/plugin-syntax-class-properties": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.8.3.tgz",
+      "integrity": "sha512-UcAyQWg2bAN647Q+O811tG9MrJ38Z10jjhQdKNAL8fsyPzE3cCN/uT+f55cFVY4aGO4jqJAvmqsuY3GQDwAoXg==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.3"
+      }
+    },
+    "@babel/plugin-syntax-json-strings": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
+      "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
+    "@babel/plugin-syntax-logical-assignment-operators": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.8.3.tgz",
+      "integrity": "sha512-Zpg2Sgc++37kuFl6ppq2Q7Awc6E6AIW671x5PY8E/f7MCIyPPGK/EoeZXvvY3P42exZ3Q4/t3YOzP/HiN79jDg==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.3"
+      }
+    },
+    "@babel/plugin-syntax-nullish-coalescing-operator": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
+      "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
+    "@babel/plugin-syntax-numeric-separator": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz",
+      "integrity": "sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.3"
+      }
+    },
     "@babel/plugin-syntax-object-rest-spread": {
       "version": "7.8.3",
       "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
@@ -236,6 +290,24 @@
         "@babel/helper-plugin-utils": "^7.8.0"
       }
     },
+    "@babel/plugin-syntax-optional-catch-binding": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
+      "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
+    "@babel/plugin-syntax-optional-chaining": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
+      "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      }
+    },
     "@babel/template": {
       "version": "7.8.6",
       "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz",
@@ -270,17 +342,17 @@
       }
     },
     "@babel/traverse": {
-      "version": "7.9.0",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.0.tgz",
-      "integrity": "sha512-jAZQj0+kn4WTHO5dUZkZKhbFrqZE7K5LAQ5JysMnmvGij+wOdr+8lWqPeW0BcF4wFwrEXXtdGO7wcV6YPJcf3w==",
+      "version": "7.9.5",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.5.tgz",
+      "integrity": "sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "^7.8.3",
-        "@babel/generator": "^7.9.0",
-        "@babel/helper-function-name": "^7.8.3",
+        "@babel/generator": "^7.9.5",
+        "@babel/helper-function-name": "^7.9.5",
         "@babel/helper-split-export-declaration": "^7.8.3",
         "@babel/parser": "^7.9.0",
-        "@babel/types": "^7.9.0",
+        "@babel/types": "^7.9.5",
         "debug": "^4.1.0",
         "globals": "^11.1.0",
         "lodash": "^4.17.13"
@@ -309,12 +381,12 @@
       }
     },
     "@babel/types": {
-      "version": "7.9.0",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.0.tgz",
-      "integrity": "sha512-BS9JKfXkzzJl8RluW4JGknzpiUV7ZrvTayM6yfqLTVBEnFtyowVIOu6rqxRd5cVO6yGoWf4T8u8dgK9oB+GCng==",
+      "version": "7.9.5",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz",
+      "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==",
       "dev": true,
       "requires": {
-        "@babel/helper-validator-identifier": "^7.9.0",
+        "@babel/helper-validator-identifier": "^7.9.5",
         "lodash": "^4.17.13",
         "to-fast-properties": "^2.0.0"
       }
@@ -333,14 +405,6 @@
       "requires": {
         "exec-sh": "^0.3.2",
         "minimist": "^1.2.0"
-      },
-      "dependencies": {
-        "minimist": {
-          "version": "1.2.5",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
-          "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
-          "dev": true
-        }
       }
     },
     "@istanbuljs/load-nyc-config": {
@@ -370,17 +434,30 @@
       "dev": true
     },
     "@jest/console": {
-      "version": "25.2.3",
-      "resolved": "https://registry.npmjs.org/@jest/console/-/console-25.2.3.tgz",
-      "integrity": "sha512-k+37B1aSvOt9tKHWbZZSOy1jdgzesB0bj96igCVUG1nAH1W5EoUfgc5EXbBVU08KSLvkVdWopLXaO3xfVGlxtQ==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/@jest/console/-/console-25.4.0.tgz",
+      "integrity": "sha512-CfE0erx4hdJ6t7RzAcE1wLG6ZzsHSmybvIBQDoCkDM1QaSeWL9wJMzID/2BbHHa7ll9SsbbK43HjbERbBaFX2A==",
       "dev": true,
       "requires": {
-        "@jest/source-map": "^25.2.1",
+        "@jest/types": "^25.4.0",
         "chalk": "^3.0.0",
-        "jest-util": "^25.2.3",
+        "jest-message-util": "^25.4.0",
+        "jest-util": "^25.4.0",
         "slash": "^3.0.0"
       },
       "dependencies": {
+        "@jest/types": {
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
+          "dev": true,
+          "requires": {
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^1.1.1",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^3.0.0"
+          }
+        },
         "ansi-styles": {
           "version": "4.2.1",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
@@ -434,33 +511,33 @@
       }
     },
     "@jest/core": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/@jest/core/-/core-25.2.4.tgz",
-      "integrity": "sha512-WcWYShl0Bqfcb32oXtjwbiR78D/djhMdJW+ulp4/bmHgeODcsieqUJfUH+kEv8M7VNV77E6jds5aA+WuGh1nmg==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/@jest/core/-/core-25.4.0.tgz",
+      "integrity": "sha512-h1x9WSVV0+TKVtATGjyQIMJENs8aF6eUjnCoi4jyRemYZmekLr8EJOGQqTWEX8W6SbZ6Skesy9pGXrKeAolUJw==",
       "dev": true,
       "requires": {
-        "@jest/console": "^25.2.3",
-        "@jest/reporters": "^25.2.4",
-        "@jest/test-result": "^25.2.4",
-        "@jest/transform": "^25.2.4",
-        "@jest/types": "^25.2.3",
+        "@jest/console": "^25.4.0",
+        "@jest/reporters": "^25.4.0",
+        "@jest/test-result": "^25.4.0",
+        "@jest/transform": "^25.4.0",
+        "@jest/types": "^25.4.0",
         "ansi-escapes": "^4.2.1",
         "chalk": "^3.0.0",
         "exit": "^0.1.2",
         "graceful-fs": "^4.2.3",
-        "jest-changed-files": "^25.2.3",
-        "jest-config": "^25.2.4",
-        "jest-haste-map": "^25.2.3",
-        "jest-message-util": "^25.2.4",
-        "jest-regex-util": "^25.2.1",
-        "jest-resolve": "^25.2.3",
-        "jest-resolve-dependencies": "^25.2.4",
-        "jest-runner": "^25.2.4",
-        "jest-runtime": "^25.2.4",
-        "jest-snapshot": "^25.2.4",
-        "jest-util": "^25.2.3",
-        "jest-validate": "^25.2.3",
-        "jest-watcher": "^25.2.4",
+        "jest-changed-files": "^25.4.0",
+        "jest-config": "^25.4.0",
+        "jest-haste-map": "^25.4.0",
+        "jest-message-util": "^25.4.0",
+        "jest-regex-util": "^25.2.6",
+        "jest-resolve": "^25.4.0",
+        "jest-resolve-dependencies": "^25.4.0",
+        "jest-runner": "^25.4.0",
+        "jest-runtime": "^25.4.0",
+        "jest-snapshot": "^25.4.0",
+        "jest-util": "^25.4.0",
+        "jest-validate": "^25.4.0",
+        "jest-watcher": "^25.4.0",
         "micromatch": "^4.0.2",
         "p-each-series": "^2.1.0",
         "realpath-native": "^2.0.0",
@@ -470,9 +547,9 @@
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -558,20 +635,20 @@
       }
     },
     "@jest/environment": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-25.2.4.tgz",
-      "integrity": "sha512-wA4xlhD19/gukkDpJ5HQsTle0pgnzI5qMFEjw267lpTDC8d9N7Ihqr5pI+l0p8Qn1SQhai+glSqxrGdzKy4jxw==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-25.4.0.tgz",
+      "integrity": "sha512-KDctiak4mu7b4J6BIoN/+LUL3pscBzoUCP+EtSPd2tK9fqyDY5OF+CmkBywkFWezS9tyH5ACOQNtpjtueEDH6Q==",
       "dev": true,
       "requires": {
-        "@jest/fake-timers": "^25.2.4",
-        "@jest/types": "^25.2.3",
-        "jest-mock": "^25.2.3"
+        "@jest/fake-timers": "^25.4.0",
+        "@jest/types": "^25.4.0",
+        "jest-mock": "^25.4.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -633,22 +710,22 @@
       }
     },
     "@jest/fake-timers": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-25.2.4.tgz",
-      "integrity": "sha512-oC1TJiwfMcBttVN7Wz+VZnqEAgYTiEMu0QLOXpypR89nab0uCB31zm/QeBZddhSstn20qe3yqOXygp6OwvKT/Q==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-25.4.0.tgz",
+      "integrity": "sha512-lI9z+VOmVX4dPPFzyj0vm+UtaB8dCJJ852lcDnY0uCPRvZAaVGnMwBBc1wxtf+h7Vz6KszoOvKAt4QijDnHDkg==",
       "dev": true,
       "requires": {
-        "@jest/types": "^25.2.3",
-        "jest-message-util": "^25.2.4",
-        "jest-mock": "^25.2.3",
-        "jest-util": "^25.2.3",
+        "@jest/types": "^25.4.0",
+        "jest-message-util": "^25.4.0",
+        "jest-mock": "^25.4.0",
+        "jest-util": "^25.4.0",
         "lolex": "^5.0.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -710,16 +787,16 @@
       }
     },
     "@jest/reporters": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-25.2.4.tgz",
-      "integrity": "sha512-VHbLxM03jCc+bTLOluW/IqHR2G0Cl0iATwIQbuZtIUast8IXO4fD0oy4jpVGpG5b20S6REA8U3BaQoCW/CeVNQ==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-25.4.0.tgz",
+      "integrity": "sha512-bhx/buYbZgLZm4JWLcRJ/q9Gvmd3oUh7k2V7gA4ZYBx6J28pIuykIouclRdiAC6eGVX1uRZT+GK4CQJLd/PwPg==",
       "dev": true,
       "requires": {
         "@bcoe/v8-coverage": "^0.2.3",
-        "@jest/console": "^25.2.3",
-        "@jest/test-result": "^25.2.4",
-        "@jest/transform": "^25.2.4",
-        "@jest/types": "^25.2.3",
+        "@jest/console": "^25.4.0",
+        "@jest/test-result": "^25.4.0",
+        "@jest/transform": "^25.4.0",
+        "@jest/types": "^25.4.0",
         "chalk": "^3.0.0",
         "collect-v8-coverage": "^1.0.0",
         "exit": "^0.1.2",
@@ -728,23 +805,23 @@
         "istanbul-lib-instrument": "^4.0.0",
         "istanbul-lib-report": "^3.0.0",
         "istanbul-lib-source-maps": "^4.0.0",
-        "istanbul-reports": "^3.0.0",
-        "jest-haste-map": "^25.2.3",
-        "jest-resolve": "^25.2.3",
-        "jest-util": "^25.2.3",
-        "jest-worker": "^25.2.1",
+        "istanbul-reports": "^3.0.2",
+        "jest-haste-map": "^25.4.0",
+        "jest-resolve": "^25.4.0",
+        "jest-util": "^25.4.0",
+        "jest-worker": "^25.4.0",
         "node-notifier": "^6.0.0",
         "slash": "^3.0.0",
         "source-map": "^0.6.0",
         "string-length": "^3.1.0",
         "terminal-link": "^2.0.0",
-        "v8-to-istanbul": "^4.0.1"
+        "v8-to-istanbul": "^4.1.3"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -806,9 +883,9 @@
       }
     },
     "@jest/source-map": {
-      "version": "25.2.1",
-      "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-25.2.1.tgz",
-      "integrity": "sha512-PgScGJm1U27+9Te/cxP4oUFqJ2PX6NhBL2a6unQ7yafCgs8k02c0LSyjSIx/ao0AwcAdCczfAPDf5lJ7zoB/7A==",
+      "version": "25.2.6",
+      "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-25.2.6.tgz",
+      "integrity": "sha512-VuIRZF8M2zxYFGTEhkNSvQkUKafQro4y+mwUxy5ewRqs5N/ynSFUODYp3fy1zCnbCMy1pz3k+u57uCqx8QRSQQ==",
       "dev": true,
       "requires": {
         "callsites": "^3.0.0",
@@ -825,22 +902,21 @@
       }
     },
     "@jest/test-result": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-25.2.4.tgz",
-      "integrity": "sha512-AI7eUy+q2lVhFnaibDFg68NGkrxVWZdD6KBr9Hm6EvN0oAe7GxpEwEavgPfNHQjU2mi6g+NsFn/6QPgTUwM1qg==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-25.4.0.tgz",
+      "integrity": "sha512-8BAKPaMCHlL941eyfqhWbmp3MebtzywlxzV+qtngQ3FH+RBqnoSAhNEPj4MG7d2NVUrMOVfrwuzGpVIK+QnMAA==",
       "dev": true,
       "requires": {
-        "@jest/console": "^25.2.3",
-        "@jest/transform": "^25.2.4",
-        "@jest/types": "^25.2.3",
+        "@jest/console": "^25.4.0",
+        "@jest/types": "^25.4.0",
         "@types/istanbul-lib-coverage": "^2.0.0",
         "collect-v8-coverage": "^1.0.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -902,33 +978,33 @@
       }
     },
     "@jest/test-sequencer": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-25.2.4.tgz",
-      "integrity": "sha512-TEZm/Rkd6YgskdpTJdYLBtu6Gc11tfWPuSpatq0duH77ekjU8dpqX2zkPdY/ayuHxztV5LTJoV5BLtI9mZfXew==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-25.4.0.tgz",
+      "integrity": "sha512-240cI+nsM3attx2bMp9uGjjHrwrpvxxrZi8Tyqp/cfOzl98oZXVakXBgxODGyBYAy/UGXPKXLvNc2GaqItrsJg==",
       "dev": true,
       "requires": {
-        "@jest/test-result": "^25.2.4",
-        "jest-haste-map": "^25.2.3",
-        "jest-runner": "^25.2.4",
-        "jest-runtime": "^25.2.4"
+        "@jest/test-result": "^25.4.0",
+        "jest-haste-map": "^25.4.0",
+        "jest-runner": "^25.4.0",
+        "jest-runtime": "^25.4.0"
       }
     },
     "@jest/transform": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-25.2.4.tgz",
-      "integrity": "sha512-6eRigvb+G6bs4kW5j1/y8wu4nCrmVuIe0epPBbiWaYlwawJ8yi1EIyK3d/btDqmBpN5GpN4YhR6iPPnDmkYdTA==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-25.4.0.tgz",
+      "integrity": "sha512-t1w2S6V1sk++1HHsxboWxPEuSpN8pxEvNrZN+Ud/knkROWtf8LeUmz73A4ezE8476a5AM00IZr9a8FO9x1+j3g==",
       "dev": true,
       "requires": {
         "@babel/core": "^7.1.0",
-        "@jest/types": "^25.2.3",
+        "@jest/types": "^25.4.0",
         "babel-plugin-istanbul": "^6.0.0",
         "chalk": "^3.0.0",
         "convert-source-map": "^1.4.0",
         "fast-json-stable-stringify": "^2.0.0",
         "graceful-fs": "^4.2.3",
-        "jest-haste-map": "^25.2.3",
-        "jest-regex-util": "^25.2.1",
-        "jest-util": "^25.2.3",
+        "jest-haste-map": "^25.4.0",
+        "jest-regex-util": "^25.2.6",
+        "jest-util": "^25.4.0",
         "micromatch": "^4.0.2",
         "pirates": "^4.0.1",
         "realpath-native": "^2.0.0",
@@ -938,9 +1014,9 @@
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -1008,9 +1084,9 @@
       }
     },
     "@jest/types": {
-      "version": "25.1.0",
-      "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.1.0.tgz",
-      "integrity": "sha512-VpOtt7tCrgvamWZh1reVsGADujKigBUFTi19mlRjqEGsE8qH4r3s+skY33dNdXOwyZIvuftZ5tqdF1IgsMejMA==",
+      "version": "25.3.0",
+      "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.3.0.tgz",
+      "integrity": "sha512-UkaDNewdqXAmCDbN2GlUM6amDKS78eCqiw/UmF5nE0mmLTd6moJkiZJML/X52Ke3LH7Swhw883IRXq8o9nWjVw==",
       "dev": true,
       "requires": {
         "@types/istanbul-lib-coverage": "^2.0.0",
@@ -1115,18 +1191,18 @@
       }
     },
     "@sinonjs/commons": {
-      "version": "1.7.1",
-      "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.1.tgz",
-      "integrity": "sha512-Debi3Baff1Qu1Unc3mjJ96MgpbwTn43S1+9yJ0llWygPwDNu2aaWBD6yc9y/Z8XDRNhx7U+u2UDg2OGQXkclUQ==",
+      "version": "1.7.2",
+      "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.2.tgz",
+      "integrity": "sha512-+DUO6pnp3udV/v2VfUWgaY5BIE1IfT7lLfeDzPVeMT1XKkaAp9LgSI9x5RtrFQoZ9Oi0PgXQQHPaoKu7dCjVxw==",
       "dev": true,
       "requires": {
         "type-detect": "4.0.8"
       }
     },
     "@types/babel__core": {
-      "version": "7.1.6",
-      "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.6.tgz",
-      "integrity": "sha512-tTnhWszAqvXnhW7m5jQU9PomXSiKXk2sFxpahXvI20SZKu9ylPi8WtIxueZ6ehDWikPT0jeFujMj3X4ZHuf3Tg==",
+      "version": "7.1.7",
+      "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.7.tgz",
+      "integrity": "sha512-RL62NqSFPCDK2FM1pSDH0scHpJvsXtZNiYlMB73DgPBaG1E38ZYVL+ei5EkWRbr+KC4YNiAUNBnRj+bgwpgjMw==",
       "dev": true,
       "requires": {
         "@babel/parser": "^7.1.0",
@@ -1156,18 +1232,18 @@
       }
     },
     "@types/babel__traverse": {
-      "version": "7.0.9",
-      "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.9.tgz",
-      "integrity": "sha512-jEFQ8L1tuvPjOI8lnpaf73oCJe+aoxL6ygqSy6c8LcW98zaC+4mzWuQIRCEvKeCOu+lbqdXcg4Uqmm1S8AP1tw==",
+      "version": "7.0.10",
+      "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.10.tgz",
+      "integrity": "sha512-74fNdUGrWsgIB/V9kTO5FGHPWYY6Eqn+3Z7L6Hc4e/BxjYV7puvBqp5HwsVYYfLm6iURYBNCx4Ut37OF9yitCw==",
       "dev": true,
       "requires": {
         "@babel/types": "^7.3.0"
       }
     },
     "@types/chrome": {
-      "version": "0.0.103",
-      "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.103.tgz",
-      "integrity": "sha512-s8So1IG1fIu2dg2MRV3k6W5OjlVaJriNXIxIWDHi+Rdz5dLeuzPKcWzkVlcaVL4gONfn44JKC0RhW+P0UohLfg==",
+      "version": "0.0.104",
+      "resolved": "https://registry.npmjs.org/@types/chrome/-/chrome-0.0.104.tgz",
+      "integrity": "sha512-NDq+Vpphs5XT7IXrIHJcy27Rvf09Mes3XNsfpP2yOXUk6YiEU1QRcSLjj/A+y5jyq/kpUwC5shNET2jFeWAqEw==",
       "dev": true,
       "requires": {
         "@types/filesystem": "*",
@@ -1220,9 +1296,9 @@
       "dev": true
     },
     "@types/istanbul-lib-report": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz",
-      "integrity": "sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz",
+      "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==",
       "dev": true,
       "requires": {
         "@types/istanbul-lib-coverage": "*"
@@ -1239,13 +1315,13 @@
       }
     },
     "@types/jest": {
-      "version": "25.1.4",
-      "resolved": "https://registry.npmjs.org/@types/jest/-/jest-25.1.4.tgz",
-      "integrity": "sha512-QDDY2uNAhCV7TMCITrxz+MRk1EizcsevzfeS6LykIlq2V1E5oO4wXG8V2ZEd9w7Snxeeagk46YbMgZ8ESHx3sw==",
+      "version": "25.2.1",
+      "resolved": "https://registry.npmjs.org/@types/jest/-/jest-25.2.1.tgz",
+      "integrity": "sha512-msra1bCaAeEdkSyA0CZ6gW1ukMIvZ5YoJkdXw/qhQdsuuDlFTcEUrUw8CLCPt2rVRUfXlClVvK2gvPs9IokZaA==",
       "dev": true,
       "requires": {
-        "jest-diff": "^25.1.0",
-        "pretty-format": "^25.1.0"
+        "jest-diff": "^25.2.1",
+        "pretty-format": "^25.2.1"
       }
     },
     "@types/json-schema": {
@@ -1261,9 +1337,15 @@
       "dev": true
     },
     "@types/node": {
-      "version": "13.9.5",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.5.tgz",
-      "integrity": "sha512-hkzMMD3xu6BrJpGVLeQ3htQQNAcOrJjX7WFmtK8zWQpz2UJf13LCFF2ALA7c9OVdvc2vQJeDdjfR35M0sBCxvw==",
+      "version": "13.13.2",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.2.tgz",
+      "integrity": "sha512-LB2R1Oyhpg8gu4SON/mfforE525+Hi/M1ineICEDftqNVTyFg1aRIeGuTvXAoWHc4nbrFncWtJgMmoyRvuGh7A==",
+      "dev": true
+    },
+    "@types/normalize-package-data": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
+      "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==",
       "dev": true
     },
     "@types/prettier": {
@@ -1297,31 +1379,31 @@
       }
     },
     "@types/yargs-parser": {
-      "version": "13.1.0",
-      "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz",
-      "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==",
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz",
+      "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==",
       "dev": true
     },
     "@typescript-eslint/eslint-plugin": {
-      "version": "2.25.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.25.0.tgz",
-      "integrity": "sha512-W2YyMtjmlrOjtXc+FtTelVs9OhuR6OlYc4XKIslJ8PUJOqgYYAPRJhAqkYRQo3G4sjvG8jSodsNycEn4W2gHUw==",
+      "version": "2.29.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.29.0.tgz",
+      "integrity": "sha512-X/YAY7azKirENm4QRpT7OVmzok02cSkqeIcLmdz6gXUQG4Hk0Fi9oBAynSAyNXeGdMRuZvjBa0c1Lu0dn/u6VA==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/experimental-utils": "2.25.0",
+        "@typescript-eslint/experimental-utils": "2.29.0",
         "functional-red-black-tree": "^1.0.1",
         "regexpp": "^3.0.0",
         "tsutils": "^3.17.1"
       }
     },
     "@typescript-eslint/experimental-utils": {
-      "version": "2.25.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.25.0.tgz",
-      "integrity": "sha512-0IZ4ZR5QkFYbaJk+8eJ2kYeA+1tzOE1sBjbwwtSV85oNWYUBep+EyhlZ7DLUCyhMUGuJpcCCFL0fDtYAP1zMZw==",
+      "version": "2.29.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.29.0.tgz",
+      "integrity": "sha512-H/6VJr6eWYstyqjWXBP2Nn1hQJyvJoFdDtsHxGiD+lEP7piGnGpb/ZQd+z1ZSB1F7dN+WsxUDh8+S4LwI+f3jw==",
       "dev": true,
       "requires": {
         "@types/json-schema": "^7.0.3",
-        "@typescript-eslint/typescript-estree": "2.25.0",
+        "@typescript-eslint/typescript-estree": "2.29.0",
         "eslint-scope": "^5.0.0",
         "eslint-utils": "^2.0.0"
       },
@@ -1338,21 +1420,21 @@
       }
     },
     "@typescript-eslint/parser": {
-      "version": "2.25.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.25.0.tgz",
-      "integrity": "sha512-mccBLaBSpNVgp191CP5W+8U1crTyXsRziWliCqzj02kpxdjKMvFHGJbK33NroquH3zB/gZ8H511HEsJBa2fNEg==",
+      "version": "2.29.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.29.0.tgz",
+      "integrity": "sha512-H78M+jcu5Tf6m/5N8iiFblUUv+HJDguMSdFfzwa6vSg9lKR8Mk9BsgeSjO8l2EshKnJKcbv0e8IDDOvSNjl0EA==",
       "dev": true,
       "requires": {
         "@types/eslint-visitor-keys": "^1.0.0",
-        "@typescript-eslint/experimental-utils": "2.25.0",
-        "@typescript-eslint/typescript-estree": "2.25.0",
+        "@typescript-eslint/experimental-utils": "2.29.0",
+        "@typescript-eslint/typescript-estree": "2.29.0",
         "eslint-visitor-keys": "^1.1.0"
       }
     },
     "@typescript-eslint/typescript-estree": {
-      "version": "2.25.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.25.0.tgz",
-      "integrity": "sha512-VUksmx5lDxSi6GfmwSK7SSoIKSw9anukWWNitQPqt58LuYrKalzsgeuignbqnB+rK/xxGlSsCy8lYnwFfB6YJg==",
+      "version": "2.29.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.29.0.tgz",
+      "integrity": "sha512-3YGbtnWy4az16Egy5Fj5CckkVlpIh0MADtAQza+jiMADRSKkjdpzZp/5WuvwK/Qib3Z0HtzrDFeWanS99dNhnA==",
       "dev": true,
       "requires": {
         "debug": "^4.1.1",
@@ -1517,7 +1599,7 @@
     },
     "array-equal": {
       "version": "1.0.0",
-      "resolved": "http://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
       "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
       "dev": true
     },
@@ -1598,24 +1680,24 @@
       "dev": true
     },
     "babel-jest": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-25.2.4.tgz",
-      "integrity": "sha512-+yDzlyJVWrqih9i2Cvjpt7COaN8vUwCsKGtxJLzg6I0xhxD54K8mvDUCliPKLufyzHh/c5C4MRj4Vk7VMjOjIg==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-25.4.0.tgz",
+      "integrity": "sha512-p+epx4K0ypmHuCnd8BapfyOwWwosNCYhedetQey1awddtfmEX0MmdxctGl956uwUmjwXR5VSS5xJcGX9DvdIog==",
       "dev": true,
       "requires": {
-        "@jest/transform": "^25.2.4",
-        "@jest/types": "^25.2.3",
-        "@types/babel__core": "^7.1.0",
+        "@jest/transform": "^25.4.0",
+        "@jest/types": "^25.4.0",
+        "@types/babel__core": "^7.1.7",
         "babel-plugin-istanbul": "^6.0.0",
-        "babel-preset-jest": "^25.2.1",
+        "babel-preset-jest": "^25.4.0",
         "chalk": "^3.0.0",
         "slash": "^3.0.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -1690,23 +1772,40 @@
       }
     },
     "babel-plugin-jest-hoist": {
-      "version": "25.2.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-25.2.1.tgz",
-      "integrity": "sha512-HysbCQfJhxLlyxDbKcB2ucGYV0LjqK4h6dBoI3RtFuOxTiTWK6XGZMsHb0tGh8iJdV4hC6Z2GCHzVvDeh9i0lQ==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-25.4.0.tgz",
+      "integrity": "sha512-M3a10JCtTyKevb0MjuH6tU+cP/NVQZ82QPADqI1RQYY1OphztsCeIeQmTsHmF/NS6m0E51Zl4QNsI3odXSQF5w==",
       "dev": true,
       "requires": {
         "@types/babel__traverse": "^7.0.6"
       }
     },
+    "babel-preset-current-node-syntax": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.2.tgz",
+      "integrity": "sha512-u/8cS+dEiK1SFILbOC8/rUI3ml9lboKuuMvZ/4aQnQmhecQAgPw5ew066C1ObnEAUmlx7dv/s2z52psWEtLNiw==",
+      "dev": true,
+      "requires": {
+        "@babel/plugin-syntax-async-generators": "^7.8.4",
+        "@babel/plugin-syntax-bigint": "^7.8.3",
+        "@babel/plugin-syntax-class-properties": "^7.8.3",
+        "@babel/plugin-syntax-json-strings": "^7.8.3",
+        "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3",
+        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
+        "@babel/plugin-syntax-numeric-separator": "^7.8.3",
+        "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+        "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
+        "@babel/plugin-syntax-optional-chaining": "^7.8.3"
+      }
+    },
     "babel-preset-jest": {
-      "version": "25.2.1",
-      "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-25.2.1.tgz",
-      "integrity": "sha512-zXHJBM5iR8oEO4cvdF83AQqqJf3tJrXy3x8nfu2Nlqvn4cneg4Ca8M7cQvC5S9BzDDy1O0tZ9iXru9J6E3ym+A==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-25.4.0.tgz",
+      "integrity": "sha512-PwFiEWflHdu3JCeTr0Pb9NcHHE34qWFnPQRVPvqQITx4CsDCzs6o05923I10XvLvn9nNsRHuiVgB72wG/90ZHQ==",
       "dev": true,
       "requires": {
-        "@babel/plugin-syntax-bigint": "^7.0.0",
-        "@babel/plugin-syntax-object-rest-spread": "^7.0.0",
-        "babel-plugin-jest-hoist": "^25.2.1"
+        "babel-plugin-jest-hoist": "^25.4.0",
+        "babel-preset-current-node-syntax": "^0.1.2"
       }
     },
     "balanced-match": {
@@ -2019,9 +2118,9 @@
       "dev": true
     },
     "collect-v8-coverage": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.0.tgz",
-      "integrity": "sha512-VKIhJgvk8E1W28m5avZ2Gv2Ruv5YiF56ug2oclvaG9md69BuZImMG2sk9g7QNKLUbtYAKQjXjYxbYZVUlMMKmQ==",
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz",
+      "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==",
       "dev": true
     },
     "collection-visit": {
@@ -2246,9 +2345,9 @@
       "dev": true
     },
     "diff-sequences": {
-      "version": "25.1.0",
-      "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.1.0.tgz",
-      "integrity": "sha512-nFIfVk5B/NStCsJ+zaPO4vYuLjlzQ6uFvPxzYyHlejNZ/UGa7G/n7peOXVrVNvRuyfstt+mZQYGpjxg9Z6N8Kw==",
+      "version": "25.2.6",
+      "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz",
+      "integrity": "sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==",
       "dev": true
     },
     "dir-glob": {
@@ -2313,6 +2412,15 @@
         "prr": "~1.0.1"
       }
     },
+    "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"
+      }
+    },
     "escape-string-regexp": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
@@ -2576,23 +2684,23 @@
       }
     },
     "expect": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/expect/-/expect-25.2.4.tgz",
-      "integrity": "sha512-hfuPhPds4yOsZtIw4kwAg70r0hqGmpqekgA+VX7pf/3wZ6FY+xIOXZhNsPMMMsspYG/YIsbAiwqsdnD4Ht+bCA==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/expect/-/expect-25.4.0.tgz",
+      "integrity": "sha512-7BDIX99BTi12/sNGJXA9KMRcby4iAmu1xccBOhyKCyEhjcVKS3hPmHdA/4nSI9QGIOkUropKqr3vv7WMDM5lvQ==",
       "dev": true,
       "requires": {
-        "@jest/types": "^25.2.3",
+        "@jest/types": "^25.4.0",
         "ansi-styles": "^4.0.0",
-        "jest-get-type": "^25.2.1",
-        "jest-matcher-utils": "^25.2.3",
-        "jest-message-util": "^25.2.4",
-        "jest-regex-util": "^25.2.1"
+        "jest-get-type": "^25.2.6",
+        "jest-matcher-utils": "^25.4.0",
+        "jest-message-util": "^25.4.0",
+        "jest-regex-util": "^25.2.6"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -2642,12 +2750,6 @@
           "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
           "dev": true
         },
-        "jest-get-type": {
-          "version": "25.2.1",
-          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.1.tgz",
-          "integrity": "sha512-EYjTiqcDTCRJDcSNKbLTwn/LcDPEE7ITk8yRMNAOjEsN6yp+Uu+V1gx4djwnuj/DvWg0YGmqaBqPVGsPxlvE7w==",
-          "dev": true
-        },
         "supports-color": {
           "version": "7.1.0",
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
@@ -3128,6 +3230,12 @@
         }
       }
     },
+    "hosted-git-info": {
+      "version": "2.8.8",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
+      "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
+      "dev": true
+    },
     "html-encoding-sniffer": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz",
@@ -3282,6 +3390,12 @@
         }
       }
     },
+    "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",
@@ -3532,9 +3646,9 @@
       }
     },
     "istanbul-reports": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.1.tgz",
-      "integrity": "sha512-Vm9xwCiQ8t2cNNnckyeAV0UdxKpcQUz4nMxsBvIu8n2kmPSiyb5uaF/8LpmKr+yqL/MdOXaX2Nmdo4Qyxium9Q==",
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz",
+      "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==",
       "dev": true,
       "requires": {
         "html-escaper": "^2.0.0",
@@ -3542,20 +3656,20 @@
       }
     },
     "jest": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/jest/-/jest-25.2.4.tgz",
-      "integrity": "sha512-Lu4LXxf4+durzN/IFilcAoQSisOwgHIXgl9vffopePpSSwFqfj1Pj4y+k3nL8oTbnvjxgDIsEcepy6he4bWqnQ==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest/-/jest-25.4.0.tgz",
+      "integrity": "sha512-XWipOheGB4wai5JfCYXd6vwsWNwM/dirjRoZgAa7H2wd8ODWbli2AiKjqG8AYhyx+8+5FBEdpO92VhGlBydzbw==",
       "dev": true,
       "requires": {
-        "@jest/core": "^25.2.4",
+        "@jest/core": "^25.4.0",
         "import-local": "^3.0.2",
-        "jest-cli": "^25.2.4"
+        "jest-cli": "^25.4.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -3606,21 +3720,21 @@
           "dev": true
         },
         "jest-cli": {
-          "version": "25.2.4",
-          "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-25.2.4.tgz",
-          "integrity": "sha512-zeY2pRDWKj2LZudIncvvguwLMEdcnJqc2jJbwza1beqi80qqLvkPF/BjbFkK2sIV3r+mfTJS+7ITrvK6pCdRjg==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-25.4.0.tgz",
+          "integrity": "sha512-usyrj1lzCJZMRN1r3QEdnn8e6E6yCx/QN7+B1sLoA68V7f3WlsxSSQfy0+BAwRiF4Hz2eHauf11GZG3PIfWTXQ==",
           "dev": true,
           "requires": {
-            "@jest/core": "^25.2.4",
-            "@jest/test-result": "^25.2.4",
-            "@jest/types": "^25.2.3",
+            "@jest/core": "^25.4.0",
+            "@jest/test-result": "^25.4.0",
+            "@jest/types": "^25.4.0",
             "chalk": "^3.0.0",
             "exit": "^0.1.2",
             "import-local": "^3.0.2",
             "is-ci": "^2.0.0",
-            "jest-config": "^25.2.4",
-            "jest-util": "^25.2.3",
-            "jest-validate": "^25.2.3",
+            "jest-config": "^25.4.0",
+            "jest-util": "^25.4.0",
+            "jest-validate": "^25.4.0",
             "prompts": "^2.0.1",
             "realpath-native": "^2.0.0",
             "yargs": "^15.3.1"
@@ -3638,20 +3752,20 @@
       }
     },
     "jest-changed-files": {
-      "version": "25.2.3",
-      "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-25.2.3.tgz",
-      "integrity": "sha512-EFxy94dvvbqRB36ezIPLKJ4fDIC+jAdNs8i8uTwFpaXd6H3LVc3ova1lNS4ZPWk09OCR2vq5kSdSQgar7zMORg==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-25.4.0.tgz",
+      "integrity": "sha512-VR/rfJsEs4BVMkwOTuStRyS630fidFVekdw/lBaBQjx9KK3VZFOZ2c0fsom2fRp8pMCrCTP6LGna00o/DXGlqA==",
       "dev": true,
       "requires": {
-        "@jest/types": "^25.2.3",
+        "@jest/types": "^25.4.0",
         "execa": "^3.2.0",
         "throat": "^5.0.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -3696,9 +3810,9 @@
           "dev": true
         },
         "cross-spawn": {
-          "version": "7.0.1",
-          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz",
-          "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==",
+          "version": "7.0.2",
+          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz",
+          "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==",
           "dev": true,
           "requires": {
             "path-key": "^3.1.0",
@@ -3802,35 +3916,35 @@
       }
     },
     "jest-config": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-25.2.4.tgz",
-      "integrity": "sha512-fxy3nIpwJqOUQJRVF/q+pNQb6dv5b9YufOeCbpPZJ/md1zXpiupbhfehpfODhnKOfqbzSiigtSLzlWWmbRxnqQ==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-25.4.0.tgz",
+      "integrity": "sha512-egT9aKYxMyMSQV1aqTgam0SkI5/I2P9qrKexN5r2uuM2+68ypnc+zPGmfUxK7p1UhE7dYH9SLBS7yb+TtmT1AA==",
       "dev": true,
       "requires": {
         "@babel/core": "^7.1.0",
-        "@jest/test-sequencer": "^25.2.4",
-        "@jest/types": "^25.2.3",
-        "babel-jest": "^25.2.4",
+        "@jest/test-sequencer": "^25.4.0",
+        "@jest/types": "^25.4.0",
+        "babel-jest": "^25.4.0",
         "chalk": "^3.0.0",
         "deepmerge": "^4.2.2",
         "glob": "^7.1.1",
-        "jest-environment-jsdom": "^25.2.4",
-        "jest-environment-node": "^25.2.4",
-        "jest-get-type": "^25.2.1",
-        "jest-jasmine2": "^25.2.4",
-        "jest-regex-util": "^25.2.1",
-        "jest-resolve": "^25.2.3",
-        "jest-util": "^25.2.3",
-        "jest-validate": "^25.2.3",
+        "jest-environment-jsdom": "^25.4.0",
+        "jest-environment-node": "^25.4.0",
+        "jest-get-type": "^25.2.6",
+        "jest-jasmine2": "^25.4.0",
+        "jest-regex-util": "^25.2.6",
+        "jest-resolve": "^25.4.0",
+        "jest-util": "^25.4.0",
+        "jest-validate": "^25.4.0",
         "micromatch": "^4.0.2",
-        "pretty-format": "^25.2.3",
+        "pretty-format": "^25.4.0",
         "realpath-native": "^2.0.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -3880,19 +3994,13 @@
           "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
           "dev": true
         },
-        "jest-get-type": {
-          "version": "25.2.1",
-          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.1.tgz",
-          "integrity": "sha512-EYjTiqcDTCRJDcSNKbLTwn/LcDPEE7ITk8yRMNAOjEsN6yp+Uu+V1gx4djwnuj/DvWg0YGmqaBqPVGsPxlvE7w==",
-          "dev": true
-        },
         "pretty-format": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.2.3.tgz",
-          "integrity": "sha512-IP4+5UOAVGoyqC/DiomOeHBUKN6q00gfyT2qpAsRH64tgOKB2yF7FHJXC18OCiU0/YFierACup/zdCOWw0F/0w==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.4.0.tgz",
+          "integrity": "sha512-PI/2dpGjXK5HyXexLPZU/jw5T9Q6S1YVXxxVxco+LIqzUFHXIbKZKdUVt7GcX7QUCr31+3fzhi4gN4/wUYPVxQ==",
           "dev": true,
           "requires": {
-            "@jest/types": "^25.2.3",
+            "@jest/types": "^25.4.0",
             "ansi-regex": "^5.0.0",
             "ansi-styles": "^4.0.0",
             "react-is": "^16.12.0"
@@ -3910,15 +4018,15 @@
       }
     },
     "jest-diff": {
-      "version": "25.1.0",
-      "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.1.0.tgz",
-      "integrity": "sha512-nepXgajT+h017APJTreSieh4zCqnSHEJ1iT8HDlewu630lSJ4Kjjr9KNzm+kzGwwcpsDE6Snx1GJGzzsefaEHw==",
+      "version": "25.3.0",
+      "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.3.0.tgz",
+      "integrity": "sha512-vyvs6RPoVdiwARwY4kqFWd4PirPLm2dmmkNzKqo38uZOzJvLee87yzDjIZLmY1SjM3XR5DwsUH+cdQ12vgqi1w==",
       "dev": true,
       "requires": {
         "chalk": "^3.0.0",
-        "diff-sequences": "^25.1.0",
-        "jest-get-type": "^25.1.0",
-        "pretty-format": "^25.1.0"
+        "diff-sequences": "^25.2.6",
+        "jest-get-type": "^25.2.6",
+        "pretty-format": "^25.3.0"
       },
       "dependencies": {
         "ansi-styles": {
@@ -3974,31 +4082,31 @@
       }
     },
     "jest-docblock": {
-      "version": "25.2.3",
-      "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-25.2.3.tgz",
-      "integrity": "sha512-d3/tmjLLrH5fpRGmIm3oFa3vOaD/IjPxtXVOrfujpfJ9y1tCDB1x/tvunmdOVAyF03/xeMwburl6ITbiQT1mVA==",
+      "version": "25.3.0",
+      "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-25.3.0.tgz",
+      "integrity": "sha512-aktF0kCar8+zxRHxQZwxMy70stc9R1mOmrLsT5VO3pIT0uzGRSDAXxSlz4NqQWpuLjPpuMhPRl7H+5FRsvIQAg==",
       "dev": true,
       "requires": {
         "detect-newline": "^3.0.0"
       }
     },
     "jest-each": {
-      "version": "25.2.3",
-      "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-25.2.3.tgz",
-      "integrity": "sha512-RTlmCjsBDK2c9T5oO4MqccA3/5Y8BUtiEy7OOQik1iyCgdnNdHbI0pNEpyapZPBG0nlvZ4mIu7aY6zNUvLraAQ==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-25.4.0.tgz",
+      "integrity": "sha512-lwRIJ8/vQU/6vq3nnSSUw1Y3nz5tkYSFIywGCZpUBd6WcRgpn8NmJoQICojbpZmsJOJNHm0BKdyuJ6Xdx+eDQQ==",
       "dev": true,
       "requires": {
-        "@jest/types": "^25.2.3",
+        "@jest/types": "^25.4.0",
         "chalk": "^3.0.0",
-        "jest-get-type": "^25.2.1",
-        "jest-util": "^25.2.3",
-        "pretty-format": "^25.2.3"
+        "jest-get-type": "^25.2.6",
+        "jest-util": "^25.4.0",
+        "pretty-format": "^25.4.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -4048,19 +4156,13 @@
           "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
           "dev": true
         },
-        "jest-get-type": {
-          "version": "25.2.1",
-          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.1.tgz",
-          "integrity": "sha512-EYjTiqcDTCRJDcSNKbLTwn/LcDPEE7ITk8yRMNAOjEsN6yp+Uu+V1gx4djwnuj/DvWg0YGmqaBqPVGsPxlvE7w==",
-          "dev": true
-        },
         "pretty-format": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.2.3.tgz",
-          "integrity": "sha512-IP4+5UOAVGoyqC/DiomOeHBUKN6q00gfyT2qpAsRH64tgOKB2yF7FHJXC18OCiU0/YFierACup/zdCOWw0F/0w==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.4.0.tgz",
+          "integrity": "sha512-PI/2dpGjXK5HyXexLPZU/jw5T9Q6S1YVXxxVxco+LIqzUFHXIbKZKdUVt7GcX7QUCr31+3fzhi4gN4/wUYPVxQ==",
           "dev": true,
           "requires": {
-            "@jest/types": "^25.2.3",
+            "@jest/types": "^25.4.0",
             "ansi-regex": "^5.0.0",
             "ansi-styles": "^4.0.0",
             "react-is": "^16.12.0"
@@ -4078,23 +4180,23 @@
       }
     },
     "jest-environment-jsdom": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-25.2.4.tgz",
-      "integrity": "sha512-5dm+tNwrLmhELdjAwiQnVGf/U9iFMWdTL4/wyrMg2HU6RQnCiuxpWbIigLHUhuP1P2Ak0F4k3xhjrikboKyShA==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-25.4.0.tgz",
+      "integrity": "sha512-KTitVGMDrn2+pt7aZ8/yUTuS333w3pWt1Mf88vMntw7ZSBNDkRS6/4XLbFpWXYfWfp1FjcjQTOKzbK20oIehWQ==",
       "dev": true,
       "requires": {
-        "@jest/environment": "^25.2.4",
-        "@jest/fake-timers": "^25.2.4",
-        "@jest/types": "^25.2.3",
-        "jest-mock": "^25.2.3",
-        "jest-util": "^25.2.3",
+        "@jest/environment": "^25.4.0",
+        "@jest/fake-timers": "^25.4.0",
+        "@jest/types": "^25.4.0",
+        "jest-mock": "^25.4.0",
+        "jest-util": "^25.4.0",
         "jsdom": "^15.2.1"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -4156,23 +4258,23 @@
       }
     },
     "jest-environment-node": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-25.2.4.tgz",
-      "integrity": "sha512-Jkc5Y8goyXPrLRHnrUlqC7P4o5zn2m4zw6qWoRJ59kxV1f2a5wK+TTGhrhCwnhW/Ckpdl/pm+LufdvhJkvJbiw==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-25.4.0.tgz",
+      "integrity": "sha512-wryZ18vsxEAKFH7Z74zi/y/SyI1j6UkVZ6QsllBuT/bWlahNfQjLNwFsgh/5u7O957dYFoXj4yfma4n4X6kU9A==",
       "dev": true,
       "requires": {
-        "@jest/environment": "^25.2.4",
-        "@jest/fake-timers": "^25.2.4",
-        "@jest/types": "^25.2.3",
-        "jest-mock": "^25.2.3",
-        "jest-util": "^25.2.3",
+        "@jest/environment": "^25.4.0",
+        "@jest/fake-timers": "^25.4.0",
+        "@jest/types": "^25.4.0",
+        "jest-mock": "^25.4.0",
+        "jest-util": "^25.4.0",
         "semver": "^6.3.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -4240,25 +4342,25 @@
       }
     },
     "jest-get-type": {
-      "version": "25.1.0",
-      "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.1.0.tgz",
-      "integrity": "sha512-yWkBnT+5tMr8ANB6V+OjmrIJufHtCAqI5ic2H40v+tRqxDmE0PGnIiTyvRWFOMtmVHYpwRqyazDbTnhpjsGvLw==",
+      "version": "25.2.6",
+      "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz",
+      "integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==",
       "dev": true
     },
     "jest-haste-map": {
-      "version": "25.2.3",
-      "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-25.2.3.tgz",
-      "integrity": "sha512-pAP22OHtPr4qgZlJJFks2LLgoQUr4XtM1a+F5UaPIZNiCRnePA0hM3L7aiJ0gzwiNIYwMTfKRwG/S1L28J3A3A==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-25.4.0.tgz",
+      "integrity": "sha512-5EoCe1gXfGC7jmXbKzqxESrgRcaO3SzWXGCnvp9BcT0CFMyrB1Q6LIsjl9RmvmJGQgW297TCfrdgiy574Rl9HQ==",
       "dev": true,
       "requires": {
-        "@jest/types": "^25.2.3",
+        "@jest/types": "^25.4.0",
         "anymatch": "^3.0.3",
         "fb-watchman": "^2.0.0",
         "fsevents": "^2.1.2",
         "graceful-fs": "^4.2.3",
-        "jest-serializer": "^25.2.1",
-        "jest-util": "^25.2.3",
-        "jest-worker": "^25.2.1",
+        "jest-serializer": "^25.2.6",
+        "jest-util": "^25.4.0",
+        "jest-worker": "^25.4.0",
         "micromatch": "^4.0.2",
         "sane": "^4.0.3",
         "walker": "^1.0.7",
@@ -4266,9 +4368,9 @@
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -4345,34 +4447,34 @@
       }
     },
     "jest-jasmine2": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-25.2.4.tgz",
-      "integrity": "sha512-juoKrmNmLwaheNbAg71SuUF9ovwUZCFNTpKVhvCXWk+SSeORcIUMptKdPCoLXV3D16htzhTSKmNxnxSk4SrTjA==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-25.4.0.tgz",
+      "integrity": "sha512-QccxnozujVKYNEhMQ1vREiz859fPN/XklOzfQjm2j9IGytAkUbSwjFRBtQbHaNZ88cItMpw02JnHGsIdfdpwxQ==",
       "dev": true,
       "requires": {
         "@babel/traverse": "^7.1.0",
-        "@jest/environment": "^25.2.4",
-        "@jest/source-map": "^25.2.1",
-        "@jest/test-result": "^25.2.4",
-        "@jest/types": "^25.2.3",
+        "@jest/environment": "^25.4.0",
+        "@jest/source-map": "^25.2.6",
+        "@jest/test-result": "^25.4.0",
+        "@jest/types": "^25.4.0",
         "chalk": "^3.0.0",
         "co": "^4.6.0",
-        "expect": "^25.2.4",
+        "expect": "^25.4.0",
         "is-generator-fn": "^2.0.0",
-        "jest-each": "^25.2.3",
-        "jest-matcher-utils": "^25.2.3",
-        "jest-message-util": "^25.2.4",
-        "jest-runtime": "^25.2.4",
-        "jest-snapshot": "^25.2.4",
-        "jest-util": "^25.2.3",
-        "pretty-format": "^25.2.3",
+        "jest-each": "^25.4.0",
+        "jest-matcher-utils": "^25.4.0",
+        "jest-message-util": "^25.4.0",
+        "jest-runtime": "^25.4.0",
+        "jest-snapshot": "^25.4.0",
+        "jest-util": "^25.4.0",
+        "pretty-format": "^25.4.0",
         "throat": "^5.0.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -4423,12 +4525,12 @@
           "dev": true
         },
         "pretty-format": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.2.3.tgz",
-          "integrity": "sha512-IP4+5UOAVGoyqC/DiomOeHBUKN6q00gfyT2qpAsRH64tgOKB2yF7FHJXC18OCiU0/YFierACup/zdCOWw0F/0w==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.4.0.tgz",
+          "integrity": "sha512-PI/2dpGjXK5HyXexLPZU/jw5T9Q6S1YVXxxVxco+LIqzUFHXIbKZKdUVt7GcX7QUCr31+3fzhi4gN4/wUYPVxQ==",
           "dev": true,
           "requires": {
-            "@jest/types": "^25.2.3",
+            "@jest/types": "^25.4.0",
             "ansi-regex": "^5.0.0",
             "ansi-styles": "^4.0.0",
             "react-is": "^16.12.0"
@@ -4446,19 +4548,19 @@
       }
     },
     "jest-leak-detector": {
-      "version": "25.2.3",
-      "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-25.2.3.tgz",
-      "integrity": "sha512-yblCMPE7NJKl7778Cf/73yyFWAas5St0iiEBwq7RDyaz6Xd4WPFnPz2j7yDb/Qce71A1IbDoLADlcwD8zT74Aw==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-25.4.0.tgz",
+      "integrity": "sha512-7Y6Bqfv2xWsB+7w44dvZuLs5SQ//fzhETgOGG7Gq3TTGFdYvAgXGwV8z159RFZ6fXiCPm/szQ90CyfVos9JIFQ==",
       "dev": true,
       "requires": {
-        "jest-get-type": "^25.2.1",
-        "pretty-format": "^25.2.3"
+        "jest-get-type": "^25.2.6",
+        "pretty-format": "^25.4.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -4508,19 +4610,13 @@
           "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
           "dev": true
         },
-        "jest-get-type": {
-          "version": "25.2.1",
-          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.1.tgz",
-          "integrity": "sha512-EYjTiqcDTCRJDcSNKbLTwn/LcDPEE7ITk8yRMNAOjEsN6yp+Uu+V1gx4djwnuj/DvWg0YGmqaBqPVGsPxlvE7w==",
-          "dev": true
-        },
         "pretty-format": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.2.3.tgz",
-          "integrity": "sha512-IP4+5UOAVGoyqC/DiomOeHBUKN6q00gfyT2qpAsRH64tgOKB2yF7FHJXC18OCiU0/YFierACup/zdCOWw0F/0w==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.4.0.tgz",
+          "integrity": "sha512-PI/2dpGjXK5HyXexLPZU/jw5T9Q6S1YVXxxVxco+LIqzUFHXIbKZKdUVt7GcX7QUCr31+3fzhi4gN4/wUYPVxQ==",
           "dev": true,
           "requires": {
-            "@jest/types": "^25.2.3",
+            "@jest/types": "^25.4.0",
             "ansi-regex": "^5.0.0",
             "ansi-styles": "^4.0.0",
             "react-is": "^16.12.0"
@@ -4538,21 +4634,21 @@
       }
     },
     "jest-matcher-utils": {
-      "version": "25.2.3",
-      "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-25.2.3.tgz",
-      "integrity": "sha512-ZmiXiwQRVM9MoKjGMP5YsGGk2Th5ncyRxfXKz5AKsmU8m43kgNZirckVzaP61MlSa9LKmXbevdYqVp1ZKAw2Rw==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-25.4.0.tgz",
+      "integrity": "sha512-yPMdtj7YDgXhnGbc66bowk8AkQ0YwClbbwk3Kzhn5GVDrciiCr27U4NJRbrqXbTdtxjImONITg2LiRIw650k5A==",
       "dev": true,
       "requires": {
         "chalk": "^3.0.0",
-        "jest-diff": "^25.2.3",
-        "jest-get-type": "^25.2.1",
-        "pretty-format": "^25.2.3"
+        "jest-diff": "^25.4.0",
+        "jest-get-type": "^25.2.6",
+        "pretty-format": "^25.4.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -4596,12 +4692,6 @@
           "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
           "dev": true
         },
-        "diff-sequences": {
-          "version": "25.2.1",
-          "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.1.tgz",
-          "integrity": "sha512-foe7dXnGlSh3jR1ovJmdv+77VQj98eKCHHwJPbZ2eEf0fHwKbkZicpPxEch9smZ+n2dnF6QFwkOQdLq9hpeJUg==",
-          "dev": true
-        },
         "has-flag": {
           "version": "4.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -4609,30 +4699,24 @@
           "dev": true
         },
         "jest-diff": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.2.3.tgz",
-          "integrity": "sha512-VtZ6LAQtaQpFsmEzps15dQc5ELbJxy4L2DOSo2Ev411TUEtnJPkAMD7JneVypeMJQ1y3hgxN9Ao13n15FAnavg==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.4.0.tgz",
+          "integrity": "sha512-kklLbJVXW0y8UKOWOdYhI6TH5MG6QAxrWiBMgQaPIuhj3dNFGirKCd+/xfplBXICQ7fI+3QcqHm9p9lWu1N6ug==",
           "dev": true,
           "requires": {
             "chalk": "^3.0.0",
-            "diff-sequences": "^25.2.1",
-            "jest-get-type": "^25.2.1",
-            "pretty-format": "^25.2.3"
+            "diff-sequences": "^25.2.6",
+            "jest-get-type": "^25.2.6",
+            "pretty-format": "^25.4.0"
           }
         },
-        "jest-get-type": {
-          "version": "25.2.1",
-          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.1.tgz",
-          "integrity": "sha512-EYjTiqcDTCRJDcSNKbLTwn/LcDPEE7ITk8yRMNAOjEsN6yp+Uu+V1gx4djwnuj/DvWg0YGmqaBqPVGsPxlvE7w==",
-          "dev": true
-        },
         "pretty-format": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.2.3.tgz",
-          "integrity": "sha512-IP4+5UOAVGoyqC/DiomOeHBUKN6q00gfyT2qpAsRH64tgOKB2yF7FHJXC18OCiU0/YFierACup/zdCOWw0F/0w==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.4.0.tgz",
+          "integrity": "sha512-PI/2dpGjXK5HyXexLPZU/jw5T9Q6S1YVXxxVxco+LIqzUFHXIbKZKdUVt7GcX7QUCr31+3fzhi4gN4/wUYPVxQ==",
           "dev": true,
           "requires": {
-            "@jest/types": "^25.2.3",
+            "@jest/types": "^25.4.0",
             "ansi-regex": "^5.0.0",
             "ansi-styles": "^4.0.0",
             "react-is": "^16.12.0"
@@ -4650,14 +4734,13 @@
       }
     },
     "jest-message-util": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-25.2.4.tgz",
-      "integrity": "sha512-9wWMH3Bf+GVTv0GcQLmH/FRr0x0toptKw9TA8U5YFLVXx7Tq9pvcNzTyJrcTJ+wLqNbMPPJlJNft4MnlcrtF5Q==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-25.4.0.tgz",
+      "integrity": "sha512-LYY9hRcVGgMeMwmdfh9tTjeux1OjZHMusq/E5f3tJN+dAoVVkJtq5ZUEPIcB7bpxDUt2zjUsrwg0EGgPQ+OhXQ==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "^7.0.0",
-        "@jest/test-result": "^25.2.4",
-        "@jest/types": "^25.2.3",
+        "@jest/types": "^25.4.0",
         "@types/stack-utils": "^1.0.1",
         "chalk": "^3.0.0",
         "micromatch": "^4.0.2",
@@ -4666,9 +4749,9 @@
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -4730,18 +4813,18 @@
       }
     },
     "jest-mock": {
-      "version": "25.2.3",
-      "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-25.2.3.tgz",
-      "integrity": "sha512-xlf+pyY0j47zoCs8zGGOGfWyxxLximE8YFOfEK8s4FruR8DtM/UjNj61um+iDuMAFEBDe1bhCXkqiKoCmWjJzg==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-25.4.0.tgz",
+      "integrity": "sha512-MdazSfcYAUjJjuVTTnusLPzE0pE4VXpOUzWdj8sbM+q6abUjm3bATVPXFqTXrxSieR8ocpvQ9v/QaQCftioQFg==",
       "dev": true,
       "requires": {
-        "@jest/types": "^25.2.3"
+        "@jest/types": "^25.4.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -4809,29 +4892,31 @@
       "dev": true
     },
     "jest-regex-util": {
-      "version": "25.2.1",
-      "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-25.2.1.tgz",
-      "integrity": "sha512-wroFVJw62LdqTdkL508ZLV82FrJJWVJMIuYG7q4Uunl1WAPTf4ftPKrqqfec4SvOIlvRZUdEX2TFpWR356YG/w==",
+      "version": "25.2.6",
+      "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-25.2.6.tgz",
+      "integrity": "sha512-KQqf7a0NrtCkYmZZzodPftn7fL1cq3GQAFVMn5Hg8uKx/fIenLEobNanUxb7abQ1sjADHBseG/2FGpsv/wr+Qw==",
       "dev": true
     },
     "jest-resolve": {
-      "version": "25.2.3",
-      "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-25.2.3.tgz",
-      "integrity": "sha512-1vZMsvM/DBH258PnpUNSXIgtzpYz+vCVCj9+fcy4akZl4oKbD+9hZSlfe9RIDpU0Fc28ozHQrmwX3EqFRRIHGg==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-25.4.0.tgz",
+      "integrity": "sha512-wOsKqVDFWUiv8BtLMCC6uAJ/pHZkfFgoBTgPtmYlsprAjkxrr2U++ZnB3l5ykBMd2O24lXvf30SMAjJIW6k2aA==",
       "dev": true,
       "requires": {
-        "@jest/types": "^25.2.3",
+        "@jest/types": "^25.4.0",
         "browser-resolve": "^1.11.3",
         "chalk": "^3.0.0",
         "jest-pnp-resolver": "^1.2.1",
+        "read-pkg-up": "^7.0.1",
         "realpath-native": "^2.0.0",
-        "resolve": "^1.15.1"
+        "resolve": "^1.15.1",
+        "slash": "^3.0.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -4882,9 +4967,9 @@
           "dev": true
         },
         "resolve": {
-          "version": "1.15.1",
-          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz",
-          "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==",
+          "version": "1.17.0",
+          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz",
+          "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==",
           "dev": true,
           "requires": {
             "path-parse": "^1.0.6"
@@ -4902,20 +4987,20 @@
       }
     },
     "jest-resolve-dependencies": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-25.2.4.tgz",
-      "integrity": "sha512-qhUnK4PfNHzNdca7Ub1mbAqE0j5WNyMTwxBZZJjQlUrdqsiYho/QGK65FuBkZuSoYtKIIqriR9TpGrPEc3P5Gg==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-25.4.0.tgz",
+      "integrity": "sha512-A0eoZXx6kLiuG1Ui7wITQPl04HwjLErKIJTt8GR3c7UoDAtzW84JtCrgrJ6Tkw6c6MwHEyAaLk7dEPml5pf48A==",
       "dev": true,
       "requires": {
-        "@jest/types": "^25.2.3",
-        "jest-regex-util": "^25.2.1",
-        "jest-snapshot": "^25.2.4"
+        "@jest/types": "^25.4.0",
+        "jest-regex-util": "^25.2.6",
+        "jest-snapshot": "^25.4.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -4977,36 +5062,36 @@
       }
     },
     "jest-runner": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-25.2.4.tgz",
-      "integrity": "sha512-5xaIfqqxck9Wg2CV4b9KmJtf/sWO7zWQx7O+34GCLGPzoPcVmB3mZtdrQI1/jS3Reqjru9ycLjgLHSf6XoxRqA==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-25.4.0.tgz",
+      "integrity": "sha512-wWQSbVgj2e/1chFdMRKZdvlmA6p1IPujhpLT7TKNtCSl1B0PGBGvJjCaiBal/twaU2yfk8VKezHWexM8IliBfA==",
       "dev": true,
       "requires": {
-        "@jest/console": "^25.2.3",
-        "@jest/environment": "^25.2.4",
-        "@jest/test-result": "^25.2.4",
-        "@jest/types": "^25.2.3",
+        "@jest/console": "^25.4.0",
+        "@jest/environment": "^25.4.0",
+        "@jest/test-result": "^25.4.0",
+        "@jest/types": "^25.4.0",
         "chalk": "^3.0.0",
         "exit": "^0.1.2",
         "graceful-fs": "^4.2.3",
-        "jest-config": "^25.2.4",
-        "jest-docblock": "^25.2.3",
-        "jest-haste-map": "^25.2.3",
-        "jest-jasmine2": "^25.2.4",
-        "jest-leak-detector": "^25.2.3",
-        "jest-message-util": "^25.2.4",
-        "jest-resolve": "^25.2.3",
-        "jest-runtime": "^25.2.4",
-        "jest-util": "^25.2.3",
-        "jest-worker": "^25.2.1",
+        "jest-config": "^25.4.0",
+        "jest-docblock": "^25.3.0",
+        "jest-haste-map": "^25.4.0",
+        "jest-jasmine2": "^25.4.0",
+        "jest-leak-detector": "^25.4.0",
+        "jest-message-util": "^25.4.0",
+        "jest-resolve": "^25.4.0",
+        "jest-runtime": "^25.4.0",
+        "jest-util": "^25.4.0",
+        "jest-worker": "^25.4.0",
         "source-map-support": "^0.5.6",
         "throat": "^5.0.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -5074,32 +5159,32 @@
       }
     },
     "jest-runtime": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-25.2.4.tgz",
-      "integrity": "sha512-6ehOUizgIghN+aV5YSrDzTZ+zJ9omgEjJbTHj3Jqes5D52XHfhzT7cSfdREwkNjRytrR7mNwZ7pRauoyNLyJ8Q==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-25.4.0.tgz",
+      "integrity": "sha512-lgNJlCDULtXu9FumnwCyWlOub8iytijwsPNa30BKrSNtgoT6NUMXOPrZvsH06U6v0wgD/Igwz13nKA2wEKU2VA==",
       "dev": true,
       "requires": {
-        "@jest/console": "^25.2.3",
-        "@jest/environment": "^25.2.4",
-        "@jest/source-map": "^25.2.1",
-        "@jest/test-result": "^25.2.4",
-        "@jest/transform": "^25.2.4",
-        "@jest/types": "^25.2.3",
+        "@jest/console": "^25.4.0",
+        "@jest/environment": "^25.4.0",
+        "@jest/source-map": "^25.2.6",
+        "@jest/test-result": "^25.4.0",
+        "@jest/transform": "^25.4.0",
+        "@jest/types": "^25.4.0",
         "@types/yargs": "^15.0.0",
         "chalk": "^3.0.0",
         "collect-v8-coverage": "^1.0.0",
         "exit": "^0.1.2",
         "glob": "^7.1.3",
         "graceful-fs": "^4.2.3",
-        "jest-config": "^25.2.4",
-        "jest-haste-map": "^25.2.3",
-        "jest-message-util": "^25.2.4",
-        "jest-mock": "^25.2.3",
-        "jest-regex-util": "^25.2.1",
-        "jest-resolve": "^25.2.3",
-        "jest-snapshot": "^25.2.4",
-        "jest-util": "^25.2.3",
-        "jest-validate": "^25.2.3",
+        "jest-config": "^25.4.0",
+        "jest-haste-map": "^25.4.0",
+        "jest-message-util": "^25.4.0",
+        "jest-mock": "^25.4.0",
+        "jest-regex-util": "^25.2.6",
+        "jest-resolve": "^25.4.0",
+        "jest-snapshot": "^25.4.0",
+        "jest-util": "^25.4.0",
+        "jest-validate": "^25.4.0",
         "realpath-native": "^2.0.0",
         "slash": "^3.0.0",
         "strip-bom": "^4.0.0",
@@ -5107,9 +5192,9 @@
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -5183,37 +5268,37 @@
       }
     },
     "jest-serializer": {
-      "version": "25.2.1",
-      "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-25.2.1.tgz",
-      "integrity": "sha512-fibDi7M5ffx6c/P66IkvR4FKkjG5ldePAK1WlbNoaU4GZmIAkS9Le/frAwRUFEX0KdnisSPWf+b1RC5jU7EYJQ==",
+      "version": "25.2.6",
+      "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-25.2.6.tgz",
+      "integrity": "sha512-RMVCfZsezQS2Ww4kB5HJTMaMJ0asmC0BHlnobQC6yEtxiFKIxohFA4QSXSabKwSggaNkqxn6Z2VwdFCjhUWuiQ==",
       "dev": true
     },
     "jest-snapshot": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-25.2.4.tgz",
-      "integrity": "sha512-nIwpW7FZCq5p0AE3Oyqyb6jL0ENJixXzJ5/CD/XRuOqp3gS5OM3O/k+NnTrniCXxPFV4ry6s9HNfiPQBi0wcoA==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-25.4.0.tgz",
+      "integrity": "sha512-J4CJ0X2SaGheYRZdLz9CRHn9jUknVmlks4UBeu270hPAvdsauFXOhx9SQP2JtRzhnR3cvro/9N9KP83/uvFfRg==",
       "dev": true,
       "requires": {
         "@babel/types": "^7.0.0",
-        "@jest/types": "^25.2.3",
+        "@jest/types": "^25.4.0",
         "@types/prettier": "^1.19.0",
         "chalk": "^3.0.0",
-        "expect": "^25.2.4",
-        "jest-diff": "^25.2.3",
-        "jest-get-type": "^25.2.1",
-        "jest-matcher-utils": "^25.2.3",
-        "jest-message-util": "^25.2.4",
-        "jest-resolve": "^25.2.3",
+        "expect": "^25.4.0",
+        "jest-diff": "^25.4.0",
+        "jest-get-type": "^25.2.6",
+        "jest-matcher-utils": "^25.4.0",
+        "jest-message-util": "^25.4.0",
+        "jest-resolve": "^25.4.0",
         "make-dir": "^3.0.0",
         "natural-compare": "^1.4.0",
-        "pretty-format": "^25.2.3",
+        "pretty-format": "^25.4.0",
         "semver": "^6.3.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -5257,12 +5342,6 @@
           "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
           "dev": true
         },
-        "diff-sequences": {
-          "version": "25.2.1",
-          "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.1.tgz",
-          "integrity": "sha512-foe7dXnGlSh3jR1ovJmdv+77VQj98eKCHHwJPbZ2eEf0fHwKbkZicpPxEch9smZ+n2dnF6QFwkOQdLq9hpeJUg==",
-          "dev": true
-        },
         "has-flag": {
           "version": "4.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -5270,30 +5349,24 @@
           "dev": true
         },
         "jest-diff": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.2.3.tgz",
-          "integrity": "sha512-VtZ6LAQtaQpFsmEzps15dQc5ELbJxy4L2DOSo2Ev411TUEtnJPkAMD7JneVypeMJQ1y3hgxN9Ao13n15FAnavg==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.4.0.tgz",
+          "integrity": "sha512-kklLbJVXW0y8UKOWOdYhI6TH5MG6QAxrWiBMgQaPIuhj3dNFGirKCd+/xfplBXICQ7fI+3QcqHm9p9lWu1N6ug==",
           "dev": true,
           "requires": {
             "chalk": "^3.0.0",
-            "diff-sequences": "^25.2.1",
-            "jest-get-type": "^25.2.1",
-            "pretty-format": "^25.2.3"
+            "diff-sequences": "^25.2.6",
+            "jest-get-type": "^25.2.6",
+            "pretty-format": "^25.4.0"
           }
         },
-        "jest-get-type": {
-          "version": "25.2.1",
-          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.1.tgz",
-          "integrity": "sha512-EYjTiqcDTCRJDcSNKbLTwn/LcDPEE7ITk8yRMNAOjEsN6yp+Uu+V1gx4djwnuj/DvWg0YGmqaBqPVGsPxlvE7w==",
-          "dev": true
-        },
         "pretty-format": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.2.3.tgz",
-          "integrity": "sha512-IP4+5UOAVGoyqC/DiomOeHBUKN6q00gfyT2qpAsRH64tgOKB2yF7FHJXC18OCiU0/YFierACup/zdCOWw0F/0w==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.4.0.tgz",
+          "integrity": "sha512-PI/2dpGjXK5HyXexLPZU/jw5T9Q6S1YVXxxVxco+LIqzUFHXIbKZKdUVt7GcX7QUCr31+3fzhi4gN4/wUYPVxQ==",
           "dev": true,
           "requires": {
-            "@jest/types": "^25.2.3",
+            "@jest/types": "^25.4.0",
             "ansi-regex": "^5.0.0",
             "ansi-styles": "^4.0.0",
             "react-is": "^16.12.0"
@@ -5317,21 +5390,21 @@
       }
     },
     "jest-util": {
-      "version": "25.2.3",
-      "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-25.2.3.tgz",
-      "integrity": "sha512-7tWiMICVSo9lNoObFtqLt9Ezt5exdFlWs5fLe1G4XLY2lEbZc814cw9t4YHScqBkWMfzth8ASHKlYBxiX2rdCw==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-25.4.0.tgz",
+      "integrity": "sha512-WSZD59sBtAUjLv1hMeKbNZXmMcrLRWcYqpO8Dz8b4CeCTZpfNQw2q9uwrYAD+BbJoLJlu4ezVPwtAmM/9/SlZA==",
       "dev": true,
       "requires": {
-        "@jest/types": "^25.2.3",
+        "@jest/types": "^25.4.0",
         "chalk": "^3.0.0",
         "is-ci": "^2.0.0",
         "make-dir": "^3.0.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -5393,23 +5466,23 @@
       }
     },
     "jest-validate": {
-      "version": "25.2.3",
-      "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-25.2.3.tgz",
-      "integrity": "sha512-GObn91jzU0B0Bv4cusAwjP6vnWy78hJUM8MOSz7keRfnac/ZhQWIsUjvk01IfeXNTemCwgR57EtdjQMzFZGREg==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-25.4.0.tgz",
+      "integrity": "sha512-hvjmes/EFVJSoeP1yOl8qR8mAtMR3ToBkZeXrD/ZS9VxRyWDqQ/E1C5ucMTeSmEOGLipvdlyipiGbHJ+R1MQ0g==",
       "dev": true,
       "requires": {
-        "@jest/types": "^25.2.3",
+        "@jest/types": "^25.4.0",
         "camelcase": "^5.3.1",
         "chalk": "^3.0.0",
-        "jest-get-type": "^25.2.1",
+        "jest-get-type": "^25.2.6",
         "leven": "^3.1.0",
-        "pretty-format": "^25.2.3"
+        "pretty-format": "^25.4.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -5459,19 +5532,13 @@
           "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
           "dev": true
         },
-        "jest-get-type": {
-          "version": "25.2.1",
-          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.1.tgz",
-          "integrity": "sha512-EYjTiqcDTCRJDcSNKbLTwn/LcDPEE7ITk8yRMNAOjEsN6yp+Uu+V1gx4djwnuj/DvWg0YGmqaBqPVGsPxlvE7w==",
-          "dev": true
-        },
         "pretty-format": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.2.3.tgz",
-          "integrity": "sha512-IP4+5UOAVGoyqC/DiomOeHBUKN6q00gfyT2qpAsRH64tgOKB2yF7FHJXC18OCiU0/YFierACup/zdCOWw0F/0w==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.4.0.tgz",
+          "integrity": "sha512-PI/2dpGjXK5HyXexLPZU/jw5T9Q6S1YVXxxVxco+LIqzUFHXIbKZKdUVt7GcX7QUCr31+3fzhi4gN4/wUYPVxQ==",
           "dev": true,
           "requires": {
-            "@jest/types": "^25.2.3",
+            "@jest/types": "^25.4.0",
             "ansi-regex": "^5.0.0",
             "ansi-styles": "^4.0.0",
             "react-is": "^16.12.0"
@@ -5489,23 +5556,23 @@
       }
     },
     "jest-watcher": {
-      "version": "25.2.4",
-      "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-25.2.4.tgz",
-      "integrity": "sha512-p7g7s3zqcy69slVzQYcphyzkB2FBmJwMbv6k6KjI5mqd6KnUnQPfQVKuVj2l+34EeuxnbXqnrjtUFmxhcL87rg==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-25.4.0.tgz",
+      "integrity": "sha512-36IUfOSRELsKLB7k25j/wutx0aVuHFN6wO94gPNjQtQqFPa2rkOymmx9rM5EzbF3XBZZ2oqD9xbRVoYa2w86gw==",
       "dev": true,
       "requires": {
-        "@jest/test-result": "^25.2.4",
-        "@jest/types": "^25.2.3",
+        "@jest/test-result": "^25.4.0",
+        "@jest/types": "^25.4.0",
         "ansi-escapes": "^4.2.1",
         "chalk": "^3.0.0",
-        "jest-util": "^25.2.3",
+        "jest-util": "^25.4.0",
         "string-length": "^3.1.0"
       },
       "dependencies": {
         "@jest/types": {
-          "version": "25.2.3",
-          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.2.3.tgz",
-          "integrity": "sha512-6oLQwO9mKif3Uph3RX5J1i3S7X7xtDHWBaaaoeKw8hOzV6YUd0qDcYcHZ6QXMHDIzSr7zzrEa51o2Ovlj6AtKQ==",
+          "version": "25.4.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
+          "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
           "dev": true,
           "requires": {
             "@types/istanbul-lib-coverage": "^2.0.0",
@@ -5567,9 +5634,9 @@
       }
     },
     "jest-worker": {
-      "version": "25.2.1",
-      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.2.1.tgz",
-      "integrity": "sha512-IHnpekk8H/hCUbBlfeaPZzU6v75bqwJp3n4dUrQuQOAgOneI4tx3jV2o8pvlXnDfcRsfkFIUD//HWXpCmR+evQ==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.4.0.tgz",
+      "integrity": "sha512-ghAs/1FtfYpMmYQ0AHqxV62XPvKdUDIBBApMZfly+E9JEmYh2K45G0R5dWxx986RN12pRCxsViwQVtGl+N4whw==",
       "dev": true,
       "requires": {
         "merge-stream": "^2.0.0",
@@ -5655,6 +5722,12 @@
       "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
       "dev": true
     },
+    "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",
@@ -5680,20 +5753,12 @@
       "dev": true
     },
     "json5": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.2.tgz",
-      "integrity": "sha512-MoUOQ4WdiN3yxhm7NEVJSJrieAo5hNSLQ5sj05OTRHPL9HOBy8u4Bu88jsC1jvqAdN+E1bJmsUcZH+1HQxliqQ==",
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
+      "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
       "dev": true,
       "requires": {
         "minimist": "^1.2.5"
-      },
-      "dependencies": {
-        "minimist": {
-          "version": "1.2.5",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
-          "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
-          "dev": true
-        }
       }
     },
     "jsonfile": {
@@ -5764,6 +5829,12 @@
         "type-check": "~0.3.2"
       }
     },
+    "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",
@@ -5920,6 +5991,12 @@
         "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==",
+      "dev": true
+    },
     "mixin-deep": {
       "version": "1.3.2",
       "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
@@ -5942,20 +6019,12 @@
       }
     },
     "mkdirp": {
-      "version": "0.5.1",
-      "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
-      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+      "version": "0.5.5",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+      "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
       "dev": true,
       "requires": {
-        "minimist": "0.0.8"
-      },
-      "dependencies": {
-        "minimist": {
-          "version": "0.0.8",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
-          "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
-          "dev": true
-        }
+        "minimist": "^1.2.5"
       }
     },
     "ms": {
@@ -6036,6 +6105,18 @@
         }
       }
     },
+    "normalize-package-data": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+      "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+      "dev": true,
+      "requires": {
+        "hosted-git-info": "^2.1.4",
+        "resolve": "^1.10.0",
+        "semver": "2 || 3 || 4 || 5",
+        "validate-npm-package-license": "^3.0.1"
+      }
+    },
     "normalize-path": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -6195,6 +6276,18 @@
         "callsites": "^3.0.0"
       }
     },
+    "parse-json": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz",
+      "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==",
+      "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": "5.1.0",
       "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz",
@@ -6286,18 +6379,18 @@
       "dev": true
     },
     "prettier": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.2.tgz",
-      "integrity": "sha512-5xJQIPT8BraI7ZnaDwSbu5zLrB6vvi8hVV58yHQ+QK64qrY40dULy0HSRlQ2/2IdzeBpjhDkqdcFBnFeDEMVdg==",
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz",
+      "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==",
       "dev": true
     },
     "pretty-format": {
-      "version": "25.1.0",
-      "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.1.0.tgz",
-      "integrity": "sha512-46zLRSGLd02Rp+Lhad9zzuNZ+swunitn8zIpfD2B4OPCRLXbM87RJT2aBLBWYOznNUML/2l/ReMyWNC80PJBUQ==",
+      "version": "25.3.0",
+      "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.3.0.tgz",
+      "integrity": "sha512-wToHwF8bkQknIcFkBqNfKu4+UZqnrLn/Vr+wwKQwwvPzkBfDDKp/qIabFqdgtoi5PEnM8LFByVsOrHoa3SpTVA==",
       "dev": true,
       "requires": {
-        "@jest/types": "^25.1.0",
+        "@jest/types": "^25.3.0",
         "ansi-regex": "^5.0.0",
         "ansi-styles": "^4.0.0",
         "react-is": "^16.12.0"
@@ -6392,11 +6485,42 @@
       "dev": true
     },
     "react-is": {
-      "version": "16.13.0",
-      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.0.tgz",
-      "integrity": "sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA==",
+      "version": "16.13.1",
+      "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+      "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
       "dev": true
     },
+    "read-pkg": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
+      "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
+      "dev": true,
+      "requires": {
+        "@types/normalize-package-data": "^2.4.0",
+        "normalize-package-data": "^2.5.0",
+        "parse-json": "^5.0.0",
+        "type-fest": "^0.6.0"
+      },
+      "dependencies": {
+        "type-fest": {
+          "version": "0.6.0",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
+          "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
+          "dev": true
+        }
+      }
+    },
+    "read-pkg-up": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
+      "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
+      "dev": true,
+      "requires": {
+        "find-up": "^4.1.0",
+        "read-pkg": "^5.2.0",
+        "type-fest": "^0.8.1"
+      }
+    },
     "readdirp": {
       "version": "3.3.0",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz",
@@ -6423,9 +6547,9 @@
       }
     },
     "regexpp": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.0.0.tgz",
-      "integrity": "sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz",
+      "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==",
       "dev": true
     },
     "remove-trailing-separator": {
@@ -6606,9 +6730,9 @@
       }
     },
     "rollup": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.3.0.tgz",
-      "integrity": "sha512-nIq2Z9YwNbEfqTlAXe/tVl8CwUsjX/8Q5Jxlx+JRoYCu5keKLc6k0zyt11sM6WtCDxhmmJEIosFy9y26ZFRx6w==",
+      "version": "2.7.2",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.7.2.tgz",
+      "integrity": "sha512-SdtTZVMMVSPe7SNv4exUyPXARe5v/p3TeeG3LRA5WabLPJt4Usi3wVrvVlyAUTG40JJmqS6zbIHt2vWTss2prw==",
       "dev": true,
       "requires": {
         "fsevents": "~2.1.2"
@@ -6759,7 +6883,7 @@
     },
     "safe-regex": {
       "version": "1.1.0",
-      "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+      "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
       "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
       "dev": true,
       "requires": {
@@ -6892,12 +7016,6 @@
             "to-regex": "^3.0.2"
           }
         },
-        "minimist": {
-          "version": "1.2.5",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
-          "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
-          "dev": true
-        },
         "normalize-path": {
           "version": "2.1.1",
           "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
@@ -7162,9 +7280,9 @@
       }
     },
     "source-map-support": {
-      "version": "0.5.16",
-      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz",
-      "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==",
+      "version": "0.5.18",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.18.tgz",
+      "integrity": "sha512-9luZr/BZ2QeU6tO2uG8N2aZpVSli4TSAOAqFOyTO51AJcD9P99c0K1h6dD6r6qo5dyT44BR5exweOaLLeldTkQ==",
       "dev": true,
       "requires": {
         "buffer-from": "^1.0.0",
@@ -7183,6 +7301,38 @@
       "integrity": "sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg==",
       "dev": true
     },
+    "spdx-correct": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
+      "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+      "dev": true,
+      "requires": {
+        "spdx-expression-parse": "^3.0.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-exceptions": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
+      "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
+      "dev": true
+    },
+    "spdx-expression-parse": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
+      "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
+      "dev": true,
+      "requires": {
+        "spdx-exceptions": "^2.1.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "spdx-license-ids": {
+      "version": "3.0.5",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
+      "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==",
+      "dev": true
+    },
     "split-string": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
@@ -7323,7 +7473,7 @@
     },
     "strip-eof": {
       "version": "1.0.0",
-      "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+      "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
       "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
       "dev": true
     },
@@ -7528,9 +7678,9 @@
       }
     },
     "ts-jest": {
-      "version": "25.3.0",
-      "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-25.3.0.tgz",
-      "integrity": "sha512-qH/uhaC+AFDU9JfAueSr0epIFJkGMvUPog4FxSEVAtPOur1Oni5WBJMiQIkfHvc7PviVRsnlVLLY2I6221CQew==",
+      "version": "25.4.0",
+      "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-25.4.0.tgz",
+      "integrity": "sha512-+0ZrksdaquxGUBwSdTIcdX7VXdwLIlSRsyjivVA9gcO+Cvr6ByqDhu/mi5+HCcb6cMkiQp5xZ8qRO7/eCqLeyw==",
       "dev": true,
       "requires": {
         "bs-logger": "0.x",
@@ -7539,16 +7689,17 @@
         "json5": "2.x",
         "lodash.memoize": "4.x",
         "make-error": "1.x",
+        "micromatch": "4.x",
         "mkdirp": "1.x",
         "resolve": "1.x",
         "semver": "6.x",
-        "yargs-parser": "^18.1.1"
+        "yargs-parser": "18.x"
       },
       "dependencies": {
         "mkdirp": {
-          "version": "1.0.3",
-          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.3.tgz",
-          "integrity": "sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g==",
+          "version": "1.0.4",
+          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+          "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
           "dev": true
         },
         "semver": {
@@ -7560,15 +7711,15 @@
       }
     },
     "ts-node": {
-      "version": "8.8.1",
-      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.8.1.tgz",
-      "integrity": "sha512-10DE9ONho06QORKAaCBpPiFCdW+tZJuY/84tyypGtl6r+/C7Asq0dhqbRZURuUlLQtZxxDvT8eoj8cGW0ha6Bg==",
+      "version": "8.9.0",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.9.0.tgz",
+      "integrity": "sha512-rwkXfOs9zmoHrV8xE++dmNd6ZIS+nmHHCxcV53ekGJrxFLMbp+pizpPS07ARvhwneCIECPppOwbZHvw9sQtU4w==",
       "dev": true,
       "requires": {
         "arg": "^4.1.0",
         "diff": "^4.0.1",
         "make-error": "^1.1.1",
-        "source-map-support": "^0.5.6",
+        "source-map-support": "^0.5.17",
         "yn": "3.1.1"
       }
     },
@@ -7777,6 +7928,16 @@
         }
       }
     },
+    "validate-npm-package-license": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+      "dev": true,
+      "requires": {
+        "spdx-correct": "^3.0.0",
+        "spdx-expression-parse": "^3.0.0"
+      }
+    },
     "verror": {
       "version": "1.10.0",
       "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
@@ -7988,9 +8149,9 @@
       }
     },
     "yargs-parser": {
-      "version": "18.1.2",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.2.tgz",
-      "integrity": "sha512-hlIPNR3IzC1YuL1c2UwwDKpXlNFBqD1Fswwh1khz5+d8Cq/8yc/Mn0i+rQXduu8hcrFKvO7Eryk+09NecTQAAQ==",
+      "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",
diff --git a/package.json b/package.json
index 0d8864bf..22cb729e 100644
--- a/package.json
+++ b/package.json
@@ -1,14 +1,15 @@
 {
   "name": "darkreader",
-  "version": "4.9.4",
+  "version": "4.9.7",
   "description": "Dark theme for every website",
   "scripts": {
     "api": "node -e \"require('./tasks/bundle-api')()\"",
-    "code-style": "eslint --fix 'src/**/*.ts' 'src/**/*.tsx' 'tasks/**/*.js' 'tests/**/*.ts' 'index.d.ts'",
+    "code-style": "eslint --fix \"src/**/*.ts\" \"src/**/*.tsx\" \"tasks/**/*.js\" \"tests/**/*.ts\" \"index.d.ts\"",
     "debug": "node tasks/debug.js",
     "prepublishOnly": "npm test && npm run api",
     "release": "npm test && node tasks/release.js",
-    "test": "jest --config=tests/jest.config.js"
+    "test": "jest --config=tests/jest.config.js",
+    "test:inject": "jest --config=tests/inject/jest.config.js"
   },
   "main": "darkreader.js",
   "repository": {
@@ -29,26 +30,26 @@
     "malevic": "0.18.2"
   },
   "devDependencies": {
-    "@types/chrome": "0.0.103",
-    "@types/jest": "25.1.4",
-    "@types/node": "13.9.5",
-    "@typescript-eslint/eslint-plugin": "2.25.0",
-    "@typescript-eslint/parser": "2.25.0",
+    "@types/chrome": "0.0.104",
+    "@types/jest": "25.2.1",
+    "@types/node": "13.13.2",
+    "@typescript-eslint/eslint-plugin": "2.29.0",
+    "@typescript-eslint/parser": "2.29.0",
     "chokidar": "3.3.1",
     "eslint": "6.8.0",
     "eslint-plugin-local": "1.0.0",
     "fs-extra": "9.0.0",
     "globby": "11.0.0",
-    "jest": "25.2.4",
+    "jest": "25.4.0",
     "less": "3.11.1",
-    "prettier": "2.0.2",
-    "rollup": "2.3.0",
+    "prettier": "2.0.5",
+    "rollup": "2.7.2",
     "rollup-plugin-commonjs": "10.1.0",
     "rollup-plugin-node-resolve": "5.2.0",
     "rollup-plugin-replace": "2.2.0",
     "rollup-plugin-typescript2": "0.27.0",
-    "ts-jest": "25.3.0",
-    "ts-node": "8.8.1",
+    "ts-jest": "25.4.0",
+    "ts-node": "8.9.0",
     "tsconfig-paths": "3.9.0",
     "typescript": "3.8.3",
     "ws": "7.2.3",
diff --git a/src/_locales/he.config b/src/_locales/he.config
new file mode 100644
index 00000000..330f27b8
--- /dev/null
+++ b/src/_locales/he.config
@@ -0,0 +1,183 @@
+@extension_description
+מצב אפל לכל אתר. תשמור על העיניים שלך, השתמש בעיצוב כהה לגלישה בלילה או אפי' ביום.
+
+@loading_please_wait
+טוען... נא המתן
+
+
+#==== Top section ====
+
+@on
+פעיל
+
+@off
+כבוי
+
+@toggle_current_site
+הוסף/הסר אתר נוכחי מהרשימה
+
+@setup_hotkey_toggle_site
+הוסף/הסר אתר נוכחי מהרשימה
+הגדר מקש קיצור
+
+@toggle_extension
+הפעל/כבה את התוסף
+
+@setup_hotkey_toggle_extension
+הפעל/כבה את התוסף
+הגדר מקש קיצור
+
+@automation
+הפעלה אוטומטית:
+
+@set_active_hours
+הגדר שעות פעילות
+
+@set_location
+הפעל לאחר השקיעה במיקום זה
+
+@longitude
+קו אורך
+
+@latitude
+קו רוחב
+
+@page_protected
+דף זה מוגן
+על ידי הדפדפן
+
+@page_in_dark_list
+אתר זה נמצא
+ברשימה אפלה גלובלית
+
+@system_dark_mode
+השתמש בסכמת הצבעים של המערכת
+
+@system_dark_mode_description
+הפעל כאשר מצב החשכה של המערכת פועל
+
+
+#==== Filter ====
+
+@filter
+מסנן
+
+@mode
+מצב
+
+@dark
+אפל
+
+@light
+מואר
+
+@brightness
+בהירות
+
+@contrast
+ניגודיות
+
+@grayscale
+גווני אפור
+
+@sepia
+גווני חום-אדמדם
+
+@only_for
+רק עבור
+
+@only_for_description
+החל הגדרות באתר הנוכחי בלבד
+
+
+#==== Site list ====
+
+@site_list
+רשימת אתרים
+
+@invert_listed_only
+רק מה שברשימה
+
+@not_invert_listed
+רק מה שלא ברשימה
+
+@add_site_to_list
+הוסף אתר נוכחי לרשימה
+
+@setup_add_site_hotkey
+הגדר מקש קיצור להוספת אתר
+
+
+#==== More settings ====
+
+@more
+עוד
+
+@select_font
+בחר גופן
+
+@text_stroke
+מריחת טקסט
+
+@try_experimental_theme_engines
+נסה מנועי ערכת נושא ניסיוניים:
+פילטר + שומר על רוויה בצבעים, משתמש ב- GPU
+נושא סטטי מייצר נושא מהיר פשוט
+נושא דינמי מנתח צבעים ותמונות
+
+@engine_filter
+מסנן
+
+@engine_filter_plus
+מסנן+
+
+@engine_static
+סטטי
+
+@engine_dynamic
+דינמי
+
+@theme_generation_mode
+מצב יצירת ערכת נושא
+
+@custom_browser_theme_on
+מותאם אישית
+
+@custom_browser_theme_off
+ברירת מחדל
+
+@change_browser_theme
+שנה את ערכת נושא הדפדפן
+
+
+#==== Footer ====
+
+@privacy
+פרטיות
+
+@help
+עזרה
+
+@donate
+לתרום
+
+@news
+חדשות
+
+@read_more
+קרא עוד
+
+@open_dev_tools
+Dev tools
+
+
+#==== Store listing ====
+
+@store_listing
+תוסף טיפוח לעיניים זה מאפשר למצב לילה ליצור ערכות נושא כהות לאתרי אינטרנט גלישה. קורא כהה ממיר צבעים בהירים מה שהופך אותם לניגודיות גבוהה וקל לקריאה בלילה.
+
+ניתן להתאים את הבהירות, הניגודיות, מסנן חום-אדמדם, מצב כהה, הגדרות גופן ורשימת אתרים להתעלמות.
+
+Reader Dark אינו מציג מודעות ואינו שולח את נתוני המשתמש לשום מקום. זהו קוד פתוח לחלוטין https://github.com/darkreader/darkreader
+
+לצורך פעולה תקינה, השבת תוספים דומים. צפייה נעימה!
diff --git a/src/_locales/zh-CN.config b/src/_locales/zh-CN.config
index b0387231..f45ecf70 100644
--- a/src/_locales/zh-CN.config
+++ b/src/_locales/zh-CN.config
@@ -1,5 +1,5 @@
 @extension_description
-黑色主题，适用于任何网站。关爱眼睛，就使用Dark Reader进行夜间和日间浏览。
+适用于任何网站的黑色主题。关爱眼睛，就使用Dark Reader进行日常浏览。
 
 @loading_please_wait
 加载中，请稍候
@@ -84,7 +84,7 @@
 棕褐色滤镜
 
 @only_for
-仅适用于
+仅用于
 
 @only_for_description
 仅将设置应用于当前网站
@@ -122,7 +122,7 @@
 @try_experimental_theme_engines
 试用**实验**主题引擎：
 **滤镜+**保留颜色饱和度，使用GPU
-**静态主题**生成一个简单的快速主题
+**静态主题**快速生成一个简单的主题
 **动态主题**分析颜色和图像
 
 @engine_filter
@@ -174,10 +174,10 @@
 #==== Store listing ====
 
 @store_listing
-这是一个护眼扩展程序，通过实时生成黑色主题，为每一个网站启用夜间模式。 Dark Reader反转明亮的颜色，使其网页内容具有高对比度并且在易于夜间阅读。
+这是一个护眼扩展程序，通过实时生成黑色主题，为每一个网站启用夜间模式。 Dark Reader反转明亮的颜色，使网页内容具有高对比度并易于在夜间阅读。
 
 您可以调整亮度、对比度，应用棕褐色滤镜、黑暗模式，设置字体和忽略的网站列表。
 
-Dark Reader无广告，也不会在任何地方发送用户的数据。它完全开源 https://github.com/darkreader/darkreader
+Dark Reader无广告，也不会向任何地方发送用户的数据。它完全开源 https://github.com/darkreader/darkreader
 
 安装前请禁用类似的扩展。冲浪愉快！
diff --git a/src/background/user-storage.ts b/src/background/user-storage.ts
index 2481f87a..e2fdfacb 100644
--- a/src/background/user-storage.ts
+++ b/src/background/user-storage.ts
@@ -38,7 +38,9 @@ export default class UserStorage {
             location: {
                 latitude: null,
                 longitude: null,
-            }
+            },
+            previewNewDesign: false,
+            enableForPDF: true,
         };
         this.settings = null;
     }
diff --git a/src/background/utils/extension-api.ts b/src/background/utils/extension-api.ts
index bc73016d..10e0dc75 100644
--- a/src/background/utils/extension-api.ts
+++ b/src/background/utils/extension-api.ts
@@ -13,6 +13,7 @@ export function canInjectScript(url: string) {
             && !url.startsWith('moz')
             && !url.startsWith('view-source:')
             && !url.startsWith('https://addons.mozilla.org')
+            && !url.endsWith('.pdf')
         );
     }
     if (isEdge()) {
@@ -20,6 +21,7 @@ export function canInjectScript(url: string) {
             && !url.startsWith('chrome')
             && !url.startsWith('edge')
             && !url.startsWith('https://chrome.google.com/webstore')
+            && !url.startsWith('https://microsoftedge.microsoft.com/addons')
         );
     }
     return (url
diff --git a/src/config/dark-sites.config b/src/config/dark-sites.config
index 78aa3bbc..f0992af6 100644
--- a/src/config/dark-sites.config
+++ b/src/config/dark-sites.config
@@ -39,6 +39,7 @@ broadcasthe.net
 bungie.net
 byte.co
 caniuse.com
+captaindisillusion.com
 caracal.club
 checkra.in
 chessbomb.com
@@ -94,10 +95,12 @@ energized.pro
 enlightenment.org
 entity.works
 envs.net
+epicgames.com
 erai-raws.info
 esportal.com
 eternal.abimon.org
 faceit.com
+factorio.com
 femto.pw
 filterblade.xyz
 flooxer.com
@@ -106,6 +109,7 @@ forum.snahp.it
 frankerfacez.com
 gamebanana.com
 gamejolt.com
+gatsbyjs.org
 geekabit.nl
 geektyper.com
 getsharex.com
@@ -119,6 +123,7 @@ glowing-bear.org
 gogoanime.se
 graydon2.dreamwidth.org
 greenmangaming.com
+groovy.bot
 gunshipmusic.com
 hackaday.com
 hackaday.io
@@ -146,6 +151,8 @@ jsfiddle.net
 killtheradio.net
 kissasian.*
 kissmanga.com
+knockout.chat
+kodenames.io
 lainchan.org
 letterboxd.com
 linux.org.ru
@@ -211,16 +218,20 @@ snazzah.com
 spacebattles.com
 spacespacespaaace.space
 speedtest.net
+star-made.org
+starmadedock.net
 staszic.waw.pl
 statbot.net
 steam.tv
 steamcharts.com
 steamcommunity.com
 steamstat.us
+steamtimeidler.com
 store.steampowered.com
 streamelements.com
 streamlabs.com
 sufficientvelocity.com
+supinic.com
 svtplay.se
 takethewalk.net
 tallguysfree.com
@@ -235,6 +246,7 @@ tilde.club
 tilde.institute
 tilde.team
 tildeverse.org
+tio.run
 toneden.io
 totalwarwarhammer.gamepedia.com
 trellobot.xyz
@@ -257,7 +269,6 @@ w0rp.com
 w41k3r.com
 warcraftdaily.com
 weboas.is
-wiki.factorio.com
 wowhead.com
 wowinterface.com
 www.directvnow.com
diff --git a/src/config/dynamic-theme-fixes.config b/src/config/dynamic-theme-fixes.config
index a4262653..e58e803a 100644
--- a/src/config/dynamic-theme-fixes.config
+++ b/src/config/dynamic-theme-fixes.config
@@ -2,6 +2,7 @@
 
 INVERT
 .jfk-bubble
+embed[type="application/pdf"]
 
 CSS
 .vimvixen-hint {
@@ -15,6 +16,58 @@ CSS
 
 ================================
 
+*.stackexchange.com
+askubuntu.com
+mathoverflow.net
+serverfault.com
+stackapps.com
+stackexchange.com
+stackoverflow.com
+superuser.com
+
+INVERT
+._glyph
+.favicon-mathoverflow
+.favicon-mathoverflowmeta
+.favicon-stackoverflowmeta
+.h-auto[alt="Academia"]
+.h-auto[alt="Anime & Manga"]
+.h-auto[alt="Ask Different"]
+.h-auto[alt="Aviation"]
+.h-auto[alt="Code Review"]
+.h-auto[alt="Electrical Engineering"]
+.h-auto[alt="English Language Learners"]
+.h-auto[alt="Japanese Language"]
+.h-auto[alt="MathOverflow"]
+.h-auto[alt="Mathematics"]
+.h-auto[alt="Server Fault"]
+.h-auto[alt="Skeptics"]
+.h-auto[alt="Software Engineering"]
+.h-auto[alt="Stack Apps"]
+.h-auto[alt="Super User"]
+.h-auto[alt="The Workplace"]
+.h-auto[alt="Theoretical Computer Science"]
+.h-auto[alt="Unix & Linux"]
+.h-auto[alt="Web Applications"]
+a.js-gps-track::before
+img[alt="The Stack Exchange Network"]
+
+CSS
+body {
+    background-image: none !important;
+}
+.profile-cards--graph {
+    background-image: repeating-linear-gradient(0deg, transparent, transparent 13px, ${#e4e6e8} -13px, ${#e4e6e8} 21px) !important;
+}
+.c-pointer {
+    color: grey !important;
+}
+.js-accepted-answer-indicator.fc-green-500 {
+    color: var(--green) !important;
+}
+
+================================
+
 01net.com
 
 CSS
@@ -30,6 +83,9 @@ CSS
 body {
     background-image: none;
 }
+#speedtest-main .hide-time {
+    color: transparent !important;
+}
 #inputfield {
     color: #333 !important;
 }
@@ -103,16 +159,18 @@ CSS
 allegro.pl
 
 CSS
-._88e3e06 {
+#opbox-listing--base i {
     background-size: 100% 100% !important;
 }
 
 ================================
 
 amazon.com
+amazon.co.uk
 
 INVERT
 #banner-image
+#ordersContainer .a-box.order-attributes img
 
 CSS
 .banner-border {
@@ -120,6 +178,10 @@ CSS
     background-color: ${white} !important;
 }
 
+img {
+    border-radius: 5% !important;
+}
+
 ================================
 
 angrymetalguy.com
@@ -221,23 +283,6 @@ CSS
 
 ================================
 
-askubuntu.com
-*.stackexchange.com
-
-CSS
-body {
-  background-image: none !important;
-}
-.profile-cards--graph .line {
-    stroke: Green;
-    fill: none;
-}
-.fc-light {
-    background-color: #181a1b;
-}
-
-================================
-
 atcoder.jp
 
 CSS
@@ -256,6 +301,11 @@ img[alt^="WEB_FreeTier"]
 .lb-is-lazyloaded
 .lb-none-v-margin.lb-img
 
+CSS
+.header-background {
+  fill: none !important;
+}
+
 ================================
 
 baike.baidu.com
@@ -440,6 +490,7 @@ INVERT
 .roundbox-rt
 .roundbox-lb
 .roundbox-rb
+.delete-resource-link
 
 ================================
 
@@ -451,6 +502,23 @@ INVERT
 
 ================================
 
+coolblue.be
+coolblue.nl
+hotorangemedia.nl
+
+CSS
+path[fill="#F60"] {
+    --darkreader-inline-fill: #F60 !important
+}
+path[fill="#FFF"] {
+    --darkreader-inline-fill: #FFF !important
+}
+path[fill="#285DAB"] {
+    --darkreader-inline-fill: #285DAB !important
+}
+
+================================
+
 coopgames.eu
 
 INVERT
@@ -550,6 +618,20 @@ INVERT
 
 ================================
 
+dev.to
+
+INVERT
+img[src$=".svg"]
+
+CSS
+body, h1, h2, h3,
+h4, h5, h6, a,
+.content-classification-text {
+    color: #e8e6e3 !important;
+}
+
+================================
+
 developer.mozilla.org
 
 INVERT
@@ -601,6 +683,7 @@ INVERT
 .link-management-drop-down-icon
 .vs-icon
 .vpc-icon
+.docs-analytics-img
 
 CSS
 .docs-preview-palette-item {
@@ -619,6 +702,12 @@ CSS
 .ia-invite-controls-area {
     background-color: transparent !important
 }
+.docs-gm .docs-revisions-switch .apps-ui-material-slide-toggle-thumb {
+    background-color: rgb(43, 46, 48) !important;
+}
+.docs-gm .docs-revisions-switch.apps-ui-material-slide-toggle-container-checked .apps-ui-material-slide-toggle-thumb {
+    background-color: rgb(9, 64, 155) !important;
+}
 
 ================================
 
@@ -671,12 +760,12 @@ INVERT
 duolingo.com
 
 INVERT
-.qLLbC
-._2boWj
+.Z392z
+._24NNT
 
 CSS
-._1gz3r{
-  opacity: 0.5;
+._2OVuy{
+  opacity: 0.3;
 }
 
 ================================
@@ -710,6 +799,16 @@ endomondo.com
 INVERT
 .header-shop-logo
 .footer-shop-logo
+.eoFeedWorkout-map-image
+.workoutMap img[src*="maps"]
+
+CSS
+.highcharts-background{
+    fill: rgb(24, 26, 27) !important;
+}
+#highcharts-0 text{
+    text-shadow: none !important;
+}
 
 ================================
 
@@ -773,8 +872,11 @@ INVERT
 .sp_V53xxlprDHX_1_5x
 .sp_V53xxlprDHX_2x
 #pagelet_ego_pane button .img._3-8_
+#homepage_panel_promote_footer_pagelet button .img._3-8_
 #event_tabs #reaction_units span img
-#homepage_panel_promote_footer_pagelet i
+.fbPlaceFlyoutWrap img
+img[src*="map"]
+[style*="map"]
 
 CSS
 .fbNubButton {
@@ -905,29 +1007,10 @@ INVERT
 .detail-data-panel__icon
 .sleep-chart-yaxis.end
 .supergraph-canvas
+.leaflet-pane.leaflet-map-pane img:not([src*="satellite"])
+.zone1desc
 
 CSS
-.highlight {
-    color: ${#ffffff} !important;
-}
-.altitudetitle {
-    color: ${#ffffff} !important;
-}
-.altdescmax {
-    color: ${#ffffff} !important;
-}
-.altdescmin {
-    color: ${#ffffff} !important;
-}
-.zonedesctitle {
-    color: ${#ffffff} !important;
-}
-.zonedescmax {
-    color: ${#ffffff} !important;
-}
-.zonedesclight {
-    color: ${#ffffff} !important;
-}
 .highcharts-container svg {
     fill: ${#3f3f3f} !important;
 }
@@ -935,6 +1018,9 @@ CSS
     background-color: rgba(255, 255, 255, 0.15) !important;
     background-blend-mode: color;
 }
+.zone1desc {
+    color: ${#ffffff} !important;
+}
 
 ================================
 
@@ -1016,13 +1102,6 @@ a[href="https://github.com"]
 
 github.com
 
-INVERT
-.octotree-sidebar
-.cc-pr__logo
-.cc-octicon
-#network canvas
-img.network-tree
-
 CSS
 .markdown-body code,
 .markdown-body pre {
@@ -1092,6 +1171,9 @@ CSS
     background-color: rgb(28, 30, 31) !important;
     color: darkgrey !important;
 }
+.jfk-bubble, .octotree-sidebar, .cc-pr__logo, .cc-octicon, #network canvas, img.network-tree {
+    filter: invert(94.4%) hue-rotate(180deg) contrast(90%) !important;
+}
 
 ================================
 
@@ -1149,7 +1231,16 @@ a.gb_xc
 .i4ewOd-LQLjdd li::before
 .un1lmc-j4gsHd
 .maps-sprite-settings-languages
-.gb_D.gb_qc
+a[href*="about/products"]
+
+================================
+
+grubhub.com
+
+CSS
+.s-checkbox-filler {
+    color: rgb(24, 26, 27) !important;
+}
 
 ================================
 
@@ -1248,6 +1339,13 @@ span[role="presentation"] > .cm-variable-2 {
 
 ================================
 
+hootsuite.com
+
+INVERT
+img[src$="hootsuite_white_form3.png"]
+
+================================
+
 imdb.com
 
 CSS
@@ -1376,6 +1474,7 @@ instructure.com
 
 INVERT
 .title_3bek::after
+.equation_image
 
 ================================
 
@@ -1394,6 +1493,22 @@ CSS
 
 ================================
 
+isbgpsafeyet.com
+
+CSS
+h1, h2, h3,
+h4, h5, h6 {
+    color: rgb(255, 255, 255) !important;
+}
+.Hero, .Footer {
+    background: None !important;
+}
+.Button-is-primary {
+    background: var(--primary-background-color);
+}
+
+================================
+
 jailbreak.fce365.info
 
 CSS
@@ -1436,6 +1551,21 @@ h1.logo
 
 ================================
 
+journal.tinkoff.ru
+
+INVERT
+.g2tvv
+._3aEco
+._1Dhxk
+.uVy35.V6dif::before
+._38Vkx.FrrKu::after
+._3LO60._4GqdT::after
+.PwECA
+.best-authors__arrow.best-authors__arrow--active
+.best-authors__arrow
+
+================================
+
 keep.google.com
 
 INVERT
@@ -1497,6 +1627,30 @@ CSS
 
 ================================
 
+lichess.org
+
+CSS
+.is2d .pawn.black {
+    background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PHBhdGggZD0iTTIyLjUgOWMtMi4yMSAwLTQgMS43OS00IDQgMCAuODkuMjkgMS43MS43OCAyLjM4QzE3LjMzIDE2LjUgMTYgMTguNTkgMTYgMjFjMCAyLjAzLjk0IDMuODQgMi40MSA1LjAzLTMgMS4wNi03LjQxIDUuNTUtNy40MSAxMy40N2gyM2MwLTcuOTItNC40MS0xMi40MS03LjQxLTEzLjQ3IDEuNDctMS4xOSAyLjQxLTMgMi40MS01LjAzIDAtMi40MS0xLjMzLTQuNS0zLjI4LTUuNjIuNDktLjY3Ljc4LTEuNDkuNzgtMi4zOCAwLTIuMjEtMS43OS00LTQtNHoiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIvPjwvc3ZnPg==') !important
+}
+.is2d .knight.black {
+    background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0yMiAxMGMxMC41IDEgMTYuNSA4IDE2IDI5SDE1YzAtOSAxMC02LjUgOC0yMSIgZmlsbD0iIzAwMCIvPjxwYXRoIGQ9Ik0yNCAxOGMuMzggMi45MS01LjU1IDcuMzctOCA5LTMgMi0yLjgyIDQuMzQtNSA0LTEuMDQyLS45NCAxLjQxLTMuMDQgMC0zLTEgMCAuMTkgMS4yMy0xIDItMSAwLTQuMDAzIDEtNC00IDAtMiA2LTEyIDYtMTJzMS44OS0xLjkgMi0zLjVjLS43My0uOTk0LS41LTItLjUtMyAxLTEgMyAyLjUgMyAyLjVoMnMuNzgtMS45OTIgMi41LTNjMSAwIDEgMyAxIDMiIGZpbGw9IiMwMDAiLz48cGF0aCBkPSJNOS41IDI1LjVhLjUuNSAwIDEgMS0xIDAgLjUuNSAwIDEgMSAxIDB6bTUuNDMzLTkuNzVhLjUgMS41IDMwIDEgMS0uODY2LS41LjUgMS41IDMwIDEgMSAuODY2LjV6IiBmaWxsPSIjZWNlY2VjIiBzdHJva2U9IiNlY2VjZWMiLz48cGF0aCBkPSJNMjQuNTUgMTAuNGwtLjQ1IDEuNDUuNS4xNWMzLjE1IDEgNS42NSAyLjQ5IDcuOSA2Ljc1UzM1Ljc1IDI5LjA2IDM1LjI1IDM5bC0uMDUuNWgyLjI1bC4wNS0uNWMuNS0xMC4wNi0uODgtMTYuODUtMy4yNS0yMS4zNC0yLjM3LTQuNDktNS43OS02LjY0LTkuMTktNy4xNmwtLjUxLS4xeiIgZmlsbD0iI2VjZWNlYyIgc3Ryb2tlPSJub25lIi8+PC9nPjwvc3ZnPg==') !important
+}
+.is2d .bishop.black {
+    background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxnIGZpbGw9IiMwMDAiIHN0cm9rZS1saW5lY2FwPSJidXR0Ij48cGF0aCBkPSJNOSAzNmMzLjM5LS45NyAxMC4xMS40MyAxMy41LTIgMy4zOSAyLjQzIDEwLjExIDEuMDMgMTMuNSAyIDAgMCAxLjY1LjU0IDMgMi0uNjguOTctMS42NS45OS0zIC41LTMuMzktLjk3LTEwLjExLjQ2LTEzLjUtMS0zLjM5IDEuNDYtMTAuMTEuMDMtMTMuNSAxLTEuMzU0LjQ5LTIuMzIzLjQ3LTMtLjUgMS4zNTQtMS45NCAzLTIgMy0yeiIvPjxwYXRoIGQ9Ik0xNSAzMmMyLjUgMi41IDEyLjUgMi41IDE1IDAgLjUtMS41IDAtMiAwLTIgMC0yLjUtMi41LTQtMi41LTQgNS41LTEuNSA2LTExLjUtNS0xNS41LTExIDQtMTAuNSAxNC01IDE1LjUgMCAwLTIuNSAxLjUtMi41IDQgMCAwLS41LjUgMCAyeiIvPjxwYXRoIGQ9Ik0yNSA4YTIuNSAyLjUgMCAxIDEtNSAwIDIuNSAyLjUgMCAxIDEgNSAweiIvPjwvZz48cGF0aCBkPSJNMTcuNSAyNmgxME0xNSAzMGgxNW0tNy41LTE0LjV2NU0yMCAxOGg1IiBzdHJva2U9IiNlY2VjZWMiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiLz48L2c+PC9zdmc+') !important
+}
+.is2d .rook.black {
+    background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PGcgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik05IDM5aDI3di0zSDl2M3ptMy41LTdsMS41LTIuNWgxN2wxLjUgMi41aC0yMHptLS41IDR2LTRoMjF2NEgxMnoiIHN0cm9rZS1saW5lY2FwPSJidXR0Ii8+PHBhdGggZD0iTTE0IDI5LjV2LTEzaDE3djEzSDE0eiIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiLz48cGF0aCBkPSJNMTQgMTYuNUwxMSAxNGgyM2wtMyAyLjVIMTR6TTExIDE0VjloNHYyaDVWOWg1djJoNVY5aDR2NUgxMXoiIHN0cm9rZS1saW5lY2FwPSJidXR0Ii8+PHBhdGggZD0iTTEyIDM1LjVoMjFtLTIwLTRoMTltLTE4LTJoMTdtLTE3LTEzaDE3TTExIDE0aDIzIiBmaWxsPSJub25lIiBzdHJva2U9IiNlY2VjZWMiIHN0cm9rZS13aWR0aD0iMSIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIvPjwvZz48L3N2Zz4=') !important
+}
+.is2d .queen.black {
+    background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PGcgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxnIHN0cm9rZT0ibm9uZSI+PGNpcmNsZSBjeD0iNiIgY3k9IjEyIiByPSIyLjc1Ii8+PGNpcmNsZSBjeD0iMTQiIGN5PSI5IiByPSIyLjc1Ii8+PGNpcmNsZSBjeD0iMjIuNSIgY3k9IjgiIHI9IjIuNzUiLz48Y2lyY2xlIGN4PSIzMSIgY3k9IjkiIHI9IjIuNzUiLz48Y2lyY2xlIGN4PSIzOSIgY3k9IjEyIiByPSIyLjc1Ii8+PC9nPjxwYXRoIGQ9Ik05IDI2YzguNS0xLjUgMjEtMS41IDI3IDBsMi41LTEyLjVMMzEgMjVsLS4zLTE0LjEtNS4yIDEzLjYtMy0xNC41LTMgMTQuNS01LjItMTMuNkwxNCAyNSA2LjUgMTMuNSA5IDI2eiIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNOSAyNmMwIDIgMS41IDIgMi41IDQgMSAxLjUgMSAxIC41IDMuNS0xLjUgMS0xLjUgMi41LTEuNSAyLjUtMS41IDEuNS41IDIuNS41IDIuNSA2LjUgMSAxNi41IDEgMjMgMCAwIDAgMS41LTEgMC0yLjUgMCAwIC41LTEuNS0xLTIuNS0uNS0yLjUtLjUtMiAuNS0zLjUgMS0yIDIuNS0yIDIuNS00LTguNS0xLjUtMTguNS0xLjUtMjcgMHoiIHN0cm9rZS1saW5lY2FwPSJidXR0Ii8+PHBhdGggZD0iTTExIDM4LjVhMzUgMzUgMSAwIDAgMjMgMCIgZmlsbD0ibm9uZSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiLz48cGF0aCBkPSJNMTEgMjlhMzUgMzUgMSAwIDEgMjMgMG0tMjEuNSAyLjVoMjBtLTIxIDNhMzUgMzUgMSAwIDAgMjIgMG0tMjMgM2EzNSAzNSAxIDAgMCAyNCAwIiBmaWxsPSJub25lIiBzdHJva2U9IiNlY2VjZWMiLz48L2c+PC9zdmc+') !important
+}
+.is2d .king.black {
+    background-image:url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0NSIgaGVpZ2h0PSI0NSI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMS41IiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjxwYXRoIGQ9Ik0yMi41IDExLjYzVjYiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiLz48cGF0aCBkPSJNMjIuNSAyNXM0LjUtNy41IDMtMTAuNWMwIDAtMS0yLjUtMy0yLjVzLTMgMi41LTMgMi41Yy0xLjUgMyAzIDEwLjUgMyAxMC41IiBmaWxsPSIjMDAwIiBzdHJva2UtbGluZWNhcD0iYnV0dCIgc3Ryb2tlLWxpbmVqb2luPSJtaXRlciIvPjxwYXRoIGQ9Ik0xMS41IDM3YzUuNSAzLjUgMTUuNSAzLjUgMjEgMHYtN3M5LTQuNSA2LTEwLjVjLTQtNi41LTEzLjUtMy41LTE2IDRWMjd2LTMuNWMtMy41LTcuNS0xMy0xMC41LTE2LTQtMyA2IDUgMTAgNSAxMFYzN3oiIGZpbGw9IiMwMDAiLz48cGF0aCBkPSJNMjAgOGg1IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIi8+PHBhdGggZD0iTTMyIDI5LjVzOC41LTQgNi4wMy05LjY1QzM0LjE1IDE0IDI1IDE4IDIyLjUgMjQuNWwuMDEgMi4xLS4wMS0yLjFDMjAgMTggOS45MDYgMTQgNi45OTcgMTkuODVjLTIuNDk3IDUuNjUgNC44NTMgOSA0Ljg1MyA5IiBzdHJva2U9IiNlY2VjZWMiLz48cGF0aCBkPSJNMTEuNSAzMGM1LjUtMyAxNS41LTMgMjEgMG0tMjEgMy41YzUuNS0zIDE1LjUtMyAyMSAwbS0yMSAzLjVjNS41LTMgMTUuNS0zIDIxIDAiIHN0cm9rZT0iI2VjZWNlYyIvPjwvZz48L3N2Zz4=') !important
+}
+
+================================
+
 linkedin.com
 
 CSS
@@ -1505,7 +1659,8 @@ CSS
     background-blend-mode: color;
 }
 .global-footer-compact__linkedin-logo,
-li-icon[type="linkedin-logo"] {
+li-icon[type="linkedin-logo"],
+.bug-text-color {
     fill: ${black} !important;
 }
 
@@ -1538,6 +1693,30 @@ img.Ha
 .ita-icon-0
 .gb_df
 img[src$="google_gsuite"]
+.rY>.sa
+.buh
+
+CSS
+@media (min-resolution: 144dpi), (-webkit-min-device-pixel-ratio: 1.5) {
+    .buk {
+        background-image: url(//ssl.gstatic.com/ui/v1/icons/mail/rfr/density_default_v1_2x.png) !important;
+    }
+    .bui {
+        background-image: url(//ssl.gstatic.com/ui/v1/icons/mail/rfr/density_comfortable_v1_2x.png) !important;
+    }
+    .buj {
+        background-image: url(//ssl.gstatic.com/ui/v1/icons/mail/rfr/density_compact_v1_2x.png) !important;
+    }
+}
+.buk {
+    background-image: url(//ssl.gstatic.com/ui/v1/icons/mail/rfr/density_default_v1_1x.png) !important;
+}
+.bui {
+    background-image: url(//ssl.gstatic.com/ui/v1/icons/mail/rfr/density_comfortable_v1_1x.png) !important;
+}
+.buj {
+    background-image: url(//ssl.gstatic.com/ui/v1/icons/mail/rfr/density_compact_v1_1x.png) !important;
+}
 
 ================================
 
@@ -1562,6 +1741,13 @@ nav {
 
 ================================
 
+marinij.com
+
+INVERT
+.custom-logo.logo > a > img
+
+================================
+
 marketplace.visualstudio.com
 
 CSS
@@ -1666,18 +1852,6 @@ CSS
 
 ================================
 
-meta.stackoverflow.com
-
-INVERT
-._glyph
-
-CSS
-.c-pointer{
-    color: gray;
-}
-
-================================
-
 metacritic.com
 
 INVERT
@@ -1735,12 +1909,22 @@ INVERT
 img[src="https://bi.im-g.pl/im/0/24525/m24525630.png"]
 
 CSS
-.main_wrapper {
+.main_wrapper,
+.top_section_bg, .bottom_section_bg {
     background-color: ${#e5e5e5} !important;
 }
 
 ================================
 
+mullvad.net
+
+CSS
+#bg {
+    fill: #192E45;
+}
+
+================================
+
 my.nintendo.com
 
 CSS
@@ -1760,6 +1944,16 @@ INVERT
 
 ================================
 
+neowin.net
+
+CSS
+.select option {
+    background-color: #1c1e1f !important;
+    color: white !important;
+}
+
+================================
+
 news.ycombinator.com
 
 INVERT
@@ -1803,6 +1997,8 @@ header a[href="/"] svg
 #customers_panel img[src*="conde-nast.full.png"]
 #customers_panel img[src*="netflix.full.png"]
 #customers_panel img[src*="visa.full.png"]
+._5532dff2
+._93bbf0b4
 
 ================================
 
@@ -1993,6 +2189,22 @@ CSS
 
 ================================
 
+openstreetmap.org
+
+INVERT
+.map-layout #map
+
+CSS
+div[dir="ltr", id="map"] {
+    filter: none !important;
+    background: #000 !important;
+}
+.map-layout #map {
+    background-color: ${#1b1b1b} !important;
+}
+
+================================
+
 overleaf.com
 
 INVERT
@@ -2000,6 +2212,15 @@ INVERT
 
 ================================
 
+ozbargain.com.au
+
+CSS
+div.comment-op {
+    background-image: linear-gradient(#000000, #212121) !important;
+}
+
+================================
+
 pgatour.com
 
 CSS
@@ -2016,7 +2237,7 @@ INVERT
 .bUWb7c
 .WF1WQd
 img[src="https://www.gstatic.com/android/market_images/web/play_prism_hlock_2x.png"]
-.gb_D.gb_qc
+a[href*="about/products"]
 
 ================================
 
@@ -2035,7 +2256,7 @@ plus.google.com
 
 INVERT
 a.gb_b > div
-.gb_D.gb_qc
+a[href*="about/products"]
 
 ================================
 
@@ -2114,6 +2335,7 @@ pyszne.pl
 INVERT
 .css-16gj3o1
 .css-13azwyo
+.gm-style
 
 CSS
 .cover, .logowrapper, .restaurant-logo__inner, .orderoverview__restaurant-image-container-inner {
@@ -2404,6 +2626,15 @@ CSS
 
 ================================
 
+softorage.com
+
+CSS
+.tg {
+    background-image: linear-gradient(36deg,#fc466b,#3f5efb) !important;
+}
+
+================================
+
 soundcloud.com
 
 INVERT
@@ -2443,24 +2674,14 @@ CSS
 
 ================================
 
-stackoverflow.com
+sport.pl
 
 INVERT
-._glyph
-.h-auto
-.favicon
-a.js-gps-track::before
+#pageHead img
 
 CSS
-.profile-cards--graph .line {
-    stroke: Green;
-    fill: none;
-}
-.fc-light {
-    background-color: transparent !important;
-}
-.fs-headline1 {
-    color: white;
+.top_section_bg, .bottom_section_bg {
+    background: ${#e5e5e5} !important;
 }
 
 ================================
@@ -2613,23 +2834,6 @@ body {
 
 ================================
 
-superuser.com
-
-INVERT
-.h-auto
-.favicon
-
-CSS
-.profile-cards--graph .line {
-    stroke: Green;
-    fill: none;
-}
-.fc-light {
-    background-color: #181a1b;
-}
-
-================================
-
 support.discordapp.com
 
 INVERT
@@ -3111,21 +3315,24 @@ CSS
 web.whatsapp.com
 
 INVERT
-.tail-container
 .selectable-text > span._3PxOr
 
 CSS
-._1pw2F {
-    border-color: white !important;
-    border-width: 15px !important;
-    border-style: solid !important;
-}
-._2RT36 {
-    outline: solid !important;
+._3Ye_R {
+    color: gray !important
 }
 [data-asset-intro-image] {
     background-image: url(/img/intro-connection_c98cc75f2aa905314d74375a975d2cf2.jpg) !important;
 }
+._11ozL {
+    border: 5px solid white !important;
+}
+html[dir=ltr] .message-out .tail-container {
+    background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAmCAYAAADeB1slAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFHGlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDIwLTA0LTE5VDEyOjUzOjEzKzAyOjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAyMC0wNC0xOVQxMjo1NzowNSswMjowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAyMC0wNC0xOVQxMjo1NzowNSswMjowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDplNDljZjc5OS1jN2VhLTQ2NDctOWYyZC1iYTc5MGRiYjJkYmQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ZTQ5Y2Y3OTktYzdlYS00NjQ3LTlmMmQtYmE3OTBkYmIyZGJkIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6ZTQ5Y2Y3OTktYzdlYS00NjQ3LTlmMmQtYmE3OTBkYmIyZGJkIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDplNDljZjc5OS1jN2VhLTQ2NDctOWYyZC1iYTc5MGRiYjJkYmQiIHN0RXZ0OndoZW49IjIwMjAtMDQtMTlUMTI6NTM6MTMrMDI6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE5IChXaW5kb3dzKSIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5VX0C4AAABTElEQVRIie3Vv0rEQBAG8G+yu5fEzlexsNUHsLUVBS0sbYUDixMs7LQUVARB7yksDRoFfQlBvRPN7d5d7sZOlCDZzW26TD35fuzsn9D84gLDsYjohpmX32/vS3sD13AAYOYlMK/a9FYCAIDzSVgrAKJpbUDUki8kxWVtgBmYfdteZ0CBzyHlUS3AXEs+j0HrvSQl22+kbWMUqs9MDzv9u0dyuTvWK9BfepeC4Mr1YloBEnxBSh67BFsDcUs+5aC1KuGlQBSqDz0cd1w21QkwmW6D6LrKg1gKCPCZy3l3AmIl0gloY5bR/AtEoerrUX7QS1Kn824NmMy0QdT1EV4AJE9PIEWl814KxEokOQVbPuZeAOJQvelRfggAvkbzB9CZ2QNR12fwDyDAp77n/rvka/KwubK9U1f+DD99yyJmr3taqNpX0AAN0AANYFHfejdtRQswUf0AAAAASUVORK5CYII=') !important
+}
+html[dir=ltr] .message-in .tail-container {
+    background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAmCAYAAADeB1slAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFFmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDUgNzkuMTYzNDk5LCAyMDE4LzA4LzEzLTE2OjQwOjIyICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOSAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDIwLTA0LTE5VDEyOjUzOjEzKzAyOjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAyMC0wNC0xOVQxMjo1NiswMjowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAyMC0wNC0xOVQxMjo1NiswMjowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo4MzYwY2FhOC1kNjZmLTI2NDctOWRhMi1lODUzMDg4NDA5NjAiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODM2MGNhYTgtZDY2Zi0yNjQ3LTlkYTItZTg1MzA4ODQwOTYwIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6ODM2MGNhYTgtZDY2Zi0yNjQ3LTlkYTItZTg1MzA4ODQwOTYwIj4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo4MzYwY2FhOC1kNjZmLTI2NDctOWRhMi1lODUzMDg4NDA5NjAiIHN0RXZ0OndoZW49IjIwMjAtMDQtMTlUMTI6NTM6MTMrMDI6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE5IChXaW5kb3dzKSIvPiA8L3JkZjpTZXE+IDwveG1wTU06SGlzdG9yeT4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7wnTSaAAAByElEQVRIie3Uu0sDMRwH8N/vesnltC+LCIJDnQSpUwUnH7g76+qioLgo+G+IOIj+B66iuIn4QBQrioeT4FGpb3GwWj1zFwc5qPVxaRu3freEXD78kvsFhRDwV1o7OgERN4QQvcXziAhB3wIA6IErhBgQAL3fp4M3BwDQghbwd+cZEaU2qwhwOc9SQrx/A4y6+rOGWGS/0ioCAQCArG2PUEr4vwG0PnKiuXxS06SWlw/YVgYL3JtLRMPL5R6VFJBMpYVtZTB3dTWaiMcuykFQptGK47zku2KJxu3C62twD4FEBanuni9jWhfe897fpnVdl+o0qSMqRd5cMRM22ZrMUZX/W8DnpT88Po7Ho5GcMqC4imQqLUI6se/v70YJIa4S4KeEiLEqOJ8N/dEfVQG2lUEuxJTJjPXf7qMqwO+Pp/zzRDwauVAO+Ahq2und7c2gyZijHPCjG+au6xQmTMa84uNSBthWBh0PF8MmXTAoVQ8kU2kBAHB5fTvd0ty04yPKAD/EYPmTo6Ohjva2HGNG8GM3MDYptbG1tfllHKPY093Xv6SsgtL36vjwYPsyez6srILSrMzPaACAgUC1UX7JNaAG1IAaUEE+AFQnnoGbc+MiAAAAAElFTkSuQmCC') !important
+}
 
 ================================
 
@@ -3182,11 +3389,16 @@ INVERT
 
 wikipedia.org
 
+IGNORE INLINE STYLE
+.legend-color
+
 INVERT
 .mwe-math-element
+.mw-ext-score
 .mw-wiki-logo
 .central-textlogo__image
 .svg-Wikimedia-logo_black
+.header .branding-box > a > span > img
 
 CSS
 div .mw-parser-output ul {
@@ -3196,6 +3408,12 @@ div .thumbimage[src$=".png"],
 div .thumbimage img[src$=".png"] {
     background-color: white;
 }
+.mw-mmv-image .svg,
+.fullImageLink [src*=".svg"],
+a[href$=".svg"]:hover > img {
+    background-color: rgba(255, 255, 255, 0.75) !important;
+    background-blend-mode: color;
+}
 
 ================================
 
@@ -3210,6 +3428,15 @@ li.menu-tooltip:not(.lang_btn)
 
 ================================
 
+wiktionary.org
+
+CSS
+div.NavFrame div.NavHead {
+    background-image: none !important;
+}
+
+================================
+
 www.bing.com
 
 CSS
@@ -3273,7 +3500,7 @@ INVERT
 .gb_0b
 #dictionary-modules img[src*="png"]
 a.gb_b > div
-.gb_D.gb_qc
+a[href*="about/products"]
 
 CSS
 .RNNXgb {
@@ -3331,6 +3558,18 @@ INVERT
 
 ================================
 
+xda-developers.com
+
+CSS
+.hb-trigger-inner, .hb-trigger-inner::before, .hb-trigger-inner::after {
+    background-color: ${rgb(48, 51, 53)} !important;
+}
+.hb-trigger:hover .hb-trigger-inner, .hb-trigger:hover .hb-trigger-inner::before, .hb-trigger:hover .hb-trigger-inner::after, .hb-trigger:active .hb-trigger-inner, .hb-trigger:active .hb-trigger-inner::before, .hb-trigger:active .hb-trigger-inner::after, .hb-trigger:focus .hb-trigger-inner, .hb-trigger:focus .hb-trigger-inner::before, .hb-trigger:focus .hb-trigger-inner::after {
+    background-color: ${black} !important;
+}
+
+================================
+
 youtube.com
 
 CSS
@@ -3539,7 +3778,7 @@ ytd-toggle-button-renderer.style-default-active[is-icon-button] {
 .ytp-menuitem[aria-checked="true"] .ytp-menuitem-toggle-checkbox::after {
     background-color: white !important;
 }
-#date yt-formatted-string.ytd-video-primary-info-renderer {
+#date yt-formatted-string.ytd-video-primary-info-renderer, .yt-view-count-renderer {
     color: var(--yt-spec-text-secondary) !important;
 }
 .ytp-contextmenu .ytp-menuitem .ytp-menuitem-toggle-checkbox {
@@ -3548,12 +3787,21 @@ ytd-toggle-button-renderer.style-default-active[is-icon-button] {
 .ytp-contextmenu .ytp-menuitem[aria-checked="true"] .ytp-menuitem-toggle-checkbox {
     background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z" fill="white"/></svg>') !important;
 }
+#backgroundFrontLayer.app-header {
+    background-image: var(--app-header-background-front-layer_-_background-image) !important;
+}
 #metadata-line.ytd-video-meta-block span.ytd-video-meta-block {
     color: var(--ytd-metadata-line-color, var(--yt-spec-text-secondary)) !important;
 }
 yt-formatted-string[has-link-only_]:not([force-default-style]) a.yt-simple-endpoint.yt-formatted-string {
     color: var(--yt-endpoint-color, var(--yt-spec-text-primary)) !important;
 }
+paper-button.ytd-subscribe-button-renderer[subscribed] {
+    background-color: var(--yt-spec-10-percent-layer) !important
+}
+.badge-style-type-live-now.ytd-badge-supported-renderer {
+    border: 1px solid rgb(255, 78, 69) !important;
+}
 
 ================================
 
diff --git a/src/config/inversion-fixes.config b/src/config/inversion-fixes.config
index 74e2b25b..4787ef15 100644
--- a/src/config/inversion-fixes.config
+++ b/src/config/inversion-fixes.config
@@ -1265,6 +1265,13 @@ html,
 
 ================================
 
+mullvad.net
+
+INVERT
+#Logo
+
+================================
+
 my.mail.ru/(music|mail|vk|ok|bk|list|gmail.com|inbox)
 
 INVERT
@@ -2293,6 +2300,7 @@ wikipedia.org
 
 INVERT
 .mwe-popups-discreet > svg
+.mw-ext-score
 .mw-mmv-overlay
 #Vorlage_Infobox_Chemikalie > tbody > tr:nth-child(2) > td > a
 
diff --git a/src/definitions.d.ts b/src/definitions.d.ts
index 9d2a494f..763217b0 100644
--- a/src/definitions.d.ts
+++ b/src/definitions.d.ts
@@ -49,6 +49,8 @@ export interface FilterConfig {
     stylesheet: string;
 }
 
+export type Theme = FilterConfig;
+
 export interface CustomSiteConfig {
     url: string[];
     theme: FilterConfig;
@@ -67,6 +69,8 @@ export interface UserSettings {
     automation: '' | 'time' | 'system' | 'location';
     time: TimeSettings;
     location: LocationSettings;
+    previewNewDesign: boolean;
+    enableForPDF: boolean;
 }
 
 export interface TimeSettings {
@@ -98,6 +102,7 @@ export interface Shortcuts {
 
 export interface DynamicThemeFix {
     url: string[];
+    ignoreInlineStyle: string[];
     invert: string[];
     css: string;
 }
diff --git a/src/generators/css-filter.ts b/src/generators/css-filter.ts
index 4b6c7b79..af8315b8 100644
--- a/src/generators/css-filter.ts
+++ b/src/generators/css-filter.ts
@@ -5,12 +5,28 @@ import {parseArray, formatArray} from '../utils/text';
 import {compareURLPatterns, isURLInList} from '../utils/url';
 import {createTextStyle} from './text-style';
 import {FilterConfig, InversionFix} from '../definitions';
+import {compareChromeVersions, getChromeVersion, isChromiumBased} from '../utils/platform';
 
 export enum FilterMode {
     light = 0,
     dark = 1
 }
 
+/**
+ * This checks if the current chromium version has the patch in it.
+ * As of Chromium v81.0.4035.0 this has been the situation
+ *
+ * Bug report: https://bugs.chromium.org/p/chromium/issues/detail?id=501582
+ * Patch: https://chromium-review.googlesource.com/c/chromium/src/+/1979258
+ */
+export function hasChromiumIssue501582() {
+    const chromeVersion = getChromeVersion();
+    return Boolean(
+        isChromiumBased() &&
+        compareChromeVersions(chromeVersion, '81.0.4035.0') >= 0
+    );
+}
+
 export default function createCSSFilterStyleheet(config: FilterConfig, url: string, frameURL: string, inversionFixes: InversionFix[]) {
     const filterValue = getCSSFilterValue(config);
     const reverseFilterValue = 'invert(100%) hue-rotate(180deg)';
@@ -63,7 +79,9 @@ export function cssFilterStyleheetTemplate(filterValue: string, reverseFilterVal
     });
 
     if (!frameURL) {
-        const [r, g, b] = applyColorMatrix([255, 255, 255], createFilterMatrix(config));
+        // If user has the chrome issue the colors should be the other way around as of the rootcolors will affect the whole background color of the page
+        const rootColors = hasChromiumIssue501582() && config.mode === FilterMode.dark ? [0, 0, 0] : [255, 255, 255];
+        const [r, g, b] = applyColorMatrix(rootColors, createFilterMatrix(config));
         const bgColor = {
             r: Math.round(r),
             g: Math.round(g),
diff --git a/src/generators/dynamic-theme.ts b/src/generators/dynamic-theme.ts
index 3dd3e3ea..ff66bb98 100644
--- a/src/generators/dynamic-theme.ts
+++ b/src/generators/dynamic-theme.ts
@@ -5,6 +5,7 @@ import {compareURLPatterns, isURLInList} from '../utils/url';
 import {DynamicThemeFix} from '../definitions';
 
 const dynamicThemeFixesCommands = {
+    'IGNORE INLINE STYLE': 'ignoreInlineStyle',
     'INVERT': 'invert',
     'CSS': 'css',
 };
@@ -50,6 +51,7 @@ export function getDynamicThemeFixesFor(url: string, frameURL: string, fixes: Dy
 
     const common = {
         url: fixes[0].url,
+        ignoreInlineStyle: fixes[0].ignoreInlineStyle || [],
         invert: fixes[0].invert || [],
         css: fixes[0].css || [],
     };
@@ -73,6 +75,7 @@ export function getDynamicThemeFixesFor(url: string, frameURL: string, fixes: Dy
 
     return {
         url: match.url,
+        ignoreInlineStyle: common.ignoreInlineStyle.concat(match.ignoreInlineStyle || []),
         invert: common.invert.concat(match.invert || []),
         css: [common.css, match.css].filter((s) => s).join('\n'),
     };
diff --git a/src/inject/dynamic-theme/index.ts b/src/inject/dynamic-theme/index.ts
index 85f090aa..5421191d 100644
--- a/src/inject/dynamic-theme/index.ts
+++ b/src/inject/dynamic-theme/index.ts
@@ -45,26 +45,25 @@ function stopStylePositionWatchers() {
 
 function createStaticStyleOverrides() {
     const fallbackStyle = createOrUpdateStyle('darkreader--fallback');
-    document.head.insertBefore(fallbackStyle, document.head.firstChild);
     fallbackStyle.textContent = getModifiedFallbackStyle(filter, {strict: true});
+    document.head.insertBefore(fallbackStyle, document.head.firstChild);
     setupStylePositionWatcher(fallbackStyle, 'fallback');
 
     const userAgentStyle = createOrUpdateStyle('darkreader--user-agent');
-    document.head.insertBefore(userAgentStyle, fallbackStyle.nextSibling);
     userAgentStyle.textContent = getModifiedUserAgentStyle(filter, isIFrame);
+    document.head.insertBefore(userAgentStyle, fallbackStyle.nextSibling);
     setupStylePositionWatcher(userAgentStyle, 'user-agent');
 
     const textStyle = createOrUpdateStyle('darkreader--text');
-    document.head.insertBefore(textStyle, fallbackStyle.nextSibling);
     if (filter.useFont || filter.textStroke > 0) {
         textStyle.textContent = createTextStyle(filter);
     } else {
         textStyle.textContent = '';
     }
+    document.head.insertBefore(textStyle, fallbackStyle.nextSibling);
     setupStylePositionWatcher(textStyle, 'text');
 
     const invertStyle = createOrUpdateStyle('darkreader--invert');
-    document.head.insertBefore(invertStyle, textStyle.nextSibling);
     if (fixes && Array.isArray(fixes.invert) && fixes.invert.length > 0) {
         invertStyle.textContent = [
             `${fixes.invert.join(', ')} {`,
@@ -77,16 +76,17 @@ function createStaticStyleOverrides() {
     } else {
         invertStyle.textContent = '';
     }
+    document.head.insertBefore(invertStyle, textStyle.nextSibling);
     setupStylePositionWatcher(invertStyle, 'invert');
 
     const inlineStyle = createOrUpdateStyle('darkreader--inline');
-    document.head.insertBefore(inlineStyle, invertStyle.nextSibling);
     inlineStyle.textContent = getInlineOverrideStyle();
+    document.head.insertBefore(inlineStyle, invertStyle.nextSibling);
     setupStylePositionWatcher(inlineStyle, 'inline');
 
     const overrideStyle = createOrUpdateStyle('darkreader--override');
-    document.head.appendChild(overrideStyle);
     overrideStyle.textContent = fixes && fixes.css ? replaceCSSTemplates(fixes.css) : '';
+    document.head.appendChild(overrideStyle);
     setupStylePositionWatcher(overrideStyle, 'override');
 }
 
@@ -94,8 +94,8 @@ const shadowRootsWithOverrides = new Set<ShadowRoot>();
 
 function createShadowStaticStyleOverrides(root: ShadowRoot) {
     const inlineStyle = createOrUpdateStyle('darkreader--inline', root);
-    root.insertBefore(inlineStyle, root.firstChild);
     inlineStyle.textContent = getInlineOverrideStyle();
+    root.insertBefore(inlineStyle, root.firstChild);
     shadowRootsWithOverrides.add(root);
 }
 
@@ -161,7 +161,7 @@ function createDynamicStyleOverrides() {
             inlineStyleElements.push(...Array.from(elements as NodeListOf<HTMLLinkElement | HTMLStyleElement>));
         }
     });
-    inlineStyleElements.forEach((el) => overrideInlineStyle(el as HTMLElement, filter));
+    inlineStyleElements.forEach((el) => overrideInlineStyle(el as HTMLElement, filter, fixes.ignoreInlineStyle));
 }
 
 let loadingStylesCounter = 0;
@@ -313,7 +313,7 @@ function watchForUpdates() {
     });
 
     watchForInlineStyles((element) => {
-        overrideInlineStyle(element, filter);
+        overrideInlineStyle(element, filter, fixes.ignoreInlineStyle);
         if (element === document.documentElement) {
             const rootVariables = getElementCSSVariables(document.documentElement);
             if (rootVariables.size > 0) {
@@ -325,7 +325,7 @@ function watchForUpdates() {
         const inlineStyleElements = root.querySelectorAll(INLINE_STYLE_SELECTOR);
         if (inlineStyleElements.length > 0) {
             createShadowStaticStyleOverrides(root);
-            inlineStyleElements.forEach((el) => overrideInlineStyle(el as HTMLElement, filter));
+            inlineStyleElements.forEach((el) => overrideInlineStyle(el as HTMLElement, filter, fixes.ignoreInlineStyle));
         }
     });
 
diff --git a/src/inject/dynamic-theme/inline-style.ts b/src/inject/dynamic-theme/inline-style.ts
index c5287505..0ff66696 100644
--- a/src/inject/dynamic-theme/inline-style.ts
+++ b/src/inject/dynamic-theme/inline-style.ts
@@ -185,7 +185,16 @@ function getInlineStyleCacheKey(el: HTMLElement, theme: FilterConfig) {
         .join(' ');
 }
 
-export function overrideInlineStyle(element: HTMLElement, theme: FilterConfig) {
+function shouldIgnoreInlineStyle(element: HTMLElement, selectors: string[]) {
+    for (const ingnoredSelector of selectors) {
+        if (element.matches(ingnoredSelector)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+export function overrideInlineStyle(element: HTMLElement, theme: FilterConfig, ignoreSelectors: string[]) {
     const cacheKey = getInlineStyleCacheKey(element, theme);
     if (cacheKey === inlineStyleCache.get(element)) {
         return;
@@ -211,6 +220,17 @@ export function overrideInlineStyle(element: HTMLElement, theme: FilterConfig) {
         unsetProps.delete(targetCSSProp);
     }
 
+    if (ignoreSelectors.length > 0) {
+        if (shouldIgnoreInlineStyle(element, ignoreSelectors)) {
+            unsetProps.forEach((cssProp) => {
+                const {store, dataAttr} = overrides[cssProp];
+                store.delete(element);
+                element.removeAttribute(dataAttr);
+            });
+            return;
+        }
+    }
+
     if (element.hasAttribute('bgcolor')) {
         let value = element.getAttribute('bgcolor');
         if (value.match(/^[0-9a-f]{3}$/i) || value.match(/^[0-9a-f]{6}$/i)) {
diff --git a/src/inject/dynamic-theme/style-manager.ts b/src/inject/dynamic-theme/style-manager.ts
index 98e046cb..914bfbf3 100644
--- a/src/inject/dynamic-theme/style-manager.ts
+++ b/src/inject/dynamic-theme/style-manager.ts
@@ -374,6 +374,15 @@ export function manageStyle(element: HTMLLinkElement | HTMLStyleElement, {update
             syncStylePositionWatcher && syncStylePositionWatcher.stop();
             insertStyle();
 
+            // Firefox issue: Some websites get CSP warning,
+            // when `textContent` is not set (e.g. pypi.org).
+            // But for other websites (e.g. facebook.com)
+            // some images disappear when `textContent`
+            // is initially set to an empty string.
+            if (syncStyle.sheet == null) {
+                syncStyle.textContent = '';
+            }
+
             const sheet = syncStyle.sheet;
             for (let i = sheet.cssRules.length - 1; i >= 0; i--) {
                 sheet.deleteRule(i);
diff --git a/src/inject/dynamic-theme/url.ts b/src/inject/dynamic-theme/url.ts
index 08691385..63c5dd52 100644
--- a/src/inject/dynamic-theme/url.ts
+++ b/src/inject/dynamic-theme/url.ts
@@ -16,7 +16,12 @@ export function getAbsoluteURL($base: string, $relative: string) {
         const u = parseURL(`${b.protocol}//${b.host}${$relative}`);
         return u.href;
     }
-    const pathParts = b.pathname.split('/').concat($relative.split('/')).filter((p) => p);
+    let pathParts = b.pathname.split('/');
+    const lastPathPart = pathParts[pathParts.length - 1];
+    if (lastPathPart.match(/\.[a-z]+$/i)) {
+        pathParts.pop();
+    }
+    pathParts = pathParts.concat(...$relative.split('/')).filter((p) => p);
     let backwardIndex: number;
     while ((backwardIndex = pathParts.indexOf('..')) > 0) {
         pathParts.splice(backwardIndex - 1, 2);
diff --git a/src/manifest.json b/src/manifest.json
index a3c60f4c..57992815 100644
--- a/src/manifest.json
+++ b/src/manifest.json
@@ -1,7 +1,7 @@
 {
     "manifest_version": 2,
     "name": "Dark Reader",
-    "version": "4.9.4",
+    "version": "4.9.7",
     "author": "Alexander Shutau",
     "description": "__MSG_extension_description__",
     "default_locale": "en",
diff --git a/src/ui/controls/dropdown/index.tsx b/src/ui/controls/dropdown/index.tsx
index d4919476..eae08b11 100644
--- a/src/ui/controls/dropdown/index.tsx
+++ b/src/ui/controls/dropdown/index.tsx
@@ -2,6 +2,7 @@ import {m} from 'malevic';
 import {getContext} from 'malevic/dom';
 
 interface DropDownProps {
+    class?: string;
     selected: string;
     values: string[];
     onChange: (value: string) => void;
@@ -54,6 +55,7 @@ export default function DropDown(props: DropDownProps) {
                 class={{
                     'dropdown__list__item': true,
                     'dropdown__list__item--selected': value === props.selected,
+                    [props.class]: props.class != null,
                 }}
                 onclick={() => {
                     store.isOpen = false;
@@ -71,6 +73,7 @@ export default function DropDown(props: DropDownProps) {
             class={{
                 'dropdown': true,
                 'dropdown--open': store.isOpen,
+                [props.class]: Boolean(props.class),
             }}
         >
             <span
diff --git a/src/ui/controls/dropdown/style.less b/src/ui/controls/dropdown/style.less
index 952240d9..adc509d7 100644
--- a/src/ui/controls/dropdown/style.less
+++ b/src/ui/controls/dropdown/style.less
@@ -51,6 +51,11 @@
             line-height: @dropdown-item-height;
             text-align: center;
             width: 100%;
+            
+            &:hover {
+                background-color: @color-control-hover;
+                transition: background-color @time-fast;
+            }
 
             &--selected {
                 overflow: hidden;
@@ -80,3 +85,7 @@
         z-index: 2;
     }
 }
+
+.preview .dropdown {
+    cursor: pointer;
+}
diff --git a/src/ui/controls/slider/style.less b/src/ui/controls/slider/style.less
index 1bc357ac..d0feb147 100644
--- a/src/ui/controls/slider/style.less
+++ b/src/ui/controls/slider/style.less
@@ -70,6 +70,7 @@
     &__thumb {
         background-color: @slider-thumb-color;
         border-radius: 50%;
+        cursor: pointer;
         display: inline-block;
         height: @slider-thumb-size;
         margin-left: -@slider-thumb-size / 2;
@@ -79,6 +80,7 @@
 
         &__value {
             color: @color-control-fore;
+            cursor: default;
             left: calc(100% + @size-text-normal / 2);
             line-height: @slider-thumb-size;
             position: absolute;
diff --git a/src/ui/devtools/components/body.tsx b/src/ui/devtools/components/body.tsx
index d9c45fda..ec92530e 100644
--- a/src/ui/devtools/components/body.tsx
+++ b/src/ui/devtools/components/body.tsx
@@ -10,6 +10,7 @@ type BodyProps = ExtWrapper;
 function Body({data, actions}: BodyProps) {
     const {state, setState} = useState({errorText: null as string});
     let textNode: HTMLTextAreaElement;
+    const previewButtonText = data.settings.previewNewDesign ? 'Switch to old design' : 'Preview new design';
 
     const wrapper = (data.settings.theme.engine === ThemeEngines.staticTheme
         ? {
@@ -53,6 +54,10 @@ function Body({data, actions}: BodyProps) {
         setState({errorText: null});
     }
 
+    function toggleDesign() {
+        actions.changeSettings({previewNewDesign: !data.settings.previewNewDesign});
+    }
+
     return (
         <body>
             <header>
@@ -68,6 +73,7 @@ function Body({data, actions}: BodyProps) {
             <div id="buttons">
                 <Button onclick={reset}>Reset</Button>
                 <Button onclick={apply}>Apply</Button>
+                <Button class="preview-design-button" onclick={toggleDesign}>{previewButtonText}</Button>
             </div>
             <p id="description">
                 Read about this tool <strong><a href={DEVTOOLS_DOCS_URL} target="_blank" rel="noopener noreferrer">here</a></strong>.
diff --git a/src/ui/devtools/style.less b/src/ui/devtools/style.less
index 3936c23b..ea42bb60 100644
--- a/src/ui/devtools/style.less
+++ b/src/ui/devtools/style.less
@@ -112,10 +112,15 @@ header {
     }
 
     .button {
-        min-width: 4rem;
+        min-width: 3rem;
         max-width: 6rem;
         width: 100%;
     }
+
+    .preview-design-button {
+        border-color: gray;
+        max-width: 8rem;
+    }
 }
 
 #description {
diff --git a/src/ui/popup/body/index.tsx b/src/ui/popup/body/index.tsx
new file mode 100644
index 00000000..78f965d0
--- /dev/null
+++ b/src/ui/popup/body/index.tsx
@@ -0,0 +1,111 @@
+import {m} from 'malevic';
+import {getContext} from 'malevic/dom';
+import {DONATE_URL} from '../../../utils/links';
+import {getLocalMessage} from '../../../utils/locales';
+import {isMobile} from '../../../utils/platform';
+import MainPage from '../main-page';
+import {Page, PageViewer} from '../page-viewer';
+import SettingsPage from '../settings-page';
+import ThemePage from '../theme/page';
+import {ViewProps} from '../types';
+
+function Logo() {
+    return (
+        <a
+            class="m-logo"
+            href="https://darkreader.org/"
+            target="_blank"
+            rel="noopener noreferrer"
+        >
+            Dark Reader
+        </a>
+    );
+}
+
+function Pages(props: ViewProps) {
+    const context = getContext();
+    const store = context.store as {
+        activePage: 'main' | 'theme' | 'settings';
+    };
+    if (store.activePage == null) {
+        store.activePage = 'main';
+    }
+
+    function onThemeNavClick() {
+        store.activePage = 'theme';
+        context.refresh();
+    }
+
+    function onSettingsNavClick() {
+        store.activePage = 'settings';
+        context.refresh();
+    }
+
+    function onBackClick() {
+        store.activePage = 'main';
+        context.refresh();
+    }
+
+    return (
+        <PageViewer
+            activePage={store.activePage}
+            onBackButtonClick={onBackClick}
+        >
+            <Page id="main">
+                <MainPage
+                    {...props}
+                    onThemeNavClick={onThemeNavClick}
+                    onSettingsNavClick={onSettingsNavClick}
+                />
+            </Page>
+            <Page id="theme">
+                <ThemePage {...props} />
+            </Page>
+            <Page id="settings">
+                <SettingsPage {...props} />
+            </Page>
+        </PageViewer>
+    );
+}
+
+function DonateGroup() {
+    return (
+        <div class="m-donate-group">
+            <a class="m-donate-button" href={DONATE_URL} target="_blank" rel="noopener noreferrer">
+                <span class="m-donate-button__text">
+                    {getLocalMessage('donate')}
+                </span>
+            </a>
+            <label class="m-donate-description">
+                This project is sponsored by you
+            </label>
+        </div>
+    );
+}
+
+export default function MobileBody(props: ViewProps) {
+    const context = getContext();
+    context.onCreate(() => {
+        document.documentElement.classList.add('preview');
+        if (isMobile()) {
+            window.addEventListener('contextmenu', (e) => e.preventDefault());
+        }
+    });
+    context.onRemove(() => {
+        document.documentElement.classList.remove('preview');
+    });
+
+    return (
+        <body>
+            <section class="m-section">
+                <Logo />
+            </section>
+            <section class="m-section pages-section">
+                <Pages {...props} />
+            </section>
+            <section class="m-section">
+                <DonateGroup />
+            </section>
+        </body>
+    );
+}
diff --git a/src/ui/popup/components/mobile/style.less b/src/ui/popup/body/style.less
similarity index 57%
rename from src/ui/popup/components/mobile/style.less
rename to src/ui/popup/body/style.less
index 292b0db8..0c9b5742 100644
--- a/src/ui/popup/components/mobile/style.less
+++ b/src/ui/popup/body/style.less
@@ -6,7 +6,10 @@
         margin: @popup-content-padding auto;
         padding: 0;
     }
+}
 
+.mobile,
+.preview {
     .m-section {
         width: 100%;
 
@@ -19,6 +22,10 @@
         }
     }
 
+    .pages-section {
+        height: 22.5rem;
+    }
+
     .m-logo {
         background-image: url('../assets/images/darkreader-type.svg');
         background-position: center;
@@ -32,77 +39,6 @@
         width: @popup-content-width;
     }
 
-    .m-simple-control {
-        align-items: stretch;
-        display: flex;
-        flex-direction: column;
-        width: 100%;
-
-        &__description {
-            font-size: @size-text-small;
-            line-height: @size-text-small-height;
-            text-align: center;
-            -moz-user-select: none;
-            user-select: none;
-        }
-    }
-
-    .m-theme-control {
-        align-items: center;
-        display: flex;
-        flex-direction: row;
-        justify-content: center;
-        min-height: @size-control-inner;
-        width: 100%;
-
-        &__label {
-            font-size: @size-text-normal;
-            line-height: @size-text-normal;
-            text-align: left;
-            -moz-user-select: none;
-            user-select: none;
-            width: 50%;
-        }
-    }
-
-    .m-theme-group {
-        &__presets-wrapper {
-            background-color: @color-control-active;
-            border: @size-border solid @color-border;
-            height: @size-control-inner;
-
-            .dropdown {
-                &__selected {
-                    border-radius: unset;
-                    height: @size-control-inner;
-                    line-height: @size-control-inner;
-                    margin-top: 0;
-                }
-
-                &__list {
-                    border-radius: unset;
-                }
-            }
-        }
-
-        &__controls-wrapper {
-            border-bottom: @size-border solid @color-border;
-            border-left: @size-border solid @color-border;
-            border-right: @size-border solid @color-border;
-            padding: @indent-small;
-        }
-
-        &__description {
-            display: inline-block;
-            font-size: @size-text-small;
-            line-height: @size-text-small-height;
-            text-align: center;
-            -moz-user-select: none;
-            user-select: none;
-            width: 100%;
-        }
-    }
-
     .m-settings-button {
         background-image: @icon-right;
         background-position: center right 0.25rem;
@@ -133,40 +69,6 @@
         }
     }
 
-    .m-check-button {
-        .checkbox {
-            width: calc(100% - 2 * @size-border);
-
-            &__checkmark {
-                background-color: @color-control-active;
-            }
-
-            &__content {
-                align-items: center;
-                display: flex;
-                flex: auto;
-                height: @size-control-inner;
-                justify-content: center;
-                -moz-user-select: none;
-                user-select: none;
-            }
-
-            &__input:checked ~ * {
-                color: @color-control-fore;
-            }
-        }
-
-        &__description {
-            display: inline-block;
-            font-size: @size-text-small;
-            line-height: @size-text-small-height;
-            text-align: center;
-            -moz-user-select: none;
-            user-select: none;
-            width: 100%;
-        }
-    }
-
     .m-help-button {
         align-items: center;
         background-image: @icon-right;
@@ -180,6 +82,11 @@
         text-decoration: none;
         width: calc(100% - 2 * @size-border);
 
+        &:hover {
+            background-color: @color-control-hover;
+            transition: background-color @time-fast;
+        }
+
         &__text {
             color: @color-control-fore;
             display: inline-block;
@@ -206,32 +113,6 @@
         }
     }
 
-    .m-back-button {
-        background-image: @icon-left;
-        background-position: center left 0.25rem;
-        background-repeat: no-repeat;
-        background-size: 1rem;
-        width: calc(100% - 2 * @size-border);
-    }
-
-    .m-paginator {
-        position: relative;
-
-        &__settings-page {
-            background-color: @color-back;
-            display: none;
-            height: 100%;
-            left: 0;
-            position: absolute;
-            top: 0;
-            width: 100%;
-
-            &--active {
-                display: initial;
-            }
-        }
-    }
-
     .m-donate-button {
         align-items: center;
         background-color: @color-control-active;
@@ -254,7 +135,6 @@
         }
     }
 
-    .m-help-description,
     .m-donate-description {
         display: inline-block;
         font-size: @size-text-small;
@@ -266,6 +146,39 @@
     }
 }
 
+.preview .dev-tools-button {
+    overflow: visible;
+    position: relative;
+    width: calc(100% - 2 * 0.125rem);
+
+    &--has-custom-fixes {
+        &::after {
+            background-color: @color-heading;
+            border-radius: @size-text-small-height / 2;
+            color: @color-control-fore;
+            content: "!";
+            font-size: @size-text-small;
+            line-height: @size-text-small-height;
+            min-width: @size-text-small-height;
+            position: absolute;
+            right: -@size-text-small-height / 3;
+            top: -@size-text-small-height / 3;
+            z-index: 3;
+        }
+    }
+}
+
+.mobile,
+.preview {
+    @import "../control-group/style.less";
+    @import "../check-button/style.less";
+    @import "../main-page/style.less";
+    @import "../page-viewer/style.less";
+    @import "../theme/controls/theme-control.less";
+    @import "../theme/page/style.less";
+    @import "../theme/preset-picker/style.less";
+}
+
 .mobile.firefox {
     * {
         font-family: Inter, Open Sans, Segoe UI, Helvetica Neue, Ubuntu, sans-serif;
diff --git a/src/ui/popup/check-button/index.tsx b/src/ui/popup/check-button/index.tsx
new file mode 100644
index 00000000..df78a735
--- /dev/null
+++ b/src/ui/popup/check-button/index.tsx
@@ -0,0 +1,22 @@
+import {m} from 'malevic';
+import {CheckBox} from '../../controls';
+import ControlGroup from '../control-group';
+
+export default function CheckButton(props: {checked: boolean; label: string; description: string; onChange: (checked: boolean) => void}) {
+    return (
+        <ControlGroup class="check-button">
+            <ControlGroup.Control>
+                <CheckBox
+                    class="check-button__checkbox"
+                    checked={props.checked}
+                    onchange={(e: {target: HTMLInputElement}) => props.onChange(e.target.checked)}
+                >
+                    {props.label}
+                </CheckBox>
+            </ControlGroup.Control>
+            <ControlGroup.Description class="check-button__description">
+                {props.description}
+            </ControlGroup.Description>
+        </ControlGroup>
+    );
+}
diff --git a/src/ui/popup/check-button/style.less b/src/ui/popup/check-button/style.less
new file mode 100644
index 00000000..b5eb34b9
--- /dev/null
+++ b/src/ui/popup/check-button/style.less
@@ -0,0 +1,35 @@
+@import "../../theme.less";
+
+.check-button {
+    .checkbox {
+        width: calc(100% - 2 * @size-border);
+
+        &__checkmark {
+            background-color: @color-control-active;
+        }
+
+        &__content {
+            align-items: center;
+            display: flex;
+            flex: auto;
+            height: @size-control-inner;
+            justify-content: center;
+            -moz-user-select: none;
+            user-select: none;
+        }
+
+        &__input:checked ~ * {
+            color: @color-control-fore;
+        }
+    }
+
+    &__description {
+        display: inline-block;
+        font-size: @size-text-small;
+        line-height: @size-text-small-height;
+        text-align: center;
+        -moz-user-select: none;
+        user-select: none;
+        width: 100%;
+    }
+}
diff --git a/src/ui/popup/components/body.tsx b/src/ui/popup/components/body.tsx
index 8952b50e..14e1aeaa 100644
--- a/src/ui/popup/components/body.tsx
+++ b/src/ui/popup/components/body.tsx
@@ -5,7 +5,7 @@ import {TabPanel, Button} from '../../controls';
 import FilterSettings from './filter-settings';
 import {Header, MoreToggleSettings} from './header';
 import Loader from './loader';
-import MobileBody from './mobile/body';
+import NewBody from '../body';
 import MoreSettings from './more-settings';
 import {News, NewsButton} from './news';
 import SiteListSettings from './site-list-settings';
@@ -53,8 +53,8 @@ function Body(props: BodyProps) {
         );
     }
 
-    if (isMobile()) {
-        return <MobileBody {...props} />;
+    if (isMobile() || props.data.settings.previewNewDesign) {
+        return <NewBody {...props} />;
     }
 
     const unreadNews = props.data.news.filter(({read}) => !read);
diff --git a/src/ui/popup/components/mobile/body.tsx b/src/ui/popup/components/mobile/body.tsx
deleted file mode 100644
index 8d4a8e2b..00000000
--- a/src/ui/popup/components/mobile/body.tsx
+++ /dev/null
@@ -1,459 +0,0 @@
-import {m} from 'malevic';
-import {getContext} from 'malevic/dom';
-import {Button, CheckBox, DropDown, MultiSwitch, Slider} from '../../../controls';
-import SiteToggle from '../site-toggle';
-import ThemeEngines from '../../../../generators/theme-engines';
-import {DONATE_URL, getHelpURL} from '../../../../utils/links';
-import {getLocalMessage} from '../../../../utils/locales';
-import {isURLEnabled, isURLInList, getURLHost} from '../../../../utils/url';
-import {ExtensionData, ExtensionActions, TabInfo, FilterConfig} from '../../../../definitions';
-
-type Theme = FilterConfig;
-
-interface MobileBodyProps {
-    data: ExtensionData;
-    tab: TabInfo;
-    actions: ExtensionActions;
-}
-
-function Logo() {
-    return (
-        <a
-            class="m-logo"
-            href="https://darkreader.org/"
-            target="_blank"
-            rel="noopener noreferrer"
-        >
-            Dark Reader
-        </a>
-    );
-}
-
-function SimpleControl(props: {class?: string}, control: Malevic.Spec, description: string) {
-    return (
-        <div class={['m-simple-control', props.class]}>
-            {control}
-            <label class="m-simple-control__description">
-                {description}
-            </label>
-        </div>
-    );
-}
-
-function ThemeControl(props: {class?: string; label: string}, control: Malevic.Spec) {
-    return (
-        <div class={['m-theme-control', props.class]}>
-            <label class="m-theme-control__label">
-                {props.label}
-            </label>
-            {control}
-        </div>
-    );
-}
-
-interface AppSwitchOptions {
-    isOn: boolean;
-    isOff: boolean;
-    isAuto: boolean;
-}
-
-function AppSwitch(props: AppSwitchOptions & {onChange: (opt: AppSwitchOptions) => void}) {
-    const values = [
-        getLocalMessage('on'),
-        'Auto',
-        getLocalMessage('off'),
-    ];
-    const value = props.isOn ? values[0] : props.isOff ? values[2] : values[1];
-
-    function onSwitchChange(v: string) {
-        const index = values.indexOf(v);
-        props.onChange({
-            isOn: index === 0,
-            isOff: index === 2,
-            isAuto: index === 1,
-        });
-    }
-
-    return (
-        <SimpleControl>
-            <MultiSwitch
-                class="m-app-switch__control"
-                options={values}
-                value={value}
-                onChange={onSwitchChange}
-            />
-            {props.isOn ?
-                'Extension is enabled' :
-                props.isOff ?
-                    'Extension is disabled' :
-                    'Switches according to system dark mode'}
-        </SimpleControl>
-    );
-}
-
-function SiteToggleGroup(props: MobileBodyProps) {
-    const isSiteEnabled = isURLEnabled(props.tab.url, props.data.settings, props.tab);
-    return (
-        <SimpleControl>
-            <SiteToggle
-                {...props}
-            />
-            {isSiteEnabled ?
-                'Enabled for current website' :
-                'Disabled for current website'}
-        </SimpleControl>
-    );
-}
-
-function SwitchGroup(props: MobileBodyProps) {
-    function onAppSwitchChange(opt: AppSwitchOptions) {
-        if (opt.isOn) {
-            props.actions.changeSettings({
-                enabled: true,
-                automation: '',
-            });
-        } else if (opt.isOff) {
-            props.actions.changeSettings({
-                enabled: false,
-                automation: '',
-            });
-        } else if (opt.isAuto) {
-            props.actions.changeSettings({
-                automation: 'system',
-            });
-        }
-    }
-
-    return (
-        <Array>
-            <AppSwitch
-                isOn={props.data.settings.enabled === true && !props.data.settings.automation}
-                isOff={props.data.settings.enabled === false && !props.data.settings.automation}
-                isAuto={Boolean(props.data.settings.automation)}
-                onChange={onAppSwitchChange}
-            />
-            <SiteToggleGroup
-                {...props}
-            />
-        </Array>
-    );
-}
-
-function formatPercent(v: number) {
-    return `${v}%`;
-}
-
-function Brightness(props: {value: number; onChange: (v: number) => void}) {
-    return (
-        <ThemeControl label={getLocalMessage('brightness')}>
-            <Slider
-                value={props.value}
-                min={50}
-                max={150}
-                step={1}
-                formatValue={formatPercent}
-                onChange={props.onChange}
-            />
-        </ThemeControl>
-    );
-}
-
-function Contrast(props: {value: number; onChange: (v: number) => void}) {
-    return (
-        <ThemeControl label={getLocalMessage('contrast')}>
-            <Slider
-                value={props.value}
-                min={50}
-                max={150}
-                step={1}
-                formatValue={formatPercent}
-                onChange={props.onChange}
-            />
-        </ThemeControl>
-    );
-}
-
-function Scheme(props: {isDark: boolean; onChange: (dark: boolean) => void}) {
-    const valDark = getLocalMessage('Dark');
-    const valLight = getLocalMessage('Light');
-    return (
-        <ThemeControl label="Scheme">
-            <DropDown
-                selected={props.isDark ? valDark : valLight}
-                values={[
-                    valDark,
-                    valLight,
-                ]}
-                onChange={(v) => props.onChange(v === valDark)}
-            />
-        </ThemeControl>
-    );
-}
-
-function Mode(props: {mode: string; onChange: (mode: string) => void}) {
-    const modes = [
-        [ThemeEngines.dynamicTheme, getLocalMessage('engine_dynamic')],
-        [ThemeEngines.cssFilter, getLocalMessage('engine_filter')],
-        [ThemeEngines.staticTheme, getLocalMessage('engine_static')],
-    ];
-    return (
-        <ThemeControl label="Mode">
-            <DropDown
-                selected={modes.find((m) => m[0] === props.mode)[1]}
-                values={modes.map((m) => m[1])}
-                onChange={(v) => {
-                    const mode = modes.find((m) => m[1] === v)[0];
-                    props.onChange(mode);
-                }}
-            />
-        </ThemeControl>
-    );
-}
-
-function ThemeControls(props: {theme: Theme; onChange: (theme: Partial<Theme>) => void}) {
-    const {theme, onChange} = props;
-    return (
-        <section class="m-section m-theme-controls">
-            <Brightness
-                value={theme.brightness}
-                onChange={(v) => onChange({brightness: v})}
-            />
-            <Contrast
-                value={theme.contrast}
-                onChange={(v) => onChange({contrast: v})}
-            />
-            <Scheme
-                isDark={theme.mode === 1}
-                onChange={(isDark) => onChange({mode: isDark ? 1 : 0})}
-            />
-            <Mode
-                mode={theme.engine}
-                onChange={(mode) => onChange({engine: mode})}
-            />
-        </section>
-    );
-}
-
-function ThemeGroup(props: MobileBodyProps) {
-    const host = getURLHost(props.tab.url || '');
-    const custom = props.data.settings.customThemes.find(
-        ({url}) => isURLInList(props.tab.url, url)
-    );
-    const theme = custom ?
-        custom.theme :
-        props.data.settings.theme;
-
-    function setTheme(config: Partial<Theme>) {
-        if (custom) {
-            custom.theme = {...custom.theme, ...config};
-            props.actions.changeSettings({
-                customThemes: props.data.settings.customThemes,
-            });
-        } else {
-            props.actions.setTheme(config);
-        }
-    }
-
-    const defaultPresetName = 'Default theme';
-    const customPresetName = `Custom for ${host}`;
-
-    function onPresetChange(name: string) {
-        const filteredCustomThemes = props.data.settings.customThemes.filter(({url}) => !isURLInList(props.tab.url, url));
-        if (name === defaultPresetName) {
-            props.actions.changeSettings({customThemes: filteredCustomThemes});
-        } else if (name === customPresetName) {
-            const extended = filteredCustomThemes.concat({
-                url: [host],
-                theme: {...props.data.settings.theme},
-            });
-            props.actions.changeSettings({customThemes: extended});
-        }
-    }
-
-    return (
-        <div class="m-theme-group">
-            <div class="m-theme-group__presets-wrapper">
-                <DropDown
-                    selected={custom ? customPresetName : defaultPresetName}
-                    values={[
-                        defaultPresetName,
-                        customPresetName,
-                    ]}
-                    onChange={onPresetChange}
-                />
-            </div>
-            <div class="m-theme-group__controls-wrapper">
-                <ThemeControls
-                    theme={theme}
-                    onChange={setTheme}
-                />
-            </div>
-            <label class="m-theme-group__description">
-                Configure theme
-            </label>
-        </div>
-    );
-}
-
-function SettingsNavButton(props: {onClick: () => void}) {
-    return (
-        <Button class="m-settings-button" onclick={props.onClick}>
-            <span class="m-settings-button__content">
-                <span class="m-settings-button__icon" />
-                <span class="m-settings-button__text">Settings</span>
-            </span>
-        </Button>
-    );
-}
-
-function MainPage(props: MobileBodyProps & {onSettingsNavClick: () => void}) {
-    return (
-        <Array>
-            <section class="m-section">
-                <SwitchGroup {...props} />
-            </section>
-            <section class="m-section">
-                <ThemeGroup {...props} />
-            </section>
-            <section class="m-section">
-                <SettingsNavButton onClick={props.onSettingsNavClick} />
-            </section>
-        </Array>
-    );
-}
-
-function CheckButton(props: {checked: boolean; label: string; description: string; onChange: (checked: boolean) => void}) {
-    return (
-        <span class="m-check-button">
-            <CheckBox
-                class="m-check-button__checkbox"
-                checked={props.checked}
-                onchange={(e: {target: HTMLInputElement}) => props.onChange(e.target.checked)}
-            >
-                {props.label}
-            </CheckBox>
-            <label class="m-check-button__description">
-                {props.description}
-            </label>
-        </span>
-    );
-}
-
-function HelpGroup() {
-    return (
-        <div class="m-help-group">
-            <a class="m-help-button" href={getHelpURL()} target="_blank" rel="noopener noreferrer">
-                <span class="m-help-button__text">
-                    {getLocalMessage('help')}
-                </span>
-            </a>
-            <label class="m-help-description">
-                Read the manual
-            </label>
-        </div>
-    );
-}
-
-function BackButton(props: {onClick: () => void}) {
-    return (
-        <Button class="m-back-button" onclick={props.onClick}>
-            Back
-        </Button>
-    );
-}
-
-function SettingsPage(props: MobileBodyProps & {onBackClick: () => void}) {
-    function onEnabledByDefaultChange(checked: boolean) {
-        props.actions.changeSettings({applyToListedOnly: !checked});
-    }
-
-    return (
-        <Array>
-            <section class="m-section">
-                <CheckButton
-                    checked={!props.data.settings.applyToListedOnly}
-                    label="Enable by default"
-                    description={props.data.settings.applyToListedOnly ?
-                        'Disabled on all websites by default' :
-                        'Enabled on all websites by default'}
-                    onChange={onEnabledByDefaultChange}
-                />
-                <HelpGroup />
-            </section>
-            <section class="m-section">
-                <BackButton onClick={props.onBackClick} />
-            </section>
-        </Array>
-    );
-}
-
-function Paginator(props: MobileBodyProps) {
-    const context = getContext();
-    const store = context.store as {
-        activePage: 'main' | 'settings';
-    };
-
-    function onSettingsNavClick() {
-        store.activePage = 'settings';
-        context.refresh();
-    }
-
-    function onSettingsBackClick() {
-        store.activePage = 'main';
-        context.refresh();
-    }
-
-    return (
-        <div class="m-paginator">
-            <div class="m-paginator__main-page">
-                <MainPage
-                    {...props}
-                    onSettingsNavClick={onSettingsNavClick}
-                />
-            </div>
-            <div
-                class={{
-                    'm-paginator__settings-page': true,
-                    'm-paginator__settings-page--active': store.activePage === 'settings',
-                }}
-            >
-                <SettingsPage {...props} onBackClick={onSettingsBackClick} />
-            </div>
-        </div>
-    );
-}
-
-function DonateGroup() {
-    return (
-        <div class="m-donate-group">
-            <a class="m-donate-button" href={DONATE_URL} target="_blank" rel="noopener noreferrer">
-                <span class="m-donate-button__text">
-                    {getLocalMessage('donate')}
-                </span>
-            </a>
-            <label class="m-donate-description">
-                This project is sponsored by you
-            </label>
-        </div>
-    );
-}
-
-export default function MobileBody(props: MobileBodyProps) {
-    function preventContextMenu() {
-        window.addEventListener('contextmenu', (e) => e.preventDefault());
-    }
-
-    return (
-        <body oncreate={preventContextMenu}>
-            <section class="m-section">
-                <Logo />
-            </section>
-            <section class="m-section">
-                <Paginator {...props} />
-            </section>
-            <section class="m-section">
-                <DonateGroup />
-            </section>
-        </body>
-    );
-}
diff --git a/src/ui/popup/control-group/index.tsx b/src/ui/popup/control-group/index.tsx
new file mode 100644
index 00000000..35c18fba
--- /dev/null
+++ b/src/ui/popup/control-group/index.tsx
@@ -0,0 +1,32 @@
+import {m} from 'malevic';
+
+function ControlGroup(
+    props: {class?: string},
+    control: Malevic.Spec,
+    description: Malevic.Spec,
+) {
+    return (
+        <span class={['control-group', props.class]}>
+            {control}
+            {description}
+        </span>
+    );
+}
+
+function Control(props: {class?: string}, control: Malevic.Child) {
+    return (
+        <span class={['control-group__control', props.class]} >
+            {control}
+        </span>
+    );
+}
+
+function Description(props: {class?: string}, description: Malevic.Child) {
+    return (
+        <span class={['control-group__description', props.class]} >
+            {description}
+        </span>
+    );
+}
+
+export default Object.assign(ControlGroup, {Control, Description});
diff --git a/src/ui/popup/control-group/style.less b/src/ui/popup/control-group/style.less
new file mode 100644
index 00000000..088d33f9
--- /dev/null
+++ b/src/ui/popup/control-group/style.less
@@ -0,0 +1,16 @@
+@import "../../theme.less";
+
+.control-group {
+    align-items: stretch;
+    display: inline-flex;
+    flex-direction: column;
+    width: 100%;
+
+    &__description {
+        font-size: @size-text-small;
+        line-height: @size-text-small-height;
+        text-align: center;
+        -moz-user-select: none;
+        user-select: none;
+    }
+}
diff --git a/src/ui/popup/main-page/app-switch.tsx b/src/ui/popup/main-page/app-switch.tsx
new file mode 100644
index 00000000..91e7cb85
--- /dev/null
+++ b/src/ui/popup/main-page/app-switch.tsx
@@ -0,0 +1,60 @@
+import {m} from 'malevic';
+import {getLocalMessage} from '../../../utils/locales';
+import {MultiSwitch} from '../../controls';
+import ControlGroup from '../control-group';
+import {ViewProps} from '../types';
+
+export default function AppSwitch(props: ViewProps) {
+    const isOn = props.data.settings.enabled === true && !props.data.settings.automation;
+    const isOff = props.data.settings.enabled === false && !props.data.settings.automation;
+
+    // TODO: Replace messages with some IDs.
+    const values = [
+        getLocalMessage('on'),
+        'Auto',
+        getLocalMessage('off'),
+    ];
+    const value = isOn ? values[0] : isOff ? values[2] : values[1];
+
+    function onSwitchChange(v: string) {
+        const index = values.indexOf(v);
+        if (index === 0) {
+            props.actions.changeSettings({
+                enabled: true,
+                automation: '',
+            });
+        } else if (index === 2) {
+            props.actions.changeSettings({
+                enabled: false,
+                automation: '',
+            });
+        } else if (index === 1) {
+            props.actions.changeSettings({
+                automation: 'system',
+            });
+        }
+    }
+
+    const description = isOn ?
+        'Extension is enabled' :
+        isOff ?
+            'Extension is disabled' :
+            // TODO: More messages (location, time etc).
+            'Switches according to system dark mode';
+
+    return (
+        <ControlGroup class="app-switch">
+            <ControlGroup.Control>
+                <MultiSwitch
+                    class="app-switch__control"
+                    options={values}
+                    value={value}
+                    onChange={onSwitchChange}
+                />
+            </ControlGroup.Control>
+            <ControlGroup.Description>
+                {description}
+            </ControlGroup.Description>
+        </ControlGroup>
+    );
+}
diff --git a/src/ui/popup/main-page/index.tsx b/src/ui/popup/main-page/index.tsx
new file mode 100644
index 00000000..99d602d9
--- /dev/null
+++ b/src/ui/popup/main-page/index.tsx
@@ -0,0 +1,47 @@
+import {m} from 'malevic';
+import {Button} from '../../controls';
+import {ViewProps} from '../types';
+import AppSwitch from './app-switch';
+import SiteToggleGroup from './site-toggle';
+import ThemeGroup from './theme-group';
+
+function SwitchGroup(props: ViewProps) {
+    return (
+        <Array>
+            <AppSwitch {...props} />
+            <SiteToggleGroup {...props} />
+        </Array>
+    );
+}
+
+function SettingsNavButton(props: {onClick: () => void}) {
+    return (
+        <Button class="m-settings-button" onclick={props.onClick}>
+            <span class="m-settings-button__content">
+                <span class="m-settings-button__icon" />
+                <span class="m-settings-button__text">Settings</span>
+            </span>
+        </Button>
+    );
+}
+
+type MainPageProps = ViewProps & {
+    onThemeNavClick: () => void;
+    onSettingsNavClick: () => void;
+};
+
+export default function MainPage(props: MainPageProps) {
+    return (
+        <Array>
+            <section class="m-section">
+                <SwitchGroup {...props} />
+            </section>
+            <section class="m-section">
+                <ThemeGroup {...props} />
+            </section>
+            <section class="m-section">
+                <SettingsNavButton onClick={props.onSettingsNavClick} />
+            </section>
+        </Array>
+    );
+}
diff --git a/src/ui/popup/main-page/site-toggle.tsx b/src/ui/popup/main-page/site-toggle.tsx
new file mode 100644
index 00000000..3ad81577
--- /dev/null
+++ b/src/ui/popup/main-page/site-toggle.tsx
@@ -0,0 +1,21 @@
+import {m} from 'malevic';
+import {isURLEnabled} from '../../../utils/url';
+import SiteToggle from '../components/site-toggle';
+import ControlGroup from '../control-group';
+import {ViewProps} from '../types';
+
+export default function SiteToggleGroup(props: ViewProps) {
+    const isSiteEnabled = isURLEnabled(props.tab.url, props.data.settings, props.tab);
+    return (
+        <ControlGroup class="site-toggle-group">
+            <ControlGroup.Control class="site-toggle-group__control">
+                <SiteToggle {...props} />
+            </ControlGroup.Control>
+            <ControlGroup.Description>
+                {isSiteEnabled ?
+                    'Enabled for current website' :
+                    'Disabled for current website'}
+            </ControlGroup.Description>
+        </ControlGroup>
+    );
+}
diff --git a/src/ui/popup/main-page/style.less b/src/ui/popup/main-page/style.less
new file mode 100644
index 00000000..e9cfba89
--- /dev/null
+++ b/src/ui/popup/main-page/style.less
@@ -0,0 +1,52 @@
+@import "../../theme.less";
+
+.app-switch {
+    &__control {
+        width: calc(100% - @size-border * 2);
+    }
+}
+
+.site-toggle-group {
+    .site-toggle {
+        width: calc(100% - @size-border * 2);
+    }
+}
+
+.theme-group {
+    &__presets-wrapper {
+        background-color: @color-control-active;
+        border: @size-border solid @color-border;
+        height: @size-control-inner;
+    }
+
+    &__controls-wrapper {
+        border-bottom: @size-border solid @color-border;
+        border-left: @size-border solid @color-border;
+        border-right: @size-border solid @color-border;
+        padding: @indent-small;
+    }
+
+    &__more-button {
+        background-color: @color-control-active;
+        background-image: @icon-right;
+        background-position: center right 0.25rem;
+        background-repeat: no-repeat;
+        background-size: 1rem;
+        border: none;
+        border-radius: @size-control-inner / 2;
+        height: @size-control-inner - 0.25rem;
+        margin-bottom: 0.125rem;
+        margin-top: @indent-small + 0.125rem;
+        width: 100%;
+    }
+
+    &__description {
+        display: inline-block;
+        font-size: @size-text-small;
+        line-height: @size-text-small-height;
+        text-align: center;
+        -moz-user-select: none;
+        user-select: none;
+        width: 100%;
+    }
+}
diff --git a/src/ui/popup/main-page/theme-group.tsx b/src/ui/popup/main-page/theme-group.tsx
new file mode 100644
index 00000000..a2cc59c4
--- /dev/null
+++ b/src/ui/popup/main-page/theme-group.tsx
@@ -0,0 +1,57 @@
+import {m} from 'malevic';
+import {Theme} from '../../../definitions';
+import {Button} from '../../controls';
+import {Brightness, Contrast, Scheme, Mode} from '../theme/controls';
+import ThemePresetPicker from '../theme/preset-picker';
+import {getCurrentThemePreset} from '../theme/utils';
+import {ViewProps} from '../types';
+
+function ThemeControls(props: {theme: Theme; onChange: (theme: Partial<Theme>) => void}) {
+    const {theme, onChange} = props;
+    return (
+        <section class="m-section m-theme-controls">
+            <Brightness
+                value={theme.brightness}
+                onChange={(v) => onChange({brightness: v})}
+            />
+            <Contrast
+                value={theme.contrast}
+                onChange={(v) => onChange({contrast: v})}
+            />
+            <Scheme
+                isDark={theme.mode === 1}
+                onChange={(isDark) => onChange({mode: isDark ? 1 : 0})}
+            />
+            <Mode
+                mode={theme.engine}
+                onChange={(mode) => onChange({engine: mode})}
+            />
+        </section>
+    );
+}
+
+export default function ThemeGroup(props: ViewProps & {onThemeNavClick: () => void}) {
+    const preset = getCurrentThemePreset(props);
+
+    return (
+        <div class="theme-group">
+            <div class="theme-group__presets-wrapper">
+                <ThemePresetPicker {...props} />
+            </div>
+            <div class="theme-group__controls-wrapper">
+                <ThemeControls
+                    theme={preset.theme}
+                    onChange={preset.change}
+                />
+                <Button class="theme-group__more-button" onclick={props.onThemeNavClick}>
+                    See all options
+                </Button>
+            </div>
+            <label class="theme-group__description">
+                Configure theme
+            </label>
+        </div>
+    );
+}
+
+
diff --git a/src/ui/popup/page-viewer/index.tsx b/src/ui/popup/page-viewer/index.tsx
new file mode 100644
index 00000000..e8d34e0f
--- /dev/null
+++ b/src/ui/popup/page-viewer/index.tsx
@@ -0,0 +1,50 @@
+import {m} from 'malevic';
+import {Button} from '../../controls';
+
+interface PageProps {
+    id: string;
+    active?: boolean;
+    first?: boolean;
+    onBackButtonClick?: () => void;
+}
+
+export function Page(props: PageProps, content: Malevic.Spec) {
+    return (
+        <div class={{'page': true, 'page--active': props.active}}>
+            <div class="page__content">
+                {content}
+            </div>
+            {props.first ? null : (
+                <Button class="page__back-button" onclick={props.onBackButtonClick}>
+                    Back
+                </Button>
+            )}
+        </div>
+    );
+}
+
+interface PageViewerProps {
+    activePage: string;
+    onBackButtonClick: () => void;
+}
+
+export function PageViewer(
+    props: PageViewerProps,
+    ...pages: Malevic.ComponentSpec<PageProps>[]
+) {
+    return (
+        <div class="page-viewer">
+            {pages.map((pageSpec, i) => {
+                return {
+                    ...pageSpec,
+                    props: {
+                        ...pageSpec.props,
+                        active: props.activePage === pageSpec.props.id,
+                        first: i === 0,
+                        onBackButtonClick: props.onBackButtonClick,
+                    },
+                } as Malevic.ComponentSpec<PageProps>;
+            })}
+        </div>
+    );
+}
diff --git a/src/ui/popup/page-viewer/style.less b/src/ui/popup/page-viewer/style.less
new file mode 100644
index 00000000..499d2f96
--- /dev/null
+++ b/src/ui/popup/page-viewer/style.less
@@ -0,0 +1,33 @@
+@import "../../theme.less";
+
+.page-viewer {
+    height: 100%;
+    position: relative;
+}
+
+.page {
+    align-items: stretch;
+    background-color: @color-back;
+    display: none;
+    flex-direction: column;
+    height: 100%;
+    justify-content: stretch;
+    left: 0;
+    position: absolute;
+    top: 0;
+    width: 100%;
+
+    &--active {
+        display: flex;
+    }
+
+    &__back-button {
+        background-image: @icon-left;
+        background-position: center left 0.25rem;
+        background-repeat: no-repeat;
+        background-size: 1rem;
+        flex: none;
+        margin-top: @indent-small;
+        width: calc(100% - 2 * @size-border);
+    }
+}
diff --git a/src/ui/popup/settings-page/devtools.tsx b/src/ui/popup/settings-page/devtools.tsx
new file mode 100644
index 00000000..a4a07be8
--- /dev/null
+++ b/src/ui/popup/settings-page/devtools.tsx
@@ -0,0 +1,67 @@
+import {m} from 'malevic';
+import ThemeEngines from '../../../generators/theme-engines';
+import {getLocalMessage} from '../../../utils/locales';
+import {Button} from '../../controls';
+import ControlGroup from '../control-group';
+import {ViewProps} from '../types';
+import {isFirefox} from '../../../utils/platform';
+
+function getExistingDevToolsWindow() {
+    return new Promise<chrome.windows.Window>((resolve) => {
+        chrome.windows.getAll({
+            populate: true,
+            windowTypes: ['popup']
+        }, (w) => {
+            for (const window of w) {
+                if (window.tabs[0].url.endsWith('ui/devtools/index.html')) {
+                    resolve(window);
+                    return;
+                }
+            }
+            resolve(null);
+        });
+    });
+}
+
+async function openDevTools() {
+    const devToolsWindow = await getExistingDevToolsWindow();
+    if (devToolsWindow) {
+        chrome.windows.update(devToolsWindow.id, {'focused': true});
+    } else {
+        chrome.windows.create({
+            type: 'popup',
+            url: isFirefox() ? '../devtools/index.html' : 'ui/devtools/index.html',
+            width: 600,
+            height: 600,
+        });
+    }
+}
+
+export default function DevToolsGroup(props: ViewProps) {
+    const globalThemeEngine = props.data.settings.theme.engine;
+    const devtoolsData = props.data.devtools;
+    const hasCustomFixes = (
+        (globalThemeEngine === ThemeEngines.dynamicTheme && devtoolsData.hasCustomDynamicFixes) ||
+        ([ThemeEngines.cssFilter, ThemeEngines.svgFilter].includes(globalThemeEngine) && devtoolsData.hasCustomFilterFixes) ||
+        (globalThemeEngine === ThemeEngines.staticTheme && devtoolsData.hasCustomStaticFixes)
+    );
+
+    return (
+        <ControlGroup>
+            <ControlGroup.Control>
+                <Button
+                    onclick={openDevTools}
+                    class={{
+                        'dev-tools-button': true,
+                        'dev-tools-button--has-custom-fixes': hasCustomFixes,
+                    }}
+                >
+                    🛠 {getLocalMessage('open_dev_tools')}
+                </Button>
+            </ControlGroup.Control>
+            <ControlGroup.Description>
+                Make a fix for a website
+            </ControlGroup.Description>
+        </ControlGroup>
+    );
+}
diff --git a/src/ui/popup/settings-page/enabled-by-default.tsx b/src/ui/popup/settings-page/enabled-by-default.tsx
new file mode 100644
index 00000000..6da8d66d
--- /dev/null
+++ b/src/ui/popup/settings-page/enabled-by-default.tsx
@@ -0,0 +1,20 @@
+import {m} from 'malevic';
+import CheckButton from '../check-button';
+import {ViewProps} from '../types';
+
+export default function EnabledByDefaultGroup(props: ViewProps) {
+    function onEnabledByDefaultChange(checked: boolean) {
+        props.actions.changeSettings({applyToListedOnly: !checked});
+    }
+
+    return (
+        <CheckButton
+            checked={!props.data.settings.applyToListedOnly}
+            label="Enable by default"
+            description={props.data.settings.applyToListedOnly ?
+                'Disabled on all websites by default' :
+                'Enabled on all websites by default'}
+            onChange={onEnabledByDefaultChange}
+        />
+    );
+}
diff --git a/src/ui/popup/settings-page/help.tsx b/src/ui/popup/settings-page/help.tsx
new file mode 100644
index 00000000..f0c7655e
--- /dev/null
+++ b/src/ui/popup/settings-page/help.tsx
@@ -0,0 +1,21 @@
+import {m} from 'malevic';
+import {getHelpURL} from '../../../utils/links';
+import {getLocalMessage} from '../../../utils/locales';
+import ControlGroup from '../control-group';
+
+export default function HelpGroup() {
+    return (
+        <ControlGroup>
+            <ControlGroup.Control>
+                <a class="m-help-button" href={getHelpURL()} target="_blank" rel="noopener noreferrer">
+                    <span class="m-help-button__text">
+                        {getLocalMessage('help')}
+                    </span>
+                </a>
+            </ControlGroup.Control>
+            <ControlGroup.Description>
+                Read the manual
+            </ControlGroup.Description>
+        </ControlGroup>
+    );
+}
diff --git a/src/ui/popup/settings-page/index.tsx b/src/ui/popup/settings-page/index.tsx
new file mode 100644
index 00000000..7c53bd49
--- /dev/null
+++ b/src/ui/popup/settings-page/index.tsx
@@ -0,0 +1,17 @@
+import {m} from 'malevic';
+import {ViewProps} from '../types';
+import DevToolsGroup from './devtools';
+import EnabledByDefaultGroup from './enabled-by-default';
+import HelpGroup from './help';
+import InvertPDF from './invert-pdf';
+
+export default function SettingsPage(props: ViewProps) {
+    return (
+        <section class="m-section">
+            <EnabledByDefaultGroup {...props} />
+            <InvertPDF {...props} />
+            <DevToolsGroup {...props} />
+            <HelpGroup />
+        </section>
+    );
+}
diff --git a/src/ui/popup/settings-page/invert-pdf.tsx b/src/ui/popup/settings-page/invert-pdf.tsx
new file mode 100644
index 00000000..66b3407f
--- /dev/null
+++ b/src/ui/popup/settings-page/invert-pdf.tsx
@@ -0,0 +1,20 @@
+import {m} from 'malevic';
+import {ViewProps} from '../types';
+import CheckButton from '../check-button';
+
+export default function InvertPDF(props: ViewProps) {
+    function onInvertPDFChange(checked: boolean) {
+        props.actions.changeSettings({enableForPDF: checked});
+    }
+
+    return (
+        <CheckButton
+            checked={props.data.settings.enableForPDF}
+            label='Enable for PDF files'
+            description={props.data.settings.enableForPDF ?
+                'Enabled for PDF documents' :
+                'Disabled for PDF documents'}
+            onChange={onInvertPDFChange}
+        />
+    );
+}
diff --git a/src/ui/popup/style.less b/src/ui/popup/style.less
index d0d954dc..a967c4ac 100644
--- a/src/ui/popup/style.less
+++ b/src/ui/popup/style.less
@@ -188,4 +188,4 @@ body {
     }
 }
 
-@import "./components/mobile/style";
+@import "./body/style";
diff --git a/src/ui/popup/theme/controls/brightness.tsx b/src/ui/popup/theme/controls/brightness.tsx
new file mode 100644
index 00000000..d5642118
--- /dev/null
+++ b/src/ui/popup/theme/controls/brightness.tsx
@@ -0,0 +1,20 @@
+import {m} from 'malevic';
+import {getLocalMessage} from '../../../../utils/locales';
+import {Slider} from '../../../controls';
+import {formatPercent} from './format';
+import ThemeControl from './theme-control';
+
+export default function Brightness(props: {value: number; onChange: (v: number) => void}) {
+    return (
+        <ThemeControl label={getLocalMessage('brightness')}>
+            <Slider
+                value={props.value}
+                min={50}
+                max={150}
+                step={1}
+                formatValue={formatPercent}
+                onChange={props.onChange}
+            />
+        </ThemeControl>
+    );
+}
diff --git a/src/ui/popup/theme/controls/contrast.tsx b/src/ui/popup/theme/controls/contrast.tsx
new file mode 100644
index 00000000..b03e83b0
--- /dev/null
+++ b/src/ui/popup/theme/controls/contrast.tsx
@@ -0,0 +1,20 @@
+import {m} from 'malevic';
+import {getLocalMessage} from '../../../../utils/locales';
+import {Slider} from '../../../controls';
+import {formatPercent} from './format';
+import ThemeControl from './theme-control';
+
+export default function Contrast(props: {value: number; onChange: (v: number) => void}) {
+    return (
+        <ThemeControl label={getLocalMessage('contrast')}>
+            <Slider
+                value={props.value}
+                min={50}
+                max={150}
+                step={1}
+                formatValue={formatPercent}
+                onChange={props.onChange}
+            />
+        </ThemeControl>
+    );
+}
diff --git a/src/ui/popup/theme/controls/format.ts b/src/ui/popup/theme/controls/format.ts
new file mode 100644
index 00000000..c676f2b3
--- /dev/null
+++ b/src/ui/popup/theme/controls/format.ts
@@ -0,0 +1,3 @@
+export function formatPercent(v: number) {
+    return `${v}%`;
+}
diff --git a/src/ui/popup/theme/controls/grayscale.tsx b/src/ui/popup/theme/controls/grayscale.tsx
new file mode 100644
index 00000000..5b7bd28c
--- /dev/null
+++ b/src/ui/popup/theme/controls/grayscale.tsx
@@ -0,0 +1,20 @@
+import {m} from 'malevic';
+import {getLocalMessage} from '../../../../utils/locales';
+import {Slider} from '../../../controls';
+import {formatPercent} from './format';
+import ThemeControl from './theme-control';
+
+export default function Grayscale(props: {value: number; onChange: (v: number) => void}) {
+    return (
+        <ThemeControl label={getLocalMessage('grayscale')}>
+            <Slider
+                value={props.value}
+                min={0}
+                max={100}
+                step={1}
+                formatValue={formatPercent}
+                onChange={props.onChange}
+            />
+        </ThemeControl>
+    );
+}
diff --git a/src/ui/popup/theme/controls/index.tsx b/src/ui/popup/theme/controls/index.tsx
new file mode 100644
index 00000000..10fb8318
--- /dev/null
+++ b/src/ui/popup/theme/controls/index.tsx
@@ -0,0 +1,15 @@
+import Brightness from './brightness';
+import Contrast from './contrast';
+import Grayscale from './grayscale';
+import Mode from './mode';
+import Scheme from './scheme';
+import Sepia from './sepia';
+
+export {
+    Brightness,
+    Contrast,
+    Grayscale,
+    Mode,
+    Scheme,
+    Sepia,
+};
diff --git a/src/ui/popup/theme/controls/mode.tsx b/src/ui/popup/theme/controls/mode.tsx
new file mode 100644
index 00000000..55fe7b0f
--- /dev/null
+++ b/src/ui/popup/theme/controls/mode.tsx
@@ -0,0 +1,25 @@
+import {m} from 'malevic';
+import ThemeEngines from '../../../../generators/theme-engines';
+import {getLocalMessage} from '../../../../utils/locales';
+import {DropDown} from '../../../controls';
+import ThemeControl from './theme-control';
+
+export default function Mode(props: {mode: string; onChange: (mode: string) => void}) {
+    const modes = [
+        [ThemeEngines.dynamicTheme, getLocalMessage('engine_dynamic')],
+        [ThemeEngines.cssFilter, getLocalMessage('engine_filter')],
+        [ThemeEngines.staticTheme, getLocalMessage('engine_static')],
+    ];
+    return (
+        <ThemeControl label="Mode">
+            <DropDown
+                selected={modes.find((m) => m[0] === props.mode)[1]}
+                values={modes.map((m) => m[1])}
+                onChange={(v) => {
+                    const mode = modes.find((m) => m[1] === v)[0];
+                    props.onChange(mode);
+                }}
+            />
+        </ThemeControl>
+    );
+}
diff --git a/src/ui/popup/theme/controls/scheme.tsx b/src/ui/popup/theme/controls/scheme.tsx
new file mode 100644
index 00000000..be06dd0e
--- /dev/null
+++ b/src/ui/popup/theme/controls/scheme.tsx
@@ -0,0 +1,21 @@
+import {m} from 'malevic';
+import {getLocalMessage} from '../../../../utils/locales';
+import {DropDown} from '../../../controls';
+import ThemeControl from './theme-control';
+
+export default function Scheme(props: {isDark: boolean; onChange: (dark: boolean) => void}) {
+    const valDark = getLocalMessage('dark');
+    const valLight = getLocalMessage('light');
+    return (
+        <ThemeControl label="Scheme">
+            <DropDown
+                selected={props.isDark ? valDark : valLight}
+                values={[
+                    valDark,
+                    valLight,
+                ]}
+                onChange={(v) => props.onChange(v === valDark)}
+            />
+        </ThemeControl>
+    );
+}
diff --git a/src/ui/popup/theme/controls/sepia.tsx b/src/ui/popup/theme/controls/sepia.tsx
new file mode 100644
index 00000000..9fa1406f
--- /dev/null
+++ b/src/ui/popup/theme/controls/sepia.tsx
@@ -0,0 +1,20 @@
+import {m} from 'malevic';
+import {getLocalMessage} from '../../../../utils/locales';
+import {Slider} from '../../../controls';
+import {formatPercent} from './format';
+import ThemeControl from './theme-control';
+
+export default function Sepia(props: {value: number; onChange: (v: number) => void}) {
+    return (
+        <ThemeControl label={getLocalMessage('sepia')}>
+            <Slider
+                value={props.value}
+                min={0}
+                max={100}
+                step={1}
+                formatValue={formatPercent}
+                onChange={props.onChange}
+            />
+        </ThemeControl>
+    );
+}
diff --git a/src/ui/popup/theme/controls/theme-control.less b/src/ui/popup/theme/controls/theme-control.less
new file mode 100644
index 00000000..581f49c0
--- /dev/null
+++ b/src/ui/popup/theme/controls/theme-control.less
@@ -0,0 +1,17 @@
+.theme-control {
+    align-items: center;
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    min-height: @size-control-inner;
+    width: 100%;
+
+    &__label {
+        font-size: @size-text-normal;
+        line-height: @size-text-normal;
+        text-align: left;
+        -moz-user-select: none;
+        user-select: none;
+        width: 50%;
+    }
+}
diff --git a/src/ui/popup/theme/controls/theme-control.tsx b/src/ui/popup/theme/controls/theme-control.tsx
new file mode 100644
index 00000000..64f5a0d7
--- /dev/null
+++ b/src/ui/popup/theme/controls/theme-control.tsx
@@ -0,0 +1,12 @@
+import {m} from 'malevic';
+
+export default function ThemeControl(props: {label: Malevic.Child}, control: Malevic.Child) {
+    return (
+        <span class="theme-control">
+            <label class="theme-control__label">
+                {props.label}
+            </label>
+            {control}
+        </span>
+    );
+}
diff --git a/src/ui/popup/theme/page/index.tsx b/src/ui/popup/theme/page/index.tsx
new file mode 100644
index 00000000..94f80ca5
--- /dev/null
+++ b/src/ui/popup/theme/page/index.tsx
@@ -0,0 +1,38 @@
+import {m} from 'malevic';
+import {ViewProps} from '../../types';
+import {Brightness, Contrast, Grayscale, Mode, Scheme, Sepia} from '../controls';
+import ThemePresetPicker from '../preset-picker';
+import {getCurrentThemePreset} from '../utils';
+
+export default function ThemePage(props: ViewProps) {
+    const {theme, change} = getCurrentThemePreset(props);
+
+    return (
+        <section class="m-section theme-page">
+            <ThemePresetPicker {...props} /><Brightness
+                value={theme.brightness}
+                onChange={(v) => change({brightness: v})}
+            />
+            <Contrast
+                value={theme.contrast}
+                onChange={(v) => change({contrast: v})}
+            />
+            <Sepia
+                value={theme.sepia}
+                onChange={(v) => change({sepia: v})}
+            />
+            <Grayscale
+                value={theme.grayscale}
+                onChange={(v) => change({grayscale: v})}
+            />
+            <Scheme
+                isDark={theme.mode === 1}
+                onChange={(isDark) => change({mode: isDark ? 1 : 0})}
+            />
+            <Mode
+                mode={theme.engine}
+                onChange={(mode) => change({engine: mode})}
+            />
+        </section>
+    );
+}
diff --git a/src/ui/popup/theme/page/style.less b/src/ui/popup/theme/page/style.less
new file mode 100644
index 00000000..f0d75890
--- /dev/null
+++ b/src/ui/popup/theme/page/style.less
@@ -0,0 +1,25 @@
+@import "../../../theme.less";
+
+.theme-page {
+    .theme-preset-picker.dropdown {
+        border-radius: unset;
+        height: @size-control-inner + 2 * @size-border;
+    }
+
+    .theme-preset-picker {
+        .dropdown {
+            &__selected {
+                border-radius: unset;
+                height: @size-control-inner + 2 * @size-border;
+                line-height: @size-control-inner + 2 * @size-border;
+            }
+        
+            &__list {
+                &__item {
+                    height: @size-control-inner + 2 * @size-border;
+                    line-height: @size-control-inner + 2 * @size-border;
+                }
+            }
+        }
+    }
+}
diff --git a/src/ui/popup/theme/preset-picker/index.tsx b/src/ui/popup/theme/preset-picker/index.tsx
new file mode 100644
index 00000000..cd2f75eb
--- /dev/null
+++ b/src/ui/popup/theme/preset-picker/index.tsx
@@ -0,0 +1,38 @@
+import {m} from 'malevic';
+import {isURLInList, getURLHost} from '../../../../utils/url';
+import {DropDown} from '../../../controls';
+import {ViewProps} from '../../types';
+
+export default function PresetPicker(props: ViewProps) {
+    const host = getURLHost(props.tab.url || '');
+    const custom = props.data.settings.customThemes.find(
+        ({url}) => isURLInList(props.tab.url, url)
+    );
+
+    const defaultPresetName = 'Default theme';
+    const customPresetName = `Custom for ${host}`;
+
+    function onPresetChange(name: string) {
+        const filteredCustomThemes = props.data.settings.customThemes.filter(({url}) => !isURLInList(props.tab.url, url));
+        if (name === defaultPresetName) {
+            props.actions.changeSettings({customThemes: filteredCustomThemes});
+        } else if (name === customPresetName) {
+            const extended = filteredCustomThemes.concat({
+                url: [host],
+                theme: {...props.data.settings.theme},
+            });
+            props.actions.changeSettings({customThemes: extended});
+        }
+    }
+    return (
+        <DropDown
+            class="theme-preset-picker"
+            selected={custom ? customPresetName : defaultPresetName}
+            values={[
+                defaultPresetName,
+                customPresetName,
+            ]}
+            onChange={onPresetChange}
+        />
+    );
+}
diff --git a/src/ui/popup/theme/preset-picker/style.less b/src/ui/popup/theme/preset-picker/style.less
new file mode 100644
index 00000000..ac0d25f1
--- /dev/null
+++ b/src/ui/popup/theme/preset-picker/style.less
@@ -0,0 +1,13 @@
+.theme-preset-picker {
+    .dropdown {
+        &__selected {
+            border-radius: unset;
+            height: @size-control-inner;
+            line-height: @size-control-inner;
+            margin-top: 0;
+        }
+        &__list {
+            border-radius: unset;
+        }
+    }
+}
diff --git a/src/ui/popup/theme/utils.ts b/src/ui/popup/theme/utils.ts
new file mode 100644
index 00000000..e81a6c23
--- /dev/null
+++ b/src/ui/popup/theme/utils.ts
@@ -0,0 +1,28 @@
+import {Theme} from '../../../definitions';
+import {isURLInList} from '../../../utils/url';
+import {ViewProps} from '../types';
+
+export function getCurrentThemePreset(props: ViewProps) {
+    const custom = props.data.settings.customThemes.find(
+        ({url}) => isURLInList(props.tab.url, url)
+    );
+    const theme = custom ?
+        custom.theme :
+        props.data.settings.theme;
+
+    function setTheme(config: Partial<Theme>) {
+        if (custom) {
+            custom.theme = {...custom.theme, ...config};
+            props.actions.changeSettings({
+                customThemes: props.data.settings.customThemes,
+            });
+        } else {
+            props.actions.setTheme(config);
+        }
+    }
+
+    return {
+        theme,
+        change: setTheme,
+    };
+}
\ No newline at end of file
diff --git a/src/ui/popup/types.d.ts b/src/ui/popup/types.d.ts
new file mode 100644
index 00000000..64c90090
--- /dev/null
+++ b/src/ui/popup/types.d.ts
@@ -0,0 +1,7 @@
+import {ExtensionData, ExtensionActions, TabInfo} from '../../definitions';
+
+export interface ViewProps {
+    actions: ExtensionActions;
+    data: ExtensionData;
+    tab: TabInfo;
+}
diff --git a/src/utils/platform.ts b/src/utils/platform.ts
index 806fc78f..31cec82e 100644
--- a/src/utils/platform.ts
+++ b/src/utils/platform.ts
@@ -1,3 +1,7 @@
+export function isChromiumBased() {
+    return navigator.userAgent.toLowerCase().includes('chrome') || navigator.userAgent.toLowerCase().includes('chromium');
+}
+
 export function isFirefox() {
     return navigator.userAgent.includes('Firefox');
 }
diff --git a/src/utils/url.ts b/src/utils/url.ts
index 5395384a..6a295aac 100644
--- a/src/utils/url.ts
+++ b/src/utils/url.ts
@@ -96,7 +96,36 @@ function createUrlRegex(urlTemplate: string): RegExp {
     return new RegExp(result, 'i');
 }
 
+export function isPDF(url: string) {
+    if (url.includes('.pdf')) {
+        if (url.includes('?')) {
+            url = url.substring(0, url.lastIndexOf('?'));
+        }
+        if (url.includes('#')) {
+            url = url.substring(0, url.lastIndexOf('#'));
+        }
+        if (url.endsWith('.pdf')) {
+            for (let i = url.length; 0 < i; i--) {
+                if (url[i] === '=') {
+                    return false;
+                } else if (url[i] === '/') {
+                    return true;
+                }
+            }
+        } else {
+            return false;
+        }
+    }
+    return false;
+}
+
 export function isURLEnabled(url: string, userSettings: UserSettings, {isProtected, isInDarkList}) {
+    if (isPDF(url) && userSettings.enableForPDF) {
+        return true;
+    }
+    if (isPDF(url) && !userSettings.enableForPDF) {
+        return false;
+    }
     if (isProtected) {
         return false;
     }


Test patch:
diff --git a/tests/config.tests.ts b/tests/config.tests.ts
index 29ddeff0..36aa7548 100644
--- a/tests/config.tests.ts
+++ b/tests/config.tests.ts
@@ -62,7 +62,7 @@ test('Dynamic Theme Fixes config', async () => {
     expect(fixes.map(({url}) => url[0])).toEqual(fixes.map(({url}) => url[0]).sort(compareURLPatterns));
 
     // selectors should have no comma
-    expect(fixes.every(({invert}) => (invert || []).every((s) => s.indexOf(',') < 0))).toBe(true);
+    expect(fixes.every(({invert, ignoreInlineStyle}) => (invert || []).concat(ignoreInlineStyle || []).every((s) => s.indexOf(',') < 0))).toBe(true);
 
     // fixes are properly formatted
     expect(throwIfDifferent(file, formatDynamicThemeFixes(fixes), 'Dynamic fixes format error')).not.toThrow();
@@ -81,9 +81,13 @@ test('Dynamic Theme Fixes config', async () => {
         'twitter.com',
         'UNSUPPORTED', 'a', 'b',
         'INVERT', 'c', 'd',
+        '========',
+        'wikipedia.org',
+        'IGNORE INLINE STYLE', 'a', 'b',
     ].join('\r\n'))).toEqual([
         {url: ['inbox.google.com', 'mail.google.com'], invert: ['a', 'b'], css: '.x { color: white !important; }'},
         {url: ['twitter.com'], invert: ['c', 'd']},
+        {url: ['wikipedia.org'], ignoreInlineStyle: ['a', 'b']},
     ]);
 });
 
diff --git a/tests/inject/dynamic.tests.ts b/tests/inject/dynamic.tests.ts
new file mode 100644
index 00000000..45fcc458
--- /dev/null
+++ b/tests/inject/dynamic.tests.ts
@@ -0,0 +1,10 @@
+import {getAbsoluteURL} from '../../src/inject/dynamic-theme/url';
+
+test('Absolute URL', () => {
+    expect(getAbsoluteURL('https://www.google.com', '/image.jpg')).toBe('https://www.google.com/image.jpg');
+    expect(getAbsoluteURL('https://www.google.com/path', '/image.jpg')).toBe('https://www.google.com/image.jpg');
+    expect(getAbsoluteURL('https://www.google.com/path', 'image.jpg')).toBe('https://www.google.com/path/image.jpg');
+    expect(getAbsoluteURL('https://www.google.com/long/path', '../image.jpg')).toBe('https://www.google.com/long/image.jpg');
+    expect(getAbsoluteURL('https://www.google.com/path/page.html', 'image.jpg')).toBe('https://www.google.com/path/image.jpg');
+    expect(getAbsoluteURL('https://www.google.com/path/page.html', '../image.jpg')).toBe('https://www.google.com/image.jpg');
+});
diff --git a/tests/inject/jest.config.js b/tests/inject/jest.config.js
new file mode 100644
index 00000000..bb1ff3e4
--- /dev/null
+++ b/tests/inject/jest.config.js
@@ -0,0 +1,26 @@
+module.exports = {
+    verbose: true,
+    testEnvironment: 'jsdom',
+    transform: {
+        '^.+\\.ts(x?)$': 'ts-jest'
+    },
+    testRegex: 'tests/inject/.*\\.tests\\.ts(x?)$',
+    moduleFileExtensions: [
+        'ts',
+        'tsx',
+        'js'
+    ],
+    collectCoverage: false,
+    coverageDirectory: 'coverage',
+    collectCoverageFrom: [
+        'src/**/*.{ts,tsx}'
+    ],
+    coveragePathIgnorePatterns: [
+        '^.+\\.d\\.ts$'
+    ],
+    globals: {
+        'ts-jest': {
+            tsConfig: './tests/inject/tsconfig.json'
+        }
+    }
+};
diff --git a/tests/inject/tsconfig.json b/tests/inject/tsconfig.json
new file mode 100644
index 00000000..8b2052d4
--- /dev/null
+++ b/tests/inject/tsconfig.json
@@ -0,0 +1,10 @@
+{
+    "extends": "../../src/tsconfig",
+    "compilerOptions": {
+        "module": "commonjs",
+        "outDir": "",
+        "types": [
+            "jest"
+        ]
+    }
+}
diff --git a/tests/jest.config.js b/tests/jest.config.js
index e4f41732..5482690a 100644
--- a/tests/jest.config.js
+++ b/tests/jest.config.js
@@ -4,7 +4,7 @@ module.exports = {
     transform: {
         '^.+\\.ts(x?)$': 'ts-jest'
     },
-    testRegex: 'tests/.*\\.tests\\.ts(x?)$',
+    testRegex: 'tests/[^/]*\\.tests\\.ts(x?)$',
     moduleFileExtensions: [
         'ts',
         'tsx',
diff --git a/tests/url.tests.ts b/tests/url.tests.ts
index ca6b1d46..a0b78348 100644
--- a/tests/url.tests.ts
+++ b/tests/url.tests.ts
@@ -1,4 +1,4 @@
-import {isURLEnabled} from '../src/utils/url';
+import {isURLEnabled, isPDF} from '../src/utils/url';
 import {UserSettings} from '../src/definitions';
 
 test('URL is enabled', () => {
@@ -67,6 +67,16 @@ test('URL is enabled', () => {
         {siteList: ['chrome.google.com'], siteListEnabled: [], applyToListedOnly: true} as UserSettings,
         {isProtected: true, isInDarkList: false},
     )).toBe(false);
+    expect(isURLEnabled(
+        'https://microsoftedge.microsoft.com/addons',
+        {siteList: ['microsoftedge.microsoft.com'], siteListEnabled: [], applyToListedOnly: false} as UserSettings,
+        {isProtected: true, isInDarkList: false},
+    )).toBe(false);
+    expect(isURLEnabled(
+        'https://microsoftedge.microsoft.com/addons',
+        {siteList: ['microsoftedge.microsoft.com'], siteListEnabled: [], applyToListedOnly: true} as UserSettings,
+        {isProtected: true, isInDarkList: false},
+    )).toBe(false);
     expect(isURLEnabled(
         'https://darkreader.org/',
         {siteList: [], siteListEnabled: [], applyToListedOnly: false} as UserSettings,
@@ -77,6 +87,43 @@ test('URL is enabled', () => {
         {siteList: ['darkreader.org'], siteListEnabled: [], applyToListedOnly: true} as UserSettings,
         {isProtected: false, isInDarkList: true},
     )).toBe(true);
+    expect(isURLEnabled(
+        'https://www.google.com/file.pdf',
+        {enableForPDF: true, siteList: ['darkreader.org'], siteListEnabled: [], applyToListedOnly: true} as UserSettings,
+        {isProtected: false, isInDarkList: false},
+    )).toBe(true);
+    expect(isURLEnabled(
+        'https://www.google.com/file.pdf/resource',
+        {enableForPDF: true, siteList: ['darkreader.org'], siteListEnabled: [], applyToListedOnly: true} as UserSettings,
+        {isProtected: false, isInDarkList: false},
+    )).toBe(false);
+    expect(isURLEnabled(
+        'https://www.google.com/file.pdf/resource',
+        {enableForPDF: true, siteList: ['darkreader.org'], siteListEnabled: [], applyToListedOnly: false} as UserSettings,
+        {isProtected: false, isInDarkList: false},
+    )).toBe(true);
+    expect(isURLEnabled(
+        'https://www.google.com/very/good/hidden/folder/pdf#file.pdf',
+        {enableForPDF: true, siteList: ['https://www.google.com/very/good/hidden/folder/pdf#file.pdf'], siteListEnabled: [], applyToListedOnly: false} as UserSettings,
+        {isProtected: false, isInDarkList: false},
+    )).toBe(false);
+
+    // Test for PDF enabling
+    expect(isPDF(
+        'https://www.google.com/file.pdf'
+    )).toBe(true);
+    expect(isPDF(
+        'https://www.google.com/file.pdf?id=2'
+    )).toBe(true);
+    expect(isPDF(
+        'https://www.google.com/file.pdf/resource'
+    )).toBe(false);
+    expect(isPDF(
+        'https://www.google.com/resource?file=file.pdf'
+    )).toBe(false);
+    expect(isPDF(
+        'https://www.google.com/very/good/hidden/folder/pdf#file.pdf'
+    )).toBe(false);
 
     // Temporary Dark Sites list fix
     expect(isURLEnabled(