diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index 770bf6da02..0000000000
--- a/.editorconfig
+++ /dev/null
@@ -1,11 +0,0 @@
-# http://editorconfig.org
-
-root = true
-
-[*.ts]
-charset = utf-8
-indent_style = space
-indent_size = 4
-end_of_line = lf
-insert_final_newline = true
-trim_trailing_whitespace = true
diff --git a/.eslintrc.js b/.eslintrc.js
deleted file mode 100644
index 823a412fc7..0000000000
--- a/.eslintrc.js
+++ /dev/null
@@ -1,32 +0,0 @@
-module.exports = {
-    root: true,
-    env: {
-        node: true
-    },
-    parser: "@typescript-eslint/parser",
-    parserOptions: {
-        project: ['./tsconfig.json']
-    },
-    plugins: [
-        "@typescript-eslint"
-    ],
-    extends: [
-        "eslint:recommended",
-        "plugin:@typescript-eslint/eslint-recommended",
-        "plugin:@typescript-eslint/recommended",
-        "plugin:@typescript-eslint/recommended-requiring-type-checking"
-    ],
-    ignorePatterns: ["**/*.js"],
-    rules: {
-        "no-prototype-builtins": "off",
-        "@typescript-eslint/no-inferrable-types": "off",
-        "@typescript-eslint/no-non-null-assertion": "off",
-        "@typescript-eslint/no-unused-vars": "off",
-        "@typescript-eslint/no-explicit-any": "off",
-        "@typescript-eslint/member-ordering": "error",
-        "@typescript-eslint/unbound-method": ["error", {
-            "ignoreStatic": true
-        }],
-        "@typescript-eslint/prefer-includes": "off"
-    }
-};
diff --git a/.eslintrc.yml b/.eslintrc.yml
new file mode 100644
index 0000000000..99b6567513
--- /dev/null
+++ b/.eslintrc.yml
@@ -0,0 +1,34 @@
+parser: '@typescript-eslint/parser'
+plugins:
+  - '@typescript-eslint'
+parserOptions:
+  ecmaVersion: 2018
+  sourceType: module
+  project: 
+    - ./tsconfig.json
+    - ./tsconfig.spec.json
+extends:
+  - 'plugin:@typescript-eslint/recommended'
+  - 'plugin:@typescript-eslint/recommended-requiring-type-checking'
+  - 'plugin:jest/recommended'
+  - 'prettier'
+  - 'prettier/@typescript-eslint'
+rules:
+  '@typescript-eslint/explicit-member-accessibility': off
+  '@typescript-eslint/no-angle-bracket-type-assertion': off
+  '@typescript-eslint/no-parameter-properties': off
+  '@typescript-eslint/explicit-function-return-type': off
+  '@typescript-eslint/member-delimiter-style': off
+  '@typescript-eslint/no-inferrable-types': off
+  '@typescript-eslint/no-explicit-any': off
+  '@typescript-eslint/member-ordering': 'error'
+  '@typescript-eslint/no-unused-vars':
+    - 'error'
+    - args: 'none'
+  # TODO: Remove these and fixed issues once we merged all the current PRs. 
+  '@typescript-eslint/ban-types': off 
+  '@typescript-eslint/no-unsafe-return': off
+  '@typescript-eslint/no-unsafe-assignment': off
+  '@typescript-eslint/no-unsafe-call': off
+  '@typescript-eslint/no-unsafe-member-access': off
+  '@typescript-eslint/explicit-module-boundary-types': off
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000000..fde1469329
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,13 @@
+version: 2
+updates:
+- package-ecosystem: npm
+  directory: "/"
+  schedule:
+    interval: daily
+    time: "10:00"
+    timezone: Europe/Budapest
+  open-pull-requests-limit: 5
+  versioning-strategy: increase
+  commit-message:
+    prefix: build
+    include: scope
diff --git a/.github/issue_template.md b/.github/issue_template.md
deleted file mode 100644
index 17f65ac671..0000000000
--- a/.github/issue_template.md
+++ /dev/null
@@ -1,32 +0,0 @@
-<!--🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅
-
-Oh hi there! 😄
-
-To expedite issue processing please search open and closed issues before submitting a new one.
-Existing issues often contain information about workarounds, resolution, or progress updates.
-
-🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅🔅-->
-
-### Description
-
-<!-- ✍️ edit: --> A clear and concise description of the problem/question...
-
-### Reproduction
-
-<!--
-Please create and share reproduction of the issue starting with this template: https://stackblitz.com/fork/class-validator-boilerplate
--->
-<!-- ✍️ edit: --> https://stackblitz.com/...
-
-<!--
-If StackBlitz is not suitable for reproduction of your issue, please create a minimal GitHub repository with the reproduction of the issue.
-Share the link to the repo below along with step-by-step instructions to reproduce the problem, as well as expected and actual behavior.
--->
-
-### Environment
-
-- [ ] nodejs: <!-- ✍️ edit: nodejs version -->
-- [ ] browser: <!-- ✍️ edit: browser version -->
-- [ ] framework/library: <!-- ✍️ edit: e.g. angular, nestjs + version -->
-
-**class-validator version:** <code><!-- ✍️je  edit: --></code>
diff --git a/.github/lock.yml b/.github/lock.yml
deleted file mode 100644
index 9346c21eb8..0000000000
--- a/.github/lock.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-# Configuration for lock-threads - https://github.com/dessant/lock-threads
-
-# Number of days of inactivity before a closed issue or pull request is locked
-daysUntilLock: 7
-
-# Label to add before locking, such as `outdated`. Set to `false` to disable
-lockLabel: false
-
-# Comment to post before locking. Set to `false` to disable
-lockComment: >
-  This thread has been automatically locked since there has not been
-  any recent activity after it was closed. Please open a new issue for
-  related bugs.
-
-# Limit to only `issues` or `pulls`
-only: issues
diff --git a/.github/semantic.yml b/.github/semantic.yml
new file mode 100644
index 0000000000..d74c23950c
--- /dev/null
+++ b/.github/semantic.yml
@@ -0,0 +1,18 @@
+titleAndCommits: true
+allowMergeCommits: false
+scopes:
+  - deps
+  - deps-dev
+types:
+  - feat
+  - fix
+  - docs
+  - style
+  - refactor
+  - perf
+  - test
+  - build
+  - ci
+  - chore
+  - revert
+  - merge
diff --git a/.github/workflows/auto-approve-dependabot-workflow.yml b/.github/workflows/auto-approve-dependabot-workflow.yml
new file mode 100644
index 0000000000..167f9f1b79
--- /dev/null
+++ b/.github/workflows/auto-approve-dependabot-workflow.yml
@@ -0,0 +1,11 @@
+name: Auto approve PRs
+on:
+  pull_request
+jobs:
+  dependabot:
+    runs-on: ubuntu-latest
+    steps:
+    - uses: hmarr/auto-approve-action@v2.0.0
+      if: github.actor == 'dependabot[bot]'
+      with:
+        github-token: "${{ secrets.GITHUB_TOKEN }}"
diff --git a/.github/workflows/continuous-deployment-workflow.yml b/.github/workflows/continuous-deployment-workflow.yml
new file mode 100644
index 0000000000..bc8c5f5812
--- /dev/null
+++ b/.github/workflows/continuous-deployment-workflow.yml
@@ -0,0 +1,28 @@
+name: CD
+on:
+  release:
+    types: [created]
+jobs:
+  publish:
+    name: Publish to NPM
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - uses: actions/setup-node@v1
+        with:
+          registry-url: https://registry.npmjs.org
+      - run: npm ci --ignore-scripts
+      - run: npm run prettier:check
+      - run: npm run lint:check
+      - run: npm run test:ci
+      - run: npm run build:es2015
+      - run: npm run build:esm5
+      - run: npm run build:cjs
+      - run: npm run build:umd
+      - run: npm run build:types
+      - run: cp LICENSE build/LICENSE
+      - run: cp README.md build/README.md
+      - run: jq 'del(.devDependencies) | del(.scripts)' package.json > build/package.json
+      - run: npm publish ./build
+        env:
+          NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
diff --git a/.github/workflows/continuous-integration-workflow.yml b/.github/workflows/continuous-integration-workflow.yml
new file mode 100644
index 0000000000..c8faa310e9
--- /dev/null
+++ b/.github/workflows/continuous-integration-workflow.yml
@@ -0,0 +1,43 @@
+name: CI
+on: [push, pull_request]
+jobs:
+  checks:
+    name: Linters
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - uses: actions/setup-node@v1
+      - run: npm ci --ignore-scripts
+      - run: npm run prettier:check
+      - run: npm run lint:check
+  tests:
+    name: Tests
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        node-version: ['10.x', '12.x', '14.x']
+      fail-fast: false
+    steps:
+      - uses: actions/checkout@v1
+      - name: Setting up Node.js (v${{ matrix.node-version }}.x)
+        uses: actions/setup-node@v1
+        with:
+          node-version: ${{ matrix.node-version }}
+      - run: npm ci --ignore-scripts
+      - run: npm run test:ci
+      - run: npm install codecov -g
+        if: ${{ matrix.node-version == '14.x' }}
+      - run: codecov -f ./coverage/clover.xml -t ${{ secrets.CODECOV_TOKEN }} --commit=$GITHUB_SHA --branch=${GITHUB_REF##*/}
+        if: ${{ matrix.node-version == '14.x' }}
+  build:
+    name: Build
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - uses: actions/setup-node@v1
+      - run: npm ci --ignore-scripts
+      - run: npm run build:es2015
+      - run: npm run build:esm5
+      - run: npm run build:cjs
+      - run: npm run build:umd
+      - run: npm run build:types
diff --git a/.github/workflows/lock-closed-issues-workflow.yml b/.github/workflows/lock-closed-issues-workflow.yml
new file mode 100644
index 0000000000..c380eafbd5
--- /dev/null
+++ b/.github/workflows/lock-closed-issues-workflow.yml
@@ -0,0 +1,22 @@
+name: 'Lock inactive threads'
+on:
+  schedule:
+    - cron: '0 0 * * *'
+jobs:
+  lock:
+    name: Lock closed issues
+    runs-on: ubuntu-latest
+    steps:
+      - uses: dessant/lock-threads@v2
+        with:
+          github-token: ${{ github.token }}
+          issue-lock-inactive-days: 30
+          pr-lock-inactive-days: 30
+          issue-lock-comment: >
+            This issue has been automatically locked since there
+            has not been any recent activity after it was closed.
+            Please open a new issue for related bugs.
+          pr-lock-comment: >
+            This pull request has been automatically locked since there
+            has not been any recent activity after it was closed.
+            Please open a new issue for related bugs.
diff --git a/.gitignore b/.gitignore
index 321cdfe19d..905e735144 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,48 +1,52 @@
-# Logs
+# Log files
 logs
 *.log
+*.tmp
+*.tmp.*
+log.txt
 npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-lerna-debug.log*
 
-# Diagnostic reports (https://nodejs.org/api/report.html)
-report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+# Testing output
+lib-cov/**
+coverage/**
 
-# Runtime data
-pids
-*.pid
-*.seed
-*.pid.lock
+# Environment files
+.env
 
-# Yarn Integrity file
-.yarn-integrity
-
-# Output of 'npm pack'
-*.tgz
+# Dependency directories
+node_modules
 
-# Optional npm cache directory
-.npm
+# MacOS related files
+*.DS_Store
+.AppleDouble
+.LSOverride
+._*
+UserInterfaceState.xcuserstate
 
-# TypeScript v1 declaration files
-typings/
+# Windows related files
+Thumbs.db
+Desktop.ini
+$RECYCLE.BIN/
 
-# TypeScript cache
-*.tsbuildinfo
+# IDE - Sublime
+*.sublime-project
+*.sublime-workspace
 
-# Coverage report dir
-coverage/
+# IDE - VSCode
+.vscode/**
+!.vscode/tasks.json
+!.vscode/launch.json
 
-# Dependency directories
-node_modules/
+# IDE - IntelliJ
+.idea
 
-# rollup.js build output
+# Compilation output folders
 dist/
 build/
+tmp/
+out-tsc/
+temp
 
-
-# IDEs
-*.iml
-.idea/
-.vscode/
-
+# Files for playing around locally
+playground.ts
+playground.js
diff --git a/.prettierrc.yml b/.prettierrc.yml
new file mode 100644
index 0000000000..57c1c99c9e
--- /dev/null
+++ b/.prettierrc.yml
@@ -0,0 +1,8 @@
+printWidth: 120
+tabWidth: 2
+useTabs: false
+semi: true
+singleQuote: true
+trailingComma: es5
+bracketSpacing: true
+arrowParens: avoid
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index c84abcae35..0000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-language: node_js
-node_js:
-  - stable
-  - lts/*
-
-after_success:
-  - bash <(curl -s https://codecov.io/bash)
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c3190c410e..429fff7258 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,237 +1,234 @@
-## [0.12.2](https://github.com/typestack/class-validator/compare/v0.12.1...v0.12.2) (2020-04-23)
+## [0.13.0](https://github.com/typestack/class-validator/compare/v0.12.2...v0.13.0) (2021-01-11)
 
+### Added
 
-### Bug Fixes
+- **project is restructured to allow three-shaking**
+- added option to fail on first validation error (#620)
+- two new validator option is added:
+  - `always` - allows setting global default for `always` option for decorators
+  - `strictGroups` - ignore decorators with at least one group, when `ValidatorOptions.groups` is empty
 
-* move `tslib` from `peerDependencies` to `dependencies` ([827eff1](https://github.com/typestack/class-validator/commit/827eff1)), closes [#588](https://github.com/typestack/class-validator/issues/588)
+### Fixed
 
+- the 'any' locale is allowed in the `isPostalCode` decorator (#634)
+- the `IsDateString()` decorator now aliases the `IsISO8601()` decorator (#672)
 
+### Changed
 
-## [0.12.1](https://github.com/typestack/class-validator/compare/v0.12.0...v0.12.1) (2020-04-18)
+- project tooling has been updated significantly
+- google-libphonenumber has been replaced with libphonenumber-js (this should have no effect on validation)
+- build process generates include both ES/CommonJS and UMD variations
+- various dev dependencies has been updated
 
+## [0.12.2](https://github.com/typestack/class-validator/compare/v0.12.1...v0.12.2) (2020-04-23)
 
 ### Bug Fixes
 
-* apply only nested validator for ValidateNested multi-dimensional array ([c463be5](https://github.com/typestack/class-validator/commit/c463be5))
+- move `tslib` from `peerDependencies` to `dependencies` ([827eff1](https://github.com/typestack/class-validator/commit/827eff1)), closes [#588](https://github.com/typestack/class-validator/issues/588)
 
+## [0.12.1](https://github.com/typestack/class-validator/compare/v0.12.0...v0.12.1) (2020-04-18)
+
+### Bug Fixes
 
+- apply only nested validator for ValidateNested multi-dimensional array ([c463be5](https://github.com/typestack/class-validator/commit/c463be5))
 
 # [0.12.0](https://github.com/typestack/class-validator/compare/v0.11.1...v0.12.0) (2020-04-18)
 
-
 ### Bug Fixes
 
-* accept negative timezone in isDateString ([#564](https://github.com/typestack/class-validator/issues/564)) ([2012d72](https://github.com/typestack/class-validator/commit/2012d72)), closes [#565](https://github.com/typestack/class-validator/issues/565)
-* apply all decorators type PropertyDecorator ([#556](https://github.com/typestack/class-validator/issues/556)) ([5fb36e3](https://github.com/typestack/class-validator/commit/5fb36e3)), closes [#555](https://github.com/typestack/class-validator/issues/555)
-* avoiding metadataStorage from DI ([#335](https://github.com/typestack/class-validator/issues/335)) ([b57fef4](https://github.com/typestack/class-validator/commit/b57fef4)), closes [#328](https://github.com/typestack/class-validator/issues/328) [#261](https://github.com/typestack/class-validator/issues/261) [#132](https://github.com/typestack/class-validator/issues/132)
-* correct registerDecorator options argument ([7909ec6](https://github.com/typestack/class-validator/commit/7909ec6)), closes [#302](https://github.com/typestack/class-validator/issues/302)
-* IsNumberString accept isNumbericOptions as argument ([62b993f](https://github.com/typestack/class-validator/commit/62b993f)), closes [#518](https://github.com/typestack/class-validator/issues/518) [#463](https://github.com/typestack/class-validator/issues/463)
-* optional `constraints` property in ValidationError ([#465](https://github.com/typestack/class-validator/issues/465)) ([84680ad](https://github.com/typestack/class-validator/commit/84680ad)), closes [#309](https://github.com/typestack/class-validator/issues/309)
-* pass context to ValidationError for async validations ([#533](https://github.com/typestack/class-validator/issues/533)) ([4eb1216](https://github.com/typestack/class-validator/commit/4eb1216))
-* switch isLatitude & isLongitude validators ([#513](https://github.com/typestack/class-validator/issues/513)) ([5497179](https://github.com/typestack/class-validator/commit/5497179)), closes [#502](https://github.com/typestack/class-validator/issues/502)
-* switch isLatitude & isLongitude validators ([#537](https://github.com/typestack/class-validator/issues/537)) ([c27500b](https://github.com/typestack/class-validator/commit/c27500b))
-* ValidateNested support multi-dimensional arrays ([#539](https://github.com/typestack/class-validator/issues/539)) ([62678e1](https://github.com/typestack/class-validator/commit/62678e1))
-
+- accept negative timezone in isDateString ([#564](https://github.com/typestack/class-validator/issues/564)) ([2012d72](https://github.com/typestack/class-validator/commit/2012d72)), closes [#565](https://github.com/typestack/class-validator/issues/565)
+- apply all decorators type PropertyDecorator ([#556](https://github.com/typestack/class-validator/issues/556)) ([5fb36e3](https://github.com/typestack/class-validator/commit/5fb36e3)), closes [#555](https://github.com/typestack/class-validator/issues/555)
+- avoiding metadataStorage from DI ([#335](https://github.com/typestack/class-validator/issues/335)) ([b57fef4](https://github.com/typestack/class-validator/commit/b57fef4)), closes [#328](https://github.com/typestack/class-validator/issues/328) [#261](https://github.com/typestack/class-validator/issues/261) [#132](https://github.com/typestack/class-validator/issues/132)
+- correct registerDecorator options argument ([7909ec6](https://github.com/typestack/class-validator/commit/7909ec6)), closes [#302](https://github.com/typestack/class-validator/issues/302)
+- IsNumberString accept isNumbericOptions as argument ([62b993f](https://github.com/typestack/class-validator/commit/62b993f)), closes [#518](https://github.com/typestack/class-validator/issues/518) [#463](https://github.com/typestack/class-validator/issues/463)
+- optional `constraints` property in ValidationError ([#465](https://github.com/typestack/class-validator/issues/465)) ([84680ad](https://github.com/typestack/class-validator/commit/84680ad)), closes [#309](https://github.com/typestack/class-validator/issues/309)
+- pass context to ValidationError for async validations ([#533](https://github.com/typestack/class-validator/issues/533)) ([4eb1216](https://github.com/typestack/class-validator/commit/4eb1216))
+- switch isLatitude & isLongitude validators ([#513](https://github.com/typestack/class-validator/issues/513)) ([5497179](https://github.com/typestack/class-validator/commit/5497179)), closes [#502](https://github.com/typestack/class-validator/issues/502)
+- switch isLatitude & isLongitude validators ([#537](https://github.com/typestack/class-validator/issues/537)) ([c27500b](https://github.com/typestack/class-validator/commit/c27500b))
+- ValidateNested support multi-dimensional arrays ([#539](https://github.com/typestack/class-validator/issues/539)) ([62678e1](https://github.com/typestack/class-validator/commit/62678e1))
 
 ### Code Refactoring
 
-* update build process to enable tree shaking ([#568](https://github.com/typestack/class-validator/issues/568)) ([11a7b8b](https://github.com/typestack/class-validator/commit/11a7b8b)), closes [#258](https://github.com/typestack/class-validator/issues/258) [#248](https://github.com/typestack/class-validator/issues/248) [#247](https://github.com/typestack/class-validator/issues/247) [#212](https://github.com/typestack/class-validator/issues/212)
-
+- update build process to enable tree shaking ([#568](https://github.com/typestack/class-validator/issues/568)) ([11a7b8b](https://github.com/typestack/class-validator/commit/11a7b8b)), closes [#258](https://github.com/typestack/class-validator/issues/258) [#248](https://github.com/typestack/class-validator/issues/248) [#247](https://github.com/typestack/class-validator/issues/247) [#212](https://github.com/typestack/class-validator/issues/212)
 
 ### Features
 
-* sync validatorjs version from v10.11.3 to v13.0.0 ([09120b7](https://github.com/typestack/class-validator/commit/09120b7)), closes [#576](https://github.com/typestack/class-validator/issues/576) [#425](https://github.com/typestack/class-validator/issues/425)
-
+- sync validatorjs version from v10.11.3 to v13.0.0 ([09120b7](https://github.com/typestack/class-validator/commit/09120b7)), closes [#576](https://github.com/typestack/class-validator/issues/576) [#425](https://github.com/typestack/class-validator/issues/425)
 
 ### BREAKING CHANGES
 
-* Validatorjs releases contain some breaking changes e.g. `IsMobileNumber` or `IsHexColor`. Please check validatorjs [CHANGELOG](https://github.com/validatorjs/validator.js/blob/master/CHANGELOG.md)
-* Validation functions was removed from `Validator` class to enable tree shaking.
+- Validatorjs releases contain some breaking changes e.g. `IsMobileNumber` or `IsHexColor`. Please check validatorjs [CHANGELOG](https://github.com/validatorjs/validator.js/blob/master/CHANGELOG.md)
+- Validation functions was removed from `Validator` class to enable tree shaking.
 
   BEFORE:
+
   ```ts
-      import {Validator} from "class-validator";
+  import { Validator } from 'class-validator';
 
-      const validator = new Validator();
-      validator.isNotIn(value, possibleValues);
-      validator.isBoolean(value);
+  const validator = new Validator();
+  validator.isNotIn(value, possibleValues);
+  validator.isBoolean(value);
   ```
+
   AFTER:
+
   ```ts
-      import {isNotIn, isBoolean} from "class-validator";
+  import { isNotIn, isBoolean } from 'class-validator';
 
-      isNotIn(value, possibleValues);
-      isBoolean(value);
+  isNotIn(value, possibleValues);
+  isBoolean(value);
   ```
-* IsNumberString decorator arguments changed to `@IsNumberString(ValidatorJS.IsNumericOptions, ValidationOptions)`.
-
 
+- IsNumberString decorator arguments changed to `@IsNumberString(ValidatorJS.IsNumericOptions, ValidationOptions)`.
 
 ## [0.11.1](https://github.com/typestack/class-validator/compare/v0.11.0...v0.11.1) (2020-03-18)
 
-
 ### Bug Fixes
 
-* IsNumber validator now works when maxDecimalPlaces=0 ([#524](https://github.com/typestack/class-validator/issues/524)) ([b8aa922](https://github.com/typestack/class-validator/commit/b8aa922))
-
+- IsNumber validator now works when maxDecimalPlaces=0 ([#524](https://github.com/typestack/class-validator/issues/524)) ([b8aa922](https://github.com/typestack/class-validator/commit/b8aa922))
 
 ### Features
 
-* add all option in isuuid validator ([#452](https://github.com/typestack/class-validator/issues/452)) ([98e9382](https://github.com/typestack/class-validator/commit/98e9382))
-* add IsFirebasePushId validator ([#548](https://github.com/typestack/class-validator/issues/548)) ([e7e2e53](https://github.com/typestack/class-validator/commit/e7e2e53))
-* add options for isISO8601 validator ([#460](https://github.com/typestack/class-validator/issues/460)) ([90a6638](https://github.com/typestack/class-validator/commit/90a6638))
-
-
+- add all option in isuuid validator ([#452](https://github.com/typestack/class-validator/issues/452)) ([98e9382](https://github.com/typestack/class-validator/commit/98e9382))
+- add IsFirebasePushId validator ([#548](https://github.com/typestack/class-validator/issues/548)) ([e7e2e53](https://github.com/typestack/class-validator/commit/e7e2e53))
+- add options for isISO8601 validator ([#460](https://github.com/typestack/class-validator/issues/460)) ([90a6638](https://github.com/typestack/class-validator/commit/90a6638))
 
 # [0.11.0](https://github.com/typestack/class-validator/compare/v0.10.2...v0.11.0) (2019-11-01)
 
-
 ### Bug Fixes
 
-* create instance of ValidationError for whitelist errors ([#434](https://github.com/typestack/class-validator/issues/434)) ([a98f5dd](https://github.com/typestack/class-validator/commit/a98f5dd)), closes [#325](https://github.com/typestack/class-validator/issues/325)
-* pass context for isDefined and custom validators ([#296](https://github.com/typestack/class-validator/issues/296)) ([0ef898e](https://github.com/typestack/class-validator/commit/0ef898e)), closes [#292](https://github.com/typestack/class-validator/issues/292)
-
+- create instance of ValidationError for whitelist errors ([#434](https://github.com/typestack/class-validator/issues/434)) ([a98f5dd](https://github.com/typestack/class-validator/commit/a98f5dd)), closes [#325](https://github.com/typestack/class-validator/issues/325)
+- pass context for isDefined and custom validators ([#296](https://github.com/typestack/class-validator/issues/296)) ([0ef898e](https://github.com/typestack/class-validator/commit/0ef898e)), closes [#292](https://github.com/typestack/class-validator/issues/292)
 
 ### Features
 
-* add isHash validator ([#445](https://github.com/typestack/class-validator/issues/445)) ([c454cf9](https://github.com/typestack/class-validator/commit/c454cf9))
-* add isISSN validator ([#450](https://github.com/typestack/class-validator/issues/450)) ([4bd586e](https://github.com/typestack/class-validator/commit/4bd586e))
-* add isJWT validator ([#444](https://github.com/typestack/class-validator/issues/444)) ([874861b](https://github.com/typestack/class-validator/commit/874861b))
-* add isMACAddress validator ([#449](https://github.com/typestack/class-validator/issues/449)) ([45b7df7](https://github.com/typestack/class-validator/commit/45b7df7))
-* add support for maxDecimalPlaces on IsNumber ([#381](https://github.com/typestack/class-validator/issues/381)) ([a4dc10e](https://github.com/typestack/class-validator/commit/a4dc10e))
+- add isHash validator ([#445](https://github.com/typestack/class-validator/issues/445)) ([c454cf9](https://github.com/typestack/class-validator/commit/c454cf9))
+- add isISSN validator ([#450](https://github.com/typestack/class-validator/issues/450)) ([4bd586e](https://github.com/typestack/class-validator/commit/4bd586e))
+- add isJWT validator ([#444](https://github.com/typestack/class-validator/issues/444)) ([874861b](https://github.com/typestack/class-validator/commit/874861b))
+- add isMACAddress validator ([#449](https://github.com/typestack/class-validator/issues/449)) ([45b7df7](https://github.com/typestack/class-validator/commit/45b7df7))
+- add support for maxDecimalPlaces on IsNumber ([#381](https://github.com/typestack/class-validator/issues/381)) ([a4dc10e](https://github.com/typestack/class-validator/commit/a4dc10e))
 
 ### BREAKING CHANGES
 
-* update @types/validator from 11.1.0 to version 12.0.0 - please check it's [changelog][validator-js-release-notes]
-
-
+- update @types/validator from 11.1.0 to version 12.0.0 - please check it's [changelog][validator-js-release-notes]
 
 ## [0.10.2](https://github.com/typestack/class-validator/compare/v0.10.1...v0.10.2) (2019-10-14)
 
-
 ### Bug Fixes
 
-* apply custom constraint class validation to each item in the array ([#295](https://github.com/typestack/class-validator/issues/295)) ([5bb704e](https://github.com/typestack/class-validator/commit/5bb704e)), closes [#260](https://github.com/typestack/class-validator/issues/260)
-
+- apply custom constraint class validation to each item in the array ([#295](https://github.com/typestack/class-validator/issues/295)) ([5bb704e](https://github.com/typestack/class-validator/commit/5bb704e)), closes [#260](https://github.com/typestack/class-validator/issues/260)
 
 ### Features
 
-* add isLatLong, isLatitude, isLongtitude validators ([#427](https://github.com/typestack/class-validator/issues/427)) ([3fd15c4](https://github.com/typestack/class-validator/commit/3fd15c4)), closes [#415](https://github.com/typestack/class-validator/issues/415)
-* add IsObject and IsNotEmptyObject new decorators ([#334](https://github.com/typestack/class-validator/issues/334)) ([0a41aeb](https://github.com/typestack/class-validator/commit/0a41aeb))
-* support ES6 Map and Set for regular validators with each option ([#430](https://github.com/typestack/class-validator/issues/430)) ([a055bba](https://github.com/typestack/class-validator/commit/a055bba)), closes [#428](https://github.com/typestack/class-validator/issues/428)
-
-
+- add isLatLong, isLatitude, isLongtitude validators ([#427](https://github.com/typestack/class-validator/issues/427)) ([3fd15c4](https://github.com/typestack/class-validator/commit/3fd15c4)), closes [#415](https://github.com/typestack/class-validator/issues/415)
+- add IsObject and IsNotEmptyObject new decorators ([#334](https://github.com/typestack/class-validator/issues/334)) ([0a41aeb](https://github.com/typestack/class-validator/commit/0a41aeb))
+- support ES6 Map and Set for regular validators with each option ([#430](https://github.com/typestack/class-validator/issues/430)) ([a055bba](https://github.com/typestack/class-validator/commit/a055bba)), closes [#428](https://github.com/typestack/class-validator/issues/428)
 
 ## [0.10.1](https://github.com/typestack/class-validator/compare/v0.10.0...v0.10.1) (2019-09-25)
 
-
 ### Bug Fixes
 
-* add default message for isMilitaryTime validator ([#411](https://github.com/typestack/class-validator/issues/411)) ([204b7df](https://github.com/typestack/class-validator/commit/204b7df)), closes [#287](https://github.com/typestack/class-validator/issues/287)
-* add default message for isPort validator ([#404](https://github.com/typestack/class-validator/issues/404)) ([74e568c](https://github.com/typestack/class-validator/commit/74e568c))
-* add locale parameter for isAlpha and isAlphanumeric validat… ([#406](https://github.com/typestack/class-validator/issues/406)) ([2f4bf4e](https://github.com/typestack/class-validator/commit/2f4bf4e))
-
+- add default message for isMilitaryTime validator ([#411](https://github.com/typestack/class-validator/issues/411)) ([204b7df](https://github.com/typestack/class-validator/commit/204b7df)), closes [#287](https://github.com/typestack/class-validator/issues/287)
+- add default message for isPort validator ([#404](https://github.com/typestack/class-validator/issues/404)) ([74e568c](https://github.com/typestack/class-validator/commit/74e568c))
+- add locale parameter for isAlpha and isAlphanumeric validat… ([#406](https://github.com/typestack/class-validator/issues/406)) ([2f4bf4e](https://github.com/typestack/class-validator/commit/2f4bf4e))
 
 ### Features
 
-* add `skipUndefinedProperties`, `skipNullProperties` options ([#414](https://github.com/typestack/class-validator/issues/414)) ([76c948a](https://github.com/typestack/class-validator/commit/76c948a)), closes [#308](https://github.com/typestack/class-validator/issues/308)
-
-
+- add `skipUndefinedProperties`, `skipNullProperties` options ([#414](https://github.com/typestack/class-validator/issues/414)) ([76c948a](https://github.com/typestack/class-validator/commit/76c948a)), closes [#308](https://github.com/typestack/class-validator/issues/308)
 
 # [0.10.0](https://github.com/typestack/class-validator/compare/v0.9.1...v0.10.0) (2019-08-10)
 
 ### Bug Fixes
 
-* add correct signature for custom error message handler ([249c41d](https://github.com/typestack/class-validator/commit/249c41d))
+- add correct signature for custom error message handler ([249c41d](https://github.com/typestack/class-validator/commit/249c41d))
 
 ### Features
 
-* add `IsISO31661Alpha3` and `IsISO31661Alpha2` validators ([#273](https://github.com/typestack/class-validator/issues/273)) ([55c57b3](https://github.com/typestack/class-validator/commit/55c57b3))
-* **IsDecimal:** implement `IsDecimal` from validatorjs ([#359](https://github.com/typestack/class-validator/issues/359)) ([b4c8e21](https://github.com/typestack/class-validator/commit/b4c8e21))
-* add `isPort` decorator ([#282](https://github.com/typestack/class-validator/issues/282)) ([36684ec](https://github.com/typestack/class-validator/commit/36684ec))
-* allow validate Map/Set ([#365](https://github.com/typestack/class-validator/issues/365)) ([f6fcdc5](https://github.com/typestack/class-validator/commit/f6fcdc5))
-* new `ValidatePromise` decorator - resolve promise before validate ([#369](https://github.com/typestack/class-validator/issues/369)) ([35ec04d](https://github.com/typestack/class-validator/commit/35ec04d))
-* replace instanceof Promise and support Promise/A+  ([#310](https://github.com/typestack/class-validator/issues/310)) ([59eac09](https://github.com/typestack/class-validator/commit/59eac09))
-* `isNumberString` now accept validator.js `IsNumericOptions` as second parameter ([#262](https://github.com/typestack/class-validator/issues/262))
+- add `IsISO31661Alpha3` and `IsISO31661Alpha2` validators ([#273](https://github.com/typestack/class-validator/issues/273)) ([55c57b3](https://github.com/typestack/class-validator/commit/55c57b3))
+- **IsDecimal:** implement `IsDecimal` from validatorjs ([#359](https://github.com/typestack/class-validator/issues/359)) ([b4c8e21](https://github.com/typestack/class-validator/commit/b4c8e21))
+- add `isPort` decorator ([#282](https://github.com/typestack/class-validator/issues/282)) ([36684ec](https://github.com/typestack/class-validator/commit/36684ec))
+- allow validate Map/Set ([#365](https://github.com/typestack/class-validator/issues/365)) ([f6fcdc5](https://github.com/typestack/class-validator/commit/f6fcdc5))
+- new `ValidatePromise` decorator - resolve promise before validate ([#369](https://github.com/typestack/class-validator/issues/369)) ([35ec04d](https://github.com/typestack/class-validator/commit/35ec04d))
+- replace instanceof Promise and support Promise/A+ ([#310](https://github.com/typestack/class-validator/issues/310)) ([59eac09](https://github.com/typestack/class-validator/commit/59eac09))
+- `isNumberString` now accept validator.js `IsNumericOptions` as second parameter ([#262](https://github.com/typestack/class-validator/issues/262))
 
 ### BREAKING CHANGES
 
-* update @types/validator from 10.4.0 to version 10.11.2 - please check it's [changelog][validator-js-release-notes] ([cb960dd](https://github.com/typestack/class-validator/commit/cb960dd))
-* `isDateString` now check to match only entire ISO Date ([#275](https://github.com/typestack/class-validator/issues/275)) ([5012464](https://github.com/typestack/class-validator/commit/5012464))
-* remove `IsCurrencyOptions`, `IsURLOptions`, `IsEmailOptions`, `IsFQDNOptions` interfaces and replace with interfaces from `@types/validator`
-
+- update @types/validator from 10.4.0 to version 10.11.2 - please check it's [changelog][validator-js-release-notes] ([cb960dd](https://github.com/typestack/class-validator/commit/cb960dd))
+- `isDateString` now check to match only entire ISO Date ([#275](https://github.com/typestack/class-validator/issues/275)) ([5012464](https://github.com/typestack/class-validator/commit/5012464))
+- remove `IsCurrencyOptions`, `IsURLOptions`, `IsEmailOptions`, `IsFQDNOptions` interfaces and replace with interfaces from `@types/validator`
 
 ## [0.9.1](https://github.com/typestack/class-validator/compare/v0.9.0...v0.9.1)
 
 ### Features
 
-* added option to pass custom context for the decorators
+- added option to pass custom context for the decorators
 
 ### Bug Fixes
 
-* validating against a schema will validate against that one instead of every registered one
+- validating against a schema will validate against that one instead of every registered one
 
 # [0.9.0](https://github.com/typestack/class-validator/compare/v0.8.5...v0.9.0) [BREAKING CHANGE]
 
 ### Features
 
-* updated [validator.js][validator-js] from 9.2.0 to 10.4.0 (Check it's [changelog][validator-js-release-notes] for what has changed.)
-  * until now fractional numbers was not allowed in the `IsNumberString` decorator, now they are allowed
-  * until now Gmail addresses could contain multiple dots or random text after a `+` symbol, this is not allowed anymore 
-* `IsPhoneNumber` decorator has been added which uses the [google-libphonenumber][google-libphonenumber] library to validate international phone numbers accurately
+- updated [validator.js][validator-js] from 9.2.0 to 10.4.0 (Check it's [changelog][validator-js-release-notes] for what has changed.)
+  - until now fractional numbers was not allowed in the `IsNumberString` decorator, now they are allowed
+  - until now Gmail addresses could contain multiple dots or random text after a `+` symbol, this is not allowed anymore
+- `IsPhoneNumber` decorator has been added which uses the [google-libphonenumber][google-libphonenumber] library to validate international phone numbers accurately
 
 ### Bug Fixes
 
-* update `IsURLOptions` to match underlying validator host list options
-* added a console warning when no metadata decorator is found as it's possibly not intended
-* the `Min` and `Max` decorator will corectly show an inclusive error message when failing
-* fixed a runtime error when `validationArguments.value` is not a string
+- update `IsURLOptions` to match underlying validator host list options
+- added a console warning when no metadata decorator is found as it's possibly not intended
+- the `Min` and `Max` decorator will corectly show an inclusive error message when failing
+- fixed a runtime error when `validationArguments.value` is not a string
 
 ## [0.8.5](https://github.com/typestack/class-validator/compare/v0.8.4...v0.8.5)
 
 ### Bug Fixes
 
-* remove `ansicolor` package, because it's incompatible with IE
+- remove `ansicolor` package, because it's incompatible with IE
 
 ## [0.8.4](https://github.com/typestack/class-validator/compare/v0.8.3...v0.8.4)
 
 ### Features
 
-* `ValidatorOptions` now has a `forbidUnknownValues` key to prevent unknown objects to pass validation
-  * it's highly advised to turn this option on
-  * now this option defaults to `false` but will be default to `true` after the **1.0** release
+- `ValidatorOptions` now has a `forbidUnknownValues` key to prevent unknown objects to pass validation
+  - it's highly advised to turn this option on
+  - now this option defaults to `false` but will be default to `true` after the **1.0** release
 
 ## [0.8.3](https://github.com/typestack/class-validator/compare/v0.8.2...v0.8.3)
 
 ### Bug Fixes
 
-* handle when `target` property is undefined when calling `ValidationError.toString()`
+- handle when `target` property is undefined when calling `ValidationError.toString()`
 
 ## [0.8.2](https://github.com/typestack/class-validator/compare/v0.8.1...v0.8.2)
 
 ### Features
 
-* added `ValidationError.toString()` method for easier debugging
-* added `printError` method to pretty-print errors in NodeJS or the browser
+- added `ValidationError.toString()` method for easier debugging
+- added `printError` method to pretty-print errors in NodeJS or the browser
 
 ### Bug Fixes
 
-* fixed wrong type info in `ValidatorOptions`
-* fixed wrong type info in `ValidationSchema` \(the `options` key now is optional\)
-* corrected `IsNumericString` to `IsNumberString` in the README
-* fixed type of `host_whitelist` and `host_backlist` in `IsURLOptions`
+- fixed wrong type info in `ValidatorOptions`
+- fixed wrong type info in `ValidationSchema` \(the `options` key now is optional\)
+- corrected `IsNumericString` to `IsNumberString` in the README
+- fixed type of `host_whitelist` and `host_backlist` in `IsURLOptions`
 
 ## [0.8.1](https://github.com/typestack/class-validator/compare/v0.8.0...v0.8.1)
 
 ### Bug Fixes
 
-* fixed wrong type info in `ValidatorOptions`
+- fixed wrong type info in `ValidatorOptions`
 
 # 0.8.0 \[BREAKING CHANGE\]
 
 ### Features
 
-* updated [validator.js][validator-js] from 7.0.0 to 9.2.0 (Check it's [changelog][validator-js-release-notes] for what has changed.)
+- updated [validator.js][validator-js] from 7.0.0 to 9.2.0 (Check it's [changelog][validator-js-release-notes] for what has changed.)
 
   This caused breaking change, if you used the `IsUrl` decorator to validate `localhost` as a valid url, from now you must use the `require_tld: false` option
 
@@ -240,106 +237,106 @@
   url: string;
   ```
 
-* added `@IsInstance` decorator and `validator.isInstance(value, target)` method.
-* changed `@IsNumber` decorator has been changed to `@IsNumber(options: IsNumberOptions)`
-* added option to strip unknown properties \(`whitelist: true`\)
-* added option to throw error on unknown properties \(`forbidNonWhitelisted: true`\)
-* added `@Allow` decorator to prevent stripping properties without other constraint
+- added `@IsInstance` decorator and `validator.isInstance(value, target)` method.
+- changed `@IsNumber` decorator has been changed to `@IsNumber(options: IsNumberOptions)`
+- added option to strip unknown properties \(`whitelist: true`\)
+- added option to throw error on unknown properties \(`forbidNonWhitelisted: true`\)
+- added `@Allow` decorator to prevent stripping properties without other constraint
 
 ### Bug Fixes
 
-* fixed issue with `@IsDateString` now it allow dates without fraction seconds to be set
-* fixed issue with `@IsDateString` now it allow dates without with timezones to be set
-* `@ValidateNested` correctly generates validation error on non object and non array values
+- fixed issue with `@IsDateString` now it allow dates without fraction seconds to be set
+- fixed issue with `@IsDateString` now it allow dates without with timezones to be set
+- `@ValidateNested` correctly generates validation error on non object and non array values
 
 ## 0.6.7
 
 ### Bug Fixes
 
-* fixed issue with `@ValidateNested` when nested property is not defined and it throw an error \(\#59\)
+- fixed issue with `@ValidateNested` when nested property is not defined and it throw an error \(\#59\)
 
 ## 0.6.5
 
 ### Bug Fixes
 
-* fixed bugs with `@IsUrl`, `@IsEmail` and several other decorators
+- fixed bugs with `@IsUrl`, `@IsEmail` and several other decorators
 
 ## 0.6.4
 
 ### Features
 
-* added `@IsMilitaryTime` decorator.
+- added `@IsMilitaryTime` decorator.
 
 ## 0.6.3
 
 ### Features
 
-* added `validateOrReject` method which rejects promise instead of returning array of errors in resolved result
+- added `validateOrReject` method which rejects promise instead of returning array of errors in resolved result
 
 ## 0.6.1
 
 ### Features
 
-* added `@IsArray` decorator.
+- added `@IsArray` decorator.
 
 # 0.6.0 \[BREAKING CHANGE\]
 
 ### Features
 
-* breaking change with `@ValidateNested` on arrays: Validator now groups the validation errors by sub-object, rather than them all being grouped together. See \#32 for a demonstration of the updated structure.
-* added `@ValidateIf` decorator, see conditional validation in docs.
+- breaking change with `@ValidateNested` on arrays: Validator now groups the validation errors by sub-object, rather than them all being grouped together. See \#32 for a demonstration of the updated structure.
+- added `@ValidateIf` decorator, see conditional validation in docs.
 
 # 0.5.0 \[BREAKING CHANGE\]
 
 ### Features
 
-* async validations must be marked with `{ async: true }` option now.
+- async validations must be marked with `{ async: true }` option now.
 
   This is optional, but it helps to determine which decorators are async to prevent their execution in `validateSync` method.
 
-* added `validateSync` method that performs non asynchronous validation and ignores validations that marked with `async: true`.
-* there is a breaking change in `registerDecorator` method. Now it accepts options object.
-* breaking change with `@ValidatorConstraint` decorator. Now it accepts option object instead of single name.
+- added `validateSync` method that performs non asynchronous validation and ignores validations that marked with `async: true`.
+- there is a breaking change in `registerDecorator` method. Now it accepts options object.
+- breaking change with `@ValidatorConstraint` decorator. Now it accepts option object instead of single name.
 
 ## 0.4.1
 
 ### Bug Fixes
 
-* fixed issue with wrong source maps packaged
+- fixed issue with wrong source maps packaged
 
 # 0.4.0 \[BREAKING CHANGE\]
 
 ### Features
 
-* everything should be imported from "class-validator" main entry point now
-* `ValidatorInterface` has been renamed to `ValidatorConstraintInterface`
-* contain can be set in the main entry point now
-* some decorator's names changed. Be aware of this
-* added few more non-string decorators
-* validator now returns array of ValidationError instead of ValidationErrorInterface. Removed old ValidationError
-* removed all other validation methods except `validator.validate`
-* finally validate method is async now, so custom async validations are supported now
-* added ability to validate inherited properties
-* added support of separate validation schemas
-* added support of default validation messages
-* added support of special tokens in validation messages
-* added support of message functions in validation options
-* added support of custom decorators
-* if no groups were specified, decorators with groups now are being ignored
-* changed signature of the `ValidationError`. Now if it has nested errors it does not return them in a flat array
+- everything should be imported from "class-validator" main entry point now
+- `ValidatorInterface` has been renamed to `ValidatorConstraintInterface`
+- contain can be set in the main entry point now
+- some decorator's names changed. Be aware of this
+- added few more non-string decorators
+- validator now returns array of ValidationError instead of ValidationErrorInterface. Removed old ValidationError
+- removed all other validation methods except `validator.validate`
+- finally validate method is async now, so custom async validations are supported now
+- added ability to validate inherited properties
+- added support of separate validation schemas
+- added support of default validation messages
+- added support of special tokens in validation messages
+- added support of message functions in validation options
+- added support of custom decorators
+- if no groups were specified, decorators with groups now are being ignored
+- changed signature of the `ValidationError`. Now if it has nested errors it does not return them in a flat array
 
 ### Bug Fixes
 
-* fixed all decorators that should not work only with strings
+- fixed all decorators that should not work only with strings
 
 # 0.3.0
 
 ### Features
 
-* package has changed its name from `validator.ts` to `class-validator`.
-* sanitation functionality has been removed from this library. Use [class-sanitizer][1] instead.
+- package has changed its name from `validator.ts` to `class-validator`.
+- sanitation functionality has been removed from this library. Use [class-sanitizer][1] instead.
 
 [1]: https://github.com/typestack/class-validator/class-sanitizer
 [validator-js]: https://github.com/chriso/validator.js
 [validator-js-release-notes]: https://github.com/chriso/validator.js/blob/master/CHANGELOG.md
-[google-libphonenumber]: https://github.com/ruimarinho/google-libphonenumber
\ No newline at end of file
+[google-libphonenumber]: https://github.com/ruimarinho/google-libphonenumber
diff --git a/LICENSE b/LICENSE
index cebb86c50a..abdf4ab616 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,7 @@
-MIT License
 
-Copyright (c) 2019 typestack
+The MIT License
+
+Copyright (c) 2015-2020 TypeStack
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -9,13 +10,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
\ No newline at end of file
diff --git a/README.md b/README.md
index 4e44720c1f..5277715dd0 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,9 @@
 # class-validator
 
-[![Build Status](https://travis-ci.org/typestack/class-validator.svg?branch=master)](https://travis-ci.org/typestack/class-validator)
+![Build Status](https://github.com/typestack/class-validator/workflows/CI/badge.svg)
+[![codecov](https://codecov.io/gh/typestack/class-validator/branch/develop/graph/badge.svg)](https://codecov.io/gh/typestack/class-validator)
 [![npm version](https://badge.fury.io/js/class-validator.svg)](https://badge.fury.io/js/class-validator)
 [![install size](https://packagephobia.now.sh/badge?p=class-validator)](https://packagephobia.now.sh/result?p=class-validator)
-[![Join the chat at https://gitter.im/typestack/class-validator](https://badges.gitter.im/typestack/class-validator.svg)](https://gitter.im/typestack/class-validator?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 
 
 Allows use of decorator and non-decorator based validation.
 Internally uses [validator.js][1] to perform validation.
@@ -11,32 +11,35 @@ Class-validator works on both browser and node.js platforms.
 
 ## Table of Contents
 
- * [Installation](#installation)
- * [Usage](#usage)
-    + [Validation errors](#validation-errors)
-    + [Validation messages](#validation-messages)
-    + [Validating arrays](#validating-arrays)
-    + [Validating sets](#validating-sets)
-    + [Validating maps](#validating-maps)
-    + [Validating nested objects](#validating-nested-objects)
-    + [Validating promises](#validating-promises)
-    + [Inheriting Validation decorators](#inheriting-validation-decorators)
-    + [Conditional validation](#conditional-validation)
-    + [Whitelisting](#whitelisting)
-    + [Passing context to decorators](#passing-context-to-decorators)
-    + [Skipping missing properties](#skipping-missing-properties)
-    + [Validation groups](#validation-groups)
-    + [Custom validation classes](#custom-validation-classes)
-    + [Custom validation decorators](#custom-validation-decorators)
-    + [Using service container](#using-service-container)
-    + [Synchronous validation](#synchronous-validation)
-    + [Manual validation](#manual-validation)
-    + [Validation decorators](#validation-decorators)
-    + [Defining validation schema without decorators](#defining-validation-schema-without-decorators)
-    + [Validating plain objects](#validating-plain-objects)
- * [Samples](#samples)
- * [Extensions](#extensions)
- * [Release notes](#release-notes)
+- [class-validator](#class-validator)
+  - [Table of Contents](#table-of-contents)
+  - [Installation](#installation)
+  - [Usage](#usage)
+    - [Passing options](#passing-options)
+  - [Validation errors](#validation-errors)
+  - [Validation messages](#validation-messages)
+  - [Validating arrays](#validating-arrays)
+  - [Validating sets](#validating-sets)
+  - [Validating maps](#validating-maps)
+  - [Validating nested objects](#validating-nested-objects)
+  - [Validating promises](#validating-promises)
+  - [Inheriting Validation decorators](#inheriting-validation-decorators)
+  - [Conditional validation](#conditional-validation)
+  - [Whitelisting](#whitelisting)
+  - [Passing context to decorators](#passing-context-to-decorators)
+  - [Skipping missing properties](#skipping-missing-properties)
+  - [Validation groups](#validation-groups)
+  - [Custom validation classes](#custom-validation-classes)
+  - [Custom validation decorators](#custom-validation-decorators)
+  - [Using service container](#using-service-container)
+  - [Synchronous validation](#synchronous-validation)
+  - [Manual validation](#manual-validation)
+  - [Validation decorators](#validation-decorators)
+  - [Defining validation schema without decorators](#defining-validation-schema-without-decorators)
+  - [Validating plain objects](#validating-plain-objects)
+  - [Samples](#samples)
+  - [Extensions](#extensions)
+  - [Release notes](#release-notes)
 
 ## Installation
 
@@ -51,57 +54,67 @@ npm install class-validator --save
 Create your class and put some validation decorators on the properties you want to validate:
 
 ```typescript
-import {validate, validateOrReject, Contains, IsInt, Length, IsEmail, IsFQDN, IsDate, Min, Max} from "class-validator";
+import {
+  validate,
+  validateOrReject,
+  Contains,
+  IsInt,
+  Length,
+  IsEmail,
+  IsFQDN,
+  IsDate,
+  Min,
+  Max,
+} from 'class-validator';
 
 export class Post {
+  @Length(10, 20)
+  title: string;
 
-    @Length(10, 20)
-    title: string;
-
-    @Contains("hello")
-    text: string;
+  @Contains('hello')
+  text: string;
 
-    @IsInt()
-    @Min(0)
-    @Max(10)
-    rating: number;
+  @IsInt()
+  @Min(0)
+  @Max(10)
+  rating: number;
 
-    @IsEmail()
-    email: string;
+  @IsEmail()
+  email: string;
 
-    @IsFQDN()
-    site: string;
-
-    @IsDate()
-    createDate: Date;
+  @IsFQDN()
+  site: string;
 
+  @IsDate()
+  createDate: Date;
 }
 
 let post = new Post();
-post.title = "Hello"; // should not pass
-post.text = "this is a great post about hell world"; // should not pass
+post.title = 'Hello'; // should not pass
+post.text = 'this is a great post about hell world'; // should not pass
 post.rating = 11; // should not pass
-post.email = "google.com"; // should not pass
-post.site = "googlecom"; // should not pass
-
-validate(post).then(errors => { // errors is an array of validation errors
-    if (errors.length > 0) {
-        console.log("validation failed. errors: ", errors);
-    } else {
-        console.log("validation succeed");
-    }
+post.email = 'google.com'; // should not pass
+post.site = 'googlecom'; // should not pass
+
+validate(post).then(errors => {
+  // errors is an array of validation errors
+  if (errors.length > 0) {
+    console.log('validation failed. errors: ', errors);
+  } else {
+    console.log('validation succeed');
+  }
 });
 
 validateOrReject(post).catch(errors => {
-    console.log("Promise rejected (validation failed). Errors: ", errors);
+  console.log('Promise rejected (validation failed). Errors: ', errors);
 });
 // or
 async function validateOrRejectExample(input) {
-    try {
-        await validateOrReject(input);
-    } catch (errors) {
-        console.log("Caught promise rejection (validation failed). Errors: ", errors)
-    }
+  try {
+    await validateOrReject(input);
+  } catch (errors) {
+    console.log('Caught promise rejection (validation failed). Errors: ', errors);
+  }
 }
 ```
 
@@ -111,18 +124,18 @@ The `validate` function optionally expects a `ValidatorOptions` object as a seco
 
 ```ts
 export interface ValidatorOptions {
-
-    skipMissingProperties?: boolean;
-    whitelist?: boolean;
-    forbidNonWhitelisted?: boolean;
-    groups?: string[];
-    dismissDefaultMessages?: boolean;
-    validationError?: {
-        target?: boolean;
-        value?: boolean;
-    };
-
-    forbidUnknownValues?: boolean;
+  skipMissingProperties?: boolean;
+  whitelist?: boolean;
+  forbidNonWhitelisted?: boolean;
+  groups?: string[];
+  dismissDefaultMessages?: boolean;
+  validationError?: {
+    target?: boolean;
+    value?: boolean;
+  };
+
+  forbidUnknownValues?: boolean;
+  stopAtFirstError?: boolean;
 }
 ```
 
@@ -181,69 +194,70 @@ You can specify validation message in the decorator options and that message wil
 returned by the `validate` method (in the case that validation for this field fails).
 
 ```typescript
-import {MinLength, MaxLength} from "class-validator";
+import { MinLength, MaxLength } from 'class-validator';
 
 export class Post {
-
-    @MinLength(10, {
-        message: "Title is too short"
-    })
-    @MaxLength(50, {
-        message: "Title is too long"
-    })
-    title: string;
+  @MinLength(10, {
+    message: 'Title is too short',
+  })
+  @MaxLength(50, {
+    message: 'Title is too long',
+  })
+  title: string;
 }
 ```
 
 There are few special tokens you can use in your messages:
-* `$value` - the value that is being validated
-* `$property` - name of the object's property being validated
-* `$target` - name of the object's class being validated
-* `$constraint1`, `$constraint2`, ... `$constraintN` - constraints defined by specific validation type
+
+- `$value` - the value that is being validated
+- `$property` - name of the object's property being validated
+- `$target` - name of the object's class being validated
+- `$constraint1`, `$constraint2`, ... `$constraintN` - constraints defined by specific validation type
 
 Example of usage:
 
 ```typescript
-import {MinLength, MaxLength} from "class-validator";
+import { MinLength, MaxLength } from 'class-validator';
 
 export class Post {
-
-    @MinLength(10, { // here, $constraint1 will be replaced with "10", and $value with actual supplied value
-        message: "Title is too short. Minimal length is $constraint1 characters, but actual is $value"
-    })
-    @MaxLength(50, { // here, $constraint1 will be replaced with "50", and $value with actual supplied value
-        message: "Title is too long. Maximal length is $constraint1 characters, but actual is $value"
-    })
-    title: string;
+  @MinLength(10, {
+    // here, $constraint1 will be replaced with "10", and $value with actual supplied value
+    message: 'Title is too short. Minimal length is $constraint1 characters, but actual is $value',
+  })
+  @MaxLength(50, {
+    // here, $constraint1 will be replaced with "50", and $value with actual supplied value
+    message: 'Title is too long. Maximal length is $constraint1 characters, but actual is $value',
+  })
+  title: string;
 }
 ```
 
 Also you can provide a function, that returns a message. This allows you to create more granular messages:
 
 ```typescript
-import {MinLength, MaxLength, ValidationArguments} from "class-validator";
+import { MinLength, MaxLength, ValidationArguments } from 'class-validator';
 
 export class Post {
-
-    @MinLength(10, {
-        message: (args: ValidationArguments) => {
-            if (args.value.length === 1) {
-                return "Too short, minimum length is 1 character";
-            } else {
-                return "Too short, minimum length is " + args.constraints[0] + " characters";
-            }
-        }
-    })
-    title: string;
+  @MinLength(10, {
+    message: (args: ValidationArguments) => {
+      if (args.value.length === 1) {
+        return 'Too short, minimum length is 1 character';
+      } else {
+        return 'Too short, minimum length is ' + args.constraints[0] + ' characters';
+      }
+    },
+  })
+  title: string;
 }
 ```
 
 Message function accepts `ValidationArguments` which contains the following information:
-* `value` - the value that is being validated
-* `constraints` - array of constraints defined by specific validation type
-* `targetName` - name of the object's class being validated
-* `object` - object that is being validated
-* `property` - name of the object's property being validated
+
+- `value` - the value that is being validated
+- `constraints` - array of constraints defined by specific validation type
+- `targetName` - name of the object's class being validated
+- `object` - object that is being validated
+- `property` - name of the object's property being validated
 
 ## Validating arrays
 
@@ -251,14 +265,13 @@ If your field is an array and you want to perform validation of each item in the
 special `each: true` decorator option:
 
 ```typescript
-import {MinLength, MaxLength} from "class-validator";
+import { MinLength, MaxLength } from 'class-validator';
 
 export class Post {
-
-    @MaxLength(20, {
-        each: true
-    })
-    tags: string[];
+  @MaxLength(20, {
+    each: true,
+  })
+  tags: string[];
 }
 ```
 
@@ -270,14 +283,13 @@ If your field is a set and you want to perform validation of each item in the se
 special `each: true` decorator option:
 
 ```typescript
-import {MinLength, MaxLength} from "class-validator";
+import { MinLength, MaxLength } from 'class-validator';
 
 export class Post {
-
-    @MaxLength(20, {
-        each: true
-    })
-    tags: Set<string>;
+  @MaxLength(20, {
+    each: true,
+  })
+  tags: Set<string>;
 }
 ```
 
@@ -289,14 +301,13 @@ If your field is a map and you want to perform validation of each item in the ma
 special `each: true` decorator option:
 
 ```typescript
-import {MinLength, MaxLength} from "class-validator";
+import { MinLength, MaxLength } from 'class-validator';
 
 export class Post {
-
-    @MaxLength(20, {
-        each: true
-    })
-    tags: Map<string, string>;
+  @MaxLength(20, {
+    each: true,
+  })
+  tags: Map<string, string>;
 }
 ```
 
@@ -308,28 +319,24 @@ If your object contains nested objects and you want the validator to perform the
 use the `@ValidateNested()` decorator:
 
 ```typescript
-import {ValidateNested} from "class-validator";
+import { ValidateNested } from 'class-validator';
 
 export class Post {
-
-    @ValidateNested()
-    user: User;
-
+  @ValidateNested()
+  user: User;
 }
 ```
 
-Please note that nested object *must* be an instance of a class, otherwise `@ValidateNested` won't know what class is target of validation. Check also [Validating plain objects](#validating-plain-objects).
+Please note that nested object _must_ be an instance of a class, otherwise `@ValidateNested` won't know what class is target of validation. Check also [Validating plain objects](#validating-plain-objects).
 
 It also works with multi-dimensional array, like :
 
 ```typescript
-import {ValidateNested} from "class-validator";
+import { ValidateNested } from 'class-validator';
 
 export class Plan2D {
-
-    @ValidateNested()
-    matrix: Point[][];
-
+  @ValidateNested()
+  matrix: Point[][];
 }
 ```
 
@@ -338,28 +345,24 @@ export class Plan2D {
 If your object contains property with `Promise`-returned value that should be validated, then you need to use the `@ValidatePromise()` decorator:
 
 ```typescript
-import {ValidatePromise, Min} from "class-validator";
+import { ValidatePromise, Min } from 'class-validator';
 
 export class Post {
-
-    @Min(0)
-    @ValidatePromise()
-    userId: Promise<number>;
-
+  @Min(0)
+  @ValidatePromise()
+  userId: Promise<number>;
 }
 ```
 
 It also works great with `@ValidateNested` decorator:
 
 ```typescript
-import {ValidateNested, ValidatePromise} from "class-validator";
+import { ValidateNested, ValidatePromise } from 'class-validator';
 
 export class Post {
-
-    @ValidateNested()
-    @ValidatePromise()
-    user: Promise<User>;
-
+  @ValidateNested()
+  @ValidatePromise()
+  user: Promise<User>;
 }
 ```
 
@@ -368,41 +371,38 @@ export class Post {
 When you define a subclass which extends from another one, the subclass will automatically inherit the parent's decorators. If a property is redefined in the descendant class decorators will be applied on it both from that and the base class.
 
 ```typescript
-import {validate} from "class-validator";
+import { validate } from 'class-validator';
 
 class BaseContent {
+  @IsEmail()
+  email: string;
 
-    @IsEmail()
-    email: string;
-
-    @IsString()
-    password: string;
+  @IsString()
+  password: string;
 }
 
 class User extends BaseContent {
+  @MinLength(10)
+  @MaxLength(20)
+  name: string;
 
-    @MinLength(10)
-    @MaxLength(20)
-    name: string;
+  @Contains('hello')
+  welcome: string;
 
-    @Contains("hello")
-    welcome: string;
-
-    @MinLength(20)
-    password: string;
+  @MinLength(20)
+  password: string;
 }
 
 let user = new User();
 
-user.email = "invalid email";  // inherited property
-user.password = "too short" // password wil be validated not only against IsString, but against MinLength as well
-user.name = "not valid";
-user.welcome = "helo";
+user.email = 'invalid email'; // inherited property
+user.password = 'too short'; // password wil be validated not only against IsString, but against MinLength as well
+user.name = 'not valid';
+user.welcome = 'helo';
 
 validate(user).then(errors => {
-    // ...
-});  // it will return errors for email, title and text properties
-
+  // ...
+}); // it will return errors for email, title and text properties
 ```
 
 ## Conditional validation
@@ -410,14 +410,14 @@ validate(user).then(errors => {
 The conditional validation decorator (`@ValidateIf`) can be used to ignore the validators on a property when the provided condition function returns false. The condition function takes the object being validated and must return a `boolean`.
 
 ```typescript
-import {ValidateIf, IsNotEmpty} from "class-validator";
+import { ValidateIf, IsNotEmpty } from 'class-validator';
 
 export class Post {
-    otherProperty:string;
+  otherProperty: string;
 
-    @ValidateIf(o => o.otherProperty === "value")
-    @IsNotEmpty()
-    example:string;
+  @ValidateIf(o => o.otherProperty === 'value')
+  @IsNotEmpty()
+  example: string;
 }
 ```
 
@@ -431,7 +431,7 @@ Even if your object is an instance of a validation class it can contain addition
 If you do not want to have such properties on your object, pass special flag to `validate` method:
 
 ```typescript
-import {validate} from "class-validator";
+import { validate } from 'class-validator';
 // ...
 validate(post, { whitelist: true });
 ```
@@ -465,13 +465,13 @@ validate(post).then(errors => {
   // (post as any).anotherNonWhitelistedProperty is not defined
   ...
 });
-````
+```
 
 If you would rather to have an error thrown when any non-whitelisted properties are present, pass another flag to
 `validate` method:
 
 ```typescript
-import {validate} from "class-validator";
+import { validate } from 'class-validator';
 // ...
 validate(post, { whitelist: true, forbidNonWhitelisted: true });
 ```
@@ -484,20 +484,20 @@ It's possible to pass a custom object to decorators which will be accessible on
 import { validate } from 'class-validator';
 
 class MyClass {
-	@MinLength(32, {
-		message: "EIC code must be at least 32 characters",
-		context: {
-			errorCode: 1003,
-			developerNote: "The validated string must contain 32 or more characters."
-		}
-	})
-	eicCode: string;
+  @MinLength(32, {
+    message: 'EIC code must be at least 32 characters',
+    context: {
+      errorCode: 1003,
+      developerNote: 'The validated string must contain 32 or more characters.',
+    },
+  })
+  eicCode: string;
 }
 
 const model = new MyClass();
 
 validate(model).then(errors => {
-    //errors[0].contexts['minLength'].errorCode === 1003
+  //errors[0].contexts['minLength'].errorCode === 1003
 });
 ```
 
@@ -509,7 +509,7 @@ but skip everything else, e.g. skip missing properties.
 In such situations you will need to pass a special flag to `validate` method:
 
 ```typescript
-import {validate} from "class-validator";
+import { validate } from 'class-validator';
 // ...
 validate(post, { skipMissingProperties: true });
 ```
@@ -521,46 +521,45 @@ for you, even if skipMissingProperties is set to true. For such cases you should
 ## Validation groups
 
 In different situations you may want to use different validation schemas of the same object.
- In such cases you can use validation groups.
+In such cases you can use validation groups.
 
 ```typescript
-import {validate, Min, Length} from "class-validator";
+import { validate, Min, Length } from 'class-validator';
 
 export class User {
-
-    @Min(12, {
-        groups: ["registration"]
-    })
-    age: number;
-
-    @Length(2, 20, {
-        groups: ["registration", "admin"]
-    })
-    name: string;
+  @Min(12, {
+    groups: ['registration'],
+  })
+  age: number;
+
+  @Length(2, 20, {
+    groups: ['registration', 'admin'],
+  })
+  name: string;
 }
 
 let user = new User();
 user.age = 10;
-user.name = "Alex";
+user.name = 'Alex';
 
 validate(user, {
-    groups: ["registration"]
+  groups: ['registration'],
 }); // this will not pass validation
 
 validate(user, {
-    groups: ["admin"]
+  groups: ['admin'],
 }); // this will pass validation
 
 validate(user, {
-    groups: ["registration", "admin"]
+  groups: ['registration', 'admin'],
 }); // this will not pass validation
 
 validate(user, {
-    groups: undefined // the default
-}); // this will not pass validation since all properties get validated regardless of their groups 
+  groups: undefined, // the default
+}); // this will not pass validation since all properties get validated regardless of their groups
 
 validate(user, {
-    groups: []
+  groups: [],
 }); // this will not pass validation, (equivalent to 'groups: undefined', see above)
 ```
 
@@ -569,96 +568,88 @@ must be applied always no matter which group is used.
 
 ## Custom validation classes
 
-If you have custom validation logic you can create a *Constraint class*:
+If you have custom validation logic you can create a _Constraint class_:
 
 1. First create a file, lets say `CustomTextLength.ts`, and define a new class:
 
-    ```typescript
-    import {ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments} from "class-validator";
-
-    @ValidatorConstraint({ name: "customText", async: false })
-    export class CustomTextLength implements ValidatorConstraintInterface {
-
-        validate(text: string, args: ValidationArguments) {
-            return text.length > 1 && text.length < 10; // for async validations you must return a Promise<boolean> here
-        }
-
-        defaultMessage(args: ValidationArguments) { // here you can provide default error message if validation failed
-            return "Text ($value) is too short or too long!";
-        }
-
-    }
-    ```
-
-    We marked our class with `@ValidatorConstraint` decorator.
-    You can also supply a validation constraint name - this name will be used as "error type" in ValidationError.
-    If you will not supply a constraint name - it will be auto-generated.
+   ```typescript
+   import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments } from 'class-validator';
 
-    Our class must implement `ValidatorConstraintInterface` interface and its `validate` method,
-    which defines validation logic. If validation succeeds, method returns true, otherwise false.
-    Custom validator can be asynchronous, if you want to perform validation after some asynchronous
-    operations, simply return a promise with boolean inside in `validate` method.
+   @ValidatorConstraint({ name: 'customText', async: false })
+   export class CustomTextLength implements ValidatorConstraintInterface {
+     validate(text: string, args: ValidationArguments) {
+       return text.length > 1 && text.length < 10; // for async validations you must return a Promise<boolean> here
+     }
 
-    Also we defined optional method `defaultMessage` which defines a default error message,
-    in the case that the decorator's implementation doesn't set an error message.
+     defaultMessage(args: ValidationArguments) {
+       // here you can provide default error message if validation failed
+       return 'Text ($value) is too short or too long!';
+     }
+   }
+   ```
 
+   We marked our class with `@ValidatorConstraint` decorator.
+   You can also supply a validation constraint name - this name will be used as "error type" in ValidationError.
+   If you will not supply a constraint name - it will be auto-generated.
 
-2. Then you can use your new validation constraint in your class:
+   Our class must implement `ValidatorConstraintInterface` interface and its `validate` method,
+   which defines validation logic. If validation succeeds, method returns true, otherwise false.
+   Custom validator can be asynchronous, if you want to perform validation after some asynchronous
+   operations, simply return a promise with boolean inside in `validate` method.
 
-    ```typescript
-    import {Validate} from "class-validator";
-    import {CustomTextLength} from "./CustomTextLength";
+   Also we defined optional method `defaultMessage` which defines a default error message,
+   in the case that the decorator's implementation doesn't set an error message.
 
-    export class Post {
+2) Then you can use your new validation constraint in your class:
 
-        @Validate(CustomTextLength, {
-            message: "Title is too short or long!"
-        })
-        title: string;
+   ```typescript
+   import { Validate } from 'class-validator';
+   import { CustomTextLength } from './CustomTextLength';
 
-    }
-    ```
+   export class Post {
+     @Validate(CustomTextLength, {
+       message: 'Title is too short or long!',
+     })
+     title: string;
+   }
+   ```
 
-    Here we set our newly created `CustomTextLength` validation constraint for `Post.title`.
+   Here we set our newly created `CustomTextLength` validation constraint for `Post.title`.
 
-3. And use validator as usual:
+3) And use validator as usual:
 
-    ```typescript
-    import {validate} from "class-validator";
+   ```typescript
+   import { validate } from 'class-validator';
 
-    validate(post).then(errors => {
-        // ...
-    });
-    ```
+   validate(post).then(errors => {
+     // ...
+   });
+   ```
 
 You can also pass constraints to your validator, like this:
 
 ```typescript
-import {Validate} from "class-validator";
-import {CustomTextLength} from "./CustomTextLength";
+import { Validate } from 'class-validator';
+import { CustomTextLength } from './CustomTextLength';
 
 export class Post {
-
-    @Validate(CustomTextLength, [3, 20], {
-        message: "Wrong post title"
-    })
-    title: string;
-
+  @Validate(CustomTextLength, [3, 20], {
+    message: 'Wrong post title',
+  })
+  title: string;
 }
 ```
 
 And use them from `validationArguments` object:
 
 ```typescript
-import {ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface} from "class-validator";
+import { ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface } from 'class-validator';
 
 @ValidatorConstraint()
 export class CustomTextLength implements ValidatorConstraintInterface {
-
-    validate(text: string, validationArguments: ValidationArguments) {
-        return text.length > validationArguments.constraints[0] && text.length < validationArguments.constraints[1];
-    }
-
+  validate(text: string, validationArguments: ValidationArguments) {
+    return text.length > validationArguments.constraints[0] && text.length < validationArguments.constraints[1];
+  }
 }
 ```
 
@@ -669,98 +660,96 @@ Lets create a decorator called `@IsLongerThan`:
 
 1. Create a decorator itself:
 
-    ```typescript
-    import {registerDecorator, ValidationOptions, ValidationArguments} from "class-validator";
-
-    export function IsLongerThan(property: string, validationOptions?: ValidationOptions) {
-       return function (object: Object, propertyName: string) {
-            registerDecorator({
-                name: "isLongerThan",
-                target: object.constructor,
-                propertyName: propertyName,
-                constraints: [property],
-                options: validationOptions,
-                validator: {
-                    validate(value: any, args: ValidationArguments) {
-                        const [relatedPropertyName] = args.constraints;
-                        const relatedValue = (args.object as any)[relatedPropertyName];
-                        return  typeof value === "string" &&
-                               typeof relatedValue === "string" &&
-                               value.length > relatedValue.length; // you can return a Promise<boolean> here as well, if you want to make async validation
-                    }
-                }
-            });
-       };
-    }
-    ```
+   ```typescript
+   import { registerDecorator, ValidationOptions, ValidationArguments } from 'class-validator';
+
+   export function IsLongerThan(property: string, validationOptions?: ValidationOptions) {
+     return function (object: Object, propertyName: string) {
+       registerDecorator({
+         name: 'isLongerThan',
+         target: object.constructor,
+         propertyName: propertyName,
+         constraints: [property],
+         options: validationOptions,
+         validator: {
+           validate(value: any, args: ValidationArguments) {
+             const [relatedPropertyName] = args.constraints;
+             const relatedValue = (args.object as any)[relatedPropertyName];
+             return typeof value === 'string' && typeof relatedValue === 'string' && value.length > relatedValue.length; // you can return a Promise<boolean> here as well, if you want to make async validation
+           },
+         },
+       });
+     };
+   }
+   ```
 
 2. Put it to use:
 
-    ```typescript
-    import {IsLongerThan} from "./IsLongerThan";
+   ```typescript
+   import { IsLongerThan } from './IsLongerThan';
 
-    export class Post {
+   export class Post {
+     title: string;
 
-        title: string;
-
-        @IsLongerThan("title", {
-           /* you can also use additional validation options, like "groups" in your custom validation decorators. "each" is not supported */
-           message: "Text must be longer than the title"
-        })
-        text: string;
-
-    }
-    ```
+     @IsLongerThan('title', {
+       /* you can also use additional validation options, like "groups" in your custom validation decorators. "each" is not supported */
+       message: 'Text must be longer than the title',
+     })
+     text: string;
+   }
+   ```
 
 In your custom decorators you can also use `ValidationConstraint`.
 Lets create another custom validation decorator called `IsUserAlreadyExist`:
 
 1. Create a ValidationConstraint and decorator:
 
-    ```typescript
-    import {registerDecorator, ValidationOptions, ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments} from "class-validator";
-
-    @ValidatorConstraint({ async: true })
-    export class IsUserAlreadyExistConstraint implements ValidatorConstraintInterface {
-
-        validate(userName: any, args: ValidationArguments) {
-            return UserRepository.findOneByName(userName).then(user => {
-                if (user) return false;
-                return true;
-            });
-        }
-
-    }
-
-    export function IsUserAlreadyExist(validationOptions?: ValidationOptions) {
-       return function (object: Object, propertyName: string) {
-            registerDecorator({
-                target: object.constructor,
-                propertyName: propertyName,
-                options: validationOptions,
-                constraints: [],
-                validator: IsUserAlreadyExistConstraint
-            });
-       };
-    }
-    ```
-
-    note that we marked our constraint that it will by async by adding `{ async: true }` in validation options.
+   ```typescript
+   import {
+     registerDecorator,
+     ValidationOptions,
+     ValidatorConstraint,
+     ValidatorConstraintInterface,
+     ValidationArguments,
+   } from 'class-validator';
+
+   @ValidatorConstraint({ async: true })
+   export class IsUserAlreadyExistConstraint implements ValidatorConstraintInterface {
+     validate(userName: any, args: ValidationArguments) {
+       return UserRepository.findOneByName(userName).then(user => {
+         if (user) return false;
+         return true;
+       });
+     }
+   }
+
+   export function IsUserAlreadyExist(validationOptions?: ValidationOptions) {
+     return function (object: Object, propertyName: string) {
+       registerDecorator({
+         target: object.constructor,
+         propertyName: propertyName,
+         options: validationOptions,
+         constraints: [],
+         validator: IsUserAlreadyExistConstraint,
+       });
+     };
+   }
+   ```
+
+   note that we marked our constraint that it will by async by adding `{ async: true }` in validation options.
 
 2. And put it to use:
 
-    ```typescript
-    import {IsUserAlreadyExist} from "./IsUserAlreadyExist";
-
-    export class User {
+   ```typescript
+   import { IsUserAlreadyExist } from './IsUserAlreadyExist';
 
-        @IsUserAlreadyExist({
-           message: "User $value already exists. Choose another name."
-        })
-        name: string;
-
-    }
-    ```
+   export class User {
+     @IsUserAlreadyExist({
+       message: 'User $value already exists. Choose another name.',
+     })
+     name: string;
+   }
+   ```
 
 ## Using service container
 
@@ -768,8 +757,8 @@ Validator supports service container in the case if want to inject dependencies
 classes. Here is example how to integrate it with [typedi][2]:
 
 ```typescript
-import {Container} from "typedi";
-import {useContainer, Validator} from "class-validator";
+import { Container } from 'typedi';
+import { useContainer, Validator } from 'class-validator';
 
 // do this somewhere in the global application level:
 useContainer(Container);
@@ -782,15 +771,15 @@ let validator = Container.get(Validator);
 ## Synchronous validation
 
 If you want to perform a simple non async validation you can use `validateSync` method instead of regular `validate`
- method. It has the same arguments as `validate` method. But note, this method **ignores** all async validations
- you have.
+method. It has the same arguments as `validate` method. But note, this method **ignores** all async validations
+you have.
 
 ## Manual validation
 
 There are several method exist in the Validator that allows to perform non-decorator based validation:
 
 ```typescript
-import {isEmpty, isBoolean} from "class-validator";
+import { isEmpty, isBoolean } from 'class-validator';
 
 isEmpty(value);
 isBoolean(value);
@@ -798,197 +787,207 @@ isBoolean(value);
 
 ## Validation decorators
 
-| Decorator                                       | Description                                                                                                                      |
-|-------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|
-| **Common validation decorators**                                                                                                                                                   |
-| `@IsDefined(value: any)`                        | Checks if value is defined (!== undefined, !== null). This is the only decorator that ignores skipMissingProperties option.      |
-| `@IsOptional()`                                 | Checks if given value is empty (=== null, === undefined) and if so, ignores all the validators on the property.                         |
-| `@Equals(comparison: any)`                      | Checks if value equals ("===") comparison.                                                                                       |
-| `@NotEquals(comparison: any)`                   | Checks if value not equal ("!==") comparison.                                                                                    |
-| `@IsEmpty()`                                    | Checks if given value is empty (=== '', === null, === undefined).                                                                |
-| `@IsNotEmpty()`                                 | Checks if given value is not empty (!== '', !== null, !== undefined).                                                            |
-| `@IsIn(values: any[])`                          | Checks if value is in a array of allowed values.                                                                                 |
-| `@IsNotIn(values: any[])`                       | Checks if value is not in a array of disallowed values.                                                                          |
-| **Type validation decorators**                                                                                                                                                     |
-| `@IsBoolean()`                                  | Checks if a value is a boolean.                                                                                                  |
-| `@IsDate()`                                     | Checks if the value is a date.                                                                                                   |
-| `@IsString()`                                   | Checks if the string is a string.                                                                                                |
-| `@IsNumber(options: IsNumberOptions)`           | Checks if the value is a number.                                                                                                 |
-| `@IsInt()`                                      | Checks if the value is an integer number.                                                                                        |
-| `@IsArray()`                                    | Checks if the value is an array                                                                                                  |
-| `@IsEnum(entity: object)`                         | Checks if the value is an valid enum                                                                                           |
-| **Number validation decorators**                                                                                                                                                   |
-| `@IsDivisibleBy(num: number)`                   | Checks if the value is a number that's divisible by another.                                                                     |
-| `@IsPositive()`                                 | Checks if the value is a positive number greater than zero.                                                                                        |
-| `@IsNegative()`                                 | Checks if the value is a negative number smaller than zero.                                                                                        |
-| `@Min(min: number)`                             | Checks if the given number is greater than or equal to given number.                                                             |
-| `@Max(max: number)`                             | Checks if the given number is less than or equal to given number.                                                                |
-| **Date validation decorators**                                                                                                                                                     |
-| `@MinDate(date: Date)`                          | Checks if the value is a date that's after the specified date.                                                                   |
-| `@MaxDate(date: Date)`                          | Checks if the value is a date that's before the specified date.                                                                  |                                                                                                                                                  |
-| **String-type validation decorators**                                                                                                                                              |
-| `@IsBooleanString()`                            | Checks if a string is a boolean (e.g. is "true" or "false").                                                                     |
-| `@IsDateString()`                               | Checks if a string is a complete representation of a date (e.g. "2017-06-07T14:34:08.700Z", "2017-06-07T14:34:08.700 or "2017-06-07T14:34:08+04:00").                                                                                                    |
-| `@IsNumberString(options?: IsNumericOptions)`   | Checks if a string is a number.                                                                                                  |
-| **String validation decorators**                                                                                                                                                   |
-| `@Contains(seed: string)`                       | Checks if the string contains the seed.                                                                                          |
-| `@NotContains(seed: string)`                    | Checks if the string not contains the seed.                                                                                      |
-| `@IsAlpha()`                                    | Checks if the string contains only letters (a-zA-Z).                                                                             |
-| `@IsAlphanumeric()`                             | Checks if the string contains only letters and numbers.  
-| `@IsDecimal(options?: IsDecimalOptions)`        | Checks if the string is a valid decimal value. Default IsDecimalOptions are `force_decimal=False`, `decimal_digits: '1,'`, `locale: 'en-US',`                                                                             |
-| `@IsAscii()`                                    | Checks if the string contains ASCII chars only.                                                                                  |
-| `@IsBase32()`                                   | Checks if a string is base32 encoded.                                                                                            |
-| `@IsBase64()`                                   | Checks if a string is base64 encoded.                                                                                            |
-| `@IsIBAN()`                                     | Checks if a string is a IBAN (International Bank Account Number).                                                                |
-| `@IsBIC()`                                      | Checks if a string is a BIC (Bank Identification Code) or SWIFT code.                                                            |
-| `@IsByteLength(min: number, max?: number)`      | Checks if the string's length (in bytes) falls in a range.                                                                       |
-| `@IsCreditCard()`                               | Checks if the string is a credit card.                                                                                           |
-| `@IsCurrency(options?: IsCurrencyOptions)`      | Checks if the string is a valid currency amount.                                                                                 |
-| `@IsEthereumAddress()`                          | Checks if the string is an Ethereum address using basic regex. Does not validate address checksums.                              |
-| `@IsBtcAddress()`                               | Checks if the string is a valid BTC address.                                                                                     |
-| `@IsDataURI()`                                  | Checks if the string is a data uri format.                                                                                       |
-| `@IsEmail(options?: IsEmailOptions)`            | Checks if the string is an email.                                                                                                |
-| `@IsFQDN(options?: IsFQDNOptions)`              | Checks if the string is a fully qualified domain name (e.g. domain.com).                                                         |
-| `@IsFullWidth()`                                | Checks if the string contains any full-width chars.                                                                              |
-| `@IsHalfWidth()`                                | Checks if the string contains any half-width chars.                                                                              |
-| `@IsVariableWidth()`                            | Checks if the string contains a mixture of full and half-width chars.                                                            |
-| `@IsHexColor()`                                 | Checks if the string is a hexadecimal color.                                                                                     |
-| `@IsHSLColor()`                                 | Checks if the string is an HSL (hue, saturation, lightness, optional alpha) color based on [CSS Colors Level 4 specification](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value).          |
-| `@IsRgbColor(options?: IsRgbOptions)`           | Checks if the string is a rgb or rgba color.                                                                                     |
-| `@IsIdentityCard(locale?: string)`              | Checks if the string is a valid identity card code.                                                                              |
-| `@IsPassportNumber(countryCode?: string)`       | Checks if the string is a valid passport number relative to a specific country code.                                             |
-| `@IsPostalCode(locale?: string)`                | Checks if the string is a postal code.                                                                                           |
-| `@IsHexadecimal()`                              | Checks if the string is a hexadecimal number.                                                                                    |
-| `@IsOctal()`                                    | Checks if the string is a octal number.                                                                                          |
-| `@IsMACAddress(options?: IsMACAddressOptions)`  | Checks if the string is a MAC Address.                                                                                            |
-| `@IsIP(version?: "4"\|"6")`                     | Checks if the string is an IP (version 4 or 6).                                                                                  |
-| `@IsPort()`                                     | Check if the string is a valid port number.                                                                                      |
-| `@IsISBN(version?: "10"\|"13")`                 | Checks if the string is an ISBN (version 10 or 13).                                                                              |
-| `@IsEAN()`                                      | Checks if the string is an if the string is an EAN (European Article Number).                                                    |
-| `@IsISIN()`                                     | Checks if the string is an ISIN (stock/security identifier).                                                                     |
-| `@IsISO8601(options?: IsISO8601Options)`        | Checks if the string is a valid ISO 8601 date. Use the option strict = true for additional checks for a valid date, e.g. invalidates dates like 2019-02-29.                                                                               |
-| `@IsJSON()`                                     | Checks if the string is valid JSON.                                                                                              |
-| `@IsJWT()`                                      | Checks if the string is valid JWT.                                                                                                |
-| `@IsObject()`                                   | Checks if the object is valid Object (null, functions, arrays will return false).                                                                                              |
-| `@IsNotEmptyObject()`                           | Checks if the object is not empty.                                                                                              |
-| `@IsLowercase()`                                | Checks if the string is lowercase.                                                                                               |
-| `@IsLatLong()`                                  | Checks if the string is a valid latitude-longitude coordinate in the format lat,long                                             |
-| `@IsLatitude()`                                 | Checks if the string or number is a valid latitude coordinate                                                                    |
-| `@IsLongitude()`                                | Checks if the string or number is a valid longitude coordinate                                                                   |
-| `@IsMobilePhone(locale: string)`                | Checks if the string is a mobile phone number.                                                                                   |
-| `@IsISO31661Alpha2()`                           | Checks if the string is a valid [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) officially assigned country code.                                                                                 |
-| `@IsISO31661Alpha3()`                           | Checks if the string is a valid [ISO 3166-1 alpha-3](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3) officially assigned country code.                                                                                 |
-| `@IsLocale()`                                   | Checks if the string is a locale.                                                                                                |
-| `@IsPhoneNumber(region: string)`                | Checks if the string is a valid phone number. "region" accepts 2 characters uppercase country code (e.g. DE, US, CH).If users must enter the intl. prefix (e.g. +41), then you may pass "ZZ" or null as region. See [google-libphonenumber, metadata.js:countryCodeToRegionCodeMap on github](https://github.com/ruimarinho/google-libphonenumber/blob/1e46138878cff479aafe2ce62175c6c49cb58720/src/metadata.js#L33)                                                                                  |
-| `@IsMongoId()`                                  | Checks if the string is a valid hex-encoded representation of a MongoDB ObjectId.                                                |
-| `@IsMultibyte()`                                | Checks if the string contains one or more multibyte chars.                                                                       |
-| `@IsNumberString(options?: IsNumericOptions)`   | Checks if the string is numeric.                                                                                                 |
-| `@IsSurrogatePair()`                            | Checks if the string contains any surrogate pairs chars.                                                                         |
-| `@IsUrl(options?: IsURLOptions)`                | Checks if the string is an url.                                                                                                  |
-| `@IsMagnetURI()`                                | Checks if the string is a [magnet uri format](https://en.wikipedia.org/wiki/Magnet_URI_scheme).                                  |
-| `@IsUUID(version?: "3"\|"4"\|"5"\|"all")`              | Checks if the string is a UUID (version 3, 4, 5 or all ).                                                                              |
-| `@IsFirebasePushId()`                                   | Checks if the string is a [Firebase Push id](https://firebase.googleblog.com/2015/02/the-2120-ways-to-ensure-unique_68.html)                                                                                      |
-| `@IsUppercase()`                                | Checks if the string is uppercase.                                                                                               |
-| `@Length(min: number, max?: number)`            | Checks if the string's length falls in a range.                                                                                  |
-| `@MinLength(min: number)`                       | Checks if the string's length is not less than given number.                                                                     |
-| `@MaxLength(max: number)`                       | Checks if the string's length is not more than given number.                                                                     |
-| `@Matches(pattern: RegExp, modifiers?: string)` | Checks if string matches the pattern. Either matches('foo', /foo/i) or matches('foo', 'foo', 'i').
-| `@IsMilitaryTime()`                             | Checks if the string is a valid representation of military time in the format HH:MM.                                         |
-| `@IsHash(algorithm: string)`                    | Checks if the string is a hash of type algorithm. <br/><br/>Algorithm is one of `['md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'ripemd128', 'ripemd160', 'tiger128', 'tiger160', 'tiger192', 'crc32', 'crc32b']`                                                                                 |
-| `@IsMimeType()`                                 | Checks if the string matches to a valid [MIME type](https://en.wikipedia.org/wiki/Media_type) format                             |
-| `@IsSemVer()`                                   | Checks if the string is a Semantic Versioning Specification (SemVer).                                                            |
-| `@IsISSN(options?: IsISSNOptions)`              | Checks if the string is a ISSN.                                                                                                  |
-| `@IsISRC()`                                     | Checks if the string is a [ISRC](https://en.wikipedia.org/wiki/International_Standard_Recording_Code).                           |
-| `@IsRFC3339()`                                  | Checks f the string is a valid [RFC 3339](https://tools.ietf.org/html/rfc3339) date.                                             |
-| **Array validation decorators**                                                                                                                                                    |
-| `@ArrayContains(values: any[])`                 | Checks if array contains all values from the given array of values.                                                           |
-| `@ArrayNotContains(values: any[])`              | Checks if array does not contain any of the given values.                                                                        |
-| `@ArrayNotEmpty()`                              | Checks if given array is not empty.                                                                                              |
-| `@ArrayMinSize(min: number)`                    | Checks if array's length is as minimal this number.                                                                              |
-| `@ArrayMaxSize(max: number)`                    | Checks if array's length is as maximal this number.                                                                              |
-| `@ArrayUnique()`                                | Checks if all array's values are unique. Comparison for objects is reference-based.                                       |
-| **Object validation decorators**                                                                                                                                                   |
-| `@IsInstance(value: any)`                       | Checks if the property is an instance of the passed value.                                                                       |
- **Other decorators**                                                                                                                                                   |
-| `@Allow()`                       | Prevent stripping off the property when no other constraint is specified for it.                                                                       |
+| Decorator                                       | Description                                                                                                                                                                                                                                                                                                                                                                                                          |
+| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **Common validation decorators**                |
+| `@IsDefined(value: any)`                        | Checks if value is defined (!== undefined, !== null). This is the only decorator that ignores skipMissingProperties option.                                                                                                                                                                                                                                                                                          |
+| `@IsOptional()`                                 | Checks if given value is empty (=== null, === undefined) and if so, ignores all the validators on the property.                                                                                                                                                                                                                                                                                                      |
+| `@Equals(comparison: any)`                      | Checks if value equals ("===") comparison.                                                                                                                                                                                                                                                                                                                                                                           |
+| `@NotEquals(comparison: any)`                   | Checks if value not equal ("!==") comparison.                                                                                                                                                                                                                                                                                                                                                                        |
+| `@IsEmpty()`                                    | Checks if given value is empty (=== '', === null, === undefined).                                                                                                                                                                                                                                                                                                                                                    |
+| `@IsNotEmpty()`                                 | Checks if given value is not empty (!== '', !== null, !== undefined).                                                                                                                                                                                                                                                                                                                                                |
+| `@IsIn(values: any[])`                          | Checks if value is in a array of allowed values.                                                                                                                                                                                                                                                                                                                                                                     |
+| `@IsNotIn(values: any[])`                       | Checks if value is not in a array of disallowed values.                                                                                                                                                                                                                                                                                                                                                              |
+| **Type validation decorators**                  |
+| `@IsBoolean()`                                  | Checks if a value is a boolean.                                                                                                                                                                                                                                                                                                                                                                                      |
+| `@IsDate()`                                     | Checks if the value is a date.                                                                                                                                                                                                                                                                                                                                                                                       |
+| `@IsString()`                                   | Checks if the string is a string.                                                                                                                                                                                                                                                                                                                                                                                    |
+| `@IsNumber(options: IsNumberOptions)`           | Checks if the value is a number.                                                                                                                                                                                                                                                                                                                                                                                     |
+| `@IsInt()`                                      | Checks if the value is an integer number.                                                                                                                                                                                                                                                                                                                                                                            |
+| `@IsArray()`                                    | Checks if the value is an array                                                                                                                                                                                                                                                                                                                                                                                      |
+| `@IsEnum(entity: object)`                       | Checks if the value is an valid enum                                                                                                                                                                                                                                                                                                                                                                                 |
+| **Number validation decorators**                |
+| `@IsDivisibleBy(num: number)`                   | Checks if the value is a number that's divisible by another.                                                                                                                                                                                                                                                                                                                                                         |
+| `@IsPositive()`                                 | Checks if the value is a positive number greater than zero.                                                                                                                                                                                                                                                                                                                                                          |
+| `@IsNegative()`                                 | Checks if the value is a negative number smaller than zero.                                                                                                                                                                                                                                                                                                                                                          |
+| `@Min(min: number)`                             | Checks if the given number is greater than or equal to given number.                                                                                                                                                                                                                                                                                                                                                 |
+| `@Max(max: number)`                             | Checks if the given number is less than or equal to given number.                                                                                                                                                                                                                                                                                                                                                    |
+| **Date validation decorators**                  |
+| `@MinDate(date: Date)`                          | Checks if the value is a date that's after the specified date.                                                                                                                                                                                                                                                                                                                                                       |
+| `@MaxDate(date: Date)`                          | Checks if the value is a date that's before the specified date.                                                                                                                                                                                                                                                                                                                                                      |  |
+| **String-type validation decorators**           |
+| `@IsBooleanString()`                            | Checks if a string is a boolean (e.g. is "true" or "false").                                                                                                                                                                                                                                                                                                                                                         |
+| `@IsDateString()`                               | Alias for `@IsISO8601()`. Checks if a string is a complete representation of a date (e.g. "2017-06-07T14:34:08.700Z", "2017-06-07T14:34:08.700 or "2017-06-07T14:34:08+04:00").                                                                                                                                                                                                                                      |
+| `@IsNumberString(options?: IsNumericOptions)`   | Checks if a string is a number.                                                                                                                                                                                                                                                                                                                                                                                      |
+| **String validation decorators**                |
+| `@Contains(seed: string)`                       | Checks if the string contains the seed.                                                                                                                                                                                                                                                                                                                                                                              |
+| `@NotContains(seed: string)`                    | Checks if the string not contains the seed.                                                                                                                                                                                                                                                                                                                                                                          |
+| `@IsAlpha()`                                    | Checks if the string contains only letters (a-zA-Z).                                                                                                                                                                                                                                                                                                                                                                 |
+| `@IsAlphanumeric()`                             | Checks if the string contains only letters and numbers.                                                                                                                                                                                                                                                                                                                                                              |
+| `@IsDecimal(options?: IsDecimalOptions)`        | Checks if the string is a valid decimal value. Default IsDecimalOptions are `force_decimal=False`, `decimal_digits: '1,'`, `locale: 'en-US',`                                                                                                                                                                                                                                                                        |
+| `@IsAscii()`                                    | Checks if the string contains ASCII chars only.                                                                                                                                                                                                                                                                                                                                                                      |
+| `@IsBase32()`                                   | Checks if a string is base32 encoded.                                                                                                                                                                                                                                                                                                                                                                                |
+| `@IsBase64()`                                   | Checks if a string is base64 encoded.                                                                                                                                                                                                                                                                                                                                                                                |
+| `@IsIBAN()`                                     | Checks if a string is a IBAN (International Bank Account Number).                                                                                                                                                                                                                                                                                                                                                    |
+| `@IsBIC()`                                      | Checks if a string is a BIC (Bank Identification Code) or SWIFT code.                                                                                                                                                                                                                                                                                                                                                |
+| `@IsByteLength(min: number, max?: number)`      | Checks if the string's length (in bytes) falls in a range.                                                                                                                                                                                                                                                                                                                                                           |
+| `@IsCreditCard()`                               | Checks if the string is a credit card.                                                                                                                                                                                                                                                                                                                                                                               |
+| `@IsCurrency(options?: IsCurrencyOptions)`      | Checks if the string is a valid currency amount.                                                                                                                                                                                                                                                                                                                                                                     |
+| `@IsEthereumAddress()`                          | Checks if the string is an Ethereum address using basic regex. Does not validate address checksums.                                                                                                                                                                                                                                                                                                                  |
+| `@IsBtcAddress()`                               | Checks if the string is a valid BTC address.                                                                                                                                                                                                                                                                                                                                                                         |
+| `@IsDataURI()`                                  | Checks if the string is a data uri format.                                                                                                                                                                                                                                                                                                                                                                           |
+| `@IsEmail(options?: IsEmailOptions)`            | Checks if the string is an email.                                                                                                                                                                                                                                                                                                                                                                                    |
+| `@IsFQDN(options?: IsFQDNOptions)`              | Checks if the string is a fully qualified domain name (e.g. domain.com).                                                                                                                                                                                                                                                                                                                                             |
+| `@IsFullWidth()`                                | Checks if the string contains any full-width chars.                                                                                                                                                                                                                                                                                                                                                                  |
+| `@IsHalfWidth()`                                | Checks if the string contains any half-width chars.                                                                                                                                                                                                                                                                                                                                                                  |
+| `@IsVariableWidth()`                            | Checks if the string contains a mixture of full and half-width chars.                                                                                                                                                                                                                                                                                                                                                |
+| `@IsHexColor()`                                 | Checks if the string is a hexadecimal color.                                                                                                                                                                                                                                                                                                                                                                         |
+| `@IsHSLColor()`                                 | Checks if the string is an HSL (hue, saturation, lightness, optional alpha) color based on [CSS Colors Level 4 specification](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value).                                                                                                                                                                                                                         |
+| `@IsRgbColor(options?: IsRgbOptions)`           | Checks if the string is a rgb or rgba color.                                                                                                                                                                                                                                                                                                                                                                         |
+| `@IsIdentityCard(locale?: string)`              | Checks if the string is a valid identity card code.                                                                                                                                                                                                                                                                                                                                                                  |
+| `@IsPassportNumber(countryCode?: string)`       | Checks if the string is a valid passport number relative to a specific country code.                                                                                                                                                                                                                                                                                                                                 |
+| `@IsPostalCode(locale?: string)`                | Checks if the string is a postal code.                                                                                                                                                                                                                                                                                                                                                                               |
+| `@IsHexadecimal()`                              | Checks if the string is a hexadecimal number.                                                                                                                                                                                                                                                                                                                                                                        |
+| `@IsOctal()`                                    | Checks if the string is a octal number.                                                                                                                                                                                                                                                                                                                                                                              |
+| `@IsMACAddress(options?: IsMACAddressOptions)`  | Checks if the string is a MAC Address.                                                                                                                                                                                                                                                                                                                                                                               |
+| `@IsIP(version?: "4"\|"6")`                     | Checks if the string is an IP (version 4 or 6).                                                                                                                                                                                                                                                                                                                                                                      |
+| `@IsPort()`                                     | Check if the string is a valid port number.                                                                                                                                                                                                                                                                                                                                                                          |
+| `@IsISBN(version?: "10"\|"13")`                 | Checks if the string is an ISBN (version 10 or 13).                                                                                                                                                                                                                                                                                                                                                                  |
+| `@IsEAN()`                                      | Checks if the string is an if the string is an EAN (European Article Number).                                                                                                                                                                                                                                                                                                                                        |
+| `@IsISIN()`                                     | Checks if the string is an ISIN (stock/security identifier).                                                                                                                                                                                                                                                                                                                                                         |
+| `@IsISO8601(options?: IsISO8601Options)`        | Checks if the string is a valid ISO 8601 date. Use the option strict = true for additional checks for a valid date, e.g. invalidates dates like 2019-02-29.                                                                                                                                                                                                                                                          |
+| `@IsJSON()`                                     | Checks if the string is valid JSON.                                                                                                                                                                                                                                                                                                                                                                                  |
+| `@IsJWT()`                                      | Checks if the string is valid JWT.                                                                                                                                                                                                                                                                                                                                                                                   |
+| `@IsObject()`                                   | Checks if the object is valid Object (null, functions, arrays will return false).                                                                                                                                                                                                                                                                                                                                    |
+| `@IsNotEmptyObject()`                           | Checks if the object is not empty.                                                                                                                                                                                                                                                                                                                                                                                   |
+| `@IsLowercase()`                                | Checks if the string is lowercase.                                                                                                                                                                                                                                                                                                                                                                                   |
+| `@IsLatLong()`                                  | Checks if the string is a valid latitude-longitude coordinate in the format lat,long                                                                                                                                                                                                                                                                                                                                 |
+| `@IsLatitude()`                                 | Checks if the string or number is a valid latitude coordinate                                                                                                                                                                                                                                                                                                                                                        |
+| `@IsLongitude()`                                | Checks if the string or number is a valid longitude coordinate                                                                                                                                                                                                                                                                                                                                                       |
+| `@IsMobilePhone(locale: string)`                | Checks if the string is a mobile phone number.                                                                                                                                                                                                                                                                                                                                                                       |
+| `@IsISO31661Alpha2()`                           | Checks if the string is a valid [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) officially assigned country code.                                                                                                                                                                                                                                                                             |
+| `@IsISO31661Alpha3()`                           | Checks if the string is a valid [ISO 3166-1 alpha-3](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3) officially assigned country code.                                                                                                                                                                                                                                                                             |
+| `@IsLocale()`                                   | Checks if the string is a locale.                                                                                                                                                                                                                                                                                                                                                                                    |
+| `@IsPhoneNumber(region: string)`                | Checks if the string is a valid phone number. "region" accepts 2 characters uppercase country code (e.g. DE, US, CH).If users must enter the intl. prefix (e.g. +41), then you may pass "ZZ" or null as region. See [google-libphonenumber, metadata.js:countryCodeToRegionCodeMap on github](https://github.com/ruimarinho/google-libphonenumber/blob/1e46138878cff479aafe2ce62175c6c49cb58720/src/metadata.js#L33) |
+| `@IsMongoId()`                                  | Checks if the string is a valid hex-encoded representation of a MongoDB ObjectId.                                                                                                                                                                                                                                                                                                                                    |
+| `@IsMultibyte()`                                | Checks if the string contains one or more multibyte chars.                                                                                                                                                                                                                                                                                                                                                           |
+| `@IsNumberString(options?: IsNumericOptions)`   | Checks if the string is numeric.                                                                                                                                                                                                                                                                                                                                                                                     |
+| `@IsSurrogatePair()`                            | Checks if the string contains any surrogate pairs chars.                                                                                                                                                                                                                                                                                                                                                             |
+| `@IsUrl(options?: IsURLOptions)`                | Checks if the string is an url.                                                                                                                                                                                                                                                                                                                                                                                      |
+| `@IsMagnetURI()`                                | Checks if the string is a [magnet uri format](https://en.wikipedia.org/wiki/Magnet_URI_scheme).                                                                                                                                                                                                                                                                                                                      |
+| `@IsUUID(version?: "3"\|"4"\|"5"\|"all")`       | Checks if the string is a UUID (version 3, 4, 5 or all ).                                                                                                                                                                                                                                                                                                                                                            |
+| `@IsFirebasePushId()`                           | Checks if the string is a [Firebase Push id](https://firebase.googleblog.com/2015/02/the-2120-ways-to-ensure-unique_68.html)                                                                                                                                                                                                                                                                                         |
+| `@IsUppercase()`                                | Checks if the string is uppercase.                                                                                                                                                                                                                                                                                                                                                                                   |
+| `@Length(min: number, max?: number)`            | Checks if the string's length falls in a range.                                                                                                                                                                                                                                                                                                                                                                      |
+| `@MinLength(min: number)`                       | Checks if the string's length is not less than given number.                                                                                                                                                                                                                                                                                                                                                         |
+| `@MaxLength(max: number)`                       | Checks if the string's length is not more than given number.                                                                                                                                                                                                                                                                                                                                                         |
+| `@Matches(pattern: RegExp, modifiers?: string)` | Checks if string matches the pattern. Either matches('foo', /foo/i) or matches('foo', 'foo', 'i').                                                                                                                                                                                                                                                                                                                   |
+| `@IsMilitaryTime()`                             | Checks if the string is a valid representation of military time in the format HH:MM.                                                                                                                                                                                                                                                                                                                                 |
+| `@IsHash(algorithm: string)`                    | Checks if the string is a hash of type algorithm. <br/><br/>Algorithm is one of `['md4', 'md5', 'sha1', 'sha256', 'sha384', 'sha512', 'ripemd128', 'ripemd160', 'tiger128', 'tiger160', 'tiger192', 'crc32', 'crc32b']`                                                                                                                                                                                              |
+| `@IsMimeType()`                                 | Checks if the string matches to a valid [MIME type](https://en.wikipedia.org/wiki/Media_type) format                                                                                                                                                                                                                                                                                                                 |
+| `@IsSemVer()`                                   | Checks if the string is a Semantic Versioning Specification (SemVer).                                                                                                                                                                                                                                                                                                                                                |
+| `@IsISSN(options?: IsISSNOptions)`              | Checks if the string is a ISSN.                                                                                                                                                                                                                                                                                                                                                                                      |
+| `@IsISRC()`                                     | Checks if the string is a [ISRC](https://en.wikipedia.org/wiki/International_Standard_Recording_Code).                                                                                                                                                                                                                                                                                                               |
+| `@IsRFC3339()`                                  | Checks f the string is a valid [RFC 3339](https://tools.ietf.org/html/rfc3339) date.                                                                                                                                                                                                                                                                                                                                 |
+| **Array validation decorators**                 |
+| `@ArrayContains(values: any[])`                 | Checks if array contains all values from the given array of values.                                                                                                                                                                                                                                                                                                                                                  |
+| `@ArrayNotContains(values: any[])`              | Checks if array does not contain any of the given values.                                                                                                                                                                                                                                                                                                                                                            |
+| `@ArrayNotEmpty()`                              | Checks if given array is not empty.                                                                                                                                                                                                                                                                                                                                                                                  |
+| `@ArrayMinSize(min: number)`                    | Checks if array's length is as minimal this number.                                                                                                                                                                                                                                                                                                                                                                  |
+| `@ArrayMaxSize(max: number)`                    | Checks if array's length is as maximal this number.                                                                                                                                                                                                                                                                                                                                                                  |
+| `@ArrayUnique()`                                | Checks if all array's values are unique. Comparison for objects is reference-based.                                                                                                                                                                                                                                                                                                                                  |
+| **Object validation decorators**                |
+| `@IsInstance(value: any)`                       | Checks if the property is an instance of the passed value.                                                                                                                                                                                                                                                                                                                                                           |
+| **Other decorators**                            |
+| `@Allow()`                                      | Prevent stripping off the property when no other constraint is specified for it.                                                                                                                                                                                                                                                                                                                                     |
 
 ## Defining validation schema without decorators
 
 You can define your validation schemas without decorators:
 
-* you can define it in the separate object
-* you can define it in the `.json` file
+- you can define it in the separate object
+- you can define it in the `.json` file
 
 This feature maybe useful in the cases if:
 
-* are using es5/es6 and don't have decorators available
-* you don't have a classes, and instead using interfaces
-* you don't want to use model at all
-* you want to have a validation schema separate of your model
-* you want beautiful json-schema based validation models
-* you simply hate decorators
+- are using es5/es6 and don't have decorators available
+- you don't have a classes, and instead using interfaces
+- you don't want to use model at all
+- you want to have a validation schema separate of your model
+- you want beautiful json-schema based validation models
+- you simply hate decorators
 
 Here is an example of using it:
 
 1. Create a schema object:
 
-    ```typescript
-    import {ValidationSchema} from "class-validator";
-    export let UserValidationSchema: ValidationSchema = { // using interface here is not required, its just for type-safety
-        name: "myUserSchema", // this is required, and must be unique
-        properties: {
-            firstName: [{
-                type: "minLength", // validation type. All validation types are listed in ValidationTypes class.
-                constraints: [2]
-            }, {
-                type: "maxLength",
-                constraints: [20]
-            }],
-            lastName: [{
-                type: "minLength",
-                constraints: [2]
-            }, {
-                type: "maxLength",
-                constraints: [20]
-            }],
-            email: [{
-                type: "isEmail"
-            }]
-        }
-    };
-    ```
-
-    Same schema can be provided in `.json` file, depend on your wish.
+   ```typescript
+   import { ValidationSchema } from 'class-validator';
+   export let UserValidationSchema: ValidationSchema = {
+     // using interface here is not required, its just for type-safety
+     name: 'myUserSchema', // this is required, and must be unique
+     properties: {
+       firstName: [
+         {
+           type: 'minLength', // validation type. All validation types are listed in ValidationTypes class.
+           constraints: [2],
+         },
+         {
+           type: 'maxLength',
+           constraints: [20],
+         },
+       ],
+       lastName: [
+         {
+           type: 'minLength',
+           constraints: [2],
+         },
+         {
+           type: 'maxLength',
+           constraints: [20],
+         },
+       ],
+       email: [
+         {
+           type: 'isEmail',
+         },
+       ],
+     },
+   };
+   ```
+
+   Same schema can be provided in `.json` file, depend on your wish.
 
 2. Register your schema:
 
-    ```typescript
-    import {registerSchema} from "class-validator";
-    import {UserValidationSchema} from "./UserValidationSchema";
-    registerSchema(UserValidationSchema); // if schema is in .json file, then you can simply do registerSchema(require("path-to-schema.json"));
-    ```
+   ```typescript
+   import { registerSchema } from 'class-validator';
+   import { UserValidationSchema } from './UserValidationSchema';
+   registerSchema(UserValidationSchema); // if schema is in .json file, then you can simply do registerSchema(require("path-to-schema.json"));
+   ```
 
-    Better to put this code in a global place, maybe when you bootstrap your application, for example in `app.ts`.
+   Better to put this code in a global place, maybe when you bootstrap your application, for example in `app.ts`.
 
 3. Validate your object using validation schema:
 
-    ```typescript
-    import {validate} from "class-validator";
-    const user = { firstName: "Johny", secondName: "Cage", email: "johny@cage.com" };
-    validate("myUserSchema", user).then(errors => {
-        if (errors.length > 0) {
-            console.log("Validation failed: ", errors);
-        } else {
-            console.log("Validation succeed.");
-        }
-    });
-    ```
-
-    That's it. Here `"myUserSchema"` is the name of our validation schema.
-    `validate` method will perform validation based on this schema
+   ```typescript
+   import { validate } from 'class-validator';
+   const user = { firstName: 'Johny', secondName: 'Cage', email: 'johny@cage.com' };
+   validate('myUserSchema', user).then(errors => {
+     if (errors.length > 0) {
+       console.log('Validation failed: ', errors);
+     } else {
+       console.log('Validation succeed.');
+     }
+   });
+   ```
+
+   That's it. Here `"myUserSchema"` is the name of our validation schema.
+   `validate` method will perform validation based on this schema
 
 ## Validating plain objects
-Due to nature of the decorators, the validated object has to be instantiated using `new Class()` syntax. If you have your class defined using class-validator decorators and you want to validate plain JS object (literal object or returned by JSON.parse), you need to transform it to the class instance (e.g. using [class-transformer](https://github.com/pleerock/class-transformer)) or just use the [class-transformer-validator](https://github.com/19majkel94/class-transformer-validator) extension which can do that for you.
+
+Due to nature of the decorators, the validated object has to be instantiated using `new Class()` syntax. If you have your class defined using class-validator decorators and you want to validate plain JS object (literal object or returned by JSON.parse), you need to transform it to the class instance via using [class-transformer](https://github.com/pleerock/class-transformer)).
 
 ## Samples
 
@@ -996,7 +995,9 @@ Take a look on samples in [./sample](https://github.com/pleerock/class-validator
 usages.
 
 ## Extensions
+
 There are several extensions that simplify class-validator integration with other modules:
+
 - [class-validator integration](https://github.com/19majkel94/class-transformer-validator) with [class-transformer](https://github.com/pleerock/class-transformer)
 - [class-validator-rule](https://github.com/yantrab/class-validator-rule)
 - [ngx-dynamic-form-builder](https://github.com/EndyKaufman/ngx-dynamic-form-builder)
diff --git a/codecov.yml b/codecov.yml
new file mode 100644
index 0000000000..1e7f6e0cdf
--- /dev/null
+++ b/codecov.yml
@@ -0,0 +1,14 @@
+coverage:
+  range: 70..100
+  round: down
+  precision: 2
+  status:
+    project:
+      default:
+        threshold: 0%
+        paths: 
+          - src/**/*.ts
+comment: off
+ignore:
+  - testing/**/*.ts
+  - src/**/*.interface.ts
diff --git a/docs/README.md b/docs/README.md
index 72ff2e0f01..28324125ba 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,38 +1,38 @@
 # Table of Contents
 
-* [Read Me](../README.md)
-* Getting Started
-  * [Installation](introduction/installation.md)
-  * [Usage with Typescript](introduction/usage-with-typescript.md)
-  * [Usage with Javascript](introduction/usage-with-javascript.md)
-  * [Dependency Injection](introduction/usage-with-di.md)
-  * [Core Principes](introduction/core-principes.md)
-* [Basic Usage](basics/README.md)
-  * [Validating objects](basics/validating-objects.md)
-  * [Validating arrays](basics/validating-arrays.md)
-  * [Validating nested objects](basics/validating-nested-objects.md)
-* [Advanced Usage](advanced/README.md)
-  * [Conditional Validation](advanced/conditional-validation.md)
-  * [Validation Groups](advanced/validation-groups.md)
-  * [Inheritance](advanced/inheritance.md)
-  * [Custom Validation Decorators](advanced/validations-decoratos.md)
-  * [Custom Validation Classes](advanced/validation-classes.md)
-* [Decorators Reference](reference/decoratos.md)  
-  * [Common Decorators](reference/common-decoratos.md)  
-  * [Number Decorators](reference/number-decoratos.md)  
-  * [String Decorators](reference/string-decoratos.md)  
-  * [Date Decorators](reference/date-decoratos.md)  
-  * [Array Decorators](reference/array-decoratos.md)  
-* [Recipes](recipes/README.md)
-  * [Simple Validations](https://stackblitz.com/edit/class-transformer-simple-validations)
-  * [Nested Objects](https://stackblitz.com/edit/class-transformer-nested-objects)
-  * [Using Groups](https://stackblitz.com/edit/class-transformer-using-groups)
-  * [Custom Validators](https://stackblitz.com/edit/class-transformer-custom-validator)
-  * [Custom Decorators](https://stackblitz.com/edit/class-transformer-custom-decorators)
-  * [Using Schemas](https://stackblitz.com/edit/class-transformer-schemas)
-  * [Inheritance](https://stackblitz.com/edit/class-transformer-inheritance)
-* [API Reference](api/README.md)
-  * [validate](api/validate.md)
-  * [ValidatorOptions ](api/ValidatorOptions.md)
-  * [ValidationError ](api/ValidationError.md)
-* [Change Log](../CHANGELOG.md)
\ No newline at end of file
+- [Read Me](../README.md)
+- Getting Started
+  - [Installation](introduction/installation.md)
+  - [Usage with Typescript](introduction/usage-with-typescript.md)
+  - [Usage with Javascript](introduction/usage-with-javascript.md)
+  - [Dependency Injection](introduction/usage-with-di.md)
+  - [Core Principes](introduction/core-principes.md)
+- [Basic Usage](basics/README.md)
+  - [Validating objects](basics/validating-objects.md)
+  - [Validating arrays](basics/validating-arrays.md)
+  - [Validating nested objects](basics/validating-nested-objects.md)
+- [Advanced Usage](advanced/README.md)
+  - [Conditional Validation](advanced/conditional-validation.md)
+  - [Validation Groups](advanced/validation-groups.md)
+  - [Inheritance](advanced/inheritance.md)
+  - [Custom Validation Decorators](advanced/validations-decoratos.md)
+  - [Custom Validation Classes](advanced/validation-classes.md)
+- [Decorators Reference](reference/decoratos.md)
+  - [Common Decorators](reference/common-decoratos.md)
+  - [Number Decorators](reference/number-decoratos.md)
+  - [String Decorators](reference/string-decoratos.md)
+  - [Date Decorators](reference/date-decoratos.md)
+  - [Array Decorators](reference/array-decoratos.md)
+- [Recipes](recipes/README.md)
+  - [Simple Validations](https://stackblitz.com/edit/class-transformer-simple-validations)
+  - [Nested Objects](https://stackblitz.com/edit/class-transformer-nested-objects)
+  - [Using Groups](https://stackblitz.com/edit/class-transformer-using-groups)
+  - [Custom Validators](https://stackblitz.com/edit/class-transformer-custom-validator)
+  - [Custom Decorators](https://stackblitz.com/edit/class-transformer-custom-decorators)
+  - [Using Schemas](https://stackblitz.com/edit/class-transformer-schemas)
+  - [Inheritance](https://stackblitz.com/edit/class-transformer-inheritance)
+- [API Reference](api/README.md)
+  - [validate](api/validate.md)
+  - [ValidatorOptions ](api/ValidatorOptions.md)
+  - [ValidationError ](api/ValidationError.md)
+- [Change Log](../CHANGELOG.md)
diff --git a/docs/basics/validating-objects.md b/docs/basics/validating-objects.md
index 5135ae25ce..ba93e25166 100644
--- a/docs/basics/validating-objects.md
+++ b/docs/basics/validating-objects.md
@@ -1,10 +1,19 @@
 # Validating objects
 
 ```ts
-import { validate, validateOrReject, IsString, IsInt, IsDate, MaxLength, Min, Max, ValidationError} from "class-validator";
+import {
+  validate,
+  validateOrReject,
+  IsString,
+  IsInt,
+  IsDate,
+  MaxLength,
+  Min,
+  Max,
+  ValidationError,
+} from 'class-validator';
 
 export class Book {
-
   @IsString()
   @MaxLength(255)
   title: string;
@@ -20,7 +29,6 @@ export class Book {
 
   @IsDate()
   publishDate: Date;
-
 }
 
 const book = new Book();
@@ -31,12 +39,12 @@ book.publishDate = new Date();
 
 validate(book).then((errors: ValidationError[]) => {
   if (errors.length > 0) {
-    console.warn("validate() - Validation failed. Errors: ", errors);
+    console.warn('validate() - Validation failed. Errors: ', errors);
   }
 });
 
 validateOrReject(book).catch((errors: ValidationError[]) => {
-  console.warn("validateOrReject() - Validation failed. Errors: ", errors);
+  console.warn('validateOrReject() - Validation failed. Errors: ', errors);
 });
 
 awaitExample();
@@ -45,9 +53,9 @@ async function awaitExample() {
   try {
     await validateOrReject(book);
   } catch (errors) {
-    console.warn("Async validateOrReject() - Validation failed. Errors: ", errors);
+    console.warn('Async validateOrReject() - Validation failed. Errors: ', errors);
   }
 }
 ```
 
-Run this example on [Stackblitz](https://stackblitz.com/edit/class-validator-simple-example-u9h1ve?file=index.ts)
\ No newline at end of file
+Run this example on [Stackblitz](https://stackblitz.com/edit/class-validator-simple-example-u9h1ve?file=index.ts)
diff --git a/docs/introduction/installation.md b/docs/introduction/installation.md
index 6b0d692c29..0667e60daa 100644
--- a/docs/introduction/installation.md
+++ b/docs/introduction/installation.md
@@ -18,4 +18,4 @@ You can install the next version of `class-validator` via
 npm install --save class-validator@next
 ```
 
-> Note: The next version can break anytime without notice. Do not use this in production.
\ No newline at end of file
+> Note: The next version can break anytime without notice. Do not use this in production.
diff --git a/gulpfile.ts b/gulpfile.ts
deleted file mode 100644
index 942df7647f..0000000000
--- a/gulpfile.ts
+++ /dev/null
@@ -1,299 +0,0 @@
-import { resolve } from "path";
-import { Gulpclass, Task, SequenceTask } from "gulpclass";
-import * as gulp from "gulp";
-import * as del from "del";
-import * as shell from "gulp-shell";
-import * as replace from "gulp-replace";
-import * as ts from "gulp-typescript";
-import * as sourcemaps from "gulp-sourcemaps";
-import { rollup, RollupOptions, Plugin } from "rollup";
-import { terser as rollupTerser } from "rollup-plugin-terser";
-import * as childProcess from "child_process";
-
-const pkg = require("./package.json");
-
-const rollupSourceMaps = require("rollup-plugin-sourcemaps");
-const rollupCommonjs = require("rollup-plugin-commonjs");
-const rollupJson = require("rollup-plugin-json");
-const rollupNodeResolve = require("rollup-plugin-node-resolve");
-const rollupUglify = require("rollup-plugin-uglify");
-
-
-const conventionalChangelog = require("gulp-conventional-changelog");
-
-@Gulpclass()
-export class Gulpfile {
-
-    rollupExternal = [
-        ...Object.keys(pkg.peerDependencies || {}),
-        ...Object.keys(pkg.dependencies || {})
-    ];
-    rollupCommonPlugins: Plugin[] = [
-        // Allow json resolution
-        rollupJson(),
-        // Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs)
-        rollupCommonjs(),
-        // Allow node_modules resolution, so you can use 'external' to control
-        // which external modules to include in the bundle
-        // https://github.com/rollup/rollup-plugin-node-resolve#usage
-        rollupNodeResolve(),
-        // Resolve source maps to the original source
-        rollupSourceMaps(),
-    ];
-    rollupCommonOptions: RollupOptions = {
-        inlineDynamicImports: true,
-        // Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash')
-        external: this.rollupExternal,
-    };
-
-
-
-    // -------------------------------------------------------------------------
-    // General tasks
-    // -------------------------------------------------------------------------
-
-    /**
-     * Cleans build folder.
-     */
-    @Task()
-    clean() {
-        return del([
-            "dist/**",
-            "build/**",
-        ]);
-    }
-
-    /**
-     * Runs typescript files compilation.
-     */
-    @Task()
-    runTests() {
-        return childProcess.spawn("npx jest --coverage", {
-            stdio: 'inherit',
-            shell: true
-        });
-    }
-
-    // -------------------------------------------------------------------------
-    // Packaging and Publishing tasks
-    // -------------------------------------------------------------------------
-
-    @Task()
-    changelog() {
-        return gulp.src("CHANGELOG.md")
-            .pipe(conventionalChangelog({
-                // conventional-changelog options go here
-                preset: "angular"
-            }, {
-                // context goes here
-            }, {
-                // git-raw-commits options go here
-            }, {
-                // conventional-commits-parser options go here
-            }, {
-                // conventional-changelog-writer options go here
-            }))
-            .pipe(gulp.dest("./"));
-    }
-
-    /**
-     * Publishes a package to npm from ./build/package directory.
-     */
-    @Task()
-    npmPublish() {
-        return gulp.src("*.js", { read: false })
-            .pipe(shell([
-                "cd ./dist/ && npm publish"
-            ]));
-    }
-
-    @Task()
-    packageCompileEsm5() {
-        const tsProjectEsm5 = ts.createProject("tsconfig.json", { module: "esnext", target: "es5" });
-        const tsResultEsm5 = gulp.src(["./src/**/*.ts"])
-            .pipe(sourcemaps.init())
-            .pipe(tsProjectEsm5());
-
-        return tsResultEsm5.js
-            .pipe(sourcemaps.write(".", { sourceRoot: "", includeContent: true }))
-            .pipe(gulp.dest("dist/esm5"));
-    }
-
-    @Task()
-    packageCompileEsm2015() {
-        const tsProjectEsm2015 = ts.createProject("tsconfig.json", { module: "esnext", target: "es2018" });
-        const tsResultEsm2015 = gulp.src(["./src/**/*.ts"])
-            .pipe(sourcemaps.init())
-            .pipe(tsProjectEsm2015());
-
-        return tsResultEsm2015.js
-            .pipe(sourcemaps.write(".", { sourceRoot: "", includeContent: true }))
-            .pipe(gulp.dest("dist/esm2015"));
-    }
-
-    @Task()
-    packageCompileTypes() {
-        const tsProject = ts.createProject("tsconfig.json", { module: "esnext" });
-        const tsResult = gulp.src(["./src/**/*.ts"])
-            .pipe(sourcemaps.init())
-            .pipe(tsProject());
-
-        return tsResult.dts.pipe(gulp.dest("dist/types"));
-    }
-
-
-    /**
-     * Copies all sources to the package directory.
-     */
-    @SequenceTask()
-    packageCompile() {
-        return [
-            ["packageCompileEsm5", "packageCompileEsm2015", "packageCompileTypes"]
-        ];
-    }
-
-    @Task()
-    packageBundleEsm5() {
-        return Promise.all([
-            this._rollupPackageBundleEsm5(true),
-            this._rollupPackageBundleEsm5(false),
-        ]);
-    }
-
-    @Task()
-    packageBundleEsm2015() {
-        return Promise.all([
-            this._rollupPackageBundleEsm2015(true),
-            this._rollupPackageBundleEsm2015(false),
-        ]);
-    }
-
-    @SequenceTask()
-    packageBundle() {
-        return [
-            ["packageBundleEsm5", "packageBundleEsm2015"]
-        ];
-    }
-
-    /**
-     * Change the "private" state of the packaged package.json file to public.
-     */
-    @Task()
-    packagePreparePackageFile() {
-        return gulp.src("./package.json")
-            .pipe(replace("\"private\": true,", "\"private\": false,"))
-            .pipe(gulp.dest("./dist"));
-    }
-
-    /**
-     * This task will replace all typescript code blocks in the README (since npm does not support typescript syntax
-     * highlighting) and copy this README file into the package folder.
-     */
-    @Task()
-    packageReadmeFile() {
-        return gulp.src("./README.md")
-            .pipe(replace(/```typescript([\s\S]*?)```/g, "```javascript$1```"))
-            .pipe(gulp.dest("./dist"));
-    }
-
-    /**
-     * Creates a package that can be published to npm.
-     */
-    @SequenceTask()
-    package() {
-        return [
-            "clean",
-            "packageCompile",
-            "packageBundle",
-            ["packagePreparePackageFile", "packageReadmeFile"]
-        ];
-    }
-
-    /**
-     * Creates a package and publishes it to npm.
-     */
-    @SequenceTask()
-    publish() {
-        return ["package", "npmPublish"];
-    }
-
-    // -------------------------------------------------------------------------
-    // Run tests tasks
-    // -------------------------------------------------------------------------
-
-    /**
-     * Runs es linting to validate source code.
-     */
-    @Task()
-    eslint() {
-        return childProcess.spawn("npx eslint --config ./.eslintrc.js --ext .ts ./src ./test", {
-            stdio: 'inherit',
-            shell: true
-        });
-    }
-
-    /**
-     * Compiles the code and runs tests.
-     */
-    @SequenceTask()
-    tests() {
-        return ["clean", "eslint", "runTests"];
-    }
-
-    private _rollupPackageBundleEsm5(isMin: boolean) {
-        return rollup({
-            ...this.rollupCommonOptions,
-            plugins: [
-                ...this.rollupCommonPlugins,
-                ...(isMin ? [rollupUglify.uglify()] : []),
-            ],
-            input: resolve(__dirname, "dist/esm5/index.js"),
-        }).then(bundle => {
-            return bundle.write({
-                file: this._getOutputFileName(resolve(__dirname, "dist/bundles/index.umd.js"), isMin),
-                format: "umd",
-                name: this._pascalCase(this._normalizePackageName(pkg.name)),
-                sourcemap: true,
-            });
-        });
-    }
-
-    private _rollupPackageBundleEsm2015(isMin: boolean) {
-        return rollup({
-            ...this.rollupCommonOptions,
-            plugins: [
-                ...this.rollupCommonPlugins,
-                ...(isMin ? [rollupTerser()] : []),
-            ],
-            input: resolve(__dirname, "dist/esm2015/index.js"),
-        }).then(bundle => {
-            return bundle.write({
-                file: this._getOutputFileName(resolve(__dirname, "dist/bundles/index.esm.js"), isMin),
-                format: "es",
-                sourcemap: true,
-            });
-        });
-    }
-
-    private _dashToCamelCase(myStr: string) {
-        return myStr.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
-    }
-
-    private _toUpperCase(myStr: string) {
-        return `${myStr.charAt(0).toUpperCase()}${myStr.substr(1)}`;
-    }
-
-    private _pascalCase(myStr: string) {
-        return this._toUpperCase(this._dashToCamelCase(myStr));
-    }
-
-    private _normalizePackageName(rawPackageName: string) {
-        const scopeEnd = rawPackageName.indexOf("/") + 1;
-        return rawPackageName.substring(scopeEnd);
-    }
-
-    private _getOutputFileName(fileName: string, isMin = false) {
-        return isMin ? fileName.replace(/\.js$/, ".min.js") : fileName;
-    }
-
-}
diff --git a/jest.config.js b/jest.config.js
index 54ad0dbdd6..7e62d43ea5 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -1,24 +1,10 @@
 module.exports = {
-    modulePaths: ["<rootDir>/node_modules"],
-    transform: {
-        "^.+\\.tsx?$": "ts-jest"
+  preset: 'ts-jest',
+  testEnvironment: 'node',
+  collectCoverageFrom: ['src/**/*.ts', '!src/**/index.ts', '!src/**/*.interface.ts'],
+  globals: {
+    'ts-jest': {
+      tsConfig: 'tsconfig.spec.json',
     },
-    testRegex: "(/__test__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
-    testEnvironment: "node",
-    moduleFileExtensions: [
-        "ts",
-        "tsx",
-        "js",
-        "jsx",
-        "json",
-        "node"
-    ],
-    modulePathIgnorePatterns: [
-        "<rootDir>/build/"
-    ],
-    coverageReporters: [
-        // "html",
-        // "lcov",
-        "text-summary"
-    ]
+  },
 };
diff --git a/package-lock.json b/package-lock.json
index f93c588ce2..68156442dc 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,203 +1,198 @@
 {
   "name": "class-validator",
-  "version": "0.12.2",
+  "version": "0.13.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
     "@babel/code-frame": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
-      "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
+      "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
       "dev": true,
       "requires": {
-        "@babel/highlight": "^7.8.3"
+        "@babel/highlight": "^7.10.4"
       }
     },
     "@babel/core": {
-      "version": "7.9.0",
-      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.9.0.tgz",
-      "integrity": "sha512-kWc7L0fw1xwvI0zi8OKVBuxRVefwGOrKSQMvrQ3dW+bIIavBY3/NpXmpjMy7bQnLgwgzWQZ8TlM57YHpHNHz4w==",
-      "dev": true,
-      "requires": {
-        "@babel/code-frame": "^7.8.3",
-        "@babel/generator": "^7.9.0",
-        "@babel/helper-module-transforms": "^7.9.0",
-        "@babel/helpers": "^7.9.0",
-        "@babel/parser": "^7.9.0",
-        "@babel/template": "^7.8.6",
-        "@babel/traverse": "^7.9.0",
-        "@babel/types": "^7.9.0",
+      "version": "7.11.4",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.4.tgz",
+      "integrity": "sha512-5deljj5HlqRXN+5oJTY7Zs37iH3z3b++KjiKtIsJy1NrjOOVSEaJHEetLBhyu0aQOSNNZ/0IuEAan9GzRuDXHg==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "^7.10.4",
+        "@babel/generator": "^7.11.4",
+        "@babel/helper-module-transforms": "^7.11.0",
+        "@babel/helpers": "^7.10.4",
+        "@babel/parser": "^7.11.4",
+        "@babel/template": "^7.10.4",
+        "@babel/traverse": "^7.11.0",
+        "@babel/types": "^7.11.0",
         "convert-source-map": "^1.7.0",
         "debug": "^4.1.0",
         "gensync": "^1.0.0-beta.1",
         "json5": "^2.1.2",
-        "lodash": "^4.17.13",
+        "lodash": "^4.17.19",
         "resolve": "^1.3.2",
         "semver": "^5.4.1",
         "source-map": "^0.5.0"
       },
       "dependencies": {
-        "convert-source-map": {
-          "version": "1.7.0",
-          "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
-          "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
-          "dev": true,
-          "requires": {
-            "safe-buffer": "~5.1.1"
-          }
-        },
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
         },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
           "dev": true
         }
       }
     },
     "@babel/generator": {
-      "version": "7.9.5",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.9.5.tgz",
-      "integrity": "sha512-GbNIxVB3ZJe3tLeDm1HSn2AhuD/mVcyLDpgtLXa5tplmWrJdF/elxB56XNqCuD6szyNkDi6wuoKXln3QeBmCHQ==",
+      "version": "7.11.4",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.4.tgz",
+      "integrity": "sha512-Rn26vueFx0eOoz7iifCN2UHT6rGtnkSGWSoDRIy8jZN3B91PzeSULbswfLoOWuTuAcNwpG/mxy+uCTDnZ9Mp1g==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.9.5",
+        "@babel/types": "^7.11.0",
         "jsesc": "^2.5.1",
-        "lodash": "^4.17.13",
         "source-map": "^0.5.0"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
+        }
       }
     },
     "@babel/helper-function-name": {
-      "version": "7.9.5",
-      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz",
-      "integrity": "sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw==",
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz",
+      "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-get-function-arity": "^7.8.3",
-        "@babel/template": "^7.8.3",
-        "@babel/types": "^7.9.5"
+        "@babel/helper-get-function-arity": "^7.10.4",
+        "@babel/template": "^7.10.4",
+        "@babel/types": "^7.10.4"
       }
     },
     "@babel/helper-get-function-arity": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz",
-      "integrity": "sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA==",
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz",
+      "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.8.3"
+        "@babel/types": "^7.10.4"
       }
     },
     "@babel/helper-member-expression-to-functions": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz",
-      "integrity": "sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA==",
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz",
+      "integrity": "sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.8.3"
+        "@babel/types": "^7.11.0"
       }
     },
     "@babel/helper-module-imports": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz",
-      "integrity": "sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg==",
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz",
+      "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.8.3"
+        "@babel/types": "^7.10.4"
       }
     },
     "@babel/helper-module-transforms": {
-      "version": "7.9.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz",
-      "integrity": "sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA==",
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz",
+      "integrity": "sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==",
       "dev": true,
       "requires": {
-        "@babel/helper-module-imports": "^7.8.3",
-        "@babel/helper-replace-supers": "^7.8.6",
-        "@babel/helper-simple-access": "^7.8.3",
-        "@babel/helper-split-export-declaration": "^7.8.3",
-        "@babel/template": "^7.8.6",
-        "@babel/types": "^7.9.0",
-        "lodash": "^4.17.13"
+        "@babel/helper-module-imports": "^7.10.4",
+        "@babel/helper-replace-supers": "^7.10.4",
+        "@babel/helper-simple-access": "^7.10.4",
+        "@babel/helper-split-export-declaration": "^7.11.0",
+        "@babel/template": "^7.10.4",
+        "@babel/types": "^7.11.0",
+        "lodash": "^4.17.19"
       }
     },
     "@babel/helper-optimise-call-expression": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz",
-      "integrity": "sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ==",
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz",
+      "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.8.3"
+        "@babel/types": "^7.10.4"
       }
     },
     "@babel/helper-plugin-utils": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz",
-      "integrity": "sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ==",
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz",
+      "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==",
       "dev": true
     },
     "@babel/helper-replace-supers": {
-      "version": "7.8.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.8.6.tgz",
-      "integrity": "sha512-PeMArdA4Sv/Wf4zXwBKPqVj7n9UF/xg6slNRtZW84FM7JpE1CbG8B612FyM4cxrf4fMAMGO0kR7voy1ForHHFA==",
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz",
+      "integrity": "sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==",
       "dev": true,
       "requires": {
-        "@babel/helper-member-expression-to-functions": "^7.8.3",
-        "@babel/helper-optimise-call-expression": "^7.8.3",
-        "@babel/traverse": "^7.8.6",
-        "@babel/types": "^7.8.6"
+        "@babel/helper-member-expression-to-functions": "^7.10.4",
+        "@babel/helper-optimise-call-expression": "^7.10.4",
+        "@babel/traverse": "^7.10.4",
+        "@babel/types": "^7.10.4"
       }
     },
     "@babel/helper-simple-access": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz",
-      "integrity": "sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw==",
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz",
+      "integrity": "sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==",
       "dev": true,
       "requires": {
-        "@babel/template": "^7.8.3",
-        "@babel/types": "^7.8.3"
+        "@babel/template": "^7.10.4",
+        "@babel/types": "^7.10.4"
       }
     },
     "@babel/helper-split-export-declaration": {
-      "version": "7.8.3",
-      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz",
-      "integrity": "sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA==",
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz",
+      "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.8.3"
+        "@babel/types": "^7.11.0"
       }
     },
     "@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.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
+      "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==",
       "dev": true
     },
     "@babel/helpers": {
-      "version": "7.9.2",
-      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.9.2.tgz",
-      "integrity": "sha512-JwLvzlXVPjO8eU9c/wF9/zOIN7X6h8DYf7mG4CiFRZRvZNKEF5dQ3H3V+ASkHoIB3mWhatgl5ONhyqHRI6MppA==",
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz",
+      "integrity": "sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==",
       "dev": true,
       "requires": {
-        "@babel/template": "^7.8.3",
-        "@babel/traverse": "^7.9.0",
-        "@babel/types": "^7.9.0"
+        "@babel/template": "^7.10.4",
+        "@babel/traverse": "^7.10.4",
+        "@babel/types": "^7.10.4"
       }
     },
     "@babel/highlight": {
-      "version": "7.9.0",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.9.0.tgz",
-      "integrity": "sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ==",
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
+      "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
       "dev": true,
       "requires": {
-        "@babel/helper-validator-identifier": "^7.9.0",
+        "@babel/helper-validator-identifier": "^7.10.4",
         "chalk": "^2.0.0",
         "js-tokens": "^4.0.0"
       },
@@ -222,18 +217,27 @@
             "supports-color": "^5.3.0"
           }
         },
+        "color-convert": {
+          "version": "1.9.3",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+          "dev": true,
+          "requires": {
+            "color-name": "1.1.3"
+          }
+        },
+        "color-name": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+          "dev": true
+        },
         "has-flag": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
           "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
           "dev": true
         },
-        "js-tokens": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
-          "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
-          "dev": true
-        },
         "supports-color": {
           "version": "5.5.0",
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -246,9 +250,9 @@
       }
     },
     "@babel/parser": {
-      "version": "7.9.4",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.9.4.tgz",
-      "integrity": "sha512-bC49otXX6N0/VYhgOMh4gnP26E9xnDZK3TmbNpxYzzz9BQLBosQwfyOe9/cXUU3txYhTzLCbcqd5c8y/OmCjHA==",
+      "version": "7.11.4",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.4.tgz",
+      "integrity": "sha512-MggwidiH+E9j5Sh8pbrX5sJvMcsqS5o+7iB42M9/k0CD63MjYbdP4nhSh7uB5wnv2/RVzTZFTxzF/kIa5mrCqA==",
       "dev": true
     },
     "@babel/plugin-syntax-async-generators": {
@@ -270,12 +274,21 @@
       }
     },
     "@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==",
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz",
+      "integrity": "sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      }
+    },
+    "@babel/plugin-syntax-import-meta": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz",
+      "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.8.3"
+        "@babel/helper-plugin-utils": "^7.10.4"
       }
     },
     "@babel/plugin-syntax-json-strings": {
@@ -288,12 +301,12 @@
       }
     },
     "@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==",
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
+      "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.8.3"
+        "@babel/helper-plugin-utils": "^7.10.4"
       }
     },
     "@babel/plugin-syntax-nullish-coalescing-operator": {
@@ -306,12 +319,12 @@
       }
     },
     "@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==",
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
+      "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.8.3"
+        "@babel/helper-plugin-utils": "^7.10.4"
       }
     },
     "@babel/plugin-syntax-object-rest-spread": {
@@ -341,77 +354,51 @@
         "@babel/helper-plugin-utils": "^7.8.0"
       }
     },
-    "@babel/runtime": {
-      "version": "7.9.6",
-      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.6.tgz",
-      "integrity": "sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ==",
-      "dev": true,
-      "requires": {
-        "regenerator-runtime": "^0.13.4"
-      }
-    },
     "@babel/template": {
-      "version": "7.8.6",
-      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.8.6.tgz",
-      "integrity": "sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg==",
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz",
+      "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==",
       "dev": true,
       "requires": {
-        "@babel/code-frame": "^7.8.3",
-        "@babel/parser": "^7.8.6",
-        "@babel/types": "^7.8.6"
+        "@babel/code-frame": "^7.10.4",
+        "@babel/parser": "^7.10.4",
+        "@babel/types": "^7.10.4"
       }
     },
     "@babel/traverse": {
-      "version": "7.9.5",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.9.5.tgz",
-      "integrity": "sha512-c4gH3jsvSuGUezlP6rzSJ6jf8fYjLj3hsMZRx/nX0h+fmHN0w+ekubRrHPqnMec0meycA2nwCsJ7dC8IPem2FQ==",
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.0.tgz",
+      "integrity": "sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg==",
       "dev": true,
       "requires": {
-        "@babel/code-frame": "^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.5",
+        "@babel/code-frame": "^7.10.4",
+        "@babel/generator": "^7.11.0",
+        "@babel/helper-function-name": "^7.10.4",
+        "@babel/helper-split-export-declaration": "^7.11.0",
+        "@babel/parser": "^7.11.0",
+        "@babel/types": "^7.11.0",
         "debug": "^4.1.0",
         "globals": "^11.1.0",
-        "lodash": "^4.17.13"
+        "lodash": "^4.17.19"
       },
       "dependencies": {
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+        "globals": {
+          "version": "11.12.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+          "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
           "dev": true
         }
       }
     },
     "@babel/types": {
-      "version": "7.9.5",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.9.5.tgz",
-      "integrity": "sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg==",
+      "version": "7.11.0",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz",
+      "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==",
       "dev": true,
       "requires": {
-        "@babel/helper-validator-identifier": "^7.9.5",
-        "lodash": "^4.17.13",
+        "@babel/helper-validator-identifier": "^7.10.4",
+        "lodash": "^4.17.19",
         "to-fast-properties": "^2.0.0"
-      },
-      "dependencies": {
-        "@babel/helper-validator-identifier": {
-          "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
-        }
       }
     },
     "@bcoe/v8-coverage": {
@@ -430,109 +417,55 @@
         "minimist": "^1.2.0"
       }
     },
-    "@gulp-sourcemaps/identity-map": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz",
-      "integrity": "sha512-ciiioYMLdo16ShmfHBXJBOFm3xPC4AuwO4xeRpFeHz7WK9PYsWCmigagG2XyzZpubK4a3qNKoUBDhbzHfa50LQ==",
+    "@eslint/eslintrc": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.1.3.tgz",
+      "integrity": "sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==",
       "dev": true,
       "requires": {
-        "acorn": "^5.0.3",
-        "css": "^2.2.1",
-        "normalize-path": "^2.1.1",
-        "source-map": "^0.6.0",
-        "through2": "^2.0.3"
+        "ajv": "^6.12.4",
+        "debug": "^4.1.1",
+        "espree": "^7.3.0",
+        "globals": "^12.1.0",
+        "ignore": "^4.0.6",
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^3.13.1",
+        "lodash": "^4.17.19",
+        "minimatch": "^3.0.4",
+        "strip-json-comments": "^3.1.1"
       },
       "dependencies": {
-        "acorn": {
-          "version": "5.7.4",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz",
-          "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
+        "ajv": {
+          "version": "6.12.4",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz",
+          "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "fast-json-stable-stringify": "^2.0.0",
+            "json-schema-traverse": "^0.4.1",
+            "uri-js": "^4.2.2"
+          }
         }
       }
     },
-    "@gulp-sourcemaps/map-sources": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz",
-      "integrity": "sha1-iQrnxdjId/bThIYCFazp1+yUW9o=",
-      "dev": true,
-      "requires": {
-        "normalize-path": "^2.0.1",
-        "through2": "^2.0.3"
-      }
-    },
     "@istanbuljs/load-nyc-config": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.0.0.tgz",
-      "integrity": "sha512-ZR0rq/f/E4f4XcgnDvtMWXCUJpi8eO0rssVhmztsZqLIEFA9UUP9zmpE0VxlM+kv/E1ul2I876Fwil2ayptDVg==",
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
+      "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
       "dev": true,
       "requires": {
         "camelcase": "^5.3.1",
         "find-up": "^4.1.0",
+        "get-package-type": "^0.1.0",
         "js-yaml": "^3.13.1",
         "resolve-from": "^5.0.0"
       },
       "dependencies": {
-        "camelcase": {
-          "version": "5.3.1",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
-          "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
-          "dev": true
-        },
-        "esprima": {
-          "version": "4.0.1",
-          "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
-          "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
-          "dev": true
-        },
-        "find-up": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
-          "dev": true,
-          "requires": {
-            "locate-path": "^5.0.0",
-            "path-exists": "^4.0.0"
-          }
-        },
-        "js-yaml": {
-          "version": "3.13.1",
-          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
-          "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
-          "dev": true,
-          "requires": {
-            "argparse": "^1.0.7",
-            "esprima": "^4.0.0"
-          }
-        },
-        "locate-path": {
+        "resolve-from": {
           "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-          "dev": true,
-          "requires": {
-            "p-locate": "^4.1.0"
-          }
-        },
-        "p-locate": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^2.2.0"
-          }
-        },
-        "path-exists": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+          "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
           "dev": true
         }
       }
@@ -544,652 +477,549 @@
       "dev": true
     },
     "@jest/console": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/@jest/console/-/console-25.4.0.tgz",
-      "integrity": "sha512-CfE0erx4hdJ6t7RzAcE1wLG6ZzsHSmybvIBQDoCkDM1QaSeWL9wJMzID/2BbHHa7ll9SsbbK43HjbERbBaFX2A==",
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.3.0.tgz",
+      "integrity": "sha512-/5Pn6sJev0nPUcAdpJHMVIsA8sKizL2ZkcKPE5+dJrCccks7tcM7c9wbgHudBJbxXLoTbqsHkG1Dofoem4F09w==",
       "dev": true,
       "requires": {
-        "@jest/types": "^25.4.0",
-        "chalk": "^3.0.0",
-        "jest-message-util": "^25.4.0",
-        "jest-util": "^25.4.0",
+        "@jest/types": "^26.3.0",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "jest-message-util": "^26.3.0",
+        "jest-util": "^26.3.0",
         "slash": "^3.0.0"
       },
       "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "chalk": {
+        "@types/istanbul-reports": {
           "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-          "dev": true,
-          "requires": {
-            "color-name": "~1.1.4"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "has-flag": "^4.0.0"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
         }
       }
     },
     "@jest/core": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/@jest/core/-/core-25.4.0.tgz",
-      "integrity": "sha512-h1x9WSVV0+TKVtATGjyQIMJENs8aF6eUjnCoi4jyRemYZmekLr8EJOGQqTWEX8W6SbZ6Skesy9pGXrKeAolUJw==",
+      "version": "26.4.2",
+      "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.4.2.tgz",
+      "integrity": "sha512-sDva7YkeNprxJfepOctzS8cAk9TOekldh+5FhVuXS40+94SHbiicRO1VV2tSoRtgIo+POs/Cdyf8p76vPTd6dg==",
       "dev": true,
       "requires": {
-        "@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",
+        "@jest/console": "^26.3.0",
+        "@jest/reporters": "^26.4.1",
+        "@jest/test-result": "^26.3.0",
+        "@jest/transform": "^26.3.0",
+        "@jest/types": "^26.3.0",
+        "@types/node": "*",
         "ansi-escapes": "^4.2.1",
-        "chalk": "^3.0.0",
+        "chalk": "^4.0.0",
         "exit": "^0.1.2",
-        "graceful-fs": "^4.2.3",
-        "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",
+        "graceful-fs": "^4.2.4",
+        "jest-changed-files": "^26.3.0",
+        "jest-config": "^26.4.2",
+        "jest-haste-map": "^26.3.0",
+        "jest-message-util": "^26.3.0",
+        "jest-regex-util": "^26.0.0",
+        "jest-resolve": "^26.4.0",
+        "jest-resolve-dependencies": "^26.4.2",
+        "jest-runner": "^26.4.2",
+        "jest-runtime": "^26.4.2",
+        "jest-snapshot": "^26.4.2",
+        "jest-util": "^26.3.0",
+        "jest-validate": "^26.4.2",
+        "jest-watcher": "^26.3.0",
         "micromatch": "^4.0.2",
         "p-each-series": "^2.1.0",
-        "realpath-native": "^2.0.0",
         "rimraf": "^3.0.0",
         "slash": "^3.0.0",
         "strip-ansi": "^6.0.0"
       },
       "dependencies": {
-        "ansi-regex": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
-          "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
-          "dev": true
-        },
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "braces": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-          "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+        "@types/istanbul-reports": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "fill-range": "^7.0.1"
+            "@types/istanbul-lib-report": "*"
           }
         },
         "chalk": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
             "ansi-styles": "^4.1.0",
             "supports-color": "^7.1.0"
           }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        }
+      }
+    },
+    "@jest/environment": {
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.3.0.tgz",
+      "integrity": "sha512-EW+MFEo0DGHahf83RAaiqQx688qpXgl99wdb8Fy67ybyzHwR1a58LHcO376xQJHfmoXTu89M09dH3J509cx2AA==",
+      "dev": true,
+      "requires": {
+        "@jest/fake-timers": "^26.3.0",
+        "@jest/types": "^26.3.0",
+        "@types/node": "*",
+        "jest-mock": "^26.3.0"
+      },
+      "dependencies": {
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "color-name": "~1.1.4"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "fill-range": {
-          "version": "7.0.1",
-          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-          "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+        "@types/istanbul-reports": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "to-regex-range": "^5.0.1"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "glob": {
-          "version": "7.1.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
-        },
-        "graceful-fs": {
-          "version": "4.2.3",
-          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
-          "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "is-number": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-          "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-          "dev": true
-        },
-        "micromatch": {
-          "version": "4.0.2",
-          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
-          "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
+        }
+      }
+    },
+    "@jest/fake-timers": {
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.3.0.tgz",
+      "integrity": "sha512-ZL9ytUiRwVP8ujfRepffokBvD2KbxbqMhrXSBhSdAhISCw3gOkuntisiSFv+A6HN0n0fF4cxzICEKZENLmW+1A==",
+      "dev": true,
+      "requires": {
+        "@jest/types": "^26.3.0",
+        "@sinonjs/fake-timers": "^6.0.1",
+        "@types/node": "*",
+        "jest-message-util": "^26.3.0",
+        "jest-mock": "^26.3.0",
+        "jest-util": "^26.3.0"
+      },
+      "dependencies": {
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "braces": "^3.0.1",
-            "picomatch": "^2.0.5"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "rimraf": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
-          "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+        "@types/istanbul-reports": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "glob": "^7.1.3"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "strip-ansi": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
-          "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        }
+      }
+    },
+    "@jest/globals": {
+      "version": "26.4.2",
+      "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.4.2.tgz",
+      "integrity": "sha512-Ot5ouAlehhHLRhc+sDz2/9bmNv9p5ZWZ9LE1pXGGTCXBasmi5jnYjlgYcYt03FBwLmZXCZ7GrL29c33/XRQiow==",
+      "dev": true,
+      "requires": {
+        "@jest/environment": "^26.3.0",
+        "@jest/types": "^26.3.0",
+        "expect": "^26.4.2"
+      },
+      "dependencies": {
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "ansi-regex": "^5.0.0"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+        "@types/istanbul-reports": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "has-flag": "^4.0.0"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "to-regex-range": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-          "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "is-number": "^7.0.0"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
         }
       }
     },
-    "@jest/environment": {
-      "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.4.0",
-        "@jest/types": "^25.4.0",
-        "jest-mock": "^25.4.0"
-      }
-    },
-    "@jest/fake-timers": {
-      "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.4.0",
-        "jest-message-util": "^25.4.0",
-        "jest-mock": "^25.4.0",
-        "jest-util": "^25.4.0",
-        "lolex": "^5.0.0"
-      }
-    },
     "@jest/reporters": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-25.4.0.tgz",
-      "integrity": "sha512-bhx/buYbZgLZm4JWLcRJ/q9Gvmd3oUh7k2V7gA4ZYBx6J28pIuykIouclRdiAC6eGVX1uRZT+GK4CQJLd/PwPg==",
+      "version": "26.4.1",
+      "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.4.1.tgz",
+      "integrity": "sha512-aROTkCLU8++yiRGVxLsuDmZsQEKO6LprlrxtAuzvtpbIFl3eIjgIf3EUxDKgomkS25R9ZzwGEdB5weCcBZlrpQ==",
       "dev": true,
       "requires": {
         "@bcoe/v8-coverage": "^0.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",
+        "@jest/console": "^26.3.0",
+        "@jest/test-result": "^26.3.0",
+        "@jest/transform": "^26.3.0",
+        "@jest/types": "^26.3.0",
+        "chalk": "^4.0.0",
         "collect-v8-coverage": "^1.0.0",
         "exit": "^0.1.2",
         "glob": "^7.1.2",
+        "graceful-fs": "^4.2.4",
         "istanbul-lib-coverage": "^3.0.0",
-        "istanbul-lib-instrument": "^4.0.0",
+        "istanbul-lib-instrument": "^4.0.3",
         "istanbul-lib-report": "^3.0.0",
         "istanbul-lib-source-maps": "^4.0.0",
         "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",
+        "jest-haste-map": "^26.3.0",
+        "jest-resolve": "^26.4.0",
+        "jest-util": "^26.3.0",
+        "jest-worker": "^26.3.0",
+        "node-notifier": "^8.0.0",
         "slash": "^3.0.0",
         "source-map": "^0.6.0",
-        "string-length": "^3.1.0",
+        "string-length": "^4.0.1",
         "terminal-link": "^2.0.0",
-        "v8-to-istanbul": "^4.1.3"
+        "v8-to-istanbul": "^5.0.1"
       },
       "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "chalk": {
+        "@types/istanbul-reports": {
           "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "color-name": "~1.1.4"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
         },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
         "jest-worker": {
-          "version": "25.4.0",
-          "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.4.0.tgz",
-          "integrity": "sha512-ghAs/1FtfYpMmYQ0AHqxV62XPvKdUDIBBApMZfly+E9JEmYh2K45G0R5dWxx986RN12pRCxsViwQVtGl+N4whw==",
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.3.0.tgz",
+          "integrity": "sha512-Vmpn2F6IASefL+DVBhPzI2J9/GJUsqzomdeN+P+dK8/jKxbh8R3BtFnx3FIta7wYlPU62cpJMJQo4kuOowcMnw==",
           "dev": true,
           "requires": {
+            "@types/node": "*",
             "merge-stream": "^2.0.0",
             "supports-color": "^7.0.0"
           }
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
         }
       }
     },
     "@jest/source-map": {
-      "version": "25.2.6",
-      "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-25.2.6.tgz",
-      "integrity": "sha512-VuIRZF8M2zxYFGTEhkNSvQkUKafQro4y+mwUxy5ewRqs5N/ynSFUODYp3fy1zCnbCMy1pz3k+u57uCqx8QRSQQ==",
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.3.0.tgz",
+      "integrity": "sha512-hWX5IHmMDWe1kyrKl7IhFwqOuAreIwHhbe44+XH2ZRHjrKIh0LO5eLQ/vxHFeAfRwJapmxuqlGAEYLadDq6ZGQ==",
       "dev": true,
       "requires": {
         "callsites": "^3.0.0",
-        "graceful-fs": "^4.2.3",
+        "graceful-fs": "^4.2.4",
         "source-map": "^0.6.0"
-      },
-      "dependencies": {
-        "graceful-fs": {
-          "version": "4.2.3",
-          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
-          "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
       }
     },
     "@jest/test-result": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-25.4.0.tgz",
-      "integrity": "sha512-8BAKPaMCHlL941eyfqhWbmp3MebtzywlxzV+qtngQ3FH+RBqnoSAhNEPj4MG7d2NVUrMOVfrwuzGpVIK+QnMAA==",
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.3.0.tgz",
+      "integrity": "sha512-a8rbLqzW/q7HWheFVMtghXV79Xk+GWwOK1FrtimpI5n1la2SY0qHri3/b0/1F0Ve0/yJmV8pEhxDfVwiUBGtgg==",
       "dev": true,
       "requires": {
-        "@jest/console": "^25.4.0",
-        "@jest/types": "^25.4.0",
+        "@jest/console": "^26.3.0",
+        "@jest/types": "^26.3.0",
         "@types/istanbul-lib-coverage": "^2.0.0",
         "collect-v8-coverage": "^1.0.0"
-      }
+      },
+      "dependencies": {
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
+          "dev": true,
+          "requires": {
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
+          }
+        },
+        "@types/istanbul-reports": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
+          "dev": true,
+          "requires": {
+            "@types/istanbul-lib-report": "*"
+          }
+        },
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        }
+      }
     },
     "@jest/test-sequencer": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-25.4.0.tgz",
-      "integrity": "sha512-240cI+nsM3attx2bMp9uGjjHrwrpvxxrZi8Tyqp/cfOzl98oZXVakXBgxODGyBYAy/UGXPKXLvNc2GaqItrsJg==",
+      "version": "26.4.2",
+      "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.4.2.tgz",
+      "integrity": "sha512-83DRD8N3M0tOhz9h0bn6Kl6dSp+US6DazuVF8J9m21WAp5x7CqSMaNycMP0aemC/SH/pDQQddbsfHRTBXVUgog==",
       "dev": true,
       "requires": {
-        "@jest/test-result": "^25.4.0",
-        "jest-haste-map": "^25.4.0",
-        "jest-runner": "^25.4.0",
-        "jest-runtime": "^25.4.0"
+        "@jest/test-result": "^26.3.0",
+        "graceful-fs": "^4.2.4",
+        "jest-haste-map": "^26.3.0",
+        "jest-runner": "^26.4.2",
+        "jest-runtime": "^26.4.2"
       }
     },
     "@jest/transform": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-25.4.0.tgz",
-      "integrity": "sha512-t1w2S6V1sk++1HHsxboWxPEuSpN8pxEvNrZN+Ud/knkROWtf8LeUmz73A4ezE8476a5AM00IZr9a8FO9x1+j3g==",
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.3.0.tgz",
+      "integrity": "sha512-Isj6NB68QorGoFWvcOjlUhpkT56PqNIsXKR7XfvoDlCANn/IANlh8DrKAA2l2JKC3yWSMH5wS0GwuQM20w3b2A==",
       "dev": true,
       "requires": {
         "@babel/core": "^7.1.0",
-        "@jest/types": "^25.4.0",
+        "@jest/types": "^26.3.0",
         "babel-plugin-istanbul": "^6.0.0",
-        "chalk": "^3.0.0",
+        "chalk": "^4.0.0",
         "convert-source-map": "^1.4.0",
         "fast-json-stable-stringify": "^2.0.0",
-        "graceful-fs": "^4.2.3",
-        "jest-haste-map": "^25.4.0",
-        "jest-regex-util": "^25.2.6",
-        "jest-util": "^25.4.0",
+        "graceful-fs": "^4.2.4",
+        "jest-haste-map": "^26.3.0",
+        "jest-regex-util": "^26.0.0",
+        "jest-util": "^26.3.0",
         "micromatch": "^4.0.2",
         "pirates": "^4.0.1",
-        "realpath-native": "^2.0.0",
         "slash": "^3.0.0",
         "source-map": "^0.6.1",
         "write-file-atomic": "^3.0.0"
       },
       "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "braces": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-          "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+        "@types/istanbul-reports": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "fill-range": "^7.0.1"
+            "@types/istanbul-lib-report": "*"
           }
         },
         "chalk": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
             "ansi-styles": "^4.1.0",
             "supports-color": "^7.1.0"
           }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-          "dev": true,
-          "requires": {
-            "color-name": "~1.1.4"
-          }
-        },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "fill-range": {
-          "version": "7.0.1",
-          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-          "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
-          "dev": true,
-          "requires": {
-            "to-regex-range": "^5.0.1"
-          }
-        },
-        "graceful-fs": {
-          "version": "4.2.3",
-          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
-          "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "is-number": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-          "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-          "dev": true
-        },
-        "micromatch": {
-          "version": "4.0.2",
-          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
-          "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
-          "dev": true,
-          "requires": {
-            "braces": "^3.0.1",
-            "picomatch": "^2.0.5"
-          }
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
-        },
-        "to-regex-range": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-          "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-          "dev": true,
-          "requires": {
-            "is-number": "^7.0.0"
-          }
         }
       }
     },
     "@jest/types": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.4.0.tgz",
-      "integrity": "sha512-XBeaWNzw2PPnGW5aXvZt3+VO60M+34RY3XDsCK5tW7kyj3RK0XClRutCfjqcBuaR2aBQTbluEDME9b5MB9UAPw==",
+      "version": "25.5.0",
+      "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.5.0.tgz",
+      "integrity": "sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw==",
       "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"
+      }
+    },
+    "@rollup/plugin-commonjs": {
+      "version": "15.0.0",
+      "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-15.0.0.tgz",
+      "integrity": "sha512-8uAdikHqVyrT32w1zB9VhW6uGwGjhKgnDNP4pQJsjdnyF4FgCj6/bmv24c7v2CuKhq32CcyCwRzMPEElaKkn0w==",
+      "dev": true,
+      "requires": {
+        "@rollup/pluginutils": "^3.1.0",
+        "commondir": "^1.0.1",
+        "estree-walker": "^2.0.1",
+        "glob": "^7.1.6",
+        "is-reference": "^1.2.1",
+        "magic-string": "^0.25.7",
+        "resolve": "^1.17.0"
       },
       "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
-          "dev": true,
-          "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
-          }
-        },
-        "chalk": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
-        "color-convert": {
+        "estree-walker": {
           "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-          "dev": true,
-          "requires": {
-            "color-name": "~1.1.4"
-          }
-        },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.1.tgz",
+          "integrity": "sha512-tF0hv+Yi2Ot1cwj9eYHtxC0jB9bmjacjQs6ZBTj82H8JwUywFuc+7E83NWfNMwHXZc11mjfFcVXPe9gEP4B8dg==",
           "dev": true
-        },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
         }
       }
     },
-    "@nodelib/fs.scandir": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.1.tgz",
-      "integrity": "sha512-NT/skIZjgotDSiXs0WqYhgcuBKhUMgfekCmCGtkUAiLqZdOnrdjmZr9wRl3ll64J9NF79uZ4fk16Dx0yMc/Xbg==",
+    "@rollup/plugin-node-resolve": {
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-9.0.0.tgz",
+      "integrity": "sha512-gPz+utFHLRrd41WMP13Jq5mqqzHL3OXrfj3/MkSyB6UBIcuNt9j60GCbarzMzdf1VHFpOxfQh/ez7wyadLMqkg==",
       "dev": true,
       "requires": {
-        "@nodelib/fs.stat": "2.0.1",
-        "run-parallel": "^1.1.9"
+        "@rollup/pluginutils": "^3.1.0",
+        "@types/resolve": "1.17.1",
+        "builtin-modules": "^3.1.0",
+        "deepmerge": "^4.2.2",
+        "is-module": "^1.0.0",
+        "resolve": "^1.17.0"
       }
     },
-    "@nodelib/fs.stat": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.1.tgz",
-      "integrity": "sha512-+RqhBlLn6YRBGOIoVYthsG0J9dfpO79eJyN7BYBkZJtfqrBwf2KK+rD/M/yjZR6WBmIhAgOV7S60eCgaSWtbFw==",
-      "dev": true
-    },
-    "@nodelib/fs.walk": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.2.tgz",
-      "integrity": "sha512-J/DR3+W12uCzAJkw7niXDcqcKBg6+5G5Q/ZpThpGNzAUz70eOR6RV4XnnSN01qHZiVl0eavoxJsBypQoKsV2QQ==",
+    "@rollup/pluginutils": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
+      "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==",
       "dev": true,
       "requires": {
-        "@nodelib/fs.scandir": "2.1.1",
-        "fastq": "^1.6.0"
+        "@types/estree": "0.0.39",
+        "estree-walker": "^1.0.1",
+        "picomatch": "^2.2.2"
       }
     },
     "@sinonjs/commons": {
-      "version": "1.7.2",
-      "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.7.2.tgz",
-      "integrity": "sha512-+DUO6pnp3udV/v2VfUWgaY5BIE1IfT7lLfeDzPVeMT1XKkaAp9LgSI9x5RtrFQoZ9Oi0PgXQQHPaoKu7dCjVxw==",
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz",
+      "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==",
       "dev": true,
       "requires": {
         "type-detect": "4.0.8"
       }
     },
+    "@sinonjs/fake-timers": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz",
+      "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==",
+      "dev": true,
+      "requires": {
+        "@sinonjs/commons": "^1.7.0"
+      }
+    },
     "@types/babel__core": {
-      "version": "7.1.7",
-      "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.7.tgz",
-      "integrity": "sha512-RL62NqSFPCDK2FM1pSDH0scHpJvsXtZNiYlMB73DgPBaG1E38ZYVL+ei5EkWRbr+KC4YNiAUNBnRj+bgwpgjMw==",
+      "version": "7.1.9",
+      "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.9.tgz",
+      "integrity": "sha512-sY2RsIJ5rpER1u3/aQ8OFSI7qGIy8o1NEEbgb2UaJcvOtXOMpd39ko723NBpjQFg9SIX7TXtjejZVGeIMLhoOw==",
       "dev": true,
       "requires": {
         "@babel/parser": "^7.1.0",
@@ -1219,39 +1049,20 @@
       }
     },
     "@types/babel__traverse": {
-      "version": "7.0.10",
-      "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.10.tgz",
-      "integrity": "sha512-74fNdUGrWsgIB/V9kTO5FGHPWYY6Eqn+3Z7L6Hc4e/BxjYV7puvBqp5HwsVYYfLm6iURYBNCx4Ut37OF9yitCw==",
+      "version": "7.0.13",
+      "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.13.tgz",
+      "integrity": "sha512-i+zS7t6/s9cdQvbqKDARrcbrPvtJGlbYsMkazo03nTAK3RX9FNrLllXys22uiTGJapPOTZTQ35nHh4ISph4SLQ==",
       "dev": true,
       "requires": {
         "@babel/types": "^7.3.0"
       }
     },
-    "@types/chokidar": {
-      "version": "1.7.5",
-      "resolved": "https://registry.npmjs.org/@types/chokidar/-/chokidar-1.7.5.tgz",
-      "integrity": "sha512-PDkSRY7KltW3M60hSBlerxI8SFPXsO3AL/aRVsO4Kh9IHRW74Ih75gUuTd/aE4LSSFqypb10UIX3QzOJwBQMGQ==",
-      "dev": true,
-      "requires": {
-        "@types/events": "*",
-        "@types/node": "*"
-      }
-    },
     "@types/color-name": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
       "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
       "dev": true
     },
-    "@types/del": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/@types/del/-/del-4.0.0.tgz",
-      "integrity": "sha512-LDE5atstX5kKnTobWknpmGHC52DH/tp8pIVsD2SSxaOFqW3AQr0EpdzYIfkZ331xe7l9Vn9NlJsBG6viU3mjBA==",
-      "dev": true,
-      "requires": {
-        "del": "*"
-      }
-    },
     "@types/eslint-visitor-keys": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz",
@@ -1264,91 +1075,19 @@
       "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
       "dev": true
     },
-    "@types/events": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz",
-      "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==",
-      "dev": true
-    },
-    "@types/fancy-log": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/@types/fancy-log/-/fancy-log-1.3.0.tgz",
-      "integrity": "sha512-mQjDxyOM1Cpocd+vm1kZBP7smwKZ4TNokFeds9LV7OZibmPJFEzY3+xZMrKfUdNT71lv8GoCPD6upKwHxubClw==",
-      "dev": true
-    },
-    "@types/glob": {
-      "version": "5.0.35",
-      "resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.35.tgz",
-      "integrity": "sha512-wc+VveszMLyMWFvXLkloixT4n0harUIVZjnpzztaZ0nKLuul7Z32iMt2fUFGAaZ4y1XWjFRMtCI5ewvyh4aIeg==",
-      "dev": true,
-      "requires": {
-        "@types/events": "*",
-        "@types/minimatch": "*",
-        "@types/node": "*"
-      }
-    },
-    "@types/glob-stream": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/@types/glob-stream/-/glob-stream-6.1.0.tgz",
-      "integrity": "sha512-RHv6ZQjcTncXo3thYZrsbAVwoy4vSKosSWhuhuQxLOTv74OJuFQxXkmUuZCr3q9uNBEVCvIzmZL/FeRNbHZGUg==",
-      "dev": true,
-      "requires": {
-        "@types/glob": "*",
-        "@types/node": "*"
-      }
-    },
-    "@types/gulp": {
-      "version": "4.0.5",
-      "resolved": "https://registry.npmjs.org/@types/gulp/-/gulp-4.0.5.tgz",
-      "integrity": "sha512-nx1QjPTiRpvLfYsZ7MBu7bT6Cm7tAXyLbY0xbdx2IEMxCK2v2urIhJMQZHW0iV1TskM71Xl6p2uRRuWDbk+/7g==",
-      "dev": true,
-      "requires": {
-        "@types/chokidar": "*",
-        "@types/undertaker": "*",
-        "@types/vinyl-fs": "*"
-      }
-    },
-    "@types/gulp-istanbul": {
-      "version": "0.9.32",
-      "resolved": "https://registry.npmjs.org/@types/gulp-istanbul/-/gulp-istanbul-0.9.32.tgz",
-      "integrity": "sha512-/up/FZZPsIw6VwsR6ONqZfhRt8Qq6T3W2ufrEZQIlTvTdfzByHWxmuO9zKLBqIBlNj0rfQgp9lxheJ+003qDRw==",
-      "dev": true,
-      "requires": {
-        "@types/node": "*"
-      }
-    },
-    "@types/gulp-mocha": {
-      "version": "0.0.32",
-      "resolved": "https://registry.npmjs.org/@types/gulp-mocha/-/gulp-mocha-0.0.32.tgz",
-      "integrity": "sha512-30OJubm6wl7oVFR7ibaaTl0h52sRQDJwB0h7SXm8KbPG7TN3Bb8QqNI7ObfGFjCoBCk9tr55R4278ckLMFzNcw==",
-      "dev": true,
-      "requires": {
-        "@types/mocha": "*",
-        "@types/node": "*"
-      }
-    },
-    "@types/gulp-replace": {
-      "version": "0.0.31",
-      "resolved": "https://registry.npmjs.org/@types/gulp-replace/-/gulp-replace-0.0.31.tgz",
-      "integrity": "sha512-dbgQ1u0N9ShXrzahBgQfMSu6qUh8nlTLt7whhQ0S0sEUHhV3scysppJ1UX0fl53PJENgAL99ueykddyrCaDt7g==",
-      "dev": true,
-      "requires": {
-        "@types/node": "*"
-      }
-    },
-    "@types/gulp-sourcemaps": {
-      "version": "0.0.32",
-      "resolved": "https://registry.npmjs.org/@types/gulp-sourcemaps/-/gulp-sourcemaps-0.0.32.tgz",
-      "integrity": "sha512-+7BAmptW2bxyJnJcCEuie7vLoop3FwWgCdBMzyv7MYXED/HeNMeQuX7uPCkp4vfU1TTu4CYFH0IckNPvo0VePA==",
+    "@types/graceful-fs": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.3.tgz",
+      "integrity": "sha512-AiHRaEB50LQg0pZmm659vNBb9f4SJ0qrAnteuzhSeAUcJKxoYgEnprg/83kppCnc2zvtCKbdZry1a5pVY3lOTQ==",
       "dev": true,
       "requires": {
         "@types/node": "*"
       }
     },
     "@types/istanbul-lib-coverage": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz",
-      "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==",
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz",
+      "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==",
       "dev": true
     },
     "@types/istanbul-lib-report": {
@@ -1361,9 +1100,9 @@
       }
     },
     "@types/istanbul-reports": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz",
-      "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==",
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz",
+      "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==",
       "dev": true,
       "requires": {
         "@types/istanbul-lib-coverage": "*",
@@ -1371,9 +1110,9 @@
       }
     },
     "@types/jest": {
-      "version": "25.2.1",
-      "resolved": "https://registry.npmjs.org/@types/jest/-/jest-25.2.1.tgz",
-      "integrity": "sha512-msra1bCaAeEdkSyA0CZ6gW1ukMIvZ5YoJkdXw/qhQdsuuDlFTcEUrUw8CLCPt2rVRUfXlClVvK2gvPs9IokZaA==",
+      "version": "26.0.14",
+      "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.14.tgz",
+      "integrity": "sha512-Hz5q8Vu0D288x3iWXePSn53W7hAjP0H7EQ6QvDO9c7t46mR0lNOLlfuwQ+JkVxuhygHzlzPX+0jKdA3ZgSh+Vg==",
       "dev": true,
       "requires": {
         "jest-diff": "^25.2.1",
@@ -1381,36 +1120,15 @@
       }
     },
     "@types/json-schema": {
-      "version": "7.0.4",
-      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.4.tgz",
-      "integrity": "sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==",
-      "dev": true
-    },
-    "@types/merge2": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/@types/merge2/-/merge2-1.1.4.tgz",
-      "integrity": "sha512-GjaXY4OultxbaOOk7lCLO7xvEcFpdjExC605YmfI6X29vhHKpJfMWKCDZd3x+BITrZaXKg97DgV/SdGVSwdzxA==",
-      "dev": true,
-      "requires": {
-        "@types/node": "*"
-      }
-    },
-    "@types/minimatch": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
-      "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
-      "dev": true
-    },
-    "@types/mocha": {
-      "version": "7.0.0",
-      "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.0.tgz",
-      "integrity": "sha512-6mh1VlA343Ax31blo37+KZ0DxDOA8b6cL963xPOOt7fMYtG07aJJ+0FRLvcDO4KrL45faOS104G7kwAjZc9l4w==",
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.5.tgz",
+      "integrity": "sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ==",
       "dev": true
     },
     "@types/node": {
-      "version": "12.7.1",
-      "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.1.tgz",
-      "integrity": "sha512-aK9jxMypeSrhiYofWWBf/T7O+KwaiAHzM4sveCdWPn71lzUSMimRnKzhXDKfKwV1kWoBo2P1aGgaIYGLf9/ljw==",
+      "version": "14.6.4",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-14.6.4.tgz",
+      "integrity": "sha512-Wk7nG1JSaMfMpoMJDKUsWYugliB2Vy55pdjLpmLixeyMi7HizW2I/9QoxsPCkXl3dO+ZOVqPumKaDUv5zJu2uQ==",
       "dev": true
     },
     "@types/normalize-package-data": {
@@ -1419,116 +1137,43 @@
       "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==",
       "dev": true
     },
+    "@types/parse-json": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+      "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
+      "dev": true
+    },
     "@types/prettier": {
-      "version": "1.19.1",
-      "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-1.19.1.tgz",
-      "integrity": "sha512-5qOlnZscTn4xxM5MeGXAMOsIOIKIbh9e85zJWfBRVPlRMEVawzoPhINYbRGkBZCI8LxvBe7tJCdWiarA99OZfQ==",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.0.2.tgz",
+      "integrity": "sha512-IkVfat549ggtkZUthUzEX49562eGikhSYeVGX97SkMFn+sTZrgRewXjQ4tPKFPCykZHkX1Zfd9OoELGqKU2jJA==",
       "dev": true
     },
     "@types/resolve": {
-      "version": "0.0.8",
-      "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz",
-      "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==",
+      "version": "1.17.1",
+      "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
+      "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==",
       "dev": true,
       "requires": {
         "@types/node": "*"
       }
     },
-    "@types/rollup-plugin-json": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/@types/rollup-plugin-json/-/rollup-plugin-json-3.0.2.tgz",
-      "integrity": "sha512-eTRym5nG4HEKDR/KrTnCMYwF7V0hgVjEesvtJCK3V8ho/aT0ZFRFgsDtx38VarM30HCsN372+i4FKYwnhcwiVA==",
-      "dev": true,
-      "requires": {
-        "@types/node": "*",
-        "rollup": "^0.63.4"
-      },
-      "dependencies": {
-        "rollup": {
-          "version": "0.63.5",
-          "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.63.5.tgz",
-          "integrity": "sha512-dFf8LpUNzIj3oE0vCvobX6rqOzHzLBoblyFp+3znPbjiSmSvOoK2kMKx+Fv9jYduG1rvcCfCveSgEaQHjWRF6g==",
-          "dev": true,
-          "requires": {
-            "@types/estree": "0.0.39",
-            "@types/node": "*"
-          }
-        }
-      }
-    },
-    "@types/rollup-plugin-sourcemaps": {
-      "version": "0.4.2",
-      "resolved": "https://registry.npmjs.org/@types/rollup-plugin-sourcemaps/-/rollup-plugin-sourcemaps-0.4.2.tgz",
-      "integrity": "sha512-dqF1rMFy4O8yNlQYwYPos5Cfav0f6M7PLH8B33gsslQ0zA9MX1jMGokwNuJ3Z3EXAzsKF/xAWNHpFmELcgYJww==",
-      "dev": true,
-      "requires": {
-        "@types/node": "*",
-        "rollup": "^0.63.4"
-      },
-      "dependencies": {
-        "rollup": {
-          "version": "0.63.5",
-          "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.63.5.tgz",
-          "integrity": "sha512-dFf8LpUNzIj3oE0vCvobX6rqOzHzLBoblyFp+3znPbjiSmSvOoK2kMKx+Fv9jYduG1rvcCfCveSgEaQHjWRF6g==",
-          "dev": true,
-          "requires": {
-            "@types/estree": "0.0.39",
-            "@types/node": "*"
-          }
-        }
-      }
-    },
     "@types/stack-utils": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
       "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==",
       "dev": true
     },
-    "@types/undertaker": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/@types/undertaker/-/undertaker-1.2.0.tgz",
-      "integrity": "sha512-bx/5nZCGkasXs6qaA3B6SVDjBZqdyk04UO12e0uEPSzjt5H8jEJw0DKe7O7IM0hM2bVHRh70pmOH7PEHqXwzOw==",
-      "dev": true,
-      "requires": {
-        "@types/events": "*",
-        "@types/undertaker-registry": "*"
-      }
-    },
-    "@types/undertaker-registry": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/@types/undertaker-registry/-/undertaker-registry-1.0.1.tgz",
-      "integrity": "sha512-Z4TYuEKn9+RbNVk1Ll2SS4x1JeLHecolIbM/a8gveaHsW0Hr+RQMraZACwTO2VD7JvepgA6UO1A1VrbktQrIbQ==",
-      "dev": true
-    },
     "@types/validator": {
-      "version": "13.0.0",
-      "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.0.0.tgz",
-      "integrity": "sha512-WAy5txG7aFX8Vw3sloEKp5p/t/Xt8jD3GRD9DacnFv6Vo8ubudAsRTXgxpQwU0mpzY/H8U4db3roDuCMjShBmw=="
-    },
-    "@types/vinyl": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.2.tgz",
-      "integrity": "sha512-2iYpNuOl98SrLPBZfEN9Mh2JCJ2EI9HU35SfgBEb51DcmaHkhp8cKMblYeBqMQiwXMgAD3W60DbQ4i/UdLiXhw==",
-      "dev": true,
-      "requires": {
-        "@types/node": "*"
-      }
-    },
-    "@types/vinyl-fs": {
-      "version": "2.4.8",
-      "resolved": "https://registry.npmjs.org/@types/vinyl-fs/-/vinyl-fs-2.4.8.tgz",
-      "integrity": "sha512-yE2pN9OOrxJVeO7IZLHAHrh5R4Q0osbn5WQRuQU6GdXoK7dNFrMK3K7YhATkzf3z0yQBkol3+gafs7Rp0s7dDg==",
-      "dev": true,
-      "requires": {
-        "@types/glob-stream": "*",
-        "@types/node": "*",
-        "@types/vinyl": "*"
-      }
+      "version": "13.1.0",
+      "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.1.0.tgz",
+      "integrity": "sha512-gHUHI6pJaANIO2r6WcbT7+WMgbL9GZooR4tWpuBOETpDIqFNxwaJluE+6rj6VGYe8k6OkfhbHz2Fkm8kl06Igw==",
+      "dev": true
     },
     "@types/yargs": {
-      "version": "15.0.4",
-      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.4.tgz",
-      "integrity": "sha512-9T1auFmbPZoxHz0enUFlUuKRy3it01R+hlggyVUMtnCTQRunsQYifnSGb8hET4Xo8yiC0o0r1paW3ud5+rbURg==",
+      "version": "15.0.5",
+      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.5.tgz",
+      "integrity": "sha512-Dk/IDOPtOgubt/IaevIUbTgV7doaKkoorvOyYM2CMwuDyP89bekI7H4xLIwunNYiK9jhCkmc6pUrJk3cj2AB9w==",
       "dev": true,
       "requires": {
         "@types/yargs-parser": "*"
@@ -1541,116 +1186,80 @@
       "dev": true
     },
     "@typescript-eslint/eslint-plugin": {
-      "version": "2.29.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.29.0.tgz",
-      "integrity": "sha512-X/YAY7azKirENm4QRpT7OVmzok02cSkqeIcLmdz6gXUQG4Hk0Fi9oBAynSAyNXeGdMRuZvjBa0c1Lu0dn/u6VA==",
+      "version": "3.10.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.10.1.tgz",
+      "integrity": "sha512-PQg0emRtzZFWq6PxBcdxRH3QIQiyFO3WCVpRL3fgj5oQS3CDs3AeAKfv4DxNhzn8ITdNJGJ4D3Qw8eAJf3lXeQ==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/experimental-utils": "2.29.0",
+        "@typescript-eslint/experimental-utils": "3.10.1",
+        "debug": "^4.1.1",
         "functional-red-black-tree": "^1.0.1",
         "regexpp": "^3.0.0",
+        "semver": "^7.3.2",
         "tsutils": "^3.17.1"
       }
     },
     "@typescript-eslint/experimental-utils": {
-      "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==",
+      "version": "3.10.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.10.1.tgz",
+      "integrity": "sha512-DewqIgscDzmAfd5nOGe4zm6Bl7PKtMG2Ad0KG8CUZAHlXfAKTF9Ol5PXhiMh39yRL2ChRH1cuuUGOcVyyrhQIw==",
       "dev": true,
       "requires": {
         "@types/json-schema": "^7.0.3",
-        "@typescript-eslint/typescript-estree": "2.29.0",
+        "@typescript-eslint/types": "3.10.1",
+        "@typescript-eslint/typescript-estree": "3.10.1",
         "eslint-scope": "^5.0.0",
         "eslint-utils": "^2.0.0"
       }
     },
     "@typescript-eslint/parser": {
-      "version": "2.29.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.29.0.tgz",
-      "integrity": "sha512-H78M+jcu5Tf6m/5N8iiFblUUv+HJDguMSdFfzwa6vSg9lKR8Mk9BsgeSjO8l2EshKnJKcbv0e8IDDOvSNjl0EA==",
+      "version": "3.10.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.10.1.tgz",
+      "integrity": "sha512-Ug1RcWcrJP02hmtaXVS3axPPTTPnZjupqhgj+NnZ6BCkwSImWk/283347+x9wN+lqOdK9Eo3vsyiyDHgsmiEJw==",
       "dev": true,
       "requires": {
         "@types/eslint-visitor-keys": "^1.0.0",
-        "@typescript-eslint/experimental-utils": "2.29.0",
-        "@typescript-eslint/typescript-estree": "2.29.0",
+        "@typescript-eslint/experimental-utils": "3.10.1",
+        "@typescript-eslint/types": "3.10.1",
+        "@typescript-eslint/typescript-estree": "3.10.1",
         "eslint-visitor-keys": "^1.1.0"
       }
     },
+    "@typescript-eslint/types": {
+      "version": "3.10.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-3.10.1.tgz",
+      "integrity": "sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ==",
+      "dev": true
+    },
     "@typescript-eslint/typescript-estree": {
-      "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==",
+      "version": "3.10.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.10.1.tgz",
+      "integrity": "sha512-QbcXOuq6WYvnB3XPsZpIwztBoquEYLXh2MtwVU+kO8jgYCiv4G5xrSP/1wg4tkvrEE+esZVquIPX/dxPlePk1w==",
       "dev": true,
       "requires": {
+        "@typescript-eslint/types": "3.10.1",
+        "@typescript-eslint/visitor-keys": "3.10.1",
         "debug": "^4.1.1",
-        "eslint-visitor-keys": "^1.1.0",
         "glob": "^7.1.6",
         "is-glob": "^4.0.1",
         "lodash": "^4.17.15",
-        "semver": "^6.3.0",
+        "semver": "^7.3.2",
         "tsutils": "^3.17.1"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "glob": {
-          "version": "7.1.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
-        "is-glob": {
-          "version": "4.0.1",
-          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
-          "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
-          "dev": true,
-          "requires": {
-            "is-extglob": "^2.1.1"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        },
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        }
       }
     },
-    "JSONStream": {
-      "version": "1.3.5",
-      "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
-      "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
+    "@typescript-eslint/visitor-keys": {
+      "version": "3.10.1",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-3.10.1.tgz",
+      "integrity": "sha512-9JgC82AaQeglebjZMgYR5wgmfUdUc+EitGUUMW8u2nDckaeimzW+VsoLV6FoimPv2id3VQzfjwBxEMVz08ameQ==",
       "dev": true,
       "requires": {
-        "jsonparse": "^1.2.0",
-        "through": ">=2.2.7 <3"
+        "eslint-visitor-keys": "^1.1.0"
       }
     },
     "abab": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz",
-      "integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==",
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.4.tgz",
+      "integrity": "sha512-Eu9ELJWCz/c1e9gTiCY+FceWxcqzjYEbqMgtndnuSqZSUCOL73TWNK2mHfIj4Cw2E/ongOp+JISVNCmovt2KYQ==",
       "dev": true
     },
     "acorn": {
@@ -1660,45 +1269,41 @@
       "dev": true
     },
     "acorn-globals": {
-      "version": "4.3.4",
-      "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz",
-      "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==",
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz",
+      "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==",
       "dev": true,
       "requires": {
-        "acorn": "^6.0.1",
-        "acorn-walk": "^6.0.1"
-      },
-      "dependencies": {
-        "acorn": {
-          "version": "6.4.1",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
-          "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==",
-          "dev": true
-        }
+        "acorn": "^7.1.1",
+        "acorn-walk": "^7.1.1"
       }
     },
     "acorn-jsx": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.2.0.tgz",
-      "integrity": "sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ==",
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
+      "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
       "dev": true
     },
     "acorn-walk": {
-      "version": "6.2.0",
-      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz",
-      "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==",
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
+      "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
       "dev": true
     },
-    "add-stream": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz",
-      "integrity": "sha1-anmQQ3ynNtXhKI25K9MmbV9csqo=",
-      "dev": true
+    "aggregate-error": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+      "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+      "dev": true,
+      "requires": {
+        "clean-stack": "^2.0.0",
+        "indent-string": "^4.0.0"
+      }
     },
     "ajv": {
-      "version": "6.12.2",
-      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.2.tgz",
-      "integrity": "sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ==",
+      "version": "6.12.3",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz",
+      "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==",
       "dev": true,
       "requires": {
         "fast-deep-equal": "^3.1.1",
@@ -1707,20 +1312,11 @@
         "uri-js": "^4.2.2"
       }
     },
-    "amdefine": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
-      "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
-      "dev": true
-    },
     "ansi-colors": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
-      "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==",
-      "dev": true,
-      "requires": {
-        "ansi-wrap": "^0.1.0"
-      }
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+      "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
+      "dev": true
     },
     "ansi-escapes": {
       "version": "4.3.1",
@@ -1739,61 +1335,32 @@
         }
       }
     },
-    "ansi-gray": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz",
-      "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=",
-      "dev": true,
-      "requires": {
-        "ansi-wrap": "0.1.0"
-      }
-    },
     "ansi-regex": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
-      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
+      "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
       "dev": true
     },
     "ansi-styles": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
+      "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
       "dev": true,
       "requires": {
-        "color-convert": "^1.9.0"
+        "@types/color-name": "^1.1.1",
+        "color-convert": "^2.0.1"
       }
     },
-    "ansi-wrap": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz",
-      "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=",
-      "dev": true
-    },
     "anymatch": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
-      "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
-      "dev": true,
-      "requires": {
-        "micromatch": "^3.1.4",
-        "normalize-path": "^2.1.1"
-      }
-    },
-    "append-buffer": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz",
-      "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
+      "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
       "dev": true,
       "requires": {
-        "buffer-equal": "^1.0.0"
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
       }
     },
-    "archy": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
-      "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
-      "dev": true
-    },
     "arg": {
       "version": "4.1.3",
       "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
@@ -1815,138 +1382,24 @@
       "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
       "dev": true
     },
-    "arr-filter": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz",
-      "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=",
-      "dev": true,
-      "requires": {
-        "make-iterator": "^1.0.0"
-      }
-    },
     "arr-flatten": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
       "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
       "dev": true
     },
-    "arr-map": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz",
-      "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=",
-      "dev": true,
-      "requires": {
-        "make-iterator": "^1.0.0"
-      }
-    },
     "arr-union": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
       "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
       "dev": true
     },
-    "array-each": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
-      "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=",
-      "dev": true
-    },
-    "array-equal": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
-      "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
-      "dev": true
-    },
-    "array-find-index": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
-      "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=",
-      "dev": true
-    },
-    "array-ify": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz",
-      "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=",
-      "dev": true
-    },
-    "array-initial": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz",
-      "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=",
-      "dev": true,
-      "requires": {
-        "array-slice": "^1.0.0",
-        "is-number": "^4.0.0"
-      },
-      "dependencies": {
-        "is-number": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
-          "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
-          "dev": true
-        }
-      }
-    },
-    "array-last": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz",
-      "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==",
-      "dev": true,
-      "requires": {
-        "is-number": "^4.0.0"
-      },
-      "dependencies": {
-        "is-number": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
-          "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
-          "dev": true
-        }
-      }
-    },
-    "array-slice": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
-      "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==",
-      "dev": true
-    },
-    "array-sort": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz",
-      "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==",
-      "dev": true,
-      "requires": {
-        "default-compare": "^1.0.0",
-        "get-value": "^2.0.6",
-        "kind-of": "^5.0.2"
-      },
-      "dependencies": {
-        "kind-of": {
-          "version": "5.1.0",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
-          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
-          "dev": true
-        }
-      }
-    },
-    "array-union": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
-      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
-      "dev": true
-    },
     "array-unique": {
       "version": "0.3.2",
       "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
       "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
       "dev": true
     },
-    "arrify": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
-      "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
-      "dev": true
-    },
     "asn1": {
       "version": "0.2.4",
       "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
@@ -1968,45 +1421,12 @@
       "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
       "dev": true
     },
-    "ast-metadata-inferer": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/ast-metadata-inferer/-/ast-metadata-inferer-0.1.1.tgz",
-      "integrity": "sha512-hc9w8Qrgg9Lf9iFcZVhNjUnhrd2BBpTlyCnegPVvCe6O0yMrF57a6Cmh7k+xUsfUOMh9wajOL5AsGOBNEyTCcw==",
-      "dev": true
-    },
     "astral-regex": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
       "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
       "dev": true
     },
-    "async-done": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz",
-      "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==",
-      "dev": true,
-      "requires": {
-        "end-of-stream": "^1.1.0",
-        "once": "^1.3.2",
-        "process-nextick-args": "^2.0.0",
-        "stream-exhaust": "^1.0.1"
-      }
-    },
-    "async-each": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
-      "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
-      "dev": true
-    },
-    "async-settle": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz",
-      "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=",
-      "dev": true,
-      "requires": {
-        "async-done": "^1.2.2"
-      }
-    },
     "asynckit": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@@ -2014,9 +1434,9 @@
       "dev": true
     },
     "atob": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz",
-      "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=",
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
       "dev": true
     },
     "aws-sign2": {
@@ -2026,74 +1446,57 @@
       "dev": true
     },
     "aws4": {
-      "version": "1.9.1",
-      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz",
-      "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==",
+      "version": "1.10.1",
+      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz",
+      "integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==",
       "dev": true
     },
     "babel-jest": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-25.4.0.tgz",
-      "integrity": "sha512-p+epx4K0ypmHuCnd8BapfyOwWwosNCYhedetQey1awddtfmEX0MmdxctGl956uwUmjwXR5VSS5xJcGX9DvdIog==",
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.3.0.tgz",
+      "integrity": "sha512-sxPnQGEyHAOPF8NcUsD0g7hDCnvLL2XyblRBcgrzTWBB/mAIpWow3n1bEL+VghnnZfreLhFSBsFluRoK2tRK4g==",
       "dev": true,
       "requires": {
-        "@jest/transform": "^25.4.0",
-        "@jest/types": "^25.4.0",
+        "@jest/transform": "^26.3.0",
+        "@jest/types": "^26.3.0",
         "@types/babel__core": "^7.1.7",
         "babel-plugin-istanbul": "^6.0.0",
-        "babel-preset-jest": "^25.4.0",
-        "chalk": "^3.0.0",
+        "babel-preset-jest": "^26.3.0",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.4",
         "slash": "^3.0.0"
       },
       "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "chalk": {
+        "@types/istanbul-reports": {
           "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "color-name": "~1.1.4"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "has-flag": "^4.0.0"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
         }
       }
@@ -2112,23 +1515,27 @@
       }
     },
     "babel-plugin-jest-hoist": {
-      "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==",
+      "version": "26.2.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.2.0.tgz",
+      "integrity": "sha512-B/hVMRv8Nh1sQ1a3EY8I0n4Y1Wty3NrR5ebOyVT302op+DOAau+xNEImGMsUWOC3++ZlMooCytKz+NgN8aKGbA==",
       "dev": true,
       "requires": {
+        "@babel/template": "^7.3.3",
+        "@babel/types": "^7.3.3",
+        "@types/babel__core": "^7.0.0",
         "@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==",
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.3.tgz",
+      "integrity": "sha512-uyexu1sVwcdFnyq9o8UQYsXwXflIh8LvrF5+cKrYam93ned1CStffB3+BEcsxGSgagoA3GEyjDqO4a/58hyPYQ==",
       "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-import-meta": "^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",
@@ -2139,30 +1546,13 @@
       }
     },
     "babel-preset-jest": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-25.4.0.tgz",
-      "integrity": "sha512-PwFiEWflHdu3JCeTr0Pb9NcHHE34qWFnPQRVPvqQITx4CsDCzs6o05923I10XvLvn9nNsRHuiVgB72wG/90ZHQ==",
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.3.0.tgz",
+      "integrity": "sha512-5WPdf7nyYi2/eRxCbVrE1kKCWxgWY4RsPEbdJWFm7QsesFGqjdkyLeu1zRkwM1cxK6EPIlNd6d2AxLk7J+t4pw==",
       "dev": true,
       "requires": {
-        "babel-plugin-jest-hoist": "^25.4.0",
-        "babel-preset-current-node-syntax": "^0.1.2"
-      }
-    },
-    "bach": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz",
-      "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=",
-      "dev": true,
-      "requires": {
-        "arr-filter": "^1.1.1",
-        "arr-flatten": "^1.0.1",
-        "arr-map": "^2.0.0",
-        "array-each": "^1.0.0",
-        "array-initial": "^1.0.0",
-        "array-last": "^1.1.1",
-        "async-done": "^1.2.2",
-        "async-settle": "^1.0.0",
-        "now-and-later": "^2.0.0"
+        "babel-plugin-jest-hoist": "^26.2.0",
+        "babel-preset-current-node-syntax": "^0.1.3"
       }
     },
     "balanced-match": {
@@ -2235,18 +1625,6 @@
         "tweetnacl": "^0.14.3"
       }
     },
-    "binary-extensions": {
-      "version": "1.13.1",
-      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
-      "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
-      "dev": true
-    },
-    "binaryextensions": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.1.1.tgz",
-      "integrity": "sha512-XBaoWE9RW8pPdPQNibZsW2zh8TW6gcarXp1FZPwT8Uop8ScSNldJEWf2k9l3HeTqdrEwsOsFcq74RiJECW34yA==",
-      "dev": true
-    },
     "brace-expansion": {
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -2258,32 +1636,12 @@
       }
     },
     "braces": {
-      "version": "2.3.2",
-      "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
-      "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
       "dev": true,
       "requires": {
-        "arr-flatten": "^1.1.0",
-        "array-unique": "^0.3.2",
-        "extend-shallow": "^2.0.1",
-        "fill-range": "^4.0.0",
-        "isobject": "^3.0.1",
-        "repeat-element": "^1.1.2",
-        "snapdragon": "^0.8.1",
-        "snapdragon-node": "^2.0.1",
-        "split-string": "^3.0.2",
-        "to-regex": "^3.0.1"
-      },
-      "dependencies": {
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        }
+        "fill-range": "^7.0.1"
       }
     },
     "browser-process-hrtime": {
@@ -2292,35 +1650,6 @@
       "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==",
       "dev": true
     },
-    "browser-resolve": {
-      "version": "1.11.3",
-      "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz",
-      "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==",
-      "dev": true,
-      "requires": {
-        "resolve": "1.1.7"
-      },
-      "dependencies": {
-        "resolve": {
-          "version": "1.1.7",
-          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
-          "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=",
-          "dev": true
-        }
-      }
-    },
-    "browserslist": {
-      "version": "4.12.0",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.12.0.tgz",
-      "integrity": "sha512-UH2GkcEDSI0k/lRkuDSzFl9ZZ87skSy9w2XAn1MsZnL+4c4rqbBd3e82UWHbYDpztABrPBhZsTEeuxVfHppqDg==",
-      "dev": true,
-      "requires": {
-        "caniuse-lite": "^1.0.30001043",
-        "electron-to-chromium": "^1.3.413",
-        "node-releases": "^1.1.53",
-        "pkg-up": "^2.0.0"
-      }
-    },
     "bs-logger": {
       "version": "0.2.6",
       "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz",
@@ -2339,16 +1668,16 @@
         "node-int64": "^0.4.0"
       }
     },
-    "buffer-equal": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz",
-      "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=",
+    "buffer-from": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
       "dev": true
     },
-    "buffer-from": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz",
-      "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==",
+    "builtin-modules": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz",
+      "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==",
       "dev": true
     },
     "cache-base": {
@@ -2374,35 +1703,10 @@
       "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
       "dev": true
     },
-    "camelcase-keys": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-4.2.0.tgz",
-      "integrity": "sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=",
-      "dev": true,
-      "requires": {
-        "camelcase": "^4.1.0",
-        "map-obj": "^2.0.0",
-        "quick-lru": "^1.0.0"
-      },
-      "dependencies": {
-        "camelcase": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
-          "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
-          "dev": true
-        }
-      }
-    },
-    "caniuse-db": {
-      "version": "1.0.30001051",
-      "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30001051.tgz",
-      "integrity": "sha512-QSzF+LZ6ZHXsSIfIbs6HMPWrrjRMlt20xgGfb/rAnLDaqCH7iDBIbIWeyk8Hk7qdfmye/tpPFzfr0lV2LvzmCg==",
-      "dev": true
-    },
-    "caniuse-lite": {
-      "version": "1.0.30001051",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001051.tgz",
-      "integrity": "sha512-sw8UUnTlRevawTMZKN7vpfwSjCBVoiMPlYd8oT2VwNylyPCBdMAUmLGUApnYYTtIm5JXsQegUAY7GPHqgfDzjw==",
+    "camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
       "dev": true
     },
     "capture-exit": {
@@ -2421,59 +1725,21 @@
       "dev": true
     },
     "chalk": {
-      "version": "2.4.2",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
+      "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
       "dev": true,
       "requires": {
-        "ansi-styles": "^3.2.1",
-        "escape-string-regexp": "^1.0.5",
-        "supports-color": "^5.3.0"
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
       }
     },
-    "chardet": {
-      "version": "0.7.0",
-      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
-      "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+    "char-regex": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz",
+      "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==",
       "dev": true
     },
-    "chokidar": {
-      "version": "2.1.6",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.6.tgz",
-      "integrity": "sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==",
-      "dev": true,
-      "requires": {
-        "anymatch": "^2.0.0",
-        "async-each": "^1.0.1",
-        "braces": "^2.3.2",
-        "fsevents": "^1.2.7",
-        "glob-parent": "^3.1.0",
-        "inherits": "^2.0.3",
-        "is-binary-path": "^1.0.0",
-        "is-glob": "^4.0.0",
-        "normalize-path": "^3.0.0",
-        "path-is-absolute": "^1.0.0",
-        "readdirp": "^2.2.1",
-        "upath": "^1.1.1"
-      },
-      "dependencies": {
-        "is-glob": {
-          "version": "4.0.1",
-          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
-          "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
-          "dev": true,
-          "requires": {
-            "is-extglob": "^2.1.1"
-          }
-        },
-        "normalize-path": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
-          "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-          "dev": true
-        }
-      }
-    },
     "ci-info": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
@@ -2503,6 +1769,12 @@
         }
       }
     },
+    "clean-stack": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+      "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+      "dev": true
+    },
     "cli-cursor": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
@@ -2512,69 +1784,90 @@
         "restore-cursor": "^3.1.0"
       }
     },
-    "cli-width": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz",
-      "integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw==",
-      "dev": true
-    },
-    "clone": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
-      "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
-      "dev": true
-    },
-    "clone-buffer": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz",
-      "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=",
-      "dev": true
-    },
-    "clone-stats": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
-      "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=",
-      "dev": true
-    },
-    "cloneable-readable": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.2.tgz",
-      "integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==",
+    "cli-truncate": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
+      "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
       "dev": true,
       "requires": {
-        "inherits": "^2.0.1",
-        "process-nextick-args": "^2.0.0",
-        "readable-stream": "^2.3.5"
+        "slice-ansi": "^3.0.0",
+        "string-width": "^4.2.0"
       },
       "dependencies": {
-        "isarray": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+        "astral-regex": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+          "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+          "dev": true
+        },
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
           "dev": true
         },
-        "readable-stream": {
-          "version": "2.3.6",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+        "slice-ansi": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
+          "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.0.0",
+            "astral-regex": "^2.0.0",
+            "is-fullwidth-code-point": "^3.0.0"
+          }
+        },
+        "string-width": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+          "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
           "dev": true,
           "requires": {
-            "core-util-is": "~1.0.0",
-            "inherits": "~2.0.3",
-            "isarray": "~1.0.0",
-            "process-nextick-args": "~2.0.0",
-            "safe-buffer": "~5.1.1",
-            "string_decoder": "~1.1.1",
-            "util-deprecate": "~1.0.1"
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.0"
           }
+        }
+      }
+    },
+    "cliui": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
+      "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+      "dev": true,
+      "requires": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^6.2.0"
+      },
+      "dependencies": {
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+          "dev": true
         },
-        "string_decoder": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+        "string-width": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+          "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
           "dev": true,
           "requires": {
-            "safe-buffer": "~5.1.0"
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.0"
           }
         }
       }
@@ -2585,29 +1878,12 @@
       "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
       "dev": true
     },
-    "code-point-at": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
-      "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
-      "dev": true
-    },
     "collect-v8-coverage": {
       "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-map": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz",
-      "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=",
-      "dev": true,
-      "requires": {
-        "arr-map": "^2.0.2",
-        "for-own": "^1.0.0",
-        "make-iterator": "^1.0.0"
-      }
-    },
     "collection-visit": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
@@ -2619,24 +1895,18 @@
       }
     },
     "color-convert": {
-      "version": "1.9.2",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz",
-      "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
       "dev": true,
       "requires": {
-        "color-name": "1.1.1"
+        "color-name": "~1.1.4"
       }
     },
     "color-name": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz",
-      "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=",
-      "dev": true
-    },
-    "color-support": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
-      "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
       "dev": true
     },
     "combined-stream": {
@@ -2648,15 +1918,23 @@
         "delayed-stream": "~1.0.0"
       }
     },
-    "compare-func": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-1.3.2.tgz",
-      "integrity": "sha1-md0LpFfh+bxyKxLAjsM+6rMfpkg=",
-      "dev": true,
-      "requires": {
-        "array-ify": "^1.0.0",
-        "dot-prop": "^3.0.0"
-      }
+    "commander": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-6.1.0.tgz",
+      "integrity": "sha512-wl7PNrYWd2y5mp1OK/LhTlv8Ff4kQJQRXXAvF+uU/TPNiVJUxZLRYGj/B0y/lPGAVcSbJqH2Za/cvHmrPMC8mA==",
+      "dev": true
+    },
+    "commondir": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+      "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
+      "dev": true
+    },
+    "compare-versions": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz",
+      "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==",
+      "dev": true
     },
     "component-emitter": {
       "version": "1.3.0",
@@ -2670,673 +1948,780 @@
       "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
       "dev": true
     },
-    "concat-stream": {
-      "version": "1.6.2",
-      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
-      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
+    "convert-source-map": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
+      "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
       "dev": true,
       "requires": {
-        "buffer-from": "^1.0.0",
-        "inherits": "^2.0.3",
-        "readable-stream": "^2.2.2",
-        "typedarray": "^0.0.6"
-      },
-      "dependencies": {
-        "isarray": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
-          "dev": true
-        },
-        "readable-stream": {
-          "version": "2.3.6",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
-          "dev": true,
-          "requires": {
-            "core-util-is": "~1.0.0",
-            "inherits": "~2.0.3",
-            "isarray": "~1.0.0",
-            "process-nextick-args": "~2.0.0",
-            "safe-buffer": "~5.1.1",
-            "string_decoder": "~1.1.1",
-            "util-deprecate": "~1.0.1"
-          }
-        },
-        "string_decoder": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-          "dev": true,
-          "requires": {
-            "safe-buffer": "~5.1.0"
-          }
-        }
+        "safe-buffer": "~5.1.1"
       }
     },
-    "conventional-changelog": {
-      "version": "3.1.8",
-      "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-3.1.8.tgz",
-      "integrity": "sha512-fb3/DOLLrQdNqN0yYn/lT6HcNsAa9A+VTDBqlZBMQcEPPIeJIMI+DBs3yu+eiYOLi22w9oShq3nn/zN6qm1Hmw==",
+    "copy-descriptor": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
+      "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+      "dev": true
+    },
+    "core-util-is": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+      "dev": true
+    },
+    "cosmiconfig": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz",
+      "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==",
       "dev": true,
       "requires": {
-        "conventional-changelog-angular": "^5.0.3",
-        "conventional-changelog-atom": "^2.0.1",
-        "conventional-changelog-codemirror": "^2.0.1",
-        "conventional-changelog-conventionalcommits": "^3.0.2",
-        "conventional-changelog-core": "^3.2.2",
-        "conventional-changelog-ember": "^2.0.2",
-        "conventional-changelog-eslint": "^3.0.2",
-        "conventional-changelog-express": "^2.0.1",
-        "conventional-changelog-jquery": "^3.0.4",
-        "conventional-changelog-jshint": "^2.0.1",
-        "conventional-changelog-preset-loader": "^2.1.1"
+        "@types/parse-json": "^4.0.0",
+        "import-fresh": "^3.2.1",
+        "parse-json": "^5.0.0",
+        "path-type": "^4.0.0",
+        "yaml": "^1.10.0"
       }
     },
-    "conventional-changelog-angular": {
-      "version": "5.0.3",
-      "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-5.0.3.tgz",
-      "integrity": "sha512-YD1xzH7r9yXQte/HF9JBuEDfvjxxwDGGwZU1+ndanbY0oFgA+Po1T9JDSpPLdP0pZT6MhCAsdvFKC4TJ4MTJTA==",
+    "cross-spawn": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
       "dev": true,
       "requires": {
-        "compare-func": "^1.3.1",
-        "q": "^1.5.1"
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
       }
     },
-    "conventional-changelog-atom": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/conventional-changelog-atom/-/conventional-changelog-atom-2.0.1.tgz",
-      "integrity": "sha512-9BniJa4gLwL20Sm7HWSNXd0gd9c5qo49gCi8nylLFpqAHhkFTj7NQfROq3f1VpffRtzfTQp4VKU5nxbe2v+eZQ==",
+    "cssom": {
+      "version": "0.4.4",
+      "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz",
+      "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==",
+      "dev": true
+    },
+    "cssstyle": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz",
+      "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==",
       "dev": true,
       "requires": {
-        "q": "^1.5.1"
+        "cssom": "~0.3.6"
+      },
+      "dependencies": {
+        "cssom": {
+          "version": "0.3.8",
+          "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
+          "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==",
+          "dev": true
+        }
       }
     },
-    "conventional-changelog-cli": {
-      "version": "2.0.21",
-      "resolved": "https://registry.npmjs.org/conventional-changelog-cli/-/conventional-changelog-cli-2.0.21.tgz",
-      "integrity": "sha512-gMT1XvSVmo9Np1WUXz8Mvt3K+OtzR+Xu13z0jq/3qsXBbLuYc2/oaUXVr68r3fYOL8E9dN2uvX7Hc7RkeWvRVA==",
+    "dashdash": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+      "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
       "dev": true,
       "requires": {
-        "add-stream": "^1.0.0",
-        "conventional-changelog": "^3.1.8",
-        "lodash": "^4.2.1",
-        "meow": "^4.0.0",
-        "tempfile": "^1.1.1"
+        "assert-plus": "^1.0.0"
       }
     },
-    "conventional-changelog-codemirror": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.1.tgz",
-      "integrity": "sha512-23kT5IZWa+oNoUaDUzVXMYn60MCdOygTA2I+UjnOMiYVhZgmVwNd6ri/yDlmQGXHqbKhNR5NoXdBzSOSGxsgIQ==",
+    "data-urls": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
+      "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==",
       "dev": true,
       "requires": {
-        "q": "^1.5.1"
+        "abab": "^2.0.3",
+        "whatwg-mimetype": "^2.3.0",
+        "whatwg-url": "^8.0.0"
       }
     },
-    "conventional-changelog-conventionalcommits": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-3.0.2.tgz",
-      "integrity": "sha512-w1+fQSDnm/7+sPKIYC5nfRVYDszt+6HdWizrigSqWFVIiiBVzkHGeqDLMSHc+Qq9qssHVAxAak5206epZyK87A==",
+    "debug": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+      "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
       "dev": true,
       "requires": {
-        "compare-func": "^1.3.1",
-        "q": "^1.5.1"
+        "ms": "^2.1.1"
       }
     },
-    "conventional-changelog-core": {
-      "version": "3.2.2",
-      "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-3.2.2.tgz",
-      "integrity": "sha512-cssjAKajxaOX5LNAJLB+UOcoWjAIBvXtDMedv/58G+YEmAXMNfC16mmPl0JDOuVJVfIqM0nqQiZ8UCm8IXbE0g==",
+    "decamelize": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+      "dev": true
+    },
+    "decimal.js": {
+      "version": "10.2.0",
+      "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.0.tgz",
+      "integrity": "sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw==",
+      "dev": true
+    },
+    "decode-uri-component": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
+      "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+      "dev": true
+    },
+    "dedent": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
+      "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=",
+      "dev": true
+    },
+    "deep-is": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
+      "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+      "dev": true
+    },
+    "deepmerge": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
+      "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
+      "dev": true
+    },
+    "define-property": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
+      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
       "dev": true,
       "requires": {
-        "conventional-changelog-writer": "^4.0.5",
-        "conventional-commits-parser": "^3.0.2",
-        "dateformat": "^3.0.0",
-        "get-pkg-repo": "^1.0.0",
-        "git-raw-commits": "2.0.0",
-        "git-remote-origin-url": "^2.0.0",
-        "git-semver-tags": "^2.0.2",
-        "lodash": "^4.2.1",
-        "normalize-package-data": "^2.3.5",
-        "q": "^1.5.1",
-        "read-pkg": "^3.0.0",
-        "read-pkg-up": "^3.0.0",
-        "through2": "^3.0.0"
+        "is-descriptor": "^1.0.2",
+        "isobject": "^3.0.1"
       },
       "dependencies": {
-        "find-up": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
-          "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
-          "dev": true,
-          "requires": {
-            "locate-path": "^2.0.0"
-          }
-        },
-        "load-json-file": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
-          "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
-          "dev": true,
-          "requires": {
-            "graceful-fs": "^4.1.2",
-            "parse-json": "^4.0.0",
-            "pify": "^3.0.0",
-            "strip-bom": "^3.0.0"
-          }
-        },
-        "locate-path": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
-          "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
-          "dev": true,
-          "requires": {
-            "p-locate": "^2.0.0",
-            "path-exists": "^3.0.0"
-          }
-        },
-        "p-limit": {
-          "version": "1.3.0",
-          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
-          "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
-          "dev": true,
-          "requires": {
-            "p-try": "^1.0.0"
-          }
-        },
-        "p-locate": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
-          "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
-          "dev": true,
-          "requires": {
-            "p-limit": "^1.1.0"
-          }
-        },
-        "p-try": {
+        "is-accessor-descriptor": {
           "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
-          "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
-          "dev": true
-        },
-        "parse-json": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
-          "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
-          "dev": true,
-          "requires": {
-            "error-ex": "^1.3.1",
-            "json-parse-better-errors": "^1.0.1"
-          }
-        },
-        "path-exists": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
-          "dev": true
-        },
-        "path-type": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
-          "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
-          "dev": true,
-          "requires": {
-            "pify": "^3.0.0"
-          }
-        },
-        "read-pkg": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
-          "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
+          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
+          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
           "dev": true,
           "requires": {
-            "load-json-file": "^4.0.0",
-            "normalize-package-data": "^2.3.2",
-            "path-type": "^3.0.0"
+            "kind-of": "^6.0.0"
           }
         },
-        "read-pkg-up": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz",
-          "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=",
+        "is-data-descriptor": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
+          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
           "dev": true,
           "requires": {
-            "find-up": "^2.0.0",
-            "read-pkg": "^3.0.0"
+            "kind-of": "^6.0.0"
           }
         },
-        "strip-bom": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
-          "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
-          "dev": true
-        },
-        "through2": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz",
-          "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==",
+        "is-descriptor": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
+          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
           "dev": true,
           "requires": {
-            "readable-stream": "2 || 3"
+            "is-accessor-descriptor": "^1.0.0",
+            "is-data-descriptor": "^1.0.0",
+            "kind-of": "^6.0.2"
           }
         }
       }
     },
-    "conventional-changelog-ember": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/conventional-changelog-ember/-/conventional-changelog-ember-2.0.2.tgz",
-      "integrity": "sha512-qtZbA3XefO/n6DDmkYywDYi6wDKNNc98MMl2F9PKSaheJ25Trpi3336W8fDlBhq0X+EJRuseceAdKLEMmuX2tg==",
-      "dev": true,
-      "requires": {
-        "q": "^1.5.1"
-      }
+    "delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+      "dev": true
     },
-    "conventional-changelog-eslint": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.2.tgz",
-      "integrity": "sha512-Yi7tOnxjZLXlCYBHArbIAm8vZ68QUSygFS7PgumPRiEk+9NPUeucy5Wg9AAyKoBprSV3o6P7Oghh4IZSLtKCvQ==",
-      "dev": true,
-      "requires": {
-        "q": "^1.5.1"
-      }
+    "detect-newline": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
+      "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
+      "dev": true
     },
-    "conventional-changelog-express": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/conventional-changelog-express/-/conventional-changelog-express-2.0.1.tgz",
-      "integrity": "sha512-G6uCuCaQhLxdb4eEfAIHpcfcJ2+ao3hJkbLrw/jSK/eROeNfnxCJasaWdDAfFkxsbpzvQT4W01iSynU3OoPLIw==",
-      "dev": true,
-      "requires": {
-        "q": "^1.5.1"
-      }
+    "diff": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+      "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+      "dev": true
     },
-    "conventional-changelog-jquery": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.4.tgz",
-      "integrity": "sha512-IVJGI3MseYoY6eybknnTf9WzeQIKZv7aNTm2KQsiFVJH21bfP2q7XVjfoMibdCg95GmgeFlaygMdeoDDa+ZbEQ==",
+    "diff-sequences": {
+      "version": "25.2.6",
+      "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz",
+      "integrity": "sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==",
+      "dev": true
+    },
+    "doctrine": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
       "dev": true,
       "requires": {
-        "q": "^1.5.1"
+        "esutils": "^2.0.2"
       }
     },
-    "conventional-changelog-jshint": {
+    "domexception": {
       "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.1.tgz",
-      "integrity": "sha512-kRFJsCOZzPFm2tzRHULWP4tauGMvccOlXYf3zGeuSW4U0mZhk5NsjnRZ7xFWrTFPlCLV+PNmHMuXp5atdoZmEg==",
+      "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz",
+      "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==",
       "dev": true,
       "requires": {
-        "compare-func": "^1.3.1",
-        "q": "^1.5.1"
-      }
-    },
-    "conventional-changelog-preset-loader": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.1.1.tgz",
-      "integrity": "sha512-K4avzGMLm5Xw0Ek/6eE3vdOXkqnpf9ydb68XYmCc16cJ99XMMbc2oaNMuPwAsxVK6CC1yA4/I90EhmWNj0Q6HA==",
-      "dev": true
-    },
-    "conventional-changelog-writer": {
-      "version": "4.0.6",
-      "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-4.0.6.tgz",
-      "integrity": "sha512-ou/sbrplJMM6KQpR5rKFYNVQYesFjN7WpNGdudQSWNi6X+RgyFUcSv871YBYkrUYV9EX8ijMohYVzn9RUb+4ag==",
-      "dev": true,
-      "requires": {
-        "compare-func": "^1.3.1",
-        "conventional-commits-filter": "^2.0.2",
-        "dateformat": "^3.0.0",
-        "handlebars": "^4.1.0",
-        "json-stringify-safe": "^5.0.1",
-        "lodash": "^4.2.1",
-        "meow": "^4.0.0",
-        "semver": "^6.0.0",
-        "split": "^1.0.0",
-        "through2": "^3.0.0"
+        "webidl-conversions": "^5.0.0"
       },
       "dependencies": {
-        "commander": {
-          "version": "2.20.0",
-          "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
-          "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
-          "dev": true,
-          "optional": true
-        },
-        "handlebars": {
-          "version": "4.1.2",
-          "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz",
-          "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==",
-          "dev": true,
-          "requires": {
-            "neo-async": "^2.6.0",
-            "optimist": "^0.6.1",
-            "source-map": "^0.6.1",
-            "uglify-js": "^3.1.4"
-          }
-        },
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+        "webidl-conversions": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz",
+          "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==",
           "dev": true
-        },
-        "through2": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz",
-          "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==",
-          "dev": true,
-          "requires": {
-            "readable-stream": "2 || 3"
-          }
-        },
-        "uglify-js": {
-          "version": "3.6.0",
-          "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz",
-          "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "commander": "~2.20.0",
-            "source-map": "~0.6.1"
-          }
         }
       }
     },
-    "conventional-commits-filter": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-2.0.2.tgz",
-      "integrity": "sha512-WpGKsMeXfs21m1zIw4s9H5sys2+9JccTzpN6toXtxhpw2VNF2JUXwIakthKBy+LN4DvJm+TzWhxOMWOs1OFCFQ==",
-      "dev": true,
-      "requires": {
-        "lodash.ismatch": "^4.4.0",
-        "modify-values": "^1.0.0"
-      }
-    },
-    "conventional-commits-parser": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-3.0.3.tgz",
-      "integrity": "sha512-KaA/2EeUkO4bKjinNfGUyqPTX/6w9JGshuQRik4r/wJz7rUw3+D3fDG6sZSEqJvKILzKXFQuFkpPLclcsAuZcg==",
+    "ecc-jsbn": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+      "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
       "dev": true,
       "requires": {
-        "JSONStream": "^1.0.4",
-        "is-text-path": "^2.0.0",
-        "lodash": "^4.2.1",
-        "meow": "^4.0.0",
-        "split2": "^2.0.0",
-        "through2": "^3.0.0",
-        "trim-off-newlines": "^1.0.0"
-      },
-      "dependencies": {
-        "through2": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz",
-          "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==",
-          "dev": true,
-          "requires": {
-            "readable-stream": "2 || 3"
-          }
-        }
+        "jsbn": "~0.1.0",
+        "safer-buffer": "^2.1.0"
       }
     },
-    "convert-source-map": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
-      "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=",
+    "emittery": {
+      "version": "0.7.1",
+      "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.1.tgz",
+      "integrity": "sha512-d34LN4L6h18Bzz9xpoku2nPwKxCPlPMr3EEKTkoEBi+1/+b0lcRkRJ1UVyyZaKNeqGR3swcGl6s390DNO4YVgQ==",
       "dev": true
     },
-    "copy-descriptor": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
-      "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
+    "emoji-regex": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
+      "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
       "dev": true
     },
-    "copy-props": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz",
-      "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==",
+    "end-of-stream": {
+      "version": "1.4.4",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
       "dev": true,
       "requires": {
-        "each-props": "^1.3.0",
-        "is-plain-object": "^2.0.1"
+        "once": "^1.4.0"
       }
     },
-    "core-util-is": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
-      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
-      "dev": true
+    "enquirer": {
+      "version": "2.3.6",
+      "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
+      "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
+      "dev": true,
+      "requires": {
+        "ansi-colors": "^4.1.1"
+      }
     },
-    "cross-spawn": {
-      "version": "6.0.5",
-      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
-      "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+    "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": {
-        "nice-try": "^1.0.4",
-        "path-key": "^2.0.1",
-        "semver": "^5.5.0",
-        "shebang-command": "^1.2.0",
-        "which": "^1.2.9"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "5.5.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
-          "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==",
-          "dev": true
-        }
+        "is-arrayish": "^0.2.1"
       }
     },
-    "css": {
-      "version": "2.2.3",
-      "resolved": "https://registry.npmjs.org/css/-/css-2.2.3.tgz",
-      "integrity": "sha512-0W171WccAjQGGTKLhw4m2nnl0zPHUlTO/I8td4XzJgIB8Hg3ZZx71qT4G4eX8OVsSiaAKiUMy73E3nsbPlg2DQ==",
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+      "dev": true
+    },
+    "escodegen": {
+      "version": "1.14.3",
+      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
+      "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
       "dev": true,
       "requires": {
-        "inherits": "^2.0.1",
-        "source-map": "^0.1.38",
-        "source-map-resolve": "^0.5.1",
-        "urix": "^0.1.0"
+        "esprima": "^4.0.1",
+        "estraverse": "^4.2.0",
+        "esutils": "^2.0.2",
+        "optionator": "^0.8.1",
+        "source-map": "~0.6.1"
       },
       "dependencies": {
-        "source-map": {
-          "version": "0.1.43",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
-          "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=",
+        "levn": {
+          "version": "0.3.0",
+          "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
+          "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
+          "dev": true,
+          "requires": {
+            "prelude-ls": "~1.1.2",
+            "type-check": "~0.3.2"
+          }
+        },
+        "optionator": {
+          "version": "0.8.3",
+          "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
+          "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
+          "dev": true,
+          "requires": {
+            "deep-is": "~0.1.3",
+            "fast-levenshtein": "~2.0.6",
+            "levn": "~0.3.0",
+            "prelude-ls": "~1.1.2",
+            "type-check": "~0.3.2",
+            "word-wrap": "~1.2.3"
+          }
+        },
+        "prelude-ls": {
+          "version": "1.1.2",
+          "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
+          "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+          "dev": true
+        },
+        "type-check": {
+          "version": "0.3.2",
+          "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
+          "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
           "dev": true,
           "requires": {
-            "amdefine": ">=0.0.4"
+            "prelude-ls": "~1.1.2"
           }
         }
       }
     },
-    "cssom": {
-      "version": "0.4.4",
-      "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz",
-      "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==",
-      "dev": true
-    },
-    "cssstyle": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.2.0.tgz",
-      "integrity": "sha512-sEb3XFPx3jNnCAMtqrXPDeSgQr+jojtCeNf8cvMNMh1cG970+lljssvQDzPq6lmmJu2Vhqood/gtEomBiHOGnA==",
+    "eslint": {
+      "version": "7.8.1",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.8.1.tgz",
+      "integrity": "sha512-/2rX2pfhyUG0y+A123d0ccXtMm7DV7sH1m3lk9nk2DZ2LReq39FXHueR9xZwshE5MdfSf0xunSaMWRqyIA6M1w==",
       "dev": true,
       "requires": {
-        "cssom": "~0.3.6"
+        "@babel/code-frame": "^7.0.0",
+        "@eslint/eslintrc": "^0.1.3",
+        "ajv": "^6.10.0",
+        "chalk": "^4.0.0",
+        "cross-spawn": "^7.0.2",
+        "debug": "^4.0.1",
+        "doctrine": "^3.0.0",
+        "enquirer": "^2.3.5",
+        "eslint-scope": "^5.1.0",
+        "eslint-utils": "^2.1.0",
+        "eslint-visitor-keys": "^1.3.0",
+        "espree": "^7.3.0",
+        "esquery": "^1.2.0",
+        "esutils": "^2.0.2",
+        "file-entry-cache": "^5.0.1",
+        "functional-red-black-tree": "^1.0.1",
+        "glob-parent": "^5.0.0",
+        "globals": "^12.1.0",
+        "ignore": "^4.0.6",
+        "import-fresh": "^3.0.0",
+        "imurmurhash": "^0.1.4",
+        "is-glob": "^4.0.0",
+        "js-yaml": "^3.13.1",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "levn": "^0.4.1",
+        "lodash": "^4.17.19",
+        "minimatch": "^3.0.4",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.9.1",
+        "progress": "^2.0.0",
+        "regexpp": "^3.1.0",
+        "semver": "^7.2.1",
+        "strip-ansi": "^6.0.0",
+        "strip-json-comments": "^3.1.0",
+        "table": "^5.2.3",
+        "text-table": "^0.2.0",
+        "v8-compile-cache": "^2.0.3"
       },
       "dependencies": {
-        "cssom": {
-          "version": "0.3.8",
-          "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz",
-          "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==",
-          "dev": true
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
         }
       }
     },
-    "currently-unhandled": {
-      "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
-      "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
+    "eslint-config-prettier": {
+      "version": "6.11.0",
+      "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz",
+      "integrity": "sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA==",
       "dev": true,
       "requires": {
-        "array-find-index": "^1.0.1"
+        "get-stdin": "^6.0.0"
       }
     },
-    "d": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
-      "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
+    "eslint-plugin-jest": {
+      "version": "23.20.0",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-23.20.0.tgz",
+      "integrity": "sha512-+6BGQt85OREevBDWCvhqj1yYA4+BFK4XnRZSGJionuEYmcglMZYLNNBBemwzbqUAckURaHdJSBcjHPyrtypZOw==",
       "dev": true,
       "requires": {
-        "es5-ext": "^0.10.9"
+        "@typescript-eslint/experimental-utils": "^2.5.0"
+      },
+      "dependencies": {
+        "@typescript-eslint/experimental-utils": {
+          "version": "2.34.0",
+          "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz",
+          "integrity": "sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==",
+          "dev": true,
+          "requires": {
+            "@types/json-schema": "^7.0.3",
+            "@typescript-eslint/typescript-estree": "2.34.0",
+            "eslint-scope": "^5.0.0",
+            "eslint-utils": "^2.0.0"
+          }
+        },
+        "@typescript-eslint/typescript-estree": {
+          "version": "2.34.0",
+          "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz",
+          "integrity": "sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==",
+          "dev": true,
+          "requires": {
+            "debug": "^4.1.1",
+            "eslint-visitor-keys": "^1.1.0",
+            "glob": "^7.1.6",
+            "is-glob": "^4.0.1",
+            "lodash": "^4.17.15",
+            "semver": "^7.3.2",
+            "tsutils": "^3.17.1"
+          }
+        }
       }
     },
-    "dashdash": {
-      "version": "1.14.1",
-      "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
-      "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+    "eslint-scope": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.0.tgz",
+      "integrity": "sha512-iiGRvtxWqgtx5m8EyQUJihBloE4EnYeGE/bz1wSPwJE6tZuJUtHlhqDM4Xj2ukE8Dyy1+HCZ4hE0fzIVMzb58w==",
       "dev": true,
       "requires": {
-        "assert-plus": "^1.0.0"
+        "esrecurse": "^4.1.0",
+        "estraverse": "^4.1.1"
       }
     },
-    "data-urls": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz",
-      "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==",
+    "eslint-utils": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
+      "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
       "dev": true,
       "requires": {
-        "abab": "^2.0.0",
-        "whatwg-mimetype": "^2.2.0",
-        "whatwg-url": "^7.0.0"
+        "eslint-visitor-keys": "^1.1.0"
       }
     },
-    "dateformat": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
-      "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==",
+    "eslint-visitor-keys": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+      "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
       "dev": true
     },
-    "debug": {
-      "version": "2.6.9",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-      "dev": true,
-      "requires": {
-        "ms": "2.0.0"
-      }
-    },
-    "debug-fabulous": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-1.1.0.tgz",
-      "integrity": "sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==",
+    "espree": {
+      "version": "7.3.0",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz",
+      "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==",
       "dev": true,
       "requires": {
-        "debug": "3.X",
-        "memoizee": "0.4.X",
-        "object-assign": "4.X"
+        "acorn": "^7.4.0",
+        "acorn-jsx": "^5.2.0",
+        "eslint-visitor-keys": "^1.3.0"
       },
       "dependencies": {
-        "debug": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
-          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
-          "dev": true,
-          "requires": {
-            "ms": "2.0.0"
-          }
+        "acorn": {
+          "version": "7.4.0",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.0.tgz",
+          "integrity": "sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==",
+          "dev": true
         }
       }
     },
-    "decamelize": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
-      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
+    "esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
       "dev": true
     },
-    "decamelize-keys": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz",
-      "integrity": "sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=",
+    "esquery": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz",
+      "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==",
       "dev": true,
       "requires": {
-        "decamelize": "^1.1.0",
-        "map-obj": "^1.0.0"
+        "estraverse": "^5.1.0"
       },
       "dependencies": {
-        "map-obj": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
-          "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
+        "estraverse": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
+          "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
           "dev": true
         }
       }
     },
-    "decode-uri-component": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
-      "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
+    "esrecurse": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
+      "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
+      "dev": true,
+      "requires": {
+        "estraverse": "^4.1.0"
+      }
+    },
+    "estraverse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
       "dev": true
     },
-    "deep-is": {
-      "version": "0.1.3",
-      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
-      "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
+    "estree-walker": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
+      "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
       "dev": true
     },
-    "deepmerge": {
-      "version": "4.2.2",
-      "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
-      "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
+    "esutils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
       "dev": true
     },
-    "default-compare": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz",
-      "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==",
+    "exec-sh": {
+      "version": "0.3.4",
+      "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz",
+      "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==",
+      "dev": true
+    },
+    "execa": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
+      "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
       "dev": true,
       "requires": {
-        "kind-of": "^5.0.2"
+        "cross-spawn": "^6.0.0",
+        "get-stream": "^4.0.0",
+        "is-stream": "^1.1.0",
+        "npm-run-path": "^2.0.0",
+        "p-finally": "^1.0.0",
+        "signal-exit": "^3.0.0",
+        "strip-eof": "^1.0.0"
       },
       "dependencies": {
-        "kind-of": {
-          "version": "5.1.0",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
-          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
+        "cross-spawn": {
+          "version": "6.0.5",
+          "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
+          "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+          "dev": true,
+          "requires": {
+            "nice-try": "^1.0.4",
+            "path-key": "^2.0.1",
+            "semver": "^5.5.0",
+            "shebang-command": "^1.2.0",
+            "which": "^1.2.9"
+          }
+        },
+        "path-key": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+          "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+          "dev": true
+        },
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+          "dev": true
+        },
+        "shebang-command": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+          "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+          "dev": true,
+          "requires": {
+            "shebang-regex": "^1.0.0"
+          }
+        },
+        "shebang-regex": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+          "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
           "dev": true
+        },
+        "which": {
+          "version": "1.3.1",
+          "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+          "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+          "dev": true,
+          "requires": {
+            "isexe": "^2.0.0"
+          }
         }
       }
     },
-    "default-resolution": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz",
-      "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=",
+    "exit": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+      "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
       "dev": true
     },
-    "define-properties": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz",
-      "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=",
+    "expand-brackets": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
+      "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
+      "dev": true,
+      "requires": {
+        "debug": "^2.3.3",
+        "define-property": "^0.2.5",
+        "extend-shallow": "^2.0.1",
+        "posix-character-classes": "^0.1.0",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "define-property": {
+          "version": "0.2.5",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
+          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^0.1.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        }
+      }
+    },
+    "expect": {
+      "version": "26.4.2",
+      "resolved": "https://registry.npmjs.org/expect/-/expect-26.4.2.tgz",
+      "integrity": "sha512-IlJ3X52Z0lDHm7gjEp+m76uX46ldH5VpqmU0006vqDju/285twh7zaWMRhs67VpQhBwjjMchk+p5aA0VkERCAA==",
       "dev": true,
       "requires": {
-        "foreach": "^2.0.5",
-        "object-keys": "^1.0.8"
+        "@jest/types": "^26.3.0",
+        "ansi-styles": "^4.0.0",
+        "jest-get-type": "^26.3.0",
+        "jest-matcher-utils": "^26.4.2",
+        "jest-message-util": "^26.3.0",
+        "jest-regex-util": "^26.0.0"
+      },
+      "dependencies": {
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
+          "dev": true,
+          "requires": {
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
+          }
+        },
+        "@types/istanbul-reports": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
+          "dev": true,
+          "requires": {
+            "@types/istanbul-lib-report": "*"
+          }
+        },
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "jest-get-type": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz",
+          "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==",
+          "dev": true
+        }
       }
     },
-    "define-property": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
-      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
+    "extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+      "dev": true
+    },
+    "extend-shallow": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+      "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
       "dev": true,
       "requires": {
-        "is-descriptor": "^1.0.2",
-        "isobject": "^3.0.1"
+        "assign-symbols": "^1.0.0",
+        "is-extendable": "^1.0.1"
+      },
+      "dependencies": {
+        "is-extendable": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+          "dev": true,
+          "requires": {
+            "is-plain-object": "^2.0.4"
+          }
+        }
+      }
+    },
+    "extglob": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
+      "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
+      "dev": true,
+      "requires": {
+        "array-unique": "^0.3.2",
+        "define-property": "^1.0.0",
+        "expand-brackets": "^2.1.4",
+        "extend-shallow": "^2.0.1",
+        "fragment-cache": "^0.2.1",
+        "regex-not": "^1.0.0",
+        "snapdragon": "^0.8.1",
+        "to-regex": "^3.0.1"
       },
       "dependencies": {
+        "define-property": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
+          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
+          "dev": true,
+          "requires": {
+            "is-descriptor": "^1.0.0"
+          }
+        },
+        "extend-shallow": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+          "dev": true,
+          "requires": {
+            "is-extendable": "^0.1.0"
+          }
+        },
         "is-accessor-descriptor": {
           "version": "1.0.0",
           "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
@@ -3368,2556 +2753,263 @@
         }
       }
     },
-    "del": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/del/-/del-5.0.0.tgz",
-      "integrity": "sha512-TfU3nUY0WDIhN18eq+pgpbLY9AfL5RfiE9czKaTSolc6aK7qASXfDErvYgjV1UqCR4sNXDoxO0/idPmhDUt2Sg==",
-      "dev": true,
-      "requires": {
-        "globby": "^10.0.0",
-        "is-path-cwd": "^2.0.0",
-        "is-path-in-cwd": "^2.0.0",
-        "p-map": "^2.0.0",
-        "rimraf": "^2.6.3"
-      }
-    },
-    "delayed-stream": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
-      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+    "extsprintf": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+      "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
       "dev": true
     },
-    "detect-file": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
-      "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=",
+    "fast-deep-equal": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
       "dev": true
     },
-    "detect-newline": {
+    "fast-json-stable-stringify": {
       "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz",
-      "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
       "dev": true
     },
-    "diff-sequences": {
-      "version": "25.2.6",
-      "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz",
-      "integrity": "sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==",
+    "fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
       "dev": true
     },
-    "dir-glob": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
-      "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+    "fb-watchman": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz",
+      "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==",
       "dev": true,
       "requires": {
-        "path-type": "^4.0.0"
-      },
-      "dependencies": {
-        "path-type": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
-          "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
-          "dev": true
-        }
+        "bser": "2.1.1"
       }
     },
-    "doctrine": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
-      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+    "figures": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+      "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
       "dev": true,
       "requires": {
-        "esutils": "^2.0.2"
+        "escape-string-regexp": "^1.0.5"
       }
     },
-    "domexception": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
-      "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==",
+    "file-entry-cache": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
+      "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==",
       "dev": true,
       "requires": {
-        "webidl-conversions": "^4.0.2"
+        "flat-cache": "^2.0.1"
       }
     },
-    "dot-prop": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz",
-      "integrity": "sha1-G3CK8JSknJoOfbyteQq6U52sEXc=",
+    "fill-range": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
       "dev": true,
       "requires": {
-        "is-obj": "^1.0.0"
+        "to-regex-range": "^5.0.1"
       }
     },
-    "duplexify": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz",
-      "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==",
+    "find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
       "dev": true,
       "requires": {
-        "end-of-stream": "^1.0.0",
-        "inherits": "^2.0.1",
-        "readable-stream": "^2.0.0",
-        "stream-shift": "^1.0.0"
-      },
-      "dependencies": {
-        "end-of-stream": {
-          "version": "1.4.1",
-          "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
-          "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
-          "dev": true,
-          "requires": {
-            "once": "^1.4.0"
-          }
-        },
-        "isarray": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
-          "dev": true
-        },
-        "readable-stream": {
-          "version": "2.3.6",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
-          "dev": true,
-          "requires": {
-            "core-util-is": "~1.0.0",
-            "inherits": "~2.0.3",
-            "isarray": "~1.0.0",
-            "process-nextick-args": "~2.0.0",
-            "safe-buffer": "~5.1.1",
-            "string_decoder": "~1.1.1",
-            "util-deprecate": "~1.0.1"
-          }
-        },
-        "string_decoder": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-          "dev": true,
-          "requires": {
-            "safe-buffer": "~5.1.0"
-          }
-        }
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
       }
     },
-    "each-props": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz",
-      "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==",
+    "find-versions": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz",
+      "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==",
       "dev": true,
       "requires": {
-        "is-plain-object": "^2.0.1",
-        "object.defaults": "^1.1.0"
+        "semver-regex": "^2.0.0"
       }
     },
-    "ecc-jsbn": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
-      "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+    "flat-cache": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
+      "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==",
       "dev": true,
       "requires": {
-        "jsbn": "~0.1.0",
-        "safer-buffer": "^2.1.0"
+        "flatted": "^2.0.0",
+        "rimraf": "2.6.3",
+        "write": "1.0.3"
+      },
+      "dependencies": {
+        "rimraf": {
+          "version": "2.6.3",
+          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+          "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+          "dev": true,
+          "requires": {
+            "glob": "^7.1.3"
+          }
+        }
       }
     },
-    "editions": {
-      "version": "1.3.4",
-      "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz",
-      "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==",
+    "flatted": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
+      "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==",
       "dev": true
     },
-    "electron-to-chromium": {
-      "version": "1.3.428",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.428.tgz",
-      "integrity": "sha512-u3+5jEfgLKq/hGO96YfAoOAM1tgFnRDTCD5mLuev44tttcXix+INtVegAkmGzUcfDsnzkPt51XXurXZLLwXt0w==",
+    "for-in": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+      "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
       "dev": true
     },
-    "emoji-regex": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+    "forever-agent": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+      "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
       "dev": true
     },
-    "end-of-stream": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
-      "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
+    "form-data": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+      "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
       "dev": true,
       "requires": {
-        "once": "^1.4.0"
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.6",
+        "mime-types": "^2.1.12"
       }
     },
-    "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==",
+    "fragment-cache": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
+      "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
       "dev": true,
       "requires": {
-        "is-arrayish": "^0.2.1"
+        "map-cache": "^0.2.2"
       }
     },
-    "es5-ext": {
-      "version": "0.10.45",
-      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.45.tgz",
-      "integrity": "sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ==",
-      "dev": true,
-      "requires": {
-        "es6-iterator": "~2.0.3",
-        "es6-symbol": "~3.1.1",
-        "next-tick": "1"
-      }
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+      "dev": true
     },
-    "es6-iterator": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
-      "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
+    "fsevents": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
+      "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
       "dev": true,
-      "requires": {
-        "d": "1",
-        "es5-ext": "^0.10.35",
-        "es6-symbol": "^3.1.1"
-      }
+      "optional": true
     },
-    "es6-shim": {
-      "version": "0.35.3",
-      "resolved": "https://registry.npmjs.org/es6-shim/-/es6-shim-0.35.3.tgz",
-      "integrity": "sha1-m/tzY/7//4emzbbNk+QF7DxLbyY=",
+    "functional-red-black-tree": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+      "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
       "dev": true
     },
-    "es6-symbol": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
-      "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
-      "dev": true,
-      "requires": {
-        "d": "1",
-        "es5-ext": "~0.10.14"
-      }
+    "gensync": {
+      "version": "1.0.0-beta.1",
+      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz",
+      "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==",
+      "dev": true
     },
-    "es6-weak-map": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz",
-      "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",
-      "dev": true,
-      "requires": {
-        "d": "1",
-        "es5-ext": "^0.10.14",
-        "es6-iterator": "^2.0.1",
-        "es6-symbol": "^3.1.1"
-      }
+    "get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "dev": true
     },
-    "escape-string-regexp": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+    "get-own-enumerable-property-symbols": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz",
+      "integrity": "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==",
       "dev": true
     },
-    "eslint": {
-      "version": "6.8.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz",
-      "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==",
-      "dev": true,
-      "requires": {
-        "@babel/code-frame": "^7.0.0",
-        "ajv": "^6.10.0",
-        "chalk": "^2.1.0",
-        "cross-spawn": "^6.0.5",
-        "debug": "^4.0.1",
-        "doctrine": "^3.0.0",
-        "eslint-scope": "^5.0.0",
-        "eslint-utils": "^1.4.3",
-        "eslint-visitor-keys": "^1.1.0",
-        "espree": "^6.1.2",
-        "esquery": "^1.0.1",
-        "esutils": "^2.0.2",
-        "file-entry-cache": "^5.0.1",
-        "functional-red-black-tree": "^1.0.1",
-        "glob-parent": "^5.0.0",
-        "globals": "^12.1.0",
-        "ignore": "^4.0.6",
-        "import-fresh": "^3.0.0",
-        "imurmurhash": "^0.1.4",
-        "inquirer": "^7.0.0",
-        "is-glob": "^4.0.0",
-        "js-yaml": "^3.13.1",
-        "json-stable-stringify-without-jsonify": "^1.0.1",
-        "levn": "^0.3.0",
-        "lodash": "^4.17.14",
-        "minimatch": "^3.0.4",
-        "mkdirp": "^0.5.1",
-        "natural-compare": "^1.4.0",
-        "optionator": "^0.8.3",
-        "progress": "^2.0.0",
-        "regexpp": "^2.0.1",
-        "semver": "^6.1.2",
-        "strip-ansi": "^5.2.0",
-        "strip-json-comments": "^3.0.1",
-        "table": "^5.2.3",
-        "text-table": "^0.2.0",
-        "v8-compile-cache": "^2.0.3"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
-          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
-          "dev": true
-        },
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "eslint-utils": {
-          "version": "1.4.3",
-          "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz",
-          "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==",
-          "dev": true,
-          "requires": {
-            "eslint-visitor-keys": "^1.1.0"
-          }
-        },
-        "glob-parent": {
-          "version": "5.1.1",
-          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
-          "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
-          "dev": true,
-          "requires": {
-            "is-glob": "^4.0.1"
-          }
-        },
-        "globals": {
-          "version": "12.4.0",
-          "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
-          "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
-          "dev": true,
-          "requires": {
-            "type-fest": "^0.8.1"
-          }
-        },
-        "ignore": {
-          "version": "4.0.6",
-          "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
-          "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
-          "dev": true
-        },
-        "is-glob": {
-          "version": "4.0.1",
-          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
-          "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
-          "dev": true,
-          "requires": {
-            "is-extglob": "^2.1.1"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        },
-        "optionator": {
-          "version": "0.8.3",
-          "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
-          "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
-          "dev": true,
-          "requires": {
-            "deep-is": "~0.1.3",
-            "fast-levenshtein": "~2.0.6",
-            "levn": "~0.3.0",
-            "prelude-ls": "~1.1.2",
-            "type-check": "~0.3.2",
-            "word-wrap": "~1.2.3"
-          }
-        },
-        "regexpp": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz",
-          "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==",
-          "dev": true
-        },
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        },
-        "strip-ansi": {
-          "version": "5.2.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^4.1.0"
-          }
-        }
-      }
+    "get-package-type": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
+      "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
+      "dev": true
     },
-    "eslint-plugin-compat": {
-      "version": "3.5.1",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-3.5.1.tgz",
-      "integrity": "sha512-dhfW12vZxxKLEVhrPoblmEopgwpYU2Sd4GdXj5OSfbQ+as9+1aY+S5pqnJYJvXXNWFFJ6aspLkCyk4NMQ/pgtA==",
-      "dev": true,
-      "requires": {
-        "@babel/runtime": "^7.7.7",
-        "ast-metadata-inferer": "^0.1.1",
-        "browserslist": "^4.8.2",
-        "caniuse-db": "^1.0.30001017",
-        "lodash.memoize": "4.1.2",
-        "mdn-browser-compat-data": "^1.0.3",
-        "semver": "^6.3.0"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        }
-      }
+    "get-stdin": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
+      "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==",
+      "dev": true
     },
-    "eslint-plugin-jest": {
-      "version": "23.8.2",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-23.8.2.tgz",
-      "integrity": "sha512-xwbnvOsotSV27MtAe7s8uGWOori0nUsrXh2f1EnpmXua8sDfY6VZhHAhHg2sqK7HBNycRQExF074XSZ7DvfoFg==",
+    "get-stream": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
+      "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
       "dev": true,
       "requires": {
-        "@typescript-eslint/experimental-utils": "^2.5.0"
+        "pump": "^3.0.0"
       }
     },
-    "eslint-scope": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz",
-      "integrity": "sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==",
-      "dev": true,
-      "requires": {
-        "esrecurse": "^4.1.0",
-        "estraverse": "^4.1.1"
-      }
+    "get-value": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+      "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+      "dev": true
     },
-    "eslint-utils": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.0.0.tgz",
-      "integrity": "sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==",
+    "getpass": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+      "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
       "dev": true,
       "requires": {
-        "eslint-visitor-keys": "^1.1.0"
+        "assert-plus": "^1.0.0"
       }
     },
-    "eslint-visitor-keys": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz",
-      "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==",
-      "dev": true
-    },
-    "espree": {
-      "version": "6.2.1",
-      "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz",
-      "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==",
+    "glob": {
+      "version": "7.1.6",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+      "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
       "dev": true,
       "requires": {
-        "acorn": "^7.1.1",
-        "acorn-jsx": "^5.2.0",
-        "eslint-visitor-keys": "^1.1.0"
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
       }
     },
-    "esprima": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
-      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
-      "dev": true
-    },
-    "esquery": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz",
-      "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==",
-      "dev": true,
-      "requires": {
-        "estraverse": "^5.1.0"
-      },
-      "dependencies": {
-        "estraverse": {
-          "version": "5.1.0",
-          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.1.0.tgz",
-          "integrity": "sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw==",
-          "dev": true
-        }
-      }
-    },
-    "esrecurse": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
-      "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
-      "dev": true,
-      "requires": {
-        "estraverse": "^4.1.0"
-      }
-    },
-    "estraverse": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
-      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
-      "dev": true
-    },
-    "estree-walker": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
-      "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
-      "dev": true
-    },
-    "esutils": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
-      "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
-      "dev": true
-    },
-    "event-emitter": {
-      "version": "0.3.5",
-      "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
-      "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
-      "dev": true,
-      "requires": {
-        "d": "1",
-        "es5-ext": "~0.10.14"
-      }
-    },
-    "exec-sh": {
-      "version": "0.3.4",
-      "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz",
-      "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==",
-      "dev": true
-    },
-    "exit": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
-      "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
-      "dev": true
-    },
-    "expand-brackets": {
-      "version": "2.1.4",
-      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
-      "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
-      "dev": true,
-      "requires": {
-        "debug": "^2.3.3",
-        "define-property": "^0.2.5",
-        "extend-shallow": "^2.0.1",
-        "posix-character-classes": "^0.1.0",
-        "regex-not": "^1.0.0",
-        "snapdragon": "^0.8.1",
-        "to-regex": "^3.0.1"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "0.2.5",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^0.1.0"
-          }
-        },
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        }
-      }
-    },
-    "expand-tilde": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
-      "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=",
-      "dev": true,
-      "requires": {
-        "homedir-polyfill": "^1.0.1"
-      }
-    },
-    "expect": {
-      "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.4.0",
-        "ansi-styles": "^4.0.0",
-        "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": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
-          "dev": true,
-          "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-          "dev": true,
-          "requires": {
-            "color-name": "~1.1.4"
-          }
-        },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        }
-      }
-    },
-    "extend": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
-      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
-      "dev": true
-    },
-    "extend-shallow": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
-      "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
-      "dev": true,
-      "requires": {
-        "assign-symbols": "^1.0.0",
-        "is-extendable": "^1.0.1"
-      },
-      "dependencies": {
-        "is-extendable": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
-          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
-          "dev": true,
-          "requires": {
-            "is-plain-object": "^2.0.4"
-          }
-        }
-      }
-    },
-    "external-editor": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
-      "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
-      "dev": true,
-      "requires": {
-        "chardet": "^0.7.0",
-        "iconv-lite": "^0.4.24",
-        "tmp": "^0.0.33"
-      }
-    },
-    "extglob": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
-      "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
-      "dev": true,
-      "requires": {
-        "array-unique": "^0.3.2",
-        "define-property": "^1.0.0",
-        "expand-brackets": "^2.1.4",
-        "extend-shallow": "^2.0.1",
-        "fragment-cache": "^0.2.1",
-        "regex-not": "^1.0.0",
-        "snapdragon": "^0.8.1",
-        "to-regex": "^3.0.1"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
-          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^1.0.0"
-          }
-        },
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        },
-        "is-accessor-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-data-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-descriptor": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
-          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
-          "dev": true,
-          "requires": {
-            "is-accessor-descriptor": "^1.0.0",
-            "is-data-descriptor": "^1.0.0",
-            "kind-of": "^6.0.2"
-          }
-        }
-      }
-    },
-    "extsprintf": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
-      "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
-      "dev": true
-    },
-    "fancy-log": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.2.tgz",
-      "integrity": "sha1-9BEl49hPLn2JpD0G2VjI94vha+E=",
-      "dev": true,
-      "requires": {
-        "ansi-gray": "^0.1.1",
-        "color-support": "^1.1.3",
-        "time-stamp": "^1.0.0"
-      }
-    },
-    "fast-deep-equal": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
-      "integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA==",
-      "dev": true
-    },
-    "fast-glob": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.0.4.tgz",
-      "integrity": "sha512-wkIbV6qg37xTJwqSsdnIphL1e+LaGz4AIQqr00mIubMaEhv1/HEmJ0uuCGZRNRUkZZmOB5mJKO0ZUTVq+SxMQg==",
-      "dev": true,
-      "requires": {
-        "@nodelib/fs.stat": "^2.0.1",
-        "@nodelib/fs.walk": "^1.2.1",
-        "glob-parent": "^5.0.0",
-        "is-glob": "^4.0.1",
-        "merge2": "^1.2.3",
-        "micromatch": "^4.0.2"
-      },
-      "dependencies": {
-        "braces": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-          "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
-          "dev": true,
-          "requires": {
-            "fill-range": "^7.0.1"
-          }
-        },
-        "fill-range": {
-          "version": "7.0.1",
-          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-          "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
-          "dev": true,
-          "requires": {
-            "to-regex-range": "^5.0.1"
-          }
-        },
-        "glob-parent": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.0.0.tgz",
-          "integrity": "sha512-Z2RwiujPRGluePM6j699ktJYxmPpJKCfpGA13jz2hmFZC7gKetzrWvg5KN3+OsIFmydGyZ1AVwERCq1w/ZZwRg==",
-          "dev": true,
-          "requires": {
-            "is-glob": "^4.0.1"
-          }
-        },
-        "is-glob": {
-          "version": "4.0.1",
-          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
-          "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
-          "dev": true,
-          "requires": {
-            "is-extglob": "^2.1.1"
-          }
-        },
-        "is-number": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-          "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-          "dev": true
-        },
-        "micromatch": {
-          "version": "4.0.2",
-          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
-          "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
-          "dev": true,
-          "requires": {
-            "braces": "^3.0.1",
-            "picomatch": "^2.0.5"
-          }
-        },
-        "to-regex-range": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-          "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-          "dev": true,
-          "requires": {
-            "is-number": "^7.0.0"
-          }
-        }
-      }
-    },
-    "fast-json-stable-stringify": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
-      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
-      "dev": true
-    },
-    "fast-levenshtein": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
-      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
-      "dev": true
-    },
-    "fastq": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz",
-      "integrity": "sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==",
-      "dev": true,
-      "requires": {
-        "reusify": "^1.0.0"
-      }
-    },
-    "fb-watchman": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz",
-      "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==",
-      "dev": true,
-      "requires": {
-        "bser": "2.1.1"
-      }
-    },
-    "figures": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
-      "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
-      "dev": true,
-      "requires": {
-        "escape-string-regexp": "^1.0.5"
-      }
-    },
-    "file-entry-cache": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz",
-      "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==",
-      "dev": true,
-      "requires": {
-        "flat-cache": "^2.0.1"
-      }
-    },
-    "fill-range": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
-      "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
-      "dev": true,
-      "requires": {
-        "extend-shallow": "^2.0.1",
-        "is-number": "^3.0.0",
-        "repeat-string": "^1.6.1",
-        "to-regex-range": "^2.1.0"
-      },
-      "dependencies": {
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        }
-      }
-    },
-    "find-up": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
-      "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
-      "dev": true,
-      "requires": {
-        "path-exists": "^2.0.0",
-        "pinkie-promise": "^2.0.0"
-      }
-    },
-    "findup-sync": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz",
-      "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==",
-      "dev": true,
-      "requires": {
-        "detect-file": "^1.0.0",
-        "is-glob": "^4.0.0",
-        "micromatch": "^3.0.4",
-        "resolve-dir": "^1.0.1"
-      },
-      "dependencies": {
-        "is-glob": {
-          "version": "4.0.1",
-          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
-          "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
-          "dev": true,
-          "requires": {
-            "is-extglob": "^2.1.1"
-          }
-        }
-      }
-    },
-    "fined": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz",
-      "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==",
-      "dev": true,
-      "requires": {
-        "expand-tilde": "^2.0.2",
-        "is-plain-object": "^2.0.3",
-        "object.defaults": "^1.1.0",
-        "object.pick": "^1.2.0",
-        "parse-filepath": "^1.0.1"
-      }
-    },
-    "flagged-respawn": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz",
-      "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==",
-      "dev": true
-    },
-    "flat-cache": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz",
-      "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==",
-      "dev": true,
-      "requires": {
-        "flatted": "^2.0.0",
-        "rimraf": "2.6.3",
-        "write": "1.0.3"
-      }
-    },
-    "flatted": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
-      "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==",
-      "dev": true
-    },
-    "flush-write-stream": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz",
-      "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.1",
-        "readable-stream": "^2.0.4"
-      },
-      "dependencies": {
-        "isarray": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
-          "dev": true
-        },
-        "readable-stream": {
-          "version": "2.3.6",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
-          "dev": true,
-          "requires": {
-            "core-util-is": "~1.0.0",
-            "inherits": "~2.0.3",
-            "isarray": "~1.0.0",
-            "process-nextick-args": "~2.0.0",
-            "safe-buffer": "~5.1.1",
-            "string_decoder": "~1.1.1",
-            "util-deprecate": "~1.0.1"
-          }
-        },
-        "string_decoder": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-          "dev": true,
-          "requires": {
-            "safe-buffer": "~5.1.0"
-          }
-        }
-      }
-    },
-    "for-in": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
-      "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
-      "dev": true
-    },
-    "for-own": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
-      "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=",
-      "dev": true,
-      "requires": {
-        "for-in": "^1.0.1"
-      }
-    },
-    "foreach": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
-      "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=",
-      "dev": true
-    },
-    "forever-agent": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
-      "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
-      "dev": true
-    },
-    "form-data": {
-      "version": "2.3.3",
-      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
-      "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
-      "dev": true,
-      "requires": {
-        "asynckit": "^0.4.0",
-        "combined-stream": "^1.0.6",
-        "mime-types": "^2.1.12"
-      }
-    },
-    "fragment-cache": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
-      "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
-      "dev": true,
-      "requires": {
-        "map-cache": "^0.2.2"
-      }
-    },
-    "fs-mkdirp-stream": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz",
-      "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.11",
-        "through2": "^2.0.3"
-      },
-      "dependencies": {
-        "graceful-fs": {
-          "version": "4.1.11",
-          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
-          "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
-          "dev": true
-        }
-      }
-    },
-    "fs.realpath": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
-      "dev": true
-    },
-    "fsevents": {
-      "version": "1.2.9",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz",
-      "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "nan": "^2.12.1",
-        "node-pre-gyp": "^0.12.0"
-      },
-      "dependencies": {
-        "abbrev": {
-          "version": "1.1.1",
-          "resolved": false,
-          "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
-          "dev": true,
-          "optional": true
-        },
-        "ansi-regex": {
-          "version": "2.1.1",
-          "resolved": false,
-          "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
-          "dev": true,
-          "optional": true
-        },
-        "aproba": {
-          "version": "1.2.0",
-          "resolved": false,
-          "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
-          "dev": true,
-          "optional": true
-        },
-        "are-we-there-yet": {
-          "version": "1.1.5",
-          "resolved": false,
-          "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "delegates": "^1.0.0",
-            "readable-stream": "^2.0.6"
-          }
-        },
-        "balanced-match": {
-          "version": "1.0.0",
-          "resolved": false,
-          "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
-          "dev": true,
-          "optional": true
-        },
-        "brace-expansion": {
-          "version": "1.1.11",
-          "resolved": false,
-          "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "balanced-match": "^1.0.0",
-            "concat-map": "0.0.1"
-          }
-        },
-        "chownr": {
-          "version": "1.1.1",
-          "resolved": false,
-          "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
-          "dev": true,
-          "optional": true
-        },
-        "code-point-at": {
-          "version": "1.1.0",
-          "resolved": false,
-          "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
-          "dev": true,
-          "optional": true
-        },
-        "concat-map": {
-          "version": "0.0.1",
-          "resolved": false,
-          "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
-          "dev": true,
-          "optional": true
-        },
-        "console-control-strings": {
-          "version": "1.1.0",
-          "resolved": false,
-          "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
-          "dev": true,
-          "optional": true
-        },
-        "core-util-is": {
-          "version": "1.0.2",
-          "resolved": false,
-          "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
-          "dev": true,
-          "optional": true
-        },
-        "debug": {
-          "version": "4.1.1",
-          "resolved": false,
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "deep-extend": {
-          "version": "0.6.0",
-          "resolved": false,
-          "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
-          "dev": true,
-          "optional": true
-        },
-        "delegates": {
-          "version": "1.0.0",
-          "resolved": false,
-          "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
-          "dev": true,
-          "optional": true
-        },
-        "detect-libc": {
-          "version": "1.0.3",
-          "resolved": false,
-          "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
-          "dev": true,
-          "optional": true
-        },
-        "fs-minipass": {
-          "version": "1.2.5",
-          "resolved": false,
-          "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "minipass": "^2.2.1"
-          }
-        },
-        "fs.realpath": {
-          "version": "1.0.0",
-          "resolved": false,
-          "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
-          "dev": true,
-          "optional": true
-        },
-        "gauge": {
-          "version": "2.7.4",
-          "resolved": false,
-          "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "aproba": "^1.0.3",
-            "console-control-strings": "^1.0.0",
-            "has-unicode": "^2.0.0",
-            "object-assign": "^4.1.0",
-            "signal-exit": "^3.0.0",
-            "string-width": "^1.0.1",
-            "strip-ansi": "^3.0.1",
-            "wide-align": "^1.1.0"
-          }
-        },
-        "glob": {
-          "version": "7.1.3",
-          "resolved": false,
-          "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
-        "has-unicode": {
-          "version": "2.0.1",
-          "resolved": false,
-          "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
-          "dev": true,
-          "optional": true
-        },
-        "iconv-lite": {
-          "version": "0.4.24",
-          "resolved": false,
-          "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "safer-buffer": ">= 2.1.2 < 3"
-          }
-        },
-        "ignore-walk": {
-          "version": "3.0.1",
-          "resolved": false,
-          "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "minimatch": "^3.0.4"
-          }
-        },
-        "inflight": {
-          "version": "1.0.6",
-          "resolved": false,
-          "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "once": "^1.3.0",
-            "wrappy": "1"
-          }
-        },
-        "inherits": {
-          "version": "2.0.3",
-          "resolved": false,
-          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
-          "dev": true,
-          "optional": true
-        },
-        "ini": {
-          "version": "1.3.5",
-          "resolved": false,
-          "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
-          "dev": true,
-          "optional": true
-        },
-        "is-fullwidth-code-point": {
-          "version": "1.0.0",
-          "resolved": false,
-          "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "number-is-nan": "^1.0.0"
-          }
-        },
-        "isarray": {
-          "version": "1.0.0",
-          "resolved": false,
-          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
-          "dev": true,
-          "optional": true
-        },
-        "minimatch": {
-          "version": "3.0.4",
-          "resolved": false,
-          "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "brace-expansion": "^1.1.7"
-          }
-        },
-        "minimist": {
-          "version": "0.0.8",
-          "resolved": false,
-          "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
-          "dev": true,
-          "optional": true
-        },
-        "minipass": {
-          "version": "2.3.5",
-          "resolved": false,
-          "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "safe-buffer": "^5.1.2",
-            "yallist": "^3.0.0"
-          }
-        },
-        "minizlib": {
-          "version": "1.2.1",
-          "resolved": false,
-          "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "minipass": "^2.2.1"
-          }
-        },
-        "mkdirp": {
-          "version": "0.5.1",
-          "resolved": false,
-          "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "minimist": "0.0.8"
-          }
-        },
-        "ms": {
-          "version": "2.1.1",
-          "resolved": false,
-          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
-          "dev": true,
-          "optional": true
-        },
-        "needle": {
-          "version": "2.3.0",
-          "resolved": false,
-          "integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "debug": "^4.1.0",
-            "iconv-lite": "^0.4.4",
-            "sax": "^1.2.4"
-          }
-        },
-        "node-pre-gyp": {
-          "version": "0.12.0",
-          "resolved": false,
-          "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "detect-libc": "^1.0.2",
-            "mkdirp": "^0.5.1",
-            "needle": "^2.2.1",
-            "nopt": "^4.0.1",
-            "npm-packlist": "^1.1.6",
-            "npmlog": "^4.0.2",
-            "rc": "^1.2.7",
-            "rimraf": "^2.6.1",
-            "semver": "^5.3.0",
-            "tar": "^4"
-          }
-        },
-        "nopt": {
-          "version": "4.0.1",
-          "resolved": false,
-          "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "abbrev": "1",
-            "osenv": "^0.1.4"
-          }
-        },
-        "npm-bundled": {
-          "version": "1.0.6",
-          "resolved": false,
-          "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==",
-          "dev": true,
-          "optional": true
-        },
-        "npm-packlist": {
-          "version": "1.4.1",
-          "resolved": false,
-          "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "ignore-walk": "^3.0.1",
-            "npm-bundled": "^1.0.1"
-          }
-        },
-        "npmlog": {
-          "version": "4.1.2",
-          "resolved": false,
-          "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "are-we-there-yet": "~1.1.2",
-            "console-control-strings": "~1.1.0",
-            "gauge": "~2.7.3",
-            "set-blocking": "~2.0.0"
-          }
-        },
-        "number-is-nan": {
-          "version": "1.0.1",
-          "resolved": false,
-          "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
-          "dev": true,
-          "optional": true
-        },
-        "object-assign": {
-          "version": "4.1.1",
-          "resolved": false,
-          "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
-          "dev": true,
-          "optional": true
-        },
-        "once": {
-          "version": "1.4.0",
-          "resolved": false,
-          "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "wrappy": "1"
-          }
-        },
-        "os-homedir": {
-          "version": "1.0.2",
-          "resolved": false,
-          "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
-          "dev": true,
-          "optional": true
-        },
-        "os-tmpdir": {
-          "version": "1.0.2",
-          "resolved": false,
-          "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
-          "dev": true,
-          "optional": true
-        },
-        "osenv": {
-          "version": "0.1.5",
-          "resolved": false,
-          "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "os-homedir": "^1.0.0",
-            "os-tmpdir": "^1.0.0"
-          }
-        },
-        "path-is-absolute": {
-          "version": "1.0.1",
-          "resolved": false,
-          "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
-          "dev": true,
-          "optional": true
-        },
-        "process-nextick-args": {
-          "version": "2.0.0",
-          "resolved": false,
-          "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
-          "dev": true,
-          "optional": true
-        },
-        "rc": {
-          "version": "1.2.8",
-          "resolved": false,
-          "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "deep-extend": "^0.6.0",
-            "ini": "~1.3.0",
-            "minimist": "^1.2.0",
-            "strip-json-comments": "~2.0.1"
-          },
-          "dependencies": {
-            "minimist": {
-              "version": "1.2.0",
-              "resolved": false,
-              "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-              "dev": true,
-              "optional": true
-            }
-          }
-        },
-        "readable-stream": {
-          "version": "2.3.6",
-          "resolved": false,
-          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "core-util-is": "~1.0.0",
-            "inherits": "~2.0.3",
-            "isarray": "~1.0.0",
-            "process-nextick-args": "~2.0.0",
-            "safe-buffer": "~5.1.1",
-            "string_decoder": "~1.1.1",
-            "util-deprecate": "~1.0.1"
-          }
-        },
-        "rimraf": {
-          "version": "2.6.3",
-          "resolved": false,
-          "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "glob": "^7.1.3"
-          }
-        },
-        "safe-buffer": {
-          "version": "5.1.2",
-          "resolved": false,
-          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
-          "dev": true,
-          "optional": true
-        },
-        "safer-buffer": {
-          "version": "2.1.2",
-          "resolved": false,
-          "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
-          "dev": true,
-          "optional": true
-        },
-        "sax": {
-          "version": "1.2.4",
-          "resolved": false,
-          "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
-          "dev": true,
-          "optional": true
-        },
-        "semver": {
-          "version": "5.7.0",
-          "resolved": false,
-          "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
-          "dev": true,
-          "optional": true
-        },
-        "set-blocking": {
-          "version": "2.0.0",
-          "resolved": false,
-          "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
-          "dev": true,
-          "optional": true
-        },
-        "signal-exit": {
-          "version": "3.0.2",
-          "resolved": false,
-          "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
-          "dev": true,
-          "optional": true
-        },
-        "string-width": {
-          "version": "1.0.2",
-          "resolved": false,
-          "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "code-point-at": "^1.0.0",
-            "is-fullwidth-code-point": "^1.0.0",
-            "strip-ansi": "^3.0.0"
-          }
-        },
-        "string_decoder": {
-          "version": "1.1.1",
-          "resolved": false,
-          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "safe-buffer": "~5.1.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "3.0.1",
-          "resolved": false,
-          "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "ansi-regex": "^2.0.0"
-          }
-        },
-        "strip-json-comments": {
-          "version": "2.0.1",
-          "resolved": false,
-          "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
-          "dev": true,
-          "optional": true
-        },
-        "tar": {
-          "version": "4.4.8",
-          "resolved": false,
-          "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "chownr": "^1.1.1",
-            "fs-minipass": "^1.2.5",
-            "minipass": "^2.3.4",
-            "minizlib": "^1.1.1",
-            "mkdirp": "^0.5.0",
-            "safe-buffer": "^5.1.2",
-            "yallist": "^3.0.2"
-          }
-        },
-        "util-deprecate": {
-          "version": "1.0.2",
-          "resolved": false,
-          "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
-          "dev": true,
-          "optional": true
-        },
-        "wide-align": {
-          "version": "1.1.3",
-          "resolved": false,
-          "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "string-width": "^1.0.2 || 2"
-          }
-        },
-        "wrappy": {
-          "version": "1.0.2",
-          "resolved": false,
-          "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
-          "dev": true,
-          "optional": true
-        },
-        "yallist": {
-          "version": "3.0.3",
-          "resolved": false,
-          "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
-          "dev": true,
-          "optional": true
-        }
-      }
-    },
-    "function-bind": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
-      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
-      "dev": true
-    },
-    "functional-red-black-tree": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
-      "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
-      "dev": true
-    },
-    "gensync": {
-      "version": "1.0.0-beta.1",
-      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz",
-      "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==",
-      "dev": true
-    },
-    "get-caller-file": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
-      "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
-      "dev": true
-    },
-    "get-pkg-repo": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-1.4.0.tgz",
-      "integrity": "sha1-xztInAbYDMVTbCyFP54FIyBWly0=",
-      "dev": true,
-      "requires": {
-        "hosted-git-info": "^2.1.4",
-        "meow": "^3.3.0",
-        "normalize-package-data": "^2.3.0",
-        "parse-github-repo-url": "^1.3.0",
-        "through2": "^2.0.0"
-      },
-      "dependencies": {
-        "camelcase": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
-          "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=",
-          "dev": true
-        },
-        "camelcase-keys": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
-          "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
-          "dev": true,
-          "requires": {
-            "camelcase": "^2.0.0",
-            "map-obj": "^1.0.0"
-          }
-        },
-        "indent-string": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
-          "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
-          "dev": true,
-          "requires": {
-            "repeating": "^2.0.0"
-          }
-        },
-        "map-obj": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
-          "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=",
-          "dev": true
-        },
-        "meow": {
-          "version": "3.7.0",
-          "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
-          "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
-          "dev": true,
-          "requires": {
-            "camelcase-keys": "^2.0.0",
-            "decamelize": "^1.1.2",
-            "loud-rejection": "^1.0.0",
-            "map-obj": "^1.0.1",
-            "minimist": "^1.1.3",
-            "normalize-package-data": "^2.3.4",
-            "object-assign": "^4.0.1",
-            "read-pkg-up": "^1.0.1",
-            "redent": "^1.0.0",
-            "trim-newlines": "^1.0.0"
-          }
-        },
-        "redent": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
-          "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
-          "dev": true,
-          "requires": {
-            "indent-string": "^2.1.0",
-            "strip-indent": "^1.0.1"
-          }
-        },
-        "strip-indent": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
-          "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
-          "dev": true,
-          "requires": {
-            "get-stdin": "^4.0.1"
-          }
-        },
-        "trim-newlines": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
-          "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=",
-          "dev": true
-        }
-      }
-    },
-    "get-stdin": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
-      "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=",
-      "dev": true
-    },
-    "get-stream": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz",
-      "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==",
-      "dev": true,
-      "requires": {
-        "pump": "^3.0.0"
-      },
-      "dependencies": {
-        "pump": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
-          "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
-          "dev": true,
-          "requires": {
-            "end-of-stream": "^1.1.0",
-            "once": "^1.3.1"
-          }
-        }
-      }
-    },
-    "get-value": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
-      "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
-      "dev": true
-    },
-    "getpass": {
-      "version": "0.1.7",
-      "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
-      "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
-      "dev": true,
-      "requires": {
-        "assert-plus": "^1.0.0"
-      }
-    },
-    "git-raw-commits": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-2.0.0.tgz",
-      "integrity": "sha512-w4jFEJFgKXMQJ0H0ikBk2S+4KP2VEjhCvLCNqbNRQC8BgGWgLKNCO7a9K9LI+TVT7Gfoloje502sEnctibffgg==",
-      "dev": true,
-      "requires": {
-        "dargs": "^4.0.1",
-        "lodash.template": "^4.0.2",
-        "meow": "^4.0.0",
-        "split2": "^2.0.0",
-        "through2": "^2.0.0"
-      },
-      "dependencies": {
-        "dargs": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/dargs/-/dargs-4.1.0.tgz",
-          "integrity": "sha1-A6nbtLXC8Tm/FK5T8LiipqhvThc=",
-          "dev": true,
-          "requires": {
-            "number-is-nan": "^1.0.0"
-          }
-        }
-      }
-    },
-    "git-remote-origin-url": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz",
-      "integrity": "sha1-UoJlna4hBxRaERJhEq0yFuxfpl8=",
-      "dev": true,
-      "requires": {
-        "gitconfiglocal": "^1.0.0",
-        "pify": "^2.3.0"
-      },
-      "dependencies": {
-        "pify": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
-          "dev": true
-        }
-      }
-    },
-    "git-semver-tags": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-2.0.2.tgz",
-      "integrity": "sha512-34lMF7Yo1xEmsK2EkbArdoU79umpvm0MfzaDkSNYSJqtM5QLAVTPWgpiXSVI5o/O9EvZPSrP4Zvnec/CqhSd5w==",
-      "dev": true,
-      "requires": {
-        "meow": "^4.0.0",
-        "semver": "^5.5.0"
-      }
-    },
-    "gitconfiglocal": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz",
-      "integrity": "sha1-QdBF84UaXqiPA/JMocYXgRRGS5s=",
-      "dev": true,
-      "requires": {
-        "ini": "^1.3.2"
-      }
-    },
-    "glob": {
-      "version": "7.1.2",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
-      "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
-      "dev": true,
-      "requires": {
-        "fs.realpath": "^1.0.0",
-        "inflight": "^1.0.4",
-        "inherits": "2",
-        "minimatch": "^3.0.4",
-        "once": "^1.3.0",
-        "path-is-absolute": "^1.0.0"
-      }
-    },
-    "glob-parent": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
-      "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
-      "dev": true,
-      "requires": {
-        "is-glob": "^3.1.0",
-        "path-dirname": "^1.0.0"
-      }
-    },
-    "glob-stream": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz",
-      "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=",
-      "dev": true,
-      "requires": {
-        "extend": "^3.0.0",
-        "glob": "^7.1.1",
-        "glob-parent": "^3.1.0",
-        "is-negated-glob": "^1.0.0",
-        "ordered-read-streams": "^1.0.0",
-        "pumpify": "^1.3.5",
-        "readable-stream": "^2.1.5",
-        "remove-trailing-separator": "^1.0.1",
-        "to-absolute-glob": "^2.0.0",
-        "unique-stream": "^2.0.2"
-      },
-      "dependencies": {
-        "isarray": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
-          "dev": true
-        },
-        "readable-stream": {
-          "version": "2.3.6",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
-          "dev": true,
-          "requires": {
-            "core-util-is": "~1.0.0",
-            "inherits": "~2.0.3",
-            "isarray": "~1.0.0",
-            "process-nextick-args": "~2.0.0",
-            "safe-buffer": "~5.1.1",
-            "string_decoder": "~1.1.1",
-            "util-deprecate": "~1.0.1"
-          }
-        },
-        "string_decoder": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-          "dev": true,
-          "requires": {
-            "safe-buffer": "~5.1.0"
-          }
-        }
-      }
-    },
-    "glob-watcher": {
-      "version": "5.0.3",
-      "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz",
-      "integrity": "sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg==",
-      "dev": true,
-      "requires": {
-        "anymatch": "^2.0.0",
-        "async-done": "^1.2.0",
-        "chokidar": "^2.0.0",
-        "is-negated-glob": "^1.0.0",
-        "just-debounce": "^1.0.0",
-        "object.defaults": "^1.1.0"
-      }
-    },
-    "global-modules": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
-      "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
-      "dev": true,
-      "requires": {
-        "global-prefix": "^1.0.1",
-        "is-windows": "^1.0.1",
-        "resolve-dir": "^1.0.0"
-      }
-    },
-    "global-prefix": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
-      "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=",
-      "dev": true,
-      "requires": {
-        "expand-tilde": "^2.0.2",
-        "homedir-polyfill": "^1.0.1",
-        "ini": "^1.3.4",
-        "is-windows": "^1.0.1",
-        "which": "^1.2.14"
-      }
-    },
-    "globals": {
-      "version": "11.12.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
-      "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
-      "dev": true
-    },
-    "globby": {
-      "version": "10.0.1",
-      "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz",
-      "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==",
-      "dev": true,
-      "requires": {
-        "@types/glob": "^7.1.1",
-        "array-union": "^2.1.0",
-        "dir-glob": "^3.0.1",
-        "fast-glob": "^3.0.3",
-        "glob": "^7.1.3",
-        "ignore": "^5.1.1",
-        "merge2": "^1.2.3",
-        "slash": "^3.0.0"
-      },
-      "dependencies": {
-        "@types/glob": {
-          "version": "7.1.1",
-          "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz",
-          "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==",
-          "dev": true,
-          "requires": {
-            "@types/events": "*",
-            "@types/minimatch": "*",
-            "@types/node": "*"
-          }
-        },
-        "glob": {
-          "version": "7.1.4",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
-          "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        }
-      }
-    },
-    "glogg": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.1.tgz",
-      "integrity": "sha512-ynYqXLoluBKf9XGR1gA59yEJisIL7YHEH4xr3ZziHB5/yl4qWfaK8Js9jGe6gBGCSCKVqiyO30WnRZADvemUNw==",
-      "dev": true,
-      "requires": {
-        "sparkles": "^1.0.0"
-      }
-    },
-    "google-libphonenumber": {
-      "version": "3.2.10",
-      "resolved": "https://registry.npmjs.org/google-libphonenumber/-/google-libphonenumber-3.2.10.tgz",
-      "integrity": "sha512-TsckE9O8QgqaIeaOXPjcJa4/kX3BzFdO1oCbMfmUpRZckml4xJhjJVxaT9Mdt/VrZZkT9lX44eHAEWfJK1tHtw=="
-    },
-    "graceful-fs": {
-      "version": "4.1.15",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz",
-      "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==",
-      "dev": true
-    },
-    "growly": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
-      "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=",
-      "dev": true,
-      "optional": true
-    },
-    "gulp": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz",
-      "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==",
-      "dev": true,
-      "requires": {
-        "glob-watcher": "^5.0.3",
-        "gulp-cli": "^2.2.0",
-        "undertaker": "^1.2.1",
-        "vinyl-fs": "^3.0.0"
-      },
-      "dependencies": {
-        "camelcase": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
-          "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
-          "dev": true
-        },
-        "cliui": {
-          "version": "3.2.0",
-          "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
-          "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
-          "dev": true,
-          "requires": {
-            "string-width": "^1.0.1",
-            "strip-ansi": "^3.0.1",
-            "wrap-ansi": "^2.0.0"
-          }
-        },
-        "gulp-cli": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.2.0.tgz",
-          "integrity": "sha512-rGs3bVYHdyJpLqR0TUBnlcZ1O5O++Zs4bA0ajm+zr3WFCfiSLjGwoCBqFs18wzN+ZxahT9DkOK5nDf26iDsWjA==",
-          "dev": true,
-          "requires": {
-            "ansi-colors": "^1.0.1",
-            "archy": "^1.0.0",
-            "array-sort": "^1.0.0",
-            "color-support": "^1.1.3",
-            "concat-stream": "^1.6.0",
-            "copy-props": "^2.0.1",
-            "fancy-log": "^1.3.2",
-            "gulplog": "^1.0.0",
-            "interpret": "^1.1.0",
-            "isobject": "^3.0.1",
-            "liftoff": "^3.1.0",
-            "matchdep": "^2.0.0",
-            "mute-stdout": "^1.0.0",
-            "pretty-hrtime": "^1.0.0",
-            "replace-homedir": "^1.0.0",
-            "semver-greatest-satisfied-range": "^1.1.0",
-            "v8flags": "^3.0.1",
-            "yargs": "^7.1.0"
-          }
-        },
-        "yargs": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz",
-          "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=",
-          "dev": true,
-          "requires": {
-            "camelcase": "^3.0.0",
-            "cliui": "^3.2.0",
-            "decamelize": "^1.1.1",
-            "get-caller-file": "^1.0.1",
-            "os-locale": "^1.4.0",
-            "read-pkg-up": "^1.0.1",
-            "require-directory": "^2.1.1",
-            "require-main-filename": "^1.0.1",
-            "set-blocking": "^2.0.0",
-            "string-width": "^1.0.2",
-            "which-module": "^1.0.0",
-            "y18n": "^3.2.1",
-            "yargs-parser": "^5.0.0"
-          }
-        }
-      }
-    },
-    "gulp-conventional-changelog": {
-      "version": "2.0.19",
-      "resolved": "https://registry.npmjs.org/gulp-conventional-changelog/-/gulp-conventional-changelog-2.0.19.tgz",
-      "integrity": "sha512-MTr9UcagJKVqAedi1XPyj7agHZKuRZPMNXgFVrI5z4h3nta/2/eOyBQhPq2L03rYzEEENTQRZ5A+cTU8k56FZQ==",
-      "dev": true,
-      "requires": {
-        "add-stream": "^1.0.0",
-        "concat-stream": "^2.0.0",
-        "conventional-changelog": "^3.1.8",
-        "fancy-log": "^1.3.2",
-        "object-assign": "^4.0.1",
-        "plugin-error": "^1.0.1",
-        "through2": "^3.0.0"
-      },
-      "dependencies": {
-        "concat-stream": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz",
-          "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
-          "dev": true,
-          "requires": {
-            "buffer-from": "^1.0.0",
-            "inherits": "^2.0.3",
-            "readable-stream": "^3.0.2",
-            "typedarray": "^0.0.6"
-          }
-        },
-        "plugin-error": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz",
-          "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==",
-          "dev": true,
-          "requires": {
-            "ansi-colors": "^1.0.1",
-            "arr-diff": "^4.0.0",
-            "arr-union": "^3.1.0",
-            "extend-shallow": "^3.0.2"
-          }
-        },
-        "through2": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz",
-          "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==",
-          "dev": true,
-          "requires": {
-            "readable-stream": "2 || 3"
-          }
-        }
-      }
-    },
-    "gulp-replace": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/gulp-replace/-/gulp-replace-1.0.0.tgz",
-      "integrity": "sha512-lgdmrFSI1SdhNMXZQbrC75MOl1UjYWlOWNbNRnz+F/KHmgxt3l6XstBoAYIdadwETFyG/6i+vWUSCawdC3pqOw==",
-      "dev": true,
-      "requires": {
-        "istextorbinary": "2.2.1",
-        "readable-stream": "^2.0.1",
-        "replacestream": "^4.0.0"
-      },
-      "dependencies": {
-        "isarray": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
-          "dev": true
-        },
-        "readable-stream": {
-          "version": "2.3.6",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
-          "dev": true,
-          "requires": {
-            "core-util-is": "~1.0.0",
-            "inherits": "~2.0.3",
-            "isarray": "~1.0.0",
-            "process-nextick-args": "~2.0.0",
-            "safe-buffer": "~5.1.1",
-            "string_decoder": "~1.1.1",
-            "util-deprecate": "~1.0.1"
-          }
-        },
-        "string_decoder": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-          "dev": true,
-          "requires": {
-            "safe-buffer": "~5.1.0"
-          }
-        }
-      }
-    },
-    "gulp-shell": {
-      "version": "0.8.0",
-      "resolved": "https://registry.npmjs.org/gulp-shell/-/gulp-shell-0.8.0.tgz",
-      "integrity": "sha512-wHNCgmqbWkk1c6Gc2dOL5SprcoeujQdeepICwfQRo91DIylTE7a794VEE+leq3cE2YDoiS5ulvRfKVIEMazcTQ==",
-      "dev": true,
-      "requires": {
-        "chalk": "^3.0.0",
-        "fancy-log": "^1.3.3",
-        "lodash.template": "^4.5.0",
-        "plugin-error": "^1.0.1",
-        "through2": "^3.0.1",
-        "tslib": "^1.10.0"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
-          "dev": true,
-          "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
-          }
-        },
-        "chalk": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-          "dev": true,
-          "requires": {
-            "color-name": "~1.1.4"
-          }
-        },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "fancy-log": {
-          "version": "1.3.3",
-          "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz",
-          "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==",
-          "dev": true,
-          "requires": {
-            "ansi-gray": "^0.1.1",
-            "color-support": "^1.1.3",
-            "parse-node-version": "^1.0.0",
-            "time-stamp": "^1.0.0"
-          }
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "plugin-error": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz",
-          "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==",
-          "dev": true,
-          "requires": {
-            "ansi-colors": "^1.0.1",
-            "arr-diff": "^4.0.0",
-            "arr-union": "^3.1.0",
-            "extend-shallow": "^3.0.2"
-          }
-        },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
-        },
-        "through2": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz",
-          "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==",
-          "dev": true,
-          "requires": {
-            "readable-stream": "2 || 3"
-          }
-        },
-        "tslib": {
-          "version": "1.10.0",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz",
-          "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==",
-          "dev": true
-        }
-      }
-    },
-    "gulp-sourcemaps": {
-      "version": "2.6.4",
-      "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-2.6.4.tgz",
-      "integrity": "sha1-y7IAhFCxvM5s0jv5gze+dRv24wo=",
-      "dev": true,
-      "requires": {
-        "@gulp-sourcemaps/identity-map": "1.X",
-        "@gulp-sourcemaps/map-sources": "1.X",
-        "acorn": "5.X",
-        "convert-source-map": "1.X",
-        "css": "2.X",
-        "debug-fabulous": "1.X",
-        "detect-newline": "2.X",
-        "graceful-fs": "4.X",
-        "source-map": "~0.6.0",
-        "strip-bom-string": "1.X",
-        "through2": "2.X"
-      },
-      "dependencies": {
-        "acorn": {
-          "version": "5.7.4",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz",
-          "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==",
-          "dev": true
-        },
-        "graceful-fs": {
-          "version": "4.1.11",
-          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
-          "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
-      }
-    },
-    "gulp-tslint": {
-      "version": "8.1.3",
-      "resolved": "https://registry.npmjs.org/gulp-tslint/-/gulp-tslint-8.1.3.tgz",
-      "integrity": "sha512-KEP350N5B9Jg6o6jnyCyKVBPemJePYpMsGfIQq0G0ErvY7tw4Lrfb/y3L4WRf7ek0OsaE8nnj86w+lcLXW8ovw==",
-      "dev": true,
-      "requires": {
-        "@types/fancy-log": "1.3.0",
-        "chalk": "2.3.1",
-        "fancy-log": "1.3.2",
-        "map-stream": "~0.0.7",
-        "plugin-error": "1.0.1",
-        "through": "~2.3.8"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "3.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-          "dev": true,
-          "requires": {
-            "color-convert": "^1.9.0"
-          }
-        },
-        "chalk": {
-          "version": "2.3.1",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.1.tgz",
-          "integrity": "sha512-QUU4ofkDoMIVO7hcx1iPTISs88wsO8jA92RQIm4JAwZvFGGAV2hSAA1NX7oVj2Ej2Q6NDTcRDjPTFrMCRZoJ6g==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.0",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.2.0"
-          }
-        },
-        "has-flag": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-          "dev": true
-        },
-        "plugin-error": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz",
-          "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==",
-          "dev": true,
-          "requires": {
-            "ansi-colors": "^1.0.1",
-            "arr-diff": "^4.0.0",
-            "arr-union": "^3.1.0",
-            "extend-shallow": "^3.0.2"
-          }
-        },
-        "supports-color": {
-          "version": "5.4.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
-          "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
-        }
-      }
-    },
-    "gulp-typescript": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/gulp-typescript/-/gulp-typescript-5.0.1.tgz",
-      "integrity": "sha512-YuMMlylyJtUSHG1/wuSVTrZp60k1dMEFKYOvDf7OvbAJWrDtxxD4oZon4ancdWwzjj30ztiidhe4VXJniF0pIQ==",
-      "dev": true,
-      "requires": {
-        "ansi-colors": "^3.0.5",
-        "plugin-error": "^1.0.1",
-        "source-map": "^0.7.3",
-        "through2": "^3.0.0",
-        "vinyl": "^2.1.0",
-        "vinyl-fs": "^3.0.3"
-      },
-      "dependencies": {
-        "ansi-colors": {
-          "version": "3.2.4",
-          "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
-          "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==",
-          "dev": true
-        },
-        "plugin-error": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz",
-          "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==",
-          "dev": true,
-          "requires": {
-            "ansi-colors": "^1.0.1",
-            "arr-diff": "^4.0.0",
-            "arr-union": "^3.1.0",
-            "extend-shallow": "^3.0.2"
-          },
-          "dependencies": {
-            "ansi-colors": {
-              "version": "1.1.0",
-              "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
-              "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==",
-              "dev": true,
-              "requires": {
-                "ansi-wrap": "^0.1.0"
-              }
-            }
-          }
-        },
-        "source-map": {
-          "version": "0.7.3",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
-          "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
-          "dev": true
-        },
-        "through2": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz",
-          "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==",
-          "dev": true,
-          "requires": {
-            "readable-stream": "2 || 3"
-          }
-        }
-      }
-    },
-    "gulpclass": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/gulpclass/-/gulpclass-0.2.0.tgz",
-      "integrity": "sha512-S2p0SgnVLjBbIEw5tHbBV6Wm6abD+leA5xZG6ukf9M+j1I/8zIeKPby9GLWnI90671YRk+lXbvEUROKaZXo8NA==",
+    "glob-parent": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
+      "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
       "dev": true,
       "requires": {
-        "@types/gulp": "^4.0.5",
-        "@types/merge2": "^1.1.4",
-        "@types/node": "*",
-        "gulp": "^4.0.0",
-        "merge2": "^1.2.2"
+        "is-glob": "^4.0.1"
       }
     },
-    "gulplog": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz",
-      "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=",
+    "globals": {
+      "version": "12.4.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz",
+      "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==",
       "dev": true,
       "requires": {
-        "glogg": "^1.0.0"
+        "type-fest": "^0.8.1"
       }
     },
+    "graceful-fs": {
+      "version": "4.2.4",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
+      "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
+      "dev": true
+    },
+    "growly": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
+      "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=",
+      "dev": true,
+      "optional": true
+    },
     "har-schema": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
@@ -5925,25 +3017,19 @@
       "dev": true
     },
     "har-validator": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
-      "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
+      "version": "5.1.5",
+      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
+      "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
       "dev": true,
       "requires": {
-        "ajv": "^6.5.5",
+        "ajv": "^6.12.3",
         "har-schema": "^2.0.0"
       }
     },
     "has-flag": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-      "dev": true
-    },
-    "has-symbols": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
-      "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
       "dev": true
     },
     "has-value": {
@@ -5967,6 +3053,26 @@
         "kind-of": "^4.0.0"
       },
       "dependencies": {
+        "is-number": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+          "dev": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+              "dev": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
         "kind-of": {
           "version": "4.0.0",
           "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
@@ -5978,28 +3084,19 @@
         }
       }
     },
-    "homedir-polyfill": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
-      "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
-      "dev": true,
-      "requires": {
-        "parse-passwd": "^1.0.0"
-      }
-    },
     "hosted-git-info": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz",
-      "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==",
+      "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",
-      "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",
+      "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==",
       "dev": true,
       "requires": {
-        "whatwg-encoding": "^1.0.1"
+        "whatwg-encoding": "^1.0.5"
       }
     },
     "html-escaper": {
@@ -6025,6 +3122,36 @@
       "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
       "dev": true
     },
+    "husky": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.0.tgz",
+      "integrity": "sha512-tTMeLCLqSBqnflBZnlVDhpaIMucSGaYyX6855jM4AguGeWCeSzNdb1mfyWduTZ3pe3SJVvVWGL0jO1iKZVPfTA==",
+      "dev": true,
+      "requires": {
+        "chalk": "^4.0.0",
+        "ci-info": "^2.0.0",
+        "compare-versions": "^3.6.0",
+        "cosmiconfig": "^7.0.0",
+        "find-versions": "^3.2.0",
+        "opencollective-postinstall": "^2.0.2",
+        "pkg-dir": "^4.2.0",
+        "please-upgrade-node": "^3.2.0",
+        "slash": "^3.0.0",
+        "which-pm-runs": "^1.0.0"
+      },
+      "dependencies": {
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        }
+      }
+    },
     "iconv-lite": {
       "version": "0.4.24",
       "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@@ -6035,9 +3162,9 @@
       }
     },
     "ignore": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.2.tgz",
-      "integrity": "sha512-vdqWBp7MyzdmHkkRWV5nY+PfGRbYbahfuvsBCh277tq+w9zyNi7h5CYJCK0kmzti9kU+O/cB7sE8HvKv6aXAKQ==",
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+      "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
       "dev": true
     },
     "import-fresh": {
@@ -6048,14 +3175,6 @@
       "requires": {
         "parent-module": "^1.0.0",
         "resolve-from": "^4.0.0"
-      },
-      "dependencies": {
-        "resolve-from": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
-          "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
-          "dev": true
-        }
       }
     },
     "import-local": {
@@ -6075,9 +3194,9 @@
       "dev": true
     },
     "indent-string": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz",
-      "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+      "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
       "dev": true
     },
     "inflight": {
@@ -6091,132 +3210,9 @@
       }
     },
     "inherits": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
-      "dev": true
-    },
-    "ini": {
-      "version": "1.3.5",
-      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
-      "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
-      "dev": true
-    },
-    "inquirer": {
-      "version": "7.1.0",
-      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.1.0.tgz",
-      "integrity": "sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg==",
-      "dev": true,
-      "requires": {
-        "ansi-escapes": "^4.2.1",
-        "chalk": "^3.0.0",
-        "cli-cursor": "^3.1.0",
-        "cli-width": "^2.0.0",
-        "external-editor": "^3.0.3",
-        "figures": "^3.0.0",
-        "lodash": "^4.17.15",
-        "mute-stream": "0.0.8",
-        "run-async": "^2.4.0",
-        "rxjs": "^6.5.3",
-        "string-width": "^4.1.0",
-        "strip-ansi": "^6.0.0",
-        "through": "^2.3.6"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
-          "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
-          "dev": true
-        },
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
-          "dev": true,
-          "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
-          }
-        },
-        "chalk": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-          "dev": true,
-          "requires": {
-            "color-name": "~1.1.4"
-          }
-        },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "is-fullwidth-code-point": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
-          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
-          "dev": true
-        },
-        "string-width": {
-          "version": "4.2.0",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
-          "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^8.0.0",
-            "is-fullwidth-code-point": "^3.0.0",
-            "strip-ansi": "^6.0.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
-          "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^5.0.0"
-          }
-        },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
-        }
-      }
-    },
-    "interpret": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz",
-      "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==",
-      "dev": true
-    },
-    "invert-kv": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
-      "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
       "dev": true
     },
     "ip-regex": {
@@ -6225,16 +3221,6 @@
       "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=",
       "dev": true
     },
-    "is-absolute": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
-      "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
-      "dev": true,
-      "requires": {
-        "is-relative": "^1.0.0",
-        "is-windows": "^1.0.1"
-      }
-    },
     "is-accessor-descriptor": {
       "version": "0.1.6",
       "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
@@ -6261,15 +3247,6 @@
       "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
       "dev": true
     },
-    "is-binary-path": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
-      "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
-      "dev": true,
-      "requires": {
-        "binary-extensions": "^1.0.0"
-      }
-    },
     "is-buffer": {
       "version": "1.1.6",
       "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
@@ -6324,6 +3301,13 @@
         }
       }
     },
+    "is-docker": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz",
+      "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==",
+      "dev": true,
+      "optional": true
+    },
     "is-extendable": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
@@ -6336,23 +3320,11 @@
       "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
       "dev": true
     },
-    "is-finite": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
-      "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
-      "dev": true,
-      "requires": {
-        "number-is-nan": "^1.0.0"
-      }
-    },
     "is-fullwidth-code-point": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
-      "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
-      "dev": true,
-      "requires": {
-        "number-is-nan": "^1.0.0"
-      }
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
+      "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+      "dev": true
     },
     "is-generator-fn": {
       "version": "2.1.0",
@@ -6361,12 +3333,12 @@
       "dev": true
     },
     "is-glob": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
-      "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
+      "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
       "dev": true,
       "requires": {
-        "is-extglob": "^2.1.0"
+        "is-extglob": "^2.1.1"
       }
     },
     "is-module": {
@@ -6375,31 +3347,11 @@
       "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
       "dev": true
     },
-    "is-negated-glob": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz",
-      "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=",
-      "dev": true
-    },
     "is-number": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
-      "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
-      "dev": true,
-      "requires": {
-        "kind-of": "^3.0.2"
-      },
-      "dependencies": {
-        "kind-of": {
-          "version": "3.2.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-          "dev": true,
-          "requires": {
-            "is-buffer": "^1.1.5"
-          }
-        }
-      }
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true
     },
     "is-obj": {
       "version": "1.0.1",
@@ -6407,36 +3359,6 @@
       "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
       "dev": true
     },
-    "is-path-cwd": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
-      "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==",
-      "dev": true
-    },
-    "is-path-in-cwd": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz",
-      "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==",
-      "dev": true,
-      "requires": {
-        "is-path-inside": "^2.1.0"
-      }
-    },
-    "is-path-inside": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz",
-      "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==",
-      "dev": true,
-      "requires": {
-        "path-is-inside": "^1.0.2"
-      }
-    },
-    "is-plain-obj": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
-      "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
-      "dev": true
-    },
     "is-plain-object": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
@@ -6446,29 +3368,26 @@
         "isobject": "^3.0.1"
       }
     },
-    "is-promise": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
-      "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=",
+    "is-potential-custom-element-name": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz",
+      "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=",
       "dev": true
     },
     "is-reference": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz",
-      "integrity": "sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
+      "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
       "dev": true,
       "requires": {
-        "@types/estree": "0.0.39"
+        "@types/estree": "*"
       }
     },
-    "is-relative": {
+    "is-regexp": {
       "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
-      "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
-      "dev": true,
-      "requires": {
-        "is-unc-path": "^1.0.0"
-      }
+      "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz",
+      "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=",
+      "dev": true
     },
     "is-stream": {
       "version": "1.1.0",
@@ -6476,42 +3395,12 @@
       "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
       "dev": true
     },
-    "is-text-path": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-2.0.0.tgz",
-      "integrity": "sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw==",
-      "dev": true,
-      "requires": {
-        "text-extensions": "^2.0.0"
-      }
-    },
     "is-typedarray": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
       "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
       "dev": true
     },
-    "is-unc-path": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
-      "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
-      "dev": true,
-      "requires": {
-        "unc-path-regex": "^0.1.2"
-      }
-    },
-    "is-utf8": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
-      "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
-      "dev": true
-    },
-    "is-valid-glob": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz",
-      "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=",
-      "dev": true
-    },
     "is-windows": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
@@ -6519,11 +3408,20 @@
       "dev": true
     },
     "is-wsl": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.1.1.tgz",
-      "integrity": "sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog==",
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+      "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
       "dev": true,
-      "optional": true
+      "optional": true,
+      "requires": {
+        "is-docker": "^2.0.0"
+      }
+    },
+    "isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+      "dev": true
     },
     "isexe": {
       "version": "2.0.0",
@@ -6550,15 +3448,12 @@
       "dev": true
     },
     "istanbul-lib-instrument": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.1.tgz",
-      "integrity": "sha512-imIchxnodll7pvQBYOqUu88EufLCU56LMeFPZZM/fJZ1irYcYdqroaV+ACK1Ila8ls09iEYArp+nqyC6lW1Vfg==",
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz",
+      "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==",
       "dev": true,
       "requires": {
         "@babel/core": "^7.7.5",
-        "@babel/parser": "^7.7.5",
-        "@babel/template": "^7.7.4",
-        "@babel/traverse": "^7.7.4",
         "@istanbuljs/schema": "^0.1.2",
         "istanbul-lib-coverage": "^3.0.0",
         "semver": "^6.3.0"
@@ -6580,24 +3475,7 @@
       "requires": {
         "istanbul-lib-coverage": "^3.0.0",
         "make-dir": "^3.0.0",
-        "supports-color": "^7.1.0"
-      },
-      "dependencies": {
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
-        }
+        "supports-color": "^7.1.0"
       }
     },
     "istanbul-lib-source-maps": {
@@ -6609,29 +3487,6 @@
         "debug": "^4.1.1",
         "istanbul-lib-coverage": "^3.0.0",
         "source-map": "^0.6.1"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
       }
     },
     "istanbul-reports": {
@@ -6644,1915 +3499,1343 @@
         "istanbul-lib-report": "^3.0.0"
       }
     },
-    "istextorbinary": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.2.1.tgz",
-      "integrity": "sha512-TS+hoFl8Z5FAFMK38nhBkdLt44CclNRgDHWeMgsV8ko3nDlr/9UI2Sf839sW7enijf8oKsZYXRvM8g0it9Zmcw==",
-      "dev": true,
-      "requires": {
-        "binaryextensions": "2",
-        "editions": "^1.3.3",
-        "textextensions": "2"
-      }
-    },
     "jest": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/jest/-/jest-25.4.0.tgz",
-      "integrity": "sha512-XWipOheGB4wai5JfCYXd6vwsWNwM/dirjRoZgAa7H2wd8ODWbli2AiKjqG8AYhyx+8+5FBEdpO92VhGlBydzbw==",
+      "version": "26.4.2",
+      "resolved": "https://registry.npmjs.org/jest/-/jest-26.4.2.tgz",
+      "integrity": "sha512-LLCjPrUh98Ik8CzW8LLVnSCfLaiY+wbK53U7VxnFSX7Q+kWC4noVeDvGWIFw0Amfq1lq2VfGm7YHWSLBV62MJw==",
       "dev": true,
       "requires": {
-        "@jest/core": "^25.4.0",
+        "@jest/core": "^26.4.2",
         "import-local": "^3.0.2",
-        "jest-cli": "^25.4.0"
+        "jest-cli": "^26.4.2"
       },
       "dependencies": {
-        "ansi-regex": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
-          "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
-          "dev": true
-        },
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "camelcase": {
-          "version": "5.3.1",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
-          "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
-          "dev": true
-        },
-        "chalk": {
+        "@types/istanbul-reports": {
           "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
-        "cliui": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
-          "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
-          "dev": true,
-          "requires": {
-            "string-width": "^4.2.0",
-            "strip-ansi": "^6.0.0",
-            "wrap-ansi": "^6.2.0"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "color-name": "~1.1.4"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "emoji-regex": {
-          "version": "8.0.0",
-          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-          "dev": true
-        },
-        "find-up": {
+        "chalk": {
           "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "locate-path": "^5.0.0",
-            "path-exists": "^4.0.0"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
         },
-        "get-caller-file": {
-          "version": "2.0.5",
-          "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
-          "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "is-fullwidth-code-point": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
-          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
-          "dev": true
-        },
         "jest-cli": {
-          "version": "25.4.0",
-          "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-25.4.0.tgz",
-          "integrity": "sha512-usyrj1lzCJZMRN1r3QEdnn8e6E6yCx/QN7+B1sLoA68V7f3WlsxSSQfy0+BAwRiF4Hz2eHauf11GZG3PIfWTXQ==",
+          "version": "26.4.2",
+          "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.4.2.tgz",
+          "integrity": "sha512-zb+lGd/SfrPvoRSC/0LWdaWCnscXc1mGYW//NP4/tmBvRPT3VntZ2jtKUONsRi59zc5JqmsSajA9ewJKFYp8Cw==",
           "dev": true,
           "requires": {
-            "@jest/core": "^25.4.0",
-            "@jest/test-result": "^25.4.0",
-            "@jest/types": "^25.4.0",
-            "chalk": "^3.0.0",
+            "@jest/core": "^26.4.2",
+            "@jest/test-result": "^26.3.0",
+            "@jest/types": "^26.3.0",
+            "chalk": "^4.0.0",
             "exit": "^0.1.2",
+            "graceful-fs": "^4.2.4",
             "import-local": "^3.0.2",
             "is-ci": "^2.0.0",
-            "jest-config": "^25.4.0",
-            "jest-util": "^25.4.0",
-            "jest-validate": "^25.4.0",
+            "jest-config": "^26.4.2",
+            "jest-util": "^26.3.0",
+            "jest-validate": "^26.4.2",
             "prompts": "^2.0.1",
-            "realpath-native": "^2.0.0",
             "yargs": "^15.3.1"
           }
-        },
-        "locate-path": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-          "dev": true,
-          "requires": {
-            "p-locate": "^4.1.0"
-          }
-        },
-        "p-locate": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^2.2.0"
-          }
-        },
-        "path-exists": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-          "dev": true
-        },
-        "require-main-filename": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
-          "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
-          "dev": true
-        },
-        "string-width": {
-          "version": "4.2.0",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
-          "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^8.0.0",
-            "is-fullwidth-code-point": "^3.0.0",
-            "strip-ansi": "^6.0.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
-          "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^5.0.0"
-          }
-        },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
-        },
-        "which-module": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
-          "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
-          "dev": true
-        },
-        "wrap-ansi": {
-          "version": "6.2.0",
-          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
-          "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^4.0.0",
-            "string-width": "^4.1.0",
-            "strip-ansi": "^6.0.0"
-          }
-        },
-        "y18n": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
-          "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
-          "dev": true
-        },
-        "yargs": {
-          "version": "15.3.1",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz",
-          "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==",
-          "dev": true,
-          "requires": {
-            "cliui": "^6.0.0",
-            "decamelize": "^1.2.0",
-            "find-up": "^4.1.0",
-            "get-caller-file": "^2.0.1",
-            "require-directory": "^2.1.1",
-            "require-main-filename": "^2.0.0",
-            "set-blocking": "^2.0.0",
-            "string-width": "^4.2.0",
-            "which-module": "^2.0.0",
-            "y18n": "^4.0.0",
-            "yargs-parser": "^18.1.1"
-          }
-        },
-        "yargs-parser": {
-          "version": "18.1.3",
-          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
-          "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
-          "dev": true,
-          "requires": {
-            "camelcase": "^5.0.0",
-            "decamelize": "^1.2.0"
-          }
         }
       }
     },
     "jest-changed-files": {
-      "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==",
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.3.0.tgz",
+      "integrity": "sha512-1C4R4nijgPltX6fugKxM4oQ18zimS7LqQ+zTTY8lMCMFPrxqBFb7KJH0Z2fRQJvw2Slbaipsqq7s1mgX5Iot+g==",
       "dev": true,
       "requires": {
-        "@jest/types": "^25.4.0",
-        "execa": "^3.2.0",
+        "@jest/types": "^26.3.0",
+        "execa": "^4.0.0",
         "throat": "^5.0.0"
       },
       "dependencies": {
-        "cross-spawn": {
-          "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",
-            "shebang-command": "^2.0.0",
-            "which": "^2.0.1"
-          }
-        },
-        "execa": {
-          "version": "3.4.0",
-          "resolved": "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz",
-          "integrity": "sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g==",
-          "dev": true,
-          "requires": {
-            "cross-spawn": "^7.0.0",
-            "get-stream": "^5.0.0",
-            "human-signals": "^1.1.1",
-            "is-stream": "^2.0.0",
-            "merge-stream": "^2.0.0",
-            "npm-run-path": "^4.0.0",
-            "onetime": "^5.1.0",
-            "p-finally": "^2.0.0",
-            "signal-exit": "^3.0.2",
-            "strip-final-newline": "^2.0.0"
-          }
-        },
-        "is-stream": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
-          "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
-          "dev": true
-        },
-        "npm-run-path": {
-          "version": "4.0.1",
-          "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
-          "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
-          "dev": true,
-          "requires": {
-            "path-key": "^3.0.0"
-          }
-        },
-        "p-finally": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz",
-          "integrity": "sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==",
-          "dev": true
-        },
-        "path-key": {
-          "version": "3.1.1",
-          "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
-          "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
-          "dev": true
-        },
-        "shebang-command": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
-          "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
-          "dev": true,
-          "requires": {
-            "shebang-regex": "^3.0.0"
-          }
-        },
-        "shebang-regex": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
-          "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
-          "dev": true
-        },
-        "which": {
-          "version": "2.0.2",
-          "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
-          "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
-          "dev": true,
-          "requires": {
-            "isexe": "^2.0.0"
-          }
-        }
-      }
-    },
-    "jest-config": {
-      "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.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.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.4.0",
-        "realpath-native": "^2.0.0"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
-          "dev": true,
-          "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
-          }
-        },
-        "braces": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-          "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
-          "dev": true,
-          "requires": {
-            "fill-range": "^7.0.1"
-          }
-        },
-        "chalk": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-          "dev": true,
-          "requires": {
-            "color-name": "~1.1.4"
-          }
-        },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "fill-range": {
-          "version": "7.0.1",
-          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-          "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
-          "dev": true,
-          "requires": {
-            "to-regex-range": "^5.0.1"
-          }
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "is-number": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-          "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-          "dev": true
-        },
-        "micromatch": {
-          "version": "4.0.2",
-          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
-          "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
-          "dev": true,
-          "requires": {
-            "braces": "^3.0.1",
-            "picomatch": "^2.0.5"
-          }
-        },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
-        },
-        "to-regex-range": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-          "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
-          "requires": {
-            "is-number": "^7.0.0"
-          }
-        }
-      }
-    },
-    "jest-diff": {
-      "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.6",
-        "jest-get-type": "^25.2.6",
-        "pretty-format": "^25.4.0"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+          "requires": {
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
+          }
+        },
+        "@types/istanbul-reports": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
+            "@types/istanbul-lib-report": "*"
           }
         },
         "chalk": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
             "ansi-styles": "^4.1.0",
             "supports-color": "^7.1.0"
           }
         },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "execa": {
+          "version": "4.0.3",
+          "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.3.tgz",
+          "integrity": "sha512-WFDXGHckXPWZX19t1kCsXzOpqX9LWYNqn4C+HqZlk/V0imTkzJZqf87ZBhvpHaftERYknpk0fjSylnXVlVgI0A==",
           "dev": true,
           "requires": {
-            "color-name": "~1.1.4"
+            "cross-spawn": "^7.0.0",
+            "get-stream": "^5.0.0",
+            "human-signals": "^1.1.1",
+            "is-stream": "^2.0.0",
+            "merge-stream": "^2.0.0",
+            "npm-run-path": "^4.0.0",
+            "onetime": "^5.1.0",
+            "signal-exit": "^3.0.2",
+            "strip-final-newline": "^2.0.0"
           }
         },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
+        "get-stream": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+          "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
+          "dev": true,
+          "requires": {
+            "pump": "^3.0.0"
+          }
         },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "is-stream": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
+          "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
           "dev": true
         },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+        "npm-run-path": {
+          "version": "4.0.1",
+          "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+          "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
           "dev": true,
           "requires": {
-            "has-flag": "^4.0.0"
+            "path-key": "^3.0.0"
           }
         }
       }
     },
-    "jest-docblock": {
-      "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"
-      },
-      "dependencies": {
-        "detect-newline": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
-          "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==",
-          "dev": true
-        }
-      }
-    },
-    "jest-each": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-25.4.0.tgz",
-      "integrity": "sha512-lwRIJ8/vQU/6vq3nnSSUw1Y3nz5tkYSFIywGCZpUBd6WcRgpn8NmJoQICojbpZmsJOJNHm0BKdyuJ6Xdx+eDQQ==",
+    "jest-config": {
+      "version": "26.4.2",
+      "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.4.2.tgz",
+      "integrity": "sha512-QBf7YGLuToiM8PmTnJEdRxyYy3mHWLh24LJZKVdXZ2PNdizSe1B/E8bVm+HYcjbEzGuVXDv/di+EzdO/6Gq80A==",
       "dev": true,
       "requires": {
-        "@jest/types": "^25.4.0",
-        "chalk": "^3.0.0",
-        "jest-get-type": "^25.2.6",
-        "jest-util": "^25.4.0",
-        "pretty-format": "^25.4.0"
+        "@babel/core": "^7.1.0",
+        "@jest/test-sequencer": "^26.4.2",
+        "@jest/types": "^26.3.0",
+        "babel-jest": "^26.3.0",
+        "chalk": "^4.0.0",
+        "deepmerge": "^4.2.2",
+        "glob": "^7.1.1",
+        "graceful-fs": "^4.2.4",
+        "jest-environment-jsdom": "^26.3.0",
+        "jest-environment-node": "^26.3.0",
+        "jest-get-type": "^26.3.0",
+        "jest-jasmine2": "^26.4.2",
+        "jest-regex-util": "^26.0.0",
+        "jest-resolve": "^26.4.0",
+        "jest-util": "^26.3.0",
+        "jest-validate": "^26.4.2",
+        "micromatch": "^4.0.2",
+        "pretty-format": "^26.4.2"
       },
       "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "chalk": {
+        "@types/istanbul-reports": {
           "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "color-name": "~1.1.4"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
         },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "jest-get-type": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz",
+          "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==",
           "dev": true
         },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+        "pretty-format": {
+          "version": "26.4.2",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.4.2.tgz",
+          "integrity": "sha512-zK6Gd8zDsEiVydOCGLkoBoZuqv8VTiHyAbKznXe/gaph/DAeZOmit9yMfgIz5adIgAMMs5XfoYSwAX3jcCO1tA==",
           "dev": true,
           "requires": {
-            "has-flag": "^4.0.0"
+            "@jest/types": "^26.3.0",
+            "ansi-regex": "^5.0.0",
+            "ansi-styles": "^4.0.0",
+            "react-is": "^16.12.0"
           }
         }
       }
     },
-    "jest-environment-jsdom": {
-      "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==",
+    "jest-diff": {
+      "version": "25.5.0",
+      "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.5.0.tgz",
+      "integrity": "sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A==",
       "dev": true,
       "requires": {
-        "@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"
+        "chalk": "^3.0.0",
+        "diff-sequences": "^25.2.6",
+        "jest-get-type": "^25.2.6",
+        "pretty-format": "^25.5.0"
       }
     },
-    "jest-environment-node": {
-      "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==",
+    "jest-docblock": {
+      "version": "26.0.0",
+      "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz",
+      "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==",
       "dev": true,
       "requires": {
-        "@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": {
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        }
+        "detect-newline": "^3.0.0"
       }
     },
-    "jest-get-type": {
-      "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.4.0",
-      "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-25.4.0.tgz",
-      "integrity": "sha512-5EoCe1gXfGC7jmXbKzqxESrgRcaO3SzWXGCnvp9BcT0CFMyrB1Q6LIsjl9RmvmJGQgW297TCfrdgiy574Rl9HQ==",
+    "jest-each": {
+      "version": "26.4.2",
+      "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.4.2.tgz",
+      "integrity": "sha512-p15rt8r8cUcRY0Mvo1fpkOGYm7iI8S6ySxgIdfh3oOIv+gHwrHTy5VWCGOecWUhDsit4Nz8avJWdT07WLpbwDA==",
       "dev": true,
       "requires": {
-        "@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.6",
-        "jest-util": "^25.4.0",
-        "jest-worker": "^25.4.0",
-        "micromatch": "^4.0.2",
-        "sane": "^4.0.3",
-        "walker": "^1.0.7",
-        "which": "^2.0.2"
+        "@jest/types": "^26.3.0",
+        "chalk": "^4.0.0",
+        "jest-get-type": "^26.3.0",
+        "jest-util": "^26.3.0",
+        "pretty-format": "^26.4.2"
       },
       "dependencies": {
-        "anymatch": {
-          "version": "3.1.1",
-          "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
-          "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
-          "dev": true,
-          "requires": {
-            "normalize-path": "^3.0.0",
-            "picomatch": "^2.0.4"
-          }
-        },
-        "braces": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-          "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
-          "dev": true,
-          "requires": {
-            "fill-range": "^7.0.1"
-          }
-        },
-        "fill-range": {
-          "version": "7.0.1",
-          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-          "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "to-regex-range": "^5.0.1"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "fsevents": {
-          "version": "2.1.3",
-          "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
-          "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
-          "dev": true,
-          "optional": true
-        },
-        "graceful-fs": {
-          "version": "4.2.3",
-          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
-          "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "is-number": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-          "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-          "dev": true
-        },
-        "jest-worker": {
-          "version": "25.4.0",
-          "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.4.0.tgz",
-          "integrity": "sha512-ghAs/1FtfYpMmYQ0AHqxV62XPvKdUDIBBApMZfly+E9JEmYh2K45G0R5dWxx986RN12pRCxsViwQVtGl+N4whw==",
+        "@types/istanbul-reports": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "merge-stream": "^2.0.0",
-            "supports-color": "^7.0.0"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "micromatch": {
-          "version": "4.0.2",
-          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
-          "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "braces": "^3.0.1",
-            "picomatch": "^2.0.5"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
         },
-        "normalize-path": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
-          "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+        "jest-get-type": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz",
+          "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==",
           "dev": true
         },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
-        },
-        "to-regex-range": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-          "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-          "dev": true,
-          "requires": {
-            "is-number": "^7.0.0"
-          }
-        },
-        "which": {
-          "version": "2.0.2",
-          "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
-          "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+        "pretty-format": {
+          "version": "26.4.2",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.4.2.tgz",
+          "integrity": "sha512-zK6Gd8zDsEiVydOCGLkoBoZuqv8VTiHyAbKznXe/gaph/DAeZOmit9yMfgIz5adIgAMMs5XfoYSwAX3jcCO1tA==",
           "dev": true,
           "requires": {
-            "isexe": "^2.0.0"
+            "@jest/types": "^26.3.0",
+            "ansi-regex": "^5.0.0",
+            "ansi-styles": "^4.0.0",
+            "react-is": "^16.12.0"
           }
         }
       }
     },
-    "jest-jasmine2": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-25.4.0.tgz",
-      "integrity": "sha512-QccxnozujVKYNEhMQ1vREiz859fPN/XklOzfQjm2j9IGytAkUbSwjFRBtQbHaNZ88cItMpw02JnHGsIdfdpwxQ==",
+    "jest-environment-jsdom": {
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.3.0.tgz",
+      "integrity": "sha512-zra8He2btIMJkAzvLaiZ9QwEPGEetbxqmjEBQwhH3CA+Hhhu0jSiEJxnJMbX28TGUvPLxBt/zyaTLrOPF4yMJA==",
       "dev": true,
       "requires": {
-        "@babel/traverse": "^7.1.0",
-        "@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.4.0",
-        "is-generator-fn": "^2.0.0",
-        "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"
+        "@jest/environment": "^26.3.0",
+        "@jest/fake-timers": "^26.3.0",
+        "@jest/types": "^26.3.0",
+        "@types/node": "*",
+        "jest-mock": "^26.3.0",
+        "jest-util": "^26.3.0",
+        "jsdom": "^16.2.2"
       },
       "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "chalk": {
+        "@types/istanbul-reports": {
           "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-          "dev": true,
-          "requires": {
-            "color-name": "~1.1.4"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "has-flag": "^4.0.0"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
         }
       }
     },
-    "jest-leak-detector": {
-      "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.6",
-        "pretty-format": "^25.4.0"
-      }
-    },
-    "jest-matcher-utils": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-25.4.0.tgz",
-      "integrity": "sha512-yPMdtj7YDgXhnGbc66bowk8AkQ0YwClbbwk3Kzhn5GVDrciiCr27U4NJRbrqXbTdtxjImONITg2LiRIw650k5A==",
+    "jest-environment-node": {
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.3.0.tgz",
+      "integrity": "sha512-c9BvYoo+FGcMj5FunbBgtBnbR5qk3uky8PKyRVpSfe2/8+LrNQMiXX53z6q2kY+j15SkjQCOSL/6LHnCPLVHNw==",
       "dev": true,
       "requires": {
-        "chalk": "^3.0.0",
-        "jest-diff": "^25.4.0",
-        "jest-get-type": "^25.2.6",
-        "pretty-format": "^25.4.0"
+        "@jest/environment": "^26.3.0",
+        "@jest/fake-timers": "^26.3.0",
+        "@jest/types": "^26.3.0",
+        "@types/node": "*",
+        "jest-mock": "^26.3.0",
+        "jest-util": "^26.3.0"
       },
       "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "chalk": {
+        "@types/istanbul-reports": {
           "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "color-name": "~1.1.4"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "has-flag": "^4.0.0"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
         }
       }
     },
-    "jest-message-util": {
-      "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==",
+    "jest-get-type": {
+      "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": "26.3.0",
+      "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.3.0.tgz",
+      "integrity": "sha512-DHWBpTJgJhLLGwE5Z1ZaqLTYqeODQIZpby0zMBsCU9iRFHYyhklYqP4EiG73j5dkbaAdSZhgB938mL51Q5LeZA==",
       "dev": true,
       "requires": {
-        "@babel/code-frame": "^7.0.0",
-        "@jest/types": "^25.4.0",
-        "@types/stack-utils": "^1.0.1",
-        "chalk": "^3.0.0",
+        "@jest/types": "^26.3.0",
+        "@types/graceful-fs": "^4.1.2",
+        "@types/node": "*",
+        "anymatch": "^3.0.3",
+        "fb-watchman": "^2.0.0",
+        "fsevents": "^2.1.2",
+        "graceful-fs": "^4.2.4",
+        "jest-regex-util": "^26.0.0",
+        "jest-serializer": "^26.3.0",
+        "jest-util": "^26.3.0",
+        "jest-worker": "^26.3.0",
         "micromatch": "^4.0.2",
-        "slash": "^3.0.0",
-        "stack-utils": "^1.0.1"
+        "sane": "^4.0.3",
+        "walker": "^1.0.7"
       },
       "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "braces": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-          "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+        "@types/istanbul-reports": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "fill-range": "^7.0.1"
+            "@types/istanbul-lib-report": "*"
           }
         },
         "chalk": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
             "ansi-styles": "^4.1.0",
             "supports-color": "^7.1.0"
           }
         },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "jest-worker": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.3.0.tgz",
+          "integrity": "sha512-Vmpn2F6IASefL+DVBhPzI2J9/GJUsqzomdeN+P+dK8/jKxbh8R3BtFnx3FIta7wYlPU62cpJMJQo4kuOowcMnw==",
           "dev": true,
           "requires": {
-            "color-name": "~1.1.4"
+            "@types/node": "*",
+            "merge-stream": "^2.0.0",
+            "supports-color": "^7.0.0"
           }
-        },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "fill-range": {
-          "version": "7.0.1",
-          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-          "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+        }
+      }
+    },
+    "jest-jasmine2": {
+      "version": "26.4.2",
+      "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.4.2.tgz",
+      "integrity": "sha512-z7H4EpCldHN1J8fNgsja58QftxBSL+JcwZmaXIvV9WKIM+x49F4GLHu/+BQh2kzRKHAgaN/E82od+8rTOBPyPA==",
+      "dev": true,
+      "requires": {
+        "@babel/traverse": "^7.1.0",
+        "@jest/environment": "^26.3.0",
+        "@jest/source-map": "^26.3.0",
+        "@jest/test-result": "^26.3.0",
+        "@jest/types": "^26.3.0",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "co": "^4.6.0",
+        "expect": "^26.4.2",
+        "is-generator-fn": "^2.0.0",
+        "jest-each": "^26.4.2",
+        "jest-matcher-utils": "^26.4.2",
+        "jest-message-util": "^26.3.0",
+        "jest-runtime": "^26.4.2",
+        "jest-snapshot": "^26.4.2",
+        "jest-util": "^26.3.0",
+        "pretty-format": "^26.4.2",
+        "throat": "^5.0.0"
+      },
+      "dependencies": {
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "to-regex-range": "^5.0.1"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "is-number": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-          "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-          "dev": true
-        },
-        "micromatch": {
-          "version": "4.0.2",
-          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
-          "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
+        "@types/istanbul-reports": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "braces": "^3.0.1",
-            "picomatch": "^2.0.5"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "has-flag": "^4.0.0"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
         },
-        "to-regex-range": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-          "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+        "pretty-format": {
+          "version": "26.4.2",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.4.2.tgz",
+          "integrity": "sha512-zK6Gd8zDsEiVydOCGLkoBoZuqv8VTiHyAbKznXe/gaph/DAeZOmit9yMfgIz5adIgAMMs5XfoYSwAX3jcCO1tA==",
           "dev": true,
           "requires": {
-            "is-number": "^7.0.0"
+            "@jest/types": "^26.3.0",
+            "ansi-regex": "^5.0.0",
+            "ansi-styles": "^4.0.0",
+            "react-is": "^16.12.0"
           }
         }
       }
     },
-    "jest-mock": {
-      "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.4.0"
-      }
-    },
-    "jest-pnp-resolver": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz",
-      "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==",
-      "dev": true
-    },
-    "jest-regex-util": {
-      "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.4.0",
-      "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-25.4.0.tgz",
-      "integrity": "sha512-wOsKqVDFWUiv8BtLMCC6uAJ/pHZkfFgoBTgPtmYlsprAjkxrr2U++ZnB3l5ykBMd2O24lXvf30SMAjJIW6k2aA==",
+    "jest-leak-detector": {
+      "version": "26.4.2",
+      "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.4.2.tgz",
+      "integrity": "sha512-akzGcxwxtE+9ZJZRW+M2o+nTNnmQZxrHJxX/HjgDaU5+PLmY1qnQPnMjgADPGCRPhB+Yawe1iij0REe+k/aHoA==",
       "dev": true,
       "requires": {
-        "@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",
-        "slash": "^3.0.0"
+        "jest-get-type": "^26.3.0",
+        "pretty-format": "^26.4.2"
       },
       "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "chalk": {
+        "@types/istanbul-reports": {
           "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "color-name": "~1.1.4"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
         },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+        "jest-get-type": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz",
+          "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==",
           "dev": true
         },
-        "find-up": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+        "pretty-format": {
+          "version": "26.4.2",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.4.2.tgz",
+          "integrity": "sha512-zK6Gd8zDsEiVydOCGLkoBoZuqv8VTiHyAbKznXe/gaph/DAeZOmit9yMfgIz5adIgAMMs5XfoYSwAX3jcCO1tA==",
           "dev": true,
           "requires": {
-            "locate-path": "^5.0.0",
-            "path-exists": "^4.0.0"
+            "@jest/types": "^26.3.0",
+            "ansi-regex": "^5.0.0",
+            "ansi-styles": "^4.0.0",
+            "react-is": "^16.12.0"
           }
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "locate-path": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+        }
+      }
+    },
+    "jest-matcher-utils": {
+      "version": "26.4.2",
+      "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.4.2.tgz",
+      "integrity": "sha512-KcbNqWfWUG24R7tu9WcAOKKdiXiXCbMvQYT6iodZ9k1f7065k0keUOW6XpJMMvah+hTfqkhJhRXmA3r3zMAg0Q==",
+      "dev": true,
+      "requires": {
+        "chalk": "^4.0.0",
+        "jest-diff": "^26.4.2",
+        "jest-get-type": "^26.3.0",
+        "pretty-format": "^26.4.2"
+      },
+      "dependencies": {
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "p-locate": "^4.1.0"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "p-locate": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+        "@types/istanbul-reports": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "p-limit": "^2.2.0"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "parse-json": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz",
-          "integrity": "sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw==",
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "@babel/code-frame": "^7.0.0",
-            "error-ex": "^1.3.1",
-            "json-parse-better-errors": "^1.0.1",
-            "lines-and-columns": "^1.1.6"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
         },
-        "path-exists": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-          "dev": true
-        },
-        "path-parse": {
-          "version": "1.0.6",
-          "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
-          "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+        "diff-sequences": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.3.0.tgz",
+          "integrity": "sha512-5j5vdRcw3CNctePNYN0Wy2e/JbWT6cAYnXv5OuqPhDpyCGc0uLu2TK0zOCJWNB9kOIfYMSpIulRaDgIi4HJ6Ig==",
           "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==",
+        "jest-diff": {
+          "version": "26.4.2",
+          "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.4.2.tgz",
+          "integrity": "sha512-6T1XQY8U28WH0Z5rGpQ+VqZSZz8EN8rZcBtfvXaOkbwxIEeRre6qnuZQlbY1AJ4MKDxQF8EkrCvK+hL/VkyYLQ==",
           "dev": true,
           "requires": {
-            "find-up": "^4.1.0",
-            "read-pkg": "^5.2.0",
-            "type-fest": "^0.8.1"
+            "chalk": "^4.0.0",
+            "diff-sequences": "^26.3.0",
+            "jest-get-type": "^26.3.0",
+            "pretty-format": "^26.4.2"
           }
         },
-        "resolve": {
-          "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"
-          }
+        "jest-get-type": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz",
+          "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==",
+          "dev": true
         },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+        "pretty-format": {
+          "version": "26.4.2",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.4.2.tgz",
+          "integrity": "sha512-zK6Gd8zDsEiVydOCGLkoBoZuqv8VTiHyAbKznXe/gaph/DAeZOmit9yMfgIz5adIgAMMs5XfoYSwAX3jcCO1tA==",
           "dev": true,
           "requires": {
-            "has-flag": "^4.0.0"
+            "@jest/types": "^26.3.0",
+            "ansi-regex": "^5.0.0",
+            "ansi-styles": "^4.0.0",
+            "react-is": "^16.12.0"
           }
         }
       }
     },
-    "jest-resolve-dependencies": {
-      "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.4.0",
-        "jest-regex-util": "^25.2.6",
-        "jest-snapshot": "^25.4.0"
-      }
-    },
-    "jest-runner": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-25.4.0.tgz",
-      "integrity": "sha512-wWQSbVgj2e/1chFdMRKZdvlmA6p1IPujhpLT7TKNtCSl1B0PGBGvJjCaiBal/twaU2yfk8VKezHWexM8IliBfA==",
+    "jest-message-util": {
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.3.0.tgz",
+      "integrity": "sha512-xIavRYqr4/otGOiLxLZGj3ieMmjcNE73Ui+LdSW/Y790j5acqCsAdDiLIbzHCZMpN07JOENRWX5DcU+OQ+TjTA==",
       "dev": true,
       "requires": {
-        "@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.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"
+        "@babel/code-frame": "^7.0.0",
+        "@jest/types": "^26.3.0",
+        "@types/stack-utils": "^1.0.1",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.4",
+        "micromatch": "^4.0.2",
+        "slash": "^3.0.0",
+        "stack-utils": "^2.0.2"
       },
       "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "chalk": {
+        "@types/istanbul-reports": {
           "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
+          "dev": true,
+          "requires": {
+            "@types/istanbul-lib-report": "*"
+          }
+        },
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
             "ansi-styles": "^4.1.0",
             "supports-color": "^7.1.0"
           }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        }
+      }
+    },
+    "jest-mock": {
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.3.0.tgz",
+      "integrity": "sha512-PeaRrg8Dc6mnS35gOo/CbZovoDPKAeB1FICZiuagAgGvbWdNNyjQjkOaGUa/3N3JtpQ/Mh9P4A2D4Fv51NnP8Q==",
+      "dev": true,
+      "requires": {
+        "@jest/types": "^26.3.0",
+        "@types/node": "*"
+      },
+      "dependencies": {
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "color-name": "~1.1.4"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "graceful-fs": {
-          "version": "4.2.3",
-          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
-          "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "jest-worker": {
-          "version": "25.4.0",
-          "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.4.0.tgz",
-          "integrity": "sha512-ghAs/1FtfYpMmYQ0AHqxV62XPvKdUDIBBApMZfly+E9JEmYh2K45G0R5dWxx986RN12pRCxsViwQVtGl+N4whw==",
+        "@types/istanbul-reports": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "merge-stream": "^2.0.0",
-            "supports-color": "^7.0.0"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "has-flag": "^4.0.0"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
         }
       }
     },
-    "jest-runtime": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-25.4.0.tgz",
-      "integrity": "sha512-lgNJlCDULtXu9FumnwCyWlOub8iytijwsPNa30BKrSNtgoT6NUMXOPrZvsH06U6v0wgD/Igwz13nKA2wEKU2VA==",
+    "jest-pnp-resolver": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz",
+      "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==",
+      "dev": true
+    },
+    "jest-regex-util": {
+      "version": "26.0.0",
+      "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz",
+      "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==",
+      "dev": true
+    },
+    "jest-resolve": {
+      "version": "26.4.0",
+      "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.4.0.tgz",
+      "integrity": "sha512-bn/JoZTEXRSlEx3+SfgZcJAVuTMOksYq9xe9O6s4Ekg84aKBObEaVXKOEilULRqviSLAYJldnoWV9c07kwtiCg==",
       "dev": true,
       "requires": {
-        "@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.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",
-        "yargs": "^15.3.1"
+        "@jest/types": "^26.3.0",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.4",
+        "jest-pnp-resolver": "^1.2.2",
+        "jest-util": "^26.3.0",
+        "read-pkg-up": "^7.0.1",
+        "resolve": "^1.17.0",
+        "slash": "^3.0.0"
       },
       "dependencies": {
-        "ansi-regex": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
-          "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
-          "dev": true
-        },
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "camelcase": {
-          "version": "5.3.1",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
-          "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
-          "dev": true
+        "@types/istanbul-reports": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
+          "dev": true,
+          "requires": {
+            "@types/istanbul-lib-report": "*"
+          }
         },
         "chalk": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
             "ansi-styles": "^4.1.0",
             "supports-color": "^7.1.0"
           }
-        },
-        "cliui": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
-          "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+        }
+      }
+    },
+    "jest-resolve-dependencies": {
+      "version": "26.4.2",
+      "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.4.2.tgz",
+      "integrity": "sha512-ADHaOwqEcVc71uTfySzSowA/RdxUpCxhxa2FNLiin9vWLB1uLPad3we+JSSROq5+SrL9iYPdZZF8bdKM7XABTQ==",
+      "dev": true,
+      "requires": {
+        "@jest/types": "^26.3.0",
+        "jest-regex-util": "^26.0.0",
+        "jest-snapshot": "^26.4.2"
+      },
+      "dependencies": {
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "string-width": "^4.2.0",
-            "strip-ansi": "^6.0.0",
-            "wrap-ansi": "^6.2.0"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "@types/istanbul-reports": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "color-name": "~1.1.4"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "emoji-regex": {
-          "version": "8.0.0",
-          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-          "dev": true
-        },
-        "find-up": {
+        "chalk": {
           "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "locate-path": "^5.0.0",
-            "path-exists": "^4.0.0"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
-        },
-        "get-caller-file": {
-          "version": "2.0.5",
-          "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
-          "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
-          "dev": true
-        },
-        "glob": {
-          "version": "7.1.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+        }
+      }
+    },
+    "jest-runner": {
+      "version": "26.4.2",
+      "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.4.2.tgz",
+      "integrity": "sha512-FgjDHeVknDjw1gRAYaoUoShe1K3XUuFMkIaXbdhEys+1O4bEJS8Avmn4lBwoMfL8O5oFTdWYKcf3tEJyyYyk8g==",
+      "dev": true,
+      "requires": {
+        "@jest/console": "^26.3.0",
+        "@jest/environment": "^26.3.0",
+        "@jest/test-result": "^26.3.0",
+        "@jest/types": "^26.3.0",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "emittery": "^0.7.1",
+        "exit": "^0.1.2",
+        "graceful-fs": "^4.2.4",
+        "jest-config": "^26.4.2",
+        "jest-docblock": "^26.0.0",
+        "jest-haste-map": "^26.3.0",
+        "jest-leak-detector": "^26.4.2",
+        "jest-message-util": "^26.3.0",
+        "jest-resolve": "^26.4.0",
+        "jest-runtime": "^26.4.2",
+        "jest-util": "^26.3.0",
+        "jest-worker": "^26.3.0",
+        "source-map-support": "^0.5.6",
+        "throat": "^5.0.0"
+      },
+      "dependencies": {
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "graceful-fs": {
-          "version": "4.2.3",
-          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz",
-          "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "is-fullwidth-code-point": {
+        "@types/istanbul-reports": {
           "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
-          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
-          "dev": true
-        },
-        "locate-path": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "p-locate": "^4.1.0"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "p-locate": {
+        "chalk": {
           "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^2.2.0"
-          }
-        },
-        "path-exists": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-          "dev": true
-        },
-        "require-main-filename": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
-          "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
-          "dev": true
-        },
-        "string-width": {
-          "version": "4.2.0",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
-          "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^8.0.0",
-            "is-fullwidth-code-point": "^3.0.0",
-            "strip-ansi": "^6.0.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
-          "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "ansi-regex": "^5.0.0"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
         },
-        "strip-bom": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
-          "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+        "jest-worker": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.3.0.tgz",
+          "integrity": "sha512-Vmpn2F6IASefL+DVBhPzI2J9/GJUsqzomdeN+P+dK8/jKxbh8R3BtFnx3FIta7wYlPU62cpJMJQo4kuOowcMnw==",
           "dev": true,
           "requires": {
-            "has-flag": "^4.0.0"
+            "@types/node": "*",
+            "merge-stream": "^2.0.0",
+            "supports-color": "^7.0.0"
           }
-        },
-        "which-module": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
-          "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
-          "dev": true
-        },
-        "wrap-ansi": {
-          "version": "6.2.0",
-          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
-          "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+        }
+      }
+    },
+    "jest-runtime": {
+      "version": "26.4.2",
+      "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.4.2.tgz",
+      "integrity": "sha512-4Pe7Uk5a80FnbHwSOk7ojNCJvz3Ks2CNQWT5Z7MJo4tX0jb3V/LThKvD9tKPNVNyeMH98J/nzGlcwc00R2dSHQ==",
+      "dev": true,
+      "requires": {
+        "@jest/console": "^26.3.0",
+        "@jest/environment": "^26.3.0",
+        "@jest/fake-timers": "^26.3.0",
+        "@jest/globals": "^26.4.2",
+        "@jest/source-map": "^26.3.0",
+        "@jest/test-result": "^26.3.0",
+        "@jest/transform": "^26.3.0",
+        "@jest/types": "^26.3.0",
+        "@types/yargs": "^15.0.0",
+        "chalk": "^4.0.0",
+        "collect-v8-coverage": "^1.0.0",
+        "exit": "^0.1.2",
+        "glob": "^7.1.3",
+        "graceful-fs": "^4.2.4",
+        "jest-config": "^26.4.2",
+        "jest-haste-map": "^26.3.0",
+        "jest-message-util": "^26.3.0",
+        "jest-mock": "^26.3.0",
+        "jest-regex-util": "^26.0.0",
+        "jest-resolve": "^26.4.0",
+        "jest-snapshot": "^26.4.2",
+        "jest-util": "^26.3.0",
+        "jest-validate": "^26.4.2",
+        "slash": "^3.0.0",
+        "strip-bom": "^4.0.0",
+        "yargs": "^15.3.1"
+      },
+      "dependencies": {
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "ansi-styles": "^4.0.0",
-            "string-width": "^4.1.0",
-            "strip-ansi": "^6.0.0"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "y18n": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
-          "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
-          "dev": true
-        },
-        "yargs": {
-          "version": "15.3.1",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz",
-          "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==",
+        "@types/istanbul-reports": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "cliui": "^6.0.0",
-            "decamelize": "^1.2.0",
-            "find-up": "^4.1.0",
-            "get-caller-file": "^2.0.1",
-            "require-directory": "^2.1.1",
-            "require-main-filename": "^2.0.0",
-            "set-blocking": "^2.0.0",
-            "string-width": "^4.2.0",
-            "which-module": "^2.0.0",
-            "y18n": "^4.0.0",
-            "yargs-parser": "^18.1.1"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "yargs-parser": {
-          "version": "18.1.3",
-          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
-          "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "camelcase": "^5.0.0",
-            "decamelize": "^1.2.0"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
         }
       }
     },
     "jest-serializer": {
-      "version": "25.2.6",
-      "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-25.2.6.tgz",
-      "integrity": "sha512-RMVCfZsezQS2Ww4kB5HJTMaMJ0asmC0BHlnobQC6yEtxiFKIxohFA4QSXSabKwSggaNkqxn6Z2VwdFCjhUWuiQ==",
-      "dev": true
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.3.0.tgz",
+      "integrity": "sha512-IDRBQBLPlKa4flg77fqg0n/pH87tcRKwe8zxOVTWISxGpPHYkRZ1dXKyh04JOja7gppc60+soKVZ791mruVdow==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*",
+        "graceful-fs": "^4.2.4"
+      }
     },
     "jest-snapshot": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-25.4.0.tgz",
-      "integrity": "sha512-J4CJ0X2SaGheYRZdLz9CRHn9jUknVmlks4UBeu270hPAvdsauFXOhx9SQP2JtRzhnR3cvro/9N9KP83/uvFfRg==",
+      "version": "26.4.2",
+      "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.4.2.tgz",
+      "integrity": "sha512-N6Uub8FccKlf5SBFnL2Ri/xofbaA68Cc3MGjP/NuwgnsvWh+9hLIR/DhrxbSiKXMY9vUW5dI6EW1eHaDHqe9sg==",
       "dev": true,
       "requires": {
         "@babel/types": "^7.0.0",
-        "@jest/types": "^25.4.0",
-        "@types/prettier": "^1.19.0",
-        "chalk": "^3.0.0",
-        "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",
+        "@jest/types": "^26.3.0",
+        "@types/prettier": "^2.0.0",
+        "chalk": "^4.0.0",
+        "expect": "^26.4.2",
+        "graceful-fs": "^4.2.4",
+        "jest-diff": "^26.4.2",
+        "jest-get-type": "^26.3.0",
+        "jest-haste-map": "^26.3.0",
+        "jest-matcher-utils": "^26.4.2",
+        "jest-message-util": "^26.3.0",
+        "jest-resolve": "^26.4.0",
         "natural-compare": "^1.4.0",
-        "pretty-format": "^25.4.0",
-        "semver": "^6.3.0"
+        "pretty-format": "^26.4.2",
+        "semver": "^7.3.2"
       },
       "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "chalk": {
+        "@types/istanbul-reports": {
           "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "color-name": "~1.1.4"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
         },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+        "diff-sequences": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.3.0.tgz",
+          "integrity": "sha512-5j5vdRcw3CNctePNYN0Wy2e/JbWT6cAYnXv5OuqPhDpyCGc0uLu2TK0zOCJWNB9kOIfYMSpIulRaDgIi4HJ6Ig==",
           "dev": true
         },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
+        "jest-diff": {
+          "version": "26.4.2",
+          "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.4.2.tgz",
+          "integrity": "sha512-6T1XQY8U28WH0Z5rGpQ+VqZSZz8EN8rZcBtfvXaOkbwxIEeRre6qnuZQlbY1AJ4MKDxQF8EkrCvK+hL/VkyYLQ==",
+          "dev": true,
+          "requires": {
+            "chalk": "^4.0.0",
+            "diff-sequences": "^26.3.0",
+            "jest-get-type": "^26.3.0",
+            "pretty-format": "^26.4.2"
+          }
         },
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+        "jest-get-type": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz",
+          "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==",
           "dev": true
         },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+        "pretty-format": {
+          "version": "26.4.2",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.4.2.tgz",
+          "integrity": "sha512-zK6Gd8zDsEiVydOCGLkoBoZuqv8VTiHyAbKznXe/gaph/DAeZOmit9yMfgIz5adIgAMMs5XfoYSwAX3jcCO1tA==",
           "dev": true,
           "requires": {
-            "has-flag": "^4.0.0"
+            "@jest/types": "^26.3.0",
+            "ansi-regex": "^5.0.0",
+            "ansi-styles": "^4.0.0",
+            "react-is": "^16.12.0"
           }
         }
       }
     },
     "jest-util": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-25.4.0.tgz",
-      "integrity": "sha512-WSZD59sBtAUjLv1hMeKbNZXmMcrLRWcYqpO8Dz8b4CeCTZpfNQw2q9uwrYAD+BbJoLJlu4ezVPwtAmM/9/SlZA==",
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.3.0.tgz",
+      "integrity": "sha512-4zpn6bwV0+AMFN0IYhH/wnzIQzRaYVrz1A8sYnRnj4UXDXbOVtWmlaZkO9mipFqZ13okIfN87aDoJWB7VH6hcw==",
       "dev": true,
       "requires": {
-        "@jest/types": "^25.4.0",
-        "chalk": "^3.0.0",
+        "@jest/types": "^26.3.0",
+        "@types/node": "*",
+        "chalk": "^4.0.0",
+        "graceful-fs": "^4.2.4",
         "is-ci": "^2.0.0",
-        "make-dir": "^3.0.0"
+        "micromatch": "^4.0.2"
       },
       "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "chalk": {
+        "@types/istanbul-reports": {
           "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "color-name": "~1.1.4"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "has-flag": "^4.0.0"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
         }
       }
     },
     "jest-validate": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-25.4.0.tgz",
-      "integrity": "sha512-hvjmes/EFVJSoeP1yOl8qR8mAtMR3ToBkZeXrD/ZS9VxRyWDqQ/E1C5ucMTeSmEOGLipvdlyipiGbHJ+R1MQ0g==",
+      "version": "26.4.2",
+      "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.4.2.tgz",
+      "integrity": "sha512-blft+xDX7XXghfhY0mrsBCYhX365n8K5wNDC4XAcNKqqjEzsRUSXP44m6PL0QJEW2crxQFLLztVnJ4j7oPlQrQ==",
       "dev": true,
       "requires": {
-        "@jest/types": "^25.4.0",
-        "camelcase": "^5.3.1",
-        "chalk": "^3.0.0",
-        "jest-get-type": "^25.2.6",
+        "@jest/types": "^26.3.0",
+        "camelcase": "^6.0.0",
+        "chalk": "^4.0.0",
+        "jest-get-type": "^26.3.0",
         "leven": "^3.1.0",
-        "pretty-format": "^25.4.0"
+        "pretty-format": "^26.4.2"
       },
       "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
+          "dev": true,
+          "requires": {
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
+          }
+        },
+        "@types/istanbul-reports": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
+            "@types/istanbul-lib-report": "*"
           }
         },
         "camelcase": {
-          "version": "5.3.1",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
-          "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.0.0.tgz",
+          "integrity": "sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w==",
           "dev": true
         },
         "chalk": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
             "ansi-styles": "^4.1.0",
             "supports-color": "^7.1.0"
           }
         },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-          "dev": true,
-          "requires": {
-            "color-name": "~1.1.4"
-          }
-        },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+        "jest-get-type": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz",
+          "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==",
           "dev": true
         },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+        "pretty-format": {
+          "version": "26.4.2",
+          "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.4.2.tgz",
+          "integrity": "sha512-zK6Gd8zDsEiVydOCGLkoBoZuqv8VTiHyAbKznXe/gaph/DAeZOmit9yMfgIz5adIgAMMs5XfoYSwAX3jcCO1tA==",
           "dev": true,
           "requires": {
-            "has-flag": "^4.0.0"
+            "@jest/types": "^26.3.0",
+            "ansi-regex": "^5.0.0",
+            "ansi-styles": "^4.0.0",
+            "react-is": "^16.12.0"
           }
         }
       }
     },
     "jest-watcher": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-25.4.0.tgz",
-      "integrity": "sha512-36IUfOSRELsKLB7k25j/wutx0aVuHFN6wO94gPNjQtQqFPa2rkOymmx9rM5EzbF3XBZZ2oqD9xbRVoYa2w86gw==",
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.3.0.tgz",
+      "integrity": "sha512-XnLdKmyCGJ3VoF6G/p5ohbJ04q/vv5aH9ENI+i6BL0uu9WWB6Z7Z2lhQQk0d2AVZcRGp1yW+/TsoToMhBFPRdQ==",
       "dev": true,
       "requires": {
-        "@jest/test-result": "^25.4.0",
-        "@jest/types": "^25.4.0",
+        "@jest/test-result": "^26.3.0",
+        "@jest/types": "^26.3.0",
+        "@types/node": "*",
         "ansi-escapes": "^4.2.1",
-        "chalk": "^3.0.0",
-        "jest-util": "^25.4.0",
-        "string-length": "^3.1.0"
+        "chalk": "^4.0.0",
+        "jest-util": "^26.3.0",
+        "string-length": "^4.0.1"
       },
       "dependencies": {
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
+        "@jest/types": {
+          "version": "26.3.0",
+          "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.3.0.tgz",
+          "integrity": "sha512-BDPG23U0qDeAvU4f99haztXwdAg3hz4El95LkAM+tHAqqhiVzRpEGHHU8EDxT/AnxOrA65YjLBwDahdJ9pTLJQ==",
           "dev": true,
           "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
+            "@types/istanbul-lib-coverage": "^2.0.0",
+            "@types/istanbul-reports": "^3.0.0",
+            "@types/node": "*",
+            "@types/yargs": "^15.0.0",
+            "chalk": "^4.0.0"
           }
         },
-        "chalk": {
+        "@types/istanbul-reports": {
           "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
-          "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz",
+          "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==",
           "dev": true,
           "requires": {
-            "color-name": "~1.1.4"
+            "@types/istanbul-lib-report": "*"
           }
         },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
           "dev": true,
           "requires": {
-            "has-flag": "^4.0.0"
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
           }
         }
       }
     },
     "jest-worker": {
-      "version": "24.9.0",
-      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz",
-      "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==",
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.3.0.tgz",
+      "integrity": "sha512-Vmpn2F6IASefL+DVBhPzI2J9/GJUsqzomdeN+P+dK8/jKxbh8R3BtFnx3FIta7wYlPU62cpJMJQo4kuOowcMnw==",
       "dev": true,
       "requires": {
+        "@types/node": "*",
         "merge-stream": "^2.0.0",
-        "supports-color": "^6.1.0"
-      },
-      "dependencies": {
-        "has-flag": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "6.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
-          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
-        }
+        "supports-color": "^7.0.0"
       }
     },
+    "js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true
+    },
     "js-yaml": {
-      "version": "3.13.1",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
-      "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
+      "version": "3.14.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
+      "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
       "dev": true,
       "requires": {
         "argparse": "^1.0.7",
@@ -8566,71 +4849,37 @@
       "dev": true
     },
     "jsdom": {
-      "version": "15.2.1",
-      "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-15.2.1.tgz",
-      "integrity": "sha512-fAl1W0/7T2G5vURSyxBzrJ1LSdQn6Tr5UX/xD4PXDx/PDgwygedfW6El/KIj3xJ7FU61TTYnc/l/B7P49Eqt6g==",
-      "dev": true,
-      "requires": {
-        "abab": "^2.0.0",
-        "acorn": "^7.1.0",
-        "acorn-globals": "^4.3.2",
-        "array-equal": "^1.0.0",
-        "cssom": "^0.4.1",
-        "cssstyle": "^2.0.0",
-        "data-urls": "^1.1.0",
-        "domexception": "^1.0.1",
-        "escodegen": "^1.11.1",
-        "html-encoding-sniffer": "^1.0.2",
+      "version": "16.4.0",
+      "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.4.0.tgz",
+      "integrity": "sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==",
+      "dev": true,
+      "requires": {
+        "abab": "^2.0.3",
+        "acorn": "^7.1.1",
+        "acorn-globals": "^6.0.0",
+        "cssom": "^0.4.4",
+        "cssstyle": "^2.2.0",
+        "data-urls": "^2.0.0",
+        "decimal.js": "^10.2.0",
+        "domexception": "^2.0.1",
+        "escodegen": "^1.14.1",
+        "html-encoding-sniffer": "^2.0.1",
+        "is-potential-custom-element-name": "^1.0.0",
         "nwsapi": "^2.2.0",
-        "parse5": "5.1.0",
-        "pn": "^1.1.0",
-        "request": "^2.88.0",
-        "request-promise-native": "^1.0.7",
-        "saxes": "^3.1.9",
-        "symbol-tree": "^3.2.2",
+        "parse5": "5.1.1",
+        "request": "^2.88.2",
+        "request-promise-native": "^1.0.8",
+        "saxes": "^5.0.0",
+        "symbol-tree": "^3.2.4",
         "tough-cookie": "^3.0.1",
-        "w3c-hr-time": "^1.0.1",
-        "w3c-xmlserializer": "^1.1.2",
-        "webidl-conversions": "^4.0.2",
+        "w3c-hr-time": "^1.0.2",
+        "w3c-xmlserializer": "^2.0.0",
+        "webidl-conversions": "^6.1.0",
         "whatwg-encoding": "^1.0.5",
         "whatwg-mimetype": "^2.3.0",
-        "whatwg-url": "^7.0.0",
-        "ws": "^7.0.0",
+        "whatwg-url": "^8.0.0",
+        "ws": "^7.2.3",
         "xml-name-validator": "^3.0.0"
-      },
-      "dependencies": {
-        "escodegen": {
-          "version": "1.14.1",
-          "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz",
-          "integrity": "sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ==",
-          "dev": true,
-          "requires": {
-            "esprima": "^4.0.1",
-            "estraverse": "^4.2.0",
-            "esutils": "^2.0.2",
-            "optionator": "^0.8.1",
-            "source-map": "~0.6.1"
-          }
-        },
-        "esprima": {
-          "version": "4.0.1",
-          "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
-          "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
-          "dev": true
-        },
-        "estraverse": {
-          "version": "4.3.0",
-          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
-          "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true,
-          "optional": true
-        }
       }
     },
     "jsesc": {
@@ -8676,22 +4925,8 @@
       "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
-        }
       }
     },
-    "jsonparse": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
-      "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
-      "dev": true
-    },
     "jsprim": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
@@ -8704,16 +4939,10 @@
         "verror": "1.10.0"
       }
     },
-    "just-debounce": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz",
-      "integrity": "sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=",
-      "dev": true
-    },
     "kind-of": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
-      "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
       "dev": true
     },
     "kleur": {
@@ -8722,150 +4951,148 @@
       "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
       "dev": true
     },
-    "last-run": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz",
-      "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=",
+    "leven": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
+      "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
+      "dev": true
+    },
+    "levn": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+      "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
       "dev": true,
       "requires": {
-        "default-resolution": "^2.0.0",
-        "es6-weak-map": "^2.0.1"
+        "prelude-ls": "^1.2.1",
+        "type-check": "~0.4.0"
       }
     },
-    "lazystream": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
-      "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
+    "libphonenumber-js": {
+      "version": "1.7.57",
+      "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.7.57.tgz",
+      "integrity": "sha512-v6DkRf1ufgGXHb6NoKbQd1YlfWqOs6jym7WjPP+YF1YtbfiWwD7M/7/XUOW+if2jNlm5av4EzeL/lYf8ClJYjg==",
+      "requires": {
+        "minimist": "^1.2.5",
+        "xml2js": "^0.4.17"
+      }
+    },
+    "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
+    },
+    "lint-staged": {
+      "version": "10.4.0",
+      "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.4.0.tgz",
+      "integrity": "sha512-uaiX4U5yERUSiIEQc329vhCTDDwUcSvKdRLsNomkYLRzijk3v8V9GWm2Nz0RMVB87VcuzLvtgy6OsjoH++QHIg==",
       "dev": true,
       "requires": {
-        "readable-stream": "^2.0.5"
+        "chalk": "^4.1.0",
+        "cli-truncate": "^2.1.0",
+        "commander": "^6.0.0",
+        "cosmiconfig": "^7.0.0",
+        "debug": "^4.1.1",
+        "dedent": "^0.7.0",
+        "enquirer": "^2.3.6",
+        "execa": "^4.0.3",
+        "listr2": "^2.6.0",
+        "log-symbols": "^4.0.0",
+        "micromatch": "^4.0.2",
+        "normalize-path": "^3.0.0",
+        "please-upgrade-node": "^3.2.0",
+        "string-argv": "0.3.1",
+        "stringify-object": "^3.3.0"
       },
       "dependencies": {
-        "isarray": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
-          "dev": true
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
         },
-        "readable-stream": {
-          "version": "2.3.6",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
+        "execa": {
+          "version": "4.0.3",
+          "resolved": "https://registry.npmjs.org/execa/-/execa-4.0.3.tgz",
+          "integrity": "sha512-WFDXGHckXPWZX19t1kCsXzOpqX9LWYNqn4C+HqZlk/V0imTkzJZqf87ZBhvpHaftERYknpk0fjSylnXVlVgI0A==",
           "dev": true,
           "requires": {
-            "core-util-is": "~1.0.0",
-            "inherits": "~2.0.3",
-            "isarray": "~1.0.0",
-            "process-nextick-args": "~2.0.0",
-            "safe-buffer": "~5.1.1",
-            "string_decoder": "~1.1.1",
-            "util-deprecate": "~1.0.1"
+            "cross-spawn": "^7.0.0",
+            "get-stream": "^5.0.0",
+            "human-signals": "^1.1.1",
+            "is-stream": "^2.0.0",
+            "merge-stream": "^2.0.0",
+            "npm-run-path": "^4.0.0",
+            "onetime": "^5.1.0",
+            "signal-exit": "^3.0.2",
+            "strip-final-newline": "^2.0.0"
           }
         },
-        "string_decoder": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+        "get-stream": {
+          "version": "5.2.0",
+          "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
+          "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
           "dev": true,
           "requires": {
-            "safe-buffer": "~5.1.0"
+            "pump": "^3.0.0"
           }
-        }
-      }
-    },
-    "lcid": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
-      "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
-      "dev": true,
-      "requires": {
-        "invert-kv": "^1.0.0"
-      }
-    },
-    "lead": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz",
-      "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=",
-      "dev": true,
-      "requires": {
-        "flush-write-stream": "^1.0.2"
-      }
-    },
-    "leven": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
-      "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
-      "dev": true
-    },
-    "levn": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
-      "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
-      "dev": true,
-      "requires": {
-        "prelude-ls": "~1.1.2",
-        "type-check": "~0.3.2"
-      }
-    },
-    "liftoff": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz",
-      "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==",
-      "dev": true,
-      "requires": {
-        "extend": "^3.0.0",
-        "findup-sync": "^3.0.0",
-        "fined": "^1.0.1",
-        "flagged-respawn": "^1.0.0",
-        "is-plain-object": "^2.0.4",
-        "object.map": "^1.0.0",
-        "rechoir": "^0.6.2",
-        "resolve": "^1.1.7"
+        },
+        "is-stream": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
+          "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
+          "dev": true
+        },
+        "npm-run-path": {
+          "version": "4.0.1",
+          "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+          "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+          "dev": true,
+          "requires": {
+            "path-key": "^3.0.0"
+          }
+        }
       }
     },
-    "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
-    },
-    "load-json-file": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
-      "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
+    "listr2": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/listr2/-/listr2-2.6.2.tgz",
+      "integrity": "sha512-6x6pKEMs8DSIpA/tixiYY2m/GcbgMplMVmhQAaLFxEtNSKLeWTGjtmU57xvv6QCm2XcqzyNXL/cTSVf4IChCRA==",
       "dev": true,
       "requires": {
-        "graceful-fs": "^4.1.2",
-        "parse-json": "^2.2.0",
-        "pify": "^2.0.0",
-        "pinkie-promise": "^2.0.0",
-        "strip-bom": "^2.0.0"
+        "chalk": "^4.1.0",
+        "cli-truncate": "^2.1.0",
+        "figures": "^3.2.0",
+        "indent-string": "^4.0.0",
+        "log-update": "^4.0.0",
+        "p-map": "^4.0.0",
+        "rxjs": "^6.6.2",
+        "through": "^2.3.8"
       },
       "dependencies": {
-        "pify": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
-          "dev": true
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
         }
       }
     },
     "locate-path": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
-      "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
       "dev": true,
       "requires": {
-        "p-locate": "^2.0.0",
-        "path-exists": "^3.0.0"
-      },
-      "dependencies": {
-        "path-exists": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
-          "dev": true
-        }
+        "p-locate": "^4.1.0"
       }
     },
     "lodash": {
@@ -8874,18 +5101,6 @@
       "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==",
       "dev": true
     },
-    "lodash._reinterpolate": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
-      "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=",
-      "dev": true
-    },
-    "lodash.ismatch": {
-      "version": "4.4.0",
-      "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz",
-      "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=",
-      "dev": true
-    },
     "lodash.memoize": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -8898,51 +5113,62 @@
       "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
       "dev": true
     },
-    "lodash.template": {
-      "version": "4.5.0",
-      "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz",
-      "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==",
-      "dev": true,
-      "requires": {
-        "lodash._reinterpolate": "^3.0.0",
-        "lodash.templatesettings": "^4.0.0"
-      }
-    },
-    "lodash.templatesettings": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz",
-      "integrity": "sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=",
-      "dev": true,
-      "requires": {
-        "lodash._reinterpolate": "~3.0.0"
-      }
-    },
-    "lolex": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/lolex/-/lolex-5.1.2.tgz",
-      "integrity": "sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A==",
-      "dev": true,
-      "requires": {
-        "@sinonjs/commons": "^1.7.0"
-      }
-    },
-    "loud-rejection": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
-      "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
+    "log-symbols": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz",
+      "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==",
       "dev": true,
       "requires": {
-        "currently-unhandled": "^0.4.1",
-        "signal-exit": "^3.0.0"
+        "chalk": "^4.0.0"
+      },
+      "dependencies": {
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        }
       }
     },
-    "lru-queue": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz",
-      "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=",
+    "log-update": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz",
+      "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==",
       "dev": true,
       "requires": {
-        "es5-ext": "~0.10.2"
+        "ansi-escapes": "^4.3.0",
+        "cli-cursor": "^3.1.0",
+        "slice-ansi": "^4.0.0",
+        "wrap-ansi": "^6.2.0"
+      },
+      "dependencies": {
+        "astral-regex": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+          "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+          "dev": true
+        },
+        "slice-ansi": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+          "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.0.0",
+            "astral-regex": "^2.0.0",
+            "is-fullwidth-code-point": "^3.0.0"
+          }
+        }
       }
     },
     "magic-string": {
@@ -8972,20 +5198,11 @@
       }
     },
     "make-error": {
-      "version": "1.3.5",
-      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.5.tgz",
-      "integrity": "sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g==",
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
       "dev": true
     },
-    "make-iterator": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz",
-      "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==",
-      "dev": true,
-      "requires": {
-        "kind-of": "^6.0.2"
-      }
-    },
     "makeerror": {
       "version": "1.0.11",
       "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz",
@@ -9001,18 +5218,6 @@
       "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
       "dev": true
     },
-    "map-obj": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-2.0.0.tgz",
-      "integrity": "sha1-plzSkIepJZi4eRJXpSPgISIqwfk=",
-      "dev": true
-    },
-    "map-stream": {
-      "version": "0.0.7",
-      "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz",
-      "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=",
-      "dev": true
-    },
     "map-visit": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
@@ -9022,229 +5227,35 @@
         "object-visit": "^1.0.0"
       }
     },
-    "matchdep": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz",
-      "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=",
-      "dev": true,
-      "requires": {
-        "findup-sync": "^2.0.0",
-        "micromatch": "^3.0.4",
-        "resolve": "^1.4.0",
-        "stack-trace": "0.0.10"
-      },
-      "dependencies": {
-        "findup-sync": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz",
-          "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=",
-          "dev": true,
-          "requires": {
-            "detect-file": "^1.0.0",
-            "is-glob": "^3.1.0",
-            "micromatch": "^3.0.4",
-            "resolve-dir": "^1.0.1"
-          }
-        }
-      }
-    },
-    "mdn-browser-compat-data": {
-      "version": "1.0.19",
-      "resolved": "https://registry.npmjs.org/mdn-browser-compat-data/-/mdn-browser-compat-data-1.0.19.tgz",
-      "integrity": "sha512-S1i9iILAsFi/C17NADg2cBT6D6Xcd5Ub+GSMQa5ScLhuVyUrRKjCNmFEED9mQ2G/lrKtvU9SGUrpPpXB8SXhCg==",
-      "dev": true,
-      "requires": {
-        "extend": "3.0.2"
-      }
-    },
-    "memoizee": {
-      "version": "0.4.12",
-      "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.12.tgz",
-      "integrity": "sha512-sprBu6nwxBWBvBOh5v2jcsGqiGLlL2xr2dLub3vR8dnE8YB17omwtm/0NSHl8jjNbcsJd5GMWJAnTSVe/O0Wfg==",
-      "dev": true,
-      "requires": {
-        "d": "1",
-        "es5-ext": "^0.10.30",
-        "es6-weak-map": "^2.0.2",
-        "event-emitter": "^0.3.5",
-        "is-promise": "^2.1",
-        "lru-queue": "0.1",
-        "next-tick": "1",
-        "timers-ext": "^0.1.2"
-      }
-    },
-    "meow": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/meow/-/meow-4.0.1.tgz",
-      "integrity": "sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A==",
-      "dev": true,
-      "requires": {
-        "camelcase-keys": "^4.0.0",
-        "decamelize-keys": "^1.0.0",
-        "loud-rejection": "^1.0.0",
-        "minimist": "^1.1.3",
-        "minimist-options": "^3.0.1",
-        "normalize-package-data": "^2.3.4",
-        "read-pkg-up": "^3.0.0",
-        "redent": "^2.0.0",
-        "trim-newlines": "^2.0.0"
-      },
-      "dependencies": {
-        "find-up": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
-          "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
-          "dev": true,
-          "requires": {
-            "locate-path": "^2.0.0"
-          }
-        },
-        "load-json-file": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
-          "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=",
-          "dev": true,
-          "requires": {
-            "graceful-fs": "^4.1.2",
-            "parse-json": "^4.0.0",
-            "pify": "^3.0.0",
-            "strip-bom": "^3.0.0"
-          }
-        },
-        "locate-path": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
-          "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
-          "dev": true,
-          "requires": {
-            "p-locate": "^2.0.0",
-            "path-exists": "^3.0.0"
-          }
-        },
-        "p-limit": {
-          "version": "1.3.0",
-          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
-          "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
-          "dev": true,
-          "requires": {
-            "p-try": "^1.0.0"
-          }
-        },
-        "p-locate": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
-          "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
-          "dev": true,
-          "requires": {
-            "p-limit": "^1.1.0"
-          }
-        },
-        "p-try": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
-          "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
-          "dev": true
-        },
-        "parse-json": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
-          "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
-          "dev": true,
-          "requires": {
-            "error-ex": "^1.3.1",
-            "json-parse-better-errors": "^1.0.1"
-          }
-        },
-        "path-exists": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
-          "dev": true
-        },
-        "path-type": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
-          "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
-          "dev": true,
-          "requires": {
-            "pify": "^3.0.0"
-          }
-        },
-        "read-pkg": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
-          "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=",
-          "dev": true,
-          "requires": {
-            "load-json-file": "^4.0.0",
-            "normalize-package-data": "^2.3.2",
-            "path-type": "^3.0.0"
-          }
-        },
-        "read-pkg-up": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz",
-          "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=",
-          "dev": true,
-          "requires": {
-            "find-up": "^2.0.0",
-            "read-pkg": "^3.0.0"
-          }
-        },
-        "strip-bom": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
-          "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
-          "dev": true
-        }
-      }
-    },
     "merge-stream": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
       "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
       "dev": true
     },
-    "merge2": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz",
-      "integrity": "sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==",
-      "dev": true
-    },
     "micromatch": {
-      "version": "3.1.10",
-      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
-      "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
+      "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
       "dev": true,
       "requires": {
-        "arr-diff": "^4.0.0",
-        "array-unique": "^0.3.2",
-        "braces": "^2.3.1",
-        "define-property": "^2.0.2",
-        "extend-shallow": "^3.0.2",
-        "extglob": "^2.0.4",
-        "fragment-cache": "^0.2.1",
-        "kind-of": "^6.0.2",
-        "nanomatch": "^1.2.9",
-        "object.pick": "^1.3.0",
-        "regex-not": "^1.0.0",
-        "snapdragon": "^0.8.1",
-        "to-regex": "^3.0.2"
+        "braces": "^3.0.1",
+        "picomatch": "^2.0.5"
       }
     },
     "mime-db": {
-      "version": "1.43.0",
-      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz",
-      "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==",
+      "version": "1.44.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
+      "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
       "dev": true
     },
     "mime-types": {
-      "version": "2.1.26",
-      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz",
-      "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==",
+      "version": "2.1.27",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
+      "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
       "dev": true,
       "requires": {
-        "mime-db": "1.43.0"
+        "mime-db": "1.44.0"
       }
     },
     "mimic-fn": {
@@ -9263,20 +5274,9 @@
       }
     },
     "minimist": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-      "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-      "dev": true
-    },
-    "minimist-options": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-3.0.2.tgz",
-      "integrity": "sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==",
-      "dev": true,
-      "requires": {
-        "arrify": "^1.0.1",
-        "is-plain-obj": "^1.1.0"
-      }
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
     },
     "mixin-deep": {
       "version": "1.3.2",
@@ -9306,47 +5306,14 @@
       "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
-        }
       }
     },
-    "modify-values": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz",
-      "integrity": "sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==",
-      "dev": true
-    },
     "ms": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
-      "dev": true
-    },
-    "mute-stdout": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz",
-      "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==",
-      "dev": true
-    },
-    "mute-stream": {
-      "version": "0.0.8",
-      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
-      "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
       "dev": true
     },
-    "nan": {
-      "version": "2.14.0",
-      "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
-      "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
-      "dev": true,
-      "optional": true
-    },
     "nanomatch": {
       "version": "1.2.13",
       "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@@ -9372,22 +5339,10 @@
       "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
       "dev": true
     },
-    "neo-async": {
-      "version": "2.6.1",
-      "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz",
-      "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==",
-      "dev": true
-    },
-    "next-tick": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
-      "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
-      "dev": true
-    },
     "nice-try": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz",
-      "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA==",
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
+      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
       "dev": true
     },
     "node-int64": {
@@ -9403,34 +5358,20 @@
       "dev": true
     },
     "node-notifier": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-6.0.0.tgz",
-      "integrity": "sha512-SVfQ/wMw+DesunOm5cKqr6yDcvUTDl/yc97ybGHMrteNEY6oekXpNpS3lZwgLlwz0FLgHoiW28ZpmBHUDg37cw==",
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.0.tgz",
+      "integrity": "sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA==",
       "dev": true,
       "optional": true,
       "requires": {
         "growly": "^1.3.0",
-        "is-wsl": "^2.1.1",
-        "semver": "^6.3.0",
+        "is-wsl": "^2.2.0",
+        "semver": "^7.3.2",
         "shellwords": "^0.1.1",
-        "which": "^1.3.1"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true,
-          "optional": true
-        }
+        "uuid": "^8.3.0",
+        "which": "^2.0.2"
       }
     },
-    "node-releases": {
-      "version": "1.1.54",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.54.tgz",
-      "integrity": "sha512-tLzytKpgwKQr37yw9CEODjNM9lnmsNxzlv575GzOZ16AgMvPcJis/DgrJX4UEV1KIYoXk6XoVfY6YaMOPJESAQ==",
-      "dev": true
-    },
     "normalize-package-data": {
       "version": "2.5.0",
       "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
@@ -9443,40 +5384,19 @@
         "validate-npm-package-license": "^3.0.1"
       },
       "dependencies": {
-        "path-parse": {
-          "version": "1.0.6",
-          "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
-          "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
+        "semver": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
           "dev": true
-        },
-        "resolve": {
-          "version": "1.11.0",
-          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz",
-          "integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==",
-          "dev": true,
-          "requires": {
-            "path-parse": "^1.0.6"
-          }
         }
       }
     },
     "normalize-path": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
-      "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
-      "dev": true,
-      "requires": {
-        "remove-trailing-separator": "^1.0.1"
-      }
-    },
-    "now-and-later": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.0.tgz",
-      "integrity": "sha1-vGHLtFbXnLMiB85HygUTb/Ln1u4=",
-      "dev": true,
-      "requires": {
-        "once": "^1.3.2"
-      }
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "dev": true
     },
     "npm-run-path": {
       "version": "2.0.2",
@@ -9485,14 +5405,16 @@
       "dev": true,
       "requires": {
         "path-key": "^2.0.0"
+      },
+      "dependencies": {
+        "path-key": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+          "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+          "dev": true
+        }
       }
     },
-    "number-is-nan": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
-      "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
-      "dev": true
-    },
     "nwsapi": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz",
@@ -9505,12 +5427,6 @@
       "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
       "dev": true
     },
-    "object-assign": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
-      "dev": true
-    },
     "object-copy": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
@@ -9542,12 +5458,6 @@
         }
       }
     },
-    "object-keys": {
-      "version": "1.0.12",
-      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
-      "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==",
-      "dev": true
-    },
     "object-visit": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
@@ -9557,40 +5467,6 @@
         "isobject": "^3.0.0"
       }
     },
-    "object.assign": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
-      "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
-      "dev": true,
-      "requires": {
-        "define-properties": "^1.1.2",
-        "function-bind": "^1.1.1",
-        "has-symbols": "^1.0.0",
-        "object-keys": "^1.0.11"
-      }
-    },
-    "object.defaults": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz",
-      "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=",
-      "dev": true,
-      "requires": {
-        "array-each": "^1.0.1",
-        "array-slice": "^1.0.0",
-        "for-own": "^1.0.0",
-        "isobject": "^3.0.0"
-      }
-    },
-    "object.map": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz",
-      "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=",
-      "dev": true,
-      "requires": {
-        "for-own": "^1.0.0",
-        "make-iterator": "^1.0.0"
-      }
-    },
     "object.pick": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
@@ -9600,16 +5476,6 @@
         "isobject": "^3.0.1"
       }
     },
-    "object.reduce": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz",
-      "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=",
-      "dev": true,
-      "requires": {
-        "for-own": "^1.0.0",
-        "make-iterator": "^1.0.0"
-      }
-    },
     "once": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
@@ -9628,100 +5494,26 @@
         "mimic-fn": "^2.1.0"
       }
     },
-    "optimist": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
-      "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
-      "dev": true,
-      "requires": {
-        "minimist": "~0.0.1",
-        "wordwrap": "~0.0.2"
-      },
-      "dependencies": {
-        "minimist": {
-          "version": "0.0.10",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
-          "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
-          "dev": true
-        },
-        "wordwrap": {
-          "version": "0.0.3",
-          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
-          "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
-          "dev": true
-        }
-      }
+    "opencollective-postinstall": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
+      "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==",
+      "dev": true
     },
     "optionator": {
-      "version": "0.8.2",
-      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
-      "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
-      "dev": true,
-      "requires": {
-        "deep-is": "~0.1.3",
-        "fast-levenshtein": "~2.0.4",
-        "levn": "~0.3.0",
-        "prelude-ls": "~1.1.2",
-        "type-check": "~0.3.2",
-        "wordwrap": "~1.0.0"
-      }
-    },
-    "ordered-read-streams": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz",
-      "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=",
-      "dev": true,
-      "requires": {
-        "readable-stream": "^2.0.1"
-      },
-      "dependencies": {
-        "isarray": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
-          "dev": true
-        },
-        "readable-stream": {
-          "version": "2.3.6",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
-          "dev": true,
-          "requires": {
-            "core-util-is": "~1.0.0",
-            "inherits": "~2.0.3",
-            "isarray": "~1.0.0",
-            "process-nextick-args": "~2.0.0",
-            "safe-buffer": "~5.1.1",
-            "string_decoder": "~1.1.1",
-            "util-deprecate": "~1.0.1"
-          }
-        },
-        "string_decoder": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-          "dev": true,
-          "requires": {
-            "safe-buffer": "~5.1.0"
-          }
-        }
-      }
-    },
-    "os-locale": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
-      "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
+      "version": "0.9.1",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+      "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
       "dev": true,
       "requires": {
-        "lcid": "^1.0.0"
+        "deep-is": "^0.1.3",
+        "fast-levenshtein": "^2.0.6",
+        "levn": "^0.4.1",
+        "prelude-ls": "^1.2.1",
+        "type-check": "^0.4.0",
+        "word-wrap": "^1.2.3"
       }
     },
-    "os-tmpdir": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
-      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
-      "dev": true
-    },
     "p-each-series": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz",
@@ -9735,45 +5527,31 @@
       "dev": true
     },
     "p-limit": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz",
-      "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==",
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
       "dev": true,
       "requires": {
         "p-try": "^2.0.0"
       }
     },
     "p-locate": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
-      "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
       "dev": true,
       "requires": {
-        "p-limit": "^1.1.0"
-      },
-      "dependencies": {
-        "p-limit": {
-          "version": "1.3.0",
-          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
-          "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
-          "dev": true,
-          "requires": {
-            "p-try": "^1.0.0"
-          }
-        },
-        "p-try": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
-          "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
-          "dev": true
-        }
+        "p-limit": "^2.2.0"
       }
     },
     "p-map": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
-      "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==",
-      "dev": true
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
+      "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
+      "dev": true,
+      "requires": {
+        "aggregate-error": "^3.0.0"
+      }
     },
     "p-try": {
       "version": "2.2.0",
@@ -9790,48 +5568,22 @@
         "callsites": "^3.0.0"
       }
     },
-    "parse-filepath": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz",
-      "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=",
-      "dev": true,
-      "requires": {
-        "is-absolute": "^1.0.0",
-        "map-cache": "^0.2.0",
-        "path-root": "^0.1.1"
-      }
-    },
-    "parse-github-repo-url": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz",
-      "integrity": "sha1-nn2LslKmy2ukJZUGC3v23z28H1A=",
-      "dev": true
-    },
     "parse-json": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
-      "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.0.1.tgz",
+      "integrity": "sha512-ztoZ4/DYeXQq4E21v169sC8qWINGpcosGv9XhTDvg9/hWvx/zrFkc9BiWxR58OJLHGk28j5BL0SDLeV2WmFZlQ==",
       "dev": true,
       "requires": {
-        "error-ex": "^1.2.0"
+        "@babel/code-frame": "^7.0.0",
+        "error-ex": "^1.3.1",
+        "json-parse-better-errors": "^1.0.1",
+        "lines-and-columns": "^1.1.6"
       }
     },
-    "parse-node-version": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz",
-      "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==",
-      "dev": true
-    },
-    "parse-passwd": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
-      "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
-      "dev": true
-    },
     "parse5": {
-      "version": "5.1.0",
-      "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz",
-      "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==",
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
+      "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
       "dev": true
     },
     "pascalcase": {
@@ -9840,20 +5592,11 @@
       "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
       "dev": true
     },
-    "path-dirname": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
-      "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
-      "dev": true
-    },
     "path-exists": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
-      "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
-      "dev": true,
-      "requires": {
-        "pinkie-promise": "^2.0.0"
-      }
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true
     },
     "path-is-absolute": {
       "version": "1.0.1",
@@ -9861,57 +5604,23 @@
       "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
       "dev": true
     },
-    "path-is-inside": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
-      "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
-      "dev": true
-    },
     "path-key": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
-      "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
       "dev": true
     },
     "path-parse": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
-      "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=",
-      "dev": true
-    },
-    "path-root": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz",
-      "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=",
-      "dev": true,
-      "requires": {
-        "path-root-regex": "^0.1.0"
-      }
-    },
-    "path-root-regex": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz",
-      "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=",
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
       "dev": true
     },
     "path-type": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
-      "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.2",
-        "pify": "^2.0.0",
-        "pinkie-promise": "^2.0.0"
-      },
-      "dependencies": {
-        "pify": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
-          "dev": true
-        }
-      }
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+      "dev": true
     },
     "performance-now": {
       "version": "2.1.0",
@@ -9920,32 +5629,11 @@
       "dev": true
     },
     "picomatch": {
-      "version": "2.0.7",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz",
-      "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==",
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
+      "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
       "dev": true
     },
-    "pify": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
-      "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
-      "dev": true
-    },
-    "pinkie": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
-      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
-      "dev": true
-    },
-    "pinkie-promise": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
-      "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
-      "dev": true,
-      "requires": {
-        "pinkie": "^2.0.0"
-      }
-    },
     "pirates": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz",
@@ -9962,70 +5650,17 @@
       "dev": true,
       "requires": {
         "find-up": "^4.0.0"
-      },
-      "dependencies": {
-        "find-up": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-          "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
-          "dev": true,
-          "requires": {
-            "locate-path": "^5.0.0",
-            "path-exists": "^4.0.0"
-          }
-        },
-        "locate-path": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-          "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-          "dev": true,
-          "requires": {
-            "p-locate": "^4.1.0"
-          }
-        },
-        "p-locate": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-          "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^2.2.0"
-          }
-        },
-        "path-exists": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-          "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-          "dev": true
-        }
       }
     },
-    "pkg-up": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz",
-      "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=",
+    "please-upgrade-node": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
+      "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
       "dev": true,
       "requires": {
-        "find-up": "^2.1.0"
-      },
-      "dependencies": {
-        "find-up": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
-          "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
-          "dev": true,
-          "requires": {
-            "locate-path": "^2.0.0"
-          }
-        }
+        "semver-compare": "^1.0.0"
       }
     },
-    "pn": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz",
-      "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==",
-      "dev": true
-    },
     "posix-character-classes": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
@@ -10033,68 +5668,29 @@
       "dev": true
     },
     "prelude-ls": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
-      "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+      "dev": true
+    },
+    "prettier": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.1.1.tgz",
+      "integrity": "sha512-9bY+5ZWCfqj3ghYBLxApy2zf6m+NJo5GzmLTpr9FsApsfjriNnS2dahWReHMi7qNPhhHl9SYHJs2cHZLgexNIw==",
       "dev": true
     },
     "pretty-format": {
-      "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==",
+      "version": "25.5.0",
+      "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.5.0.tgz",
+      "integrity": "sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ==",
       "dev": true,
       "requires": {
-        "@jest/types": "^25.4.0",
+        "@jest/types": "^25.5.0",
         "ansi-regex": "^5.0.0",
         "ansi-styles": "^4.0.0",
         "react-is": "^16.12.0"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
-          "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
-          "dev": true
-        },
-        "ansi-styles": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
-          "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
-          "dev": true,
-          "requires": {
-            "@types/color-name": "^1.1.1",
-            "color-convert": "^2.0.1"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-          "dev": true,
-          "requires": {
-            "color-name": "~1.1.4"
-          }
-        },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
-        }
       }
     },
-    "pretty-hrtime": {
-      "version": "1.0.3",
-      "resolved": "http://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
-      "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=",
-      "dev": true
-    },
-    "process-nextick-args": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
-      "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
-      "dev": true
-    },
     "progress": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
@@ -10118,35 +5714,13 @@
       "dev": true
     },
     "pump": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
-      "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
+      "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
       "dev": true,
       "requires": {
         "end-of-stream": "^1.1.0",
         "once": "^1.3.1"
-      },
-      "dependencies": {
-        "end-of-stream": {
-          "version": "1.4.1",
-          "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
-          "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
-          "dev": true,
-          "requires": {
-            "once": "^1.4.0"
-          }
-        }
-      }
-    },
-    "pumpify": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
-      "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
-      "dev": true,
-      "requires": {
-        "duplexify": "^3.6.0",
-        "inherits": "^2.0.3",
-        "pump": "^2.0.0"
       }
     },
     "punycode": {
@@ -10155,145 +5729,62 @@
       "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
       "dev": true
     },
-    "q": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
-      "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
-      "dev": true
-    },
     "qs": {
       "version": "6.5.2",
       "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
       "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
-      "dev": true
-    },
-    "quick-lru": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz",
-      "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=",
-      "dev": true
-    },
-    "react-is": {
-      "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": "1.1.0",
-      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
-      "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
-      "dev": true,
-      "requires": {
-        "load-json-file": "^1.0.0",
-        "normalize-package-data": "^2.3.2",
-        "path-type": "^1.0.0"
-      }
-    },
-    "read-pkg-up": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
-      "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
-      "dev": true,
-      "requires": {
-        "find-up": "^1.0.0",
-        "read-pkg": "^1.0.0"
-      }
-    },
-    "readable-stream": {
-      "version": "3.4.0",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
-      "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.3",
-        "string_decoder": "^1.1.1",
-        "util-deprecate": "^1.0.1"
-      },
-      "dependencies": {
-        "string_decoder": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz",
-          "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==",
-          "dev": true,
-          "requires": {
-            "safe-buffer": "~5.1.0"
-          }
-        }
-      }
+      "dev": true
     },
-    "readdirp": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
-      "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
+    "randombytes": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
       "dev": true,
       "requires": {
-        "graceful-fs": "^4.1.11",
-        "micromatch": "^3.1.10",
-        "readable-stream": "^2.0.2"
-      },
-      "dependencies": {
-        "isarray": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
-          "dev": true
-        },
-        "readable-stream": {
-          "version": "2.3.6",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
-          "dev": true,
-          "requires": {
-            "core-util-is": "~1.0.0",
-            "inherits": "~2.0.3",
-            "isarray": "~1.0.0",
-            "process-nextick-args": "~2.0.0",
-            "safe-buffer": "~5.1.1",
-            "string_decoder": "~1.1.1",
-            "util-deprecate": "~1.0.1"
-          }
-        },
-        "string_decoder": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-          "dev": true,
-          "requires": {
-            "safe-buffer": "~5.1.0"
-          }
-        }
+        "safe-buffer": "^5.1.0"
       }
     },
-    "realpath-native": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-2.0.0.tgz",
-      "integrity": "sha512-v1SEYUOXXdbBZK8ZuNgO4TBjamPsiSgcFr0aP+tEKpQZK8vooEUqV6nm6Cv502mX4NF2EfsnVqtNAHG+/6Ur1Q==",
+    "react-is": {
+      "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
     },
-    "rechoir": {
-      "version": "0.6.2",
-      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
-      "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
+    "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": {
-        "resolve": "^1.1.6"
+        "@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
+        }
       }
     },
-    "redent": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/redent/-/redent-2.0.0.tgz",
-      "integrity": "sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=",
+    "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": {
-        "indent-string": "^3.0.0",
-        "strip-indent": "^2.0.0"
+        "find-up": "^4.1.0",
+        "read-pkg": "^5.2.0",
+        "type-fest": "^0.8.1"
       }
     },
-    "regenerator-runtime": {
-      "version": "0.13.5",
-      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz",
-      "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==",
+    "reflect-metadata": {
+      "version": "0.1.13",
+      "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
+      "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==",
       "dev": true
     },
     "regex-not": {
@@ -10312,27 +5803,6 @@
       "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==",
       "dev": true
     },
-    "remove-bom-buffer": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz",
-      "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==",
-      "dev": true,
-      "requires": {
-        "is-buffer": "^1.1.5",
-        "is-utf8": "^0.2.1"
-      }
-    },
-    "remove-bom-stream": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz",
-      "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=",
-      "dev": true,
-      "requires": {
-        "remove-bom-buffer": "^3.0.0",
-        "safe-buffer": "^5.1.0",
-        "through2": "^2.0.3"
-      }
-    },
     "remove-trailing-separator": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
@@ -10351,75 +5821,6 @@
       "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
       "dev": true
     },
-    "repeating": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
-      "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
-      "dev": true,
-      "requires": {
-        "is-finite": "^1.0.0"
-      }
-    },
-    "replace-ext": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
-      "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=",
-      "dev": true
-    },
-    "replace-homedir": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz",
-      "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=",
-      "dev": true,
-      "requires": {
-        "homedir-polyfill": "^1.0.1",
-        "is-absolute": "^1.0.0",
-        "remove-trailing-separator": "^1.1.0"
-      }
-    },
-    "replacestream": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/replacestream/-/replacestream-4.0.3.tgz",
-      "integrity": "sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA==",
-      "dev": true,
-      "requires": {
-        "escape-string-regexp": "^1.0.3",
-        "object-assign": "^4.0.1",
-        "readable-stream": "^2.0.2"
-      },
-      "dependencies": {
-        "isarray": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
-          "dev": true
-        },
-        "readable-stream": {
-          "version": "2.3.6",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
-          "dev": true,
-          "requires": {
-            "core-util-is": "~1.0.0",
-            "inherits": "~2.0.3",
-            "isarray": "~1.0.0",
-            "process-nextick-args": "~2.0.0",
-            "safe-buffer": "~5.1.1",
-            "string_decoder": "~1.1.1",
-            "util-deprecate": "~1.0.1"
-          }
-        },
-        "string_decoder": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-          "dev": true,
-          "requires": {
-            "safe-buffer": "~5.1.0"
-          }
-        }
-      }
-    },
     "request": {
       "version": "2.88.2",
       "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
@@ -10457,25 +5858,31 @@
             "psl": "^1.1.28",
             "punycode": "^2.1.1"
           }
+        },
+        "uuid": {
+          "version": "3.4.0",
+          "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+          "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
+          "dev": true
         }
       }
     },
     "request-promise-core": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz",
-      "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==",
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz",
+      "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==",
       "dev": true,
       "requires": {
-        "lodash": "^4.17.15"
+        "lodash": "^4.17.19"
       }
     },
     "request-promise-native": {
-      "version": "1.0.8",
-      "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz",
-      "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==",
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz",
+      "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==",
       "dev": true,
       "requires": {
-        "request-promise-core": "1.1.3",
+        "request-promise-core": "1.1.4",
         "stealthy-require": "^1.1.1",
         "tough-cookie": "^2.3.3"
       },
@@ -10499,18 +5906,18 @@
       "dev": true
     },
     "require-main-filename": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
-      "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
+      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
       "dev": true
     },
     "resolve": {
-      "version": "1.8.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
-      "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==",
+      "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.5"
+        "path-parse": "^1.0.6"
       }
     },
     "resolve-cwd": {
@@ -10520,33 +5927,22 @@
       "dev": true,
       "requires": {
         "resolve-from": "^5.0.0"
-      }
-    },
-    "resolve-dir": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
-      "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=",
-      "dev": true,
-      "requires": {
-        "expand-tilde": "^2.0.0",
-        "global-modules": "^1.0.0"
+      },
+      "dependencies": {
+        "resolve-from": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+          "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+          "dev": true
+        }
       }
     },
     "resolve-from": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
-      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
       "dev": true
     },
-    "resolve-options": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz",
-      "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=",
-      "dev": true,
-      "requires": {
-        "value-or-function": "^3.0.0"
-      }
-    },
     "resolve-url": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
@@ -10569,199 +5965,34 @@
       "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
       "dev": true
     },
-    "reusify": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
-      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
-      "dev": true
-    },
     "rimraf": {
-      "version": "2.6.3",
-      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
-      "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
       "dev": true,
       "requires": {
         "glob": "^7.1.3"
-      },
-      "dependencies": {
-        "glob": {
-          "version": "7.1.4",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
-          "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        }
       }
     },
     "rollup": {
-      "version": "1.32.1",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.32.1.tgz",
-      "integrity": "sha512-/2HA0Ec70TvQnXdzynFffkjA6XN+1e2pEv/uKS5Ulca40g2L7KuOE3riasHoNVHOsFD5KKZgDsMk1CP3Tw9s+A==",
-      "dev": true,
-      "requires": {
-        "@types/estree": "*",
-        "@types/node": "*",
-        "acorn": "^7.1.0"
-      }
-    },
-    "rollup-plugin-commonjs": {
-      "version": "10.1.0",
-      "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz",
-      "integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==",
-      "dev": true,
-      "requires": {
-        "estree-walker": "^0.6.1",
-        "is-reference": "^1.1.2",
-        "magic-string": "^0.25.2",
-        "resolve": "^1.11.0",
-        "rollup-pluginutils": "^2.8.1"
-      },
-      "dependencies": {
-        "path-parse": {
-          "version": "1.0.6",
-          "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
-          "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
-          "dev": true
-        },
-        "resolve": {
-          "version": "1.15.1",
-          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz",
-          "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==",
-          "dev": true,
-          "requires": {
-            "path-parse": "^1.0.6"
-          }
-        }
-      }
-    },
-    "rollup-plugin-json": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/rollup-plugin-json/-/rollup-plugin-json-4.0.0.tgz",
-      "integrity": "sha512-hgb8N7Cgfw5SZAkb3jf0QXii6QX/FOkiIq2M7BAQIEydjHvTyxXHQiIzZaTFgx1GK0cRCHOCBHIyEkkLdWKxow==",
+      "version": "2.26.11",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.26.11.tgz",
+      "integrity": "sha512-xyfxxhsE6hW57xhfL1I+ixH8l2bdoIMaAecdQiWF3N7IgJEMu99JG+daBiSZQjnBpzFxa0/xZm+3pbCdAQehHw==",
       "dev": true,
       "requires": {
-        "rollup-pluginutils": "^2.5.0"
-      }
-    },
-    "rollup-plugin-node-resolve": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz",
-      "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==",
-      "dev": true,
-      "requires": {
-        "@types/resolve": "0.0.8",
-        "builtin-modules": "^3.1.0",
-        "is-module": "^1.0.0",
-        "resolve": "^1.11.1",
-        "rollup-pluginutils": "^2.8.1"
-      },
-      "dependencies": {
-        "builtin-modules": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz",
-          "integrity": "sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==",
-          "dev": true
-        },
-        "path-parse": {
-          "version": "1.0.6",
-          "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
-          "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
-          "dev": true
-        },
-        "resolve": {
-          "version": "1.15.1",
-          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz",
-          "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==",
-          "dev": true,
-          "requires": {
-            "path-parse": "^1.0.6"
-          }
-        }
-      }
-    },
-    "rollup-plugin-replace": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/rollup-plugin-replace/-/rollup-plugin-replace-2.2.0.tgz",
-      "integrity": "sha512-/5bxtUPkDHyBJAKketb4NfaeZjL5yLZdeUihSfbF2PQMz+rSTEb8ARKoOl3UBT4m7/X+QOXJo3sLTcq+yMMYTA==",
-      "dev": true,
-      "requires": {
-        "magic-string": "^0.25.2",
-        "rollup-pluginutils": "^2.6.0"
-      }
-    },
-    "rollup-plugin-sourcemaps": {
-      "version": "0.4.2",
-      "resolved": "https://registry.npmjs.org/rollup-plugin-sourcemaps/-/rollup-plugin-sourcemaps-0.4.2.tgz",
-      "integrity": "sha1-YhJaqUCHqt97g+9N+vYptHMTXoc=",
-      "dev": true,
-      "requires": {
-        "rollup-pluginutils": "^2.0.1",
-        "source-map-resolve": "^0.5.0"
+        "fsevents": "~2.1.2"
       }
     },
     "rollup-plugin-terser": {
-      "version": "5.3.0",
-      "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-5.3.0.tgz",
-      "integrity": "sha512-XGMJihTIO3eIBsVGq7jiNYOdDMb3pVxuzY0uhOE/FM4x/u9nQgr3+McsjzqBn3QfHIpNSZmFnpoKAwHBEcsT7g==",
-      "dev": true,
-      "requires": {
-        "@babel/code-frame": "^7.5.5",
-        "jest-worker": "^24.9.0",
-        "rollup-pluginutils": "^2.8.2",
-        "serialize-javascript": "^2.1.2",
-        "terser": "^4.6.2"
-      }
-    },
-    "rollup-plugin-uglify": {
-      "version": "6.0.4",
-      "resolved": "https://registry.npmjs.org/rollup-plugin-uglify/-/rollup-plugin-uglify-6.0.4.tgz",
-      "integrity": "sha512-ddgqkH02klveu34TF0JqygPwZnsbhHVI6t8+hGTcYHngPkQb5MIHI0XiztXIN/d6V9j+efwHAqEL7LspSxQXGw==",
-      "dev": true,
-      "requires": {
-        "@babel/code-frame": "^7.0.0",
-        "jest-worker": "^24.0.0",
-        "serialize-javascript": "^2.1.2",
-        "uglify-js": "^3.4.9"
-      },
-      "dependencies": {
-        "commander": {
-          "version": "2.20.3",
-          "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
-          "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        },
-        "uglify-js": {
-          "version": "3.8.1",
-          "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.8.1.tgz",
-          "integrity": "sha512-W7KxyzeaQmZvUFbGj4+YFshhVrMBGSg2IbcYAjGWGvx8DHvJMclbTDMpffdxFUGPBHjIytk7KJUR/KUXstUGDw==",
-          "dev": true,
-          "requires": {
-            "commander": "~2.20.3",
-            "source-map": "~0.6.1"
-          }
-        }
-      }
-    },
-    "rollup-pluginutils": {
-      "version": "2.8.2",
-      "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
-      "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz",
+      "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==",
       "dev": true,
       "requires": {
-        "estree-walker": "^0.6.1"
+        "@babel/code-frame": "^7.10.4",
+        "jest-worker": "^26.2.1",
+        "serialize-javascript": "^4.0.0",
+        "terser": "^5.0.0"
       }
     },
     "rsvp": {
@@ -10770,25 +6001,10 @@
       "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==",
       "dev": true
     },
-    "run-async": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.0.tgz",
-      "integrity": "sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg==",
-      "dev": true,
-      "requires": {
-        "is-promise": "^2.1.0"
-      }
-    },
-    "run-parallel": {
-      "version": "1.1.9",
-      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz",
-      "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==",
-      "dev": true
-    },
     "rxjs": {
-      "version": "6.5.5",
-      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.5.tgz",
-      "integrity": "sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ==",
+      "version": "6.6.3",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz",
+      "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==",
       "dev": true,
       "requires": {
         "tslib": "^1.9.0"
@@ -10802,7 +6018,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": {
@@ -10832,72 +6048,171 @@
         "walker": "~1.0.5"
       },
       "dependencies": {
-        "execa": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
-          "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+        "anymatch": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
+          "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
           "dev": true,
           "requires": {
-            "cross-spawn": "^6.0.0",
-            "get-stream": "^4.0.0",
-            "is-stream": "^1.1.0",
-            "npm-run-path": "^2.0.0",
-            "p-finally": "^1.0.0",
-            "signal-exit": "^3.0.0",
-            "strip-eof": "^1.0.0"
+            "micromatch": "^3.1.4",
+            "normalize-path": "^2.1.1"
           }
         },
-        "get-stream": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
-          "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
+        "braces": {
+          "version": "2.3.2",
+          "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
+          "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
           "dev": true,
           "requires": {
-            "pump": "^3.0.0"
+            "arr-flatten": "^1.1.0",
+            "array-unique": "^0.3.2",
+            "extend-shallow": "^2.0.1",
+            "fill-range": "^4.0.0",
+            "isobject": "^3.0.1",
+            "repeat-element": "^1.1.2",
+            "snapdragon": "^0.8.1",
+            "snapdragon-node": "^2.0.1",
+            "split-string": "^3.0.2",
+            "to-regex": "^3.0.1"
+          },
+          "dependencies": {
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+              "dev": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            }
+          }
+        },
+        "fill-range": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+          "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+          "dev": true,
+          "requires": {
+            "extend-shallow": "^2.0.1",
+            "is-number": "^3.0.0",
+            "repeat-string": "^1.6.1",
+            "to-regex-range": "^2.1.0"
+          },
+          "dependencies": {
+            "extend-shallow": {
+              "version": "2.0.1",
+              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
+              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
+              "dev": true,
+              "requires": {
+                "is-extendable": "^0.1.0"
+              }
+            }
           }
         },
-        "pump": {
+        "is-number": {
           "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
-          "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+          "dev": true,
+          "requires": {
+            "kind-of": "^3.0.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+              "dev": true,
+              "requires": {
+                "is-buffer": "^1.1.5"
+              }
+            }
+          }
+        },
+        "micromatch": {
+          "version": "3.1.10",
+          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
+          "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
+          "dev": true,
+          "requires": {
+            "arr-diff": "^4.0.0",
+            "array-unique": "^0.3.2",
+            "braces": "^2.3.1",
+            "define-property": "^2.0.2",
+            "extend-shallow": "^3.0.2",
+            "extglob": "^2.0.4",
+            "fragment-cache": "^0.2.1",
+            "kind-of": "^6.0.2",
+            "nanomatch": "^1.2.9",
+            "object.pick": "^1.3.0",
+            "regex-not": "^1.0.0",
+            "snapdragon": "^0.8.1",
+            "to-regex": "^3.0.2"
+          }
+        },
+        "normalize-path": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+          "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+          "dev": true,
+          "requires": {
+            "remove-trailing-separator": "^1.0.1"
+          }
+        },
+        "to-regex-range": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
+          "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
           "dev": true,
           "requires": {
-            "end-of-stream": "^1.1.0",
-            "once": "^1.3.1"
+            "is-number": "^3.0.0",
+            "repeat-string": "^1.6.1"
           }
         }
       }
     },
+    "sax": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+      "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+    },
     "saxes": {
-      "version": "3.1.11",
-      "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz",
-      "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==",
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz",
+      "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==",
       "dev": true,
       "requires": {
-        "xmlchars": "^2.1.1"
+        "xmlchars": "^2.2.0"
       }
     },
     "semver": {
-      "version": "5.7.0",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
-      "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
+      "version": "7.3.2",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
+      "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
       "dev": true
     },
-    "semver-greatest-satisfied-range": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz",
-      "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=",
+    "semver-compare": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
+      "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=",
+      "dev": true
+    },
+    "semver-regex": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz",
+      "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==",
+      "dev": true
+    },
+    "serialize-javascript": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
+      "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
       "dev": true,
       "requires": {
-        "sver-compat": "^1.5.0"
+        "randombytes": "^2.1.0"
       }
     },
-    "serialize-javascript": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz",
-      "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==",
-      "dev": true
-    },
     "set-blocking": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
@@ -10905,9 +6220,9 @@
       "dev": true
     },
     "set-value": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz",
-      "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
+      "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
       "dev": true,
       "requires": {
         "extend-shallow": "^2.0.1",
@@ -10928,18 +6243,18 @@
       }
     },
     "shebang-command": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
-      "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
       "dev": true,
       "requires": {
-        "shebang-regex": "^1.0.0"
+        "shebang-regex": "^3.0.0"
       }
     },
     "shebang-regex": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
-      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
       "dev": true
     },
     "shellwords": {
@@ -10950,9 +6265,9 @@
       "optional": true
     },
     "signal-exit": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
-      "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
+      "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
       "dev": true
     },
     "sisteransi": {
@@ -10978,10 +6293,28 @@
         "is-fullwidth-code-point": "^2.0.0"
       },
       "dependencies": {
-        "is-fullwidth-code-point": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^1.9.0"
+          }
+        },
+        "color-convert": {
+          "version": "1.9.3",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+          "dev": true,
+          "requires": {
+            "color-name": "1.1.3"
+          }
+        },
+        "color-name": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
           "dev": true
         }
       }
@@ -11002,6 +6335,15 @@
         "use": "^3.1.0"
       },
       "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "dev": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
         "define-property": {
           "version": "0.2.5",
           "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
@@ -11019,6 +6361,18 @@
           "requires": {
             "is-extendable": "^0.1.0"
           }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "dev": true
+        },
+        "source-map": {
+          "version": "0.5.7",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+          "dev": true
         }
       }
     },
@@ -11094,18 +6448,18 @@
       }
     },
     "source-map": {
-      "version": "0.5.7",
-      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-      "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
       "dev": true
     },
     "source-map-resolve": {
-      "version": "0.5.2",
-      "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
-      "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
+      "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
       "dev": true,
       "requires": {
-        "atob": "^2.1.1",
+        "atob": "^2.1.2",
         "decode-uri-component": "^0.2.0",
         "resolve-url": "^0.2.1",
         "source-map-url": "^0.4.0",
@@ -11113,21 +6467,13 @@
       }
     },
     "source-map-support": {
-      "version": "0.5.12",
-      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz",
-      "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==",
+      "version": "0.5.19",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
+      "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
       "dev": true,
       "requires": {
         "buffer-from": "^1.0.0",
         "source-map": "^0.6.0"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
       }
     },
     "source-map-url": {
@@ -11142,16 +6488,10 @@
       "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
       "dev": true
     },
-    "sparkles": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz",
-      "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==",
-      "dev": true
-    },
     "spdx-correct": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
-      "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
+      "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
       "dev": true,
       "requires": {
         "spdx-expression-parse": "^3.0.0",
@@ -11159,15 +6499,15 @@
       }
     },
     "spdx-exceptions": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
-      "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==",
+      "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==",
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+      "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
       "dev": true,
       "requires": {
         "spdx-exceptions": "^2.1.0",
@@ -11175,20 +6515,11 @@
       }
     },
     "spdx-license-ids": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz",
-      "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA==",
+      "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": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz",
-      "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==",
-      "dev": true,
-      "requires": {
-        "through": "2"
-      }
-    },
     "split-string": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
@@ -11198,15 +6529,6 @@
         "extend-shallow": "^3.0.0"
       }
     },
-    "split2": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz",
-      "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==",
-      "dev": true,
-      "requires": {
-        "through2": "^2.0.2"
-      }
-    },
     "sprintf-js": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@@ -11230,17 +6552,22 @@
         "tweetnacl": "~0.14.0"
       }
     },
-    "stack-trace": {
-      "version": "0.0.10",
-      "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
-      "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=",
-      "dev": true
-    },
     "stack-utils": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz",
-      "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==",
-      "dev": true
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.2.tgz",
+      "integrity": "sha512-0H7QK2ECz3fyZMzQ8rH0j2ykpfbnd20BFtfg/SqVC2+sCTtcw0aDTGB7dk+de4U4uUeuz6nOtJcrkFFLG1B0Rg==",
+      "dev": true,
+      "requires": {
+        "escape-string-regexp": "^2.0.0"
+      },
+      "dependencies": {
+        "escape-string-regexp": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+          "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+          "dev": true
+        }
+      }
     },
     "static-extend": {
       "version": "0.1.2",
@@ -11269,26 +6596,31 @@
       "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=",
       "dev": true
     },
-    "stream-exhaust": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz",
-      "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==",
-      "dev": true
-    },
-    "stream-shift": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz",
-      "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=",
+    "string-argv": {
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz",
+      "integrity": "sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==",
       "dev": true
     },
     "string-length": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz",
+      "integrity": "sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw==",
+      "dev": true,
+      "requires": {
+        "char-regex": "^1.0.2",
+        "strip-ansi": "^6.0.0"
+      }
+    },
+    "string-width": {
       "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/string-length/-/string-length-3.1.0.tgz",
-      "integrity": "sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA==",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
+      "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
       "dev": true,
       "requires": {
-        "astral-regex": "^1.0.0",
-        "strip-ansi": "^5.2.0"
+        "emoji-regex": "^7.0.1",
+        "is-fullwidth-code-point": "^2.0.0",
+        "strip-ansi": "^5.1.0"
       },
       "dependencies": {
         "ansi-regex": {
@@ -11308,39 +6640,30 @@
         }
       }
     },
-    "string-width": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
-      "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+    "stringify-object": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz",
+      "integrity": "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==",
       "dev": true,
       "requires": {
-        "code-point-at": "^1.0.0",
-        "is-fullwidth-code-point": "^1.0.0",
-        "strip-ansi": "^3.0.0"
+        "get-own-enumerable-property-symbols": "^3.0.0",
+        "is-obj": "^1.0.1",
+        "is-regexp": "^1.0.0"
       }
     },
     "strip-ansi": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
-      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+      "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
       "dev": true,
       "requires": {
-        "ansi-regex": "^2.0.0"
+        "ansi-regex": "^5.0.0"
       }
     },
     "strip-bom": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
-      "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
-      "dev": true,
-      "requires": {
-        "is-utf8": "^0.2.0"
-      }
-    },
-    "strip-bom-string": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
-      "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
+      "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
       "dev": true
     },
     "strip-eof": {
@@ -11355,25 +6678,19 @@
       "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
       "dev": true
     },
-    "strip-indent": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz",
-      "integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=",
-      "dev": true
-    },
     "strip-json-comments": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.0.tgz",
-      "integrity": "sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w==",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
       "dev": true
     },
     "supports-color": {
-      "version": "5.5.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
+      "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
       "dev": true,
       "requires": {
-        "has-flag": "^3.0.0"
+        "has-flag": "^4.0.0"
       }
     },
     "supports-hyperlinks": {
@@ -11384,33 +6701,6 @@
       "requires": {
         "has-flag": "^4.0.0",
         "supports-color": "^7.0.0"
-      },
-      "dependencies": {
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "7.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
-          "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
-        }
-      }
-    },
-    "sver-compat": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz",
-      "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=",
-      "dev": true,
-      "requires": {
-        "es6-iterator": "^2.0.1",
-        "es6-symbol": "^3.1.1"
       }
     },
     "symbol-tree": {
@@ -11429,64 +6719,6 @@
         "lodash": "^4.17.14",
         "slice-ansi": "^2.1.0",
         "string-width": "^3.0.0"
-      },
-      "dependencies": {
-        "ansi-regex": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
-          "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
-          "dev": true
-        },
-        "emoji-regex": {
-          "version": "7.0.3",
-          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
-          "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
-          "dev": true
-        },
-        "is-fullwidth-code-point": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
-          "dev": true
-        },
-        "string-width": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
-          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^7.0.1",
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^5.1.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "5.2.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-          "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^4.1.0"
-          }
-        }
-      }
-    },
-    "tempfile": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/tempfile/-/tempfile-1.1.1.tgz",
-      "integrity": "sha1-W8xOrsxKsscH2LwR2ZzMmiyyh/I=",
-      "dev": true,
-      "requires": {
-        "os-tmpdir": "^1.0.0",
-        "uuid": "^2.0.1"
-      },
-      "dependencies": {
-        "uuid": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz",
-          "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=",
-          "dev": true
-        }
       }
     },
     "terminal-link": {
@@ -11500,9 +6732,9 @@
       }
     },
     "terser": {
-      "version": "4.6.10",
-      "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.10.tgz",
-      "integrity": "sha512-qbF/3UOo11Hggsbsqm2hPa6+L4w7bkr+09FNseEe8xrcVD3APGLFqE+Oz1ZKAxjYnFsj80rLOfgAtJ0LNJjtTA==",
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.0.tgz",
+      "integrity": "sha512-XTT3D3AwxC54KywJijmY2mxZ8nJiEjBHVYzq8l9OaYuRFWeQNBwvipuzzYEP4e+/AVcd1hqG/CqgsdIRyT45Fg==",
       "dev": true,
       "requires": {
         "commander": "^2.20.0",
@@ -11515,12 +6747,6 @@
           "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
           "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
           "dev": true
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
         }
       }
     },
@@ -11533,42 +6759,14 @@
         "@istanbuljs/schema": "^0.1.2",
         "glob": "^7.1.4",
         "minimatch": "^3.0.4"
-      },
-      "dependencies": {
-        "glob": {
-          "version": "7.1.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        }
       }
     },
-    "text-extensions": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.0.0.tgz",
-      "integrity": "sha512-F91ZqLgvi1E0PdvmxMgp+gcf6q8fMH7mhdwWfzXnl1k+GbpQDmi8l7DzLC5JTASKbwpY3TfxajAUzAXcv2NmsQ==",
-      "dev": true
-    },
     "text-table": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
       "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
       "dev": true
     },
-    "textextensions": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.2.0.tgz",
-      "integrity": "sha512-j5EMxnryTvKxwH2Cq+Pb43tsf6sdEgw6Pdwxk83mPaq0ToeFJt6WE4J3s5BqY7vmjlLgkgXvhtXUxo80FyBhCA==",
-      "dev": true
-    },
     "throat": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz",
@@ -11581,89 +6779,12 @@
       "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
       "dev": true
     },
-    "through2": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
-      "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
-      "dev": true,
-      "requires": {
-        "readable-stream": "^2.1.5",
-        "xtend": "~4.0.1"
-      },
-      "dependencies": {
-        "isarray": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
-          "dev": true
-        },
-        "readable-stream": {
-          "version": "2.3.6",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
-          "dev": true,
-          "requires": {
-            "core-util-is": "~1.0.0",
-            "inherits": "~2.0.3",
-            "isarray": "~1.0.0",
-            "process-nextick-args": "~2.0.0",
-            "safe-buffer": "~5.1.1",
-            "string_decoder": "~1.1.1",
-            "util-deprecate": "~1.0.1"
-          }
-        },
-        "string_decoder": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-          "dev": true,
-          "requires": {
-            "safe-buffer": "~5.1.0"
-          }
-        }
-      }
-    },
-    "time-stamp": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz",
-      "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=",
-      "dev": true
-    },
-    "timers-ext": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.5.tgz",
-      "integrity": "sha512-tsEStd7kmACHENhsUPaxb8Jf8/+GZZxyNFQbZD07HQOyooOa6At1rQqjffgvg7n+dxscQa9cjjMdWhJtsP2sxg==",
-      "dev": true,
-      "requires": {
-        "es5-ext": "~0.10.14",
-        "next-tick": "1"
-      }
-    },
-    "tmp": {
-      "version": "0.0.33",
-      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
-      "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
-      "dev": true,
-      "requires": {
-        "os-tmpdir": "~1.0.2"
-      }
-    },
     "tmpl": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz",
       "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=",
       "dev": true
     },
-    "to-absolute-glob": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz",
-      "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=",
-      "dev": true,
-      "requires": {
-        "is-absolute": "^1.0.0",
-        "is-negated-glob": "^1.0.0"
-      }
-    },
     "to-fast-properties": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@@ -11703,22 +6824,12 @@
       }
     },
     "to-regex-range": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
-      "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
-      "dev": true,
-      "requires": {
-        "is-number": "^3.0.0",
-        "repeat-string": "^1.6.1"
-      }
-    },
-    "to-through": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz",
-      "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=",
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
       "dev": true,
       "requires": {
-        "through2": "^2.0.3"
+        "is-number": "^7.0.0"
       }
     },
     "tough-cookie": {
@@ -11733,143 +6844,59 @@
       }
     },
     "tr46": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
-      "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz",
+      "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==",
       "dev": true,
       "requires": {
-        "punycode": "^2.1.0"
+        "punycode": "^2.1.1"
       }
     },
-    "trim-newlines": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-2.0.0.tgz",
-      "integrity": "sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=",
-      "dev": true
-    },
-    "trim-off-newlines": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz",
-      "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=",
-      "dev": true
-    },
     "ts-jest": {
-      "version": "25.4.0",
-      "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-25.4.0.tgz",
-      "integrity": "sha512-+0ZrksdaquxGUBwSdTIcdX7VXdwLIlSRsyjivVA9gcO+Cvr6ByqDhu/mi5+HCcb6cMkiQp5xZ8qRO7/eCqLeyw==",
+      "version": "26.3.0",
+      "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.3.0.tgz",
+      "integrity": "sha512-Jq2uKfx6bPd9+JDpZNMBJMdMQUC3sJ08acISj8NXlVgR2d5OqslEHOR2KHMgwymu8h50+lKIm0m0xj/ioYdW2Q==",
       "dev": true,
       "requires": {
+        "@types/jest": "26.x",
         "bs-logger": "0.x",
         "buffer-from": "1.x",
         "fast-json-stable-stringify": "2.x",
+        "jest-util": "26.x",
         "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.x"
-      },
-      "dependencies": {
-        "braces": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
-          "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
-          "dev": true,
-          "requires": {
-            "fill-range": "^7.0.1"
-          }
-        },
-        "camelcase": {
-          "version": "5.3.1",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
-          "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
-          "dev": true
-        },
-        "fill-range": {
-          "version": "7.0.1",
-          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
-          "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
-          "dev": true,
-          "requires": {
-            "to-regex-range": "^5.0.1"
-          }
-        },
-        "is-number": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-          "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-          "dev": true
-        },
-        "micromatch": {
-          "version": "4.0.2",
-          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
-          "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
-          "dev": true,
-          "requires": {
-            "braces": "^3.0.1",
-            "picomatch": "^2.0.5"
-          }
-        },
+        "lodash.memoize": "4.x",
+        "make-error": "1.x",
+        "mkdirp": "1.x",
+        "semver": "7.x",
+        "yargs-parser": "18.x"
+      },
+      "dependencies": {
         "mkdirp": {
           "version": "1.0.4",
           "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
           "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
           "dev": true
-        },
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        },
-        "to-regex-range": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-          "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-          "dev": true,
-          "requires": {
-            "is-number": "^7.0.0"
-          }
-        },
-        "yargs-parser": {
-          "version": "18.1.3",
-          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
-          "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
-          "dev": true,
-          "requires": {
-            "camelcase": "^5.0.0",
-            "decamelize": "^1.2.0"
-          }
         }
       }
     },
     "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": "9.0.0",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz",
+      "integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==",
       "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"
-      },
-      "dependencies": {
-        "diff": {
-          "version": "4.0.2",
-          "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
-          "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
-          "dev": true
-        }
       }
     },
     "tslib": {
       "version": "1.13.0",
       "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
-      "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q=="
+      "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==",
+      "dev": true
     },
     "tsutils": {
       "version": "3.17.1",
@@ -11896,12 +6923,12 @@
       "dev": true
     },
     "type-check": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
-      "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
       "dev": true,
       "requires": {
-        "prelude-ls": "~1.1.2"
+        "prelude-ls": "^1.2.1"
       }
     },
     "type-detect": {
@@ -11916,12 +6943,6 @@
       "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
       "dev": true
     },
-    "typedarray": {
-      "version": "0.0.6",
-      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
-      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
-      "dev": true
-    },
     "typedarray-to-buffer": {
       "version": "3.1.5",
       "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
@@ -11932,95 +6953,21 @@
       }
     },
     "typescript": {
-      "version": "3.5.3",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz",
-      "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==",
-      "dev": true
-    },
-    "unc-path-regex": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
-      "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=",
-      "dev": true
-    },
-    "undertaker": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz",
-      "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==",
-      "dev": true,
-      "requires": {
-        "arr-flatten": "^1.0.1",
-        "arr-map": "^2.0.0",
-        "bach": "^1.0.0",
-        "collection-map": "^1.0.0",
-        "es6-weak-map": "^2.0.1",
-        "last-run": "^1.1.0",
-        "object.defaults": "^1.0.0",
-        "object.reduce": "^1.0.0",
-        "undertaker-registry": "^1.0.0"
-      }
-    },
-    "undertaker-registry": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz",
-      "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=",
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz",
+      "integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==",
       "dev": true
     },
     "union-value": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
-      "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
+      "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
       "dev": true,
       "requires": {
         "arr-union": "^3.1.0",
         "get-value": "^2.0.6",
         "is-extendable": "^0.1.1",
-        "set-value": "^0.4.3"
-      },
-      "dependencies": {
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        },
-        "set-value": {
-          "version": "0.4.3",
-          "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
-          "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
-          "dev": true,
-          "requires": {
-            "extend-shallow": "^2.0.1",
-            "is-extendable": "^0.1.1",
-            "is-plain-object": "^2.0.1",
-            "to-object-path": "^0.3.0"
-          }
-        }
-      }
-    },
-    "unique-stream": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz",
-      "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==",
-      "dev": true,
-      "requires": {
-        "json-stable-stringify-without-jsonify": "^1.0.1",
-        "through2-filter": "^3.0.0"
-      },
-      "dependencies": {
-        "through2-filter": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz",
-          "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==",
-          "dev": true,
-          "requires": {
-            "through2": "~2.0.0",
-            "xtend": "~4.0.0"
-          }
-        }
+        "set-value": "^2.0.1"
       }
     },
     "unset-value": {
@@ -12060,21 +7007,9 @@
           "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
           "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
           "dev": true
-        },
-        "isarray": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
-          "dev": true
         }
       }
     },
-    "upath": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.2.tgz",
-      "integrity": "sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==",
-      "dev": true
-    },
     "uri-js": {
       "version": "4.2.2",
       "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
@@ -12096,28 +7031,23 @@
       "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
       "dev": true
     },
-    "util-deprecate": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
-      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
-      "dev": true
-    },
     "uuid": {
-      "version": "3.4.0",
-      "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
-      "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
-      "dev": true
+      "version": "8.3.0",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz",
+      "integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==",
+      "dev": true,
+      "optional": true
     },
     "v8-compile-cache": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz",
-      "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==",
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz",
+      "integrity": "sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==",
       "dev": true
     },
     "v8-to-istanbul": {
-      "version": "4.1.3",
-      "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-4.1.3.tgz",
-      "integrity": "sha512-sAjOC+Kki6aJVbUOXJbcR0MnbfjvBzwKZazEJymA2IX49uoOdEdk+4fBq5cXgYgiyKtAyrrJNtBZdOeDIF+Fng==",
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-5.0.1.tgz",
+      "integrity": "sha512-mbDNjuDajqYe3TXFk5qxcQy8L1msXNE37WTlLoqqpBfRsimbNcrlhQlDPntmECEcUvdC+AQ8CyMMf6EUx1r74Q==",
       "dev": true,
       "requires": {
         "@types/istanbul-lib-coverage": "^2.0.1",
@@ -12125,15 +7055,6 @@
         "source-map": "^0.7.3"
       },
       "dependencies": {
-        "convert-source-map": {
-          "version": "1.7.0",
-          "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
-          "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
-          "dev": true,
-          "requires": {
-            "safe-buffer": "~5.1.1"
-          }
-        },
         "source-map": {
           "version": "0.7.3",
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
@@ -12142,15 +7063,6 @@
         }
       }
     },
-    "v8flags": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz",
-      "integrity": "sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w==",
-      "dev": true,
-      "requires": {
-        "homedir-polyfill": "^1.0.1"
-      }
-    },
     "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",
@@ -12162,15 +7074,9 @@
       }
     },
     "validator": {
-      "version": "13.0.0",
-      "resolved": "https://registry.npmjs.org/validator/-/validator-13.0.0.tgz",
-      "integrity": "sha512-anYx5fURbgF04lQV18nEQWZ/3wHGnxiKdG4aL8J+jEDsm98n/sU/bey+tYk6tnGJzm7ioh5FoqrAiQ6m03IgaA=="
-    },
-    "value-or-function": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz",
-      "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=",
-      "dev": true
+      "version": "13.1.1",
+      "resolved": "https://registry.npmjs.org/validator/-/validator-13.1.1.tgz",
+      "integrity": "sha512-8GfPiwzzRoWTg7OV1zva1KvrSemuMkv07MA9TTl91hfhe+wKrsrgVN4H2QSFd/U/FhiU3iWPYVgvbsOGwhyFWw=="
     },
     "verror": {
       "version": "1.10.0",
@@ -12183,164 +7089,6 @@
         "extsprintf": "^1.2.0"
       }
     },
-    "vinyl": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz",
-      "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==",
-      "dev": true,
-      "requires": {
-        "clone": "^2.1.1",
-        "clone-buffer": "^1.0.0",
-        "clone-stats": "^1.0.0",
-        "cloneable-readable": "^1.0.0",
-        "remove-trailing-separator": "^1.0.1",
-        "replace-ext": "^1.0.0"
-      }
-    },
-    "vinyl-fs": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz",
-      "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==",
-      "dev": true,
-      "requires": {
-        "fs-mkdirp-stream": "^1.0.0",
-        "glob-stream": "^6.1.0",
-        "graceful-fs": "^4.0.0",
-        "is-valid-glob": "^1.0.0",
-        "lazystream": "^1.0.0",
-        "lead": "^1.0.0",
-        "object.assign": "^4.0.4",
-        "pumpify": "^1.3.5",
-        "readable-stream": "^2.3.3",
-        "remove-bom-buffer": "^3.0.0",
-        "remove-bom-stream": "^1.2.0",
-        "resolve-options": "^1.1.0",
-        "through2": "^2.0.0",
-        "to-through": "^2.0.0",
-        "value-or-function": "^3.0.0",
-        "vinyl": "^2.0.0",
-        "vinyl-sourcemap": "^1.1.0"
-      },
-      "dependencies": {
-        "clone": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
-          "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
-          "dev": true
-        },
-        "clone-stats": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
-          "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=",
-          "dev": true
-        },
-        "isarray": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
-          "dev": true
-        },
-        "readable-stream": {
-          "version": "2.3.6",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
-          "dev": true,
-          "requires": {
-            "core-util-is": "~1.0.0",
-            "inherits": "~2.0.3",
-            "isarray": "~1.0.0",
-            "process-nextick-args": "~2.0.0",
-            "safe-buffer": "~5.1.1",
-            "string_decoder": "~1.1.1",
-            "util-deprecate": "~1.0.1"
-          }
-        },
-        "replace-ext": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
-          "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=",
-          "dev": true
-        },
-        "string_decoder": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-          "dev": true,
-          "requires": {
-            "safe-buffer": "~5.1.0"
-          }
-        },
-        "vinyl": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz",
-          "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==",
-          "dev": true,
-          "requires": {
-            "clone": "^2.1.1",
-            "clone-buffer": "^1.0.0",
-            "clone-stats": "^1.0.0",
-            "cloneable-readable": "^1.0.0",
-            "remove-trailing-separator": "^1.0.1",
-            "replace-ext": "^1.0.0"
-          }
-        }
-      }
-    },
-    "vinyl-sourcemap": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz",
-      "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=",
-      "dev": true,
-      "requires": {
-        "append-buffer": "^1.0.2",
-        "convert-source-map": "^1.5.0",
-        "graceful-fs": "^4.1.6",
-        "normalize-path": "^2.1.1",
-        "now-and-later": "^2.0.0",
-        "remove-bom-buffer": "^3.0.0",
-        "vinyl": "^2.0.0"
-      },
-      "dependencies": {
-        "clone": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz",
-          "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=",
-          "dev": true
-        },
-        "clone-stats": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
-          "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=",
-          "dev": true
-        },
-        "graceful-fs": {
-          "version": "4.1.11",
-          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
-          "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
-          "dev": true
-        },
-        "replace-ext": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
-          "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=",
-          "dev": true
-        },
-        "vinyl": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz",
-          "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==",
-          "dev": true,
-          "requires": {
-            "clone": "^2.1.1",
-            "clone-buffer": "^1.0.0",
-            "clone-stats": "^1.0.0",
-            "cloneable-readable": "^1.0.0",
-            "remove-trailing-separator": "^1.0.1",
-            "replace-ext": "^1.0.0"
-          }
-        }
-      }
-    },
     "w3c-hr-time": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
@@ -12351,13 +7099,11 @@
       }
     },
     "w3c-xmlserializer": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz",
-      "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz",
+      "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==",
       "dev": true,
       "requires": {
-        "domexception": "^1.0.1",
-        "webidl-conversions": "^4.0.2",
         "xml-name-validator": "^3.0.0"
       }
     },
@@ -12371,35 +7117,11 @@
       }
     },
     "webidl-conversions": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
-      "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
+      "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==",
       "dev": true
     },
-    "webpack-config-utils": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/webpack-config-utils/-/webpack-config-utils-2.3.1.tgz",
-      "integrity": "sha512-0uC5uj7sThFTePTQjfpe5Wqcbw3KSCxqswOmW96lwk2ZI2CU098rWY2ZqOVGJQYJ3hfEltmjcLNkKutw8LJAlg==",
-      "dev": true,
-      "requires": {
-        "webpack-combine-loaders": "2.0.4"
-      },
-      "dependencies": {
-        "qs": {
-          "version": "6.5.2",
-          "bundled": true,
-          "dev": true
-        },
-        "webpack-combine-loaders": {
-          "version": "2.0.4",
-          "bundled": true,
-          "dev": true,
-          "requires": {
-            "qs": "^6.5.2"
-          }
-        }
-      }
-    },
     "whatwg-encoding": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",
@@ -12416,29 +7138,43 @@
       "dev": true
     },
     "whatwg-url": {
-      "version": "7.1.0",
-      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
-      "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.1.0.tgz",
+      "integrity": "sha512-vEIkwNi9Hqt4TV9RdnaBPNt+E2Sgmo3gePebCRgZ1R7g6d23+53zCTnuB0amKI4AXq6VM8jj2DUAa0S1vjJxkw==",
       "dev": true,
       "requires": {
         "lodash.sortby": "^4.7.0",
-        "tr46": "^1.0.1",
-        "webidl-conversions": "^4.0.2"
+        "tr46": "^2.0.2",
+        "webidl-conversions": "^5.0.0"
+      },
+      "dependencies": {
+        "webidl-conversions": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz",
+          "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==",
+          "dev": true
+        }
       }
     },
     "which": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
-      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
       "dev": true,
       "requires": {
         "isexe": "^2.0.0"
       }
     },
     "which-module": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
+      "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=",
+      "dev": true
+    },
+    "which-pm-runs": {
       "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
-      "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
+      "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz",
+      "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=",
       "dev": true
     },
     "word-wrap": {
@@ -12447,20 +7183,40 @@
       "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
       "dev": true
     },
-    "wordwrap": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
-      "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
-      "dev": true
-    },
     "wrap-ansi": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
-      "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
+      "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
       "dev": true,
       "requires": {
-        "string-width": "^1.0.1",
-        "strip-ansi": "^3.0.1"
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "dependencies": {
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+          "dev": true
+        },
+        "string-width": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+          "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.0"
+          }
+        }
       }
     },
     "wrappy": {
@@ -12491,9 +7247,9 @@
       }
     },
     "ws": {
-      "version": "7.2.3",
-      "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz",
-      "integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==",
+      "version": "7.3.1",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz",
+      "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==",
       "dev": true
     },
     "xml-name-validator": {
@@ -12502,41 +7258,92 @@
       "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==",
       "dev": true
     },
+    "xml2js": {
+      "version": "0.4.23",
+      "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
+      "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
+      "requires": {
+        "sax": ">=0.6.0",
+        "xmlbuilder": "~11.0.0"
+      }
+    },
+    "xmlbuilder": {
+      "version": "11.0.1",
+      "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+      "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
+    },
     "xmlchars": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
       "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
       "dev": true
     },
-    "xtend": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
-      "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
+    "y18n": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
+      "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==",
       "dev": true
     },
-    "y18n": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
-      "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
+    "yaml": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz",
+      "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==",
       "dev": true
     },
-    "yargs-parser": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz",
-      "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=",
+    "yargs": {
+      "version": "15.4.1",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
+      "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
       "dev": true,
       "requires": {
-        "camelcase": "^3.0.0"
+        "cliui": "^6.0.0",
+        "decamelize": "^1.2.0",
+        "find-up": "^4.1.0",
+        "get-caller-file": "^2.0.1",
+        "require-directory": "^2.1.1",
+        "require-main-filename": "^2.0.0",
+        "set-blocking": "^2.0.0",
+        "string-width": "^4.2.0",
+        "which-module": "^2.0.0",
+        "y18n": "^4.0.0",
+        "yargs-parser": "^18.1.2"
       },
       "dependencies": {
-        "camelcase": {
+        "emoji-regex": {
+          "version": "8.0.0",
+          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+          "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
           "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
-          "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+          "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
           "dev": true
+        },
+        "string-width": {
+          "version": "4.2.0",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+          "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+          "dev": true,
+          "requires": {
+            "emoji-regex": "^8.0.0",
+            "is-fullwidth-code-point": "^3.0.0",
+            "strip-ansi": "^6.0.0"
+          }
         }
       }
     },
+    "yargs-parser": {
+      "version": "18.1.3",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
+      "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
+      "dev": true,
+      "requires": {
+        "camelcase": "^5.0.0",
+        "decamelize": "^1.2.0"
+      }
+    },
     "yn": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
diff --git a/package.json b/package.json
index befa033b28..86de25a924 100644
--- a/package.json
+++ b/package.json
@@ -1,86 +1,65 @@
 {
   "name": "class-validator",
-  "private": true,
-  "version": "0.12.2",
-  "description": "Class-based validation with Typescript / ES6 / ES5 using decorators or validation schemas. Supports both node.js and browser",
+  "version": "0.13.0",
+  "description": "Decorator-based property validation for classes.",
+  "author": "TypeStack contributors",
   "license": "MIT",
-  "readmeFilename": "README.md",
-  "main": "./bundles/index.umd.js",
+  "sideEffects": false,
+  "main": "./cjs/index.js",
   "module": "./esm5/index.js",
   "es2015": "./esm2015/index.js",
   "typings": "./types/index.d.ts",
-  "sideEffects": false,
-  "author": {
-    "name": "Umed Khudoiberdiev",
-    "email": "pleerock.me@gmail.com"
-  },
   "repository": {
     "type": "git",
     "url": "https://github.com/typestack/class-validator.git"
   },
-  "bugs": {
-    "url": "https://github.com/typestack/class-validator/issues"
-  },
   "tags": [
     "validator",
     "validation",
-    "typescript",
-    "typescript-validator"
+    "decorators",
+    "typescript"
   ],
+  "scripts": {
+    "build": "npm run build:cjs",
+    "build:clean": "rimraf build",
+    "build:es2015": "tsc --project tsconfig.prod.esm2015.json",
+    "build:esm5": "tsc --project tsconfig.prod.esm5.json",
+    "build:cjs": "tsc --project tsconfig.prod.cjs.json",
+    "build:umd": "rollup --config rollup.config.js",
+    "build:types": "tsc --project tsconfig.prod.types.json",
+    "prettier:fix": "prettier --write \"**/*.{ts,md}\"",
+    "prettier:check": "prettier --check \"**/*.{ts,md}\"",
+    "lint:fix": "eslint --max-warnings 0 --fix --ext .ts src/",
+    "lint:check": "eslint --max-warnings 0 --ext .ts src/",
+    "test": "jest --coverage --verbose",
+    "test:watch": "jest --watch",
+    "test:ci": "jest --runInBand --no-cache --coverage --verbose"
+  },
   "dependencies": {
-    "@types/validator": "13.0.0",
-    "google-libphonenumber": "^3.2.9",
-    "tslib": ">=1.13.0",
-    "validator": "13.0.0"
+    "libphonenumber-js": "^1.7.57",
+    "validator": "^13.1.1"
   },
   "devDependencies": {
-    "@types/del": "^4.0.0",
-    "@types/gulp": "^4.0.2",
-    "@types/gulp-istanbul": "^0.9.32",
-    "@types/gulp-mocha": "0.0.32",
-    "@types/gulp-replace": "0.0.31",
-    "@types/gulp-sourcemaps": "0.0.32",
-    "@types/jest": "^25.2.1",
-    "@types/node": "^12.7.1",
-    "@types/rollup-plugin-json": "^3.0.2",
-    "@types/rollup-plugin-sourcemaps": "^0.4.2",
-    "@typescript-eslint/eslint-plugin": "^2.29.0",
-    "@typescript-eslint/parser": "^2.29.0",
-    "conventional-changelog-angular": "^5.0.3",
-    "conventional-changelog-cli": "^2.0.21",
-    "del": "^5.0.0",
-    "es6-shim": "^0.35.3",
-    "eslint": "^6.8.0",
-    "eslint-plugin-compat": "^3.5.1",
-    "eslint-plugin-jest": "^23.8.2",
-    "gulp": "^4.0.2",
-    "gulp-conventional-changelog": "^2.0.19",
-    "gulp-replace": "^1.0.0",
-    "gulp-shell": "^0.8.0",
-    "gulp-sourcemaps": "^2.6.4",
-    "gulp-tslint": "^8.1.3",
-    "gulp-typescript": "^5.0.1",
-    "gulpclass": "^0.2.0",
-    "jest": "^25.4.0",
-    "rollup": "^1.20.1",
-    "rollup-plugin-commonjs": "^10.0.2",
-    "rollup-plugin-json": "^4.0.0",
-    "rollup-plugin-node-resolve": "^5.2.0",
-    "rollup-plugin-replace": "^2.2.0",
-    "rollup-plugin-sourcemaps": "^0.4.2",
-    "rollup-plugin-terser": "^5.3.0",
-    "rollup-plugin-uglify": "^6.0.4",
-    "ts-jest": "^25.4.0",
-    "ts-node": "^8.8.1",
-    "tslib": "^1.13.0",
-    "typescript": "^3.5.3",
-    "webpack-config-utils": "^2.3.1"
-  },
-  "scripts": {
-    "build": "gulp package",
-    "test": "gulp tests",
-    "lint": "gulp eslint",
-    "changelog": "gulp changelog"
-  },
-  "browserslist": ["> 5%"]
+    "@rollup/plugin-commonjs": "^15.0.0",
+    "@rollup/plugin-node-resolve": "^9.0.0",
+    "@types/jest": "^26.0.14",
+    "@types/node": "^14.6.4",
+    "@types/validator": "^13.1.0",
+    "@typescript-eslint/eslint-plugin": "^3.10.1",
+    "@typescript-eslint/parser": "^3.10.1",
+    "eslint": "^7.8.1",
+    "eslint-config-prettier": "^6.11.0",
+    "eslint-plugin-jest": "^23.20.0",
+    "husky": "^4.3.0",
+    "jest": "^26.4.2",
+    "lint-staged": "^10.4.0",
+    "prettier": "^2.1.1",
+    "reflect-metadata": "0.1.13",
+    "rimraf": "3.0.2",
+    "rollup": "^2.26.11",
+    "rollup-plugin-terser": "^7.0.2",
+    "ts-jest": "^26.3.0",
+    "ts-node": "^9.0.0",
+    "typescript": "^4.0.2"
+  }
 }
diff --git a/rollup.config.js b/rollup.config.js
new file mode 100644
index 0000000000..32d1ba61fb
--- /dev/null
+++ b/rollup.config.js
@@ -0,0 +1,23 @@
+import { nodeResolve } from '@rollup/plugin-node-resolve';
+import commonjs from '@rollup/plugin-commonjs';
+import { terser } from 'rollup-plugin-terser';
+
+export default {
+  input: 'build/esm5/index.js',
+  output: [
+    {
+      name: 'ClassValidator',
+      format: 'umd',
+      file: 'build/bundles/class-validator.umd.js',
+      sourcemap: true,
+    },
+    {
+      name: 'ClassValidator',
+      format: 'umd',
+      file: 'build/bundles/class-validator.umd.min.js',
+      sourcemap: true,
+      plugins: [terser()],
+    },
+  ],
+  plugins: [commonjs(), nodeResolve()],
+};
diff --git a/sample/sample1-simple-validation/Post.ts b/sample/sample1-simple-validation/Post.ts
index 8a3e2c6f6a..07bda197f1 100644
--- a/sample/sample1-simple-validation/Post.ts
+++ b/sample/sample1-simple-validation/Post.ts
@@ -1,38 +1,49 @@
-import {Contains, IsInt, MinLength, MaxLength, IsEmail, IsFQDN, IsDate, ArrayNotEmpty, ArrayMinSize, ArrayMaxSize, IsEnum} from "../../src/decorator/decorators";
+import {
+  Contains,
+  IsInt,
+  MinLength,
+  MaxLength,
+  IsEmail,
+  IsFQDN,
+  IsDate,
+  ArrayNotEmpty,
+  ArrayMinSize,
+  ArrayMaxSize,
+  IsEnum,
+} from '../../src/decorator/decorators';
 
 export enum PostType {
-    Public,
-    Private
+  Public,
+  Private,
 }
 
 export class Post {
+  @MinLength(10)
+  @MaxLength(20)
+  title: string;
 
-    @MinLength(10)
-    @MaxLength(20)
-    title: string;
+  @Contains('hello')
+  text: string;
 
-    @Contains("hello")
-    text: string;
+  @IsInt()
+  rating: number;
 
-    @IsInt()
-    rating: number;
+  @IsEmail()
+  email: string;
 
-    @IsEmail()
-    email: string;
+  @IsFQDN()
+  site: string;
 
-    @IsFQDN()
-    site: string;
+  @IsDate()
+  createDate: Date;
 
-    @IsDate()
-    createDate: Date;
+  @ArrayNotEmpty()
+  @ArrayMinSize(2)
+  @ArrayMaxSize(5)
+  @MinLength(3, { each: true, message: 'Tag is too short. Minimal length is $value characters' })
+  @MaxLength(50, { each: true, message: 'Tag is too long. Maximal length is $value characters' })
+  tags: string[];
 
-    @ArrayNotEmpty()
-    @ArrayMinSize(2)
-    @ArrayMaxSize(5)
-    @MinLength(3, { each: true, message: "Tag is too short. Minimal length is $value characters" })
-    @MaxLength(50, { each: true, message: "Tag is too long. Maximal length is $value characters" })
-    tags: string[];
-
-    @IsEnum(PostType)
-    type: PostType;
+  @IsEnum(PostType)
+  type: PostType;
 }
diff --git a/sample/sample1-simple-validation/app.ts b/sample/sample1-simple-validation/app.ts
index 8fa0f46526..71f717b05f 100644
--- a/sample/sample1-simple-validation/app.ts
+++ b/sample/sample1-simple-validation/app.ts
@@ -1,171 +1,171 @@
-import {validate} from "../../src/index";
-import {Post, PostType} from "./Post";
+import { validate } from '../../src/index';
+import { Post, PostType } from './Post';
 
 // Sample1. simple validation
 
 let post1 = new Post();
-post1.title = "Hello world"; // should pass
-post1.text = "this is a great post about hello world"; // should pass
+post1.title = 'Hello world'; // should pass
+post1.text = 'this is a great post about hello world'; // should pass
 post1.rating = 10; // should pass
-post1.email = "info@google.com"; // should pass
-post1.site = "google.com"; // should pass
+post1.email = 'info@google.com'; // should pass
+post1.site = 'google.com'; // should pass
 post1.createDate = new Date(); // should pass
-post1.tags = ["abcd1", "abcd2", "abcd3", "abcd4", "abcd4"]; // should pass
+post1.tags = ['abcd1', 'abcd2', 'abcd3', 'abcd4', 'abcd4']; // should pass
 post1.type = PostType.Private;
 
 validate(post1).then(result => {
-    console.log("1. should pass: ", result); // should pass completely, e.g. return empty array
+  console.log('1. should pass: ', result); // should pass completely, e.g. return empty array
 });
 
 let post2 = new Post();
-post2.title = "Hello"; // should not pass
-post2.text = "this is a great post about hell world"; // should not pass
+post2.title = 'Hello'; // should not pass
+post2.text = 'this is a great post about hell world'; // should not pass
 post2.rating = 1.1; // should not pass
-post2.email = "google.com"; // should not pass
-post2.site = "googlecom"; // should not pass
+post2.email = 'google.com'; // should not pass
+post2.site = 'googlecom'; // should not pass
 post2.type = PostType.Private; // should pass
 
 // should not pass because date property is missing
 validate(post2).then(result => {
-    console.log("2. should not pass: ", result); // should not pass completely, must return array of ValidationError-s
+  console.log('2. should not pass: ', result); // should not pass completely, must return array of ValidationError-s
 });
 
 // Sample2. using validation options to skip properties that are not defined
 
 let post3 = new Post();
-post3.title = "Hello"; // should not pass
-post3.text = "this is a great post about hell world"; // should not pass
+post3.title = 'Hello'; // should not pass
+post3.text = 'this is a great post about hell world'; // should not pass
 post3.rating = 1.1; // should not pass
-post3.email = "google.com"; // should not pass
-post3.site = "googlecom"; // should not pass
+post3.email = 'google.com'; // should not pass
+post3.site = 'googlecom'; // should not pass
 post3.type = PostType.Private;
 
 validate(post3, { skipMissingProperties: true }).then(result => {
-    console.log("3. should not pass: ", result); // should not pass, but returned ValidationError-s should not have error about date field
+  console.log('3. should not pass: ', result); // should not pass, but returned ValidationError-s should not have error about date field
 });
 
 let post4 = new Post();
-post4.title = "Hello world"; // should pass
-post4.text = "this is a great post about hello world"; // should pass
+post4.title = 'Hello world'; // should pass
+post4.text = 'this is a great post about hello world'; // should pass
 post4.rating = 10; // should pass
-post4.email = "info@google.com"; // should pass
-post4.site = "google.com"; // should pass
+post4.email = 'info@google.com'; // should pass
+post4.site = 'google.com'; // should pass
 post4.type = PostType.Private;
 
 validate(post4, { skipMissingProperties: true }).then(result => {
-    console.log("4. should pass: ", result); // should pass even if date is not set
+  console.log('4. should pass: ', result); // should pass even if date is not set
 });
 
 // Sample3. using validation groups
 
 let post5 = new Post();
-post5.title = "Hello world"; // should pass
-post5.text = "this is a great post about hello world"; // should pass
+post5.title = 'Hello world'; // should pass
+post5.text = 'this is a great post about hello world'; // should pass
 post5.rating = 10; // should pass
-post5.email = "info@google.com"; // should pass
-post5.site = "google.com"; // should pass
+post5.email = 'info@google.com'; // should pass
+post5.site = 'google.com'; // should pass
 post5.type = PostType.Private;
 
 validate(post5, { skipMissingProperties: true }).then(result => {
-    console.log("5. should pass: ", result); // should pass even if date is not set
+  console.log('5. should pass: ', result); // should pass even if date is not set
 });
 
 // Sample4. array validation
 
 let post6 = new Post();
-post6.title = "Hello world"; // should pass
-post6.text = "this is a great post about hello world"; // should pass
+post6.title = 'Hello world'; // should pass
+post6.text = 'this is a great post about hello world'; // should pass
 post6.rating = 10; // should pass
-post6.email = "info@google.com"; // should pass
-post6.site = "google.com"; // should pass
+post6.email = 'info@google.com'; // should pass
+post6.site = 'google.com'; // should pass
 post6.createDate = new Date(); // should pass
-post6.tags = ["abcd1", "abcd2", "abcd3", "abcd4", "abcd4"];
+post6.tags = ['abcd1', 'abcd2', 'abcd3', 'abcd4', 'abcd4'];
 post6.type = PostType.Private;
 
 validate(post6).then(result => {
-    console.log("6. should pass: ", result); // should pass completely, e.g. return empty array
+  console.log('6. should pass: ', result); // should pass completely, e.g. return empty array
 });
 
 let post7 = new Post();
-post7.title = "Hello world"; // should pass
-post7.text = "this is a great post about hello world"; // should pass
+post7.title = 'Hello world'; // should pass
+post7.text = 'this is a great post about hello world'; // should pass
 post7.rating = 10; // should pass
-post7.email = "info@google.com"; // should pass
-post7.site = "google.com"; // should pass
+post7.email = 'info@google.com'; // should pass
+post7.site = 'google.com'; // should pass
 post7.createDate = new Date(); // should pass
-post7.tags = ["news", "a"];
+post7.tags = ['news', 'a'];
 post7.type = PostType.Private;
 
 validate(post7).then(result => {
-    console.log("7. should not pass: ", result); // should not pass
+  console.log('7. should not pass: ', result); // should not pass
 });
 
 let post8 = new Post();
-post8.title = "Hello world"; // should pass
-post8.text = "this is a great post about hello world"; // should pass
+post8.title = 'Hello world'; // should pass
+post8.text = 'this is a great post about hello world'; // should pass
 post8.rating = 10; // should pass
-post8.email = "info@google.com"; // should pass
-post8.site = "google.com"; // should pass
+post8.email = 'info@google.com'; // should pass
+post8.site = 'google.com'; // should pass
 post8.createDate = new Date(); // should pass
 post8.tags = [];
 post8.type = PostType.Private;
 
 validate(post8).then(result => {
-    console.log("8. should not pass: ", result); // should not pass
+  console.log('8. should not pass: ', result); // should not pass
 });
 
 let post9 = new Post();
-post9.title = "Hello world"; // should pass
-post9.text = "this is a great post about hello world"; // should pass
+post9.title = 'Hello world'; // should pass
+post9.text = 'this is a great post about hello world'; // should pass
 post9.rating = 10; // should pass
-post9.email = "info@google.com"; // should pass
-post9.site = "google.com"; // should pass
+post9.email = 'info@google.com'; // should pass
+post9.site = 'google.com'; // should pass
 post9.createDate = new Date(); // should pass
-post9.tags = ["abcd1", "abcd2", "abcd3", "abcd4", "abcd4", "abcd4"];
+post9.tags = ['abcd1', 'abcd2', 'abcd3', 'abcd4', 'abcd4', 'abcd4'];
 post9.type = PostType.Private;
 
 validate(post9).then(result => {
-    console.log("9. should not pass: ", result); // should not pass
+  console.log('9. should not pass: ', result); // should not pass
 });
 
 let post10 = new Post();
-post10.title = "Hello world"; // should pass
-post10.text = "this is a great post about hello world"; // should pass
+post10.title = 'Hello world'; // should pass
+post10.text = 'this is a great post about hello world'; // should pass
 post10.rating = 10; // should pass
-post10.email = "info@google.com"; // should pass
-post10.site = "google.com"; // should pass
+post10.email = 'info@google.com'; // should pass
+post10.site = 'google.com'; // should pass
 post10.createDate = new Date(); // should pass
-post10.tags = ["abcd1", "abcd2", "abcd3", "abcd4", "abcd4"];
+post10.tags = ['abcd1', 'abcd2', 'abcd3', 'abcd4', 'abcd4'];
 post10.type = PostType.Private;
 
 validate(post10).then(result => {
-    console.log("10. should pass: ", result); // should pass
+  console.log('10. should pass: ', result); // should pass
 });
 
 let post11 = new Post();
-post11.title = "Hello world"; // should pass
-post11.text = "this is a great post about hello world"; // should pass
+post11.title = 'Hello world'; // should pass
+post11.text = 'this is a great post about hello world'; // should pass
 post11.rating = 10; // should pass
-post11.email = "info@google.com"; // should pass
-post11.site = "google.com"; // should pass
+post11.email = 'info@google.com'; // should pass
+post11.site = 'google.com'; // should pass
 post11.createDate = new Date(); // should pass
 post11.tags = null;
 post11.type = PostType.Private;
 
 validate(post11).then(result => {
-    console.log("11. should not pass: ", result); // should not pass
+  console.log('11. should not pass: ', result); // should not pass
 });
 
 let post12 = new Post();
-post12.title = "Hello world"; // should pass
-post12.text = "this is a great post about hello world"; // should pass
+post12.title = 'Hello world'; // should pass
+post12.text = 'this is a great post about hello world'; // should pass
 post12.rating = 10; // should pass
-post12.email = "info@google.com"; // should pass
-post12.site = "google.com"; // should pass
+post12.email = 'info@google.com'; // should pass
+post12.site = 'google.com'; // should pass
 post12.createDate = new Date(); // should pass
-post12.tags = ["abcd1", "abcd2", "abcd3", "abcd4", "abcd4"]; // should pass
+post12.tags = ['abcd1', 'abcd2', 'abcd3', 'abcd4', 'abcd4']; // should pass
 post12.type = 99; // should not pass
 
 validate(post1).then(result => {
-    console.log("12. should not pass: ", result); // should not pass as type is not a valid enum
+  console.log('12. should not pass: ', result); // should not pass as type is not a valid enum
 });
diff --git a/sample/sample2-using-groups/Post.ts b/sample/sample2-using-groups/Post.ts
index 4ae81ce862..9e2916733e 100644
--- a/sample/sample2-using-groups/Post.ts
+++ b/sample/sample2-using-groups/Post.ts
@@ -1,38 +1,36 @@
-import {Contains, IsInt, Length, IsEmail, IsFQDN, IsDate} from "../../src/decorator/decorators";
+import { Contains, IsInt, Length, IsEmail, IsFQDN, IsDate } from '../../src/decorator/decorators';
 
 export class Post {
-
-    @Length(10, 20, {
-        message: "Incorrect length!",
-        groups: ["users", "moderators"]
-    })
-    @Length(0, 20, {
-        message: "Incorrect length!",
-        groups: ["admins"]
-    })
-    title: string;
-
-    @Contains("hello", {
-        message: "It should contain word \"hello!\"",
-        groups: ["users", "moderators"]
-    })
-    text: string;
-
-    @IsInt()
-    rating: number;
-
-    @IsEmail(undefined, {
-        always: true
-    })
-    email: string;
-
-    @IsFQDN(undefined, {
-        message: "Site address should be correct",
-        groups: ["users"]
-    })
-    site: string;
-
-    @IsDate()
-    createDate: Date;
-
-}
\ No newline at end of file
+  @Length(10, 20, {
+    message: 'Incorrect length!',
+    groups: ['users', 'moderators'],
+  })
+  @Length(0, 20, {
+    message: 'Incorrect length!',
+    groups: ['admins'],
+  })
+  title: string;
+
+  @Contains('hello', {
+    message: 'It should contain word "hello!"',
+    groups: ['users', 'moderators'],
+  })
+  text: string;
+
+  @IsInt()
+  rating: number;
+
+  @IsEmail(undefined, {
+    always: true,
+  })
+  email: string;
+
+  @IsFQDN(undefined, {
+    message: 'Site address should be correct',
+    groups: ['users'],
+  })
+  site: string;
+
+  @IsDate()
+  createDate: Date;
+}
diff --git a/sample/sample2-using-groups/app.ts b/sample/sample2-using-groups/app.ts
index c0aa999f62..64cbe298a5 100644
--- a/sample/sample2-using-groups/app.ts
+++ b/sample/sample2-using-groups/app.ts
@@ -1,76 +1,76 @@
-import {Validator} from "../../src/validation/Validator";
-import {Post} from "./Post";
+import { Validator } from '../../src/validation/Validator';
+import { Post } from './Post';
 
 let validator = new Validator();
 
 let post1 = new Post();
-post1.title = "Hello world"; // should pass
-post1.text = "this is a great post about hello world"; // should pass
+post1.title = 'Hello world'; // should pass
+post1.text = 'this is a great post about hello world'; // should pass
 post1.rating = 10; // should pass
-post1.email = "info@google.com"; // should pass
-post1.site = "google.com"; // should pass
+post1.email = 'info@google.com'; // should pass
+post1.site = 'google.com'; // should pass
 post1.createDate = new Date(); // should pass
 
-validator.validate(post1, { groups: ["users"] }).then(result => {
-    console.log("1.1. should pass: ", result);
+validator.validate(post1, { groups: ['users'] }).then(result => {
+  console.log('1.1. should pass: ', result);
 });
 
-validator.validate(post1, { groups: ["admins"] }).then(result => {
-    console.log("1.2. should pass: ", result);
+validator.validate(post1, { groups: ['admins'] }).then(result => {
+  console.log('1.2. should pass: ', result);
 });
 
 let post2 = new Post();
-post2.title = "Hi!"; // should not pass for user or moderator, but should pass for admin
-post2.text = "this is a great post about hello world"; // should pass
+post2.title = 'Hi!'; // should not pass for user or moderator, but should pass for admin
+post2.text = 'this is a great post about hello world'; // should pass
 post2.rating = 10; // should pass
-post2.email = "info@google.com"; // should pass
-post2.site = "google.com"; // should pass
+post2.email = 'info@google.com'; // should pass
+post2.site = 'google.com'; // should pass
 post2.createDate = new Date(); // should pass
 
-validator.validate(post2, { groups: ["users"] }).then(result => {
-    console.log("2.1. should not pass: ", result);
+validator.validate(post2, { groups: ['users'] }).then(result => {
+  console.log('2.1. should not pass: ', result);
 });
 
-validator.validate(post2, { groups: ["moderators"] }).then(result => {
-    console.log("2.2. should not pass: ", result);
+validator.validate(post2, { groups: ['moderators'] }).then(result => {
+  console.log('2.2. should not pass: ', result);
 });
 
-validator.validate(post2, { groups: ["admins"] }).then(result => {
-    console.log("2.3. should pass: ", result);
+validator.validate(post2, { groups: ['admins'] }).then(result => {
+  console.log('2.3. should pass: ', result);
 });
 
-validator.validate(post2, { groups: ["users", "admins"] }).then(result => {
-    console.log("2.4. should not pass: ", result);
+validator.validate(post2, { groups: ['users', 'admins'] }).then(result => {
+  console.log('2.4. should not pass: ', result);
 });
 
 let post3 = new Post();
-post3.title = "Hello world"; // should not pass for user or moderator, but should pass for admin
-post3.text = "this is a great post about hello world"; // should pass
+post3.title = 'Hello world'; // should not pass for user or moderator, but should pass for admin
+post3.text = 'this is a great post about hello world'; // should pass
 post3.rating = 10; // should pass
-post3.email = "info@google.com"; // should pass
-post3.site = "google.com"; // should pass
+post3.email = 'info@google.com'; // should pass
+post3.site = 'google.com'; // should pass
 // note that we dont set date
 
-validator.validate(post3, { groups: ["users"] }).then(result => {
-    console.log("3.1. should pass: ", result);
+validator.validate(post3, { groups: ['users'] }).then(result => {
+  console.log('3.1. should pass: ', result);
 });
 
 validator.validate(post3).then(result => {
-    console.log("3.2. should not pass: ", result);
+  console.log('3.2. should not pass: ', result);
 });
 
 let post4 = new Post();
-post4.title = "Hello world"; // should not pass for user or moderator, but should pass for admin
-post4.text = "this is a great post about hello world"; // should pass
+post4.title = 'Hello world'; // should not pass for user or moderator, but should pass for admin
+post4.text = 'this is a great post about hello world'; // should pass
 post4.rating = 10; // should pass
-post4.email = ""; // should not pass
-post4.site = "google.com"; // should pass
+post4.email = ''; // should not pass
+post4.site = 'google.com'; // should pass
 // note that we dont set date
 
-validator.validate(post4, { groups: ["users"] }).then(result => {
-    console.log("4.1. should not pass: ", result);
+validator.validate(post4, { groups: ['users'] }).then(result => {
+  console.log('4.1. should not pass: ', result);
 });
 
 validator.validate(post4).then(result => {
-    console.log("4.2. should not pass: ", result);
-});
\ No newline at end of file
+  console.log('4.2. should not pass: ', result);
+});
diff --git a/sample/sample3-nested-objects/Post.ts b/sample/sample3-nested-objects/Post.ts
index 85e794be87..7b55a240ca 100644
--- a/sample/sample3-nested-objects/Post.ts
+++ b/sample/sample3-nested-objects/Post.ts
@@ -1,14 +1,12 @@
-import {Contains, IsInt, Length, IsEmail, IsFQDN, IsDate, ValidateNested} from "../../src/decorator/decorators";
-import {Tag} from "./Tag";
+import { Contains, IsInt, Length, IsEmail, IsFQDN, IsDate, ValidateNested } from '../../src/decorator/decorators';
+import { Tag } from './Tag';
 
 export class Post {
-
-    @Length(10, 20, {
-        message: "Incorrect length!"
-    })
-    title: string;
-
-    @ValidateNested()
-    tags: Tag[];
-
-}
\ No newline at end of file
+  @Length(10, 20, {
+    message: 'Incorrect length!',
+  })
+  title: string;
+
+  @ValidateNested()
+  tags: Tag[];
+}
diff --git a/sample/sample3-nested-objects/Tag.ts b/sample/sample3-nested-objects/Tag.ts
index c547f90ec3..1b2878acbf 100644
--- a/sample/sample3-nested-objects/Tag.ts
+++ b/sample/sample3-nested-objects/Tag.ts
@@ -1,10 +1,8 @@
-import {Contains, IsInt, Length, IsEmail, IsFQDN, IsDate} from "../../src/decorator/decorators";
+import { Contains, IsInt, Length, IsEmail, IsFQDN, IsDate } from '../../src/decorator/decorators';
 
 export class Tag {
-
-    @Length(10, 20, {
-        message: "Tag is too short or long"
-    })
-    name: string;
-
-}
\ No newline at end of file
+  @Length(10, 20, {
+    message: 'Tag is too short or long',
+  })
+  name: string;
+}
diff --git a/sample/sample3-nested-objects/app.ts b/sample/sample3-nested-objects/app.ts
index 494791d623..61ff03d5ad 100644
--- a/sample/sample3-nested-objects/app.ts
+++ b/sample/sample3-nested-objects/app.ts
@@ -1,19 +1,19 @@
-import {Validator} from "../../src/validation/Validator";
-import {Post} from "./Post";
-import {Tag} from "./Tag";
+import { Validator } from '../../src/validation/Validator';
+import { Post } from './Post';
+import { Tag } from './Tag';
 
 let validator = new Validator();
 
 let tag1 = new Tag();
-tag1.name = "ja";
+tag1.name = 'ja';
 
 let tag2 = new Tag();
-tag2.name = "node.js";
+tag2.name = 'node.js';
 
 let post1 = new Post();
-post1.title = "Hello world";
+post1.title = 'Hello world';
 post1.tags = [tag1, tag2];
 
 validator.validate(post1).then(result => {
-    console.log("1. should not pass: ", result);
-});
\ No newline at end of file
+  console.log('1. should not pass: ', result);
+});
diff --git a/sample/sample4-custom-validator/CustomTextLength.ts b/sample/sample4-custom-validator/CustomTextLength.ts
index 04e3746e83..b5a9a2dd14 100644
--- a/sample/sample4-custom-validator/CustomTextLength.ts
+++ b/sample/sample4-custom-validator/CustomTextLength.ts
@@ -1,11 +1,9 @@
-import {ValidatorConstraintInterface} from "../../src/validation/ValidatorConstraintInterface";
-import {ValidatorConstraint} from "../../src/decorator/decorators";
+import { ValidatorConstraintInterface } from '../../src/validation/ValidatorConstraintInterface';
+import { ValidatorConstraint } from '../../src/decorator/decorators';
 
 @ValidatorConstraint()
 export class CustomTextLength implements ValidatorConstraintInterface {
-
-    validate(text: string) {
-        return text.length > 1 && text.length < 10;
-    }
-
-}
\ No newline at end of file
+  validate(text: string) {
+    return text.length > 1 && text.length < 10;
+  }
+}
diff --git a/sample/sample4-custom-validator/Post.ts b/sample/sample4-custom-validator/Post.ts
index 6a4d226c0a..e2978c7780 100644
--- a/sample/sample4-custom-validator/Post.ts
+++ b/sample/sample4-custom-validator/Post.ts
@@ -1,12 +1,22 @@
-import {Contains, IsInt, MinLength, MaxLength, IsEmail, IsFQDN, IsDate, IsNotEmpty, ArrayNotEmpty, ArrayMinSize, ArrayMaxSize} from "../../src/decorator/decorators";
-import {Validate} from "../../src/decorator/decorators";
-import {CustomTextLength} from "./CustomTextLength";
+import {
+  Contains,
+  IsInt,
+  MinLength,
+  MaxLength,
+  IsEmail,
+  IsFQDN,
+  IsDate,
+  IsNotEmpty,
+  ArrayNotEmpty,
+  ArrayMinSize,
+  ArrayMaxSize,
+} from '../../src/decorator/decorators';
+import { Validate } from '../../src/decorator/decorators';
+import { CustomTextLength } from './CustomTextLength';
 
 export class Post {
-
-    @Validate(CustomTextLength, {
-        message: "Wrong post title"
-    })
-    title: string;
-
-}
\ No newline at end of file
+  @Validate(CustomTextLength, {
+    message: 'Wrong post title',
+  })
+  title: string;
+}
diff --git a/sample/sample4-custom-validator/app.ts b/sample/sample4-custom-validator/app.ts
index ada11cbfd7..83bb705bbd 100644
--- a/sample/sample4-custom-validator/app.ts
+++ b/sample/sample4-custom-validator/app.ts
@@ -1,18 +1,18 @@
-import {Validator} from "../../src/validation/Validator";
-import {Post} from "./Post";
+import { Validator } from '../../src/validation/Validator';
+import { Post } from './Post';
 
 let validator = new Validator();
 
 let post1 = new Post();
-post1.title = "Hello world";
+post1.title = 'Hello world';
 
 validator.validate(post1).then(result => {
-    console.log("1. should not pass: ", result);
+  console.log('1. should not pass: ', result);
 });
 
 let post2 = new Post();
-post2.title = "Hello !!!";
+post2.title = 'Hello !!!';
 
 validator.validate(post2).then(result => {
-    console.log("2. should pass: ", result);
+  console.log('2. should pass: ', result);
 });
diff --git a/sample/sample5-schemas/Post.ts b/sample/sample5-schemas/Post.ts
index 234dfc312f..1d132407d0 100644
--- a/sample/sample5-schemas/Post.ts
+++ b/sample/sample5-schemas/Post.ts
@@ -1,11 +1,9 @@
 export class Post {
-
-    title: string;
-    text: string;
-    rating: number;
-    email: string;
-    site: string;
-    createDate: Date;
-    tags: string[];
-
-}
\ No newline at end of file
+  title: string;
+  text: string;
+  rating: number;
+  email: string;
+  site: string;
+  createDate: Date;
+  tags: string[];
+}
diff --git a/sample/sample5-schemas/app.ts b/sample/sample5-schemas/app.ts
index 9c5c4a6dde..592b3a77df 100644
--- a/sample/sample5-schemas/app.ts
+++ b/sample/sample5-schemas/app.ts
@@ -1,8 +1,8 @@
-import {validate, registerSchema} from "../../src/index";
-import {Post} from "./Post";
+import { validate, registerSchema } from '../../src/index';
+import { Post } from './Post';
 
 // load schema. we load it a bit tricky way because we output source code into separate directory, so our json resource left in another directory
-const postSchema = require(__dirname + "/../../../../sample/sample5-schemas/post.json");
+const postSchema = require(__dirname + '/../../../../sample/sample5-schemas/post.json');
 
 // register this schema
 registerSchema(postSchema);
@@ -10,143 +10,143 @@ registerSchema(postSchema);
 // Sample1. simple validation
 
 let post1 = new Post();
-post1.title = "Hello world"; // should pass
-post1.text = "this is a great post about hello world"; // should pass
+post1.title = 'Hello world'; // should pass
+post1.text = 'this is a great post about hello world'; // should pass
 post1.rating = 10; // should pass
-post1.email = "info@google.com"; // should pass
-post1.site = "google.com"; // should pass
+post1.email = 'info@google.com'; // should pass
+post1.site = 'google.com'; // should pass
 post1.createDate = new Date(); // should pass
-post1.tags = ["abcd1", "abcd2", "abcd3", "abcd4", "abcd4"]; // should pass
+post1.tags = ['abcd1', 'abcd2', 'abcd3', 'abcd4', 'abcd4']; // should pass
 
-validate("post", post1).then(result => {
-    console.log("1. should pass: ", result); // should pass completely, e.g. return empty array
+validate('post', post1).then(result => {
+  console.log('1. should pass: ', result); // should pass completely, e.g. return empty array
 });
 
 let post2 = new Post();
-post2.title = "Hello"; // should not pass
-post2.text = "this is a great post about hell world"; // should not pass
+post2.title = 'Hello'; // should not pass
+post2.text = 'this is a great post about hell world'; // should not pass
 post2.rating = 11; // should not pass
-post2.email = "google.com"; // should not pass
-post2.site = "googlecom"; // should not pass
+post2.email = 'google.com'; // should not pass
+post2.site = 'googlecom'; // should not pass
 // should not pass because date property is missing
 
-validate("post", post2).then(result => {
-    console.log("2. should not pass: ", result); // should not pass completely, must return array of ValidationError-s
+validate('post', post2).then(result => {
+  console.log('2. should not pass: ', result); // should not pass completely, must return array of ValidationError-s
 });
 
 // Sample2. using validation options to skip properties that are not defined
 
 let post3 = new Post();
-post3.title = "Hello"; // should not pass
-post3.text = "this is a great post about hell world"; // should not pass
+post3.title = 'Hello'; // should not pass
+post3.text = 'this is a great post about hell world'; // should not pass
 post3.rating = 11; // should not pass
-post3.email = "google.com"; // should not pass
-post3.site = "googlecom"; // should not pass
+post3.email = 'google.com'; // should not pass
+post3.site = 'googlecom'; // should not pass
 
-validate("post", post3, { skipMissingProperties: true }).then(result => {
-    console.log("3. should not pass: ", result); // should not pass, but returned ValidationError-s should not have error about date field
+validate('post', post3, { skipMissingProperties: true }).then(result => {
+  console.log('3. should not pass: ', result); // should not pass, but returned ValidationError-s should not have error about date field
 });
 
 let post4 = new Post();
-post4.title = "Hello world"; // should pass
-post4.text = "this is a great post about hello world"; // should pass
+post4.title = 'Hello world'; // should pass
+post4.text = 'this is a great post about hello world'; // should pass
 post4.rating = 10; // should pass
-post4.email = "info@google.com"; // should pass
-post4.site = "google.com"; // should pass
+post4.email = 'info@google.com'; // should pass
+post4.site = 'google.com'; // should pass
 
-validate("post", post4, { skipMissingProperties: true }).then(result => {
-    console.log("4. should pass: ", result); // should pass even if date is not set
+validate('post', post4, { skipMissingProperties: true }).then(result => {
+  console.log('4. should pass: ', result); // should pass even if date is not set
 });
 
 // Sample3. using validation groups
 
 let post5 = new Post();
-post5.title = "Hello world"; // should pass
-post5.text = "this is a great post about hello world"; // should pass
+post5.title = 'Hello world'; // should pass
+post5.text = 'this is a great post about hello world'; // should pass
 post5.rating = 10; // should pass
-post5.email = "info@google.com"; // should pass
-post5.site = "google.com"; // should pass
+post5.email = 'info@google.com'; // should pass
+post5.site = 'google.com'; // should pass
 
-validate("post", post5, { skipMissingProperties: true }).then(result => {
-    console.log("5. should pass: ", result); // should pass even if date is not set
+validate('post', post5, { skipMissingProperties: true }).then(result => {
+  console.log('5. should pass: ', result); // should pass even if date is not set
 });
 
 // Sample4. array validation
 
 let post6 = new Post();
-post6.title = "Hello world"; // should pass
-post6.text = "this is a great post about hello world"; // should pass
+post6.title = 'Hello world'; // should pass
+post6.text = 'this is a great post about hello world'; // should pass
 post6.rating = 10; // should pass
-post6.email = "info@google.com"; // should pass
-post6.site = "google.com"; // should pass
+post6.email = 'info@google.com'; // should pass
+post6.site = 'google.com'; // should pass
 post6.createDate = new Date(); // should pass
-post6.tags = ["abcd1", "abcd2", "abcd3", "abcd4", "abcd4"];
+post6.tags = ['abcd1', 'abcd2', 'abcd3', 'abcd4', 'abcd4'];
 
-validate("post", post6).then(result => {
-    console.log("6. should pass: ", result); // should pass completely, e.g. return empty array
+validate('post', post6).then(result => {
+  console.log('6. should pass: ', result); // should pass completely, e.g. return empty array
 });
 
 let post7 = new Post();
-post7.title = "Hello world"; // should pass
-post7.text = "this is a great post about hello world"; // should pass
+post7.title = 'Hello world'; // should pass
+post7.text = 'this is a great post about hello world'; // should pass
 post7.rating = 10; // should pass
-post7.email = "info@google.com"; // should pass
-post7.site = "google.com"; // should pass
+post7.email = 'info@google.com'; // should pass
+post7.site = 'google.com'; // should pass
 post7.createDate = new Date(); // should pass
-post7.tags = ["news", "a"];
+post7.tags = ['news', 'a'];
 
-validate("post", post7).then(result => {
-    console.log("7. should not pass: ", result); // should not pass
+validate('post', post7).then(result => {
+  console.log('7. should not pass: ', result); // should not pass
 });
 
 let post8 = new Post();
-post8.title = "Hello world"; // should pass
-post8.text = "this is a great post about hello world"; // should pass
+post8.title = 'Hello world'; // should pass
+post8.text = 'this is a great post about hello world'; // should pass
 post8.rating = 10; // should pass
-post8.email = "info@google.com"; // should pass
-post8.site = "google.com"; // should pass
+post8.email = 'info@google.com'; // should pass
+post8.site = 'google.com'; // should pass
 post8.createDate = new Date(); // should pass
 post8.tags = [];
 
-validate("post", post8).then(result => {
-    console.log("8. should not pass: ", result); // should not pass
+validate('post', post8).then(result => {
+  console.log('8. should not pass: ', result); // should not pass
 });
 
 let post9 = new Post();
-post9.title = "Hello world"; // should pass
-post9.text = "this is a great post about hello world"; // should pass
+post9.title = 'Hello world'; // should pass
+post9.text = 'this is a great post about hello world'; // should pass
 post9.rating = 10; // should pass
-post9.email = "info@google.com"; // should pass
-post9.site = "google.com"; // should pass
+post9.email = 'info@google.com'; // should pass
+post9.site = 'google.com'; // should pass
 post9.createDate = new Date(); // should pass
-post9.tags = ["a", "abcd1", "abcd2", "abcd3", "abcd4", "abcd4", "abcd4"];
+post9.tags = ['a', 'abcd1', 'abcd2', 'abcd3', 'abcd4', 'abcd4', 'abcd4'];
 
-validate("post", post9).then(result => {
-    console.log("9. should not pass: ", result); // should not pass
+validate('post', post9).then(result => {
+  console.log('9. should not pass: ', result); // should not pass
 });
 
 let post10 = new Post();
-post10.title = "Hello world"; // should pass
-post10.text = "this is a great post about hello world"; // should pass
+post10.title = 'Hello world'; // should pass
+post10.text = 'this is a great post about hello world'; // should pass
 post10.rating = 10; // should pass
-post10.email = "info@google.com"; // should pass
-post10.site = "google.com"; // should pass
+post10.email = 'info@google.com'; // should pass
+post10.site = 'google.com'; // should pass
 post10.createDate = new Date(); // should pass
-post10.tags = ["abcd1", "abcd2", "abcd3", "abcd4", "abcd4"];
+post10.tags = ['abcd1', 'abcd2', 'abcd3', 'abcd4', 'abcd4'];
 
-validate("post", post10).then(result => {
-    console.log("10. should pass: ", result); // should pass
+validate('post', post10).then(result => {
+  console.log('10. should pass: ', result); // should pass
 });
 
 let post11 = new Post();
-post11.title = "Hello world"; // should pass
-post11.text = "this is a great post about hello world"; // should pass
+post11.title = 'Hello world'; // should pass
+post11.text = 'this is a great post about hello world'; // should pass
 post11.rating = 10; // should pass
-post11.email = "info@google.com"; // should pass
-post11.site = "google.com"; // should pass
+post11.email = 'info@google.com'; // should pass
+post11.site = 'google.com'; // should pass
 post11.createDate = new Date(); // should pass
 post11.tags = null;
 
-validate("post", post11).then(result => {
-    console.log("11. should not pass: ", result); // should not pass
-});
\ No newline at end of file
+validate('post', post11).then(result => {
+  console.log('11. should not pass: ', result); // should not pass
+});
diff --git a/sample/sample6-custom-decorator/IsLongerThan.ts b/sample/sample6-custom-decorator/IsLongerThan.ts
index 90bde6e092..21be1f3417 100644
--- a/sample/sample6-custom-decorator/IsLongerThan.ts
+++ b/sample/sample6-custom-decorator/IsLongerThan.ts
@@ -1,30 +1,26 @@
-import {registerDecorator} from "../../src/index";
-import {ValidationOptions} from "../../src/decorator/ValidationOptions";
-import {ValidatorConstraintInterface} from "../../src/validation/ValidatorConstraintInterface";
-import {ValidatorConstraint} from "../../src/decorator/decorators";
-import {ValidationArguments} from "../../src/validation/ValidationArguments";
+import { registerDecorator } from '../../src/index';
+import { ValidationOptions } from '../../src/decorator/ValidationOptions';
+import { ValidatorConstraintInterface } from '../../src/validation/ValidatorConstraintInterface';
+import { ValidatorConstraint } from '../../src/decorator/decorators';
+import { ValidationArguments } from '../../src/validation/ValidationArguments';
 
 export function IsLongerThan(property: string, validationOptions?: ValidationOptions) {
-    return function (object: Object, propertyName: string) {
-        registerDecorator({
-            target: object.constructor,
-            propertyName: propertyName,
-            options: validationOptions,
-            constraints: [property],
-            validator: IsLongerThanConstraint
-        });
-    };
+  return function (object: Object, propertyName: string) {
+    registerDecorator({
+      target: object.constructor,
+      propertyName: propertyName,
+      options: validationOptions,
+      constraints: [property],
+      validator: IsLongerThanConstraint,
+    });
+  };
 }
 
-@ValidatorConstraint({ name: "isLongerThan" })
+@ValidatorConstraint({ name: 'isLongerThan' })
 export class IsLongerThanConstraint implements ValidatorConstraintInterface {
-    
-    validate(value: any, args: ValidationArguments) {
-        const [relatedPropertyName] = args.constraints;
-        const relatedValue = (args.object as any)[relatedPropertyName];
-        return  typeof value === "string" && 
-                typeof relatedValue === "string" && 
-                value.length > relatedValue.length;
-    }
-    
-}
\ No newline at end of file
+  validate(value: any, args: ValidationArguments) {
+    const [relatedPropertyName] = args.constraints;
+    const relatedValue = (args.object as any)[relatedPropertyName];
+    return typeof value === 'string' && typeof relatedValue === 'string' && value.length > relatedValue.length;
+  }
+}
diff --git a/sample/sample6-custom-decorator/IsUserAlreadyExist.ts b/sample/sample6-custom-decorator/IsUserAlreadyExist.ts
index 49474e9c61..6cf59f7a3a 100644
--- a/sample/sample6-custom-decorator/IsUserAlreadyExist.ts
+++ b/sample/sample6-custom-decorator/IsUserAlreadyExist.ts
@@ -1,26 +1,26 @@
-import {registerDecorator} from "../../src/index";
-import {ValidationOptions} from "../../src/decorator/ValidationOptions";
-import {ValidationArguments} from "../../src/validation/ValidationArguments";
+import { registerDecorator } from '../../src/index';
+import { ValidationOptions } from '../../src/decorator/ValidationOptions';
+import { ValidationArguments } from '../../src/validation/ValidationArguments';
 
 export function IsUserAlreadyExist(validationOptions?: ValidationOptions) {
-    return function (object: Object, propertyName: string) {
-        registerDecorator({
-            name: "isUserAlreadyExist",
-            async: true,
-            target: object.constructor,
-            propertyName: propertyName,
-            options: validationOptions,
-            validator: {
-                validate(value: any, args: ValidationArguments) {
-                    return new Promise(ok => {
-                        if (value !== "admin" && value !== "user") {
-                            ok(true);
-                        } else {
-                            ok(false);
-                        }
-                    });
-                }
+  return function (object: Object, propertyName: string) {
+    registerDecorator({
+      name: 'isUserAlreadyExist',
+      async: true,
+      target: object.constructor,
+      propertyName: propertyName,
+      options: validationOptions,
+      validator: {
+        validate(value: any, args: ValidationArguments) {
+          return new Promise(ok => {
+            if (value !== 'admin' && value !== 'user') {
+              ok(true);
+            } else {
+              ok(false);
             }
-        });
-    };
-}
\ No newline at end of file
+          });
+        },
+      },
+    });
+  };
+}
diff --git a/sample/sample6-custom-decorator/User.ts b/sample/sample6-custom-decorator/User.ts
index 549fe706a6..6c0950a1ad 100644
--- a/sample/sample6-custom-decorator/User.ts
+++ b/sample/sample6-custom-decorator/User.ts
@@ -1,16 +1,14 @@
-import {IsUserAlreadyExist} from "./IsUserAlreadyExist";
-import {IsLongerThan} from "./IsLongerThan";
+import { IsUserAlreadyExist } from './IsUserAlreadyExist';
+import { IsLongerThan } from './IsLongerThan';
 
 export class User {
+  @IsUserAlreadyExist({
+    message: 'User with name $value already exists',
+  })
+  firstName: string;
 
-    @IsUserAlreadyExist({
-        message: "User with name $value already exists"
-    })
-    firstName: string;
-
-    @IsLongerThan("firstName", {
-        message: "User's last name must be longer than firstName"
-    })
-    lastName: string;
-    
-}
\ No newline at end of file
+  @IsLongerThan('firstName', {
+    message: "User's last name must be longer than firstName",
+  })
+  lastName: string;
+}
diff --git a/sample/sample6-custom-decorator/app.ts b/sample/sample6-custom-decorator/app.ts
index a0bed65ff3..1f3eb93db5 100644
--- a/sample/sample6-custom-decorator/app.ts
+++ b/sample/sample6-custom-decorator/app.ts
@@ -1,41 +1,41 @@
-import {Validator} from "../../src/validation/Validator";
-import {User} from "./User";
+import { Validator } from '../../src/validation/Validator';
+import { User } from './User';
 
 let validator = new Validator();
 
 let user1 = new User();
-user1.firstName = "Umed";
+user1.firstName = 'Umed';
 
 validator.validate(user1, { skipMissingProperties: true }).then(result => {
-    console.log("1. should pass: ", result);
+  console.log('1. should pass: ', result);
 });
 
 let user2 = new User();
-user2.firstName = "admin";
+user2.firstName = 'admin';
 
 validator.validate(user2, { skipMissingProperties: true }).then(result => {
-    console.log("2. should not pass: ", result);
+  console.log('2. should not pass: ', result);
 });
 
 let user3 = new User();
-user3.firstName = "user";
+user3.firstName = 'user';
 
 validator.validate(user3, { skipMissingProperties: true }).then(result => {
-    console.log("3. should not pass: ", result);
+  console.log('3. should not pass: ', result);
 });
 
 let user4 = new User();
-user4.firstName = "Zak";
-user4.lastName = "Henry";
+user4.firstName = 'Zak';
+user4.lastName = 'Henry';
 
 validator.validate(user4).then(result => {
-    console.log("4. should pass: ", result);
+  console.log('4. should pass: ', result);
 });
 
 let user5 = new User();
-user5.firstName = "Henry";
-user5.lastName = "Zak";
+user5.firstName = 'Henry';
+user5.lastName = 'Zak';
 
 validator.validate(user5).then(result => {
-    console.log("5. should not pass: ", result);
-});
\ No newline at end of file
+  console.log('5. should not pass: ', result);
+});
diff --git a/sample/sample7-inheritance-support/BaseContent.ts b/sample/sample7-inheritance-support/BaseContent.ts
index e6b0171fbd..3b6958eec8 100644
--- a/sample/sample7-inheritance-support/BaseContent.ts
+++ b/sample/sample7-inheritance-support/BaseContent.ts
@@ -1,8 +1,6 @@
-import {IsEmail} from "../../src/decorator/decorators";
+import { IsEmail } from '../../src/decorator/decorators';
 
 export class BaseContent {
-
-    @IsEmail()
-    email: string;
-
-}
\ No newline at end of file
+  @IsEmail()
+  email: string;
+}
diff --git a/sample/sample7-inheritance-support/Post.ts b/sample/sample7-inheritance-support/Post.ts
index 6d3a6d2325..e57db37d1b 100644
--- a/sample/sample7-inheritance-support/Post.ts
+++ b/sample/sample7-inheritance-support/Post.ts
@@ -1,16 +1,14 @@
-import {Contains, IsInt, MinLength, MaxLength} from "../../src/decorator/decorators";
-import {BaseContent} from "./BaseContent";
+import { Contains, IsInt, MinLength, MaxLength } from '../../src/decorator/decorators';
+import { BaseContent } from './BaseContent';
 
 export class Post extends BaseContent {
+  @MinLength(10)
+  @MaxLength(20)
+  title: string;
 
-    @MinLength(10)
-    @MaxLength(20)
-    title: string;
+  @Contains('hello')
+  text: string;
 
-    @Contains("hello")
-    text: string;
-
-    @IsInt()
-    rating: number;
-
-}
\ No newline at end of file
+  @IsInt()
+  rating: number;
+}
diff --git a/sample/sample7-inheritance-support/app.ts b/sample/sample7-inheritance-support/app.ts
index 9b4d534c84..d2cf9d8a76 100644
--- a/sample/sample7-inheritance-support/app.ts
+++ b/sample/sample7-inheritance-support/app.ts
@@ -1,14 +1,14 @@
-import {validate} from "../../src/index";
-import {Post} from "./Post";
+import { validate } from '../../src/index';
+import { Post } from './Post';
 
 // Sample1. simple validation
 
 let post1 = new Post();
-post1.title = "Hello world"; // should pass
-post1.text = "this is a great post about hello world"; // should pass
+post1.title = 'Hello world'; // should pass
+post1.text = 'this is a great post about hello world'; // should pass
 post1.rating = 10; // should pass
-post1.email = "@google.com"; // should not pass
+post1.email = '@google.com'; // should not pass
 
 validate(post1).then(result => {
-    console.log("1. should not pass: ", result); // should not pass completely
+  console.log('1. should not pass: ', result); // should not pass completely
 });
diff --git a/sample/sample8-es6-maps/Post.ts b/sample/sample8-es6-maps/Post.ts
index 5cb1749a6e..0148b1f4ad 100644
--- a/sample/sample8-es6-maps/Post.ts
+++ b/sample/sample8-es6-maps/Post.ts
@@ -1,14 +1,12 @@
-import {Contains, IsInt, Length, IsEmail, IsFQDN, IsDate, ValidateNested} from "../../src/decorator/decorators";
-import {Tag} from "./Tag";
+import { Contains, IsInt, Length, IsEmail, IsFQDN, IsDate, ValidateNested } from '../../src/decorator/decorators';
+import { Tag } from './Tag';
 
 export class Post {
+  @Length(10, 20, {
+    message: 'Incorrect length!',
+  })
+  title: string;
 
-    @Length(10, 20, {
-        message: "Incorrect length!"
-    })
-    title: string;
-
-    @ValidateNested()
-    tags: Map<string, Tag>;
-
+  @ValidateNested()
+  tags: Map<string, Tag>;
 }
diff --git a/sample/sample8-es6-maps/Tag.ts b/sample/sample8-es6-maps/Tag.ts
index a9dd9d6621..0d19e8893c 100644
--- a/sample/sample8-es6-maps/Tag.ts
+++ b/sample/sample8-es6-maps/Tag.ts
@@ -1,10 +1,8 @@
-import {Contains, IsInt, Length, IsEmail, IsFQDN, IsDate} from "../../src/decorator/decorators";
+import { Contains, IsInt, Length, IsEmail, IsFQDN, IsDate } from '../../src/decorator/decorators';
 
 export class Tag {
-
-    @Length(10, 20, {
-        message: "Tag value is too short or long"
-    })
-    value: string;
-
+  @Length(10, 20, {
+    message: 'Tag value is too short or long',
+  })
+  value: string;
 }
diff --git a/sample/sample8-es6-maps/app.ts b/sample/sample8-es6-maps/app.ts
index 6df5ea25f9..3e893047c1 100644
--- a/sample/sample8-es6-maps/app.ts
+++ b/sample/sample8-es6-maps/app.ts
@@ -1,21 +1,21 @@
-import {Validator} from "../../src/validation/Validator";
-import {Post} from "./Post";
-import {Tag} from "./Tag";
+import { Validator } from '../../src/validation/Validator';
+import { Post } from './Post';
+import { Tag } from './Tag';
 
 let validator = new Validator();
 
 let tag1 = new Tag();
-tag1.value = "ja";
+tag1.value = 'ja';
 
 let tag2 = new Tag();
-tag2.value = "node.js";
+tag2.value = 'node.js';
 
 let post1 = new Post();
-post1.title = "Hello world";
+post1.title = 'Hello world';
 post1.tags = new Map();
-post1.tags.set("tag1", tag1);
-post1.tags.set("tag2", tag2);
+post1.tags.set('tag1', tag1);
+post1.tags.set('tag2', tag2);
 
 validator.validate(post1).then(result => {
-    console.log("1. should not pass: ", result);
+  console.log('1. should not pass: ', result);
 });
diff --git a/sample/sample9-es6-sets/Post.ts b/sample/sample9-es6-sets/Post.ts
index 1f7b740eb6..d14f5de039 100644
--- a/sample/sample9-es6-sets/Post.ts
+++ b/sample/sample9-es6-sets/Post.ts
@@ -1,14 +1,12 @@
-import {Contains, IsInt, Length, IsEmail, IsFQDN, IsDate, ValidateNested} from "../../src/decorator/decorators";
-import {Tag} from "./Tag";
+import { Contains, IsInt, Length, IsEmail, IsFQDN, IsDate, ValidateNested } from '../../src/decorator/decorators';
+import { Tag } from './Tag';
 
 export class Post {
+  @Length(10, 20, {
+    message: 'Incorrect length!',
+  })
+  title: string;
 
-    @Length(10, 20, {
-        message: "Incorrect length!"
-    })
-    title: string;
-
-    @ValidateNested()
-    tags: Set<Tag>;
-
+  @ValidateNested()
+  tags: Set<Tag>;
 }
diff --git a/sample/sample9-es6-sets/Tag.ts b/sample/sample9-es6-sets/Tag.ts
index a9dd9d6621..0d19e8893c 100644
--- a/sample/sample9-es6-sets/Tag.ts
+++ b/sample/sample9-es6-sets/Tag.ts
@@ -1,10 +1,8 @@
-import {Contains, IsInt, Length, IsEmail, IsFQDN, IsDate} from "../../src/decorator/decorators";
+import { Contains, IsInt, Length, IsEmail, IsFQDN, IsDate } from '../../src/decorator/decorators';
 
 export class Tag {
-
-    @Length(10, 20, {
-        message: "Tag value is too short or long"
-    })
-    value: string;
-
+  @Length(10, 20, {
+    message: 'Tag value is too short or long',
+  })
+  value: string;
 }
diff --git a/sample/sample9-es6-sets/app.ts b/sample/sample9-es6-sets/app.ts
index 0321945236..58686cf42d 100644
--- a/sample/sample9-es6-sets/app.ts
+++ b/sample/sample9-es6-sets/app.ts
@@ -1,21 +1,21 @@
-import {Validator} from "../../src/validation/Validator";
-import {Post} from "./Post";
-import {Tag} from "./Tag";
+import { Validator } from '../../src/validation/Validator';
+import { Post } from './Post';
+import { Tag } from './Tag';
 
 let validator = new Validator();
 
 let tag1 = new Tag();
-tag1.value = "ja";
+tag1.value = 'ja';
 
 let tag2 = new Tag();
-tag2.value = "node.js";
+tag2.value = 'node.js';
 
 let post1 = new Post();
-post1.title = "Hello world";
+post1.title = 'Hello world';
 post1.tags = new Set();
 post1.tags.add(tag1);
 post1.tags.add(tag2);
 
 validator.validate(post1).then(result => {
-    console.log("1. should not pass: ", result);
+  console.log('1. should not pass: ', result);
 });
diff --git a/src/.eslintrc.js b/src/.eslintrc.js
deleted file mode 100644
index 47c22e9d23..0000000000
--- a/src/.eslintrc.js
+++ /dev/null
@@ -1,8 +0,0 @@
-module.exports = {
-    env: {
-        browser: true,
-    },
-    extends: [
-    	"plugin:compat/recommended"
-    ]
-};
diff --git a/src/container.ts b/src/container.ts
index c2e2e5f554..2a288bde81 100644
--- a/src/container.ts
+++ b/src/container.ts
@@ -1,66 +1,59 @@
-
 /**
  * Container options.
  */
 export interface UseContainerOptions {
-
-    /**
-     * If set to true, then default container will be used in the case if given container haven't returned anything.
-     */
-    fallback?: boolean;
-
-    /**
-     * If set to true, then default container will be used in the case if given container thrown an exception.
-     */
-    fallbackOnErrors?: boolean;
-
+  /**
+   * If set to true, then default container will be used in the case if given container haven't returned anything.
+   */
+  fallback?: boolean;
+
+  /**
+   * If set to true, then default container will be used in the case if given container thrown an exception.
+   */
+  fallbackOnErrors?: boolean;
 }
 
 /**
  * Container to be used by this library for inversion control. If container was not implicitly set then by default
  * container simply creates a new instance of the given class.
  */
-const defaultContainer: { get<T>(someClass: { new (...args: any[]): T }|Function): T } = new (class {
-    private instances: { type: Function; object: any }[] = [];
-    get<T>(someClass: { new (...args: any[]): T }): T {
-        let instance = this.instances.find(instance => instance.type === someClass);
-        if (!instance) {
-            instance = { type: someClass, object: new someClass() };
-            this.instances.push(instance);
-        }
-
-        return instance.object;
+const defaultContainer: { get<T>(someClass: { new (...args: any[]): T } | Function): T } = new (class {
+  private instances: { type: Function; object: any }[] = [];
+  get<T>(someClass: { new (...args: any[]): T }): T {
+    let instance = this.instances.find(instance => instance.type === someClass);
+    if (!instance) {
+      instance = { type: someClass, object: new someClass() };
+      this.instances.push(instance);
     }
+
+    return instance.object;
+  }
 })();
 
-let userContainer: { get<T>(someClass: { new (...args: any[]): T }|Function): T };
+let userContainer: { get<T>(someClass: { new (...args: any[]): T } | Function): T };
 let userContainerOptions: UseContainerOptions;
 
 /**
  * Sets container to be used by this library.
  */
 export function useContainer(iocContainer: { get(someClass: any): any }, options?: UseContainerOptions): void {
-    userContainer = iocContainer;
-    userContainerOptions = options;
+  userContainer = iocContainer;
+  userContainerOptions = options;
 }
 
 /**
  * Gets the IOC container used by this library.
  */
-export function getFromContainer<T>(someClass: { new (...args: any[]): T }|Function): T {
-    if (userContainer) {
-        try {
-            const instance = userContainer.get(someClass);
-            if (instance)
-                return instance;
-
-            if (!userContainerOptions || !userContainerOptions.fallback)
-                return instance;
-
-        } catch (error) {
-            if (!userContainerOptions || !userContainerOptions.fallbackOnErrors)
-                throw error;
-        }
+export function getFromContainer<T>(someClass: { new (...args: any[]): T } | Function): T {
+  if (userContainer) {
+    try {
+      const instance = userContainer.get(someClass);
+      if (instance) return instance;
+
+      if (!userContainerOptions || !userContainerOptions.fallback) return instance;
+    } catch (error) {
+      if (!userContainerOptions || !userContainerOptions.fallbackOnErrors) throw error;
     }
-    return defaultContainer.get<T>(someClass);
+  }
+  return defaultContainer.get<T>(someClass);
 }
diff --git a/src/decorator/ValidationOptions.ts b/src/decorator/ValidationOptions.ts
index 3a44d0fa2f..60059a5fa6 100644
--- a/src/decorator/ValidationOptions.ts
+++ b/src/decorator/ValidationOptions.ts
@@ -1,45 +1,39 @@
-import { ValidationArguments } from "../validation/ValidationArguments";
+import { ValidationArguments } from '../validation/ValidationArguments';
 
 /**
  * Options used to pass to validation decorators.
  */
 export interface ValidationOptions {
-
-    /**
-     * Specifies if validated value is an array and each of its items must be validated.
-     */
-    each?: boolean;
-
-    /**
-     * Error message to be used on validation fail.
-     * Message can be either string or a function that returns a string.
-     */
-    message?: string | ((validationArguments: ValidationArguments) => string);
-
-    /**
-     * Validation groups used for this validation.
-     */
-    groups?: string[];
-
-    /**
-     * Indicates if validation must be performed always, no matter of validation groups used.
-     */
-    always?: boolean;
-
-    /*
-     * A transient set of data passed through to the validation result for response mapping
-     */
-    context?: any;
+  /**
+   * Specifies if validated value is an array and each of its items must be validated.
+   */
+  each?: boolean;
+
+  /**
+   * Error message to be used on validation fail.
+   * Message can be either string or a function that returns a string.
+   */
+  message?: string | ((validationArguments: ValidationArguments) => string);
+
+  /**
+   * Validation groups used for this validation.
+   */
+  groups?: string[];
+
+  /**
+   * Indicates if validation must be performed always, no matter of validation groups used.
+   */
+  always?: boolean;
+
+  /*
+   * A transient set of data passed through to the validation result for response mapping
+   */
+  context?: any;
 }
 
-
 export function isValidationOptions(val: any): val is ValidationOptions {
-    if (!val) {
-        return false;
-    }
-    return "each" in val
-        || "message" in val
-        || "groups" in val
-        || "always" in val
-        || "context" in val;
+  if (!val) {
+    return false;
+  }
+  return 'each' in val || 'message' in val || 'groups' in val || 'always' in val || 'context' in val;
 }
diff --git a/src/decorator/array/ArrayContains.ts b/src/decorator/array/ArrayContains.ts
index 7652aaf112..96cf4fa891 100644
--- a/src/decorator/array/ArrayContains.ts
+++ b/src/decorator/array/ArrayContains.ts
@@ -1,17 +1,16 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const ARRAY_CONTAINS = "arrayContains";
+export const ARRAY_CONTAINS = 'arrayContains';
 
 /**
  * Checks if array contains all values from the given array of values.
  * If null or undefined is given then this function returns false.
  */
 export function arrayContains(array: unknown, values: any[]): boolean {
-    if (!(array instanceof Array))
-        return false;
+  if (!(array instanceof Array)) return false;
 
-    return values.every(value => array.indexOf(value) !== -1);
+  return values.every(value => array.indexOf(value) !== -1);
 }
 
 /**
@@ -19,18 +18,18 @@ export function arrayContains(array: unknown, values: any[]): boolean {
  * If null or undefined is given then this function returns false.
  */
 export function ArrayContains(values: any[], validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: ARRAY_CONTAINS,
-            constraints: [values],
-            validator: {
-                validate: (value, args): boolean => arrayContains(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must contain $constraint1 values",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: ARRAY_CONTAINS,
+      constraints: [values],
+      validator: {
+        validate: (value, args): boolean => arrayContains(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must contain $constraint1 values',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/array/ArrayMaxSize.ts b/src/decorator/array/ArrayMaxSize.ts
index 5779a2bebc..1eaff66c0f 100644
--- a/src/decorator/array/ArrayMaxSize.ts
+++ b/src/decorator/array/ArrayMaxSize.ts
@@ -1,14 +1,14 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const ARRAY_MAX_SIZE = "arrayMaxSize";
+export const ARRAY_MAX_SIZE = 'arrayMaxSize';
 
 /**
  * Checks if array's length is as maximal this number.
  * If null or undefined is given then this function returns false.
  */
 export function arrayMaxSize(array: unknown, max: number): boolean {
-    return array instanceof Array && array.length <= max;
+  return array instanceof Array && array.length <= max;
 }
 
 /**
@@ -16,18 +16,18 @@ export function arrayMaxSize(array: unknown, max: number): boolean {
  * If null or undefined is given then this function returns false.
  */
 export function ArrayMaxSize(max: number, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: ARRAY_MAX_SIZE,
-            constraints: [max],
-            validator: {
-                validate: (value, args): boolean => arrayMaxSize(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must contain not more than $constraint1 elements",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: ARRAY_MAX_SIZE,
+      constraints: [max],
+      validator: {
+        validate: (value, args): boolean => arrayMaxSize(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must contain not more than $constraint1 elements',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/array/ArrayMinSize.ts b/src/decorator/array/ArrayMinSize.ts
index 523820e666..4d2748b91f 100644
--- a/src/decorator/array/ArrayMinSize.ts
+++ b/src/decorator/array/ArrayMinSize.ts
@@ -1,14 +1,14 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const ARRAY_MIN_SIZE = "arrayMinSize";
+export const ARRAY_MIN_SIZE = 'arrayMinSize';
 
 /**
  * Checks if array's length is as minimal this number.
  * If null or undefined is given then this function returns false.
  */
 export function arrayMinSize(array: unknown, min: number): boolean {
-    return array instanceof Array && array.length >= min;
+  return array instanceof Array && array.length >= min;
 }
 
 /**
@@ -16,18 +16,18 @@ export function arrayMinSize(array: unknown, min: number): boolean {
  * If null or undefined is given then this function returns false.
  */
 export function ArrayMinSize(min: number, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: ARRAY_MIN_SIZE,
-            constraints: [min],
-            validator: {
-                validate: (value, args): boolean => arrayMinSize(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must contain at least $constraint1 elements",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: ARRAY_MIN_SIZE,
+      constraints: [min],
+      validator: {
+        validate: (value, args): boolean => arrayMinSize(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must contain at least $constraint1 elements',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/array/ArrayNotContains.ts b/src/decorator/array/ArrayNotContains.ts
index 624580a264..66a323732b 100644
--- a/src/decorator/array/ArrayNotContains.ts
+++ b/src/decorator/array/ArrayNotContains.ts
@@ -1,17 +1,16 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const ARRAY_NOT_CONTAINS = "arrayNotContains";
+export const ARRAY_NOT_CONTAINS = 'arrayNotContains';
 
 /**
  * Checks if array does not contain any of the given values.
  * If null or undefined is given then this function returns false.
  */
 export function arrayNotContains(array: unknown, values: any[]): boolean {
-    if (!(array instanceof Array))
-        return false;
+  if (!(array instanceof Array)) return false;
 
-    return values.every(value => array.indexOf(value) === -1);
+  return values.every(value => array.indexOf(value) === -1);
 }
 
 /**
@@ -19,18 +18,18 @@ export function arrayNotContains(array: unknown, values: any[]): boolean {
  * If null or undefined is given then this function returns false.
  */
 export function ArrayNotContains(values: any[], validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: ARRAY_NOT_CONTAINS,
-            constraints: [values],
-            validator: {
-                validate: (value, args): boolean => arrayNotContains(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property should not contain $constraint1 values",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: ARRAY_NOT_CONTAINS,
+      constraints: [values],
+      validator: {
+        validate: (value, args): boolean => arrayNotContains(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property should not contain $constraint1 values',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/array/ArrayNotEmpty.ts b/src/decorator/array/ArrayNotEmpty.ts
index 0e0ef25565..6f3414f6e8 100644
--- a/src/decorator/array/ArrayNotEmpty.ts
+++ b/src/decorator/array/ArrayNotEmpty.ts
@@ -1,14 +1,14 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const ARRAY_NOT_EMPTY = "arrayNotEmpty";
+export const ARRAY_NOT_EMPTY = 'arrayNotEmpty';
 
 /**
  * Checks if given array is not empty.
  * If null or undefined is given then this function returns false.
  */
 export function arrayNotEmpty(array: unknown): boolean {
-    return array instanceof Array && array.length > 0;
+  return array instanceof Array && array.length > 0;
 }
 
 /**
@@ -16,17 +16,14 @@ export function arrayNotEmpty(array: unknown): boolean {
  * If null or undefined is given then this function returns false.
  */
 export function ArrayNotEmpty(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: ARRAY_NOT_EMPTY,
-            validator: {
-                validate: (value, args): boolean => arrayNotEmpty(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property should not be empty",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: ARRAY_NOT_EMPTY,
+      validator: {
+        validate: (value, args): boolean => arrayNotEmpty(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property should not be empty', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/array/ArrayUnique.ts b/src/decorator/array/ArrayUnique.ts
index e0fb6766c7..873e4e5dc3 100644
--- a/src/decorator/array/ArrayUnique.ts
+++ b/src/decorator/array/ArrayUnique.ts
@@ -1,18 +1,17 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const ARRAY_UNIQUE = "arrayUnique";
+export const ARRAY_UNIQUE = 'arrayUnique';
 
 /**
  * Checks if all array's values are unique. Comparison for objects is reference-based.
  * If null or undefined is given then this function returns false.
  */
 export function arrayUnique(array: unknown): boolean {
-    if (!(array instanceof Array))
-        return false;
+  if (!(array instanceof Array)) return false;
 
-    const uniqueItems = array.filter((a, b, c) => c.indexOf(a) === b);
-    return array.length === uniqueItems.length;
+  const uniqueItems = array.filter((a, b, c) => c.indexOf(a) === b);
+  return array.length === uniqueItems.length;
 }
 
 /**
@@ -20,17 +19,17 @@ export function arrayUnique(array: unknown): boolean {
  * If null or undefined is given then this function returns false.
  */
 export function ArrayUnique(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: ARRAY_UNIQUE,
-            validator: {
-                validate: (value, args): boolean => arrayUnique(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "All $property's elements must be unique",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: ARRAY_UNIQUE,
+      validator: {
+        validate: (value, args): boolean => arrayUnique(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + "All $property's elements must be unique",
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/common/Allow.ts b/src/decorator/common/Allow.ts
index fe5795f6d2..943722ec8c 100644
--- a/src/decorator/common/Allow.ts
+++ b/src/decorator/common/Allow.ts
@@ -1,20 +1,20 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { ValidationMetadataArgs } from "../../metadata/ValidationMetadataArgs";
-import { ValidationTypes } from "../../validation/ValidationTypes";
-import { ValidationMetadata } from "../../metadata/ValidationMetadata";
-import { getMetadataStorage } from "../../metadata/MetadataStorage";
+import { ValidationOptions } from '../ValidationOptions';
+import { ValidationMetadataArgs } from '../../metadata/ValidationMetadataArgs';
+import { ValidationTypes } from '../../validation/ValidationTypes';
+import { ValidationMetadata } from '../../metadata/ValidationMetadata';
+import { getMetadataStorage } from '../../metadata/MetadataStorage';
 
 /**
  * If object has both allowed and not allowed properties a validation error will be thrown.
  */
 export function Allow(validationOptions?: ValidationOptions): PropertyDecorator {
-    return function (object: object, propertyName: string): void {
-        const args: ValidationMetadataArgs = {
-            type: ValidationTypes.WHITELIST,
-            target: object.constructor,
-            propertyName: propertyName,
-            validationOptions: validationOptions
-        };
-        getMetadataStorage().addValidationMetadata(new ValidationMetadata(args));
+  return function (object: object, propertyName: string): void {
+    const args: ValidationMetadataArgs = {
+      type: ValidationTypes.WHITELIST,
+      target: object.constructor,
+      propertyName: propertyName,
+      validationOptions: validationOptions,
     };
+    getMetadataStorage().addValidationMetadata(new ValidationMetadata(args));
+  };
 }
diff --git a/src/decorator/common/Equals.ts b/src/decorator/common/Equals.ts
index 97ca520144..27b89a801a 100644
--- a/src/decorator/common/Equals.ts
+++ b/src/decorator/common/Equals.ts
@@ -1,31 +1,31 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const EQUALS = "equals";
+export const EQUALS = 'equals';
 
 /**
  * Checks if value matches ("===") the comparison.
  */
 export function equals(value: unknown, comparison: unknown): boolean {
-    return value === comparison;
+  return value === comparison;
 }
 
 /**
  * Checks if value matches ("===") the comparison.
  */
 export function Equals(comparison: any, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: EQUALS,
-            constraints: [comparison],
-            validator: {
-                validate: (value, args): boolean => equals(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be equal to $constraint1",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: EQUALS,
+      constraints: [comparison],
+      validator: {
+        validate: (value, args): boolean => equals(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be equal to $constraint1',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/common/IsDefined.ts b/src/decorator/common/IsDefined.ts
index 7686cfc552..69c08901a3 100644
--- a/src/decorator/common/IsDefined.ts
+++ b/src/decorator/common/IsDefined.ts
@@ -1,6 +1,6 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "./ValidateBy";
-import { ValidationTypes } from "../../validation/ValidationTypes";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from './ValidateBy';
+import { ValidationTypes } from '../../validation/ValidationTypes';
 
 // isDefined is (yet) a special case
 export const IS_DEFINED = ValidationTypes.IS_DEFINED;
@@ -9,24 +9,24 @@ export const IS_DEFINED = ValidationTypes.IS_DEFINED;
  * Checks if value is defined (!== undefined, !== null).
  */
 export function isDefined(value: any): boolean {
-    return value !== undefined && value !== null;
+  return value !== undefined && value !== null;
 }
 
 /**
  * Checks if value is defined (!== undefined, !== null).
  */
 export function IsDefined(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_DEFINED,
-            validator: {
-                validate: (value): boolean => isDefined(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property should not be null or undefined",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_DEFINED,
+      validator: {
+        validate: (value): boolean => isDefined(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property should not be null or undefined',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/common/IsEmpty.ts b/src/decorator/common/IsEmpty.ts
index ff6214e67d..1447811b9e 100644
--- a/src/decorator/common/IsEmpty.ts
+++ b/src/decorator/common/IsEmpty.ts
@@ -1,30 +1,27 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const IS_EMPTY = "isEmpty";
+export const IS_EMPTY = 'isEmpty';
 
 /**
  * Checks if given value is empty (=== '', === null, === undefined).
  */
 export function isEmpty(value: unknown): boolean {
-    return value === "" || value === null || value === undefined;
+  return value === '' || value === null || value === undefined;
 }
 
 /**
  * Checks if given value is empty (=== '', === null, === undefined).
  */
 export function IsEmpty(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_EMPTY,
-            validator: {
-                validate: (value, args): boolean => isEmpty(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be empty",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_EMPTY,
+      validator: {
+        validate: (value, args): boolean => isEmpty(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be empty', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/common/IsIn.ts b/src/decorator/common/IsIn.ts
index 61f74ac92a..2570a8cf86 100644
--- a/src/decorator/common/IsIn.ts
+++ b/src/decorator/common/IsIn.ts
@@ -1,31 +1,31 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const IS_IN = "isIn";
+export const IS_IN = 'isIn';
 
 /**
  * Checks if given value is in a array of allowed values.
  */
 export function isIn(value: unknown, possibleValues: readonly unknown[]): boolean {
-    return !(possibleValues instanceof Array) || possibleValues.some(possibleValue => possibleValue === value);
+  return !(possibleValues instanceof Array) || possibleValues.some(possibleValue => possibleValue === value);
 }
 
 /**
  * Checks if given value is in a array of allowed values.
  */
 export function IsIn(values: readonly any[], validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_IN,
-            constraints: [values],
-            validator: {
-                validate: (value, args): boolean => isIn(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be one of the following values: $constraint1",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_IN,
+      constraints: [values],
+      validator: {
+        validate: (value, args): boolean => isIn(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be one of the following values: $constraint1',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/common/IsLatLong.ts b/src/decorator/common/IsLatLong.ts
index 1e122e2023..becbf29c33 100644
--- a/src/decorator/common/IsLatLong.ts
+++ b/src/decorator/common/IsLatLong.ts
@@ -1,31 +1,31 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "./ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from './ValidateBy';
+import isLatLongValidator from 'validator/lib/isLatLong';
 
-export const IS_LATLONG = "isLatLong";
+export const IS_LATLONG = 'isLatLong';
 
 /**
  * Checks if a value is string in format a "latitude,longitude".
  */
 export function isLatLong(value: string): boolean {
-    return typeof value === "string" && validator.isLatLong(value);
+  return typeof value === 'string' && isLatLongValidator(value);
 }
 
 /**
  * Checks if a value is string in format a "latitude,longitude".
  */
 export function IsLatLong(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_LATLONG,
-            validator: {
-                validate: (value, args): boolean => isLatLong(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a latitude,longitude string",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_LATLONG,
+      validator: {
+        validate: (value, args): boolean => isLatLong(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a latitude,longitude string',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/common/IsLatitude.ts b/src/decorator/common/IsLatitude.ts
index 773e9aab9d..1be12e130e 100644
--- a/src/decorator/common/IsLatitude.ts
+++ b/src/decorator/common/IsLatitude.ts
@@ -1,31 +1,31 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "./ValidateBy";
-import { isLatLong } from "./IsLatLong";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from './ValidateBy';
+import { isLatLong } from './IsLatLong';
 
-export const IS_LATITUDE = "isLatitude";
+export const IS_LATITUDE = 'isLatitude';
 
 /**
  * Checks if a given value is a latitude.
  */
 export function isLatitude(value: string): boolean {
-    return (typeof value === "number" || typeof value === "string") && isLatLong(`${value},0`);
+  return (typeof value === 'number' || typeof value === 'string') && isLatLong(`${value},0`);
 }
 
 /**
  * Checks if a given value is a latitude.
  */
 export function IsLatitude(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_LATITUDE,
-            validator: {
-                validate: (value, args): boolean => isLatitude(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a latitude string or number",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_LATITUDE,
+      validator: {
+        validate: (value, args): boolean => isLatitude(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a latitude string or number',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/common/IsLongitude.ts b/src/decorator/common/IsLongitude.ts
index 4ca50e427e..013f5387af 100644
--- a/src/decorator/common/IsLongitude.ts
+++ b/src/decorator/common/IsLongitude.ts
@@ -1,31 +1,31 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "./ValidateBy";
-import { isLatLong } from "./IsLatLong";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from './ValidateBy';
+import { isLatLong } from './IsLatLong';
 
-export const IS_LONGITUDE = "isLongitude";
+export const IS_LONGITUDE = 'isLongitude';
 
 /**
  * Checks if a given value is a longitude.
  */
 export function isLongitude(value: string): boolean {
-    return (typeof value === "number" || typeof value === "string") && isLatLong(`0,${value}`);
+  return (typeof value === 'number' || typeof value === 'string') && isLatLong(`0,${value}`);
 }
 
 /**
  * Checks if a given value is a longitude.
  */
 export function IsLongitude(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_LONGITUDE,
-            validator: {
-                validate: (value, args): boolean => isLongitude(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a longitude string or number",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_LONGITUDE,
+      validator: {
+        validate: (value, args): boolean => isLongitude(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a longitude string or number',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/common/IsNotEmpty.ts b/src/decorator/common/IsNotEmpty.ts
index c269567b55..605da09edc 100644
--- a/src/decorator/common/IsNotEmpty.ts
+++ b/src/decorator/common/IsNotEmpty.ts
@@ -1,30 +1,27 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const IS_NOT_EMPTY = "isNotEmpty";
+export const IS_NOT_EMPTY = 'isNotEmpty';
 
 /**
  * Checks if given value is not empty (!== '', !== null, !== undefined).
  */
 export function isNotEmpty(value: unknown): boolean {
-    return value !== "" && value !== null && value !== undefined;
+  return value !== '' && value !== null && value !== undefined;
 }
 
 /**
  * Checks if given value is not empty (!== '', !== null, !== undefined).
  */
 export function IsNotEmpty(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_NOT_EMPTY,
-            validator: {
-                validate: (value, args): boolean => isNotEmpty(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property should not be empty",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_NOT_EMPTY,
+      validator: {
+        validate: (value, args): boolean => isNotEmpty(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property should not be empty', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/common/IsNotIn.ts b/src/decorator/common/IsNotIn.ts
index 87e7160a4e..37c9b8997e 100644
--- a/src/decorator/common/IsNotIn.ts
+++ b/src/decorator/common/IsNotIn.ts
@@ -1,31 +1,31 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const IS_NOT_IN = "isNotIn";
+export const IS_NOT_IN = 'isNotIn';
 
 /**
  * Checks if given value not in a array of allowed values.
  */
 export function isNotIn(value: unknown, possibleValues: readonly unknown[]): boolean {
-    return !(possibleValues instanceof Array) || !possibleValues.some(possibleValue => possibleValue === value);
+  return !(possibleValues instanceof Array) || !possibleValues.some(possibleValue => possibleValue === value);
 }
 
 /**
  * Checks if given value not in a array of allowed values.
  */
 export function IsNotIn(values: readonly any[], validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_NOT_IN,
-            constraints: [values],
-            validator: {
-                validate: (value, args): boolean => isNotIn(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property should not be one of the following values: $constraint1",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_NOT_IN,
+      constraints: [values],
+      validator: {
+        validate: (value, args): boolean => isNotIn(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property should not be one of the following values: $constraint1',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/common/IsOptional.ts b/src/decorator/common/IsOptional.ts
index 3560b37cf9..25ef08915c 100644
--- a/src/decorator/common/IsOptional.ts
+++ b/src/decorator/common/IsOptional.ts
@@ -1,23 +1,25 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { ValidationMetadataArgs } from "../../metadata/ValidationMetadataArgs";
-import { ValidationTypes } from "../../validation/ValidationTypes";
-import { ValidationMetadata } from "../../metadata/ValidationMetadata";
-import { getMetadataStorage } from "../../metadata/MetadataStorage";
+import { ValidationOptions } from '../ValidationOptions';
+import { ValidationMetadataArgs } from '../../metadata/ValidationMetadataArgs';
+import { ValidationTypes } from '../../validation/ValidationTypes';
+import { ValidationMetadata } from '../../metadata/ValidationMetadata';
+import { getMetadataStorage } from '../../metadata/MetadataStorage';
 
 /**
  * Checks if value is missing and if so, ignores all validators.
  */
 export function IsOptional(validationOptions?: ValidationOptions): PropertyDecorator {
-    return function (object: object, propertyName: string): void {
-        const args: ValidationMetadataArgs = {
-            type: ValidationTypes.CONDITIONAL_VALIDATION,
-            target: object.constructor,
-            propertyName: propertyName,
-            constraints: [(object: any, value: any): boolean => {
-                return object[propertyName] !== null && object[propertyName] !== undefined;
-            }],
-            validationOptions: validationOptions
-        };
-        getMetadataStorage().addValidationMetadata(new ValidationMetadata(args));
+  return function (object: object, propertyName: string): void {
+    const args: ValidationMetadataArgs = {
+      type: ValidationTypes.CONDITIONAL_VALIDATION,
+      target: object.constructor,
+      propertyName: propertyName,
+      constraints: [
+        (object: any, value: any): boolean => {
+          return object[propertyName] !== null && object[propertyName] !== undefined;
+        },
+      ],
+      validationOptions: validationOptions,
     };
+    getMetadataStorage().addValidationMetadata(new ValidationMetadata(args));
+  };
 }
diff --git a/src/decorator/common/NotEquals.ts b/src/decorator/common/NotEquals.ts
index 266e0e9d59..3872a2dd0b 100644
--- a/src/decorator/common/NotEquals.ts
+++ b/src/decorator/common/NotEquals.ts
@@ -1,31 +1,31 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const NOT_EQUALS = "notEquals";
+export const NOT_EQUALS = 'notEquals';
 
 /**
  * Checks if value does not match ("!==") the comparison.
  */
 export function notEquals(value: unknown, comparison: unknown): boolean {
-    return value !== comparison;
+  return value !== comparison;
 }
 
 /**
  * Checks if value does not match ("!==") the comparison.
  */
 export function NotEquals(comparison: any, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: NOT_EQUALS,
-            constraints: [comparison],
-            validator: {
-                validate: (value, args): boolean => notEquals(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property should not be equal to $constraint1",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: NOT_EQUALS,
+      constraints: [comparison],
+      validator: {
+        validate: (value, args): boolean => notEquals(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property should not be equal to $constraint1',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/common/Validate.ts b/src/decorator/common/Validate.ts
index 1661e3ada2..ab466d70c1 100644
--- a/src/decorator/common/Validate.ts
+++ b/src/decorator/common/Validate.ts
@@ -1,25 +1,26 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { ValidationMetadataArgs } from "../../metadata/ValidationMetadataArgs";
-import { ValidationMetadata } from "../../metadata/ValidationMetadata";
-import { getMetadataStorage } from "../../metadata/MetadataStorage";
-import { ValidationTypes } from "../../validation/ValidationTypes";
-import { ConstraintMetadata } from "../../metadata/ConstraintMetadata";
+import { ValidationOptions } from '../ValidationOptions';
+import { ValidationMetadataArgs } from '../../metadata/ValidationMetadataArgs';
+import { ValidationMetadata } from '../../metadata/ValidationMetadata';
+import { getMetadataStorage } from '../../metadata/MetadataStorage';
+import { ValidationTypes } from '../../validation/ValidationTypes';
+import { ConstraintMetadata } from '../../metadata/ConstraintMetadata';
 
 /**
  * Registers custom validator class.
  */
 export function ValidatorConstraint(options?: { name?: string; async?: boolean }) {
-    return function (target: Function): void {
-        const isAsync = options && options.async;
-        let name = options && options.name ? options.name : "";
-        if (!name) {
-            name = (target as any).name;
-            if (!name) // generate name if it was not given
-                name = name.replace(/\.?([A-Z]+)/g, (x, y) => "_" + y.toLowerCase()).replace(/^_/, "");
-        }
-        const metadata = new ConstraintMetadata(target, name, isAsync);
-        getMetadataStorage().addConstraintMetadata(metadata);
-    };
+  return function (target: Function): void {
+    const isAsync = options && options.async;
+    let name = options && options.name ? options.name : '';
+    if (!name) {
+      name = (target as any).name;
+      if (!name)
+        // generate name if it was not given
+        name = name.replace(/\.?([A-Z]+)/g, (x, y) => '_' + (y as string).toLowerCase()).replace(/^_/, '');
+    }
+    const metadata = new ConstraintMetadata(target, name, isAsync);
+    getMetadataStorage().addConstraintMetadata(metadata);
+  };
 }
 
 /**
@@ -27,17 +28,27 @@ export function ValidatorConstraint(options?: { name?: string; async?: boolean }
  * Validation class must be decorated with ValidatorConstraint decorator.
  */
 export function Validate(constraintClass: Function, validationOptions?: ValidationOptions): PropertyDecorator;
-export function Validate(constraintClass: Function, constraints?: any[], validationOptions?: ValidationOptions): PropertyDecorator;
-export function Validate(constraintClass: Function, constraintsOrValidationOptions?: any[] | ValidationOptions, maybeValidationOptions?: ValidationOptions): PropertyDecorator {
-    return function (object: object, propertyName: string): void {
-        const args: ValidationMetadataArgs = {
-            type: ValidationTypes.CUSTOM_VALIDATION,
-            target: object.constructor,
-            propertyName: propertyName,
-            constraintCls: constraintClass,
-            constraints: constraintsOrValidationOptions instanceof Array ? constraintsOrValidationOptions : undefined,
-            validationOptions: !(constraintsOrValidationOptions instanceof Array) ? constraintsOrValidationOptions : maybeValidationOptions
-        };
-        getMetadataStorage().addValidationMetadata(new ValidationMetadata(args));
+export function Validate(
+  constraintClass: Function,
+  constraints?: any[],
+  validationOptions?: ValidationOptions
+): PropertyDecorator;
+export function Validate(
+  constraintClass: Function,
+  constraintsOrValidationOptions?: any[] | ValidationOptions,
+  maybeValidationOptions?: ValidationOptions
+): PropertyDecorator {
+  return function (object: object, propertyName: string): void {
+    const args: ValidationMetadataArgs = {
+      type: ValidationTypes.CUSTOM_VALIDATION,
+      target: object.constructor,
+      propertyName: propertyName,
+      constraintCls: constraintClass,
+      constraints: constraintsOrValidationOptions instanceof Array ? constraintsOrValidationOptions : undefined,
+      validationOptions: !(constraintsOrValidationOptions instanceof Array)
+        ? constraintsOrValidationOptions
+        : maybeValidationOptions,
     };
+    getMetadataStorage().addValidationMetadata(new ValidationMetadata(args));
+  };
 }
diff --git a/src/decorator/common/ValidateBy.ts b/src/decorator/common/ValidateBy.ts
index a0d6f66881..641cb00a06 100644
--- a/src/decorator/common/ValidateBy.ts
+++ b/src/decorator/common/ValidateBy.ts
@@ -1,35 +1,34 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { registerDecorator } from "../../register-decorator";
-import { ValidationArguments } from "../../validation/ValidationArguments";
-import { ValidatorConstraintInterface } from "../../validation/ValidatorConstraintInterface";
+import { ValidationOptions } from '../ValidationOptions';
+import { registerDecorator } from '../../register-decorator';
+import { ValidationArguments } from '../../validation/ValidationArguments';
+import { ValidatorConstraintInterface } from '../../validation/ValidatorConstraintInterface';
 
 export interface ValidateByOptions {
-    name: string;
-    constraints?: any[];
-    validator: ValidatorConstraintInterface | Function;
-    async?: boolean;
+  name: string;
+  constraints?: any[];
+  validator: ValidatorConstraintInterface | Function;
+  async?: boolean;
 }
 
 export function buildMessage(
-    impl: (eachPrefix: string, args?: ValidationArguments) => string,
-    validationOptions?: ValidationOptions): (validationArguments?: ValidationArguments) => string {
-    return (validationArguments?: ValidationArguments): string => {
-        const eachPrefix = validationOptions && validationOptions.each
-            ? "each value in "
-            : "";
-        return impl(eachPrefix, validationArguments);
-    };
+  impl: (eachPrefix: string, args?: ValidationArguments) => string,
+  validationOptions?: ValidationOptions
+): (validationArguments?: ValidationArguments) => string {
+  return (validationArguments?: ValidationArguments): string => {
+    const eachPrefix = validationOptions && validationOptions.each ? 'each value in ' : '';
+    return impl(eachPrefix, validationArguments);
+  };
 }
 
 export function ValidateBy(options: ValidateByOptions, validationOptions?: ValidationOptions): PropertyDecorator {
-    return function (object: object, propertyName: string): void {
-        registerDecorator({
-            name: options.name,
-            target: object.constructor,
-            propertyName: propertyName,
-            options: validationOptions,
-            constraints: options.constraints,
-            validator: options.validator
-        });
-    };
+  return function (object: object, propertyName: string): void {
+    registerDecorator({
+      name: options.name,
+      target: object.constructor,
+      propertyName: propertyName,
+      options: validationOptions,
+      constraints: options.constraints,
+      validator: options.validator,
+    });
+  };
 }
diff --git a/src/decorator/common/ValidateIf.ts b/src/decorator/common/ValidateIf.ts
index e14a679250..14f1deeb77 100644
--- a/src/decorator/common/ValidateIf.ts
+++ b/src/decorator/common/ValidateIf.ts
@@ -1,21 +1,24 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { ValidationMetadataArgs } from "../../metadata/ValidationMetadataArgs";
-import { ValidationTypes } from "../../validation/ValidationTypes";
-import { ValidationMetadata } from "../../metadata/ValidationMetadata";
-import { getMetadataStorage } from "../../metadata/MetadataStorage";
+import { ValidationOptions } from '../ValidationOptions';
+import { ValidationMetadataArgs } from '../../metadata/ValidationMetadataArgs';
+import { ValidationTypes } from '../../validation/ValidationTypes';
+import { ValidationMetadata } from '../../metadata/ValidationMetadata';
+import { getMetadataStorage } from '../../metadata/MetadataStorage';
 
 /**
  * Ignores the other validators on a property when the provided condition function returns false.
  */
-export function ValidateIf(condition: (object: any, value: any) => boolean, validationOptions?: ValidationOptions): PropertyDecorator {
-    return function (object: object, propertyName: string): void {
-        const args: ValidationMetadataArgs = {
-            type: ValidationTypes.CONDITIONAL_VALIDATION,
-            target: object.constructor,
-            propertyName: propertyName,
-            constraints: [condition],
-            validationOptions: validationOptions
-        };
-        getMetadataStorage().addValidationMetadata(new ValidationMetadata(args));
+export function ValidateIf(
+  condition: (object: any, value: any) => boolean,
+  validationOptions?: ValidationOptions
+): PropertyDecorator {
+  return function (object: object, propertyName: string): void {
+    const args: ValidationMetadataArgs = {
+      type: ValidationTypes.CONDITIONAL_VALIDATION,
+      target: object.constructor,
+      propertyName: propertyName,
+      constraints: [condition],
+      validationOptions: validationOptions,
     };
+    getMetadataStorage().addValidationMetadata(new ValidationMetadata(args));
+  };
 }
diff --git a/src/decorator/common/ValidateNested.ts b/src/decorator/common/ValidateNested.ts
index 74bcfcc1b6..da56eaefa4 100644
--- a/src/decorator/common/ValidateNested.ts
+++ b/src/decorator/common/ValidateNested.ts
@@ -1,24 +1,24 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { ValidationMetadataArgs } from "../../metadata/ValidationMetadataArgs";
-import { ValidationTypes } from "../../validation/ValidationTypes";
-import { ValidationMetadata } from "../../metadata/ValidationMetadata";
-import { getMetadataStorage } from "../../metadata/MetadataStorage";
+import { ValidationOptions } from '../ValidationOptions';
+import { ValidationMetadataArgs } from '../../metadata/ValidationMetadataArgs';
+import { ValidationTypes } from '../../validation/ValidationTypes';
+import { ValidationMetadata } from '../../metadata/ValidationMetadata';
+import { getMetadataStorage } from '../../metadata/MetadataStorage';
 
 /**
  * Objects / object arrays marked with this decorator will also be validated.
  */
 export function ValidateNested(validationOptions?: ValidationOptions): PropertyDecorator {
-    const opts: ValidationOptions = { ...validationOptions };
-    const eachPrefix = opts.each ? "each value in " : "";
-    opts.message = opts.message || eachPrefix + "nested property $property must be either object or array";
+  const opts: ValidationOptions = { ...validationOptions };
+  const eachPrefix = opts.each ? 'each value in ' : '';
+  opts.message = opts.message || eachPrefix + 'nested property $property must be either object or array';
 
-    return function (object: object, propertyName: string): void {
-        const args: ValidationMetadataArgs = {
-            type: ValidationTypes.NESTED_VALIDATION,
-            target: object.constructor,
-            propertyName: propertyName,
-            validationOptions: opts,
-        };
-        getMetadataStorage().addValidationMetadata(new ValidationMetadata(args));
+  return function (object: object, propertyName: string): void {
+    const args: ValidationMetadataArgs = {
+      type: ValidationTypes.NESTED_VALIDATION,
+      target: object.constructor,
+      propertyName: propertyName,
+      validationOptions: opts,
     };
+    getMetadataStorage().addValidationMetadata(new ValidationMetadata(args));
+  };
 }
diff --git a/src/decorator/common/ValidatePromise.ts b/src/decorator/common/ValidatePromise.ts
index e08bdc7c49..bd90519e86 100644
--- a/src/decorator/common/ValidatePromise.ts
+++ b/src/decorator/common/ValidatePromise.ts
@@ -1,20 +1,20 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { ValidationMetadataArgs } from "../../metadata/ValidationMetadataArgs";
-import { ValidationTypes } from "../../validation/ValidationTypes";
-import { ValidationMetadata } from "../../metadata/ValidationMetadata";
-import { getMetadataStorage } from "../../metadata/MetadataStorage";
+import { ValidationOptions } from '../ValidationOptions';
+import { ValidationMetadataArgs } from '../../metadata/ValidationMetadataArgs';
+import { ValidationTypes } from '../../validation/ValidationTypes';
+import { ValidationMetadata } from '../../metadata/ValidationMetadata';
+import { getMetadataStorage } from '../../metadata/MetadataStorage';
 
 /**
  * Resolve promise before validation
  */
 export function ValidatePromise(validationOptions?: ValidationOptions): PropertyDecorator {
-    return function (object: object, propertyName: string): void {
-        const args: ValidationMetadataArgs = {
-            type: ValidationTypes.PROMISE_VALIDATION,
-            target: object.constructor,
-            propertyName: propertyName,
-            validationOptions: validationOptions,
-        };
-        getMetadataStorage().addValidationMetadata(new ValidationMetadata(args));
+  return function (object: object, propertyName: string): void {
+    const args: ValidationMetadataArgs = {
+      type: ValidationTypes.PROMISE_VALIDATION,
+      target: object.constructor,
+      propertyName: propertyName,
+      validationOptions: validationOptions,
     };
+    getMetadataStorage().addValidationMetadata(new ValidationMetadata(args));
+  };
 }
diff --git a/src/decorator/date/MaxDate.ts b/src/decorator/date/MaxDate.ts
index 24b5f19fee..e679c8d0c6 100644
--- a/src/decorator/date/MaxDate.ts
+++ b/src/decorator/date/MaxDate.ts
@@ -1,31 +1,31 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const MAX_DATE = "maxDate";
+export const MAX_DATE = 'maxDate';
 
- /**
+/**
  * Checks if the value is a date that's before the specified date.
  */
 export function maxDate(date: unknown, maxDate: Date): boolean {
-    return date instanceof Date && date.getTime() <= maxDate.getTime();
+  return date instanceof Date && date.getTime() <= maxDate.getTime();
 }
 
 /**
  * Checks if the value is a date that's after the specified date.
  */
 export function MaxDate(date: Date, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: MAX_DATE,
-            constraints: [date],
-            validator: {
-                validate: (value, args): boolean => maxDate(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => "maximal allowed date for " + eachPrefix + "$property is $constraint1",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: MAX_DATE,
+      constraints: [date],
+      validator: {
+        validate: (value, args): boolean => maxDate(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => 'maximal allowed date for ' + eachPrefix + '$property is $constraint1',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/date/MinDate.ts b/src/decorator/date/MinDate.ts
index ceeaa518c9..ae93c841a7 100644
--- a/src/decorator/date/MinDate.ts
+++ b/src/decorator/date/MinDate.ts
@@ -1,31 +1,31 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const MIN_DATE = "minDate";
+export const MIN_DATE = 'minDate';
 
 /**
  * Checks if the value is a date that's after the specified date.
  */
 export function minDate(date: unknown, minDate: Date): boolean {
-    return date instanceof Date && date.getTime() >= minDate.getTime();
+  return date instanceof Date && date.getTime() >= minDate.getTime();
 }
 
 /**
  * Checks if the value is a date that's after the specified date.
  */
 export function MinDate(date: Date, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: MIN_DATE,
-            constraints: [date],
-            validator: {
-                validate: (value, args): boolean => minDate(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => "minimal allowed date for " + eachPrefix + "$property is $constraint1",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: MIN_DATE,
+      constraints: [date],
+      validator: {
+        validate: (value, args): boolean => minDate(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => 'minimal allowed date for ' + eachPrefix + '$property is $constraint1',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/decorators.ts b/src/decorator/decorators.ts
index 9a02464cd7..41b843f4ae 100644
--- a/src/decorator/decorators.ts
+++ b/src/decorator/decorators.ts
@@ -6,139 +6,139 @@
 // Common checkers
 // -------------------------------------------------------------------------
 
-export * from "./common/Allow";
-export * from "./common/IsDefined";
-export * from "./common/IsOptional";
-export * from "./common/Validate";
-export * from "./common/ValidateBy";
-export * from "./common/ValidateIf";
-export * from "./common/ValidateNested";
-export * from "./common/ValidatePromise";
-export * from "./common/IsLatLong";
-export * from "./common/IsLatitude";
-export * from "./common/IsLongitude";
-export * from "./common/Equals";
-export * from "./common/NotEquals";
-export * from "./common/IsEmpty";
-export * from "./common/IsNotEmpty";
-export * from "./common/IsIn";
-export * from "./common/IsNotIn";
+export * from './common/Allow';
+export * from './common/IsDefined';
+export * from './common/IsOptional';
+export * from './common/Validate';
+export * from './common/ValidateBy';
+export * from './common/ValidateIf';
+export * from './common/ValidateNested';
+export * from './common/ValidatePromise';
+export * from './common/IsLatLong';
+export * from './common/IsLatitude';
+export * from './common/IsLongitude';
+export * from './common/Equals';
+export * from './common/NotEquals';
+export * from './common/IsEmpty';
+export * from './common/IsNotEmpty';
+export * from './common/IsIn';
+export * from './common/IsNotIn';
 
 // -------------------------------------------------------------------------
 // Number checkers
 // -------------------------------------------------------------------------
 
-export * from "./number/IsDivisibleBy";
-export * from "./number/IsPositive";
-export * from "./number/IsNegative";
-export * from "./number/Max";
-export * from "./number/Min";
+export * from './number/IsDivisibleBy';
+export * from './number/IsPositive';
+export * from './number/IsNegative';
+export * from './number/Max';
+export * from './number/Min';
 
 // -------------------------------------------------------------------------
 // Date checkers
 // -------------------------------------------------------------------------
 
-export * from "./date/MinDate";
-export * from "./date/MaxDate";
+export * from './date/MinDate';
+export * from './date/MaxDate';
 
 // -------------------------------------------------------------------------
 // String checkers
 // -------------------------------------------------------------------------
 
-export * from "./string/Contains";
-export * from "./string/NotContains";
-export * from "./string/IsAlpha";
-export * from "./string/IsAlphanumeric";
-export * from "./string/IsDecimal";
-export * from "./string/IsAscii";
-export * from "./string/IsBase64";
-export * from "./string/IsByteLength";
-export * from "./string/IsCreditCard";
-export * from "./string/IsCurrency";
-export * from "./string/IsEmail";
-export * from "./string/IsFQDN";
-export * from "./string/IsFullWidth";
-export * from "./string/IsHalfWidth";
-export * from "./string/IsVariableWidth";
-export * from "./string/IsHexColor";
-export * from "./string/IsHexadecimal";
-export * from "./string/IsMacAddress";
-export * from "./string/IsIP";
-export * from "./string/IsPort";
-export * from "./string/IsISBN";
-export * from "./string/IsISIN";
-export * from "./string/IsISO8601";
-export * from "./string/IsJSON";
-export * from "./string/IsJWT";
-export * from "./string/IsLowercase";
-export * from "./string/IsMobilePhone";
-export * from "./string/IsISO31661Alpha2";
-export * from "./string/IsISO31661Alpha3";
-export * from "./string/IsMongoId";
-export * from "./string/IsMultibyte";
-export * from "./string/IsSurrogatePair";
-export * from "./string/IsUrl";
-export * from "./string/IsUUID";
-export * from "./string/IsFirebasePushId";
-export * from "./string/IsUppercase";
-export * from "./string/Length";
-export * from "./string/MaxLength";
-export * from "./string/MinLength";
-export * from "./string/Matches";
-export * from "./string/IsPhoneNumber";
-export * from "./string/IsMilitaryTime";
-export * from "./string/IsHash";
-export * from "./string/IsISSN";
-export * from "./string/IsDateString";
-export * from "./string/IsBooleanString";
-export * from "./string/IsNumberString";
-export * from "./string/IsBase32";
-export * from "./string/IsBIC";
-export * from "./string/IsBtcAddress";
-export * from "./string/IsDataURI";
-export * from "./string/IsEAN";
-export * from "./string/IsEthereumAddress";
-export * from "./string/IsHSL";
-export * from "./string/IsIBAN";
-export * from "./string/IsIdentityCard";
-export * from "./string/IsISRC";
-export * from "./string/IsLocale";
-export * from "./string/IsMagnetURI";
-export * from "./string/IsMimeType";
-export * from "./string/IsOctal";
-export * from "./string/IsPassportNumber";
-export * from "./string/IsPostalCode";
-export * from "./string/IsRFC3339";
-export * from "./string/IsRgbColor";
-export * from "./string/IsSemVer";
+export * from './string/Contains';
+export * from './string/NotContains';
+export * from './string/IsAlpha';
+export * from './string/IsAlphanumeric';
+export * from './string/IsDecimal';
+export * from './string/IsAscii';
+export * from './string/IsBase64';
+export * from './string/IsByteLength';
+export * from './string/IsCreditCard';
+export * from './string/IsCurrency';
+export * from './string/IsEmail';
+export * from './string/IsFQDN';
+export * from './string/IsFullWidth';
+export * from './string/IsHalfWidth';
+export * from './string/IsVariableWidth';
+export * from './string/IsHexColor';
+export * from './string/IsHexadecimal';
+export * from './string/IsMacAddress';
+export * from './string/IsIP';
+export * from './string/IsPort';
+export * from './string/IsISBN';
+export * from './string/IsISIN';
+export * from './string/IsISO8601';
+export * from './string/IsJSON';
+export * from './string/IsJWT';
+export * from './string/IsLowercase';
+export * from './string/IsMobilePhone';
+export * from './string/IsISO31661Alpha2';
+export * from './string/IsISO31661Alpha3';
+export * from './string/IsMongoId';
+export * from './string/IsMultibyte';
+export * from './string/IsSurrogatePair';
+export * from './string/IsUrl';
+export * from './string/IsUUID';
+export * from './string/IsFirebasePushId';
+export * from './string/IsUppercase';
+export * from './string/Length';
+export * from './string/MaxLength';
+export * from './string/MinLength';
+export * from './string/Matches';
+export * from './string/IsPhoneNumber';
+export * from './string/IsMilitaryTime';
+export * from './string/IsHash';
+export * from './string/IsISSN';
+export * from './string/IsDateString';
+export * from './string/IsBooleanString';
+export * from './string/IsNumberString';
+export * from './string/IsBase32';
+export * from './string/IsBIC';
+export * from './string/IsBtcAddress';
+export * from './string/IsDataURI';
+export * from './string/IsEAN';
+export * from './string/IsEthereumAddress';
+export * from './string/IsHSL';
+export * from './string/IsIBAN';
+export * from './string/IsIdentityCard';
+export * from './string/IsISRC';
+export * from './string/IsLocale';
+export * from './string/IsMagnetURI';
+export * from './string/IsMimeType';
+export * from './string/IsOctal';
+export * from './string/IsPassportNumber';
+export * from './string/IsPostalCode';
+export * from './string/IsRFC3339';
+export * from './string/IsRgbColor';
+export * from './string/IsSemVer';
 
 // -------------------------------------------------------------------------
 // Type checkers
 // -------------------------------------------------------------------------
 
-export * from "./typechecker/IsBoolean";
-export * from "./typechecker/IsDate";
-export * from "./typechecker/IsNumber";
-export * from "./typechecker/IsEnum";
-export * from "./typechecker/IsInt";
-export * from "./typechecker/IsString";
-export * from "./typechecker/IsArray";
-export * from "./typechecker/IsObject";
+export * from './typechecker/IsBoolean';
+export * from './typechecker/IsDate';
+export * from './typechecker/IsNumber';
+export * from './typechecker/IsEnum';
+export * from './typechecker/IsInt';
+export * from './typechecker/IsString';
+export * from './typechecker/IsArray';
+export * from './typechecker/IsObject';
 
 // -------------------------------------------------------------------------
 // Array checkers
 // -------------------------------------------------------------------------
 
-export * from "./array/ArrayContains";
-export * from "./array/ArrayNotContains";
-export * from "./array/ArrayNotEmpty";
-export * from "./array/ArrayMinSize";
-export * from "./array/ArrayMaxSize";
-export * from "./array/ArrayUnique";
+export * from './array/ArrayContains';
+export * from './array/ArrayNotContains';
+export * from './array/ArrayNotEmpty';
+export * from './array/ArrayMinSize';
+export * from './array/ArrayMaxSize';
+export * from './array/ArrayUnique';
 
 // -------------------------------------------------------------------------
 // Object checkers
 // -------------------------------------------------------------------------
 
-export * from "./object/IsNotEmptyObject";
-export * from "./object/IsInstance";
+export * from './object/IsNotEmptyObject';
+export * from './object/IsInstance';
diff --git a/src/decorator/number/IsDivisibleBy.ts b/src/decorator/number/IsDivisibleBy.ts
index 8d7f3abe3f..65574c2f64 100644
--- a/src/decorator/number/IsDivisibleBy.ts
+++ b/src/decorator/number/IsDivisibleBy.ts
@@ -1,34 +1,32 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isDivisibleByValidator from 'validator/lib/isDivisibleBy';
 
-export const IS_DIVISIBLE_BY = "isDivisibleBy";
+export const IS_DIVISIBLE_BY = 'isDivisibleBy';
 
 /**
  * Checks if value is a number that's divisible by another.
  */
 export function isDivisibleBy(value: unknown, num: number): boolean {
-    return typeof value === "number" &&
-        typeof num === "number" &&
-        validator.isDivisibleBy(String(value), num);
+  return typeof value === 'number' && typeof num === 'number' && isDivisibleByValidator(String(value), num);
 }
 
 /**
  * Checks if value is a number that's divisible by another.
  */
 export function IsDivisibleBy(num: number, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_DIVISIBLE_BY,
-            constraints: [num],
-            validator: {
-                validate: (value, args): boolean => isDivisibleBy(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be divisible by $constraint1",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_DIVISIBLE_BY,
+      constraints: [num],
+      validator: {
+        validate: (value, args): boolean => isDivisibleBy(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be divisible by $constraint1',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/number/IsNegative.ts b/src/decorator/number/IsNegative.ts
index a3c9891d0d..85463760fa 100644
--- a/src/decorator/number/IsNegative.ts
+++ b/src/decorator/number/IsNegative.ts
@@ -1,30 +1,30 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const IS_NEGATIVE = "isNegative";
+export const IS_NEGATIVE = 'isNegative';
 
 /**
  * Checks if the value is a negative number smaller than zero.
  */
 export function isNegative(value: unknown): boolean {
-    return typeof value === "number" && value < 0;
+  return typeof value === 'number' && value < 0;
 }
 
 /**
  * Checks if the value is a negative number smaller than zero.
  */
 export function IsNegative(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_NEGATIVE,
-            validator: {
-                validate: (value, args): boolean => isNegative(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a negative number",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_NEGATIVE,
+      validator: {
+        validate: (value, args): boolean => isNegative(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a negative number',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/number/IsPositive.ts b/src/decorator/number/IsPositive.ts
index ccf679bbe7..41c888d678 100644
--- a/src/decorator/number/IsPositive.ts
+++ b/src/decorator/number/IsPositive.ts
@@ -1,30 +1,30 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const IS_POSITIVE = "isPositive";
+export const IS_POSITIVE = 'isPositive';
 
 /**
  * Checks if the value is a positive number greater than zero.
  */
 export function isPositive(value: unknown): boolean {
-    return typeof value === "number" && value > 0;
+  return typeof value === 'number' && value > 0;
 }
 
 /**
  * Checks if the value is a positive number greater than zero.
  */
 export function IsPositive(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_POSITIVE,
-            validator: {
-                validate: (value, args): boolean => isPositive(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a positive number",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_POSITIVE,
+      validator: {
+        validate: (value, args): boolean => isPositive(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a positive number',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/number/Max.ts b/src/decorator/number/Max.ts
index 792efdd277..682bb0747d 100644
--- a/src/decorator/number/Max.ts
+++ b/src/decorator/number/Max.ts
@@ -1,31 +1,31 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const MAX = "max";
+export const MAX = 'max';
 
 /**
  * Checks if the first number is less than or equal to the second.
  */
 export function max(num: unknown, max: number): boolean {
-    return typeof num === "number" && typeof max === "number" && num <= max;
+  return typeof num === 'number' && typeof max === 'number' && num <= max;
 }
 
 /**
  * Checks if the first number is less than or equal to the second.
  */
 export function Max(maxValue: number, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: MAX,
-            constraints: [maxValue],
-            validator: {
-                validate: (value, args): boolean => max(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must not be greater than $constraint1",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: MAX,
+      constraints: [maxValue],
+      validator: {
+        validate: (value, args): boolean => max(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must not be greater than $constraint1',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/number/Min.ts b/src/decorator/number/Min.ts
index 88223aac9c..9eede60de4 100644
--- a/src/decorator/number/Min.ts
+++ b/src/decorator/number/Min.ts
@@ -1,31 +1,31 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const MIN = "min";
+export const MIN = 'min';
 
 /**
  * Checks if the first number is greater than or equal to the second.
  */
 export function min(num: unknown, min: number): boolean {
-    return typeof num === "number" && typeof min === "number" && num >= min;
+  return typeof num === 'number' && typeof min === 'number' && num >= min;
 }
 
 /**
  * Checks if the first number is greater than or equal to the second.
  */
 export function Min(minValue: number, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: MIN,
-            constraints: [minValue],
-            validator: {
-                validate: (value, args): boolean => min(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must not be less than $constraint1",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: MIN,
+      constraints: [minValue],
+      validator: {
+        validate: (value, args): boolean => min(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must not be less than $constraint1',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/object/IsInstance.ts b/src/decorator/object/IsInstance.ts
index d72b4f5287..10bf2d0bd9 100644
--- a/src/decorator/object/IsInstance.ts
+++ b/src/decorator/object/IsInstance.ts
@@ -1,39 +1,39 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const IS_INSTANCE = "isInstance";
+export const IS_INSTANCE = 'isInstance';
 
 /**
  * Checks if the value is an instance of the specified object.
  */
 export function isInstance(object: unknown, targetTypeConstructor: new (...args: any[]) => any): boolean {
-    return targetTypeConstructor
-        && typeof targetTypeConstructor === "function"
-        && object instanceof targetTypeConstructor;
+  return (
+    targetTypeConstructor && typeof targetTypeConstructor === 'function' && object instanceof targetTypeConstructor
+  );
 }
 
 /**
  * Checks if the value is an instance of the specified object.
  */
-export function IsInstance(targetType: new (...args: any[]) => any, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_INSTANCE,
-            constraints: [targetType],
-            validator: {
-                validate: (value, args): boolean => isInstance(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix, args) => {
-                        if (args.constraints[0]) {
-                            return eachPrefix + `$property must be an instance of ${args.constraints[0].name}`;
-                        } else {
-                            return eachPrefix + `${IS_INSTANCE} decorator expects and object as value, but got falsy value.`;
-                        }
-                    },
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+export function IsInstance(
+  targetType: new (...args: any[]) => any,
+  validationOptions?: ValidationOptions
+): PropertyDecorator {
+  return ValidateBy(
+    {
+      name: IS_INSTANCE,
+      constraints: [targetType],
+      validator: {
+        validate: (value, args): boolean => isInstance(value, args.constraints[0]),
+        defaultMessage: buildMessage((eachPrefix, args) => {
+          if (args.constraints[0]) {
+            return eachPrefix + `$property must be an instance of ${args.constraints[0].name as string}`;
+          } else {
+            return eachPrefix + `${IS_INSTANCE} decorator expects and object as value, but got falsy value.`;
+          }
+        }, validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/object/IsNotEmptyObject.ts b/src/decorator/object/IsNotEmptyObject.ts
index b68addca48..1fe85b91cf 100644
--- a/src/decorator/object/IsNotEmptyObject.ts
+++ b/src/decorator/object/IsNotEmptyObject.ts
@@ -1,42 +1,51 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import { isObject } from "../typechecker/IsObject";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import { isObject } from '../typechecker/IsObject';
 
-export const IS_NOT_EMPTY_OBJECT = "isNotEmptyObject";
+export const IS_NOT_EMPTY_OBJECT = 'isNotEmptyObject';
 
 /**
  * Checks if the value is valid Object & not empty.
  * Returns false if the value is not an object or an empty valid object.
  */
-export function isNotEmptyObject(value: unknown): boolean {
-    if (!isObject(value)) {
-        return false;
-    }
-    for (const key in value) {
-        if (value.hasOwnProperty(key)) {
-            return true;
-        }
+export function isNotEmptyObject(value: unknown, options?: { nullable?: boolean }): boolean {
+  if (!isObject(value)) {
+    return false;
+  }
+
+  if (options?.nullable === true) {
+    return !Object.values(value).every(propertyValue => propertyValue === null || propertyValue === undefined);
+  }
+
+  for (const key in value) {
+    if (value.hasOwnProperty(key)) {
+      return true;
     }
+  }
 
-    return false;
+  return false;
 }
 
 /**
  * Checks if the value is valid Object & not empty.
  * Returns false if the value is not an object or an empty valid object.
  */
-export function IsNotEmptyObject(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_NOT_EMPTY_OBJECT,
-            validator: {
-                validate: (value, args): boolean => isNotEmptyObject(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a non-empty object",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+export function IsNotEmptyObject(
+  options?: { nullable?: boolean },
+  validationOptions?: ValidationOptions
+): PropertyDecorator {
+  return ValidateBy(
+    {
+      name: IS_NOT_EMPTY_OBJECT,
+      constraints: [options],
+      validator: {
+        validate: (value, args): boolean => isNotEmptyObject(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a non-empty object',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/Contains.ts b/src/decorator/string/Contains.ts
index 4ad25ae52a..f9067c5bff 100644
--- a/src/decorator/string/Contains.ts
+++ b/src/decorator/string/Contains.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import containsValidator from 'validator/lib/contains';
 
-export const CONTAINS = "contains";
+export const CONTAINS = 'contains';
 
 /**
  * Checks if the string contains the seed.
  * If given value is not a string, then it returns false.
  */
 export function contains(value: unknown, seed: string): boolean {
-    return typeof value === "string" && validator.contains(value, seed);
+  return typeof value === 'string' && containsValidator(value, seed);
 }
 
 /**
@@ -17,18 +17,18 @@ export function contains(value: unknown, seed: string): boolean {
  * If given value is not a string, then it returns false.
  */
 export function Contains(seed: string, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: CONTAINS,
-            constraints: [seed],
-            validator: {
-                validate: (value, args): boolean => contains(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must contain a $constraint1 string",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: CONTAINS,
+      constraints: [seed],
+      validator: {
+        validate: (value, args): boolean => contains(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must contain a $constraint1 string',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsAlpha.ts b/src/decorator/string/IsAlpha.ts
index 65c6e53ba7..2e75f33f0e 100644
--- a/src/decorator/string/IsAlpha.ts
+++ b/src/decorator/string/IsAlpha.ts
@@ -1,15 +1,16 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import ValidatorJS from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isAlphaValidator from 'validator/lib/isAlpha';
+import ValidatorJS from 'validator';
 
-export const IS_ALPHA = "isAlpha";
+export const IS_ALPHA = 'isAlpha';
 
 /**
  * Checks if the string contains only letters (a-zA-Z).
  * If given value is not a string, then it returns false.
  */
 export function isAlpha(value: unknown, locale?: ValidatorJS.AlphaLocale): boolean {
-    return typeof value === "string" && ValidatorJS.isAlpha(value, locale);
+  return typeof value === 'string' && isAlphaValidator(value, locale);
 }
 
 /**
@@ -17,18 +18,18 @@ export function isAlpha(value: unknown, locale?: ValidatorJS.AlphaLocale): boole
  * If given value is not a string, then it returns false.
  */
 export function IsAlpha(locale?: string, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_ALPHA,
-            constraints: [locale],
-            validator: {
-                validate: (value, args): boolean => isAlpha(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must contain only letters (a-zA-Z)",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_ALPHA,
+      constraints: [locale],
+      validator: {
+        validate: (value, args): boolean => isAlpha(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must contain only letters (a-zA-Z)',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsAlphanumeric.ts b/src/decorator/string/IsAlphanumeric.ts
index 69b2389aae..2447b0310e 100644
--- a/src/decorator/string/IsAlphanumeric.ts
+++ b/src/decorator/string/IsAlphanumeric.ts
@@ -1,15 +1,16 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import ValidatorJS from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isAlphanumericValidator from 'validator/lib/isAlphanumeric';
+import ValidatorJS from 'validator';
 
-export const IS_ALPHANUMERIC = "isAlphanumeric";
+export const IS_ALPHANUMERIC = 'isAlphanumeric';
 
 /**
  * Checks if the string contains only letters and numbers.
  * If given value is not a string, then it returns false.
  */
 export function isAlphanumeric(value: unknown, locale?: ValidatorJS.AlphanumericLocale): boolean {
-    return typeof value === "string" && ValidatorJS.isAlphanumeric(value, locale);
+  return typeof value === 'string' && isAlphanumericValidator(value, locale);
 }
 
 /**
@@ -17,18 +18,18 @@ export function isAlphanumeric(value: unknown, locale?: ValidatorJS.Alphanumeric
  * If given value is not a string, then it returns false.
  */
 export function IsAlphanumeric(locale?: string, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_ALPHANUMERIC,
-            constraints: [locale],
-            validator: {
-                validate: (value, args): boolean => isAlphanumeric(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must contain only letters and numbers",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_ALPHANUMERIC,
+      constraints: [locale],
+      validator: {
+        validate: (value, args): boolean => isAlphanumeric(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must contain only letters and numbers',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsAscii.ts b/src/decorator/string/IsAscii.ts
index 4a3e0a06be..05f74725dd 100644
--- a/src/decorator/string/IsAscii.ts
+++ b/src/decorator/string/IsAscii.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isAsciiValidator from 'validator/lib/isAscii';
 
-export const IS_ASCII = "isAscii";
+export const IS_ASCII = 'isAscii';
 
 /**
  * Checks if the string contains ASCII chars only.
  * If given value is not a string, then it returns false.
  */
 export function isAscii(value: unknown): boolean {
-    return typeof value === "string" && validator.isAscii(value);
+  return typeof value === 'string' && isAsciiValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isAscii(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsAscii(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_ASCII,
-            validator: {
-                validate: (value, args): boolean => isAscii(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must contain only ASCII characters",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_ASCII,
+      validator: {
+        validate: (value, args): boolean => isAscii(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must contain only ASCII characters',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsBIC.ts b/src/decorator/string/IsBIC.ts
index fcc9bbf211..b530e67758 100644
--- a/src/decorator/string/IsBIC.ts
+++ b/src/decorator/string/IsBIC.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isBICValidator from 'validator/lib/isBIC';
 
-export const IS_BIC = "isBIC";
+export const IS_BIC = 'isBIC';
 
 /**
  * Check if a string is a BIC (Bank Identification Code) or SWIFT code.
  * If given value is not a string, then it returns false.
  */
 export function isBIC(value: unknown): boolean {
-    return typeof value === "string" && validator.isBIC(value);
+  return typeof value === 'string' && isBICValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isBIC(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsBIC(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_BIC,
-            validator: {
-                validate: (value, args): boolean => isBIC(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a BIC or SWIFT code",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_BIC,
+      validator: {
+        validate: (value, args): boolean => isBIC(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a BIC or SWIFT code',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsBase32.ts b/src/decorator/string/IsBase32.ts
index 29bf573116..99958d0d3e 100644
--- a/src/decorator/string/IsBase32.ts
+++ b/src/decorator/string/IsBase32.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isBase32Validator from 'validator/lib/isBase32';
 
-export const IS_BASE32 = "isBase32";
+export const IS_BASE32 = 'isBase32';
 
 /**
  * Checks if a string is base32 encoded.
  * If given value is not a string, then it returns false.
  */
 export function isBase32(value: unknown): boolean {
-    return typeof value === "string" && validator.isBase32(value);
+  return typeof value === 'string' && isBase32Validator(value);
 }
 
 /**
@@ -17,17 +17,14 @@ export function isBase32(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsBase32(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_BASE32,
-            validator: {
-                validate: (value, args): boolean => isBase32(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be base32 encoded",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_BASE32,
+      validator: {
+        validate: (value, args): boolean => isBase32(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be base32 encoded', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsBase64.ts b/src/decorator/string/IsBase64.ts
index 6481d14d9d..75600c6982 100644
--- a/src/decorator/string/IsBase64.ts
+++ b/src/decorator/string/IsBase64.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isBase64Validator from 'validator/lib/isBase64';
 
-export const IS_BASE64 = "isBase64";
+export const IS_BASE64 = 'isBase64';
 
 /**
  * Checks if a string is base64 encoded.
  * If given value is not a string, then it returns false.
  */
 export function isBase64(value: unknown): boolean {
-    return typeof value === "string" && validator.isBase64(value);
+  return typeof value === 'string' && isBase64Validator(value);
 }
 
 /**
@@ -17,17 +17,14 @@ export function isBase64(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsBase64(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_BASE64,
-            validator: {
-                validate: (value, args): boolean => isBase64(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be base64 encoded",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_BASE64,
+      validator: {
+        validate: (value, args): boolean => isBase64(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be base64 encoded', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsBooleanString.ts b/src/decorator/string/IsBooleanString.ts
index ba9fd4156b..e53d71b37b 100644
--- a/src/decorator/string/IsBooleanString.ts
+++ b/src/decorator/string/IsBooleanString.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isBooleanValidator from 'validator/lib/isBoolean';
 
-export const IS_BOOLEAN_STRING = "isBooleanString";
+export const IS_BOOLEAN_STRING = 'isBooleanString';
 
 /**
  * Checks if a string is a boolean.
  * If given value is not a string, then it returns false.
  */
 export function isBooleanString(value: unknown): boolean {
-    return typeof value === "string" && validator.isBoolean(value);
+  return typeof value === 'string' && isBooleanValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isBooleanString(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsBooleanString(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_BOOLEAN_STRING,
-            validator: {
-                validate: (value, args): boolean => isBooleanString(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a boolean string",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_BOOLEAN_STRING,
+      validator: {
+        validate: (value, args): boolean => isBooleanString(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a boolean string',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsBtcAddress.ts b/src/decorator/string/IsBtcAddress.ts
index 19bf3c1dff..f9162adcec 100644
--- a/src/decorator/string/IsBtcAddress.ts
+++ b/src/decorator/string/IsBtcAddress.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isBtcAddressValidator from 'validator/lib/isBtcAddress';
 
-export const IS_BTC_ADDRESS = "isBtcAddress";
+export const IS_BTC_ADDRESS = 'isBtcAddress';
 
 /**
  * Check if the string is a valid BTC address.
  * If given value is not a string, then it returns false.
  */
 export function isBtcAddress(value: unknown): boolean {
-    return typeof value === "string" && validator.isBtcAddress(value);
+  return typeof value === 'string' && isBtcAddressValidator(value);
 }
 
 /**
@@ -17,17 +17,14 @@ export function isBtcAddress(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsBtcAddress(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_BTC_ADDRESS,
-            validator: {
-                validate: (value, args): boolean => isBtcAddress(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a BTC address",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_BTC_ADDRESS,
+      validator: {
+        validate: (value, args): boolean => isBtcAddress(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be a BTC address', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsByteLength.ts b/src/decorator/string/IsByteLength.ts
index e30f399e7d..82ab23d257 100644
--- a/src/decorator/string/IsByteLength.ts
+++ b/src/decorator/string/IsByteLength.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isByteLengthValidator from 'validator/lib/isByteLength';
 
-export const IS_BYTE_LENGTH = "isByteLength";
+export const IS_BYTE_LENGTH = 'isByteLength';
 
 /**
  * Checks if the string's length (in bytes) falls in a range.
  * If given value is not a string, then it returns false.
  */
 export function isByteLength(value: unknown, min: number, max?: number): boolean {
-    return typeof value === "string" && validator.isByteLength(value, { min, max });
+  return typeof value === 'string' && isByteLengthValidator(value, { min, max });
 }
 
 /**
@@ -17,18 +17,18 @@ export function isByteLength(value: unknown, min: number, max?: number): boolean
  * If given value is not a string, then it returns false.
  */
 export function IsByteLength(min: number, max?: number, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_BYTE_LENGTH,
-            constraints: [min, max],
-            validator: {
-                validate: (value, args): boolean => isByteLength(value, args.constraints[0], args.constraints[1]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property's byte length must fall into ($constraint1, $constraint2) range",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_BYTE_LENGTH,
+      constraints: [min, max],
+      validator: {
+        validate: (value, args): boolean => isByteLength(value, args.constraints[0], args.constraints[1]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + "$property's byte length must fall into ($constraint1, $constraint2) range",
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsCreditCard.ts b/src/decorator/string/IsCreditCard.ts
index b0a69bef94..2511d1930c 100644
--- a/src/decorator/string/IsCreditCard.ts
+++ b/src/decorator/string/IsCreditCard.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isCreditCardValidator from 'validator/lib/isCreditCard';
 
-export const IS_CREDIT_CARD = "isCreditCard";
+export const IS_CREDIT_CARD = 'isCreditCard';
 
 /**
  * Checks if the string is a credit card.
  * If given value is not a string, then it returns false.
  */
 export function isCreditCard(value: unknown): boolean {
-    return typeof value === "string" && validator.isCreditCard(value);
+  return typeof value === 'string' && isCreditCardValidator(value);
 }
 
 /**
@@ -17,17 +17,14 @@ export function isCreditCard(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsCreditCard(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_CREDIT_CARD,
-            validator: {
-                validate: (value, args): boolean => isCreditCard(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a credit card",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_CREDIT_CARD,
+      validator: {
+        validate: (value, args): boolean => isCreditCard(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be a credit card', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsCurrency.ts b/src/decorator/string/IsCurrency.ts
index 941ca321cb..419df0affb 100644
--- a/src/decorator/string/IsCurrency.ts
+++ b/src/decorator/string/IsCurrency.ts
@@ -1,34 +1,35 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import ValidatorJS from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isCurrencyValidator from 'validator/lib/isCurrency';
+import ValidatorJS from 'validator';
 
-export const IS_CURRENCY = "isCurrency";
+export const IS_CURRENCY = 'isCurrency';
 
 /**
  * Checks if the string is a valid currency amount.
  * If given value is not a string, then it returns false.
  */
 export function isCurrency(value: unknown, options?: ValidatorJS.IsCurrencyOptions): boolean {
-    return typeof value === "string" && ValidatorJS.isCurrency(value, options);
+  return typeof value === 'string' && isCurrencyValidator(value, options);
 }
 
 /**
  * Checks if the string is a valid currency amount.
  * If given value is not a string, then it returns false.
  */
-export function IsCurrency(options?: ValidatorJS.IsCurrencyOptions, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_CURRENCY,
-            constraints: [options],
-            validator: {
-                validate: (value, args): boolean => isCurrency(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a currency",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+export function IsCurrency(
+  options?: ValidatorJS.IsCurrencyOptions,
+  validationOptions?: ValidationOptions
+): PropertyDecorator {
+  return ValidateBy(
+    {
+      name: IS_CURRENCY,
+      constraints: [options],
+      validator: {
+        validate: (value, args): boolean => isCurrency(value, args.constraints[0]),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be a currency', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsDataURI.ts b/src/decorator/string/IsDataURI.ts
index 10a2f9970a..f07e5fefae 100644
--- a/src/decorator/string/IsDataURI.ts
+++ b/src/decorator/string/IsDataURI.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isDataURIValidator from 'validator/lib/isDataURI';
 
-export const IS_DATA_URI = "isDataURI";
+export const IS_DATA_URI = 'isDataURI';
 
 /**
  * Check if the string is a data uri format.
  * If given value is not a string, then it returns false.
  */
 export function isDataURI(value: unknown): boolean {
-    return typeof value === "string" && validator.isDataURI(value);
+  return typeof value === 'string' && isDataURIValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isDataURI(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsDataURI(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_DATA_URI,
-            validator: {
-                validate: (value, args): boolean => isDataURI(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a data uri format",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_DATA_URI,
+      validator: {
+        validate: (value, args): boolean => isDataURI(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a data uri format',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsDateString.ts b/src/decorator/string/IsDateString.ts
index b9159fe70e..a7c5c5a6fb 100644
--- a/src/decorator/string/IsDateString.ts
+++ b/src/decorator/string/IsDateString.ts
@@ -1,31 +1,36 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import ValidatorJS from 'validator';
+import { isISO8601 } from './IsISO8601';
 
-export const IS_DATE_STRING = "isDateString";
+export const IS_DATE_STRING = 'isDateString';
 
 /**
- * Checks if a given value is a ISOString date.
+ * Alias for IsISO8601 validator
  */
-export function isDateString(value: unknown): boolean {
-    const regex = /^\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d(?:\.\d+)?(?:Z|[+-][0-2]\d(?::[0-5]\d)?)?$/g;
-    return typeof value === "string" && regex.test(value);
+export function isDateString(value: unknown, options?: ValidatorJS.IsISO8601Options): boolean {
+  return isISO8601(value, options);
 }
 
 /**
- * Checks if a given value is a ISOString date.
+ * Alias for IsISO8601 validator
  */
-export function IsDateString(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_DATE_STRING,
-            validator: {
-                validate: (value, args): boolean => isDateString(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a ISOString",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+export function IsDateString(
+  options?: ValidatorJS.IsISO8601Options,
+  validationOptions?: ValidationOptions
+): PropertyDecorator {
+  return ValidateBy(
+    {
+      name: IS_DATE_STRING,
+      constraints: [options],
+      validator: {
+        validate: (value, args): boolean => isDateString(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a valid ISO 8601 date string',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsDecimal.ts b/src/decorator/string/IsDecimal.ts
index 71d34bde12..2c29589f3f 100644
--- a/src/decorator/string/IsDecimal.ts
+++ b/src/decorator/string/IsDecimal.ts
@@ -1,34 +1,38 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import ValidatorJS from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isDecimalValidator from 'validator/lib/isDecimal';
+import ValidatorJS from 'validator';
 
-export const IS_DECIMAL = "isDecimal";
+export const IS_DECIMAL = 'isDecimal';
 
 /**
  * Checks if the string is a valid decimal.
  * If given value is not a string, then it returns false.
  */
 export function isDecimal(value: unknown, options?: ValidatorJS.IsDecimalOptions): boolean {
-    return typeof value === "string" && ValidatorJS.isDecimal(value, options);
+  return typeof value === 'string' && isDecimalValidator(value, options);
 }
 
 /**
  * Checks if the string contains only letters and numbers.
  * If given value is not a string, then it returns false.
  */
-export function IsDecimal(options?: ValidatorJS.IsDecimalOptions, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_DECIMAL,
-            constraints: [options],
-            validator: {
-                validate: (value, args): boolean => isDecimal(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property is not a valid decimal number.",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+export function IsDecimal(
+  options?: ValidatorJS.IsDecimalOptions,
+  validationOptions?: ValidationOptions
+): PropertyDecorator {
+  return ValidateBy(
+    {
+      name: IS_DECIMAL,
+      constraints: [options],
+      validator: {
+        validate: (value, args): boolean => isDecimal(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property is not a valid decimal number.',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsEAN.ts b/src/decorator/string/IsEAN.ts
index 687f911355..73669e969a 100644
--- a/src/decorator/string/IsEAN.ts
+++ b/src/decorator/string/IsEAN.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isEANValidator from 'validator/lib/isEAN';
 
-export const IS_EAN = "isEAN";
+export const IS_EAN = 'isEAN';
 
 /**
  * Check if the string is an EAN (European Article Number).
  * If given value is not a string, then it returns false.
  */
 export function isEAN(value: unknown): boolean {
-    return typeof value === "string" && validator.isEAN(value);
+  return typeof value === 'string' && isEANValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isEAN(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsEAN(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_EAN,
-            validator: {
-                validate: (value, args): boolean => isEAN(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be an EAN (European Article Number)",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_EAN,
+      validator: {
+        validate: (value, args): boolean => isEAN(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be an EAN (European Article Number)',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsEmail.ts b/src/decorator/string/IsEmail.ts
index 173d8a25a4..ac1a86b6c7 100644
--- a/src/decorator/string/IsEmail.ts
+++ b/src/decorator/string/IsEmail.ts
@@ -1,34 +1,35 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import ValidatorJS from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isEmailValidator from 'validator/lib/isEmail';
+import ValidatorJS from 'validator';
 
-export const IS_EMAIL = "isEmail";
+export const IS_EMAIL = 'isEmail';
 
 /**
  * Checks if the string is an email.
  * If given value is not a string, then it returns false.
  */
 export function isEmail(value: unknown, options?: ValidatorJS.IsEmailOptions): boolean {
-    return typeof value === "string" && ValidatorJS.isEmail(value, options);
+  return typeof value === 'string' && isEmailValidator(value, options);
 }
 
 /**
  * Checks if the string is an email.
  * If given value is not a string, then it returns false.
  */
-export function IsEmail(options?: ValidatorJS.IsEmailOptions, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_EMAIL,
-            constraints: [options],
-            validator: {
-                validate: (value, args): boolean => isEmail(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be an email",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+export function IsEmail(
+  options?: ValidatorJS.IsEmailOptions,
+  validationOptions?: ValidationOptions
+): PropertyDecorator {
+  return ValidateBy(
+    {
+      name: IS_EMAIL,
+      constraints: [options],
+      validator: {
+        validate: (value, args): boolean => isEmail(value, args.constraints[0]),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be an email', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsEthereumAddress.ts b/src/decorator/string/IsEthereumAddress.ts
index 229ec459de..cf8dbdbb1b 100644
--- a/src/decorator/string/IsEthereumAddress.ts
+++ b/src/decorator/string/IsEthereumAddress.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isEthereumAddressValidator from 'validator/lib/isEthereumAddress';
 
-export const IS_ETHEREUM_ADDRESS = "isEthereumAddress";
+export const IS_ETHEREUM_ADDRESS = 'isEthereumAddress';
 
 /**
  * Check if the string is an Ethereum address using basic regex. Does not validate address checksums.
  * If given value is not a string, then it returns false.
  */
 export function isEthereumAddress(value: unknown): boolean {
-    return typeof value === "string" && validator.isEthereumAddress(value);
+  return typeof value === 'string' && isEthereumAddressValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isEthereumAddress(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsEthereumAddress(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_ETHEREUM_ADDRESS,
-            validator: {
-                validate: (value, args): boolean => isEthereumAddress(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be an Ethereum address",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_ETHEREUM_ADDRESS,
+      validator: {
+        validate: (value, args): boolean => isEthereumAddress(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be an Ethereum address',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsFQDN.ts b/src/decorator/string/IsFQDN.ts
index 3fa315ae0d..21b56b6e83 100644
--- a/src/decorator/string/IsFQDN.ts
+++ b/src/decorator/string/IsFQDN.ts
@@ -1,15 +1,16 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import ValidatorJS from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isFqdnValidator from 'validator/lib/isFQDN';
+import ValidatorJS from 'validator';
 
-export const IS_FQDN = "isFqdn";
+export const IS_FQDN = 'isFqdn';
 
 /**
  * Checks if the string is a fully qualified domain name (e.g. domain.com).
  * If given value is not a string, then it returns false.
  */
 export function isFQDN(value: unknown, options?: ValidatorJS.IsFQDNOptions): boolean {
-    return typeof value === "string" && ValidatorJS.isFQDN(value, options);
+  return typeof value === 'string' && isFqdnValidator(value, options);
 }
 
 /**
@@ -17,18 +18,18 @@ export function isFQDN(value: unknown, options?: ValidatorJS.IsFQDNOptions): boo
  * If given value is not a string, then it returns false.
  */
 export function IsFQDN(options?: ValidatorJS.IsFQDNOptions, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_FQDN,
-            constraints: [options],
-            validator: {
-                validate: (value, args): boolean => isFQDN(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a valid domain name",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_FQDN,
+      constraints: [options],
+      validator: {
+        validate: (value, args): boolean => isFQDN(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a valid domain name',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsFirebasePushId.ts b/src/decorator/string/IsFirebasePushId.ts
index 97cc3c933d..1d81230c7b 100644
--- a/src/decorator/string/IsFirebasePushId.ts
+++ b/src/decorator/string/IsFirebasePushId.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const IS_FIREBASE_PUSH_ID = "IsFirebasePushId";
+export const IS_FIREBASE_PUSH_ID = 'IsFirebasePushId';
 
 /**
  * Checks if the string is a Firebase Push Id
  * If given value is not a Firebase Push Id, it returns false
  */
 export function isFirebasePushId(value: unknown): boolean {
-    const webSafeRegex = /^[a-zA-Z0-9_-]*$/;
-    return typeof value === "string" && value.length === 20 && webSafeRegex.test(value);
+  const webSafeRegex = /^[a-zA-Z0-9_-]*$/;
+  return typeof value === 'string' && value.length === 20 && webSafeRegex.test(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isFirebasePushId(value: unknown): boolean {
  * If given value is not a Firebase Push Id, it returns false
  */
 export function IsFirebasePushId(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_FIREBASE_PUSH_ID,
-            validator: {
-                validate: (value, args): boolean => isFirebasePushId(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a Firebase Push Id",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_FIREBASE_PUSH_ID,
+      validator: {
+        validate: (value, args): boolean => isFirebasePushId(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a Firebase Push Id',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsFullWidth.ts b/src/decorator/string/IsFullWidth.ts
index 0dc9e20e12..cb9a7cc3a5 100644
--- a/src/decorator/string/IsFullWidth.ts
+++ b/src/decorator/string/IsFullWidth.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isFullWidthValidator from 'validator/lib/isFullWidth';
 
-export const IS_FULL_WIDTH = "isFullWidth";
+export const IS_FULL_WIDTH = 'isFullWidth';
 
 /**
  * Checks if the string contains any full-width chars.
  * If given value is not a string, then it returns false.
  */
 export function isFullWidth(value: unknown): boolean {
-    return typeof value === "string" && validator.isFullWidth(value);
+  return typeof value === 'string' && isFullWidthValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isFullWidth(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsFullWidth(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_FULL_WIDTH,
-            validator: {
-                validate: (value, args): boolean => isFullWidth(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must contain a full-width characters",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_FULL_WIDTH,
+      validator: {
+        validate: (value, args): boolean => isFullWidth(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must contain a full-width characters',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsHSL.ts b/src/decorator/string/IsHSL.ts
index c3b0bceea5..401cbc6fb1 100644
--- a/src/decorator/string/IsHSL.ts
+++ b/src/decorator/string/IsHSL.ts
@@ -1,16 +1,16 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isHSLValidator from 'validator/lib/isHSL';
 
-export const IS_HSL = "isHSL";
+export const IS_HSL = 'isHSL';
 
 /**
-* Check if the string is an HSL (hue, saturation, lightness, optional alpha) color based on CSS Colors Level 4 specification.
+ * Check if the string is an HSL (hue, saturation, lightness, optional alpha) color based on CSS Colors Level 4 specification.
  * Comma-separated format supported. Space-separated format supported with the exception of a few edge cases (ex: hsl(200grad+.1%62%/1)).
  * If given value is not a string, then it returns false.
  */
 export function isHSL(value: unknown): boolean {
-    return typeof value === "string" && validator.isHSL(value);
+  return typeof value === 'string' && isHSLValidator(value);
 }
 
 /**
@@ -19,17 +19,14 @@ export function isHSL(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsHSL(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_HSL,
-            validator: {
-                validate: (value, args): boolean => isHSL(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a HSL color",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_HSL,
+      validator: {
+        validate: (value, args): boolean => isHSL(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be a HSL color', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsHalfWidth.ts b/src/decorator/string/IsHalfWidth.ts
index 3166031156..6eb0f914d9 100644
--- a/src/decorator/string/IsHalfWidth.ts
+++ b/src/decorator/string/IsHalfWidth.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isHalfWidthValidator from 'validator/lib/isHalfWidth';
 
-export const IS_HALF_WIDTH = "isHalfWidth";
+export const IS_HALF_WIDTH = 'isHalfWidth';
 
 /**
  * Checks if the string contains any half-width chars.
  * If given value is not a string, then it returns false.
  */
 export function isHalfWidth(value: unknown): boolean {
-    return typeof value === "string" && validator.isHalfWidth(value);
+  return typeof value === 'string' && isHalfWidthValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isHalfWidth(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsHalfWidth(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_HALF_WIDTH,
-            validator: {
-                validate: (value, args): boolean => isHalfWidth(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must contain a half-width characters",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_HALF_WIDTH,
+      validator: {
+        validate: (value, args): boolean => isHalfWidth(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must contain a half-width characters',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsHash.ts b/src/decorator/string/IsHash.ts
index c7b6017bc5..834bc9384a 100644
--- a/src/decorator/string/IsHash.ts
+++ b/src/decorator/string/IsHash.ts
@@ -1,8 +1,9 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import ValidatorJS from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isHashValidator from 'validator/lib/isHash';
+import ValidatorJS from 'validator';
 
-export const IS_HASH = "isHash";
+export const IS_HASH = 'isHash';
 
 /**
  * Check if the string is a hash of type algorithm.
@@ -10,7 +11,7 @@ export const IS_HASH = "isHash";
  * 'tiger160', 'tiger192', 'crc32', 'crc32b']
  */
 export function isHash(value: unknown, algorithm: ValidatorJS.HashAlgorithm): boolean {
-    return typeof value === "string" && ValidatorJS.isHash(value, algorithm);
+  return typeof value === 'string' && isHashValidator(value, algorithm);
 }
 
 /**
@@ -19,18 +20,18 @@ export function isHash(value: unknown, algorithm: ValidatorJS.HashAlgorithm): bo
  * 'tiger160', 'tiger192', 'crc32', 'crc32b']
  */
 export function IsHash(algorithm: string, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_HASH,
-            constraints: [algorithm],
-            validator: {
-                validate: (value, args): boolean => isHash(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a hash of type $constraint1",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_HASH,
+      constraints: [algorithm],
+      validator: {
+        validate: (value, args): boolean => isHash(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a hash of type $constraint1',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsHexColor.ts b/src/decorator/string/IsHexColor.ts
index 7daef132b8..c72c471135 100644
--- a/src/decorator/string/IsHexColor.ts
+++ b/src/decorator/string/IsHexColor.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isHexColorValidator from 'validator/lib/isHexColor';
 
-export const IS_HEX_COLOR = "isHexColor";
+export const IS_HEX_COLOR = 'isHexColor';
 
 /**
  * Checks if the string is a hexadecimal color.
  * If given value is not a string, then it returns false.
  */
 export function isHexColor(value: unknown): boolean {
-    return typeof value === "string" && validator.isHexColor(value);
+  return typeof value === 'string' && isHexColorValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isHexColor(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsHexColor(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_HEX_COLOR,
-            validator: {
-                validate: (value, args): boolean => isHexColor(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a hexadecimal color",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_HEX_COLOR,
+      validator: {
+        validate: (value, args): boolean => isHexColor(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a hexadecimal color',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsHexadecimal.ts b/src/decorator/string/IsHexadecimal.ts
index 0656ce9916..26d3eb3e34 100644
--- a/src/decorator/string/IsHexadecimal.ts
+++ b/src/decorator/string/IsHexadecimal.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isHexadecimalValidator from 'validator/lib/isHexadecimal';
 
-export const IS_HEXADECIMAL = "isHexadecimal";
+export const IS_HEXADECIMAL = 'isHexadecimal';
 
 /**
  * Checks if the string is a hexadecimal number.
  * If given value is not a string, then it returns false.
  */
 export function isHexadecimal(value: unknown): boolean {
-    return typeof value === "string" && validator.isHexadecimal(value);
+  return typeof value === 'string' && isHexadecimalValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isHexadecimal(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsHexadecimal(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_HEXADECIMAL,
-            validator: {
-                validate: (value, args): boolean => isHexadecimal(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a hexadecimal number",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_HEXADECIMAL,
+      validator: {
+        validate: (value, args): boolean => isHexadecimal(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a hexadecimal number',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsIBAN.ts b/src/decorator/string/IsIBAN.ts
index a381f44766..d0a159fc83 100644
--- a/src/decorator/string/IsIBAN.ts
+++ b/src/decorator/string/IsIBAN.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isIBANValidator from 'validator/lib/isIBAN';
 
-export const IS_IBAN = "isIBAN";
+export const IS_IBAN = 'isIBAN';
 
 /**
  * Check if a string is a IBAN (International Bank Account Number).
  * If given value is not a string, then it returns false.
  */
 export function isIBAN(value: unknown): boolean {
-    return typeof value === "string" && validator.isIBAN(value);
+  return typeof value === 'string' && isIBANValidator(value);
 }
 
 /**
@@ -17,17 +17,14 @@ export function isIBAN(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsIBAN(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_IBAN,
-            validator: {
-                validate: (value, args): boolean => isIBAN(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be an IBAN",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_IBAN,
+      validator: {
+        validate: (value, args): boolean => isIBAN(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be an IBAN', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsIP.ts b/src/decorator/string/IsIP.ts
index 0b2c6481de..840f28afd1 100644
--- a/src/decorator/string/IsIP.ts
+++ b/src/decorator/string/IsIP.ts
@@ -1,18 +1,18 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import ValidatorJS from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isIPValidator from 'validator/lib/isIP';
 
-export type IsIpVersion = "4" | "6" | 4 | 6;
+export type IsIpVersion = '4' | '6' | 4 | 6;
 
-export const IS_IP = "isIp";
+export const IS_IP = 'isIp';
 
 /**
  * Checks if the string is an IP (version 4 or 6).
  * If given value is not a string, then it returns false.
  */
 export function isIP(value: unknown, version?: IsIpVersion): boolean {
-    const versionStr = version ? (`${version}` as "4" | "6") : undefined;
-    return typeof value === "string" && ValidatorJS.isIP(value, versionStr);
+  const versionStr = version ? (`${version}` as '4' | '6') : undefined;
+  return typeof value === 'string' && isIPValidator(value, versionStr);
 }
 
 /**
@@ -20,18 +20,15 @@ export function isIP(value: unknown, version?: IsIpVersion): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsIP(version?: IsIpVersion, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_IP,
-            constraints: [version],
-            validator: {
-                validate: (value, args): boolean => isIP(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be an ip address",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_IP,
+      constraints: [version],
+      validator: {
+        validate: (value, args): boolean => isIP(value, args.constraints[0]),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be an ip address', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsISBN.ts b/src/decorator/string/IsISBN.ts
index c65e645700..afd1a3bda6 100644
--- a/src/decorator/string/IsISBN.ts
+++ b/src/decorator/string/IsISBN.ts
@@ -1,18 +1,18 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import ValidatorJS from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isIsbnValidator from 'validator/lib/isISBN';
 
-export type IsISBNVersion = "10" | "13" | 10 | 13;
+export type IsISBNVersion = '10' | '13' | 10 | 13;
 
-export const IS_ISBN = "isIsbn";
+export const IS_ISBN = 'isIsbn';
 
 /**
  * Checks if the string is an ISBN (version 10 or 13).
  * If given value is not a string, then it returns false.
  */
 export function isISBN(value: unknown, version?: IsISBNVersion): boolean {
-    const versionStr = version ? (`${version}` as "10" | "13") : undefined;
-    return typeof value === "string" && ValidatorJS.isISBN(value, versionStr);
+  const versionStr = version ? (`${version}` as '10' | '13') : undefined;
+  return typeof value === 'string' && isIsbnValidator(value, versionStr);
 }
 
 /**
@@ -20,18 +20,15 @@ export function isISBN(value: unknown, version?: IsISBNVersion): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsISBN(version?: IsISBNVersion, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_ISBN,
-            constraints: [version],
-            validator: {
-                validate: (value, args): boolean => isISBN(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be an ISBN",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_ISBN,
+      constraints: [version],
+      validator: {
+        validate: (value, args): boolean => isISBN(value, args.constraints[0]),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be an ISBN', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsISIN.ts b/src/decorator/string/IsISIN.ts
index bd20b4d50b..2f9b143b1d 100644
--- a/src/decorator/string/IsISIN.ts
+++ b/src/decorator/string/IsISIN.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isIsinValidator from 'validator/lib/isISIN';
 
-export const IS_ISIN = "isIsin";
+export const IS_ISIN = 'isIsin';
 
 /**
  * Checks if the string is an ISIN (stock/security identifier).
  * If given value is not a string, then it returns false.
  */
 export function isISIN(value: unknown): boolean {
-    return typeof value === "string" && validator.isISIN(value);
+  return typeof value === 'string' && isIsinValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isISIN(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsISIN(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_ISIN,
-            validator: {
-                validate: (value, args): boolean => isISIN(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be an ISIN (stock/security identifier)",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_ISIN,
+      validator: {
+        validate: (value, args): boolean => isISIN(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be an ISIN (stock/security identifier)',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsISO31661Alpha2.ts b/src/decorator/string/IsISO31661Alpha2.ts
index 89d63d8fb4..87b19551ae 100644
--- a/src/decorator/string/IsISO31661Alpha2.ts
+++ b/src/decorator/string/IsISO31661Alpha2.ts
@@ -1,31 +1,31 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isISO31661Alpha2Validator from 'validator/lib/isISO31661Alpha2';
 
-export const IS_ISO31661_ALPHA_2 = "isISO31661Alpha2";
+export const IS_ISO31661_ALPHA_2 = 'isISO31661Alpha2';
 
 /**
  * Check if the string is a valid [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) officially assigned country code.
  */
 export function isISO31661Alpha2(value: unknown): boolean {
-    return typeof value === "string" && validator.isISO31661Alpha2(value);
+  return typeof value === 'string' && isISO31661Alpha2Validator(value);
 }
 
 /**
  * Check if the string is a valid [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) officially assigned country code.
  */
 export function IsISO31661Alpha2(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_ISO31661_ALPHA_2,
-            validator: {
-                validate: (value, args): boolean => isISO31661Alpha2(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a valid ISO31661 Alpha2 code",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_ISO31661_ALPHA_2,
+      validator: {
+        validate: (value, args): boolean => isISO31661Alpha2(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a valid ISO31661 Alpha2 code',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsISO31661Alpha3.ts b/src/decorator/string/IsISO31661Alpha3.ts
index b0d83a6d7d..bf43ff519b 100644
--- a/src/decorator/string/IsISO31661Alpha3.ts
+++ b/src/decorator/string/IsISO31661Alpha3.ts
@@ -1,31 +1,31 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isISO31661Alpha3Validator from 'validator/lib/isISO31661Alpha3';
 
-export const IS_ISO31661_ALPHA_3 = "isISO31661Alpha3";
+export const IS_ISO31661_ALPHA_3 = 'isISO31661Alpha3';
 
 /**
  * Check if the string is a valid [ISO 3166-1 alpha-3](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3) officially assigned country code.
  */
 export function isISO31661Alpha3(value: unknown): boolean {
-    return typeof value === "string" && validator.isISO31661Alpha3(value);
+  return typeof value === 'string' && isISO31661Alpha3Validator(value);
 }
 
 /**
  * Check if the string is a valid [ISO 3166-1 alpha-3](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-3) officially assigned country code.
  */
 export function IsISO31661Alpha3(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_ISO31661_ALPHA_3,
-            validator: {
-                validate: (value, args): boolean => isISO31661Alpha3(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a valid ISO31661 Alpha3 code",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_ISO31661_ALPHA_3,
+      validator: {
+        validate: (value, args): boolean => isISO31661Alpha3(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a valid ISO31661 Alpha3 code',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsISO8601.ts b/src/decorator/string/IsISO8601.ts
index c29982d81d..9c67aeffa5 100644
--- a/src/decorator/string/IsISO8601.ts
+++ b/src/decorator/string/IsISO8601.ts
@@ -1,8 +1,9 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import ValidatorJS from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isIso8601Validator from 'validator/lib/isISO8601';
+import ValidatorJS from 'validator';
 
-export const IS_ISO8601 = "isIso8601";
+export const IS_ISO8601 = 'isIso8601';
 
 /**
  * Checks if the string is a valid ISO 8601 date.
@@ -10,7 +11,7 @@ export const IS_ISO8601 = "isIso8601";
  * Use the option strict = true for additional checks for a valid date, e.g. invalidates dates like 2019-02-29.
  */
 export function isISO8601(value: unknown, options?: ValidatorJS.IsISO8601Options): boolean {
-    return typeof value === "string" && ValidatorJS.isISO8601(value, options);
+  return typeof value === 'string' && isIso8601Validator(value, options);
 }
 
 /**
@@ -18,19 +19,22 @@ export function isISO8601(value: unknown, options?: ValidatorJS.IsISO8601Options
  * If given value is not a string, then it returns false.
  * Use the option strict = true for additional checks for a valid date, e.g. invalidates dates like 2019-02-29.
  */
-export function IsISO8601(options?: ValidatorJS.IsISO8601Options, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_ISO8601,
-            constraints: [options],
-            validator: {
-                validate: (value, args): boolean => isISO8601(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a valid ISO 8601 date string",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+export function IsISO8601(
+  options?: ValidatorJS.IsISO8601Options,
+  validationOptions?: ValidationOptions
+): PropertyDecorator {
+  return ValidateBy(
+    {
+      name: IS_ISO8601,
+      constraints: [options],
+      validator: {
+        validate: (value, args): boolean => isISO8601(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a valid ISO 8601 date string',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsISRC.ts b/src/decorator/string/IsISRC.ts
index 4550a441f3..f41b3c3cdc 100644
--- a/src/decorator/string/IsISRC.ts
+++ b/src/decorator/string/IsISRC.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isISRCValidator from 'validator/lib/isISRC';
 
-export const IS_ISRC = "isISRC";
+export const IS_ISRC = 'isISRC';
 
 /**
  * Check if the string is a ISRC.
  * If given value is not a string, then it returns false.
  */
 export function isISRC(value: unknown): boolean {
-    return typeof value === "string" && validator.isISRC(value);
+  return typeof value === 'string' && isISRCValidator(value);
 }
 
 /**
@@ -17,17 +17,14 @@ export function isISRC(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsISRC(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_ISRC,
-            validator: {
-                validate: (value, args): boolean => isISRC(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be an ISRC",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_ISRC,
+      validator: {
+        validate: (value, args): boolean => isISRC(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be an ISRC', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsISSN.ts b/src/decorator/string/IsISSN.ts
index 7507136d48..3677d2e957 100644
--- a/src/decorator/string/IsISSN.ts
+++ b/src/decorator/string/IsISSN.ts
@@ -1,15 +1,16 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import ValidatorJS from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isISSNValidator from 'validator/lib/isISSN';
+import ValidatorJS from 'validator';
 
-export const IS_ISSN = "isISSN";
+export const IS_ISSN = 'isISSN';
 
 /**
  * Checks if the string is a ISSN.
  * If given value is not a string, then it returns false.
  */
 export function isISSN(value: unknown, options?: ValidatorJS.IsISSNOptions): boolean {
-    return typeof value === "string" && ValidatorJS.isISSN(value, options);
+  return typeof value === 'string' && isISSNValidator(value, options);
 }
 
 /**
@@ -17,18 +18,15 @@ export function isISSN(value: unknown, options?: ValidatorJS.IsISSNOptions): boo
  * If given value is not a string, then it returns false.
  */
 export function IsISSN(options?: ValidatorJS.IsISSNOptions, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_ISSN,
-            constraints: [options],
-            validator: {
-                validate: (value, args): boolean => isISSN(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a ISSN",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_ISSN,
+      constraints: [options],
+      validator: {
+        validate: (value, args): boolean => isISSN(value, args.constraints[0]),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be a ISSN', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsIdentityCard.ts b/src/decorator/string/IsIdentityCard.ts
index 7eea6ec59f..543534cfc9 100644
--- a/src/decorator/string/IsIdentityCard.ts
+++ b/src/decorator/string/IsIdentityCard.ts
@@ -1,8 +1,9 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import ValidatorJS from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isIdentityCardValidator from 'validator/lib/isIdentityCard';
+import ValidatorJS from 'validator';
 
-export const IS_IDENTITY_CARD = "isIdentityCard";
+export const IS_IDENTITY_CARD = 'isIdentityCard';
 
 /**
  * Check if the string is a valid identity card code.
@@ -11,7 +12,7 @@ export const IS_IDENTITY_CARD = "isIdentityCard";
  * If given value is not a string, then it returns false.
  */
 export function isIdentityCard(value: unknown, locale: ValidatorJS.IdentityCardLocale): boolean {
-    return typeof value === "string" && ValidatorJS.isIdentityCard(value, locale);
+  return typeof value === 'string' && isIdentityCardValidator(value, locale);
 }
 
 /**
@@ -20,19 +21,22 @@ export function isIdentityCard(value: unknown, locale: ValidatorJS.IdentityCardL
  * Defaults to 'any'.
  * If given value is not a string, then it returns false.
  */
-export function IsIdentityCard(locale?: ValidatorJS.IdentityCardLocale, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_IDENTITY_CARD,
-            constraints: [locale],
-            validator: {
-                validate: (value, args): boolean => isIdentityCard(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a identity card number",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+export function IsIdentityCard(
+  locale?: ValidatorJS.IdentityCardLocale,
+  validationOptions?: ValidationOptions
+): PropertyDecorator {
+  return ValidateBy(
+    {
+      name: IS_IDENTITY_CARD,
+      constraints: [locale],
+      validator: {
+        validate: (value, args): boolean => isIdentityCard(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a identity card number',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsJSON.ts b/src/decorator/string/IsJSON.ts
index 99d8b32f8f..2bdf8f04b9 100644
--- a/src/decorator/string/IsJSON.ts
+++ b/src/decorator/string/IsJSON.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isJSONValidator from 'validator/lib/isJSON';
 
-export const IS_JSON = "isJson";
+export const IS_JSON = 'isJson';
 
 /**
  * Checks if the string is valid JSON (note: uses JSON.parse).
  * If given value is not a string, then it returns false.
  */
 export function isJSON(value: unknown): boolean {
-    return typeof value === "string" && validator.isJSON(value);
+  return typeof value === 'string' && isJSONValidator(value);
 }
 
 /**
@@ -17,17 +17,14 @@ export function isJSON(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsJSON(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_JSON,
-            validator: {
-                validate: (value, args): boolean => isJSON(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a json string",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_JSON,
+      validator: {
+        validate: (value, args): boolean => isJSON(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be a json string', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsJWT.ts b/src/decorator/string/IsJWT.ts
index 3e5740cdd6..69ecc900a7 100644
--- a/src/decorator/string/IsJWT.ts
+++ b/src/decorator/string/IsJWT.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isJwtValidator from 'validator/lib/isJWT';
 
-export const IS_JWT = "isJwt";
+export const IS_JWT = 'isJwt';
 
 /**
  * Checks if the string is valid JWT token.
  * If given value is not a string, then it returns false.
  */
 export function isJWT(value: unknown): boolean {
-    return typeof value === "string" && validator.isJWT(value);
+  return typeof value === 'string' && isJwtValidator(value);
 }
 
 /**
@@ -17,17 +17,14 @@ export function isJWT(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsJWT(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_JWT,
-            validator: {
-                validate: (value, args): boolean => isJWT(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a jwt string",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_JWT,
+      validator: {
+        validate: (value, args): boolean => isJWT(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be a jwt string', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsLocale.ts b/src/decorator/string/IsLocale.ts
index 8b10b0f7f9..043ddf2510 100644
--- a/src/decorator/string/IsLocale.ts
+++ b/src/decorator/string/IsLocale.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isLocaleValidator from 'validator/lib/isLocale';
 
-export const IS_LOCALE = "isLocale";
+export const IS_LOCALE = 'isLocale';
 
 /**
  * Check if the string is a locale.
  * If given value is not a string, then it returns false.
  */
 export function isLocale(value: unknown): boolean {
-    return typeof value === "string" && validator.isLocale(value);
+  return typeof value === 'string' && isLocaleValidator(value);
 }
 
 /**
@@ -17,17 +17,14 @@ export function isLocale(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsLocale(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_LOCALE,
-            validator: {
-                validate: (value, args): boolean => isLocale(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be locale",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_LOCALE,
+      validator: {
+        validate: (value, args): boolean => isLocale(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be locale', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsLowercase.ts b/src/decorator/string/IsLowercase.ts
index 15dd4b77d7..1042dadcfd 100644
--- a/src/decorator/string/IsLowercase.ts
+++ b/src/decorator/string/IsLowercase.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isLowercaseValidator from 'validator/lib/isLowercase';
 
-export const IS_LOWERCASE = "isLowercase";
+export const IS_LOWERCASE = 'isLowercase';
 
 /**
  * Checks if the string is lowercase.
  * If given value is not a string, then it returns false.
  */
 export function isLowercase(value: unknown): boolean {
-    return typeof value === "string" && validator.isLowercase(value);
+  return typeof value === 'string' && isLowercaseValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isLowercase(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsLowercase(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_LOWERCASE,
-            validator: {
-                validate: (value, args): boolean => isLowercase(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a lowercase string",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_LOWERCASE,
+      validator: {
+        validate: (value, args): boolean => isLowercase(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a lowercase string',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsMacAddress.ts b/src/decorator/string/IsMacAddress.ts
index 694f305706..ed91b32a6c 100644
--- a/src/decorator/string/IsMacAddress.ts
+++ b/src/decorator/string/IsMacAddress.ts
@@ -1,39 +1,45 @@
-import { ValidationOptions, isValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import ValidatorJS from "validator";
+import { ValidationOptions, isValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isMacAddressValidator from 'validator/lib/isMACAddress';
+import ValidatorJS from 'validator';
 
-export const IS_MAC_ADDRESS = "isMacAddress";
+export const IS_MAC_ADDRESS = 'isMacAddress';
 
 /**
  * Check if the string is a MAC address.
  * If given value is not a string, then it returns false.
  */
 export function isMACAddress(value: unknown, options?: ValidatorJS.IsMACAddressOptions): boolean {
-    return typeof value === "string" && ValidatorJS.isMACAddress(value, options);
+  return typeof value === 'string' && isMacAddressValidator(value, options);
 }
 
 /**
  * Check if the string is a MAC address.
  * If given value is not a string, then it returns false.
  */
-export function IsMACAddress(optionsArg?: ValidatorJS.IsMACAddressOptions, validationOptionsArg?: ValidationOptions): PropertyDecorator;
+export function IsMACAddress(
+  optionsArg?: ValidatorJS.IsMACAddressOptions,
+  validationOptionsArg?: ValidationOptions
+): PropertyDecorator;
 export function IsMACAddress(validationOptionsArg?: ValidationOptions): PropertyDecorator;
-export function IsMACAddress(optionsOrValidationOptionsArg?: ValidatorJS.IsMACAddressOptions | ValidationOptions, validationOptionsArg?: ValidationOptions): PropertyDecorator {
-    const options = !isValidationOptions(optionsOrValidationOptionsArg) ? optionsOrValidationOptionsArg : undefined;
-    const validationOptions = isValidationOptions(optionsOrValidationOptionsArg) ? optionsOrValidationOptionsArg : validationOptionsArg;
+export function IsMACAddress(
+  optionsOrValidationOptionsArg?: ValidatorJS.IsMACAddressOptions | ValidationOptions,
+  validationOptionsArg?: ValidationOptions
+): PropertyDecorator {
+  const options = !isValidationOptions(optionsOrValidationOptionsArg) ? optionsOrValidationOptionsArg : undefined;
+  const validationOptions = isValidationOptions(optionsOrValidationOptionsArg)
+    ? optionsOrValidationOptionsArg
+    : validationOptionsArg;
 
-    return ValidateBy(
-        {
-            name: IS_MAC_ADDRESS,
-            constraints: [options],
-            validator: {
-                validate: (value, args): boolean => isMACAddress(value, options),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a MAC Address",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_MAC_ADDRESS,
+      constraints: [options],
+      validator: {
+        validate: (value, args): boolean => isMACAddress(value, options),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be a MAC Address', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsMagnetURI.ts b/src/decorator/string/IsMagnetURI.ts
index 865605e4de..a4758dca65 100644
--- a/src/decorator/string/IsMagnetURI.ts
+++ b/src/decorator/string/IsMagnetURI.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isMagnetURIValidator from 'validator/lib/isMagnetURI';
 
-export const IS_MAGNET_URI = "isMagnetURI";
+export const IS_MAGNET_URI = 'isMagnetURI';
 
 /**
  * Check if the string is a magnet uri format.
  * If given value is not a string, then it returns false.
  */
 export function isMagnetURI(value: unknown): boolean {
-    return typeof value === "string" && validator.isMagnetURI(value);
+  return typeof value === 'string' && isMagnetURIValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isMagnetURI(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsMagnetURI(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_MAGNET_URI,
-            validator: {
-                validate: (value, args): boolean => isMagnetURI(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be magnet uri format",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_MAGNET_URI,
+      validator: {
+        validate: (value, args): boolean => isMagnetURI(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be magnet uri format',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsMilitaryTime.ts b/src/decorator/string/IsMilitaryTime.ts
index 0200ee7b73..6d209b2ac1 100644
--- a/src/decorator/string/IsMilitaryTime.ts
+++ b/src/decorator/string/IsMilitaryTime.ts
@@ -1,16 +1,16 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import matchesValidator from 'validator/lib/matches';
 
-export const IS_MILITARY_TIME = "isMilitaryTime";
+export const IS_MILITARY_TIME = 'isMilitaryTime';
 
 /**
  * Checks if the string represents a time without a given timezone in the format HH:MM (military)
  * If the given value does not match the pattern HH:MM, then it returns false.
  */
 export function isMilitaryTime(value: unknown): boolean {
-    const militaryTimeRegex = /^([01]\d|2[0-3]):?([0-5]\d)$/;
-    return typeof value === "string" && validator.matches(value, militaryTimeRegex);
+  const militaryTimeRegex = /^([01]\d|2[0-3]):?([0-5]\d)$/;
+  return typeof value === 'string' && matchesValidator(value, militaryTimeRegex);
 }
 
 /**
@@ -18,17 +18,17 @@ export function isMilitaryTime(value: unknown): boolean {
  * If the given value does not match the pattern HH:MM, then it returns false.
  */
 export function IsMilitaryTime(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_MILITARY_TIME,
-            validator: {
-                validate: (value, args): boolean => isMilitaryTime(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a valid representation of military time in the format HH:MM",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_MILITARY_TIME,
+      validator: {
+        validate: (value, args): boolean => isMilitaryTime(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a valid representation of military time in the format HH:MM',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsMimeType.ts b/src/decorator/string/IsMimeType.ts
index e848ecc55a..edc5136953 100644
--- a/src/decorator/string/IsMimeType.ts
+++ b/src/decorator/string/IsMimeType.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isMimeTypeValidator from 'validator/lib/isMimeType';
 
-export const IS_MIME_TYPE = "isMimeType";
+export const IS_MIME_TYPE = 'isMimeType';
 
 /**
  * Check if the string matches to a valid MIME type format
  * If given value is not a string, then it returns false.
  */
 export function isMimeType(value: unknown): boolean {
-    return typeof value === "string" && validator.isMimeType(value);
+  return typeof value === 'string' && isMimeTypeValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isMimeType(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsMimeType(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_MIME_TYPE,
-            validator: {
-                validate: (value, args): boolean => isMimeType(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be MIME type format",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_MIME_TYPE,
+      validator: {
+        validate: (value, args): boolean => isMimeType(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be MIME type format',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsMobilePhone.ts b/src/decorator/string/IsMobilePhone.ts
index e26be4d420..56dad32da9 100644
--- a/src/decorator/string/IsMobilePhone.ts
+++ b/src/decorator/string/IsMobilePhone.ts
@@ -1,8 +1,9 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isMobilePhoneValidator from 'validator/lib/isMobilePhone';
+import ValidatorJS from 'validator';
 
-export const IS_MOBILE_PHONE = "isMobilePhone";
+export const IS_MOBILE_PHONE = 'isMobilePhone';
 
 /**
  * Checks if the string is a mobile phone number (locale is either an array of locales (e.g ['sk-SK', 'sr-RS'])
@@ -16,8 +17,12 @@ export const IS_MOBILE_PHONE = "isMobilePhone";
  * 'zh-HK', 'zh-MO', 'zh-TW']
  * If given value is not a string, then it returns false.
  */
-export function isMobilePhone(value: unknown, locale?: validator.MobilePhoneLocale, options?: validator.IsMobilePhoneOptions): boolean {
-    return typeof value === "string" && validator.isMobilePhone(value, locale, options);
+export function isMobilePhone(
+  value: unknown,
+  locale?: ValidatorJS.MobilePhoneLocale,
+  options?: ValidatorJS.IsMobilePhoneOptions
+): boolean {
+  return typeof value === 'string' && isMobilePhoneValidator(value, locale, options);
 }
 
 /**
@@ -32,19 +37,20 @@ export function isMobilePhone(value: unknown, locale?: validator.MobilePhoneLoca
  * 'zh-HK', 'zh-MO', 'zh-TW']
  * If given value is not a string, then it returns false.
  */
-export function IsMobilePhone(locale?: validator.MobilePhoneLocale, options?: validator.IsMobilePhoneOptions, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_MOBILE_PHONE,
-            constraints: [locale, options],
-            validator: {
-                validate: (value, args): boolean => isMobilePhone(value, args.constraints[0], args.constraints[1]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a phone number",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+export function IsMobilePhone(
+  locale?: ValidatorJS.MobilePhoneLocale,
+  options?: ValidatorJS.IsMobilePhoneOptions,
+  validationOptions?: ValidationOptions
+): PropertyDecorator {
+  return ValidateBy(
+    {
+      name: IS_MOBILE_PHONE,
+      constraints: [locale, options],
+      validator: {
+        validate: (value, args): boolean => isMobilePhone(value, args.constraints[0], args.constraints[1]),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be a phone number', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsMongoId.ts b/src/decorator/string/IsMongoId.ts
index 91c868e15d..fa8507fb66 100644
--- a/src/decorator/string/IsMongoId.ts
+++ b/src/decorator/string/IsMongoId.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isMongoIdValidator from 'validator/lib/isMongoId';
 
-export const IS_MONGO_ID = "isMongoId";
+export const IS_MONGO_ID = 'isMongoId';
 
 /**
  * Checks if the string is a valid hex-encoded representation of a MongoDB ObjectId.
  * If given value is not a string, then it returns false.
  */
 export function isMongoId(value: unknown): boolean {
-    return typeof value === "string" && validator.isMongoId(value);
+  return typeof value === 'string' && isMongoIdValidator(value);
 }
 
 /**
@@ -17,17 +17,14 @@ export function isMongoId(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsMongoId(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_MONGO_ID,
-            validator: {
-                validate: (value, args): boolean => isMongoId(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a mongodb id",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_MONGO_ID,
+      validator: {
+        validate: (value, args): boolean => isMongoId(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be a mongodb id', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsMultibyte.ts b/src/decorator/string/IsMultibyte.ts
index 0cdd306b46..c295b640c9 100644
--- a/src/decorator/string/IsMultibyte.ts
+++ b/src/decorator/string/IsMultibyte.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isMultibyteValidator from 'validator/lib/isMultibyte';
 
-export const IS_MULTIBYTE = "isMultibyte";
+export const IS_MULTIBYTE = 'isMultibyte';
 
 /**
  * Checks if the string contains one or more multibyte chars.
  * If given value is not a string, then it returns false.
  */
 export function isMultibyte(value: unknown): boolean {
-    return typeof value === "string" && validator.isMultibyte(value);
+  return typeof value === 'string' && isMultibyteValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isMultibyte(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsMultibyte(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_MULTIBYTE,
-            validator: {
-                validate: (value, args): boolean => isMultibyte(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must contain one or more multibyte chars",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_MULTIBYTE,
+      validator: {
+        validate: (value, args): boolean => isMultibyte(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must contain one or more multibyte chars',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsNumberString.ts b/src/decorator/string/IsNumberString.ts
index 08a1363dc3..9c3ed53dc4 100644
--- a/src/decorator/string/IsNumberString.ts
+++ b/src/decorator/string/IsNumberString.ts
@@ -1,34 +1,35 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import ValidatorJS from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isNumericValidator from 'validator/lib/isNumeric';
+import ValidatorJS from 'validator';
 
-export const IS_NUMBER_STRING = "isNumberString";
+export const IS_NUMBER_STRING = 'isNumberString';
 
 /**
  * Checks if the string is numeric.
  * If given value is not a string, then it returns false.
  */
 export function isNumberString(value: unknown, options?: ValidatorJS.IsNumericOptions): boolean {
-    return typeof value === "string" && ValidatorJS.isNumeric(value, options);
+  return typeof value === 'string' && isNumericValidator(value, options);
 }
 
 /**
  * Checks if the string is numeric.
  * If given value is not a string, then it returns false.
  */
-export function IsNumberString(options?: ValidatorJS.IsNumericOptions, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_NUMBER_STRING,
-            constraints: [options],
-            validator: {
-                validate: (value, args): boolean => isNumberString(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a number string",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+export function IsNumberString(
+  options?: ValidatorJS.IsNumericOptions,
+  validationOptions?: ValidationOptions
+): PropertyDecorator {
+  return ValidateBy(
+    {
+      name: IS_NUMBER_STRING,
+      constraints: [options],
+      validator: {
+        validate: (value, args): boolean => isNumberString(value, args.constraints[0]),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be a number string', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsOctal.ts b/src/decorator/string/IsOctal.ts
index 23403998a5..4427926455 100644
--- a/src/decorator/string/IsOctal.ts
+++ b/src/decorator/string/IsOctal.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isOctalValidator from 'validator/lib/isOctal';
 
-export const IS_OCTAL = "isOctal";
+export const IS_OCTAL = 'isOctal';
 
 /**
  * Check if the string is a valid octal number.
  * If given value is not a string, then it returns false.
  */
 export function isOctal(value: unknown): boolean {
-    return typeof value === "string" && validator.isOctal(value);
+  return typeof value === 'string' && isOctalValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isOctal(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsOctal(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_OCTAL,
-            validator: {
-                validate: (value, args): boolean => isOctal(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be valid octal number",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_OCTAL,
+      validator: {
+        validate: (value, args): boolean => isOctal(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be valid octal number',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsPassportNumber.ts b/src/decorator/string/IsPassportNumber.ts
index c86e2f2fcd..e3d00063ea 100644
--- a/src/decorator/string/IsPassportNumber.ts
+++ b/src/decorator/string/IsPassportNumber.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isPassportNumberValidator from 'validator/lib/isPassportNumber';
 
-export const IS_PASSPORT_NUMBER = "isPassportNumber";
+export const IS_PASSPORT_NUMBER = 'isPassportNumber';
 
 /**
  * Check if the string is a valid passport number relative to a specific country code.
  * If given value is not a string, then it returns false.
  */
 export function isPassportNumber(value: unknown, countryCode: string): boolean {
-    return typeof value === "string" && validator.isPassportNumber(value, countryCode);
+  return typeof value === 'string' && isPassportNumberValidator(value, countryCode);
 }
 
 /**
@@ -17,18 +17,18 @@ export function isPassportNumber(value: unknown, countryCode: string): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsPassportNumber(countryCode: string, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_PASSPORT_NUMBER,
-            constraints: [countryCode],
-            validator: {
-                validate: (value, args): boolean => isPassportNumber(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be valid passport number",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_PASSPORT_NUMBER,
+      constraints: [countryCode],
+      validator: {
+        validate: (value, args): boolean => isPassportNumber(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be valid passport number',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsPhoneNumber.ts b/src/decorator/string/IsPhoneNumber.ts
index c514da0758..5d93dc6049 100644
--- a/src/decorator/string/IsPhoneNumber.ts
+++ b/src/decorator/string/IsPhoneNumber.ts
@@ -1,47 +1,47 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import { PhoneNumberUtil } from "google-libphonenumber";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import { parsePhoneNumberFromString, CountryCode } from 'libphonenumber-js';
 
-export const IS_PHONE_NUMBER = "isPhoneNumber";
+export const IS_PHONE_NUMBER = 'isPhoneNumber';
 
 /**
  * Checks if the string is a valid phone number.
  * @param value the potential phone number string to test
  * @param {string} region 2 characters uppercase country code (e.g. DE, US, CH).
  * If users must enter the intl. prefix (e.g. +41), then you may pass "ZZ" or null as region.
- * See [google-libphonenumber, metadata.js:countryCodeToRegionCodeMap on github]{@link https://github.com/ruimarinho/google-libphonenumber/blob/1e46138878cff479aafe2ce62175c6c49cb58720/src/metadata.js#L33}
  */
-export function isPhoneNumber(value: string, region: string | null): boolean {
-    const phoneUtil = PhoneNumberUtil.getInstance();
-    try {
-        const phoneNum = phoneUtil.parseAndKeepRawInput(value, region);
-        const result = phoneUtil.isValidNumber(phoneNum);
-        return result;
-    } catch (error) {
-        // logging?
-        return false;
-    }
+export function isPhoneNumber(value: string, region: CountryCode | undefined): boolean {
+  try {
+    const phoneNum = parsePhoneNumberFromString(value, region);
+    const result = phoneNum?.isValid();
+    return !!result;
+  } catch (error) {
+    // logging?
+    return false;
+  }
 }
 
 /**
  * Checks if the string is a valid phone number.
  * @param region 2 characters uppercase country code (e.g. DE, US, CH).
  * If users must enter the intl. prefix (e.g. +41), then you may pass "ZZ" or null as region.
- * See [google-libphonenumber, metadata.js:countryCodeToRegionCodeMap on github]{@link https://github.com/ruimarinho/google-libphonenumber/blob/1e46138878cff479aafe2ce62175c6c49cb58720/src/metadata.js#L33}
  */
-export function IsPhoneNumber(region: string | null, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_PHONE_NUMBER,
-            constraints: [region],
-            validator: {
-                validate: (value, args): boolean => isPhoneNumber(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a valid phone number",
-                    validationOptions
-                ),
-            }
-        },
-        validationOptions
-    );
+export function IsPhoneNumber(
+  region: CountryCode | undefined,
+  validationOptions?: ValidationOptions
+): PropertyDecorator {
+  return ValidateBy(
+    {
+      name: IS_PHONE_NUMBER,
+      constraints: [region],
+      validator: {
+        validate: (value, args): boolean => isPhoneNumber(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a valid phone number',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsPort.ts b/src/decorator/string/IsPort.ts
index 13c3af3bcb..d7809e3c42 100644
--- a/src/decorator/string/IsPort.ts
+++ b/src/decorator/string/IsPort.ts
@@ -1,31 +1,28 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isPortValidator from 'validator/lib/isPort';
 
-export const IS_PORT = "isPort";
+export const IS_PORT = 'isPort';
 
 /**
  * Check if the string is a valid port number.
  */
 export function isPort(value: unknown): boolean {
-    return typeof value === "string" && validator.isPort(value);
+  return typeof value === 'string' && isPortValidator(value);
 }
 
 /**
  * Check if the string is a valid port number.
  */
 export function IsPort(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_PORT,
-            validator: {
-                validate: (value, args): boolean => isPort(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a port",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_PORT,
+      validator: {
+        validate: (value, args): boolean => isPort(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be a port', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsPostalCode.ts b/src/decorator/string/IsPostalCode.ts
index 3c031d0cbb..3d802ee7df 100644
--- a/src/decorator/string/IsPostalCode.ts
+++ b/src/decorator/string/IsPostalCode.ts
@@ -1,16 +1,17 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isPostalCodeValidator from 'validator/lib/isPostalCode';
+import ValidatorJS from 'validator';
 
-export const IS_POSTAL_CODE = "isPostalCode";
+export const IS_POSTAL_CODE = 'isPostalCode';
 
 /**
  * Check if the string is a postal code,
  * (locale is one of [ 'AD', 'AT', 'AU', 'BE', 'BG', 'BR', 'CA', 'CH', 'CZ', 'DE', 'DK', 'DZ', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU', 'ID', 'IE' 'IL', 'IN', 'IR', 'IS', 'IT', 'JP', 'KE', 'LI', 'LT', 'LU', 'LV', 'MT', 'MX', 'NL', 'NO', 'NZ', 'PL', 'PR', 'PT', 'RO', 'RU', 'SA', 'SE', 'SI', 'TN', 'TW', 'UA', 'US', 'ZA', 'ZM' ] OR 'any'. If 'any' is used, function will check if any of the locals match. Locale list is validator.isPostalCodeLocales.).
  * If given value is not a string, then it returns false.
  */
-export function isPostalCode(value: unknown, locale: validator.PostalCodeLocale): boolean {
-    return typeof value === "string" && validator.isPostalCode(value, locale);
+export function isPostalCode(value: unknown, locale: 'any' | ValidatorJS.PostalCodeLocale): boolean {
+  return typeof value === 'string' && isPostalCodeValidator(value, locale);
 }
 
 /**
@@ -18,19 +19,19 @@ export function isPostalCode(value: unknown, locale: validator.PostalCodeLocale)
  * (locale is one of [ 'AD', 'AT', 'AU', 'BE', 'BG', 'BR', 'CA', 'CH', 'CZ', 'DE', 'DK', 'DZ', 'EE', 'ES', 'FI', 'FR', 'GB', 'GR', 'HR', 'HU', 'ID', 'IE' 'IL', 'IN', 'IR', 'IS', 'IT', 'JP', 'KE', 'LI', 'LT', 'LU', 'LV', 'MT', 'MX', 'NL', 'NO', 'NZ', 'PL', 'PR', 'PT', 'RO', 'RU', 'SA', 'SE', 'SI', 'TN', 'TW', 'UA', 'US', 'ZA', 'ZM' ] OR 'any'. If 'any' is used, function will check if any of the locals match. Locale list is validator.isPostalCodeLocales.).
  * If given value is not a string, then it returns false.
  */
-export function IsPostalCode(locale?: validator.PostalCodeLocale, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_POSTAL_CODE,
-            constraints: [locale],
-            validator: {
-                validate: (value, args): boolean => isPostalCode(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a postal code",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+export function IsPostalCode(
+  locale?: 'any' | ValidatorJS.PostalCodeLocale,
+  validationOptions?: ValidationOptions
+): PropertyDecorator {
+  return ValidateBy(
+    {
+      name: IS_POSTAL_CODE,
+      constraints: [locale],
+      validator: {
+        validate: (value, args): boolean => isPostalCode(value, args.constraints[0]),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be a postal code', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsRFC3339.ts b/src/decorator/string/IsRFC3339.ts
index 51a1bb0c4d..88262b79a5 100644
--- a/src/decorator/string/IsRFC3339.ts
+++ b/src/decorator/string/IsRFC3339.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isRFC3339Validator from 'validator/lib/isRFC3339';
 
-export const IS_RFC_3339 = "isRFC3339";
+export const IS_RFC_3339 = 'isRFC3339';
 
 /**
  * Check if the string is a valid RFC 3339 date.
  * If given value is not a string, then it returns false.
  */
 export function isRFC3339(value: unknown): boolean {
-    return typeof value === "string" && validator.isRFC3339(value);
+  return typeof value === 'string' && isRFC3339Validator(value);
 }
 
 /**
@@ -17,17 +17,14 @@ export function isRFC3339(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsRFC3339(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_RFC_3339,
-            validator: {
-                validate: (value, args): boolean => isRFC3339(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be RFC 3339 date",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_RFC_3339,
+      validator: {
+        validate: (value, args): boolean => isRFC3339(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be RFC 3339 date', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsRgbColor.ts b/src/decorator/string/IsRgbColor.ts
index 1d91898364..e11250d957 100644
--- a/src/decorator/string/IsRgbColor.ts
+++ b/src/decorator/string/IsRgbColor.ts
@@ -1,16 +1,16 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isRgbColorValidator from 'validator/lib/isRgbColor';
 
-export const IS_RGB_COLOR = "isRgbColor";
+export const IS_RGB_COLOR = 'isRgbColor';
 
 /**
-* Check if the string is a rgb or rgba color.
+ * Check if the string is a rgb or rgba color.
  * `includePercentValues` defaults to true. If you don't want to allow to set rgb or rgba values with percents, like rgb(5%,5%,5%), or rgba(90%,90%,90%,.3), then set it to false.
  * If given value is not a string, then it returns false.
  */
 export function isRgbColor(value: unknown, includePercentValues?: boolean): boolean {
-    return typeof value === "string" && validator.isRgbColor(value, includePercentValues);
+  return typeof value === 'string' && isRgbColorValidator(value, includePercentValues);
 }
 
 /**
@@ -19,18 +19,15 @@ export function isRgbColor(value: unknown, includePercentValues?: boolean): bool
  * If given value is not a string, then it returns false.
  */
 export function IsRgbColor(includePercentValues?: boolean, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_RGB_COLOR,
-            constraints: [includePercentValues],
-            validator: {
-                validate: (value, args): boolean => isRgbColor(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be RGB color",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_RGB_COLOR,
+      constraints: [includePercentValues],
+      validator: {
+        validate: (value, args): boolean => isRgbColor(value, args.constraints[0]),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be RGB color', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsSemVer.ts b/src/decorator/string/IsSemVer.ts
index 202026435b..e599655085 100644
--- a/src/decorator/string/IsSemVer.ts
+++ b/src/decorator/string/IsSemVer.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isSemVerValidator from 'validator/lib/isSemVer';
 
-export const IS_SEM_VER = "isSemVer";
+export const IS_SEM_VER = 'isSemVer';
 
 /**
  * Check if the string is a Semantic Versioning Specification (SemVer).
  * If given value is not a string, then it returns false.
  */
 export function isSemVer(value: unknown): boolean {
-    return typeof value === "string" && validator.isSemVer(value);
+  return typeof value === 'string' && isSemVerValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isSemVer(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsSemVer(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_SEM_VER,
-            validator: {
-                validate: (value, args): boolean => isSemVer(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a Semantic Versioning Specification",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_SEM_VER,
+      validator: {
+        validate: (value, args): boolean => isSemVer(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a Semantic Versioning Specification',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsSurrogatePair.ts b/src/decorator/string/IsSurrogatePair.ts
index 72aaccc66a..8cd7e2a8d0 100644
--- a/src/decorator/string/IsSurrogatePair.ts
+++ b/src/decorator/string/IsSurrogatePair.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isSurrogatePairValidator from 'validator/lib/isSurrogatePair';
 
-export const IS_SURROGATE_PAIR = "isSurrogatePair";
+export const IS_SURROGATE_PAIR = 'isSurrogatePair';
 
 /**
  * Checks if the string contains any surrogate pairs chars.
  * If given value is not a string, then it returns false.
  */
 export function isSurrogatePair(value: unknown): boolean {
-    return typeof value === "string" && validator.isSurrogatePair(value);
+  return typeof value === 'string' && isSurrogatePairValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isSurrogatePair(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsSurrogatePair(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_SURROGATE_PAIR,
-            validator: {
-                validate: (value, args): boolean => isSurrogatePair(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must contain any surrogate pairs chars",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_SURROGATE_PAIR,
+      validator: {
+        validate: (value, args): boolean => isSurrogatePair(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must contain any surrogate pairs chars',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsUUID.ts b/src/decorator/string/IsUUID.ts
index 9f140ac74a..bc0b815ad2 100644
--- a/src/decorator/string/IsUUID.ts
+++ b/src/decorator/string/IsUUID.ts
@@ -1,17 +1,17 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isUuidValidator from 'validator/lib/isUUID';
 
-export type UUIDVersion = "3" | "4" | "5" | "all" | 3 | 4 | 5;
+export type UUIDVersion = '3' | '4' | '5' | 'all' | 3 | 4 | 5;
 
-export const IS_UUID = "isUuid";
+export const IS_UUID = 'isUuid';
 
 /**
  * Checks if the string is a UUID (version 3, 4 or 5).
  * If given value is not a string, then it returns false.
  */
 export function isUUID(value: unknown, version?: UUIDVersion): boolean {
-    return typeof value === "string" && validator.isUUID(value, version);
+  return typeof value === 'string' && isUuidValidator(value, version);
 }
 
 /**
@@ -19,18 +19,15 @@ export function isUUID(value: unknown, version?: UUIDVersion): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsUUID(version?: UUIDVersion, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_UUID,
-            constraints: [version],
-            validator: {
-                validate: (value, args): boolean => isUUID(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be an UUID",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_UUID,
+      constraints: [version],
+      validator: {
+        validate: (value, args): boolean => isUUID(value, args.constraints[0]),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be an UUID', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsUppercase.ts b/src/decorator/string/IsUppercase.ts
index fd1504e682..2e22354082 100644
--- a/src/decorator/string/IsUppercase.ts
+++ b/src/decorator/string/IsUppercase.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isUppercaseValidator from 'validator/lib/isUppercase';
 
-export const IS_UPPERCASE = "isUppercase";
+export const IS_UPPERCASE = 'isUppercase';
 
 /**
  * Checks if the string is uppercase.
  * If given value is not a string, then it returns false.
  */
 export function isUppercase(value: unknown): boolean {
-    return typeof value === "string" && validator.isUppercase(value);
+  return typeof value === 'string' && isUppercaseValidator(value);
 }
 
 /**
@@ -17,17 +17,14 @@ export function isUppercase(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsUppercase(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_UPPERCASE,
-            validator: {
-                validate: (value, args): boolean => isUppercase(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be uppercase",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_UPPERCASE,
+      validator: {
+        validate: (value, args): boolean => isUppercase(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be uppercase', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsUrl.ts b/src/decorator/string/IsUrl.ts
index 23ae981aa8..45494bde65 100644
--- a/src/decorator/string/IsUrl.ts
+++ b/src/decorator/string/IsUrl.ts
@@ -1,15 +1,16 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import ValidatorJS from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isUrlValidator from 'validator/lib/isURL';
+import ValidatorJS from 'validator';
 
-export const IS_URL = "isUrl";
+export const IS_URL = 'isUrl';
 
 /**
  * Checks if the string is an url.
  * If given value is not a string, then it returns false.
  */
 export function isURL(value: string, options?: ValidatorJS.IsURLOptions): boolean {
-    return typeof value === "string" && ValidatorJS.isURL(value, options);
+  return typeof value === 'string' && isUrlValidator(value, options);
 }
 
 /**
@@ -17,18 +18,15 @@ export function isURL(value: string, options?: ValidatorJS.IsURLOptions): boolea
  * If given value is not a string, then it returns false.
  */
 export function IsUrl(options?: ValidatorJS.IsURLOptions, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_URL,
-            constraints: [options],
-            validator: {
-                validate: (value, args): boolean => isURL(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be an URL address",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_URL,
+      constraints: [options],
+      validator: {
+        validate: (value, args): boolean => isURL(value, args.constraints[0]),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be an URL address', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/IsVariableWidth.ts b/src/decorator/string/IsVariableWidth.ts
index f601cfba51..0eb4d312d3 100644
--- a/src/decorator/string/IsVariableWidth.ts
+++ b/src/decorator/string/IsVariableWidth.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isVariableWidthValidator from 'validator/lib/isVariableWidth';
 
-export const IS_VARIABLE_WIDTH = "isVariableWidth";
+export const IS_VARIABLE_WIDTH = 'isVariableWidth';
 
 /**
  * Checks if the string contains variable-width chars.
  * If given value is not a string, then it returns false.
  */
 export function isVariableWidth(value: unknown): boolean {
-    return typeof value === "string" && validator.isVariableWidth(value);
+  return typeof value === 'string' && isVariableWidthValidator(value);
 }
 
 /**
@@ -17,17 +17,17 @@ export function isVariableWidth(value: unknown): boolean {
  * If given value is not a string, then it returns false.
  */
 export function IsVariableWidth(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_VARIABLE_WIDTH,
-            validator: {
-                validate: (value, args): boolean => isVariableWidth(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must contain a full-width and half-width characters",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_VARIABLE_WIDTH,
+      validator: {
+        validate: (value, args): boolean => isVariableWidth(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must contain a full-width and half-width characters',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/Length.ts b/src/decorator/string/Length.ts
index ab10bfbb08..e5611e9b8b 100644
--- a/src/decorator/string/Length.ts
+++ b/src/decorator/string/Length.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isLengthValidator from 'validator/lib/isLength';
 
-export const LENGTH = "length";
+export const IS_LENGTH = 'isLength';
 
 /**
  * Checks if the string's length falls in a range. Note: this function takes into account surrogate pairs.
  * If given value is not a string, then it returns false.
  */
 export function length(value: unknown, min: number, max?: number): boolean {
-    return typeof value === "string" && validator.isLength(value, { min, max });
+  return typeof value === 'string' && isLengthValidator(value, { min, max });
 }
 
 /**
@@ -17,27 +17,27 @@ export function length(value: unknown, min: number, max?: number): boolean {
  * If given value is not a string, then it returns false.
  */
 export function Length(min: number, max?: number, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: LENGTH,
-            constraints: [min, max],
-            validator: {
-                validate: (value, args): boolean => length(value, args.constraints[0], args.constraints[1]),
-                defaultMessage: buildMessage(
-                    (eachPrefix, args) => {
-                        const isMinLength = args.constraints[0] !== null && args.constraints[0] !== undefined;
-                        const isMaxLength = args.constraints[1] !== null && args.constraints[1] !== undefined;
-                        if (isMinLength && (!args.value || args.value.length < args.constraints[0])) {
-                            return eachPrefix + "$property must be longer than or equal to $constraint1 characters";
-                        } else if (isMaxLength && (args.value.length > args.constraints[1])) {
-                            return eachPrefix + "$property must be shorter than or equal to $constraint2 characters";
-                        }
-                        return eachPrefix + "$property must be longer than or equal to $constraint1 and shorter than or equal to $constraint2 characters";
-                    },
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_LENGTH,
+      constraints: [min, max],
+      validator: {
+        validate: (value, args): boolean => length(value, args.constraints[0], args.constraints[1]),
+        defaultMessage: buildMessage((eachPrefix, args) => {
+          const isMinLength = args.constraints[0] !== null && args.constraints[0] !== undefined;
+          const isMaxLength = args.constraints[1] !== null && args.constraints[1] !== undefined;
+          if (isMinLength && (!args.value || args.value.length < args.constraints[0])) {
+            return eachPrefix + '$property must be longer than or equal to $constraint1 characters';
+          } else if (isMaxLength && args.value.length > args.constraints[1]) {
+            return eachPrefix + '$property must be shorter than or equal to $constraint2 characters';
+          }
+          return (
+            eachPrefix +
+            '$property must be longer than or equal to $constraint1 and shorter than or equal to $constraint2 characters'
+          );
+        }, validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/Matches.ts b/src/decorator/string/Matches.ts
index 8a075c5706..fb164848f2 100644
--- a/src/decorator/string/Matches.ts
+++ b/src/decorator/string/Matches.ts
@@ -1,8 +1,8 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import matchesValidator from 'validator/lib/matches';
 
-export const MATCHES = "matches";
+export const MATCHES = 'matches';
 
 /**
  * Checks if string matches the pattern. Either matches('foo', /foo/i).
@@ -11,7 +11,7 @@ export const MATCHES = "matches";
 export function matches(value: string, pattern: RegExp): boolean;
 export function matches(value: string, pattern: string, modifiers: string): boolean;
 export function matches(value: string, pattern: RegExp | string, modifiers?: string): boolean {
-    return typeof value === "string" && validator.matches(value, pattern as unknown as any, modifiers);
+  return typeof value === 'string' && matchesValidator(value, (pattern as unknown) as any, modifiers);
 }
 
 /**
@@ -20,26 +20,30 @@ export function matches(value: string, pattern: RegExp | string, modifiers?: str
  */
 export function Matches(pattern: RegExp, validationOptions?: ValidationOptions): PropertyDecorator;
 export function Matches(pattern: string, modifiers?: string, validationOptions?: ValidationOptions): PropertyDecorator;
-export function Matches(pattern: RegExp | string, modifiersOrAnnotationOptions?: string | ValidationOptions, validationOptions?: ValidationOptions): PropertyDecorator {
-    let modifiers: string;
-    if (modifiersOrAnnotationOptions && modifiersOrAnnotationOptions instanceof Object && !validationOptions) {
-        validationOptions = modifiersOrAnnotationOptions;
-    } else {
-        modifiers = modifiersOrAnnotationOptions as string;
-    }
+export function Matches(
+  pattern: RegExp | string,
+  modifiersOrAnnotationOptions?: string | ValidationOptions,
+  validationOptions?: ValidationOptions
+): PropertyDecorator {
+  let modifiers: string;
+  if (modifiersOrAnnotationOptions && modifiersOrAnnotationOptions instanceof Object && !validationOptions) {
+    validationOptions = modifiersOrAnnotationOptions;
+  } else {
+    modifiers = modifiersOrAnnotationOptions as string;
+  }
 
-    return ValidateBy(
-        {
-            name: MATCHES,
-            constraints: [pattern, modifiers],
-            validator: {
-                validate: (value, args): boolean => matches(value, args.constraints[0], args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix, args) => eachPrefix + "$property must match $constraint1 regular expression",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: MATCHES,
+      constraints: [pattern, modifiers],
+      validator: {
+        validate: (value, args): boolean => matches(value, args.constraints[0], args.constraints[1]),
+        defaultMessage: buildMessage(
+          (eachPrefix, args) => eachPrefix + '$property must match $constraint1 regular expression',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/MaxLength.ts b/src/decorator/string/MaxLength.ts
index 2f024870bc..59852e5e97 100644
--- a/src/decorator/string/MaxLength.ts
+++ b/src/decorator/string/MaxLength.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isLengthValidator from 'validator/lib/isLength';
 
-export const MAX_LENGTH = "maxLength";
+export const MAX_LENGTH = 'maxLength';
 
 /**
  * Checks if the string's length is not more than given number. Note: this function takes into account surrogate pairs.
  * If given value is not a string, then it returns false.
  */
 export function maxLength(value: unknown, max: number): boolean {
-    return typeof value === "string" && validator.isLength(value, { min: 0, max });
+  return typeof value === 'string' && isLengthValidator(value, { min: 0, max });
 }
 
 /**
@@ -17,18 +17,18 @@ export function maxLength(value: unknown, max: number): boolean {
  * If given value is not a string, then it returns false.
  */
 export function MaxLength(max: number, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: MAX_LENGTH,
-            constraints: [max],
-            validator: {
-                validate: (value, args): boolean => maxLength(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be shorter than or equal to $constraint1 characters",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: MAX_LENGTH,
+      constraints: [max],
+      validator: {
+        validate: (value, args): boolean => maxLength(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be shorter than or equal to $constraint1 characters',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/MinLength.ts b/src/decorator/string/MinLength.ts
index 2238fe81e2..d3e5fca5c8 100644
--- a/src/decorator/string/MinLength.ts
+++ b/src/decorator/string/MinLength.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import isLengthValidator from 'validator/lib/isLength';
 
-export const MIN_LENGTH = "minLength";
+export const MIN_LENGTH = 'minLength';
 
 /**
  * Checks if the string's length is not less than given number. Note: this function takes into account surrogate pairs.
  * If given value is not a string, then it returns false.
  */
 export function minLength(value: unknown, min: number): boolean {
-    return typeof value === "string" && validator.isLength(value, { min });
+  return typeof value === 'string' && isLengthValidator(value, { min });
 }
 
 /**
@@ -17,18 +17,18 @@ export function minLength(value: unknown, min: number): boolean {
  * If given value is not a string, then it returns false.
  */
 export function MinLength(min: number, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: MIN_LENGTH,
-            constraints: [min],
-            validator: {
-                validate: (value, args): boolean => minLength(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be longer than or equal to $constraint1 characters",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: MIN_LENGTH,
+      constraints: [min],
+      validator: {
+        validate: (value, args): boolean => minLength(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be longer than or equal to $constraint1 characters',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/string/NotContains.ts b/src/decorator/string/NotContains.ts
index e8ca277916..5f784e6bc3 100644
--- a/src/decorator/string/NotContains.ts
+++ b/src/decorator/string/NotContains.ts
@@ -1,15 +1,15 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
-import validator from "validator";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
+import containsValidator from 'validator/lib/contains';
 
-export const NOT_CONTAINS = "notContains";
+export const NOT_CONTAINS = 'notContains';
 
 /**
  * Checks if the string does not contain the seed.
  * If given value is not a string, then it returns false.
  */
 export function notContains(value: unknown, seed: string): boolean {
-    return typeof value === "string" && !validator.contains(value, seed);
+  return typeof value === 'string' && !containsValidator(value, seed);
 }
 
 /**
@@ -17,18 +17,18 @@ export function notContains(value: unknown, seed: string): boolean {
  * If given value is not a string, then it returns false.
  */
 export function NotContains(seed: string, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: NOT_CONTAINS,
-            constraints: [seed],
-            validator: {
-                validate: (value, args): boolean => notContains(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property should not contain a $constraint1 string",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: NOT_CONTAINS,
+      constraints: [seed],
+      validator: {
+        validate: (value, args): boolean => notContains(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property should not contain a $constraint1 string',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/typechecker/IsArray.ts b/src/decorator/typechecker/IsArray.ts
index 89d26f4727..ba0e8b704c 100644
--- a/src/decorator/typechecker/IsArray.ts
+++ b/src/decorator/typechecker/IsArray.ts
@@ -1,30 +1,27 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const IS_ARRAY = "isArray";
+export const IS_ARRAY = 'isArray';
 
 /**
  * Checks if a given value is an array
  */
 export function isArray(value: unknown): boolean {
-    return value instanceof Array;
+  return value instanceof Array;
 }
 
 /**
  * Checks if a given value is an array
  */
 export function IsArray(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_ARRAY,
-            validator: {
-                validate: (value, args): boolean => isArray(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be an array",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_ARRAY,
+      validator: {
+        validate: (value, args): boolean => isArray(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be an array', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/typechecker/IsBoolean.ts b/src/decorator/typechecker/IsBoolean.ts
index 12818ac029..12af6aec91 100644
--- a/src/decorator/typechecker/IsBoolean.ts
+++ b/src/decorator/typechecker/IsBoolean.ts
@@ -1,30 +1,27 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const IS_BOOLEAN = "isBoolean";
+export const IS_BOOLEAN = 'isBoolean';
 
 /**
  * Checks if a given value is a boolean.
  */
 export function isBoolean(value: unknown): boolean {
-    return value instanceof Boolean || typeof value === "boolean";
+  return value instanceof Boolean || typeof value === 'boolean';
 }
 
 /**
  * Checks if a value is a boolean.
  */
 export function IsBoolean(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_BOOLEAN,
-            validator: {
-                validate: (value, args): boolean => isBoolean(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a boolean value",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_BOOLEAN,
+      validator: {
+        validate: (value, args): boolean => isBoolean(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be a boolean value', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/typechecker/IsDate.ts b/src/decorator/typechecker/IsDate.ts
index 1f5bd7170a..4bf19e772e 100644
--- a/src/decorator/typechecker/IsDate.ts
+++ b/src/decorator/typechecker/IsDate.ts
@@ -1,30 +1,27 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const IS_DATE = "isDate";
+export const IS_DATE = 'isDate';
 
 /**
  * Checks if a given value is a date.
  */
 export function isDate(value: unknown): boolean {
-    return value instanceof Date && !isNaN(value.getTime());
+  return value instanceof Date && !isNaN(value.getTime());
 }
 
 /**
  * Checks if a value is a date.
  */
 export function IsDate(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_DATE,
-            validator: {
-                validate: (value, args): boolean => isDate(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a Date instance",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_DATE,
+      validator: {
+        validate: (value, args): boolean => isDate(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be a Date instance', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/typechecker/IsEnum.ts b/src/decorator/typechecker/IsEnum.ts
index bb6071229c..a3ffc711f9 100644
--- a/src/decorator/typechecker/IsEnum.ts
+++ b/src/decorator/typechecker/IsEnum.ts
@@ -1,33 +1,32 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const IS_ENUM = "isEnum";
+export const IS_ENUM = 'isEnum';
 
 /**
  * Checks if a given value is an enum
  */
 export function isEnum(value: unknown, entity: any): boolean {
-    const enumValues = Object.keys(entity)
-        .map(k => entity[k]);
-    return enumValues.indexOf(value) >= 0;
+  const enumValues = Object.keys(entity).map(k => entity[k]);
+  return enumValues.indexOf(value) >= 0;
 }
 
 /**
  * Checks if a given value is an enum
  */
 export function IsEnum(entity: object, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_ENUM,
-            constraints: [entity],
-            validator: {
-                validate: (value, args): boolean => isEnum(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a valid enum value",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_ENUM,
+      constraints: [entity],
+      validator: {
+        validate: (value, args): boolean => isEnum(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a valid enum value',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/typechecker/IsInt.ts b/src/decorator/typechecker/IsInt.ts
index e563f43e93..36b96abae8 100644
--- a/src/decorator/typechecker/IsInt.ts
+++ b/src/decorator/typechecker/IsInt.ts
@@ -1,30 +1,30 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const IS_INT = "isInt";
+export const IS_INT = 'isInt';
 
 /**
  * Checks if value is an integer.
  */
 export function isInt(val: unknown): boolean {
-    return typeof val === "number" && Number.isInteger(val);
+  return typeof val === 'number' && Number.isInteger(val);
 }
 
 /**
  * Checks if value is an integer.
  */
 export function IsInt(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_INT,
-            validator: {
-                validate: (value, args): boolean => isInt(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be an integer number",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_INT,
+      validator: {
+        validate: (value, args): boolean => isInt(value),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be an integer number',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/typechecker/IsNumber.ts b/src/decorator/typechecker/IsNumber.ts
index 495e90e52b..84febe1beb 100644
--- a/src/decorator/typechecker/IsNumber.ts
+++ b/src/decorator/typechecker/IsNumber.ts
@@ -1,62 +1,62 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const IS_NUMBER = "isNumber";
+export const IS_NUMBER = 'isNumber';
 
 /**
  * Options to be passed to IsNumber decorator.
  */
 export interface IsNumberOptions {
-    allowNaN?: boolean;
-    allowInfinity?: boolean;
-    maxDecimalPlaces?: number;
+  allowNaN?: boolean;
+  allowInfinity?: boolean;
+  maxDecimalPlaces?: number;
 }
 
 /**
  * Checks if a given value is a number.
  */
 export function isNumber(value: unknown, options: IsNumberOptions = {}): boolean {
-    if (typeof value !== "number") {
-        return false;
+  if (typeof value !== 'number') {
+    return false;
+  }
+
+  if (value === Infinity || value === -Infinity) {
+    return options.allowInfinity;
+  }
+
+  if (Number.isNaN(value)) {
+    return options.allowNaN;
+  }
+
+  if (options.maxDecimalPlaces !== undefined) {
+    let decimalPlaces = 0;
+    if (value % 1 !== 0) {
+      decimalPlaces = value.toString().split('.')[1].length;
     }
-
-    if (value === Infinity || value === -Infinity) {
-        return options.allowInfinity;
-    }
-
-    if (Number.isNaN(value)) {
-        return options.allowNaN;
-    }
-
-    if (options.maxDecimalPlaces !== undefined) {
-        let decimalPlaces = 0;
-        if ((value % 1) !== 0) {
-            decimalPlaces = value.toString().split(".")[1].length;
-        }
-        if (decimalPlaces > options.maxDecimalPlaces) {
-            return false;
-        }
+    if (decimalPlaces > options.maxDecimalPlaces) {
+      return false;
     }
+  }
 
-    return Number.isFinite(value);
+  return Number.isFinite(value);
 }
 
 /**
  * Checks if a value is a number.
  */
 export function IsNumber(options: IsNumberOptions = {}, validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_NUMBER,
-            constraints: [options],
-            validator: {
-                validate: (value, args): boolean => isNumber(value, args.constraints[0]),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a number conforming to the specified constraints",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_NUMBER,
+      constraints: [options],
+      validator: {
+        validate: (value, args): boolean => isNumber(value, args.constraints[0]),
+        defaultMessage: buildMessage(
+          eachPrefix => eachPrefix + '$property must be a number conforming to the specified constraints',
+          validationOptions
+        ),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/typechecker/IsObject.ts b/src/decorator/typechecker/IsObject.ts
index 01601c4feb..ac431dd32e 100644
--- a/src/decorator/typechecker/IsObject.ts
+++ b/src/decorator/typechecker/IsObject.ts
@@ -1,14 +1,14 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const IS_OBJECT = "isObject";
+export const IS_OBJECT = 'isObject';
 
 /**
  * Checks if the value is valid Object.
  * Returns false if the value is not an object.
  */
 export function isObject(value: unknown): value is object {
-    return value != null && (typeof value === "object" || typeof value === "function") && !Array.isArray(value);
+  return value != null && (typeof value === 'object' || typeof value === 'function') && !Array.isArray(value);
 }
 
 /**
@@ -16,17 +16,14 @@ export function isObject(value: unknown): value is object {
  * Returns false if the value is not an object.
  */
 export function IsObject(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_OBJECT,
-            validator: {
-                validate: (value, args): boolean => isObject(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be an object",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_OBJECT,
+      validator: {
+        validate: (value, args): boolean => isObject(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be an object', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/decorator/typechecker/IsString.ts b/src/decorator/typechecker/IsString.ts
index ae54b267e9..4c309cd622 100644
--- a/src/decorator/typechecker/IsString.ts
+++ b/src/decorator/typechecker/IsString.ts
@@ -1,30 +1,27 @@
-import { ValidationOptions } from "../ValidationOptions";
-import { buildMessage, ValidateBy } from "../common/ValidateBy";
+import { ValidationOptions } from '../ValidationOptions';
+import { buildMessage, ValidateBy } from '../common/ValidateBy';
 
-export const IS_STRING = "isString";
+export const IS_STRING = 'isString';
 
 /**
-* Checks if a given value is a real string.
-*/
+ * Checks if a given value is a real string.
+ */
 export function isString(value: unknown): value is string {
-   return value instanceof String || typeof value === "string";
+  return value instanceof String || typeof value === 'string';
 }
 
 /**
-* Checks if a given value is a real string.
-*/
+ * Checks if a given value is a real string.
+ */
 export function IsString(validationOptions?: ValidationOptions): PropertyDecorator {
-    return ValidateBy(
-        {
-            name: IS_STRING,
-            validator: {
-                validate: (value, args): boolean => isString(value),
-                defaultMessage: buildMessage(
-                    (eachPrefix) => eachPrefix + "$property must be a string",
-                    validationOptions
-                )
-            }
-        },
-        validationOptions
-    );
+  return ValidateBy(
+    {
+      name: IS_STRING,
+      validator: {
+        validate: (value, args): boolean => isString(value),
+        defaultMessage: buildMessage(eachPrefix => eachPrefix + '$property must be a string', validationOptions),
+      },
+    },
+    validationOptions
+  );
 }
diff --git a/src/index.ts b/src/index.ts
index 49523b7bd1..34aa0f38b5 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,26 +1,26 @@
-import {ValidationError} from "./validation/ValidationError";
-import {ValidatorOptions} from "./validation/ValidatorOptions";
-import {ValidationSchema} from "./validation-schema/ValidationSchema";
-import {getMetadataStorage} from "./metadata/MetadataStorage";
-import {Validator} from "./validation/Validator";
-import {getFromContainer} from "./container";
+import { ValidationError } from './validation/ValidationError';
+import { ValidatorOptions } from './validation/ValidatorOptions';
+import { ValidationSchema } from './validation-schema/ValidationSchema';
+import { getMetadataStorage } from './metadata/MetadataStorage';
+import { Validator } from './validation/Validator';
+import { getFromContainer } from './container';
 
 // -------------------------------------------------------------------------
 // Export everything api users needs
 // -------------------------------------------------------------------------
 
-export * from "./container";
-export * from "./decorator/decorators";
-export * from "./decorator/ValidationOptions";
-export * from "./validation/ValidatorConstraintInterface";
-export * from "./validation/ValidationError";
-export * from "./validation/ValidatorOptions";
-export * from "./validation/ValidationArguments";
-export * from "./validation/ValidationTypes";
-export * from "./validation/Validator";
-export * from "./validation-schema/ValidationSchema";
-export * from "./register-decorator";
-export * from "./metadata/MetadataStorage";
+export * from './container';
+export * from './decorator/decorators';
+export * from './decorator/ValidationOptions';
+export * from './validation/ValidatorConstraintInterface';
+export * from './validation/ValidationError';
+export * from './validation/ValidatorOptions';
+export * from './validation/ValidationArguments';
+export * from './validation/ValidationTypes';
+export * from './validation/Validator';
+export * from './validation-schema/ValidationSchema';
+export * from './register-decorator';
+export * from './metadata/MetadataStorage';
 
 // -------------------------------------------------------------------------
 // Shortcut methods for api users
@@ -34,19 +34,29 @@ export function validate(object: object, validatorOptions?: ValidatorOptions): P
 /**
  * Validates given object by a given validation schema.
  */
-export function validate(schemaName: string, object: object, validatorOptions?: ValidatorOptions): Promise<ValidationError[]>;
+export function validate(
+  schemaName: string,
+  object: object,
+  validatorOptions?: ValidatorOptions
+): Promise<ValidationError[]>;
 
 /**
  * Validates given object by object's decorators or given validation schema.
  */
-export function validate(schemaNameOrObject: object|string,
-                         objectOrValidationOptions?: object|ValidatorOptions,
-                         maybeValidatorOptions?: ValidatorOptions): Promise<ValidationError[]> {
-    if (typeof schemaNameOrObject === "string") {
-        return getFromContainer(Validator).validate(schemaNameOrObject, objectOrValidationOptions as object, maybeValidatorOptions);
-    } else {
-        return getFromContainer(Validator).validate(schemaNameOrObject, objectOrValidationOptions as ValidatorOptions);
-    }
+export function validate(
+  schemaNameOrObject: object | string,
+  objectOrValidationOptions?: object | ValidatorOptions,
+  maybeValidatorOptions?: ValidatorOptions
+): Promise<ValidationError[]> {
+  if (typeof schemaNameOrObject === 'string') {
+    return getFromContainer(Validator).validate(
+      schemaNameOrObject,
+      objectOrValidationOptions as object,
+      maybeValidatorOptions
+    );
+  } else {
+    return getFromContainer(Validator).validate(schemaNameOrObject, objectOrValidationOptions as ValidatorOptions);
+  }
 }
 
 /**
@@ -57,19 +67,32 @@ export function validateOrReject(object: object, validatorOptions?: ValidatorOpt
 /**
  * Validates given object by a given validation schema and reject on error.
  */
-export function validateOrReject(schemaName: string, object: object, validatorOptions?: ValidatorOptions): Promise<void>;
+export function validateOrReject(
+  schemaName: string,
+  object: object,
+  validatorOptions?: ValidatorOptions
+): Promise<void>;
 
 /**
  * Validates given object by object's decorators or given validation schema and reject on error.
  */
-export function validateOrReject(schemaNameOrObject: object|string,
-                         objectOrValidationOptions?: object|ValidatorOptions,
-                         maybeValidatorOptions?: ValidatorOptions): Promise<void> {
-    if (typeof schemaNameOrObject === "string") {
-        return getFromContainer(Validator).validateOrReject(schemaNameOrObject, objectOrValidationOptions as object, maybeValidatorOptions);
-    } else {
-        return getFromContainer(Validator).validateOrReject(schemaNameOrObject, objectOrValidationOptions as ValidatorOptions);
-    }
+export function validateOrReject(
+  schemaNameOrObject: object | string,
+  objectOrValidationOptions?: object | ValidatorOptions,
+  maybeValidatorOptions?: ValidatorOptions
+): Promise<void> {
+  if (typeof schemaNameOrObject === 'string') {
+    return getFromContainer(Validator).validateOrReject(
+      schemaNameOrObject,
+      objectOrValidationOptions as object,
+      maybeValidatorOptions
+    );
+  } else {
+    return getFromContainer(Validator).validateOrReject(
+      schemaNameOrObject,
+      objectOrValidationOptions as ValidatorOptions
+    );
+  }
 }
 
 /**
@@ -84,26 +107,36 @@ export function validateSync(object: object, validatorOptions?: ValidatorOptions
  * Note that this method completely ignores async validations.
  * If you want to properly perform validation you need to call validate method instead.
  */
-export function validateSync(schemaName: string, object: object, validatorOptions?: ValidatorOptions): ValidationError[];
+export function validateSync(
+  schemaName: string,
+  object: object,
+  validatorOptions?: ValidatorOptions
+): ValidationError[];
 
 /**
  * Validates given object by object's decorators or given validation schema.
  * Note that this method completely ignores async validations.
  * If you want to properly perform validation you need to call validate method instead.
  */
-export function validateSync(schemaNameOrObject: object|string,
-                             objectOrValidationOptions?: object|ValidatorOptions,
-                             maybeValidatorOptions?: ValidatorOptions): ValidationError[] {
-    if (typeof schemaNameOrObject === "string") {
-        return getFromContainer(Validator).validateSync(schemaNameOrObject, objectOrValidationOptions as object, maybeValidatorOptions);
-    } else {
-        return getFromContainer(Validator).validateSync(schemaNameOrObject, objectOrValidationOptions as ValidatorOptions);
-    }
+export function validateSync(
+  schemaNameOrObject: object | string,
+  objectOrValidationOptions?: object | ValidatorOptions,
+  maybeValidatorOptions?: ValidatorOptions
+): ValidationError[] {
+  if (typeof schemaNameOrObject === 'string') {
+    return getFromContainer(Validator).validateSync(
+      schemaNameOrObject,
+      objectOrValidationOptions as object,
+      maybeValidatorOptions
+    );
+  } else {
+    return getFromContainer(Validator).validateSync(schemaNameOrObject, objectOrValidationOptions as ValidatorOptions);
+  }
 }
 
 /**
  * Registers a new validation schema.
  */
 export function registerSchema(schema: ValidationSchema): void {
-    getMetadataStorage().addValidationSchema(schema);
+  getMetadataStorage().addValidationSchema(schema);
 }
diff --git a/src/metadata/ConstraintMetadata.ts b/src/metadata/ConstraintMetadata.ts
index 0045024fb1..61ffcecc13 100644
--- a/src/metadata/ConstraintMetadata.ts
+++ b/src/metadata/ConstraintMetadata.ts
@@ -1,49 +1,47 @@
-import {ValidatorConstraintInterface} from "../validation/ValidatorConstraintInterface";
-import {getFromContainer} from "../container";
+import { ValidatorConstraintInterface } from '../validation/ValidatorConstraintInterface';
+import { getFromContainer } from '../container';
 
 /**
  * This metadata interface contains information for custom validators.
  */
 export class ConstraintMetadata {
-
-    // -------------------------------------------------------------------------
-    // Properties
-    // -------------------------------------------------------------------------
-
-    /**
-     * Target class which performs validation.
-     */
-    target: Function;
-
-    /**
-     * Custom validation's name, that will be used as validation error type.
-     */
-    name: string;
-
-    /**
-     * Indicates if this validation is asynchronous or not.
-     */
-    async: boolean;
-
-    // -------------------------------------------------------------------------
-    // Constructor
-    // -------------------------------------------------------------------------
-
-    constructor(target: Function, name?: string, async: boolean = false) {
-        this.target = target;
-        this.name = name;
-        this.async = async;
-    }
-
-    // -------------------------------------------------------------------------
-    // Accessors
-    // -------------------------------------------------------------------------
-
-    /**
-     * Instance of the target custom validation class which performs validation.
-     */
-    get instance(): ValidatorConstraintInterface {
-        return getFromContainer<ValidatorConstraintInterface>(this.target);
-    }
-
+  // -------------------------------------------------------------------------
+  // Properties
+  // -------------------------------------------------------------------------
+
+  /**
+   * Target class which performs validation.
+   */
+  target: Function;
+
+  /**
+   * Custom validation's name, that will be used as validation error type.
+   */
+  name: string;
+
+  /**
+   * Indicates if this validation is asynchronous or not.
+   */
+  async: boolean;
+
+  // -------------------------------------------------------------------------
+  // Constructor
+  // -------------------------------------------------------------------------
+
+  constructor(target: Function, name?: string, async: boolean = false) {
+    this.target = target;
+    this.name = name;
+    this.async = async;
+  }
+
+  // -------------------------------------------------------------------------
+  // Accessors
+  // -------------------------------------------------------------------------
+
+  /**
+   * Instance of the target custom validation class which performs validation.
+   */
+  get instance(): ValidatorConstraintInterface {
+    return getFromContainer<ValidatorConstraintInterface>(this.target);
+  }
 }
diff --git a/src/metadata/MetadataStorage.ts b/src/metadata/MetadataStorage.ts
index c4593964b7..6a038af896 100644
--- a/src/metadata/MetadataStorage.ts
+++ b/src/metadata/MetadataStorage.ts
@@ -1,116 +1,140 @@
-import {ValidationMetadata} from "./ValidationMetadata";
-import {ConstraintMetadata} from "./ConstraintMetadata";
-import {ValidationSchema} from "../validation-schema/ValidationSchema";
-import {ValidationSchemaToMetadataTransformer} from "../validation-schema/ValidationSchemaToMetadataTransformer";
+import { ValidationMetadata } from './ValidationMetadata';
+import { ConstraintMetadata } from './ConstraintMetadata';
+import { ValidationSchema } from '../validation-schema/ValidationSchema';
+import { ValidationSchemaToMetadataTransformer } from '../validation-schema/ValidationSchemaToMetadataTransformer';
+import { getGlobal } from '../utils';
 
 /**
  * Storage all metadatas.
  */
 export class MetadataStorage {
-
-    // -------------------------------------------------------------------------
-    // Private properties
-    // -------------------------------------------------------------------------
-
-    private validationMetadatas: ValidationMetadata[] = [];
-    private constraintMetadatas: ConstraintMetadata[] = [];
-
-    get hasValidationMetaData(): boolean {
-        return !!this.validationMetadatas.length;
-    }
-
-    // -------------------------------------------------------------------------
-    // Public Methods
-    // -------------------------------------------------------------------------
-
-    /**
-     * Adds a new validation metadata.
-     */
-    addValidationSchema(schema: ValidationSchema): void {
-        const validationMetadatas = new ValidationSchemaToMetadataTransformer().transform(schema);
-        validationMetadatas.forEach(validationMetadata => this.addValidationMetadata(validationMetadata));
-    }
-
-    /**
-     * Adds a new validation metadata.
-     */
-    addValidationMetadata(metadata: ValidationMetadata): void {
-        this.validationMetadatas.push(metadata);
-    }
-
-    /**
-     * Adds a new constraint metadata.
-     */
-    addConstraintMetadata(metadata: ConstraintMetadata): void {
-        this.constraintMetadatas.push(metadata);
-    }
-
-    /**
-     * Groups metadata by their property names.
-     */
-    groupByPropertyName(metadata: ValidationMetadata[]): { [propertyName: string]: ValidationMetadata[] } {
-        const grouped: { [propertyName: string]: ValidationMetadata[] } = {};
-        metadata.forEach(metadata => {
-            if (!grouped[metadata.propertyName])
-                grouped[metadata.propertyName] = [];
-            grouped[metadata.propertyName].push(metadata);
-        });
-        return grouped;
-    }
-
-    /**
-     * Gets all validation metadatas for the given object with the given groups.
-     */
-    getTargetValidationMetadatas(targetConstructor: Function, targetSchema: string, groups?: string[]): ValidationMetadata[] {
-
-        // get directly related to a target metadatas
-        const originalMetadatas = this.validationMetadatas.filter(metadata => {
-            if (metadata.target !== targetConstructor && metadata.target !== targetSchema)
-                return false;
-            if (metadata.always)
-                return true;
-            if (groups && groups.length > 0)
-                return metadata.groups && !!metadata.groups.find(group => groups.indexOf(group) !== -1);
-
-            return true;
-        });
-
-        // get metadatas for inherited classes
-        const inheritedMetadatas = this.validationMetadatas.filter(metadata => {
-            // if target is a string it's means we validate against a schema, and there is no inheritance support for schemas
-            if (typeof metadata.target === "string")
-                return false;
-            if (metadata.target === targetConstructor)
-                return false;
-            if (metadata.target instanceof Function &&
-                !(targetConstructor.prototype instanceof (metadata.target)))
-                return false;
-            if (metadata.always)
-                return true;
-            if (groups && groups.length > 0)
-                return metadata.groups && !!metadata.groups.find(group => groups.indexOf(group) !== -1);
-
-            return true;
-        });
-
-        // filter out duplicate metadatas, prefer original metadatas instead of inherited metadatas
-        const uniqueInheritedMetadatas = inheritedMetadatas.filter(inheritedMetadata => {
-            return !originalMetadatas.find(originalMetadata => {
-                return  originalMetadata.propertyName === inheritedMetadata.propertyName &&
-                        originalMetadata.type === inheritedMetadata.type;
-            });
-        });
-
-        return originalMetadatas.concat(uniqueInheritedMetadatas);
-    }
-
-    /**
-     * Gets all validator constraints for the given object.
-     */
-    getTargetValidatorConstraints(target: Function): ConstraintMetadata[] {
-        return this.constraintMetadatas.filter(metadata => metadata.target === target);
-    }
-
+  // -------------------------------------------------------------------------
+  // Private properties
+  // -------------------------------------------------------------------------
+
+  private validationMetadatas: ValidationMetadata[] = [];
+  private constraintMetadatas: ConstraintMetadata[] = [];
+
+  get hasValidationMetaData(): boolean {
+    return !!this.validationMetadatas.length;
+  }
+
+  // -------------------------------------------------------------------------
+  // Public Methods
+  // -------------------------------------------------------------------------
+
+  /**
+   * Adds a new validation metadata.
+   */
+  addValidationSchema(schema: ValidationSchema): void {
+    const validationMetadatas = new ValidationSchemaToMetadataTransformer().transform(schema);
+    validationMetadatas.forEach(validationMetadata => this.addValidationMetadata(validationMetadata));
+  }
+
+  /**
+   * Adds a new validation metadata.
+   */
+  addValidationMetadata(metadata: ValidationMetadata): void {
+    this.validationMetadatas.push(metadata);
+  }
+
+  /**
+   * Adds a new constraint metadata.
+   */
+  addConstraintMetadata(metadata: ConstraintMetadata): void {
+    this.constraintMetadatas.push(metadata);
+  }
+
+  /**
+   * Groups metadata by their property names.
+   */
+  groupByPropertyName(metadata: ValidationMetadata[]): { [propertyName: string]: ValidationMetadata[] } {
+    const grouped: { [propertyName: string]: ValidationMetadata[] } = {};
+    metadata.forEach(metadata => {
+      if (!grouped[metadata.propertyName]) grouped[metadata.propertyName] = [];
+      grouped[metadata.propertyName].push(metadata);
+    });
+    return grouped;
+  }
+
+  /**
+   * Gets all validation metadatas for the given object with the given groups.
+   */
+  getTargetValidationMetadatas(
+    targetConstructor: Function,
+    targetSchema: string,
+    always: boolean,
+    strictGroups: boolean,
+    groups?: string[]
+  ): ValidationMetadata[] {
+    const includeMetadataBecauseOfAlwaysOption = (metadata: ValidationMetadata): boolean => {
+      // `metadata.always` overrides global default.
+      if (typeof metadata.always !== 'undefined') return metadata.always;
+
+      // `metadata.groups` overrides global default.
+      if (metadata.groups && metadata.groups.length) return false;
+
+      // Use global default.
+      return always;
+    };
+
+    const excludeMetadataBecauseOfStrictGroupsOption = (metadata: ValidationMetadata): boolean => {
+      if (strictGroups) {
+        // Validation is not using groups.
+        if (!groups || !groups.length) {
+          // `metadata.groups` has at least one group.
+          if (metadata.groups && metadata.groups.length) return true;
+        }
+      }
+
+      return false;
+    };
+
+    // get directly related to a target metadatas
+    const originalMetadatas = this.validationMetadatas.filter(metadata => {
+      if (metadata.target !== targetConstructor && metadata.target !== targetSchema) return false;
+      if (includeMetadataBecauseOfAlwaysOption(metadata)) return true;
+      if (excludeMetadataBecauseOfStrictGroupsOption(metadata)) return false;
+      if (groups && groups.length > 0)
+        return metadata.groups && !!metadata.groups.find(group => groups.indexOf(group) !== -1);
+
+      return true;
+    });
+
+    // get metadatas for inherited classes
+    const inheritedMetadatas = this.validationMetadatas.filter(metadata => {
+      // if target is a string it's means we validate against a schema, and there is no inheritance support for schemas
+      if (typeof metadata.target === 'string') return false;
+      if (metadata.target === targetConstructor) return false;
+      if (metadata.target instanceof Function && !(targetConstructor.prototype instanceof metadata.target))
+        return false;
+      if (includeMetadataBecauseOfAlwaysOption(metadata)) return true;
+      if (excludeMetadataBecauseOfStrictGroupsOption(metadata)) return false;
+      if (groups && groups.length > 0)
+        return metadata.groups && !!metadata.groups.find(group => groups.indexOf(group) !== -1);
+
+      return true;
+    });
+
+    // filter out duplicate metadatas, prefer original metadatas instead of inherited metadatas
+    const uniqueInheritedMetadatas = inheritedMetadatas.filter(inheritedMetadata => {
+      return !originalMetadatas.find(originalMetadata => {
+        return (
+          originalMetadata.propertyName === inheritedMetadata.propertyName &&
+          originalMetadata.type === inheritedMetadata.type
+        );
+      });
+    });
+
+    return originalMetadatas.concat(uniqueInheritedMetadatas);
+  }
+
+  /**
+   * Gets all validator constraints for the given object.
+   */
+  getTargetValidatorConstraints(target: Function): ConstraintMetadata[] {
+    return this.constraintMetadatas.filter(metadata => metadata.target === target);
+  }
 }
 
 /**
@@ -118,11 +142,11 @@ export class MetadataStorage {
  * Metadata storage follows the best practices and stores metadata in a global variable.
  */
 export function getMetadataStorage(): MetadataStorage {
-    if (typeof window !== "undefined") {
-        (window).global = window;
-    }
-    if (!(global as any).classValidatorMetadataStorage)
-        (global as any).classValidatorMetadataStorage = new MetadataStorage();
+  const global = getGlobal();
+
+  if (!global.classValidatorMetadataStorage) {
+    global.classValidatorMetadataStorage = new MetadataStorage();
+  }
 
-    return (global as any).classValidatorMetadataStorage;
+  return global.classValidatorMetadataStorage;
 }
diff --git a/src/metadata/ValidationMetadata.ts b/src/metadata/ValidationMetadata.ts
index 70e433c9b9..c174fbc74d 100644
--- a/src/metadata/ValidationMetadata.ts
+++ b/src/metadata/ValidationMetadata.ts
@@ -1,88 +1,86 @@
-import {ValidationMetadataArgs} from "./ValidationMetadataArgs";
-import {ValidationArguments} from "../validation/ValidationArguments";
+import { ValidationMetadataArgs } from './ValidationMetadataArgs';
+import { ValidationArguments } from '../validation/ValidationArguments';
 
 /**
  * This metadata contains validation rules.
  */
 export class ValidationMetadata {
-
-    // -------------------------------------------------------------------------
-    // Properties
-    // -------------------------------------------------------------------------
-
-    /**
-     * Validation type.
-     */
-    type: string;
-
-    /**
-     * Target class to which this validation is applied.
-     */
-    target: Function|string;
-
-    /**
-     * Property of the object to be validated.
-     */
-    propertyName: string;
-
-    /**
-     * Constraint class that performs validation. Used only for custom validations.
-     */
-    constraintCls: Function;
-
-    /**
-     * Array of constraints of this validation.
-     */
-    constraints: any[];
-
-    /**
-     * Validation message to be shown in the case of error.
-     */
-    message: string|((args: ValidationArguments) => string);
-
-    /**
-     * Validation groups used for this validation.
-     */
-    groups: string[] = [];
-
-    /**
-     * Indicates if validation must be performed always, no matter of validation groups used.
-     */
-    always: boolean = false;
-
-    /**
-     * Specifies if validated value is an array and each of its item must be validated.
-     */
-    each: boolean = false;
-
-    /*
-     * A transient set of data passed through to the validation result for response mapping
-     */
-    context?: any = undefined;
-
-    /**
-     * Extra options specific to validation type.
-     */
-    validationTypeOptions: any;
-
-    // -------------------------------------------------------------------------
-    // Constructor
-    // -------------------------------------------------------------------------
-
-    constructor(args: ValidationMetadataArgs) {
-        this.type = args.type;
-        this.target = args.target;
-        this.propertyName = args.propertyName;
-        this.constraints = args.constraints;
-        this.constraintCls = args.constraintCls;
-        this.validationTypeOptions = args.validationTypeOptions;
-        if (args.validationOptions) {
-            this.message = args.validationOptions.message;
-            this.groups = args.validationOptions.groups;
-            this.always = args.validationOptions.always;
-            this.each = args.validationOptions.each;
-            this.context = args.validationOptions.context;
-        }
+  // -------------------------------------------------------------------------
+  // Properties
+  // -------------------------------------------------------------------------
+
+  /**
+   * Validation type.
+   */
+  type: string;
+
+  /**
+   * Target class to which this validation is applied.
+   */
+  target: Function | string;
+
+  /**
+   * Property of the object to be validated.
+   */
+  propertyName: string;
+
+  /**
+   * Constraint class that performs validation. Used only for custom validations.
+   */
+  constraintCls: Function;
+
+  /**
+   * Array of constraints of this validation.
+   */
+  constraints: any[];
+
+  /**
+   * Validation message to be shown in the case of error.
+   */
+  message: string | ((args: ValidationArguments) => string);
+
+  /**
+   * Validation groups used for this validation.
+   */
+  groups: string[] = [];
+
+  /**
+   * Indicates if validation must be performed always, no matter of validation groups used.
+   */
+  always?: boolean;
+
+  /**
+   * Specifies if validated value is an array and each of its item must be validated.
+   */
+  each: boolean = false;
+
+  /*
+   * A transient set of data passed through to the validation result for response mapping
+   */
+  context?: any = undefined;
+
+  /**
+   * Extra options specific to validation type.
+   */
+  validationTypeOptions: any;
+
+  // -------------------------------------------------------------------------
+  // Constructor
+  // -------------------------------------------------------------------------
+
+  constructor(args: ValidationMetadataArgs) {
+    this.type = args.type;
+    this.target = args.target;
+    this.propertyName = args.propertyName;
+    this.constraints = args.constraints;
+    this.constraintCls = args.constraintCls;
+    this.validationTypeOptions = args.validationTypeOptions;
+    if (args.validationOptions) {
+      this.message = args.validationOptions.message;
+      this.groups = args.validationOptions.groups;
+      this.always = args.validationOptions.always;
+      this.each = args.validationOptions.each;
+      this.context = args.validationOptions.context;
     }
-
+  }
 }
diff --git a/src/metadata/ValidationMetadataArgs.ts b/src/metadata/ValidationMetadataArgs.ts
index 8dcdb904ba..69e5a34885 100644
--- a/src/metadata/ValidationMetadataArgs.ts
+++ b/src/metadata/ValidationMetadataArgs.ts
@@ -1,42 +1,41 @@
-import {ValidationOptions} from "../decorator/ValidationOptions";
+import { ValidationOptions } from '../decorator/ValidationOptions';
 
 /**
  * Constructor arguments for ValidationMetadata class.
  */
 export interface ValidationMetadataArgs {
-
-    /**
-     * Validation type.
-     */
-    type: string;
-
-    /**
-     * Object that is used to be validated.
-     */
-    target: Function|string;
-
-    /**
-     * Property of the object to be validated.
-     */
-    propertyName: string;
-
-    /**
-     * Constraint class that performs validation. Used only for custom validations.
-     */
-    constraintCls?: Function;
-
-    /**
-     * Array of constraints of this validation.
-     */
-    constraints?: any[];
-
-    /**
-     * Validation options.
-     */
-    validationOptions?: ValidationOptions;
-
-    /**
-     * Extra options specific to validation type.
-     */
-    validationTypeOptions?: any;
-}
\ No newline at end of file
+  /**
+   * Validation type.
+   */
+  type: string;
+
+  /**
+   * Object that is used to be validated.
+   */
+  target: Function | string;
+
+  /**
+   * Property of the object to be validated.
+   */
+  propertyName: string;
+
+  /**
+   * Constraint class that performs validation. Used only for custom validations.
+   */
+  constraintCls?: Function;
+
+  /**
+   * Array of constraints of this validation.
+   */
+  constraints?: any[];
+
+  /**
+   * Validation options.
+   */
+  validationOptions?: ValidationOptions;
+
+  /**
+   * Extra options specific to validation type.
+   */
+  validationTypeOptions?: any;
+}
diff --git a/src/register-decorator.ts b/src/register-decorator.ts
index 3516296008..10b5cee5eb 100644
--- a/src/register-decorator.ts
+++ b/src/register-decorator.ts
@@ -1,88 +1,86 @@
-import {ConstraintMetadata} from "./metadata/ConstraintMetadata";
-import {ValidatorConstraintInterface} from "./validation/ValidatorConstraintInterface";
-import {ValidationMetadata} from "./metadata/ValidationMetadata";
-import {ValidationMetadataArgs} from "./metadata/ValidationMetadataArgs";
-import {ValidationTypes} from "./validation/ValidationTypes";
-import {ValidationArguments} from "./validation/ValidationArguments";
-import { getFromContainer } from "./container";
-import { MetadataStorage, getMetadataStorage } from "./metadata/MetadataStorage";
-import { ValidationOptions } from "./decorator/ValidationOptions";
+import { ConstraintMetadata } from './metadata/ConstraintMetadata';
+import { ValidatorConstraintInterface } from './validation/ValidatorConstraintInterface';
+import { ValidationMetadata } from './metadata/ValidationMetadata';
+import { ValidationMetadataArgs } from './metadata/ValidationMetadataArgs';
+import { ValidationTypes } from './validation/ValidationTypes';
+import { ValidationArguments } from './validation/ValidationArguments';
+import { getFromContainer } from './container';
+import { MetadataStorage, getMetadataStorage } from './metadata/MetadataStorage';
+import { ValidationOptions } from './decorator/ValidationOptions';
 
 export interface ValidationDecoratorOptions {
+  /**
+   * Target object to be validated.
+   */
+  target: Function;
 
-    /**
-     * Target object to be validated.
-     */
-    target: Function;
+  /**
+   * Target object's property name to be validated.
+   */
+  propertyName: string;
 
-    /**
-     * Target object's property name to be validated.
-     */
-    propertyName: string;
+  /**
+   * Name of the validation that is being registered.
+   */
+  name?: string;
 
-    /**
-     * Name of the validation that is being registered.
-     */
-    name?: string;
+  /**
+   * Indicates if this decorator will perform async validation.
+   */
+  async?: boolean;
 
-    /**
-     * Indicates if this decorator will perform async validation.
-     */
-    async?: boolean;
+  /**
+   * Validator options.
+   */
+  options?: ValidationOptions;
 
-    /**
-     * Validator options.
-     */
-    options?: ValidationOptions;
+  /**
+   * Array of validation constraints.
+   */
+  constraints?: any[];
 
-    /**
-     * Array of validation constraints.
-     */
-    constraints?: any[];
-
-    /**
-     * Validator that performs validation.
-     */
-    validator: ValidatorConstraintInterface|Function;
+  /**
+   * Validator that performs validation.
+   */
+  validator: ValidatorConstraintInterface | Function;
 }
 
 /**
  * Registers a custom validation decorator.
  */
 export function registerDecorator(options: ValidationDecoratorOptions): void {
+  let constraintCls: Function;
+  if (options.validator instanceof Function) {
+    constraintCls = options.validator;
+    const constraintClasses = getFromContainer(MetadataStorage).getTargetValidatorConstraints(options.validator);
+    if (constraintClasses.length > 1) {
+      throw `More than one implementation of ValidatorConstraintInterface found for validator on: ${options.target.name}:${options.propertyName}`;
+    }
+  } else {
+    const validator = options.validator;
+    constraintCls = class CustomConstraint implements ValidatorConstraintInterface {
+      validate(value: any, validationArguments?: ValidationArguments): Promise<boolean> | boolean {
+        return validator.validate(value, validationArguments);
+      }
 
-    let constraintCls: Function;
-    if (options.validator instanceof Function) {
-        constraintCls = options.validator;
-        const constraintClasses = getFromContainer(MetadataStorage).getTargetValidatorConstraints(options.validator);
-        if (constraintClasses.length > 1) {
-            throw `More than one implementation of ValidatorConstraintInterface found for validator on: ${options.target}:${options.propertyName}`;
+      defaultMessage(validationArguments?: ValidationArguments): string {
+        if (validator.defaultMessage) {
+          return validator.defaultMessage(validationArguments);
         }
-    } else {
-        const validator = options.validator;
-        constraintCls = class CustomConstraint implements ValidatorConstraintInterface {
-            validate(value: any, validationArguments?: ValidationArguments): Promise<boolean>|boolean {
-                return validator.validate(value, validationArguments);
-            }
-
-            defaultMessage(validationArguments?: ValidationArguments): string {
-                if (validator.defaultMessage) {
-                    return validator.defaultMessage(validationArguments);
-                }
 
-                return "";
-            }
-        };
-        getMetadataStorage().addConstraintMetadata(new ConstraintMetadata(constraintCls, options.name, options.async));
-    }
-
-    const validationMetadataArgs: ValidationMetadataArgs = {
-        type: options.name && ValidationTypes.isValid(options.name) ? options.name : ValidationTypes.CUSTOM_VALIDATION,
-        target: options.target,
-        propertyName: options.propertyName,
-        validationOptions: options.options,
-        constraintCls: constraintCls,
-        constraints: options.constraints
+        return '';
+      }
     };
-    getMetadataStorage().addValidationMetadata(new ValidationMetadata(validationMetadataArgs));
+    getMetadataStorage().addConstraintMetadata(new ConstraintMetadata(constraintCls, options.name, options.async));
+  }
+
+  const validationMetadataArgs: ValidationMetadataArgs = {
+    type: options.name && ValidationTypes.isValid(options.name) ? options.name : ValidationTypes.CUSTOM_VALIDATION,
+    target: options.target,
+    propertyName: options.propertyName,
+    validationOptions: options.options,
+    constraintCls: constraintCls,
+    constraints: options.constraints,
+  };
+  getMetadataStorage().addValidationMetadata(new ValidationMetadata(validationMetadataArgs));
 }
diff --git a/src/types.d.ts b/src/types.d.ts
deleted file mode 100644
index b4b006174d..0000000000
--- a/src/types.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-declare let window: any;
-
-declare module "ansicolor";
-declare module "google-libphonenumber";
diff --git a/src/utils.ts b/src/utils.ts
deleted file mode 100644
index cfe41b2e75..0000000000
--- a/src/utils.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-// https://github.com/TylorS/typed-is-promise/blob/abf1514e1b6961adfc75765476b0debb96b2c3ae/src/index.ts
-
-export function isPromise<T = any>(p: any): p is Promise<T> {
-    return p !== null && typeof p === "object" && typeof p.then === "function";
-}
-
-/**
- * Convert Map, Set to Array
- */
-export function convertToArray<T>(val: Array<T> | Set<T> | Map<any, T>): Array<T> {
-    if (val instanceof Map) {
-        return Array.from(val.values());
-    }
-    return Array.isArray(val) ? val : Array.from(val);
-}
diff --git a/src/utils/convert-to-array.util.ts b/src/utils/convert-to-array.util.ts
new file mode 100644
index 0000000000..4f38179aaf
--- /dev/null
+++ b/src/utils/convert-to-array.util.ts
@@ -0,0 +1,9 @@
+/**
+ * Convert Map, Set to Array
+ */
+export function convertToArray<T>(val: Array<T> | Set<T> | Map<any, T>): Array<T> {
+  if (val instanceof Map) {
+    return Array.from(val.values());
+  }
+  return Array.isArray(val) ? val : Array.from(val);
+}
diff --git a/src/utils/get-global.util.ts b/src/utils/get-global.util.ts
new file mode 100644
index 0000000000..1fac64cbf0
--- /dev/null
+++ b/src/utils/get-global.util.ts
@@ -0,0 +1,31 @@
+/**
+ * This function returns the global object across Node and browsers.
+ *
+ * Note: `globalThis` is the standardized approach however it has been added to
+ * Node.js in version 12. We need to include this snippet until Node 12 EOL.
+ */
+export function getGlobal() {
+  if (typeof globalThis !== 'undefined') {
+    return globalThis;
+  }
+
+  if (typeof global !== 'undefined') {
+    return global;
+  }
+
+  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+  // @ts-ignore: Cannot find name 'window'.
+  if (typeof window !== 'undefined') {
+    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+    // @ts-ignore: Cannot find name 'window'.
+    return window;
+  }
+
+  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+  // @ts-ignore: Cannot find name 'self'.
+  if (typeof self !== 'undefined') {
+    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+    // @ts-ignore: Cannot find name 'self'.
+    return self;
+  }
+}
diff --git a/src/utils/index.ts b/src/utils/index.ts
new file mode 100644
index 0000000000..0094adfff7
--- /dev/null
+++ b/src/utils/index.ts
@@ -0,0 +1,3 @@
+export * from './convert-to-array.util';
+export * from './get-global.util';
+export * from './is-promise.util';
diff --git a/src/utils/is-promise.util.ts b/src/utils/is-promise.util.ts
new file mode 100644
index 0000000000..f4d00a4a35
--- /dev/null
+++ b/src/utils/is-promise.util.ts
@@ -0,0 +1,5 @@
+// https://github.com/TylorS/typed-is-promise/blob/abf1514e1b6961adfc75765476b0debb96b2c3ae/src/index.ts
+
+export function isPromise<T = any>(p: any): p is Promise<T> {
+  return p !== null && typeof p === 'object' && typeof p.then === 'function';
+}
diff --git a/src/validation-schema/ValidationSchema.ts b/src/validation-schema/ValidationSchema.ts
index 7b4a57fa95..5a0aa0b5ca 100644
--- a/src/validation-schema/ValidationSchema.ts
+++ b/src/validation-schema/ValidationSchema.ts
@@ -3,61 +3,58 @@
  * Also using validation schemas makes this library to be easily used with es6/es5.
  */
 export interface ValidationSchema {
-
-    /**
-     * Schema name. This is required, because we tell validator to validate by this schema using its name.
-     */
-    name: string;
-
+  /**
+   * Schema name. This is required, because we tell validator to validate by this schema using its name.
+   */
+  name: string;
+
+  /**
+   * Validated properties.
+   */
+  properties: {
     /**
-     * Validated properties.
+     * Name of the object's property to be validated which holds an array of validation constraints.
      */
-    properties: {
-
-        /**
-         * Name of the object's property to be validated which holds an array of validation constraints.
-         */
-        [propertyName: string]: {
-
-            /**
-             * Validation type. Should be one of the ValidationTypes value.
-             */
-            type: string;
-
-            /**
-             * Constraints set by validation type.
-             */
-            constraints?: any[];
-
-            /**
-             * Error message used to be used on validation fail.
-             * You can use "$value" to use value that was failed by validation.
-             * You can use "$constraint1" and "$constraint2" keys in the message string,
-             * and they will be replaced with constraint values if they exist.
-             * Message can be either string, either a function that returns a string.
-             * Second option allows to use values and custom messages depend of them.
-             */
-            message?: string|((value?: any, constraint1?: any, constraint2?: any) => string);
-
-            /**
-             * Specifies if validated value is an array and each of its item must be validated.
-             */
-            each?: boolean;
-
-            /**
-             * Indicates if validation must be performed always, no matter of validation groups used.
-             */
-            always?: boolean;
-
-            /**
-             * Validation groups used for this validation.
-             */
-            groups?: string[];
-
-            /**
-             * Specific validation type options.
-             */
-            options?: any;
-        }[];
-    };
+    [propertyName: string]: {
+      /**
+       * Validation type. Should be one of the ValidationTypes value.
+       */
+      type: string;
+
+      /**
+       * Constraints set by validation type.
+       */
+      constraints?: any[];
+
+      /**
+       * Error message used to be used on validation fail.
+       * You can use "$value" to use value that was failed by validation.
+       * You can use "$constraint1" and "$constraint2" keys in the message string,
+       * and they will be replaced with constraint values if they exist.
+       * Message can be either string, either a function that returns a string.
+       * Second option allows to use values and custom messages depend of them.
+       */
+      message?: string | ((value?: any, constraint1?: any, constraint2?: any) => string);
+
+      /**
+       * Specifies if validated value is an array and each of its item must be validated.
+       */
+      each?: boolean;
+
+      /**
+       * Indicates if validation must be performed always, no matter of validation groups used.
+       */
+      always?: boolean;
+
+      /**
+       * Validation groups used for this validation.
+       */
+      groups?: string[];
+
+      /**
+       * Specific validation type options.
+       */
+      options?: any;
+    }[];
+  };
 }
diff --git a/src/validation-schema/ValidationSchemaToMetadataTransformer.ts b/src/validation-schema/ValidationSchemaToMetadataTransformer.ts
index dd45ff54b6..09901592fc 100644
--- a/src/validation-schema/ValidationSchemaToMetadataTransformer.ts
+++ b/src/validation-schema/ValidationSchemaToMetadataTransformer.ts
@@ -1,36 +1,33 @@
-import {ValidationSchema} from "./ValidationSchema";
-import {ValidationMetadata} from "../metadata/ValidationMetadata";
-import {ValidationMetadataArgs} from "../metadata/ValidationMetadataArgs";
-import {ValidationOptions} from "../decorator/ValidationOptions";
-import {ValidationTypes} from "../validation/ValidationTypes";
+import { ValidationSchema } from './ValidationSchema';
+import { ValidationMetadata } from '../metadata/ValidationMetadata';
+import { ValidationMetadataArgs } from '../metadata/ValidationMetadataArgs';
+import { ValidationOptions } from '../decorator/ValidationOptions';
 
 /**
  * Used to transform validation schemas to validation metadatas.
  */
 export class ValidationSchemaToMetadataTransformer {
-
-    transform(schema: ValidationSchema): ValidationMetadata[] {
-        const metadatas: ValidationMetadata[] = [];
-        Object.keys(schema.properties).forEach(property => {
-            schema.properties[property].forEach(validation => {
-                const validationOptions: ValidationOptions = {
-                    message: validation.message,
-                    groups: validation.groups,
-                    always: validation.always,
-                    each: validation.each
-                };
-                const args: ValidationMetadataArgs = {
-                    type: validation.type,
-                    target: schema.name,
-                    propertyName: property,
-                    constraints: validation.constraints,
-                    validationTypeOptions: validation.options,
-                    validationOptions: validationOptions
-                };
-                metadatas.push(new ValidationMetadata(args));
-            });
-        });
-        return metadatas;
-    }
-
+  transform(schema: ValidationSchema): ValidationMetadata[] {
+    const metadatas: ValidationMetadata[] = [];
+    Object.keys(schema.properties).forEach(property => {
+      schema.properties[property].forEach(validation => {
+        const validationOptions: ValidationOptions = {
+          message: validation.message,
+          groups: validation.groups,
+          always: validation.always,
+          each: validation.each,
+        };
+        const args: ValidationMetadataArgs = {
+          type: validation.type,
+          target: schema.name,
+          propertyName: property,
+          constraints: validation.constraints,
+          validationTypeOptions: validation.options,
+          validationOptions: validationOptions,
+        };
+        metadatas.push(new ValidationMetadata(args));
+      });
+    });
+    return metadatas;
+  }
 }
diff --git a/src/validation/ValidationArguments.ts b/src/validation/ValidationArguments.ts
index 3ef08cca32..5e760187f2 100644
--- a/src/validation/ValidationArguments.ts
+++ b/src/validation/ValidationArguments.ts
@@ -3,30 +3,28 @@
  * either by returning a function that accepts MessageArguments and returns a message string built based on these arguments.
  */
 export interface ValidationArguments {
+  /**
+   * Validating value.
+   */
+  value: any;
 
-    /**
-     * Validating value.
-     */
-    value: any;
+  /**
+   * Constraints set by this validation type.
+   */
+  constraints: any[];
 
-    /**
-     * Constraints set by this validation type.
-     */
-    constraints: any[];
+  /**
+   * Name of the target that is being validated.
+   */
+  targetName: string;
 
-    /**
-     * Name of the target that is being validated.
-     */
-    targetName: string;
-
-    /**
-     * Object that is being validated.
-     */
-    object: object;
-
-    /**
-     * Name of the object's property being validated.
-     */
-    property: string;
+  /**
+   * Object that is being validated.
+   */
+  object: object;
 
+  /**
+   * Name of the object's property being validated.
+   */
+  property: string;
 }
diff --git a/src/validation/ValidationError.ts b/src/validation/ValidationError.ts
index 78fb4ee67b..55892f4bd2 100644
--- a/src/validation/ValidationError.ts
+++ b/src/validation/ValidationError.ts
@@ -2,74 +2,79 @@
  * Validation error description.
  */
 export class ValidationError {
+  /**
+   * Object that was validated.
+   *
+   * OPTIONAL - configurable via the ValidatorOptions.validationError.target option
+   */
+  target?: object;
 
-    /**
-     * Object that was validated.
-     *
-     * OPTIONAL - configurable via the ValidatorOptions.validationError.target option
-     */
-    target?: object;
+  /**
+   * Object's property that haven't pass validation.
+   */
+  property: string;
 
-    /**
-     * Object's property that haven't pass validation.
-     */
-    property: string;
+  /**
+   * Value that haven't pass a validation.
+   *
+   * OPTIONAL - configurable via the ValidatorOptions.validationError.value option
+   */
+  value?: any;
 
-    /**
-     * Value that haven't pass a validation.
-     *
-     * OPTIONAL - configurable via the ValidatorOptions.validationError.value option
-     */
-    value?: any;
+  /**
+   * Constraints that failed validation with error messages.
+   */
+  constraints?: {
+    [type: string]: string;
+  };
 
-    /**
-     * Constraints that failed validation with error messages.
-     */
-    constraints?: {
-        [type: string]: string;
-    };
+  /**
+   * Contains all nested validation errors of the property.
+   */
+  children: ValidationError[];
 
-    /**
-     * Contains all nested validation errors of the property.
-     */
-    children: ValidationError[];
+  /*
+   * A transient set of data passed through to the validation result for response mapping
+   */
+  contexts?: {
+    [type: string]: any;
+  };
 
+  /**
+   *
+   * @param shouldDecorate decorate the message with ANSI formatter escape codes for better readability
+   * @param hasParent true when the error is a child of an another one
+   * @param parentPath path as string to the parent of this property
+   */
+  toString(shouldDecorate: boolean = false, hasParent: boolean = false, parentPath: string = ``): string {
+    const boldStart = shouldDecorate ? `\x1b[1m` : ``;
+    const boldEnd = shouldDecorate ? `\x1b[22m` : ``;
+    const propConstraintFailed = (propertyName: string): string =>
+      ` - property ${boldStart}${parentPath}${propertyName}${boldEnd} has failed the following constraints: ${boldStart}${Object.keys(
+        this.constraints
+      ).join(`, `)}${boldEnd} \n`;
 
-    /*
-     * A transient set of data passed through to the validation result for response mapping
-     */
-    contexts?: {
-        [type: string]: any;
-    };
+    if (!hasParent) {
+      return (
+        `An instance of ${boldStart}${
+          this.target ? this.target.constructor.name : 'an object'
+        }${boldEnd} has failed the validation:\n` +
+        (this.constraints ? propConstraintFailed(this.property) : ``) +
+        this.children.map(childError => childError.toString(shouldDecorate, true, this.property)).join(``)
+      );
+    } else {
+      // we format numbers as array indexes for better readability.
+      const formattedProperty = Number.isInteger(+this.property)
+        ? `[${this.property}]`
+        : `${parentPath ? `.` : ``}${this.property}`;
 
-    /**
-     *
-     * @param shouldDecorate decorate the message with ANSI formatter escape codes for better readability
-     * @param hasParent true when the error is a child of an another one
-     * @param parentPath path as string to the parent of this property
-     */
-    toString(shouldDecorate: boolean = false, hasParent: boolean = false, parentPath: string = ``): string {
-        const boldStart = shouldDecorate ? `\x1b[1m` : ``;
-        const boldEnd = shouldDecorate ? `\x1b[22m` : ``;
-        const propConstraintFailed = (propertyName: string): string => ` - property ${boldStart}${parentPath}${propertyName}${boldEnd} has failed the following constraints: ${boldStart}${Object.keys(this.constraints).join(`, `)}${boldEnd} \n`;
-
-        if (!hasParent) {
-            return `An instance of ${boldStart}${this.target ? this.target.constructor.name : "an object"}${boldEnd} has failed the validation:\n` +
-                (this.constraints ? propConstraintFailed(this.property) : ``) +
-                this.children
-                    .map(childError => childError.toString(shouldDecorate, true, this.property))
-                    .join(``);
-        } else {
-            // we format numbers as array indexes for better readability.
-            const formattedProperty = Number.isInteger(+this.property) ? `[${this.property}]` : `${parentPath ? `.` : ``}${this.property}`;
-
-            if (this.constraints) {
-                return propConstraintFailed(formattedProperty);
-            } else {
-                return this.children
-                    .map(childError => childError.toString(shouldDecorate, true, `${parentPath}${formattedProperty}`, ))
-                    .join(``);
-            }
-        }
+      if (this.constraints) {
+        return propConstraintFailed(formattedProperty);
+      } else {
+        return this.children
+          .map(childError => childError.toString(shouldDecorate, true, `${parentPath}${formattedProperty}`))
+          .join(``);
+      }
     }
+  }
 }
diff --git a/src/validation/ValidationExecutor.ts b/src/validation/ValidationExecutor.ts
index 4c44e05784..1112506038 100644
--- a/src/validation/ValidationExecutor.ts
+++ b/src/validation/ValidationExecutor.ts
@@ -1,405 +1,425 @@
-import {Validator} from "./Validator";
-import {ValidationError} from "./ValidationError";
-import {ValidationMetadata} from "../metadata/ValidationMetadata";
-import {ValidatorOptions} from "./ValidatorOptions";
-import {ValidationTypes} from "./ValidationTypes";
-import {ConstraintMetadata} from "../metadata/ConstraintMetadata";
-import {ValidationArguments} from "./ValidationArguments";
-import {ValidationUtils} from "./ValidationUtils";
-import {isPromise, convertToArray} from "../utils";
-import { getMetadataStorage } from "../metadata/MetadataStorage";
+import { Validator } from './Validator';
+import { ValidationError } from './ValidationError';
+import { ValidationMetadata } from '../metadata/ValidationMetadata';
+import { ValidatorOptions } from './ValidatorOptions';
+import { ValidationTypes } from './ValidationTypes';
+import { ConstraintMetadata } from '../metadata/ConstraintMetadata';
+import { ValidationArguments } from './ValidationArguments';
+import { ValidationUtils } from './ValidationUtils';
+import { isPromise, convertToArray } from '../utils';
+import { getMetadataStorage } from '../metadata/MetadataStorage';
 
 /**
  * Executes validation over given object.
  */
 export class ValidationExecutor {
-
-    // -------------------------------------------------------------------------
-    // Properties
-    // -------------------------------------------------------------------------
-
-    awaitingPromises: Promise<any>[] = [];
-    ignoreAsyncValidations: boolean = false;
-
-    // -------------------------------------------------------------------------
-    // Private Properties
-    // -------------------------------------------------------------------------
-
-    private metadataStorage = getMetadataStorage();
-
-    // -------------------------------------------------------------------------
-    // Constructor
-    // -------------------------------------------------------------------------
-
-    constructor(private validator: Validator,
-                private validatorOptions?: ValidatorOptions) {
+  // -------------------------------------------------------------------------
+  // Properties
+  // -------------------------------------------------------------------------
+
+  awaitingPromises: Promise<any>[] = [];
+  ignoreAsyncValidations: boolean = false;
+
+  // -------------------------------------------------------------------------
+  // Private Properties
+  // -------------------------------------------------------------------------
+
+  private metadataStorage = getMetadataStorage();
+
+  // -------------------------------------------------------------------------
+  // Constructor
+  // -------------------------------------------------------------------------
+
+  constructor(private validator: Validator, private validatorOptions?: ValidatorOptions) {}
+
+  // -------------------------------------------------------------------------
+  // Public Methods
+  // -------------------------------------------------------------------------
+
+  execute(object: object, targetSchema: string, validationErrors: ValidationError[]): void {
+    /**
+     * If there is no metadata registered it means possibly the dependencies are not flatterned and
+     * more than one instance is used.
+     *
+     * TODO: This needs proper handling, forcing to use the same container or some other proper solution.
+     */
+    if (!this.metadataStorage.hasValidationMetaData) {
+      console.warn(
+        `No metadata found. There is more than once class-validator version installed probably. You need to flatten your dependencies.`
+      );
     }
 
-    // -------------------------------------------------------------------------
-    // Public Methods
-    // -------------------------------------------------------------------------
-
-    execute(object: object, targetSchema: string, validationErrors: ValidationError[]): void {
-        /**
-         * If there is no metadata registered it means possibly the dependencies are not flatterned and
-         * more than one instance is used.
-         *
-         * TODO: This needs proper handling, forcing to use the same container or some other proper solution.
-         */
-        if (!this.metadataStorage.hasValidationMetaData) {
-            console.warn(`No metadata found. There is more than once class-validator version installed probably. You need to flatten your dependencies.`);
-        }
-
-        const groups = this.validatorOptions ? this.validatorOptions.groups : undefined;
-        const targetMetadatas = this.metadataStorage.getTargetValidationMetadatas(object.constructor, targetSchema, groups);
-        const groupedMetadatas = this.metadataStorage.groupByPropertyName(targetMetadatas);
-
-        if (this.validatorOptions && this.validatorOptions.forbidUnknownValues && !targetMetadatas.length) {
-            const validationError = new ValidationError();
-
-            if (!this.validatorOptions ||
-                !this.validatorOptions.validationError ||
-                this.validatorOptions.validationError.target === undefined ||
-                this.validatorOptions.validationError.target === true)
-                validationError.target = object;
-
-            validationError.value = undefined;
-            validationError.property = undefined;
-            validationError.children = [];
-            validationError.constraints = { unknownValue: "an unknown value was passed to the validate function" };
-
-            validationErrors.push(validationError);
-
-            return;
-        }
-
-        if (this.validatorOptions && this.validatorOptions.whitelist)
-            this.whitelist(object, groupedMetadatas, validationErrors);
-
-        // General validation
-        Object.keys(groupedMetadatas).forEach(propertyName => {
-            const value = (object as any)[propertyName];
-            const definedMetadatas = groupedMetadatas[propertyName].filter(metadata => metadata.type === ValidationTypes.IS_DEFINED);
-            const metadatas = groupedMetadatas[propertyName].filter(
-              metadata => metadata.type !== ValidationTypes.IS_DEFINED && metadata.type !== ValidationTypes.WHITELIST);
-
-            if (value instanceof Promise && metadatas.find(metadata => metadata.type === ValidationTypes.PROMISE_VALIDATION)) {
-                this.awaitingPromises.push(value.then((resolvedValue) => {
-                    this.performValidations(object, resolvedValue, propertyName, definedMetadatas, metadatas, validationErrors);
-                }));
-            } else {
-                this.performValidations(object, value, propertyName, definedMetadatas, metadatas, validationErrors);
-            }
-        });
+    const groups = this.validatorOptions ? this.validatorOptions.groups : undefined;
+    const strictGroups = (this.validatorOptions && this.validatorOptions.strictGroups) || false;
+    const always = (this.validatorOptions && this.validatorOptions.always) || false;
+
+    const targetMetadatas = this.metadataStorage.getTargetValidationMetadatas(
+      object.constructor,
+      targetSchema,
+      always,
+      strictGroups,
+      groups
+    );
+    const groupedMetadatas = this.metadataStorage.groupByPropertyName(targetMetadatas);
+
+    if (this.validatorOptions && this.validatorOptions.forbidUnknownValues && !targetMetadatas.length) {
+      const validationError = new ValidationError();
+
+      if (
+        !this.validatorOptions ||
+        !this.validatorOptions.validationError ||
+        this.validatorOptions.validationError.target === undefined ||
+        this.validatorOptions.validationError.target === true
+      )
+        validationError.target = object;
+
+      validationError.value = undefined;
+      validationError.property = undefined;
+      validationError.children = [];
+      validationError.constraints = { unknownValue: 'an unknown value was passed to the validate function' };
+
+      validationErrors.push(validationError);
+
+      return;
     }
 
-    whitelist(object: any,
-              groupedMetadatas: { [propertyName: string]: ValidationMetadata[] },
-              validationErrors: ValidationError[]): void {
-        const notAllowedProperties: string[] = [];
-
-        Object.keys(object).forEach(propertyName => {
-            // does this property have no metadata?
-            if (!groupedMetadatas[propertyName] || groupedMetadatas[propertyName].length === 0)
-                notAllowedProperties.push(propertyName);
+    if (this.validatorOptions && this.validatorOptions.whitelist)
+      this.whitelist(object, groupedMetadatas, validationErrors);
+
+    // General validation
+    Object.keys(groupedMetadatas).forEach(propertyName => {
+      const value = (object as any)[propertyName];
+      const definedMetadatas = groupedMetadatas[propertyName].filter(
+        metadata => metadata.type === ValidationTypes.IS_DEFINED
+      );
+      const metadatas = groupedMetadatas[propertyName].filter(
+        metadata => metadata.type !== ValidationTypes.IS_DEFINED && metadata.type !== ValidationTypes.WHITELIST
+      );
+
+      if (
+        value instanceof Promise &&
+        metadatas.find(metadata => metadata.type === ValidationTypes.PROMISE_VALIDATION)
+      ) {
+        this.awaitingPromises.push(
+          value.then(resolvedValue => {
+            this.performValidations(object, resolvedValue, propertyName, definedMetadatas, metadatas, validationErrors);
+          })
+        );
+      } else {
+        this.performValidations(object, value, propertyName, definedMetadatas, metadatas, validationErrors);
+      }
+    });
+  }
+
+  whitelist(
+    object: any,
+    groupedMetadatas: { [propertyName: string]: ValidationMetadata[] },
+    validationErrors: ValidationError[]
+  ): void {
+    const notAllowedProperties: string[] = [];
+
+    Object.keys(object).forEach(propertyName => {
+      // does this property have no metadata?
+      if (!groupedMetadatas[propertyName] || groupedMetadatas[propertyName].length === 0)
+        notAllowedProperties.push(propertyName);
+    });
+
+    if (notAllowedProperties.length > 0) {
+      if (this.validatorOptions && this.validatorOptions.forbidNonWhitelisted) {
+        // throw errors
+        notAllowedProperties.forEach(property => {
+          const validationError: ValidationError = this.generateValidationError(object, object[property], property);
+          validationError.constraints = { [ValidationTypes.WHITELIST]: `property ${property} should not exist` };
+          validationError.children = undefined;
+          validationErrors.push(validationError);
         });
-
-        if (notAllowedProperties.length > 0) {
-
-            if (this.validatorOptions && this.validatorOptions.forbidNonWhitelisted) {
-
-                // throw errors
-                notAllowedProperties.forEach(property => {
-                    const validationError: ValidationError = this.generateValidationError(object, (object)[property], property);
-                    validationError.constraints = { [ValidationTypes.WHITELIST]: `property ${property} should not exist` };
-                    validationError.children = undefined;
-                    validationErrors.push(validationError);
-                });
-
-            } else {
-
-                // strip non allowed properties
-                notAllowedProperties.forEach(property => delete (object)[property]);
-
-            }
+      } else {
+        // strip non allowed properties
+        notAllowedProperties.forEach(property => delete object[property]);
+      }
+    }
+  }
+
+  stripEmptyErrors(errors: ValidationError[]): ValidationError[] {
+    return errors.filter(error => {
+      if (error.children) {
+        error.children = this.stripEmptyErrors(error.children);
+      }
+
+      if (Object.keys(error.constraints).length === 0) {
+        if (error.children.length === 0) {
+          return false;
+        } else {
+          delete error.constraints;
         }
+      }
+
+      return true;
+    });
+  }
+
+  // -------------------------------------------------------------------------
+  // Private Methods
+  // -------------------------------------------------------------------------
+
+  private performValidations(
+    object: any,
+    value: any,
+    propertyName: string,
+    definedMetadatas: ValidationMetadata[],
+    metadatas: ValidationMetadata[],
+    validationErrors: ValidationError[]
+  ): void {
+    const customValidationMetadatas = metadatas.filter(metadata => metadata.type === ValidationTypes.CUSTOM_VALIDATION);
+    const nestedValidationMetadatas = metadatas.filter(metadata => metadata.type === ValidationTypes.NESTED_VALIDATION);
+    const conditionalValidationMetadatas = metadatas.filter(
+      metadata => metadata.type === ValidationTypes.CONDITIONAL_VALIDATION
+    );
+
+    const validationError = this.generateValidationError(object, value, propertyName);
+    validationErrors.push(validationError);
+
+    const canValidate = this.conditionalValidations(object, value, conditionalValidationMetadatas);
+    if (!canValidate) {
+      return;
     }
 
-    stripEmptyErrors(errors: ValidationError[]): ValidationError[] {
-        return errors.filter(error => {
-            if (error.children) {
-                error.children = this.stripEmptyErrors(error.children);
-            }
+    // handle IS_DEFINED validation type the special way - it should work no matter skipUndefinedProperties/skipMissingProperties is set or not
+    this.customValidations(object, value, definedMetadatas, validationError);
+    this.mapContexts(object, value, definedMetadatas, validationError);
 
-            if (Object.keys(error.constraints).length === 0) {
-                if (error.children.length === 0) {
-                    return false;
-                } else {
-                    delete error.constraints;
-                }
-            }
+    if (value === undefined && this.validatorOptions && this.validatorOptions.skipUndefinedProperties === true) {
+      return;
+    }
 
-            return true;
-        });
+    if (value === null && this.validatorOptions && this.validatorOptions.skipNullProperties === true) {
+      return;
     }
 
-    // -------------------------------------------------------------------------
-    // Private Methods
-    // -------------------------------------------------------------------------
+    if (
+      (value === null || value === undefined) &&
+      this.validatorOptions &&
+      this.validatorOptions.skipMissingProperties === true
+    ) {
+      return;
+    }
 
-    private performValidations (object: any,
-                                value: any, propertyName: string,
-                                definedMetadatas: ValidationMetadata[],
-                                metadatas: ValidationMetadata[],
-                                validationErrors: ValidationError[]): void {
+    this.customValidations(object, value, customValidationMetadatas, validationError);
+    this.nestedValidations(value, nestedValidationMetadatas, validationError.children);
+
+    this.mapContexts(object, value, metadatas, validationError);
+    this.mapContexts(object, value, customValidationMetadatas, validationError);
+  }
+
+  private generateValidationError(object: object, value: any, propertyName: string): ValidationError {
+    const validationError = new ValidationError();
+
+    if (
+      !this.validatorOptions ||
+      !this.validatorOptions.validationError ||
+      this.validatorOptions.validationError.target === undefined ||
+      this.validatorOptions.validationError.target === true
+    )
+      validationError.target = object;
+
+    if (
+      !this.validatorOptions ||
+      !this.validatorOptions.validationError ||
+      this.validatorOptions.validationError.value === undefined ||
+      this.validatorOptions.validationError.value === true
+    )
+      validationError.value = value;
+
+    validationError.property = propertyName;
+    validationError.children = [];
+    validationError.constraints = {};
+
+    return validationError;
+  }
+
+  private conditionalValidations(object: object, value: any, metadatas: ValidationMetadata[]): ValidationMetadata[] {
+    return metadatas
+      .map(metadata => metadata.constraints[0](object, value))
+      .reduce((resultA, resultB) => resultA && resultB, true);
+  }
+
+  private customValidations(object: object, value: any, metadatas: ValidationMetadata[], error: ValidationError): void {
+    metadatas.forEach(metadata => {
+      this.metadataStorage.getTargetValidatorConstraints(metadata.constraintCls).forEach(customConstraintMetadata => {
+        if (customConstraintMetadata.async && this.ignoreAsyncValidations) return;
+        if (
+          this.validatorOptions &&
+          this.validatorOptions.stopAtFirstError &&
+          Object.keys(error.constraints || {}).length > 0
+        )
+          return;
 
-        const customValidationMetadatas = metadatas.filter(metadata => metadata.type === ValidationTypes.CUSTOM_VALIDATION);
-        const nestedValidationMetadatas = metadatas.filter(metadata => metadata.type === ValidationTypes.NESTED_VALIDATION);
-        const conditionalValidationMetadatas = metadatas.filter(metadata => metadata.type === ValidationTypes.CONDITIONAL_VALIDATION);
+        const validationArguments: ValidationArguments = {
+          targetName: object.constructor ? (object.constructor as any).name : undefined,
+          property: metadata.propertyName,
+          object: object,
+          value: value,
+          constraints: metadata.constraints,
+        };
 
-        const validationError = this.generateValidationError(object, value, propertyName);
-        validationErrors.push(validationError);
+        if (!metadata.each || !(value instanceof Array || value instanceof Set || value instanceof Map)) {
+          const validatedValue = customConstraintMetadata.instance.validate(value, validationArguments);
+          if (isPromise(validatedValue)) {
+            const promise = validatedValue.then(isValid => {
+              if (!isValid) {
+                const [type, message] = this.createValidationError(object, value, metadata, customConstraintMetadata);
+                error.constraints[type] = message;
+                if (metadata.context) {
+                  if (!error.contexts) {
+                    error.contexts = {};
+                  }
+                  error.contexts[type] = Object.assign(error.contexts[type] || {}, metadata.context);
+                }
+              }
+            });
+            this.awaitingPromises.push(promise);
+          } else {
+            if (!validatedValue) {
+              const [type, message] = this.createValidationError(object, value, metadata, customConstraintMetadata);
+              error.constraints[type] = message;
+            }
+          }
 
-        const canValidate = this.conditionalValidations(object, value, conditionalValidationMetadatas);
-        if (!canValidate) {
-            return;
+          return;
         }
 
-        // handle IS_DEFINED validation type the special way - it should work no matter skipUndefinedProperties/skipMissingProperties is set or not
-        this.customValidations(object, value, definedMetadatas, validationError);
-        this.mapContexts(object, value, definedMetadatas, validationError);
+        // convert set and map into array
+        const arrayValue = convertToArray(value);
+        // Validation needs to be applied to each array item
+        const validatedSubValues = arrayValue.map((subValue: any) =>
+          customConstraintMetadata.instance.validate(subValue, validationArguments)
+        );
+        const validationIsAsync = validatedSubValues.some((validatedSubValue: boolean | Promise<boolean>) =>
+          isPromise(validatedSubValue)
+        );
+
+        if (validationIsAsync) {
+          // Wrap plain values (if any) in promises, so that all are async
+          const asyncValidatedSubValues = validatedSubValues.map((validatedSubValue: boolean | Promise<boolean>) =>
+            isPromise(validatedSubValue) ? validatedSubValue : Promise.resolve(validatedSubValue)
+          );
+          const asyncValidationIsFinishedPromise = Promise.all(asyncValidatedSubValues).then(
+            (flatValidatedValues: boolean[]) => {
+              const validationResult = flatValidatedValues.every((isValid: boolean) => isValid);
+              if (!validationResult) {
+                const [type, message] = this.createValidationError(object, value, metadata, customConstraintMetadata);
+                error.constraints[type] = message;
+                if (metadata.context) {
+                  if (!error.contexts) {
+                    error.contexts = {};
+                  }
+                  error.contexts[type] = Object.assign(error.contexts[type] || {}, metadata.context);
+                }
+              }
+            }
+          );
 
-        if (value === undefined && this.validatorOptions && this.validatorOptions.skipUndefinedProperties === true) {
-            return;
-        }
+          this.awaitingPromises.push(asyncValidationIsFinishedPromise);
 
-        if (value === null && this.validatorOptions && this.validatorOptions.skipNullProperties === true) {
-            return;
+          return;
         }
 
-        if ((value === null || value === undefined) && this.validatorOptions && this.validatorOptions.skipMissingProperties === true) {
-            return;
+        const validationResult = validatedSubValues.every((isValid: boolean) => isValid);
+        if (!validationResult) {
+          const [type, message] = this.createValidationError(object, value, metadata, customConstraintMetadata);
+          error.constraints[type] = message;
         }
+      });
+    });
+  }
 
-        this.customValidations(object, value, customValidationMetadatas, validationError);
-        this.nestedValidations(value, nestedValidationMetadatas, validationError.children);
-
-        this.mapContexts(object, value, metadatas, validationError);
-        this.mapContexts(object, value, customValidationMetadatas, validationError);
+  private nestedValidations(value: any, metadatas: ValidationMetadata[], errors: ValidationError[]): void {
+    if (value === void 0) {
+      return;
     }
 
-    private generateValidationError(object: object, value: any, propertyName: string): ValidationError {
-        const validationError = new ValidationError();
-
-        if (!this.validatorOptions ||
-            !this.validatorOptions.validationError ||
-            this.validatorOptions.validationError.target === undefined ||
-            this.validatorOptions.validationError.target === true)
-            validationError.target = object;
-
-        if (!this.validatorOptions ||
-            !this.validatorOptions.validationError ||
-            this.validatorOptions.validationError.value === undefined ||
-            this.validatorOptions.validationError.value === true)
-            validationError.value = value;
+    metadatas.forEach(metadata => {
+      if (metadata.type !== ValidationTypes.NESTED_VALIDATION && metadata.type !== ValidationTypes.PROMISE_VALIDATION) {
+        return;
+      }
 
-        validationError.property = propertyName;
-        validationError.children = [];
-        validationError.constraints = {};
-
-        return validationError;
-    }
-
-    private conditionalValidations(object: object,
-                                   value: any,
-                                   metadatas: ValidationMetadata[]): ValidationMetadata[] {
-        return metadatas
-            .map(metadata => metadata.constraints[0](object, value))
-            .reduce((resultA, resultB) => resultA && resultB, true);
-    }
-
-    private customValidations(object: object,
-                              value: any,
-                              metadatas: ValidationMetadata[],
-                              error: ValidationError): void {
-
-        metadatas.forEach(metadata => {
-            this.metadataStorage
-                .getTargetValidatorConstraints(metadata.constraintCls)
-                .forEach(customConstraintMetadata => {
-                    if (customConstraintMetadata.async && this.ignoreAsyncValidations)
-                        return;
-
-                    const validationArguments: ValidationArguments = {
-                        targetName: object.constructor ? (object.constructor as any).name : undefined,
-                        property: metadata.propertyName,
-                        object: object,
-                        value: value,
-                        constraints: metadata.constraints
-                    };
-
-                    if (!metadata.each || !(value instanceof Array || value instanceof Set || value instanceof Map)) {
-                        const validatedValue = customConstraintMetadata.instance.validate(value, validationArguments);
-                        if (isPromise(validatedValue)) {
-                            const promise = validatedValue.then(isValid => {
-                                if (!isValid) {
-                                    const [type, message] = this.createValidationError(object, value, metadata, customConstraintMetadata);
-                                    error.constraints[type] = message;
-                                    if (metadata.context) {
-                                        if (!error.contexts) {
-                                            error.contexts = {};
-                                        }
-                                        error.contexts[type] = Object.assign((error.contexts[type] || {}), metadata.context);
-                                    }
-                                }
-                            });
-                            this.awaitingPromises.push(promise);
-                        } else {
-                            if (!validatedValue) {
-                                const [type, message] = this.createValidationError(object, value, metadata, customConstraintMetadata);
-                                error.constraints[type] = message;
-                            }
-                        }
-
-                        return;
-                    }
-
-                    // convert set and map into array
-                    const arrayValue = convertToArray(value);
-                    // Validation needs to be applied to each array item
-                    const validatedSubValues = arrayValue.map((subValue: any) => customConstraintMetadata.instance.validate(subValue, validationArguments));
-                    const validationIsAsync = validatedSubValues
-                        .some((validatedSubValue: boolean | Promise<boolean>) => isPromise(validatedSubValue));
-
-                    if (validationIsAsync) {
-                        // Wrap plain values (if any) in promises, so that all are async
-                        const asyncValidatedSubValues = validatedSubValues
-                            .map((validatedSubValue: boolean | Promise<boolean>) => isPromise(validatedSubValue) ? validatedSubValue : Promise.resolve(validatedSubValue));
-                        const asyncValidationIsFinishedPromise = Promise.all(asyncValidatedSubValues)
-                            .then((flatValidatedValues: boolean[]) => {
-                                const validationResult = flatValidatedValues.every((isValid: boolean) => isValid);
-                                if (!validationResult) {
-                                    const [type, message] = this.createValidationError(object, value, metadata, customConstraintMetadata);
-                                    error.constraints[type] = message;
-                                    if (metadata.context) {
-                                        if (!error.contexts) {
-                                            error.contexts = {};
-                                        }
-                                        error.contexts[type] = Object.assign((error.contexts[type] || {}), metadata.context);
-                                    }
-                                }
-                            });
-
-                        this.awaitingPromises.push(asyncValidationIsFinishedPromise);
-
-                        return;
-                    }
-
-                    const validationResult = validatedSubValues.every((isValid: boolean) => isValid);
-                    if (!validationResult) {
-                        const [type, message] = this.createValidationError(object, value, metadata, customConstraintMetadata);
-                        error.constraints[type] = message;
-                    }
-                });
+      if (value instanceof Array || value instanceof Set || value instanceof Map) {
+        // Treats Set as an array - as index of Set value is value itself and it is common case to have Object as value
+        const arrayLikeValue = value instanceof Set ? Array.from(value) : value;
+        arrayLikeValue.forEach((subValue: any, index: any) => {
+          this.performValidations(value, subValue, index.toString(), [], metadatas, errors);
         });
-    }
-
-    private nestedValidations(value: any, metadatas: ValidationMetadata[], errors: ValidationError[]): void {
-
-        if (value === void 0) {
-            return;
+      } else if (value instanceof Object) {
+        const targetSchema = typeof metadata.target === 'string' ? metadata.target : metadata.target.name;
+        this.execute(value, targetSchema, errors);
+      } else {
+        const error = new ValidationError();
+        error.value = value;
+        error.property = metadata.propertyName;
+        error.target = metadata.target as object;
+        const [type, message] = this.createValidationError(metadata.target as object, value, metadata);
+        error.constraints = {
+          [type]: message,
+        };
+        errors.push(error);
+      }
+    });
+  }
+
+  private mapContexts(object: object, value: any, metadatas: ValidationMetadata[], error: ValidationError): void {
+    return metadatas.forEach(metadata => {
+      if (metadata.context) {
+        let customConstraint;
+        if (metadata.type === ValidationTypes.CUSTOM_VALIDATION) {
+          const customConstraints = this.metadataStorage.getTargetValidatorConstraints(metadata.constraintCls);
+          customConstraint = customConstraints[0];
         }
 
-        metadatas.forEach(metadata => {
-            if (
-                metadata.type !== ValidationTypes.NESTED_VALIDATION &&
-                metadata.type !== ValidationTypes.PROMISE_VALIDATION
-            ) {
-                return;
-            }
+        const type = this.getConstraintType(metadata, customConstraint);
 
-            if (value instanceof Array || value instanceof Set || value instanceof Map) {
-                // Treats Set as an array - as index of Set value is value itself and it is common case to have Object as value
-                const arrayLikeValue = value instanceof Set ? Array.from(value) : value;
-                arrayLikeValue.forEach((subValue: any, index: any) => {
-                    this.performValidations(value, subValue, index.toString(), [], metadatas, errors);
-                });
-
-            } else if (value instanceof Object) {
-                const targetSchema = typeof metadata.target === "string" ? metadata.target : metadata.target.name;
-                this.execute(value, targetSchema, errors);
-
-            } else {
-                const error = new ValidationError();
-                error.value = value;
-                error.property = metadata.propertyName;
-                error.target = metadata.target as object;
-                const [type, message] = this.createValidationError(metadata.target as object, value, metadata);
-                error.constraints = {
-                    [type]: message
-                };
-                errors.push(error);
-            }
-        });
-    }
-
-    private mapContexts(object: object,
-                        value: any,
-                        metadatas: ValidationMetadata[],
-                        error: ValidationError): void {
-
-        return metadatas
-            .forEach(metadata => {
-                if (metadata.context) {
-                    let customConstraint;
-                    if (metadata.type === ValidationTypes.CUSTOM_VALIDATION) {
-                        const customConstraints = this.metadataStorage.getTargetValidatorConstraints(metadata.constraintCls);
-                        customConstraint = customConstraints[0];
-                    }
-
-                    const type = this.getConstraintType(metadata, customConstraint);
-
-                    if (error.constraints[type]) {
-                        if (!error.contexts) {
-                            error.contexts = {};
-                        }
-
-                        error.contexts[type] = Object.assign((error.contexts[type] || {}), metadata.context);
-                    }
-                }
-            });
-    }
-
-    private createValidationError(object: object,
-                                  value: any,
-                                  metadata: ValidationMetadata,
-                                  customValidatorMetadata?: ConstraintMetadata): [string, string] {
+        if (error.constraints[type]) {
+          if (!error.contexts) {
+            error.contexts = {};
+          }
 
-        const targetName = object.constructor ? (object.constructor as any).name : undefined;
-        const type = this.getConstraintType(metadata, customValidatorMetadata);
-        const validationArguments: ValidationArguments = {
-            targetName: targetName,
-            property: metadata.propertyName,
-            object: object,
-            value: value,
-            constraints: metadata.constraints
-        };
-
-        let message = metadata.message || "";
-        if (!metadata.message &&
-            (!this.validatorOptions || (this.validatorOptions && !this.validatorOptions.dismissDefaultMessages))) {
-            if (customValidatorMetadata && customValidatorMetadata.instance.defaultMessage instanceof Function) {
-                message = customValidatorMetadata.instance.defaultMessage(validationArguments);
-            }
+          error.contexts[type] = Object.assign(error.contexts[type] || {}, metadata.context);
         }
-
-        const messageString = ValidationUtils.replaceMessageSpecialTokens(message, validationArguments);
-        return [type, messageString];
+      }
+    });
+  }
+
+  private createValidationError(
+    object: object,
+    value: any,
+    metadata: ValidationMetadata,
+    customValidatorMetadata?: ConstraintMetadata
+  ): [string, string] {
+    const targetName = object.constructor ? (object.constructor as any).name : undefined;
+    const type = this.getConstraintType(metadata, customValidatorMetadata);
+    const validationArguments: ValidationArguments = {
+      targetName: targetName,
+      property: metadata.propertyName,
+      object: object,
+      value: value,
+      constraints: metadata.constraints,
+    };
+
+    let message = metadata.message || '';
+    if (
+      !metadata.message &&
+      (!this.validatorOptions || (this.validatorOptions && !this.validatorOptions.dismissDefaultMessages))
+    ) {
+      if (customValidatorMetadata && customValidatorMetadata.instance.defaultMessage instanceof Function) {
+        message = customValidatorMetadata.instance.defaultMessage(validationArguments);
+      }
     }
 
-    private getConstraintType(metadata: ValidationMetadata, customValidatorMetadata?: ConstraintMetadata): string {
-        const type = customValidatorMetadata && customValidatorMetadata.name ? customValidatorMetadata.name : metadata.type;
-        return type;
-    }
+    const messageString = ValidationUtils.replaceMessageSpecialTokens(message, validationArguments);
+    return [type, messageString];
+  }
 
+  private getConstraintType(metadata: ValidationMetadata, customValidatorMetadata?: ConstraintMetadata): string {
+    const type = customValidatorMetadata && customValidatorMetadata.name ? customValidatorMetadata.name : metadata.type;
+    return type;
+  }
 }
diff --git a/src/validation/ValidationTypes.ts b/src/validation/ValidationTypes.ts
index 235d569613..640e7f3ffe 100644
--- a/src/validation/ValidationTypes.ts
+++ b/src/validation/ValidationTypes.ts
@@ -2,22 +2,24 @@
  * Validation types.
  */
 export class ValidationTypes {
+  /* system */
+  static CUSTOM_VALIDATION = 'customValidation'; // done
+  static NESTED_VALIDATION = 'nestedValidation'; // done
+  static PROMISE_VALIDATION = 'promiseValidation'; // done
+  static CONDITIONAL_VALIDATION = 'conditionalValidation'; // done
+  static WHITELIST = 'whitelistValidation'; // done
+  static IS_DEFINED = 'isDefined'; // done
 
-    /* system */
-    static CUSTOM_VALIDATION = "customValidation"; // done
-    static NESTED_VALIDATION = "nestedValidation"; // done
-    static PROMISE_VALIDATION = "promiseValidation"; // done
-    static CONDITIONAL_VALIDATION = "conditionalValidation"; // done
-    static WHITELIST = "whitelistValidation"; // done
-    static IS_DEFINED = "isDefined"; // done
-
-    /**
-     * Checks if validation type is valid.
-     */
-    static isValid(type: string): boolean {
-        return type !== "isValid" &&
-            type !== "getMessage" &&
-            Object.keys(this).map(key => (this as any)[key]).indexOf(type) !== -1;
-    }
-
+  /**
+   * Checks if validation type is valid.
+   */
+  static isValid(type: string): boolean {
+    return (
+      type !== 'isValid' &&
+      type !== 'getMessage' &&
+      Object.keys(this)
+        .map(key => (this as any)[key])
+        .indexOf(type) !== -1
+    );
+  }
 }
diff --git a/src/validation/ValidationUtils.ts b/src/validation/ValidationUtils.ts
index 51debee3c5..00e01c6925 100644
--- a/src/validation/ValidationUtils.ts
+++ b/src/validation/ValidationUtils.ts
@@ -1,32 +1,33 @@
-import {ValidationArguments} from "./ValidationArguments";
+import { ValidationArguments } from './ValidationArguments';
 
 export class ValidationUtils {
+  static replaceMessageSpecialTokens(
+    message: string | ((args: ValidationArguments) => string),
+    validationArguments: ValidationArguments
+  ): string {
+    let messageString: string;
+    if (message instanceof Function) {
+      messageString = (message as (args: ValidationArguments) => string)(validationArguments);
+    } else if (typeof message === 'string') {
+      messageString = message;
+    }
 
-    static replaceMessageSpecialTokens(message: string|((args: ValidationArguments) => string),
-                                validationArguments: ValidationArguments): string {
-
-        let messageString: string;
-        if (message instanceof Function) {
-            messageString = (message as (args: ValidationArguments) => string)(validationArguments);
-
-        } else if (typeof message === "string") {
-            messageString = message;
-        }
-
-        if (messageString && validationArguments.constraints instanceof Array) {
-            validationArguments.constraints.forEach((constraint, index) => {
-                messageString = messageString.replace(new RegExp(`\\$constraint${index + 1}`, "g"), constraint);
-            });
-        }
-
-        if (messageString && validationArguments.value !== undefined && validationArguments.value !== null && typeof validationArguments.value === "string")
-            messageString = messageString.replace(/\$value/g, validationArguments.value);
-        if (messageString)
-            messageString = messageString.replace(/\$property/g, validationArguments.property);
-        if (messageString)
-            messageString = messageString.replace(/\$target/g, validationArguments.targetName);
-
-        return messageString;
+    if (messageString && validationArguments.constraints instanceof Array) {
+      validationArguments.constraints.forEach((constraint, index) => {
+        messageString = messageString.replace(new RegExp(`\\$constraint${index + 1}`, 'g'), constraint);
+      });
     }
 
+    if (
+      messageString &&
+      validationArguments.value !== undefined &&
+      validationArguments.value !== null &&
+      typeof validationArguments.value === 'string'
+    )
+      messageString = messageString.replace(/\$value/g, validationArguments.value);
+    if (messageString) messageString = messageString.replace(/\$property/g, validationArguments.property);
+    if (messageString) messageString = messageString.replace(/\$target/g, validationArguments.targetName);
+
+    return messageString;
+  }
 }
diff --git a/src/validation/Validator.ts b/src/validation/Validator.ts
index 260ad8a712..77e46ef2b0 100644
--- a/src/validation/Validator.ts
+++ b/src/validation/Validator.ts
@@ -1,99 +1,113 @@
-import {ValidationMetadata} from "../metadata/ValidationMetadata";
-import {ValidationTypes} from "./ValidationTypes";
-import {ValidationError} from "./ValidationError";
-import {ValidatorOptions} from "./ValidatorOptions";
-import {ValidationExecutor} from "./ValidationExecutor";
-import {ValidationOptions} from "../decorator/ValidationOptions";
-import * as validator from "validator";
+import { ValidationError } from './ValidationError';
+import { ValidatorOptions } from './ValidatorOptions';
+import { ValidationExecutor } from './ValidationExecutor';
+import { ValidationOptions } from '../decorator/ValidationOptions';
 
 /**
  * Validator performs validation of the given object based on its metadata.
  */
 export class Validator {
-    // -------------------------------------------------------------------------
-    // Public Methods
-    // -------------------------------------------------------------------------
+  // -------------------------------------------------------------------------
+  // Public Methods
+  // -------------------------------------------------------------------------
 
-    /**
-     * Performs validation of the given object based on decorators used in given object class.
-     */
-    validate(object: object, options?: ValidatorOptions): Promise<ValidationError[]>;
+  /**
+   * Performs validation of the given object based on decorators used in given object class.
+   */
+  validate(object: object, options?: ValidatorOptions): Promise<ValidationError[]>;
 
-    /**
-     * Performs validation of the given object based on validation schema.
-     */
-    validate(schemaName: string, object: object, options?: ValidatorOptions): Promise<ValidationError[]>;
+  /**
+   * Performs validation of the given object based on validation schema.
+   */
+  validate(schemaName: string, object: object, options?: ValidatorOptions): Promise<ValidationError[]>;
 
-    /**
-     * Performs validation of the given object based on decorators or validation schema.
-     */
-    validate(objectOrSchemaName: object|string, objectOrValidationOptions: object|ValidationOptions, maybeValidatorOptions?: ValidatorOptions): Promise<ValidationError[]> {
-        return this.coreValidate(objectOrSchemaName, objectOrValidationOptions, maybeValidatorOptions);
-    }
+  /**
+   * Performs validation of the given object based on decorators or validation schema.
+   */
+  validate(
+    objectOrSchemaName: object | string,
+    objectOrValidationOptions: object | ValidationOptions,
+    maybeValidatorOptions?: ValidatorOptions
+  ): Promise<ValidationError[]> {
+    return this.coreValidate(objectOrSchemaName, objectOrValidationOptions, maybeValidatorOptions);
+  }
 
-    /**
-     * Performs validation of the given object based on decorators used in given object class and reject on error.
-     */
-    validateOrReject(object: object, options?: ValidatorOptions): Promise<void>;
+  /**
+   * Performs validation of the given object based on decorators used in given object class and reject on error.
+   */
+  validateOrReject(object: object, options?: ValidatorOptions): Promise<void>;
 
-    /**
-     * Performs validation of the given object based on validation schema and reject on error.
-     */
-    validateOrReject(schemaName: string, object: object, options?: ValidatorOptions): Promise<void>;
+  /**
+   * Performs validation of the given object based on validation schema and reject on error.
+   */
+  validateOrReject(schemaName: string, object: object, options?: ValidatorOptions): Promise<void>;
 
-    /**
-     * Performs validation of the given object based on decorators or validation schema and reject on error.
-     */
-    async validateOrReject(objectOrSchemaName: object|string, objectOrValidationOptions: object|ValidationOptions, maybeValidatorOptions?: ValidatorOptions): Promise<void> {
-        const errors = await this.coreValidate(objectOrSchemaName, objectOrValidationOptions, maybeValidatorOptions);
-        if (errors.length)
-            return Promise.reject(errors);
-    }
+  /**
+   * Performs validation of the given object based on decorators or validation schema and reject on error.
+   */
+  async validateOrReject(
+    objectOrSchemaName: object | string,
+    objectOrValidationOptions: object | ValidationOptions,
+    maybeValidatorOptions?: ValidatorOptions
+  ): Promise<void> {
+    const errors = await this.coreValidate(objectOrSchemaName, objectOrValidationOptions, maybeValidatorOptions);
+    if (errors.length) return Promise.reject(errors);
+  }
 
-    /**
-     * Performs validation of the given object based on decorators used in given object class.
-     * NOTE: This method completely ignores all async validations.
-     */
-    validateSync(object: object, options?: ValidatorOptions): ValidationError[];
+  /**
+   * Performs validation of the given object based on decorators used in given object class.
+   * NOTE: This method completely ignores all async validations.
+   */
+  validateSync(object: object, options?: ValidatorOptions): ValidationError[];
 
-    /**
-     * Performs validation of the given object based on validation schema.
-     */
-    validateSync(schemaName: string, object: object, options?: ValidatorOptions): ValidationError[];
+  /**
+   * Performs validation of the given object based on validation schema.
+   */
+  validateSync(schemaName: string, object: object, options?: ValidatorOptions): ValidationError[];
 
-    /**
-     * Performs validation of the given object based on decorators or validation schema.
-     */
-    validateSync(objectOrSchemaName: object|string, objectOrValidationOptions: object|ValidationOptions, maybeValidatorOptions?: ValidatorOptions): ValidationError[] {
-        const object = typeof objectOrSchemaName === "string" ? objectOrValidationOptions as object : objectOrSchemaName;
-        const options = typeof objectOrSchemaName === "string" ? maybeValidatorOptions : objectOrValidationOptions as ValidationOptions;
-        const schema = typeof objectOrSchemaName === "string" ? objectOrSchemaName : undefined;
+  /**
+   * Performs validation of the given object based on decorators or validation schema.
+   */
+  validateSync(
+    objectOrSchemaName: object | string,
+    objectOrValidationOptions: object | ValidationOptions,
+    maybeValidatorOptions?: ValidatorOptions
+  ): ValidationError[] {
+    const object = typeof objectOrSchemaName === 'string' ? (objectOrValidationOptions as object) : objectOrSchemaName;
+    const options =
+      typeof objectOrSchemaName === 'string' ? maybeValidatorOptions : (objectOrValidationOptions as ValidationOptions);
+    const schema = typeof objectOrSchemaName === 'string' ? objectOrSchemaName : undefined;
 
-        const executor = new ValidationExecutor(this, options);
-        executor.ignoreAsyncValidations = true;
-        const validationErrors: ValidationError[] = [];
-        executor.execute(object, schema, validationErrors);
-        return executor.stripEmptyErrors(validationErrors);
-    }
+    const executor = new ValidationExecutor(this, options);
+    executor.ignoreAsyncValidations = true;
+    const validationErrors: ValidationError[] = [];
+    executor.execute(object, schema, validationErrors);
+    return executor.stripEmptyErrors(validationErrors);
+  }
 
-    // -------------------------------------------------------------------------
-    // Private Properties
-    // -------------------------------------------------------------------------
-    /**
-     * Performs validation of the given object based on decorators or validation schema.
-     * Common method for `validateOrReject` and `validate` methods.
-     */
-    private coreValidate(objectOrSchemaName: object|string, objectOrValidationOptions: object|ValidationOptions, maybeValidatorOptions?: ValidatorOptions): Promise<ValidationError[]> {
-        const object = typeof objectOrSchemaName === "string" ? objectOrValidationOptions as object : objectOrSchemaName;
-        const options = typeof objectOrSchemaName === "string" ? maybeValidatorOptions : objectOrValidationOptions as ValidationOptions;
-        const schema = typeof objectOrSchemaName === "string" ? objectOrSchemaName : undefined;
+  // -------------------------------------------------------------------------
+  // Private Properties
+  // -------------------------------------------------------------------------
+  /**
+   * Performs validation of the given object based on decorators or validation schema.
+   * Common method for `validateOrReject` and `validate` methods.
+   */
+  private coreValidate(
+    objectOrSchemaName: object | string,
+    objectOrValidationOptions: object | ValidationOptions,
+    maybeValidatorOptions?: ValidatorOptions
+  ): Promise<ValidationError[]> {
+    const object = typeof objectOrSchemaName === 'string' ? (objectOrValidationOptions as object) : objectOrSchemaName;
+    const options =
+      typeof objectOrSchemaName === 'string' ? maybeValidatorOptions : (objectOrValidationOptions as ValidationOptions);
+    const schema = typeof objectOrSchemaName === 'string' ? objectOrSchemaName : undefined;
 
-        const executor = new ValidationExecutor(this, options);
-        const validationErrors: ValidationError[] = [];
-        executor.execute(object, schema, validationErrors);
+    const executor = new ValidationExecutor(this, options);
+    const validationErrors: ValidationError[] = [];
+    executor.execute(object, schema, validationErrors);
 
-        return Promise.all(executor.awaitingPromises).then(() => {
-            return executor.stripEmptyErrors(validationErrors);
-        });
-    }
+    return Promise.all(executor.awaitingPromises).then(() => {
+      return executor.stripEmptyErrors(validationErrors);
+    });
+  }
 }
diff --git a/src/validation/ValidatorConstraintInterface.ts b/src/validation/ValidatorConstraintInterface.ts
index 5d485bd0df..f29ce2f6fe 100644
--- a/src/validation/ValidatorConstraintInterface.ts
+++ b/src/validation/ValidatorConstraintInterface.ts
@@ -1,17 +1,15 @@
-import {ValidationArguments} from "./ValidationArguments";
+import { ValidationArguments } from './ValidationArguments';
 /**
  * Custom validators must implement this interface to provide custom validation logic.
  */
 export interface ValidatorConstraintInterface {
+  /**
+   * Method to be called to perform custom validation over given value.
+   */
+  validate(value: any, validationArguments?: ValidationArguments): Promise<boolean> | boolean;
 
-    /**
-     * Method to be called to perform custom validation over given value.
-     */
-    validate(value: any, validationArguments?: ValidationArguments): Promise<boolean>|boolean;
-
-    /**
-     * Gets default message when validation for this constraint fail.
-     */
-    defaultMessage?(validationArguments?: ValidationArguments): string;
-
-}
\ No newline at end of file
+  /**
+   * Gets default message when validation for this constraint fail.
+   */
+  defaultMessage?(validationArguments?: ValidationArguments): string;
+}
diff --git a/src/validation/ValidatorOptions.ts b/src/validation/ValidatorOptions.ts
index d610985eb3..fdd142d79f 100644
--- a/src/validation/ValidatorOptions.ts
+++ b/src/validation/ValidatorOptions.ts
@@ -2,64 +2,77 @@
  * Options passed to validator during validation.
  */
 export interface ValidatorOptions {
-    /**
-     * If set to true then validator will skip validation of all properties that are undefined in the validating object.
-     */
-    skipUndefinedProperties?: boolean;
-
-    /**
-     * If set to true then validator will skip validation of all properties that are null in the validating object.
-     */
-    skipNullProperties?: boolean;
+  /**
+   * If set to true then validator will skip validation of all properties that are undefined in the validating object.
+   */
+  skipUndefinedProperties?: boolean;
 
-    /**
-     * If set to true then validator will skip validation of all properties that are null or undefined in the validating object.
-     */
-    skipMissingProperties?: boolean;
+  /**
+   * If set to true then validator will skip validation of all properties that are null in the validating object.
+   */
+  skipNullProperties?: boolean;
 
-    /**
-     * If set to true validator will strip validated object of any properties that do not have any decorators.
-     *
-     * Tip: if no other decorator is suitable for your property use @Allow decorator.
-     */
-    whitelist?: boolean;
+  /**
+   * If set to true then validator will skip validation of all properties that are null or undefined in the validating object.
+   */
+  skipMissingProperties?: boolean;
 
-    /**
-     * If set to true, instead of stripping non-whitelisted properties validator will throw an error
-     */
-    forbidNonWhitelisted?: boolean;
+  /**
+   * If set to true validator will strip validated object of any properties that do not have any decorators.
+   *
+   * Tip: if no other decorator is suitable for your property use @Allow decorator.
+   */
+  whitelist?: boolean;
 
-    /**
-     * Groups to be used during validation of the object.
-     */
-    groups?: string[];
+  /**
+   * If set to true, instead of stripping non-whitelisted properties validator will throw an error
+   */
+  forbidNonWhitelisted?: boolean;
 
-    /**
-     * If set to true, the validation will not use default messages.
-     * Error message always will be undefined if its not explicitly set.
-     */
-    dismissDefaultMessages?: boolean;
+  /**
+   * Groups to be used during validation of the object.
+   */
+  groups?: string[];
 
-    /**
-     * ValidationError special options.
-     */
-    validationError?: {
+  /**
+   * Set default for `always` option of decorators. Default can be overridden in decorator options.
+   */
+  always?: boolean;
 
-        /**
-         * Indicates if target should be exposed in ValidationError.
-         */
-        target?: boolean;
+  /**
+   * If [groups]{@link ValidatorOptions#groups} is not given or is empty,
+   * ignore decorators with at least one group.
+   */
+  strictGroups?: boolean;
 
-        /**
-         * Indicates if validated value should be exposed in ValidationError.
-         */
-        value?: boolean;
+  /**
+   * If set to true, the validation will not use default messages.
+   * Error message always will be undefined if its not explicitly set.
+   */
+  dismissDefaultMessages?: boolean;
 
-    };
+  /**
+   * ValidationError special options.
+   */
+  validationError?: {
+    /**
+     * Indicates if target should be exposed in ValidationError.
+     */
+    target?: boolean;
 
     /**
-     * Settings true will cause fail validation of unknown objects.
+     * Indicates if validated value should be exposed in ValidationError.
      */
-    forbidUnknownValues?: boolean;
+    value?: boolean;
+  };
+
+  /**
+   * Settings true will cause fail validation of unknown objects.
+   */
+  forbidUnknownValues?: boolean;
 
+  /**
+   * When set to true, validation of the given property will stop after encountering the first error. Defaults to false.
+   */
+  stopAtFirstError?: boolean;
 }
diff --git a/test/functional/conditional-validation.spec.ts b/test/functional/conditional-validation.spec.ts
index 40feee59f4..e633763799 100644
--- a/test/functional/conditional-validation.spec.ts
+++ b/test/functional/conditional-validation.spec.ts
@@ -1,95 +1,95 @@
-import {IsNotEmpty, ValidateIf, IsOptional, Equals} from "../../src/decorator/decorators";
-import {Validator} from "../../src/validation/Validator";
+import { IsNotEmpty, ValidateIf, IsOptional, Equals } from '../../src/decorator/decorators';
+import { Validator } from '../../src/validation/Validator';
 
 const validator = new Validator();
 
-describe("conditional validation", () => {
-    it("shouldn't validate a property when the condition is false", () => {
-        expect.assertions(1);
+describe('conditional validation', () => {
+  it("shouldn't validate a property when the condition is false", () => {
+    expect.assertions(1);
 
-        class MyClass {
-            @ValidateIf(o => false)
-            @IsNotEmpty()
-            title: string;
-        }
+    class MyClass {
+      @ValidateIf(o => false)
+      @IsNotEmpty()
+      title: string;
+    }
 
-        const model = new MyClass();
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(0);
-        });
+    const model = new MyClass();
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(0);
     });
+  });
 
-    it("should validate a property when the condition is true", () => {
-        expect.assertions(5);
+  it('should validate a property when the condition is true', () => {
+    expect.assertions(5);
 
-        class MyClass {
-            @ValidateIf(o => true)
-            @IsNotEmpty()
-            title: string = "";
-        }
+    class MyClass {
+      @ValidateIf(o => true)
+      @IsNotEmpty()
+      title: string = '';
+    }
 
-        const model = new MyClass();
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].target).toEqual(model);
-            expect(errors[0].property).toEqual("title");
-            expect(errors[0].constraints).toEqual({ isNotEmpty: "title should not be empty" });
-            expect(errors[0].value).toEqual("");
-        });
+    const model = new MyClass();
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].target).toEqual(model);
+      expect(errors[0].property).toEqual('title');
+      expect(errors[0].constraints).toEqual({ isNotEmpty: 'title should not be empty' });
+      expect(errors[0].value).toEqual('');
     });
+  });
 
-    it("should pass the object being validated to the condition function", () => {
-        expect.assertions(3);
+  it('should pass the object being validated to the condition function', () => {
+    expect.assertions(3);
 
-        class MyClass {
-            @ValidateIf(o => {
-                expect(o).toBeInstanceOf(MyClass);
-                expect(o.title).toEqual("title");
-                return true;
-            })
-            @IsNotEmpty()
-            title: string = "title";
-        }
+    class MyClass {
+      @ValidateIf(o => {
+        expect(o).toBeInstanceOf(MyClass);
+        expect(o.title).toEqual('title');
+        return true;
+      })
+      @IsNotEmpty()
+      title: string = 'title';
+    }
 
-        const model = new MyClass();
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(0);
-        });
+    const model = new MyClass();
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(0);
     });
+  });
 
-    it("should validate a property when value is empty", () => {
-        expect.assertions(5);
+  it('should validate a property when value is empty', () => {
+    expect.assertions(5);
 
-        class MyClass {
-            @IsOptional()
-            @Equals("test")
-            title: string = "";
-        }
+    class MyClass {
+      @IsOptional()
+      @Equals('test')
+      title: string = '';
+    }
 
-        const model = new MyClass();
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].target).toEqual(model);
-            expect(errors[0].property).toEqual("title");
-            expect(errors[0].constraints).toEqual({ equals: "title must be equal to test" });
-            expect(errors[0].value).toEqual("");
-        });
+    const model = new MyClass();
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].target).toEqual(model);
+      expect(errors[0].property).toEqual('title');
+      expect(errors[0].constraints).toEqual({ equals: 'title must be equal to test' });
+      expect(errors[0].value).toEqual('');
     });
+  });
 
-    it("should validate a property when value is supplied", () => {
-        class MyClass {
-            @IsOptional()
-            @Equals("test")
-            title: string = "bad_value";
-        }
+  it('should validate a property when value is supplied', () => {
+    class MyClass {
+      @IsOptional()
+      @Equals('test')
+      title: string = 'bad_value';
+    }
 
-        const model = new MyClass();
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].target).toEqual(model);
-            expect(errors[0].property).toEqual("title");
-            expect(errors[0].constraints).toEqual({ equals: "title must be equal to test" });
-            expect(errors[0].value).toEqual("bad_value");
-        });
+    const model = new MyClass();
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].target).toEqual(model);
+      expect(errors[0].property).toEqual('title');
+      expect(errors[0].constraints).toEqual({ equals: 'title must be equal to test' });
+      expect(errors[0].value).toEqual('bad_value');
     });
+  });
 });
diff --git a/test/functional/custom-decorators.spec.ts b/test/functional/custom-decorators.spec.ts
index 2af65c5a53..b23a66f358 100644
--- a/test/functional/custom-decorators.spec.ts
+++ b/test/functional/custom-decorators.spec.ts
@@ -1,241 +1,238 @@
-import {Validator} from "../../src/validation/Validator";
-import {ValidationArguments} from "../../src/validation/ValidationArguments";
-import {registerDecorator} from "../../src/register-decorator";
-import {ValidationOptions} from "../../src/decorator/ValidationOptions";
-import {ValidatorConstraint} from "../../src/decorator/decorators";
-import {ValidatorConstraintInterface} from "../../src/validation/ValidatorConstraintInterface";
+import { Validator } from '../../src/validation/Validator';
+import { ValidationArguments } from '../../src/validation/ValidationArguments';
+import { registerDecorator } from '../../src/register-decorator';
+import { ValidationOptions } from '../../src/decorator/ValidationOptions';
+import { ValidatorConstraint } from '../../src/decorator/decorators';
+import { ValidatorConstraintInterface } from '../../src/validation/ValidatorConstraintInterface';
 
 const validator = new Validator();
 
-describe("decorator with inline validation", () => {
-    function IsLongerThan(property: string, validationOptions?: ValidationOptions) {
-        return function(object: object, propertyName: string): void {
-            registerDecorator({
-                target: object.constructor,
-                propertyName: propertyName,
-                options: validationOptions,
-                constraints: [property],
-                name: "isLongerThan",
-                validator: {
-                    validate(value: any, args: ValidationArguments): Promise<boolean> | boolean {
-                        const [relatedPropertyName] = args.constraints;
-                        const relatedValue = (args.object as any)[relatedPropertyName];
-                        if (relatedValue === undefined || relatedValue === null) {
-                            return true;
-                        }
-
-                        const result = typeof value === "string" &&
-                            typeof relatedValue === "string" &&
-                            value.length > relatedValue.length;
-
-                        const asPromise = validationOptions &&
-                            validationOptions.context &&
-                            validationOptions.context.promise;
-
-                        return asPromise ? Promise.resolve(result) : result;
-                    }
-                }
-            });
-        };
-    }
-
-    class MyClass {
-        @IsLongerThan("lastName", {
-            context: {foo: "bar"},
-            message: "$property must be longer then $constraint1. Given value: $value"
-        })
-        firstName: string;
-        lastName: string;
-    }
-
-    class MyClassWithAsyncValidator {
-        @IsLongerThan("lastName", {
-            context: {foo: "bar", promise: true},
-            message: "$property must be longer then $constraint1. Given value: $value"
-        })
-        firstName: string;
-        lastName: string;
-    }
-
-    it("if firstName is not empty and lastLame is empty then it should succeed", () => {
-        expect.assertions(1);
-        const model = new MyClass();
-        model.firstName = "hell no world";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(0);
-        });
+describe('decorator with inline validation', () => {
+  function IsLongerThan(property: string, validationOptions?: ValidationOptions) {
+    return function (object: object, propertyName: string): void {
+      registerDecorator({
+        target: object.constructor,
+        propertyName: propertyName,
+        options: validationOptions,
+        constraints: [property],
+        name: 'isLongerThan',
+        validator: {
+          validate(value: any, args: ValidationArguments): Promise<boolean> | boolean {
+            const [relatedPropertyName] = args.constraints;
+            const relatedValue = (args.object as any)[relatedPropertyName];
+            if (relatedValue === undefined || relatedValue === null) {
+              return true;
+            }
+
+            const result =
+              typeof value === 'string' && typeof relatedValue === 'string' && value.length > relatedValue.length;
+
+            const asPromise = validationOptions && validationOptions.context && validationOptions.context.promise;
+
+            return asPromise ? Promise.resolve(result) : result;
+          },
+        },
+      });
+    };
+  }
+
+  class MyClass {
+    @IsLongerThan('lastName', {
+      context: { foo: 'bar' },
+      message: '$property must be longer then $constraint1. Given value: $value',
+    })
+    firstName: string;
+    lastName: string;
+  }
+
+  class MyClassWithAsyncValidator {
+    @IsLongerThan('lastName', {
+      context: { foo: 'bar', promise: true },
+      message: '$property must be longer then $constraint1. Given value: $value',
+    })
+    firstName: string;
+    lastName: string;
+  }
+
+  it('if firstName is not empty and lastLame is empty then it should succeed', () => {
+    expect.assertions(1);
+    const model = new MyClass();
+    model.firstName = 'hell no world';
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(0);
     });
-
-    it("if firstName is empty and lastLame is not empty then it should fail", () => {
-        expect.assertions(2);
-        const model = new MyClass();
-        model.firstName = "";
-        model.lastName = "Kim";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].constraints).toEqual({isLongerThan: "firstName must be longer then lastName. Given value: "});
-        });
+  });
+
+  it('if firstName is empty and lastLame is not empty then it should fail', () => {
+    expect.assertions(2);
+    const model = new MyClass();
+    model.firstName = '';
+    model.lastName = 'Kim';
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].constraints).toEqual({ isLongerThan: 'firstName must be longer then lastName. Given value: ' });
     });
-
-    it("if firstName is shorter then lastLame then it should fail", () => {
-        expect.assertions(2);
-        const model = new MyClass();
-        model.firstName = "Li";
-        model.lastName = "Kim";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].constraints).toEqual({isLongerThan: "firstName must be longer then lastName. Given value: Li"});
-        });
+  });
+
+  it('if firstName is shorter then lastLame then it should fail', () => {
+    expect.assertions(2);
+    const model = new MyClass();
+    model.firstName = 'Li';
+    model.lastName = 'Kim';
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].constraints).toEqual({
+        isLongerThan: 'firstName must be longer then lastName. Given value: Li',
+      });
     });
-
-    it("should include context", () => {
-        expect.assertions(4);
-        const model = new MyClass();
-        const asyncModel = new MyClassWithAsyncValidator();
-        model.firstName = asyncModel.firstName = "Paul";
-        model.lastName = asyncModel.lastName = "Walker";
-
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].contexts).toEqual({isLongerThan: {foo: "bar"}});
-            return validator.validate(asyncModel).then(errors => {
-                expect(errors.length).toEqual(1);
-                expect(errors[0].contexts).toHaveProperty("isLongerThan.foo", "bar");
-            });
-        });
+  });
+
+  it('should include context', () => {
+    expect.assertions(4);
+    const model = new MyClass();
+    const asyncModel = new MyClassWithAsyncValidator();
+    model.firstName = asyncModel.firstName = 'Paul';
+    model.lastName = asyncModel.lastName = 'Walker';
+
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].contexts).toEqual({ isLongerThan: { foo: 'bar' } });
+      return validator.validate(asyncModel).then(errors => {
+        expect(errors.length).toEqual(1);
+        expect(errors[0].contexts).toHaveProperty('isLongerThan.foo', 'bar');
+      });
     });
+  });
 });
 
-describe("decorator with default message", () => {
-    function IsLonger(property: string, validationOptions?: ValidationOptions) {
-        return function(object: object, propertyName: string): void {
-            registerDecorator({
-                target: object.constructor,
-                propertyName: propertyName,
-                options: validationOptions,
-                constraints: [property],
-                name: "isLonger",
-                validator: {
-                    validate(value: any, args: ValidationArguments): boolean {
-                        const [relatedPropertyName] = args.constraints;
-                        const relatedValue = (args.object as any)[relatedPropertyName];
-                        if (relatedValue === undefined || relatedValue === null)
-                            return true;
-
-                        return typeof value === "string" &&
-                            typeof relatedValue === "string" &&
-                            value.length > relatedValue.length;
-                    },
-                    defaultMessage(args: ValidationArguments): string {
-                        return args.property + " must be longer then " + args.constraints[0];
-                    }
-                }
-            });
-        };
-    }
-
-    class SecondClass {
-        @IsLonger("lastName")
-        firstName: string;
-        lastName: string;
-    }
-
-    it("if firstName is not empty and lastLame is empty then it should succeed", () => {
-        expect.assertions(1);
-        const model = new SecondClass();
-        model.firstName = "hell no world";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(0);
-        });
+describe('decorator with default message', () => {
+  function IsLonger(property: string, validationOptions?: ValidationOptions) {
+    return function (object: object, propertyName: string): void {
+      registerDecorator({
+        target: object.constructor,
+        propertyName: propertyName,
+        options: validationOptions,
+        constraints: [property],
+        name: 'isLonger',
+        validator: {
+          validate(value: any, args: ValidationArguments): boolean {
+            const [relatedPropertyName] = args.constraints;
+            const relatedValue = (args.object as any)[relatedPropertyName];
+            if (relatedValue === undefined || relatedValue === null) return true;
+
+            return typeof value === 'string' && typeof relatedValue === 'string' && value.length > relatedValue.length;
+          },
+          defaultMessage(args: ValidationArguments): string {
+            return args.property + ' must be longer then ' + args.constraints[0];
+          },
+        },
+      });
+    };
+  }
+
+  class SecondClass {
+    @IsLonger('lastName')
+    firstName: string;
+    lastName: string;
+  }
+
+  it('if firstName is not empty and lastLame is empty then it should succeed', () => {
+    expect.assertions(1);
+    const model = new SecondClass();
+    model.firstName = 'hell no world';
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(0);
     });
-
-    it("if firstName is empty and lastLame is not empty then it should fail", () => {
-        expect.assertions(2);
-        const model = new SecondClass();
-        model.firstName = "";
-        model.lastName = "Kim";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].constraints).toEqual({isLonger: "firstName must be longer then lastName"});
-        });
+  });
+
+  it('if firstName is empty and lastLame is not empty then it should fail', () => {
+    expect.assertions(2);
+    const model = new SecondClass();
+    model.firstName = '';
+    model.lastName = 'Kim';
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].constraints).toEqual({ isLonger: 'firstName must be longer then lastName' });
     });
-
-    it("if firstName is shorter then lastLame then it should fail", () => {
-        expect.assertions(2);
-        const model = new SecondClass();
-        model.firstName = "Li";
-        model.lastName = "Kim";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].constraints).toEqual({isLonger: "firstName must be longer then lastName"});
-        });
+  });
+
+  it('if firstName is shorter then lastLame then it should fail', () => {
+    expect.assertions(2);
+    const model = new SecondClass();
+    model.firstName = 'Li';
+    model.lastName = 'Kim';
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].constraints).toEqual({ isLonger: 'firstName must be longer then lastName' });
     });
+  });
 });
 
-describe("decorator with separate validation constraint class", () => {
-    @ValidatorConstraint({name: "isShortenThan"})
-    class IsShortenThanConstraint implements ValidatorConstraintInterface {
-        validate(value: any, args: ValidationArguments): boolean {
-            const [relatedPropertyName] = args.constraints;
-            const relatedValue = (args.object as any)[relatedPropertyName];
-            if (value === null || value === undefined)
-                return true;
-
-            return typeof value === "string" &&
-                typeof relatedValue === "string" &&
-                value.length < relatedValue.length;
-        }
-    }
-
-    function IsShorterThan(property: string, validationOptions?: ValidationOptions) {
-        return function(object: object, propertyName: string): void {
-            registerDecorator({
-                target: object.constructor,
-                propertyName: propertyName,
-                options: validationOptions,
-                constraints: [property],
-                validator: IsShortenThanConstraint
-            });
-        };
-    }
-
-    class MyClass {
-        firstName: string;
+describe('decorator with separate validation constraint class', () => {
+  @ValidatorConstraint({ name: 'isShortenThan' })
+  class IsShortenThanConstraint implements ValidatorConstraintInterface {
+    validate(value: any, args: ValidationArguments): boolean {
+      const [relatedPropertyName] = args.constraints;
+      const relatedValue = (args.object as any)[relatedPropertyName];
+      if (value === null || value === undefined) return true;
 
-        @IsShorterThan("firstName", {
-            message: "$property must be shorter then $constraint1. Given value: $value"
-        })
-        lastName: string;
+      return typeof value === 'string' && typeof relatedValue === 'string' && value.length < relatedValue.length;
     }
-
-    it("if firstName is not empty and lastLame is empty then it should succeed", () => {
-        expect.assertions(1);
-        const model = new MyClass();
-        model.firstName = "hell no world";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(0);
-        });
+  }
+
+  function IsShorterThan(property: string, validationOptions?: ValidationOptions) {
+    return function (object: object, propertyName: string): void {
+      registerDecorator({
+        target: object.constructor,
+        propertyName: propertyName,
+        options: validationOptions,
+        constraints: [property],
+        validator: IsShortenThanConstraint,
+      });
+    };
+  }
+
+  class MyClass {
+    firstName: string;
+
+    @IsShorterThan('firstName', {
+      message: '$property must be shorter then $constraint1. Given value: $value',
+    })
+    lastName: string;
+  }
+
+  it('if firstName is not empty and lastLame is empty then it should succeed', () => {
+    expect.assertions(1);
+    const model = new MyClass();
+    model.firstName = 'hell no world';
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(0);
     });
-
-    it("if firstName is empty and lastLame is not empty then it should fail", () => {
-        expect.assertions(2);
-        const model = new MyClass();
-        model.firstName = "";
-        model.lastName = "Kim";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].constraints).toEqual({isShortenThan: "lastName must be shorter then firstName. Given value: Kim"});
-        });
+  });
+
+  it('if firstName is empty and lastLame is not empty then it should fail', () => {
+    expect.assertions(2);
+    const model = new MyClass();
+    model.firstName = '';
+    model.lastName = 'Kim';
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].constraints).toEqual({
+        isShortenThan: 'lastName must be shorter then firstName. Given value: Kim',
+      });
     });
-
-    it("if firstName is shorter then lastLame then it should fail", () => {
-        expect.assertions(2);
-        const model = new MyClass();
-        model.firstName = "Li";
-        model.lastName = "Kim";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].constraints).toEqual({isShortenThan: "lastName must be shorter then firstName. Given value: Kim"});
-        });
+  });
+
+  it('if firstName is shorter then lastLame then it should fail', () => {
+    expect.assertions(2);
+    const model = new MyClass();
+    model.firstName = 'Li';
+    model.lastName = 'Kim';
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].constraints).toEqual({
+        isShortenThan: 'lastName must be shorter then firstName. Given value: Kim',
+      });
     });
+  });
 });
diff --git a/test/functional/inherited-validation.spec.ts b/test/functional/inherited-validation.spec.ts
index acc8aa79b4..04254a9d3b 100644
--- a/test/functional/inherited-validation.spec.ts
+++ b/test/functional/inherited-validation.spec.ts
@@ -1,37 +1,37 @@
-import {Contains, MinLength} from "../../src/decorator/decorators";
-import {Validator} from "../../src/validation/Validator";
+import { Contains, MinLength } from '../../src/decorator/decorators';
+import { Validator } from '../../src/validation/Validator';
 
 const validator = new Validator();
 
-describe("inherited validation", () => {
-    it("should validate inherited properties", () => {
-        expect.assertions(9);
+describe('inherited validation', () => {
+  it('should validate inherited properties', () => {
+    expect.assertions(9);
 
-        class MyClass {
-            @Contains("hello")
-            title: string;
-        }
+    class MyClass {
+      @Contains('hello')
+      title: string;
+    }
 
-        class MySubClass extends MyClass {
-            @MinLength(5)
-            name: string;
-        }
+    class MySubClass extends MyClass {
+      @MinLength(5)
+      name: string;
+    }
 
-        const model = new MySubClass();
-        model.title = "helo world";
-        model.name = "my";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(2);
-            // subclass own props are validated first
-            expect(errors[0].target).toEqual(model);
-            expect(errors[0].property).toEqual("name");
-            expect(errors[0].constraints).toEqual({ minLength: "name must be longer than or equal to 5 characters" });
-            expect(errors[0].value).toEqual("my");
-            // parent props are validated afterwards
-            expect(errors[1].target).toEqual(model);
-            expect(errors[1].property).toEqual("title");
-            expect(errors[1].constraints).toEqual({ contains: "title must contain a hello string" });
-            expect(errors[1].value).toEqual("helo world");
-        });
+    const model = new MySubClass();
+    model.title = 'helo world';
+    model.name = 'my';
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(2);
+      // subclass own props are validated first
+      expect(errors[0].target).toEqual(model);
+      expect(errors[0].property).toEqual('name');
+      expect(errors[0].constraints).toEqual({ minLength: 'name must be longer than or equal to 5 characters' });
+      expect(errors[0].value).toEqual('my');
+      // parent props are validated afterwards
+      expect(errors[1].target).toEqual(model);
+      expect(errors[1].property).toEqual('title');
+      expect(errors[1].constraints).toEqual({ contains: 'title must contain a hello string' });
+      expect(errors[1].value).toEqual('helo world');
     });
+  });
 });
diff --git a/test/functional/nested-validation.spec.ts b/test/functional/nested-validation.spec.ts
index 6255e80cf7..862af95ce2 100644
--- a/test/functional/nested-validation.spec.ts
+++ b/test/functional/nested-validation.spec.ts
@@ -1,305 +1,310 @@
-import {Contains, IsDefined, MinLength, ValidateNested} from "../../src/decorator/decorators";
-import {Validator} from "../../src/validation/Validator";
-import {ValidationTypes} from "../../src/validation/ValidationTypes";
+import { Contains, IsDefined, MinLength, ValidateNested } from '../../src/decorator/decorators';
+import { Validator } from '../../src/validation/Validator';
+import { ValidationTypes } from '../../src/validation/ValidationTypes';
 
 const validator = new Validator();
 
-describe("nested validation", () => {
-    it("should not validate missing nested objects", () => {
-        expect.assertions(4);
+describe('nested validation', () => {
+  it('should not validate missing nested objects', () => {
+    expect.assertions(4);
 
-        class MySubClass {
-            @MinLength(5)
-            name: string;
-        }
+    class MySubClass {
+      @MinLength(5)
+      name: string;
+    }
 
-        class MyClass {
-            @Contains("hello")
-            title: string;
+    class MyClass {
+      @Contains('hello')
+      title: string;
 
-            @ValidateNested() @IsDefined()
-            mySubClass: MySubClass;
-        }
+      @ValidateNested()
+      @IsDefined()
+      mySubClass: MySubClass;
+    }
 
-        const model: MyClass = new MyClass();
-        model.title = "helo";
+    const model: MyClass = new MyClass();
+    model.title = 'helo';
 
-        return validator.validate(model).then(errors => {
-            expect(errors[1].target).toEqual(model);
-            expect(errors[1].value).toBeUndefined();
-            expect(errors[1].property).toEqual("mySubClass");
-            expect(errors[1].constraints).toEqual({isDefined: "mySubClass should not be null or undefined"});
-        });
+    return validator.validate(model).then(errors => {
+      expect(errors[1].target).toEqual(model);
+      expect(errors[1].value).toBeUndefined();
+      expect(errors[1].property).toEqual('mySubClass');
+      expect(errors[1].constraints).toEqual({ isDefined: 'mySubClass should not be null or undefined' });
     });
-
-    it("should validate nested objects", () => {
-        expect.assertions(55);
-
-        class MySubClass {
-            @MinLength(5)
-            name: string;
-        }
-
-        class MyClass {
-            @Contains("hello")
-            title: string;
-
-            @ValidateNested()
-            mySubClass: MySubClass;
-
-            @ValidateNested()
-            mySubClasses: MySubClass[];
-
-            @ValidateNested()
-            mySubSubClasses: MySubClass[][];
-
-            @ValidateNested()
-            mySubSubSubClasses: MySubClass[][][];
-        }
-
-        const model = new MyClass();
-        model.title = "helo world";
-        model.mySubClass = new MySubClass();
-        model.mySubClass.name = "my";
-        model.mySubClasses = [new MySubClass(), new MySubClass()];
-        model.mySubClasses[0].name = "my";
-        model.mySubClasses[1].name = "not-short";
-        model.mySubSubClasses = [[new MySubClass()]];
-        model.mySubSubClasses[0][0].name = "sub";
-        model.mySubSubSubClasses = [[[new MySubClass()]]];
-        model.mySubSubSubClasses[0][0][0].name = "sub";
-
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(5);
-
-            expect(errors[0].target).toEqual(model);
-            expect(errors[0].property).toEqual("title");
-            expect(errors[0].constraints).toEqual({contains: "title must contain a hello string"});
-            expect(errors[0].value).toEqual("helo world");
-
-            expect(errors[1].target).toEqual(model);
-            expect(errors[1].property).toEqual("mySubClass");
-            expect(errors[1].value).toEqual(model.mySubClass);
-            expect(errors[1].constraints).toBeUndefined();
-            const subError1 = errors[1].children[0];
-            expect(subError1.target).toEqual(model.mySubClass);
-            expect(subError1.property).toEqual("name");
-            expect(subError1.constraints).toEqual({minLength: "name must be longer than or equal to 5 characters"});
-            expect(subError1.value).toEqual("my");
-
-            expect(errors[2].target).toEqual(model);
-            expect(errors[2].property).toEqual("mySubClasses");
-            expect(errors[2].value).toEqual(model.mySubClasses);
-            expect(errors[2].constraints).toBeUndefined();
-            const subError2 = errors[2].children[0];
-            expect(subError2.target).toEqual(model.mySubClasses);
-            expect(subError2.value).toEqual(model.mySubClasses[0]);
-            expect(subError2.property).toEqual("0");
-            const subSubError = subError2.children[0];
-            expect(subSubError.target).toEqual(model.mySubClasses[0]);
-            expect(subSubError.property).toEqual("name");
-            expect(subSubError.constraints).toEqual({minLength: "name must be longer than or equal to 5 characters"});
-            expect(subSubError.value).toEqual("my");
-
-            expect(errors[3].target).toEqual(model);
-            expect(errors[3].property).toEqual("mySubSubClasses");
-            expect(errors[3].value).toEqual(model.mySubSubClasses);
-            expect(errors[3].constraints).toBeUndefined();
-            const subError3 = errors[3].children[0];
-            expect(subError3.target).toEqual(model.mySubSubClasses);
-            expect(subError3.value).toEqual(model.mySubSubClasses[0]);
-            expect(subError3.property).toEqual("0");
-            const subSubError3 = subError3.children[0];
-            expect(subSubError3.target).toEqual(model.mySubSubClasses[0]);
-            expect(subSubError3.value).toEqual(model.mySubSubClasses[0][0]);
-            expect(subSubError3.property).toEqual("0");
-            const subSubSubError3 = subSubError3.children[0];
-            expect(subSubSubError3.target).toEqual(model.mySubSubClasses[0][0]);
-            expect(subSubSubError3.property).toEqual("name");
-            expect(subSubSubError3.constraints).toEqual({minLength: "name must be longer than or equal to 5 characters"});
-            expect(subSubSubError3.value).toEqual("sub");
-
-            expect(errors[4].target).toEqual(model);
-            expect(errors[4].property).toEqual("mySubSubSubClasses");
-            expect(errors[4].value).toEqual(model.mySubSubSubClasses);
-            expect(errors[4].constraints).toBeUndefined();
-            const subError4 = errors[4].children[0];
-            expect(subError4.target).toEqual(model.mySubSubSubClasses);
-            expect(subError4.value).toEqual(model.mySubSubSubClasses[0]);
-            expect(subError4.property).toEqual("0");
-            const subSubError4 = subError4.children[0];
-            expect(subSubError4.target).toEqual(model.mySubSubSubClasses[0]);
-            expect(subSubError4.value).toEqual(model.mySubSubSubClasses[0][0]);
-            expect(subSubError4.property).toEqual("0");
-            const subSubSubError4 = subSubError4.children[0];
-            expect(subSubSubError4.target).toEqual(model.mySubSubSubClasses[0][0]);
-            expect(subSubSubError4.value).toEqual(model.mySubSubSubClasses[0][0][0]);
-            expect(subSubSubError4.property).toEqual("0");
-            const subSubSubSubError4 = subSubSubError4.children[0];
-            expect(subSubSubSubError4.target).toEqual(model.mySubSubSubClasses[0][0][0]);
-            expect(subSubSubSubError4.property).toEqual("name");
-            expect(subSubSubSubError4.constraints).toEqual({minLength: "name must be longer than or equal to 5 characters"});
-            expect(subSubSubSubError4.value).toEqual("sub");
-        });
+  });
+
+  it('should validate nested objects', () => {
+    expect.assertions(55);
+
+    class MySubClass {
+      @MinLength(5)
+      name: string;
+    }
+
+    class MyClass {
+      @Contains('hello')
+      title: string;
+
+      @ValidateNested()
+      mySubClass: MySubClass;
+
+      @ValidateNested()
+      mySubClasses: MySubClass[];
+
+      @ValidateNested()
+      mySubSubClasses: MySubClass[][];
+
+      @ValidateNested()
+      mySubSubSubClasses: MySubClass[][][];
+    }
+
+    const model = new MyClass();
+    model.title = 'helo world';
+    model.mySubClass = new MySubClass();
+    model.mySubClass.name = 'my';
+    model.mySubClasses = [new MySubClass(), new MySubClass()];
+    model.mySubClasses[0].name = 'my';
+    model.mySubClasses[1].name = 'not-short';
+    model.mySubSubClasses = [[new MySubClass()]];
+    model.mySubSubClasses[0][0].name = 'sub';
+    model.mySubSubSubClasses = [[[new MySubClass()]]];
+    model.mySubSubSubClasses[0][0][0].name = 'sub';
+
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(5);
+
+      expect(errors[0].target).toEqual(model);
+      expect(errors[0].property).toEqual('title');
+      expect(errors[0].constraints).toEqual({ contains: 'title must contain a hello string' });
+      expect(errors[0].value).toEqual('helo world');
+
+      expect(errors[1].target).toEqual(model);
+      expect(errors[1].property).toEqual('mySubClass');
+      expect(errors[1].value).toEqual(model.mySubClass);
+      expect(errors[1].constraints).toBeUndefined();
+      const subError1 = errors[1].children[0];
+      expect(subError1.target).toEqual(model.mySubClass);
+      expect(subError1.property).toEqual('name');
+      expect(subError1.constraints).toEqual({ minLength: 'name must be longer than or equal to 5 characters' });
+      expect(subError1.value).toEqual('my');
+
+      expect(errors[2].target).toEqual(model);
+      expect(errors[2].property).toEqual('mySubClasses');
+      expect(errors[2].value).toEqual(model.mySubClasses);
+      expect(errors[2].constraints).toBeUndefined();
+      const subError2 = errors[2].children[0];
+      expect(subError2.target).toEqual(model.mySubClasses);
+      expect(subError2.value).toEqual(model.mySubClasses[0]);
+      expect(subError2.property).toEqual('0');
+      const subSubError = subError2.children[0];
+      expect(subSubError.target).toEqual(model.mySubClasses[0]);
+      expect(subSubError.property).toEqual('name');
+      expect(subSubError.constraints).toEqual({ minLength: 'name must be longer than or equal to 5 characters' });
+      expect(subSubError.value).toEqual('my');
+
+      expect(errors[3].target).toEqual(model);
+      expect(errors[3].property).toEqual('mySubSubClasses');
+      expect(errors[3].value).toEqual(model.mySubSubClasses);
+      expect(errors[3].constraints).toBeUndefined();
+      const subError3 = errors[3].children[0];
+      expect(subError3.target).toEqual(model.mySubSubClasses);
+      expect(subError3.value).toEqual(model.mySubSubClasses[0]);
+      expect(subError3.property).toEqual('0');
+      const subSubError3 = subError3.children[0];
+      expect(subSubError3.target).toEqual(model.mySubSubClasses[0]);
+      expect(subSubError3.value).toEqual(model.mySubSubClasses[0][0]);
+      expect(subSubError3.property).toEqual('0');
+      const subSubSubError3 = subSubError3.children[0];
+      expect(subSubSubError3.target).toEqual(model.mySubSubClasses[0][0]);
+      expect(subSubSubError3.property).toEqual('name');
+      expect(subSubSubError3.constraints).toEqual({ minLength: 'name must be longer than or equal to 5 characters' });
+      expect(subSubSubError3.value).toEqual('sub');
+
+      expect(errors[4].target).toEqual(model);
+      expect(errors[4].property).toEqual('mySubSubSubClasses');
+      expect(errors[4].value).toEqual(model.mySubSubSubClasses);
+      expect(errors[4].constraints).toBeUndefined();
+      const subError4 = errors[4].children[0];
+      expect(subError4.target).toEqual(model.mySubSubSubClasses);
+      expect(subError4.value).toEqual(model.mySubSubSubClasses[0]);
+      expect(subError4.property).toEqual('0');
+      const subSubError4 = subError4.children[0];
+      expect(subSubError4.target).toEqual(model.mySubSubSubClasses[0]);
+      expect(subSubError4.value).toEqual(model.mySubSubSubClasses[0][0]);
+      expect(subSubError4.property).toEqual('0');
+      const subSubSubError4 = subSubError4.children[0];
+      expect(subSubSubError4.target).toEqual(model.mySubSubSubClasses[0][0]);
+      expect(subSubSubError4.value).toEqual(model.mySubSubSubClasses[0][0][0]);
+      expect(subSubSubError4.property).toEqual('0');
+      const subSubSubSubError4 = subSubSubError4.children[0];
+      expect(subSubSubSubError4.target).toEqual(model.mySubSubSubClasses[0][0][0]);
+      expect(subSubSubSubError4.property).toEqual('name');
+      expect(subSubSubSubError4.constraints).toEqual({
+        minLength: 'name must be longer than or equal to 5 characters',
+      });
+      expect(subSubSubSubError4.value).toEqual('sub');
     });
+  });
 
-    it("should validate when nested is not object", () => {
-        expect.assertions(4);
+  it('should validate when nested is not object', () => {
+    expect.assertions(4);
 
-        class MySubClass {
-            @MinLength(5)
-            name: string;
-        }
+    class MySubClass {
+      @MinLength(5)
+      name: string;
+    }
 
-        class MyClass {
-            @ValidateNested()
-            mySubClass: MySubClass;
-        }
+    class MyClass {
+      @ValidateNested()
+      mySubClass: MySubClass;
+    }
 
-        const model = new MyClass();
-        model.mySubClass = "invalidnested object" as any;
+    const model = new MyClass();
+    model.mySubClass = 'invalidnested object' as any;
 
-        return validator.validate(model).then(errors => {
-            expect(errors[0].target).toEqual(model);
-            expect(errors[0].property).toEqual("mySubClass");
-            expect(errors[0].children.length).toEqual(1);
+    return validator.validate(model).then(errors => {
+      expect(errors[0].target).toEqual(model);
+      expect(errors[0].property).toEqual('mySubClass');
+      expect(errors[0].children.length).toEqual(1);
 
-            const subError = errors[0].children[0];
-            expect(subError.constraints).toEqual({[ValidationTypes.NESTED_VALIDATION]: "nested property mySubClass must be either object or array"});
-        });
+      const subError = errors[0].children[0];
+      expect(subError.constraints).toEqual({
+        [ValidationTypes.NESTED_VALIDATION]: 'nested property mySubClass must be either object or array',
+      });
     });
-
-    it("should validate nested set", () => {
-        expect.assertions(24);
-
-        class MySubClass {
-            @MinLength(5)
-            name: string;
-        }
-
-        class MyClass {
-            @Contains("hello")
-            title: string;
-
-            @ValidateNested()
-            mySubClass: MySubClass;
-
-            @ValidateNested()
-            mySubClasses: Set<MySubClass>;
-        }
-
-        const model = new MyClass();
-        model.title = "helo world";
-        model.mySubClass = new MySubClass();
-        model.mySubClass.name = "my";
-        model.mySubClasses = new Set();
-
-        const submodel1 = new MySubClass();
-        submodel1.name = "my";
-        model.mySubClasses.add(submodel1);
-
-        const submodel2 = new MySubClass();
-        submodel2.name = "not-short";
-        model.mySubClasses.add(submodel2);
-
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(3);
-
-            expect(errors[0].target).toEqual(model);
-            expect(errors[0].property).toEqual("title");
-            expect(errors[0].constraints).toEqual({contains: "title must contain a hello string"});
-            expect(errors[0].value).toEqual("helo world");
-
-            expect(errors[1].target).toEqual(model);
-            expect(errors[1].property).toEqual("mySubClass");
-            expect(errors[1].value).toEqual(model.mySubClass);
-            expect(errors[1].constraints).toBeUndefined();
-            const subError1 = errors[1].children[0];
-            expect(subError1.target).toEqual(model.mySubClass);
-            expect(subError1.property).toEqual("name");
-            expect(subError1.constraints).toEqual({minLength: "name must be longer than or equal to 5 characters"});
-            expect(subError1.value).toEqual("my");
-
-            expect(errors[2].target).toEqual(model);
-            expect(errors[2].property).toEqual("mySubClasses");
-            expect(errors[2].value).toEqual(model.mySubClasses);
-            expect(errors[2].constraints).toBeUndefined();
-            const subError2 = errors[2].children[0];
-            expect(subError2.target).toEqual(model.mySubClasses);
-            expect(subError2.value).toEqual(submodel1);
-            expect(subError2.property).toEqual("0");
-            const subSubError = subError2.children[0];
-            expect(subSubError.target).toEqual(submodel1);
-            expect(subSubError.property).toEqual("name");
-            expect(subSubError.constraints).toEqual({minLength: "name must be longer than or equal to 5 characters"});
-            expect(subSubError.value).toEqual("my");
-        });
+  });
+
+  it('should validate nested set', () => {
+    expect.assertions(24);
+
+    class MySubClass {
+      @MinLength(5)
+      name: string;
+    }
+
+    class MyClass {
+      @Contains('hello')
+      title: string;
+
+      @ValidateNested()
+      mySubClass: MySubClass;
+
+      @ValidateNested()
+      mySubClasses: Set<MySubClass>;
+    }
+
+    const model = new MyClass();
+    model.title = 'helo world';
+    model.mySubClass = new MySubClass();
+    model.mySubClass.name = 'my';
+    model.mySubClasses = new Set();
+
+    const submodel1 = new MySubClass();
+    submodel1.name = 'my';
+    model.mySubClasses.add(submodel1);
+
+    const submodel2 = new MySubClass();
+    submodel2.name = 'not-short';
+    model.mySubClasses.add(submodel2);
+
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(3);
+
+      expect(errors[0].target).toEqual(model);
+      expect(errors[0].property).toEqual('title');
+      expect(errors[0].constraints).toEqual({ contains: 'title must contain a hello string' });
+      expect(errors[0].value).toEqual('helo world');
+
+      expect(errors[1].target).toEqual(model);
+      expect(errors[1].property).toEqual('mySubClass');
+      expect(errors[1].value).toEqual(model.mySubClass);
+      expect(errors[1].constraints).toBeUndefined();
+      const subError1 = errors[1].children[0];
+      expect(subError1.target).toEqual(model.mySubClass);
+      expect(subError1.property).toEqual('name');
+      expect(subError1.constraints).toEqual({ minLength: 'name must be longer than or equal to 5 characters' });
+      expect(subError1.value).toEqual('my');
+
+      expect(errors[2].target).toEqual(model);
+      expect(errors[2].property).toEqual('mySubClasses');
+      expect(errors[2].value).toEqual(model.mySubClasses);
+      expect(errors[2].constraints).toBeUndefined();
+      const subError2 = errors[2].children[0];
+      expect(subError2.target).toEqual(model.mySubClasses);
+      expect(subError2.value).toEqual(submodel1);
+      expect(subError2.property).toEqual('0');
+      const subSubError = subError2.children[0];
+      expect(subSubError.target).toEqual(submodel1);
+      expect(subSubError.property).toEqual('name');
+      expect(subSubError.constraints).toEqual({ minLength: 'name must be longer than or equal to 5 characters' });
+      expect(subSubError.value).toEqual('my');
     });
-
-    it("should validate nested map", () => {
-        expect.assertions(24);
-
-        class MySubClass {
-            @MinLength(5)
-            name: string;
-        }
-
-        class MyClass {
-            @Contains("hello")
-            title: string;
-
-            @ValidateNested()
-            mySubClass: MySubClass;
-
-            @ValidateNested()
-            mySubClasses: Map<string, MySubClass>;
-        }
-
-        const model = new MyClass();
-        model.title = "helo world";
-        model.mySubClass = new MySubClass();
-        model.mySubClass.name = "my";
-        model.mySubClasses = new Map();
-
-        const submodel1 = new MySubClass();
-        submodel1.name = "my";
-        model.mySubClasses.set("key1", submodel1);
-
-        const submodel2 = new MySubClass();
-        submodel2.name = "not-short";
-        model.mySubClasses.set("key2", submodel2);
-
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(3);
-
-            expect(errors[0].target).toEqual(model);
-            expect(errors[0].property).toEqual("title");
-            expect(errors[0].constraints).toEqual({contains: "title must contain a hello string"});
-            expect(errors[0].value).toEqual("helo world");
-
-            expect(errors[1].target).toEqual(model);
-            expect(errors[1].property).toEqual("mySubClass");
-            expect(errors[1].value).toEqual(model.mySubClass);
-            expect(errors[1].constraints).toBeUndefined();
-            const subError1 = errors[1].children[0];
-            expect(subError1.target).toEqual(model.mySubClass);
-            expect(subError1.property).toEqual("name");
-            expect(subError1.constraints).toEqual({minLength: "name must be longer than or equal to 5 characters"});
-            expect(subError1.value).toEqual("my");
-
-            expect(errors[2].target).toEqual(model);
-            expect(errors[2].property).toEqual("mySubClasses");
-            expect(errors[2].value).toEqual(model.mySubClasses);
-            expect(errors[2].constraints).toBeUndefined();
-            const subError2 = errors[2].children[0];
-            expect(subError2.target).toEqual(model.mySubClasses);
-            expect(subError2.value).toEqual(submodel1);
-            expect(subError2.property).toEqual("key1");
-            const subSubError = subError2.children[0];
-            expect(subSubError.target).toEqual(submodel1);
-            expect(subSubError.property).toEqual("name");
-            expect(subSubError.constraints).toEqual({minLength: "name must be longer than or equal to 5 characters"});
-            expect(subSubError.value).toEqual("my");
-        });
+  });
+
+  it('should validate nested map', () => {
+    expect.assertions(24);
+
+    class MySubClass {
+      @MinLength(5)
+      name: string;
+    }
+
+    class MyClass {
+      @Contains('hello')
+      title: string;
+
+      @ValidateNested()
+      mySubClass: MySubClass;
+
+      @ValidateNested()
+      mySubClasses: Map<string, MySubClass>;
+    }
+
+    const model = new MyClass();
+    model.title = 'helo world';
+    model.mySubClass = new MySubClass();
+    model.mySubClass.name = 'my';
+    model.mySubClasses = new Map();
+
+    const submodel1 = new MySubClass();
+    submodel1.name = 'my';
+    model.mySubClasses.set('key1', submodel1);
+
+    const submodel2 = new MySubClass();
+    submodel2.name = 'not-short';
+    model.mySubClasses.set('key2', submodel2);
+
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(3);
+
+      expect(errors[0].target).toEqual(model);
+      expect(errors[0].property).toEqual('title');
+      expect(errors[0].constraints).toEqual({ contains: 'title must contain a hello string' });
+      expect(errors[0].value).toEqual('helo world');
+
+      expect(errors[1].target).toEqual(model);
+      expect(errors[1].property).toEqual('mySubClass');
+      expect(errors[1].value).toEqual(model.mySubClass);
+      expect(errors[1].constraints).toBeUndefined();
+      const subError1 = errors[1].children[0];
+      expect(subError1.target).toEqual(model.mySubClass);
+      expect(subError1.property).toEqual('name');
+      expect(subError1.constraints).toEqual({ minLength: 'name must be longer than or equal to 5 characters' });
+      expect(subError1.value).toEqual('my');
+
+      expect(errors[2].target).toEqual(model);
+      expect(errors[2].property).toEqual('mySubClasses');
+      expect(errors[2].value).toEqual(model.mySubClasses);
+      expect(errors[2].constraints).toBeUndefined();
+      const subError2 = errors[2].children[0];
+      expect(subError2.target).toEqual(model.mySubClasses);
+      expect(subError2.value).toEqual(submodel1);
+      expect(subError2.property).toEqual('key1');
+      const subSubError = subError2.children[0];
+      expect(subSubError.target).toEqual(submodel1);
+      expect(subSubError.property).toEqual('name');
+      expect(subSubError.constraints).toEqual({ minLength: 'name must be longer than or equal to 5 characters' });
+      expect(subSubError.value).toEqual('my');
     });
+  });
 });
diff --git a/test/functional/promise-validation.spec.ts b/test/functional/promise-validation.spec.ts
index 4ddbdcb804..0de1d1ac3c 100644
--- a/test/functional/promise-validation.spec.ts
+++ b/test/functional/promise-validation.spec.ts
@@ -1,153 +1,157 @@
-import {Contains, IsDefined, MinLength, ValidateNested, ValidatePromise} from "../../src/decorator/decorators";
-import {Validator} from "../../src/validation/Validator";
-import {ValidationTypes} from "../../src/validation/ValidationTypes";
+import { Contains, IsDefined, MinLength, ValidateNested, ValidatePromise } from '../../src/decorator/decorators';
+import { Validator } from '../../src/validation/Validator';
+import { ValidationTypes } from '../../src/validation/ValidationTypes';
 
 const validator = new Validator();
 
-describe("promise validation", () => {
-    it("should not validate missing nested objects", () => {
-        expect.assertions(4);
-
-        class MySubClass {
-            @MinLength(5)
-            name: string;
-        }
-
-        class MyClass {
-            @Contains("hello")
-            title: string;
-
-            @ValidatePromise() @ValidateNested() @IsDefined()
-            mySubClass: Promise<MySubClass>;
-        }
-
-        const model: any = new MyClass();
-        model.title = "helo";
-
-        return validator.validate(model).then(errors => {
-            expect(errors[1].target).toEqual(model);
-            expect(errors[1].value).toBeUndefined();
-            expect(errors[1].property).toEqual("mySubClass");
-            expect(errors[1].constraints).toEqual({isDefined: "mySubClass should not be null or undefined"});
-        });
+describe('promise validation', () => {
+  it('should not validate missing nested objects', () => {
+    expect.assertions(4);
+
+    class MySubClass {
+      @MinLength(5)
+      name: string;
+    }
+
+    class MyClass {
+      @Contains('hello')
+      title: string;
+
+      @ValidatePromise()
+      @ValidateNested()
+      @IsDefined()
+      mySubClass: Promise<MySubClass>;
+    }
+
+    const model: any = new MyClass();
+    model.title = 'helo';
+
+    return validator.validate(model).then(errors => {
+      expect(errors[1].target).toEqual(model);
+      expect(errors[1].value).toBeUndefined();
+      expect(errors[1].property).toEqual('mySubClass');
+      expect(errors[1].constraints).toEqual({ isDefined: 'mySubClass should not be null or undefined' });
     });
-
-    it("should validate nested objects", () => {
-        expect.assertions(24);
-
-        class MySubClass {
-            @MinLength(5)
-            name: string;
-        }
-
-        class MyClass {
-            @Contains("hello")
-            title: string;
-
-            @ValidatePromise() @ValidateNested()
-            mySubClass: Promise<MySubClass>;
-
-            @ValidatePromise() @ValidateNested()
-            mySubClasses: Promise<MySubClass[]>;
-        }
-
-        const model = new MyClass();
-        model.title = "helo world";
-        const mySubClass = new MySubClass();
-        mySubClass.name = "my";
-        model.mySubClass = Promise.resolve(mySubClass);
-        const mySubClasses = [new MySubClass(), new MySubClass()];
-        mySubClasses[0].name = "my";
-        mySubClasses[1].name = "not-short";
-        model.mySubClasses = Promise.resolve(mySubClasses);
-        return validator.validate(model).then(errors => {
-            return Promise.all([
-                model.mySubClass,
-                model.mySubClasses
-            ]).then(([modelMySubClass, modelMySubClasses]) => {
-                expect(errors.length).toEqual(3);
-
-                expect(errors[0].target).toEqual(model);
-                expect(errors[0].property).toEqual("title");
-                expect(errors[0].constraints).toEqual({contains: "title must contain a hello string"});
-                expect(errors[0].value).toEqual("helo world");
-
-                expect(errors[1].target).toEqual(model);
-                expect(errors[1].property).toEqual("mySubClass");
-                expect(errors[1].value).toEqual(modelMySubClass);
-                expect(errors[1].constraints).toBeUndefined();
-                const subError1 = errors[1].children[0];
-                expect(subError1.target).toEqual(modelMySubClass);
-                expect(subError1.property).toEqual("name");
-                expect(subError1.constraints).toEqual({minLength: "name must be longer than or equal to 5 characters"});
-                expect(subError1.value).toEqual("my");
-
-                expect(errors[2].target).toEqual(model);
-                expect(errors[2].property).toEqual("mySubClasses");
-                expect(errors[2].value).toEqual(modelMySubClasses);
-                expect(errors[2].constraints).toBeUndefined();
-                const subError2 = errors[2].children[0];
-                expect(subError2.target).toEqual(modelMySubClasses);
-                expect(subError2.value).toEqual(modelMySubClasses[0]);
-                expect(subError2.property).toEqual("0");
-                const subSubError = subError2.children[0];
-                expect(subSubError.target).toEqual(modelMySubClasses[0]);
-                expect(subSubError.property).toEqual("name");
-                expect(subSubError.constraints).toEqual({minLength: "name must be longer than or equal to 5 characters"});
-                expect(subSubError.value).toEqual("my");
-            });
-        });
+  });
+
+  it('should validate nested objects', () => {
+    expect.assertions(24);
+
+    class MySubClass {
+      @MinLength(5)
+      name: string;
+    }
+
+    class MyClass {
+      @Contains('hello')
+      title: string;
+
+      @ValidatePromise()
+      @ValidateNested()
+      mySubClass: Promise<MySubClass>;
+
+      @ValidatePromise()
+      @ValidateNested()
+      mySubClasses: Promise<MySubClass[]>;
+    }
+
+    const model = new MyClass();
+    model.title = 'helo world';
+    const mySubClass = new MySubClass();
+    mySubClass.name = 'my';
+    model.mySubClass = Promise.resolve(mySubClass);
+    const mySubClasses = [new MySubClass(), new MySubClass()];
+    mySubClasses[0].name = 'my';
+    mySubClasses[1].name = 'not-short';
+    model.mySubClasses = Promise.resolve(mySubClasses);
+    return validator.validate(model).then(errors => {
+      return Promise.all([model.mySubClass, model.mySubClasses]).then(([modelMySubClass, modelMySubClasses]) => {
+        expect(errors.length).toEqual(3);
+
+        expect(errors[0].target).toEqual(model);
+        expect(errors[0].property).toEqual('title');
+        expect(errors[0].constraints).toEqual({ contains: 'title must contain a hello string' });
+        expect(errors[0].value).toEqual('helo world');
+
+        expect(errors[1].target).toEqual(model);
+        expect(errors[1].property).toEqual('mySubClass');
+        expect(errors[1].value).toEqual(modelMySubClass);
+        expect(errors[1].constraints).toBeUndefined();
+        const subError1 = errors[1].children[0];
+        expect(subError1.target).toEqual(modelMySubClass);
+        expect(subError1.property).toEqual('name');
+        expect(subError1.constraints).toEqual({ minLength: 'name must be longer than or equal to 5 characters' });
+        expect(subError1.value).toEqual('my');
+
+        expect(errors[2].target).toEqual(model);
+        expect(errors[2].property).toEqual('mySubClasses');
+        expect(errors[2].value).toEqual(modelMySubClasses);
+        expect(errors[2].constraints).toBeUndefined();
+        const subError2 = errors[2].children[0];
+        expect(subError2.target).toEqual(modelMySubClasses);
+        expect(subError2.value).toEqual(modelMySubClasses[0]);
+        expect(subError2.property).toEqual('0');
+        const subSubError = subError2.children[0];
+        expect(subSubError.target).toEqual(modelMySubClasses[0]);
+        expect(subSubError.property).toEqual('name');
+        expect(subSubError.constraints).toEqual({ minLength: 'name must be longer than or equal to 5 characters' });
+        expect(subSubError.value).toEqual('my');
+      });
     });
-
-    it("should validate when nested is not object", () => {
-        expect.assertions(4);
-
-        class MySubClass {
-            @MinLength(5)
-            name: string;
-        }
-
-        class MyClass {
-            @ValidatePromise() @ValidateNested()
-            mySubClass: MySubClass;
-
-        }
-
-        const model = new MyClass();
-        model.mySubClass = "invalidnested object" as any;
-
-        return validator.validate(model).then(errors => {
-            expect(errors[0].target).toEqual(model);
-            expect(errors[0].property).toEqual("mySubClass");
-            expect(errors[0].children.length).toEqual(1);
-
-            const subError = errors[0].children[0];
-            expect(subError.constraints).toEqual({[ValidationTypes.NESTED_VALIDATION]: "nested property mySubClass must be either object or array"});
-        });
+  });
+
+  it('should validate when nested is not object', () => {
+    expect.assertions(4);
+
+    class MySubClass {
+      @MinLength(5)
+      name: string;
+    }
+
+    class MyClass {
+      @ValidatePromise()
+      @ValidateNested()
+      mySubClass: MySubClass;
+    }
+
+    const model = new MyClass();
+    model.mySubClass = 'invalidnested object' as any;
+
+    return validator.validate(model).then(errors => {
+      expect(errors[0].target).toEqual(model);
+      expect(errors[0].property).toEqual('mySubClass');
+      expect(errors[0].children.length).toEqual(1);
+
+      const subError = errors[0].children[0];
+      expect(subError.constraints).toEqual({
+        [ValidationTypes.NESTED_VALIDATION]: 'nested property mySubClass must be either object or array',
+      });
     });
+  });
 
-    it("should validate array promise", () => {
-        expect.assertions(5);
+  it('should validate array promise', () => {
+    expect.assertions(5);
 
-        class MyClass {
-            @ValidatePromise() @MinLength(2)
-            arrProperty: Promise<string[]>;
-        }
+    class MyClass {
+      @ValidatePromise()
+      @MinLength(2)
+      arrProperty: Promise<string[]>;
+    }
 
-        const model = new MyClass();
-        model.arrProperty = Promise.resolve(["one"]);
+    const model = new MyClass();
+    model.arrProperty = Promise.resolve(['one']);
 
-        return validator.validate(model).then(errors => {
-            return Promise.all([
-                model.arrProperty,
-            ]).then(([modelArrProperty]) => {
-                expect(errors.length).toEqual(1);
+    return validator.validate(model).then(errors => {
+      return Promise.all([model.arrProperty]).then(([modelArrProperty]) => {
+        expect(errors.length).toEqual(1);
 
-                expect(errors[0].target).toEqual(model);
-                expect(errors[0].property).toEqual("arrProperty");
-                expect(errors[0].constraints).toEqual({minLength: "arrProperty must be longer than or equal to 2 characters"});
-                expect(errors[0].value).toEqual(modelArrProperty);
-            });
+        expect(errors[0].target).toEqual(model);
+        expect(errors[0].property).toEqual('arrProperty');
+        expect(errors[0].constraints).toEqual({
+          minLength: 'arrProperty must be longer than or equal to 2 characters',
         });
+        expect(errors[0].value).toEqual(modelArrProperty);
+      });
     });
+  });
 });
diff --git a/test/functional/reject-validation.spec.ts b/test/functional/reject-validation.spec.ts
index 9794851997..3a51db74ac 100644
--- a/test/functional/reject-validation.spec.ts
+++ b/test/functional/reject-validation.spec.ts
@@ -1,39 +1,39 @@
-import {ValidationError} from "./../../src/validation/ValidationError";
-import {Contains} from "../../src/decorator/decorators";
-import {Validator} from "../../src/validation/Validator";
+import { ValidationError } from './../../src/validation/ValidationError';
+import { Contains } from '../../src/decorator/decorators';
+import { Validator } from '../../src/validation/Validator';
 
 class MyClass {
-    @Contains("hello", {
-        message: "$value is not valid. Your string must contain a hello word"
-    })
-    someProperty: string;
+  @Contains('hello', {
+    message: '$value is not valid. Your string must contain a hello word',
+  })
+  someProperty: string;
 }
 
-describe("validateOrReject()", () => {
-    let validator: Validator;
-    let model: MyClass;
+describe('validateOrReject()', () => {
+  let validator: Validator;
+  let model: MyClass;
 
-    beforeEach(() => {
-        validator = new Validator();
-        model = new MyClass();
-    });
+  beforeEach(() => {
+    validator = new Validator();
+    model = new MyClass();
+  });
 
-    it("should resolve promise when no error", () => {
-        expect.assertions(1);
-        model.someProperty = "hello world";
-        return validator.validateOrReject(model)
-            .then((args) => {
-                expect(args).toBeUndefined();
-            });
+  it('should resolve promise when no error', () => {
+    expect.assertions(1);
+    model.someProperty = 'hello world';
+    return validator.validateOrReject(model).then(args => {
+      expect(args).toBeUndefined();
     });
+  });
 
-    it("should reject promise on error", () => {
-        expect.assertions(2);
-        model.someProperty = "hell no world";
-        return validator.validateOrReject(model)
-            .catch((errors: ValidationError[]) => {
-                expect(errors.length).toEqual(1);
-                expect(errors[0].constraints).toEqual({contains: "hell no world is not valid. Your string must contain a hello word"});
-            });
+  it('should reject promise on error', () => {
+    expect.assertions(2);
+    model.someProperty = 'hell no world';
+    return validator.validateOrReject(model).catch((errors: ValidationError[]) => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].constraints).toEqual({
+        contains: 'hell no world is not valid. Your string must contain a hello word',
+      });
     });
+  });
 });
diff --git a/test/functional/sync-validation.spec.ts b/test/functional/sync-validation.spec.ts
index 76a5e4e608..39ae097587 100644
--- a/test/functional/sync-validation.spec.ts
+++ b/test/functional/sync-validation.spec.ts
@@ -1,70 +1,70 @@
-import {Validator} from "../../src/validation/Validator";
-import {ValidationArguments} from "../../src/validation/ValidationArguments";
-import {registerDecorator} from "../../src/register-decorator";
-import {ValidationOptions} from "../../src/decorator/ValidationOptions";
-import {ValidatorConstraint, Validate, IsNotEmpty} from "../../src/decorator/decorators";
-import {ValidatorConstraintInterface} from "../../src/validation/ValidatorConstraintInterface";
+import { Validator } from '../../src/validation/Validator';
+import { ValidationArguments } from '../../src/validation/ValidationArguments';
+import { registerDecorator } from '../../src/register-decorator';
+import { ValidationOptions } from '../../src/decorator/ValidationOptions';
+import { ValidatorConstraint, Validate, IsNotEmpty } from '../../src/decorator/decorators';
+import { ValidatorConstraintInterface } from '../../src/validation/ValidatorConstraintInterface';
 
 const validator = new Validator();
 
-describe("sync validation should ignore async validation constraints", () => {
-    @ValidatorConstraint({name: "isShortenThan", async: true})
-    class IsShortenThanConstraint implements ValidatorConstraintInterface {
-        validate(value: any, args: ValidationArguments): Promise<boolean> {
-            return Promise.resolve(false);
-        }
+describe('sync validation should ignore async validation constraints', () => {
+  @ValidatorConstraint({ name: 'isShortenThan', async: true })
+  class IsShortenThanConstraint implements ValidatorConstraintInterface {
+    validate(value: any, args: ValidationArguments): Promise<boolean> {
+      return Promise.resolve(false);
     }
+  }
 
-    function IsLonger(property: string, validationOptions?: ValidationOptions) {
-        return function(object: object, propertyName: string): void {
-            registerDecorator({
-                target: object.constructor,
-                propertyName: propertyName,
-                options: validationOptions,
-                constraints: [property],
-                async: true,
-                name: "isLonger",
-                validator: {
-                    validate(value: any, args: ValidationArguments): Promise<boolean> {
-                        return Promise.resolve(false);
-                    }
-                }
-            });
-        };
-    }
+  function IsLonger(property: string, validationOptions?: ValidationOptions) {
+    return function (object: object, propertyName: string): void {
+      registerDecorator({
+        target: object.constructor,
+        propertyName: propertyName,
+        options: validationOptions,
+        constraints: [property],
+        async: true,
+        name: 'isLonger',
+        validator: {
+          validate(value: any, args: ValidationArguments): Promise<boolean> {
+            return Promise.resolve(false);
+          },
+        },
+      });
+    };
+  }
 
-    class SecondClass {
-        @IsLonger("lastName")
-        firstName: string;
+  class SecondClass {
+    @IsLonger('lastName')
+    firstName: string;
 
-        @Validate(IsShortenThanConstraint)
-        lastName: string;
+    @Validate(IsShortenThanConstraint)
+    lastName: string;
 
-        @IsNotEmpty({message: "name should not be empty"})
-        name: string;
+    @IsNotEmpty({ message: 'name should not be empty' })
+    name: string;
 
-        @IsNotEmpty()
-        alwaysWithValue: string = "this field always has a value";
-    }
+    @IsNotEmpty()
+    alwaysWithValue: string = 'this field always has a value';
+  }
 
-    it("should ignore async validations and validate only sync validation types", () => {
-        expect.assertions(1);
-        const model = new SecondClass();
-        model.firstName = "such validation may lead";
-        model.firstName = "to recursion";
-        model.name = "Umed";
-        const errors = validator.validateSync(model);
-        expect(errors.length).toEqual(0);
-    });
+  it('should ignore async validations and validate only sync validation types', () => {
+    expect.assertions(1);
+    const model = new SecondClass();
+    model.firstName = 'such validation may lead';
+    model.firstName = 'to recursion';
+    model.name = 'Umed';
+    const errors = validator.validateSync(model);
+    expect(errors.length).toEqual(0);
+  });
 
-    it("should ignore async validations and validate only sync validation types", () => {
-        expect.assertions(2);
-        const model = new SecondClass();
-        model.firstName = "such validation may lead";
-        model.firstName = "to recursion";
-        model.name = "";
-        const errors = validator.validateSync(model);
-        expect(errors.length).toEqual(1);
-        expect(errors[0].constraints).toEqual({isNotEmpty: "name should not be empty"});
-    });
+  it('should ignore async validations and validate only sync validation types', () => {
+    expect.assertions(2);
+    const model = new SecondClass();
+    model.firstName = 'such validation may lead';
+    model.firstName = 'to recursion';
+    model.name = '';
+    const errors = validator.validateSync(model);
+    expect(errors.length).toEqual(1);
+    expect(errors[0].constraints).toEqual({ isNotEmpty: 'name should not be empty' });
+  });
 });
diff --git a/test/functional/validation-error.spec.ts b/test/functional/validation-error.spec.ts
index 5ce529b20b..b68441ae03 100644
--- a/test/functional/validation-error.spec.ts
+++ b/test/functional/validation-error.spec.ts
@@ -1,5 +1,5 @@
-import {IsString, IsUrl, IsOptional, ValidateNested, MinLength} from "../../src/decorator/decorators";
-import {Validator} from "../../src/validation/Validator";
+import { IsString, IsUrl, IsOptional, ValidateNested, MinLength } from '../../src/decorator/decorators';
+import { Validator } from '../../src/validation/Validator';
 
 const validator = new Validator();
 
@@ -10,56 +10,62 @@ const validator = new Validator();
  *   - testing arrays
  *   - testing color codes?
  */
-describe("ValidationError", () => {
-    it("should correctly log error message without ANSI escape codes", async () => {
-        class NestedClass {
-            @IsString()
-            public name: string;
+describe('ValidationError', () => {
+  it('should correctly log error message without ANSI escape codes', async () => {
+    class NestedClass {
+      @IsString()
+      public name: string;
 
-            @IsUrl()
-            public url: string;
+      @IsUrl()
+      public url: string;
 
-            @IsOptional()
-            @ValidateNested()
-            public insideNested: NestedClass;
+      @IsOptional()
+      @ValidateNested()
+      public insideNested: NestedClass;
 
-            constructor(url: string, name: any, insideNested?: NestedClass) {
-                this.url = url;
-                this.name = name;
-                this.insideNested = insideNested;
-            }
-        }
+      constructor(url: string, name: any, insideNested?: NestedClass) {
+        this.url = url;
+        this.name = name;
+        this.insideNested = insideNested;
+      }
+    }
 
-        class RootClass {
-            @IsString()
-            @MinLength(15)
-            public title: string;
+    class RootClass {
+      @IsString()
+      @MinLength(15)
+      public title: string;
 
-            @ValidateNested()
-            public nestedObj: NestedClass;
+      @ValidateNested()
+      public nestedObj: NestedClass;
 
-            @ValidateNested({each: true})
-            public nestedArr: NestedClass[];
+      @ValidateNested({ each: true })
+      public nestedArr: NestedClass[];
 
-            constructor() {
-                this.title = (5 as any);
-                this.nestedObj = new NestedClass("invalid-url", 5, new NestedClass("invalid-url", 5));
-                this.nestedArr = [new NestedClass("invalid-url", 5), new NestedClass("invalid-url", 5)];
-            }
-        }
+      constructor() {
+        this.title = 5 as any;
+        this.nestedObj = new NestedClass('invalid-url', 5, new NestedClass('invalid-url', 5));
+        this.nestedArr = [new NestedClass('invalid-url', 5), new NestedClass('invalid-url', 5)];
+      }
+    }
 
-        const validationErrors = await validator.validate(new RootClass());
-        expect(validationErrors[0].toString()).toEqual("An instance of RootClass has failed the validation:\n" +
-            " - property title has failed the following constraints: minLength, isString \n");
-        expect(validationErrors[1].toString()).toEqual("An instance of RootClass has failed the validation:\n" +
-            " - property nestedObj.name has failed the following constraints: isString \n" +
-            " - property nestedObj.url has failed the following constraints: isUrl \n" +
-            " - property nestedObj.insideNested.name has failed the following constraints: isString \n" +
-            " - property nestedObj.insideNested.url has failed the following constraints: isUrl \n");
-        expect(validationErrors[2].toString()).toEqual("An instance of RootClass has failed the validation:\n" +
-            " - property nestedArr[0].name has failed the following constraints: isString \n" +
-            " - property nestedArr[0].url has failed the following constraints: isUrl \n" +
-            " - property nestedArr[1].name has failed the following constraints: isString \n" +
-            " - property nestedArr[1].url has failed the following constraints: isUrl \n");
-    });
+    const validationErrors = await validator.validate(new RootClass());
+    expect(validationErrors[0].toString()).toEqual(
+      'An instance of RootClass has failed the validation:\n' +
+        ' - property title has failed the following constraints: minLength, isString \n'
+    );
+    expect(validationErrors[1].toString()).toEqual(
+      'An instance of RootClass has failed the validation:\n' +
+        ' - property nestedObj.name has failed the following constraints: isString \n' +
+        ' - property nestedObj.url has failed the following constraints: isUrl \n' +
+        ' - property nestedObj.insideNested.name has failed the following constraints: isString \n' +
+        ' - property nestedObj.insideNested.url has failed the following constraints: isUrl \n'
+    );
+    expect(validationErrors[2].toString()).toEqual(
+      'An instance of RootClass has failed the validation:\n' +
+        ' - property nestedArr[0].name has failed the following constraints: isString \n' +
+        ' - property nestedArr[0].url has failed the following constraints: isUrl \n' +
+        ' - property nestedArr[1].name has failed the following constraints: isString \n' +
+        ' - property nestedArr[1].url has failed the following constraints: isUrl \n'
+    );
+  });
 });
diff --git a/test/functional/validation-functions-and-decorators.spec.ts b/test/functional/validation-functions-and-decorators.spec.ts
index af570765a8..8e77b7fc79 100644
--- a/test/functional/validation-functions-and-decorators.spec.ts
+++ b/test/functional/validation-functions-and-decorators.spec.ts
@@ -1,4462 +1,4437 @@
 import {
-    IsBooleanString,
-    IsPositive,
-    IsLatLong,
-    IsLongitude,
-    IsLatitude,
-    IsNegative,
-    Contains,
-    Equals,
-    MinDate,
-    MaxDate,
-    IsAlpha,
-    IsAlphanumeric,
-    IsAscii,
-    IsDecimal,
-    IsBase64,
-    IsBoolean,
-    IsByteLength,
-    IsCreditCard,
-    IsCurrency,
-    IsDate,
-    IsDivisibleBy,
-    IsEmail,
-    IsEnum,
-    IsFQDN,
-    IsFullWidth,
-    IsHalfWidth,
-    IsVariableWidth,
-    IsHexColor,
-    IsHexadecimal,
-    IsIP,
-    IsISBN,
-    IsISO8601,
-    IsIn,
-    IsInt,
-    IsJSON,
-    IsJWT,
-    IsObject,
-    IsNotEmptyObject,
-    Length,
-    IsLowercase,
-    IsMongoId,
-    IsMultibyte,
-    IsNumberString,
-    IsSurrogatePair,
-    IsUrl,
-    IsUUID,
-    IsUppercase,
-    Matches,
-    MinLength,
-    MaxLength,
-    Min,
-    Max,
-    IsNotEmpty,
-    IsMilitaryTime,
-    ArrayNotEmpty,
-    ArrayMinSize,
-    ArrayMaxSize,
-    NotEquals,
-    IsEmpty,
-    IsDefined,
-    IsNotIn,
-    IsNumber,
-    IsString,
-    NotContains,
-    ArrayContains,
-    ArrayNotContains,
-    ArrayUnique,
-    IsArray,
-    IsDateString,
-    IsInstance,
-    IsPhoneNumber,
-    IsISO31661Alpha2,
-    IsISO31661Alpha3,
-    IsHash,
-    IsMACAddress,
-    IsISSN,
-    IsFirebasePushId,
-    isDefined,
-    isNumber,
-    isURL,
-    isBoolean,
-    isString,
-    isInt,
-    isArray,
-    isEnum,
-    contains,
-    isObject,
-    isNotEmptyObject,
-    isInstance,
-    notContains,
-    isAlpha,
-    isAlphanumeric,
-    isAscii,
-    isDecimal,
-    isBase64,
-    isByteLength,
-    isCreditCard,
-    isCurrency,
-    isEmail,
-    isFQDN,
-    isFullWidth,
-    isHalfWidth,
-    isVariableWidth,
-    isHexColor,
-    isHexadecimal,
-    isMACAddress,
-    isISBN,
-    isISO8601,
-    isIP,
-    isJSON,
-    isJWT,
-    isLowercase,
-    isMongoId,
-    isMultibyte,
-    isSurrogatePair,
-    isUUID,
-    isUppercase,
-    length,
-    minLength,
-    maxLength,
-    isFirebasePushId,
-    equals,
-    notEquals,
-    isEmpty,
-    isNotEmpty,
-    isIn,
-    isNotIn,
-    isDateString,
-    isDivisibleBy,
-    isPositive,
-    isNegative,
-    min,
-    max,
-    isBooleanString,
-    isNumberString,
-    matches,
-    isHash,
-    isISSN,
-    arrayContains,
-    arrayNotContains,
-    arrayMinSize,
-    arrayMaxSize,
-    arrayUnique,
-    arrayNotEmpty,
-    minDate,
-    maxDate,
-    isDate,
-    IsEAN,
-    isEAN,
-    IsEthereumAddress,
-    isEthereumAddress,
-    IsBtcAddress,
-    isBtcAddress,
-    IsDataURI,
-    isDataURI,
-    IsHSL,
-    isHSL,
-    IsRgbColor,
-    isRgbColor,
-    isIdentityCard,
-    IsIdentityCard,
-    IsBase32,
-    isBase32,
-    IsIBAN,
-    isIBAN,
-    IsBIC,
-    isBIC,
-    IsISRC,
-    isISRC,
-    IsRFC3339,
-    isRFC3339,
-    IsLocale,
-    isLocale,
-    IsMagnetURI,
-    isMagnetURI,
-    IsMimeType,
-    isMimeType,
-    isOctal,
-    IsOctal,
-    IsPassportNumber,
-    isPassportNumber,
-    IsPostalCode,
-    isPostalCode,
-    IsSemVer,
-    isSemVer
-} from "../../src/decorator/decorators";
-import {Validator} from "../../src/validation/Validator";
-import {ValidatorOptions} from "../../src/validation/ValidatorOptions";
-import {default as ValidatorJS} from "validator";
-
-export function checkValidValues(object: { someProperty: any }, values: any[], validatorOptions?: ValidatorOptions): Promise<any> {
-    const validator = new Validator();
-    const promises = values.map(value => {
-        object.someProperty = value;
-        return validator.validate(object, validatorOptions)
-            .then((errors) => {
-                expect(errors.length).toEqual(0);
-                if (errors.length !== 0) {
-                    console.log(`Unexpected errors: ${JSON.stringify(errors)}`);
-                    throw new Error("Unexpected validation errors");
-                }
-            });
-    });
-
-    return Promise.all(promises);
+  IsBooleanString,
+  IsPositive,
+  IsLatLong,
+  IsLongitude,
+  IsLatitude,
+  IsNegative,
+  Contains,
+  Equals,
+  MinDate,
+  MaxDate,
+  IsAlpha,
+  IsAlphanumeric,
+  IsAscii,
+  IsDecimal,
+  IsBase64,
+  IsBoolean,
+  IsByteLength,
+  IsCreditCard,
+  IsCurrency,
+  IsDate,
+  IsDivisibleBy,
+  IsEmail,
+  IsEnum,
+  IsFQDN,
+  IsFullWidth,
+  IsHalfWidth,
+  IsVariableWidth,
+  IsHexColor,
+  IsHexadecimal,
+  IsIP,
+  IsISBN,
+  IsISO8601,
+  IsIn,
+  IsInt,
+  IsJSON,
+  IsJWT,
+  IsObject,
+  IsNotEmptyObject,
+  Length,
+  IsLowercase,
+  IsMongoId,
+  IsMultibyte,
+  IsNumberString,
+  IsSurrogatePair,
+  IsUrl,
+  IsUUID,
+  IsUppercase,
+  Matches,
+  MinLength,
+  MaxLength,
+  Min,
+  Max,
+  IsNotEmpty,
+  IsMilitaryTime,
+  ArrayNotEmpty,
+  ArrayMinSize,
+  ArrayMaxSize,
+  NotEquals,
+  IsEmpty,
+  IsDefined,
+  IsNotIn,
+  IsNumber,
+  IsString,
+  NotContains,
+  ArrayContains,
+  ArrayNotContains,
+  ArrayUnique,
+  IsArray,
+  IsDateString,
+  IsInstance,
+  IsPhoneNumber,
+  IsISO31661Alpha2,
+  IsISO31661Alpha3,
+  IsHash,
+  IsMACAddress,
+  IsISSN,
+  IsFirebasePushId,
+  isDefined,
+  isNumber,
+  isURL,
+  isBoolean,
+  isString,
+  isInt,
+  isArray,
+  isEnum,
+  contains,
+  isObject,
+  isNotEmptyObject,
+  isInstance,
+  notContains,
+  isAlpha,
+  isAlphanumeric,
+  isAscii,
+  isDecimal,
+  isBase64,
+  isByteLength,
+  isCreditCard,
+  isCurrency,
+  isEmail,
+  isFQDN,
+  isFullWidth,
+  isHalfWidth,
+  isVariableWidth,
+  isHexColor,
+  isHexadecimal,
+  isMACAddress,
+  isISBN,
+  isISO8601,
+  isIP,
+  isJSON,
+  isJWT,
+  isLowercase,
+  isMongoId,
+  isMultibyte,
+  isSurrogatePair,
+  isUUID,
+  isUppercase,
+  length,
+  minLength,
+  maxLength,
+  isFirebasePushId,
+  equals,
+  notEquals,
+  isEmpty,
+  isNotEmpty,
+  isIn,
+  isNotIn,
+  isDateString,
+  isDivisibleBy,
+  isPositive,
+  isNegative,
+  min,
+  max,
+  isBooleanString,
+  isNumberString,
+  matches,
+  isHash,
+  isISSN,
+  arrayContains,
+  arrayNotContains,
+  arrayMinSize,
+  arrayMaxSize,
+  arrayUnique,
+  arrayNotEmpty,
+  minDate,
+  maxDate,
+  isDate,
+  IsEAN,
+  isEAN,
+  IsEthereumAddress,
+  isEthereumAddress,
+  IsBtcAddress,
+  isBtcAddress,
+  IsDataURI,
+  isDataURI,
+  IsHSL,
+  isHSL,
+  IsRgbColor,
+  isRgbColor,
+  isIdentityCard,
+  IsIdentityCard,
+  IsBase32,
+  isBase32,
+  IsIBAN,
+  isIBAN,
+  IsBIC,
+  isBIC,
+  IsISRC,
+  isISRC,
+  IsRFC3339,
+  isRFC3339,
+  IsLocale,
+  isLocale,
+  IsMagnetURI,
+  isMagnetURI,
+  IsMimeType,
+  isMimeType,
+  isOctal,
+  IsOctal,
+  IsPassportNumber,
+  isPassportNumber,
+  IsPostalCode,
+  isPostalCode,
+  IsSemVer,
+  isSemVer,
+} from '../../src/decorator/decorators';
+import { Validator } from '../../src/validation/Validator';
+import { ValidatorOptions } from '../../src/validation/ValidatorOptions';
+import { default as ValidatorJS } from 'validator';
+
+export function checkValidValues(
+  object: { someProperty: any },
+  values: any[],
+  validatorOptions?: ValidatorOptions
+): Promise<any> {
+  const validator = new Validator();
+  const promises = values.map(value => {
+    object.someProperty = value;
+    return validator.validate(object, validatorOptions).then(errors => {
+      expect(errors.length).toEqual(0);
+      if (errors.length !== 0) {
+        console.log(`Unexpected errors: ${JSON.stringify(errors)}`);
+        throw new Error('Unexpected validation errors');
+      }
+    });
+  });
+
+  return Promise.all(promises);
 }
 
-export function checkInvalidValues(object: { someProperty: any }, values: any[], validatorOptions?: ValidatorOptions): Promise<any> {
-    const validator = new Validator();
-    const promises = values.map(value => {
-        object.someProperty = value;
-        return validator
-            .validate(object, validatorOptions)
-            .then((errors) => {
-                expect(errors.length).toEqual(1);
-                if (errors.length !== 1) {
-                    throw new Error("Missing validation errors");
-                }
-            }).catch((error) => {
-                console.log(error);
-            });
-    });
+export function checkInvalidValues(
+  object: { someProperty: any },
+  values: any[],
+  validatorOptions?: ValidatorOptions
+): Promise<any> {
+  const validator = new Validator();
+  const promises = values.map(value => {
+    object.someProperty = value;
+    return validator
+      .validate(object, validatorOptions)
+      .then(errors => {
+        expect(errors.length).toEqual(1);
+        if (errors.length !== 1) {
+          throw new Error('Missing validation errors');
+        }
+      })
+      .catch(error => {
+        console.log(error);
+      });
+  });
 
-    return Promise.all(promises);
+  return Promise.all(promises);
 }
 
-export function checkReturnedError(object: { someProperty: any },
-                                   values: any[],
-                                   validationType: string,
-                                   message: string,
-                                   validatorOptions?: ValidatorOptions): Promise<any> {
-    const validator = new Validator();
-    const promises = values.map(value => {
-        object.someProperty = value;
-        return validator
-            .validate(object, validatorOptions)
-            .then(errors => {
-                expect(errors.length).toEqual(1);
-                expect(errors[0].target).toEqual(object);
-                expect(errors[0].property).toEqual("someProperty");
-                expect(errors[0].constraints).toEqual({[validationType]: message});
-                expect(errors[0].value).toEqual(value);
-            });
-    });
-
-    return Promise.all(promises);
+export function checkReturnedError(
+  object: { someProperty: any },
+  values: any[],
+  validationType: string,
+  message: string,
+  validatorOptions?: ValidatorOptions
+): Promise<any> {
+  const validator = new Validator();
+  const promises = values.map(value => {
+    object.someProperty = value;
+    return validator.validate(object, validatorOptions).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].target).toEqual(object);
+      expect(errors[0].property).toEqual('someProperty');
+      expect(errors[0].constraints).toEqual({ [validationType]: message });
+      expect(errors[0].value).toEqual(value);
+    });
+  });
+
+  return Promise.all(promises);
 }
 
 const validator = new Validator();
 
-describe("IsDefined", () => {
+describe('IsDefined', () => {
+  const validValues = [0, 1, true, false, '', '0', '1234', -1];
+  const invalidValues: any[] = [null, undefined];
 
-    const validValues = [0, 1, true, false, "", "0", "1234", -1];
-    const invalidValues: any[] = [null, undefined];
+  class MyClass {
+    @IsDefined()
+    someProperty: string;
+  }
 
-    class MyClass {
-        @IsDefined()
-        someProperty: string;
-    }
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+  it('should not fail if validator.validate said that its valid with skipUndefinedProperties set to true', () => {
+    return checkValidValues(new MyClass(), validValues, { skipUndefinedProperties: true });
+  });
 
-    it("should not fail if validator.validate said that its valid with skipUndefinedProperties set to true", () => {
-        return checkValidValues(new MyClass(), validValues, {skipUndefinedProperties: true});
-    });
+  it('should fail if validator.validate said that its invalid with skipUndefinedProperties set to true', () => {
+    return checkInvalidValues(new MyClass(), invalidValues, { skipUndefinedProperties: true });
+  });
 
-    it("should fail if validator.validate said that its invalid with skipUndefinedProperties set to true", () => {
-        return checkInvalidValues(new MyClass(), invalidValues, {skipUndefinedProperties: true});
-    });
+  it('should not fail if validator.validate said that its valid with skipNullProperties set to true', () => {
+    return checkValidValues(new MyClass(), validValues, { skipNullProperties: true });
+  });
 
-    it("should not fail if validator.validate said that its valid with skipNullProperties set to true", () => {
-        return checkValidValues(new MyClass(), validValues, {skipNullProperties: true});
-    });
+  it('should fail if validator.validate said that its invalid with skipNullProperties set to true', () => {
+    return checkInvalidValues(new MyClass(), invalidValues, { skipNullProperties: true });
+  });
 
-    it("should fail if validator.validate said that its invalid with skipNullProperties set to true", () => {
-        return checkInvalidValues(new MyClass(), invalidValues, {skipNullProperties: true});
-    });
+  it('should not fail if validator.validate said that its valid with skipMissingProperties set to true', () => {
+    return checkValidValues(new MyClass(), validValues, { skipMissingProperties: true });
+  });
 
-    it("should not fail if validator.validate said that its valid with skipMissingProperties set to true", () => {
-        return checkValidValues(new MyClass(), validValues, {skipMissingProperties: true});
-    });
+  it('should fail if validator.validate said that its invalid with skipMissingProperties set to true', () => {
+    return checkInvalidValues(new MyClass(), invalidValues, { skipMissingProperties: true });
+  });
 
-    it("should fail if validator.validate said that its invalid with skipMissingProperties set to true", () => {
-        return checkInvalidValues(new MyClass(), invalidValues, {skipMissingProperties: true});
-    });
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isDefined(value)).toBeTruthy());
+  });
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isDefined(value)).toBeTruthy());
-    });
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isDefined(value)).toBeFalsy());
+  });
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isDefined(value)).toBeFalsy());
-    });
+  it('should return error object with proper data', () => {
+    const validationType = 'isDefined';
+    const message = 'someProperty should not be null or undefined';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should return error object with proper data", () => {
-        const validationType = "isDefined";
-        const message = "someProperty should not be null or undefined";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+describe('Equals', () => {
+  const constraint = 'Alex';
+  const validValues = ['Alex'];
+  const invalidValues = ['Alexxx'];
+
+  class MyClass {
+    @Equals(constraint)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(equals(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(equals(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'equals';
+    const message = 'someProperty must be equal to ' + constraint;
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("Equals", () => {
-    const constraint = "Alex";
-    const validValues = ["Alex"];
-    const invalidValues = ["Alexxx"];
+describe('NotEquals', () => {
+  const constraint = 'Alex';
+  const validValues = ['Alexxx'];
+  const invalidValues = ['Alex'];
+
+  class MyClass {
+    @NotEquals(constraint)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(notEquals(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(notEquals(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'notEquals';
+    const message = 'someProperty should not be equal to ' + constraint;
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    class MyClass {
-        @Equals(constraint)
-        someProperty: string;
-    }
+describe('IsEmpty', () => {
+  const validValues = [null, undefined, ''];
+  const invalidValues = ['0', 0, 1, false, true];
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  class MyClass {
+    @IsEmpty()
+    someProperty: string;
+  }
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(equals(value, constraint)).toBeTruthy());
-    });
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(equals(value, constraint)).toBeFalsy());
-    });
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isEmpty(value)).toBeTruthy());
+  });
 
-    it("should return error object with proper data", () => {
-        const validationType = "equals";
-        const message = "someProperty must be equal to " + constraint;
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isEmpty(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isEmpty';
+    const message = 'someProperty must be empty';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("NotEquals", () => {
-    const constraint = "Alex";
-    const validValues = ["Alexxx"];
-    const invalidValues = ["Alex"];
+describe('IsNotEmpty', () => {
+  const validValues = ['a', 'abc'];
+  const invalidValues = ['', undefined, null];
 
-    class MyClass {
-        @NotEquals(constraint)
-        someProperty: string;
-    }
+  class MyClass {
+    @IsNotEmpty()
+    someProperty: string;
+  }
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(notEquals(value, constraint)).toBeTruthy());
-    });
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isNotEmpty(value)).toBeTruthy());
+  });
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(notEquals(value, constraint)).toBeFalsy());
-    });
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isNotEmpty(value)).toBeFalsy());
+  });
 
-    it("should return error object with proper data", () => {
-        const validationType = "notEquals";
-        const message = "someProperty should not be equal to " + constraint;
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+  it('should return error object with proper data', () => {
+    const validationType = 'isNotEmpty';
+    const message = 'someProperty should not be empty';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("IsEmpty", () => {
-    const validValues = [null, undefined, ""];
-    const invalidValues = ["0", 0, 1, false, true];
+describe('IsIn', () => {
+  const constraint = ['foo', 'bar'] as const;
+  const validValues = ['foo', 'bar'];
+  const invalidValues = ['foobar', 'barfoo', ''];
+
+  class MyClass {
+    @IsIn(constraint)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isIn(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isIn(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isIn';
+    const message = 'someProperty must be one of the following values: ' + constraint;
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    class MyClass {
-        @IsEmpty()
-        someProperty: string;
-    }
+describe('IsNotIn', () => {
+  const constraint = ['foo', 'bar'] as const;
+  const validValues = ['foobar', 'barfoo', ''];
+  const invalidValues = ['foo', 'bar'];
+
+  class MyClass {
+    @IsNotIn(constraint)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isNotIn(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isNotIn(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isNotIn';
+    const message = 'someProperty should not be one of the following values: ' + constraint;
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+// -------------------------------------------------------------------------
+// Specifications: type check
+// -------------------------------------------------------------------------
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+describe('IsBoolean', () => {
+  const validValues = [true, false];
+  const invalidValues = [0, 1, 'true', null, undefined];
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isEmpty(value)).toBeTruthy());
-    });
+  class MyClass {
+    @IsBoolean()
+    someProperty: any;
+  }
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isEmpty(value)).toBeFalsy());
-    });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    it("should return error object with proper data", () => {
-        const validationType = "isEmpty";
-        const message = "someProperty must be empty";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-describe("IsNotEmpty", () => {
-    const validValues = ["a", "abc"];
-    const invalidValues = ["", undefined, null];
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isBoolean(value)).toBeTruthy());
+  });
 
-    class MyClass {
-        @IsNotEmpty()
-        someProperty: string;
-    }
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isBoolean(value)).toBeFalsy());
+  });
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  it('should return error object with proper data', () => {
+    const validationType = 'isBoolean';
+    const message = 'someProperty must be a boolean value';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+describe('IsLatLong', () => {
+  const validValues = ['27.6945311,85.3446311', '27.675509,85.2100893'];
+  const invalidValues = ['276945311,853446311', 'asas,as.as12'];
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isNotEmpty(value)).toBeTruthy());
-    });
+  class MyClass {
+    @IsLatLong()
+    someProperty: any;
+  }
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isNotEmpty(value)).toBeFalsy());
-    });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    it("should return error object with proper data", () => {
-        const validationType = "isNotEmpty";
-        const message = "someProperty should not be empty";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 });
 
-describe("IsIn", () => {
-    const constraint = ["foo", "bar"] as const;
-    const validValues = ["foo", "bar"];
-    const invalidValues = ["foobar", "barfoo", ""];
+describe('IsLatitude', () => {
+  const validValues = ['27.6945311', '27.675509', 27.675509];
+  const invalidValues = ['276945311', 'asas', 1234222, 5678921];
 
-    class MyClass {
-        @IsIn(constraint)
-        someProperty: string;
-    }
+  class MyClass {
+    @IsLatitude()
+    someProperty: any;
+  }
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+});
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isIn(value, constraint)).toBeTruthy());
-    });
+describe('IsLongitude', () => {
+  const validValues = ['85.3446311', '85.2100893', 85.2100893];
+  const invalidValues = ['853446311', 'as.as12', 12345, 737399];
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isIn(value, constraint)).toBeFalsy());
-    });
+  class MyClass {
+    @IsLongitude()
+    someProperty: any;
+  }
 
-    it("should return error object with proper data", () => {
-        const validationType = "isIn";
-        const message = "someProperty must be one of the following values: " + constraint;
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 });
 
-describe("IsNotIn", () => {
-    const constraint = ["foo", "bar"] as const;
-    const validValues = ["foobar", "barfoo", ""];
-    const invalidValues = ["foo", "bar"];
+describe('IsDate', () => {
+  const validValues = [new Date()];
+  const invalidValues = [1, true, false, 'Mon Aug 17 2015 00:24:56 GMT-0500 (CDT)', '2009-05-19 14:39:22-06:00'];
 
-    class MyClass {
-        @IsNotIn(constraint)
-        someProperty: string;
-    }
+  class MyClass {
+    @IsDate()
+    someProperty: Date;
+  }
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isNotIn(value, constraint)).toBeTruthy());
-    });
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isDate(value)).toBeTruthy());
+  });
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isNotIn(value, constraint)).toBeFalsy());
-    });
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isDate(value)).toBeFalsy());
+  });
 
-    it("should return error object with proper data", () => {
-        const validationType = "isNotIn";
-        const message = "someProperty should not be one of the following values: " + constraint;
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+  it('should return error object with proper data', () => {
+    const validationType = 'isDate';
+    const message = 'someProperty must be a Date instance';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-// -------------------------------------------------------------------------
-// Specifications: type check
-// -------------------------------------------------------------------------
+describe('IsNumber', () => {
+  const validValues = [0, 1, 2, 3, 4, 5.4, -10];
+  const invalidValues = ['1', '0', true, false, '-100', 'abc', undefined, null];
+
+  class MyClass {
+    @IsNumber()
+    someProperty: number;
+  }
+
+  class NaNTestClass {
+    @IsNumber({ allowNaN: true })
+    someProperty: number;
+  }
+
+  class InfinityTestClass {
+    @IsNumber({ allowInfinity: true })
+    someProperty: number;
+  }
+
+  class MaxDecimalPlacesTest {
+    @IsNumber({ maxDecimalPlaces: 3 })
+    someProperty: number;
+  }
+
+  class ZeroDecimalPlacesTest {
+    @IsNumber({ maxDecimalPlaces: 0 })
+    someProperty: number;
+  }
+
+  it('should fail if NaN passed without allowing NaN values', () => {
+    return checkInvalidValues(new MyClass(), [NaN]);
+  });
+
+  it('should fail if Infinity passed without allowing NaN values', () => {
+    return checkInvalidValues(new MyClass(), [Infinity, -Infinity]);
+  });
+
+  it('should not fail if NaN passed and NaN as value is allowed', () => {
+    return checkValidValues(new NaNTestClass(), [NaN]);
+  });
+
+  it('should not fail if Infinity passed and Infinity as value is allowed', () => {
+    return checkValidValues(new InfinityTestClass(), [Infinity, -Infinity]);
+  });
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isNumber(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isNumber(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isNumber';
+    const message = 'someProperty must be a number conforming to the specified constraints';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+
+  it('should pass if number of decimal places within maxDecimalPlaces', () => {
+    return checkValidValues(new MaxDecimalPlacesTest(), [1.123]);
+  });
+
+  it('should fail if number of decimal places exceeds maxDecimalPlaces', () => {
+    return checkInvalidValues(new MaxDecimalPlacesTest(), [1.1234]);
+  });
+
+  it('should pass if number of decimal places is zero', () => {
+    return checkValidValues(new ZeroDecimalPlacesTest(), [-10, -1, 0, 1, 10]);
+  });
+
+  it('should fail if number of decimal places is not zero', () => {
+    return checkInvalidValues(new ZeroDecimalPlacesTest(), [-11.1, -2.2, -0.1, 0.1, 2.2, 11.1]);
+  });
+});
 
-describe("IsBoolean", () => {
-    const validValues = [true, false];
-    const invalidValues = [0, 1, "true", null, undefined];
+describe('IsInt', () => {
+  const validValues = [2, 4, 100, 1000];
+  const invalidValues = ['01', '-01', '000', '100e10', '123.123', '   ', '', 2.5, -0.1];
 
-    class MyClass {
-        @IsBoolean()
-        someProperty: any;
-    }
+  class MyClass {
+    @IsInt()
+    someProperty: string;
+  }
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isBoolean(value)).toBeTruthy());
-    });
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isInt(value)).toBeTruthy());
+  });
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isBoolean(value)).toBeFalsy());
-    });
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isInt(value as any)).toBeFalsy());
+  });
 
-    it("should return error object with proper data", () => {
-        const validationType = "isBoolean";
-        const message = "someProperty must be a boolean value";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+  it('should return error object with proper data', () => {
+    const validationType = 'isInt';
+    const message = 'someProperty must be an integer number';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("IsLatLong", () => {
-    const validValues = ["27.6945311,85.3446311", "27.675509,85.2100893"];
-    const invalidValues = ["276945311,853446311", "asas,as.as12"];
+describe('IsString', () => {
+  const validValues = ['true', 'false', 'hello', '0', '', '1'];
+  const invalidValues = [true, false, 1, 2, null, undefined];
 
-    class MyClass {
-        @IsLatLong()
-        someProperty: any;
-    }
+  class MyClass {
+    @IsString()
+    someProperty: string;
+  }
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-});
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-describe("IsLatitude", () => {
-    const validValues = ["27.6945311", "27.675509", 27.675509];
-    const invalidValues = ["276945311", "asas", 1234222, 5678921];
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isString(value)).toBeTruthy());
+  });
 
-    class MyClass {
-        @IsLatitude()
-        someProperty: any;
-    }
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isString(value as any)).toBeFalsy());
+  });
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  it('should return error object with proper data', () => {
+    const validationType = 'isString';
+    const message = 'someProperty must be a string';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+describe('IsDateString', () => {
+  const validValues = [
+    '2017-06-06T17:04:42.081Z',
+    '2017-06-06T17:04:42.081',
+    '2018-01-04T08:15:30',
+    '2018-01-04T08:15:30Z',
+    '2018-01-04T08:15:30+04:00',
+    '2018-01-04T08:15:30+04',
+    '2020-03-26T11:00:01-03:00',
+    '2020-03-26T11:00:01-03',
+    '2019-09-03T20:16:24.12Z',
+  ];
+  const invalidValues = [
+    true,
+    false,
+    1,
+    2,
+    null,
+    undefined,
+    'text',
+    'text2018-01-04T08:15:30+04',
+    '2018-01-04T08:15:30Ztext',
+    '2019-18-13T22:14:14.761Z', // month greater than 12
+    '2019-12-39T22:14:14.761Z', // day greater than 31
+    '2019-12-31T29:14:14.761Z', // hour greater than 24
+    '2019-00-31T29:14:14.761Z', // month of 0
+    '2019-01-00T29:14:14.761Z', // day of 0
+    '2019-09-03T20:16:24.12-5:00', // single digit hour in timezone offset
+    '2019-09-03T20:16:24.12+5:00',
+    '2019-09-03T20:16:24.12-05:0', // single digit minute in timezone offset
+    '2019-09-03T20:16:24.12+05:0',
+  ];
+
+  class MyClass {
+    @IsDateString()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isDateString(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isDateString(value as any)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isDateString';
+    const message = 'someProperty must be a valid ISO 8601 date string';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("IsLongitude", () => {
-    const validValues = ["85.3446311", "85.2100893", 85.2100893];
-    const invalidValues = ["853446311", "as.as12", 12345, 737399];
+describe('IsArray', () => {
+  const validValues = [[], [1, 2, 3], [0, 0, 0], [''], [0], [undefined], [{}], []];
+  const invalidValues = [true, false, 1, {}, null, undefined];
 
-    class MyClass {
-        @IsLongitude()
-        someProperty: any;
-    }
+  class MyClass {
+    @IsArray()
+    someProperty: string[];
+  }
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-});
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-describe("IsDate", () => {
-    const validValues = [new Date()];
-    const invalidValues = [1, true, false, "Mon Aug 17 2015 00:24:56 GMT-0500 (CDT)", "2009-05-19 14:39:22-06:00"];
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isArray(value)).toBeTruthy());
+  });
 
-    class MyClass {
-        @IsDate()
-        someProperty: Date;
-    }
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isArray(value as any)).toBeFalsy());
+  });
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  it('should return error object with proper data', () => {
+    const validationType = 'isArray';
+    const message = 'someProperty must be an array';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+describe('IsEnum', () => {
+  enum MyEnum {
+    First = 1,
+    Second = 999,
+  }
+
+  enum MyStringEnum {
+    First = 'first',
+    Second = 'second',
+  }
+
+  const validValues = [MyEnum.First, MyEnum.Second];
+  const validStringValues = [MyStringEnum.First, MyStringEnum.Second];
+  const invalidValues = [true, false, 0, {}, null, undefined, 'F2irst'];
+
+  class MyClass {
+    @IsEnum(MyEnum)
+    someProperty: MyEnum;
+  }
+
+  class MyClass2 {
+    @IsEnum(MyStringEnum)
+    someProperty: MyStringEnum;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should not fail if validator.validate said that its valid (string enum)', () => {
+    return checkValidValues(new MyClass2(), validStringValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should fail if validator.validate said that its invalid (string enum)', () => {
+    return checkInvalidValues(new MyClass2(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isEnum(value, MyEnum)).toBeTruthy());
+  });
+
+  it('should not fail if method in validator said that its valid (string enum)', () => {
+    validStringValues.forEach(value => expect(isEnum(value, MyStringEnum)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isEnum(value, MyEnum)).toBeFalsy());
+  });
+
+  it('should fail if method in validator said that its invalid (string enum)', () => {
+    invalidValues.forEach(value => expect(isEnum(value, MyStringEnum)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isEnum';
+    const message = 'someProperty must be a valid enum value';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+
+  it('should return error object with proper data (string enum)', () => {
+    const validationType = 'isEnum';
+    const message = 'someProperty must be a valid enum value';
+    checkReturnedError(new MyClass2(), invalidValues, validationType, message);
+  });
+});
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isDate(value)).toBeTruthy());
-    });
+describe('IsDivisibleBy', () => {
+  const constraint = 2;
+  const validValues = [2, 4, 100, 1000];
+  const invalidValues = ['', undefined, null];
+
+  class MyClass {
+    @IsDivisibleBy(constraint)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isDivisibleBy(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isDivisibleBy(value as any, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isDivisibleBy';
+    const message = 'someProperty must be divisible by ' + constraint;
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isDate(value)).toBeFalsy());
-    });
+describe('IsPositive', () => {
+  const validValues = [3, 5000];
+  const invalidValues = [
+    '-1',
+    '-2',
+    '0',
+    '1',
+    '2',
+    '3',
+    '4',
+    '5',
+    '6',
+    '7',
+    '8',
+    '9',
+    '100000',
+    -500,
+    -123,
+    -1,
+    '   ',
+    '',
+  ];
+
+  class MyClass {
+    @IsPositive()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isPositive(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isPositive(value as any)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isPositive';
+    const message = 'someProperty must be a positive number';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should return error object with proper data", () => {
-        const validationType = "isDate";
-        const message = "someProperty must be a Date instance";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+describe('IsNegative', () => {
+  const validValues = [-3, -5000, -0.1];
+  const invalidValues = [
+    '-1',
+    '-2',
+    '0',
+    '1',
+    '2',
+    '3',
+    '4',
+    '5',
+    '6',
+    '7',
+    '8',
+    '9',
+    '100000',
+    500,
+    123,
+    1,
+    '   ',
+    '',
+  ];
+
+  class MyClass {
+    @IsNegative()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isNegative(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isNegative(value as any)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isNegative';
+    const message = 'someProperty must be a negative number';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("IsNumber", () => {
-    const validValues = [0, 1, 2, 3, 4, 5.4, -10];
-    const invalidValues = ["1", "0", true, false, "-100", "abc", undefined, null];
+describe('Min', () => {
+  const constraint = 10;
+  const validValues = [10, 11, 20, 30, 40];
+  const invalidValues = [2, 3, 4, 5, 6, 7, 8, 9, -10];
+
+  class MyClass {
+    @Min(constraint)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(min(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(min(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'min';
+    const message = 'someProperty must not be less than ' + constraint;
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    class MyClass {
-        @IsNumber()
-        someProperty: number;
-    }
+describe('Max', () => {
+  const constraint = 10;
+  const validValues = [1, 2, 3, 4, 5, 6, 7, 8, 9, -10, 10];
+  const invalidValues = [11, 20, 30, 40];
+
+  class MyClass {
+    @Max(constraint)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(max(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(max(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'max';
+    const message = 'someProperty must not be greater than ' + constraint;
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    class NaNTestClass {
-        @IsNumber({allowNaN: true})
-        someProperty: number;
-    }
+describe('MinDate', () => {
+  const constraint = new Date(1995, 11, 17);
+  const validValues = [new Date()];
+  const invalidValues = [new Date(1994, 11, 17)];
+
+  class MyClass {
+    @MinDate(constraint)
+    someProperty: Date;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(minDate(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(minDate(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'minDate';
+    const message = 'minimal allowed date for someProperty is ' + constraint;
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    class InfinityTestClass {
-        @IsNumber({allowInfinity: true})
-        someProperty: number;
-    }
+describe('MaxDate', () => {
+  const constraint = new Date(1995, 11, 17);
+  const validValues = [new Date(1994, 11, 17)];
+  const invalidValues = [new Date()];
+
+  class MyClass {
+    @MaxDate(constraint)
+    someProperty: Date;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(maxDate(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(maxDate(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'maxDate';
+    const message = 'maximal allowed date for someProperty is ' + constraint;
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    class MaxDecimalPlacesTest {
-        @IsNumber({maxDecimalPlaces: 3})
-        someProperty: number;
-    }
+describe('IsBooleanString', () => {
+  const validValues = ['1', '0', 'true', 'false'];
+  const invalidValues = ['2', '3', 'falze'];
 
-    class ZeroDecimalPlacesTest {
-        @IsNumber({maxDecimalPlaces: 0})
-        someProperty: number;
-    }
+  class MyClass {
+    @IsBooleanString()
+    someProperty: string;
+  }
 
-    it("should fail if NaN passed without allowing NaN values", () => {
-        return checkInvalidValues(new MyClass(), [NaN]);
-    });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    it("should fail if Infinity passed without allowing NaN values", () => {
-        return checkInvalidValues(new MyClass(), [Infinity, -Infinity]);
-    });
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-    it("should not fail if NaN passed and NaN as value is allowed", () => {
-        return checkValidValues(new NaNTestClass(), [NaN]);
-    });
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isBooleanString(value)).toBeTruthy());
+  });
 
-    it("should not fail if Infinity passed and Infinity as value is allowed", () => {
-        return checkValidValues(new InfinityTestClass(), [Infinity, -Infinity]);
-    });
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isBooleanString(value)).toBeFalsy());
+  });
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  it('should return error object with proper data', () => {
+    const validationType = 'isBooleanString';
+    const message = 'someProperty must be a boolean string';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+describe('IsNumberString', () => {
+  const validValues = ['123', '123.123', '00123', '-00123', '0', '-0', '+123'];
+  const invalidValues = [' ', '.'];
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isNumber(value)).toBeTruthy());
-    });
+  class MyClass {
+    @IsNumberString()
+    someProperty: string;
+  }
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isNumber(value)).toBeFalsy());
-    });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    it("should return error object with proper data", () => {
-        const validationType = "isNumber";
-        const message = "someProperty must be a number conforming to the specified constraints";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-    it("should pass if number of decimal places within maxDecimalPlaces", () => {
-        return checkValidValues(new MaxDecimalPlacesTest(), [1.123]);
-    });
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isNumberString(value)).toBeTruthy());
+  });
 
-    it("should fail if number of decimal places exceeds maxDecimalPlaces", () => {
-        return checkInvalidValues(new MaxDecimalPlacesTest(), [1.1234]);
-    });
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isNumberString(value)).toBeFalsy());
+  });
 
-    it("should pass if number of decimal places is zero", () => {
-        return checkValidValues(new ZeroDecimalPlacesTest(), [-10, -1, 0, 1, 10]);
-    });
+  it('should return error object with proper data', () => {
+    const validationType = 'isNumberString';
+    const message = 'someProperty must be a number string';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if number of decimal places is not zero", () => {
-        return checkInvalidValues(new ZeroDecimalPlacesTest(), [-11.1, -2.2, -0.1, 0.1, 2.2, 11.1]);
-    });
+describe('Contains', () => {
+  const constraint = 'hello';
+  const validValues = ['hello world'];
+  const invalidValues = [null, undefined, 'bye world'];
+
+  class MyClass {
+    @Contains(constraint)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(contains(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(contains(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'contains';
+    const message = 'someProperty must contain a ' + constraint + ' string';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("IsInt", () => {
-    const validValues = [2, 4, 100, 1000];
-    const invalidValues = [
-        "01",
-        "-01",
-        "000",
-        "100e10",
-        "123.123",
-        "   ",
-        "",
-        2.5,
-        -0.1
-    ];
+describe('NotContains', () => {
+  const constraint = 'hello';
+  const validValues = ['bye world'];
+  const invalidValues = [null, undefined, 'hello world'];
+
+  class MyClass {
+    @NotContains(constraint)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(notContains(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(notContains(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'notContains';
+    const message = 'someProperty should not contain a ' + constraint + ' string';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    class MyClass {
-        @IsInt()
-        someProperty: string;
-    }
+describe('IsAlpha', () => {
+  const constraint = 'en-GB';
+  const validValues = ['hellomynameisalex'];
+  const invalidValues = [null, undefined, 'hello1mynameisalex'];
+
+  class MyClass {
+    @IsAlpha()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isAlpha(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isAlpha(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isAlpha';
+    const message = 'someProperty must contain only letters (a-zA-Z)';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+describe('IsAlphanumeric', () => {
+  const constraint = '';
+  const validValues = ['hellomyname1salex'];
+  const invalidValues = [null, undefined, 'hell*mynameisalex'];
+
+  class MyClass {
+    @IsAlphanumeric()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isAlphanumeric(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isAlphanumeric(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isAlphanumeric';
+    const message = 'someProperty must contain only letters and numbers';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+describe('IsAscii', () => {
+  const constraint = '';
+  const validValues = ['hellomyname1salex'];
+  const invalidValues = [null, undefined, 'hell*mynameisлеха'];
+
+  class MyClass {
+    @IsAscii()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isAscii(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isAscii(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isAscii';
+    const message = 'someProperty must contain only ASCII characters';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isInt(value)).toBeTruthy());
-    });
+describe('IsDecimal', () => {
+  const validValues = [
+    '100.0',
+    '100.1',
+    '100.3',
+    '100.4',
+    '100.5',
+    '100.6',
+    '100.7',
+    '100.8',
+    '100.9',
+    '1.9',
+    '-1.9',
+    '-124.1',
+  ];
+
+  const invalidValues = [
+    null,
+    undefined,
+    'hello',
+    '',
+    '1',
+    '1.',
+    '1,',
+    '-1',
+    '100',
+    '100,100',
+    '100.23',
+    '100.214141',
+    '100,23',
+    '100,2143192',
+  ];
+
+  const isDecimalOptions: ValidatorJS.IsDecimalOptions = {
+    // eslint-disable-next-line @typescript-eslint/camelcase
+    force_decimal: true,
+    // eslint-disable-next-line @typescript-eslint/camelcase
+    decimal_digits: '1',
+    locale: 'en-US',
+  };
+
+  class MyClass {
+    @IsDecimal(isDecimalOptions)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isDecimal(value, isDecimalOptions)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isDecimal(value, isDecimalOptions)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isDecimal';
+    const message = 'someProperty is not a valid decimal number.';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isInt(value as any)).toBeFalsy());
-    });
+describe('IsBase32', () => {
+  const constraint = '';
+  const validValues = [
+    'ZG======',
+    'JBSQ====',
+    'JBSWY===',
+    'JBSWY3A=',
+    'JBSWY3DP',
+    'JBSWY3DPEA======',
+    'K5SWYY3PNVSSA5DPEBXG6ZA=',
+    'K5SWYY3PNVSSA5DPEBXG6===',
+  ];
+  const invalidValues = [
+    null,
+    undefined,
+    '12345',
+    '',
+    'JBSWY3DPtesting123',
+    'ZG=====',
+    'Z======',
+    'Zm=8JBSWY3DP',
+    '=m9vYg==',
+    'Zm9vYm/y====',
+  ];
+
+  class MyClass {
+    @IsBase32()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isBase32(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isBase32(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isBase32';
+    const message = 'someProperty must be base32 encoded';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should return error object with proper data", () => {
-        const validationType = "isInt";
-        const message = "someProperty must be an integer number";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+describe('IsBase64', () => {
+  const constraint = '';
+  const validValues = ['aGVsbG8='];
+  const invalidValues = [null, undefined, 'hell*mynameisalex'];
+
+  class MyClass {
+    @IsBase64()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isBase64(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isBase64(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isBase64';
+    const message = 'someProperty must be base64 encoded';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("IsString", () => {
-    const validValues = ["true", "false", "hello", "0", "", "1"];
-    const invalidValues = [
-        true,
-        false,
-        1,
-        2,
-        null,
-        undefined
-    ];
+describe('IsIBAN', () => {
+  const constraint = '';
+  const validValues = ['GR96 0810 0010 0000 0123 4567 890'];
+  const invalidValues = [null, undefined, 'XX22YYY1234567890123'];
+
+  class MyClass {
+    @IsIBAN()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isIBAN(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isIBAN(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isIBAN';
+    const message = 'someProperty must be an IBAN';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    class MyClass {
-        @IsString()
-        someProperty: string;
-    }
+describe('IsBIC', () => {
+  const constraint = '';
+  const validValues = ['SBICKEN1345'];
+  const invalidValues = [null, undefined, 'SBIC23NXXX'];
+
+  class MyClass {
+    @IsBIC()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isBIC(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isBIC(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isBIC';
+    const message = 'someProperty must be a BIC or SWIFT code';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+describe('IsEthereumAddress', () => {
+  const constraint = '';
+  const validValues = ['0x683E07492fBDfDA84457C16546ac3f433BFaa128'];
+  const invalidValues = [null, undefined, '0xFCb5AFB808b5679b4911230Aa41FfCD0cd335b422222'];
+
+  class MyClass {
+    @IsEthereumAddress()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isEthereumAddress(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isEthereumAddress(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isEthereumAddress';
+    const message = 'someProperty must be an Ethereum address';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+describe('IsBtcAddress', () => {
+  const constraint = '';
+  const validValues = ['bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq'];
+  const invalidValues = [null, undefined, 'pp8skudq3x5hzw8ew7vzsw8tn4k8wxsqsv0lt0mf3g'];
+
+  class MyClass {
+    @IsBtcAddress()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isBtcAddress(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isBtcAddress(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isBtcAddress';
+    const message = 'someProperty must be a BTC address';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isString(value)).toBeTruthy());
-    });
+describe('IsDataURI', () => {
+  const constraint = '';
+  const validValues = ['data:text/html;charset=US-ASCII,%3Ch1%3EHello!%3C%2Fh1%3E'];
+  const invalidValues = [null, undefined, 'data:HelloWorld'];
+
+  class MyClass {
+    @IsDataURI()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isDataURI(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isDataURI(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isDataURI';
+    const message = 'someProperty must be a data uri format';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isString(value as any)).toBeFalsy());
-    });
+describe('IsHSL', () => {
+  const constraint = '';
+  const validValues = ['hsl(-540, 03%, 4%)'];
+  const invalidValues = [null, undefined, 'hsl(-0160, 100%, 100a)'];
+
+  class MyClass {
+    @IsHSL()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isHSL(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isHSL(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isHSL';
+    const message = 'someProperty must be a HSL color';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should return error object with proper data", () => {
-        const validationType = "isString";
-        const message = "someProperty must be a string";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+describe('IsRgbColor', () => {
+  const constraint = '';
+  const validValues = ['rgba(255,255,255,0.1)'];
+  const invalidValues = [null, undefined, 'rgba(0,0,0)'];
+
+  class MyClass {
+    @IsRgbColor()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isRgbColor(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isRgbColor(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isRgbColor';
+    const message = 'someProperty must be RGB color';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("IsDateString", () => {
-    const validValues = [
-        "2017-06-06T17:04:42.081Z",
-        "2017-06-06T17:04:42.081",
-        "2018-01-04T08:15:30",
-        "2018-01-04T08:15:30Z",
-        "2018-01-04T08:15:30+04:00",
-        "2018-01-04T08:15:30+04",
-        "2020-03-26T11:00:01-03:00",
-        "2020-03-26T11:00:01-03",
-    ];
-    const invalidValues = [
-        true,
-        false,
-        1,
-        2,
-        null,
-        undefined,
-        "text",
-        "text2018-01-04T08:15:30+04",
-        "2018-01-04T08:15:30Ztext",
-    ];
+describe('IsIdentityCard', () => {
+  const constraint = 'he-IL';
+  const validValues = ['335240479'];
+  const invalidValues = [null, undefined, 'A1234567L'];
+
+  class MyClass {
+    @IsIdentityCard(constraint)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isIdentityCard(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isIdentityCard(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isIdentityCard';
+    const message = 'someProperty must be a identity card number';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    class MyClass {
-        @IsDateString()
-        someProperty: string;
-    }
+describe('IsEAN', () => {
+  const constraint = '';
+  const validValues = ['9771234567003'];
+  const invalidValues = [null, undefined, '079777681629'];
+
+  class MyClass {
+    @IsEAN()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isEAN(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isEAN(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isEAN';
+    const message = 'someProperty must be an EAN (European Article Number)';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+describe('IsISRC', () => {
+  const constraint = '';
+  const validValues = ['GBAYE6800011'];
+  const invalidValues = [null, undefined, 'SRC15705223'];
+
+  class MyClass {
+    @IsISRC()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isISRC(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isISRC(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isISRC';
+    const message = 'someProperty must be an ISRC';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+describe('IsRFC3339', () => {
+  const constraint = '';
+  const validValues = ['2010-02-18t00:23:23.33+06:00'];
+  const invalidValues = [null, undefined, '2009-05-31 14:60:55Z'];
+
+  class MyClass {
+    @IsRFC3339()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isRFC3339(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isRFC3339(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isRFC3339';
+    const message = 'someProperty must be RFC 3339 date';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isDateString(value)).toBeTruthy());
-    });
+describe('IsLocale', () => {
+  const constraint = '';
+  const validValues = ['en_US_POSIX'];
+  const invalidValues = [null, undefined, 'lo_POP'];
+
+  class MyClass {
+    @IsLocale()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isLocale(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isLocale(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isLocale';
+    const message = 'someProperty must be locale';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isDateString(value as any)).toBeFalsy());
-    });
+describe('IsMagnetURI', () => {
+  const constraint = '';
+  const validValues = ['magnet:?xt=urn:btih:1GSHJVBDVDVJFYEHKFHEFIO8573898434JBFEGHD&dn=foo&tr=udp://foo.com:1337'];
+  const invalidValues = [
+    null,
+    undefined,
+    'magnet:?xt=uarn:btih:MCJDCYUFHEUD6E2752T7UJNEKHSUGEJFGTFHVBJS&dn=bar&tr=udp://bar.com:1337',
+  ];
+
+  class MyClass {
+    @IsMagnetURI()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isMagnetURI(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isMagnetURI(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isMagnetURI';
+    const message = 'someProperty must be magnet uri format';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should return error object with proper data", () => {
-        const validationType = "isDateString";
-        // const message = "someProperty deve ser um texto de data";
-        const message = "someProperty must be a ISOString";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+describe('IsMimeType', () => {
+  const constraint = '';
+  const validValues = ['multipart/form-data; boundary=something; charset=utf-8'];
+  const invalidValues = [null, undefined, 'font/woff2; charset=utf-8'];
+
+  class MyClass {
+    @IsMimeType()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isMimeType(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isMimeType(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isMimeType';
+    const message = 'someProperty must be MIME type format';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("IsArray", () => {
-    const validValues = [[], [1, 2, 3], [0, 0, 0], [""], [0], [undefined], [{}], []];
-    const invalidValues = [
-        true,
-        false,
-        1,
-        {},
-        null,
-        undefined
-    ];
+describe('IsOctal', () => {
+  const constraint = '';
+  const validValues = ['0o01234567'];
+  const invalidValues = [null, undefined, '00c12345670c'];
+
+  class MyClass {
+    @IsOctal()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isOctal(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isOctal(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isOctal';
+    const message = 'someProperty must be valid octal number';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    class MyClass {
-        @IsArray()
-        someProperty: string[];
-    }
+describe('IsPassportNumber', () => {
+  const constraint = 'DE';
+  const validValues = ['C26VMVVC3'];
+  const invalidValues = [null, undefined, 'AS0123456'];
+
+  class MyClass {
+    @IsPassportNumber(constraint)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isPassportNumber(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isPassportNumber(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isPassportNumber';
+    const message = 'someProperty must be valid passport number';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+describe('IsPostalCode', () => {
+  const constraint = 'BR';
+  const validValues = ['39100-000'];
+  const invalidValues = [null, undefined, '13165-00'];
+
+  class MyClass {
+    @IsPostalCode(constraint)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isPostalCode(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isPostalCode(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isPostalCode';
+    const message = 'someProperty must be a postal code';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+describe('IsSemVer', () => {
+  const constraint = '';
+  const validValues = ['1.1.2+meta-valid'];
+  const invalidValues = [null, undefined, '1.0.0-alpha_beta'];
+
+  class MyClass {
+    @IsSemVer()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isSemVer(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isSemVer(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isSemVer';
+    const message = 'someProperty must be a Semantic Versioning Specification';
+    checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isArray(value)).toBeTruthy());
-    });
+describe('IsByteLength', () => {
+  const constraint1 = 2;
+  const constraint2 = 20;
+  const validValues = ['hellostring'];
+  const invalidValues = [null, undefined, 'helloveryveryveryverylongstring'];
+
+  class MyClass {
+    @IsByteLength(constraint1, constraint2)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isByteLength(value, constraint1, constraint2)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isByteLength(value, constraint1, constraint2)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isByteLength';
+    const message = "someProperty's byte length must fall into (" + constraint1 + ', ' + constraint2 + ') range';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isArray(value as any)).toBeFalsy());
-    });
+describe('IsCreditCard', () => {
+  const validValues = [
+    '375556917985515',
+    '36050234196908',
+    '4716461583322103',
+    '4716-2210-5188-5662',
+    '4929 7226 5379 7141',
+    '5398228707871527',
+  ];
+  const invalidValues = [null, undefined, 'foo', 'foo', '5398228707871528'];
+
+  class MyClass {
+    @IsCreditCard()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isCreditCard(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isCreditCard(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isCreditCard';
+    const message = 'someProperty must be a credit card';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should return error object with proper data", () => {
-        const validationType = "isArray";
-        const message = "someProperty must be an array";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+describe('IsCurrency', () => {
+  const validValues = [
+    '-$10,123.45',
+    '$10,123.45',
+    '$10123.45',
+    '10,123.45',
+    '10123.45',
+    '10,123',
+    '1,123,456',
+    '1123456',
+    '1.39',
+    '.03',
+    '0.10',
+    '$0.10',
+    '-$0.01',
+    '-$.99',
+    '$100,234,567.89',
+    '$10,123',
+    '10,123',
+    '-10123',
+  ];
+  const invalidValues = [
+    null,
+    undefined,
+    '1.234',
+    '$1.1',
+    '$ 32.50',
+    '500$',
+    '.0001',
+    '$.001',
+    '$0.001',
+    '12,34.56',
+    '123456,123,123456',
+    '123,4',
+    ',123',
+    '$-,123',
+    '$',
+    '.',
+    ',',
+    '00',
+    '$-',
+    '$-,.',
+    '-',
+    '-$',
+    '',
+    '- $',
+  ];
+
+  class MyClass {
+    @IsCurrency()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isCurrency(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isCurrency(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isCurrency';
+    const message = 'someProperty must be a currency';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
+describe('IsEmail', () => {
+  const validValues = [
+    'foo@bar.com',
+    'x@x.au',
+    'foo@bar.com.au',
+    'foo+bar@bar.com',
+    'hans.m端ller@test.com',
+    'hans@m端ller.com',
+    'test|123@m端ller.com',
+    '"foobar"@example.com',
+    '"  foo  m端ller "@example.com',
+    '"foo\\@bar"@example.com',
+  ];
+  const invalidValues = [
+    null,
+    undefined,
+    'invalidemail@',
+    'invalid.com',
+    '@invalid.com',
+    'foo@bar.com.',
+    'somename@gmail.com',
+    'foo@bar.co.uk.',
+    'z@co.c',
+    'gmail...ignores...dots...@gmail.com',
+    'gmailgmailgmailgmailgmail@gmail.com',
+  ];
+
+  class MyClass {
+    @IsEmail()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => {
+      expect(isEmail(value)).toBeTruthy();
+    });
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isEmail(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isEmail';
+    const message = 'someProperty must be an email';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-describe("IsEnum", () => {
-    enum MyEnum {
-        First = 1,
-        Second = 999
-    }
+describe('IsFQDN', () => {
+  const validValues = [
+    'domain.com',
+    'dom.plato',
+    'a.domain.co',
+    'foo--bar.com',
+    'xn--froschgrn-x9a.com',
+    'rebecca.blackfriday',
+  ];
+  const invalidValues = [
+    null,
+    undefined,
+    'abc',
+    '256.0.0.0',
+    '_.com',
+    '*.some.com',
+    's!ome.com',
+    'domain.com/',
+    '/more.com',
+  ];
+
+  class MyClass {
+    @IsFQDN()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isFQDN(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isFQDN(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isFqdn';
+    const message = 'someProperty must be a valid domain name';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    enum MyStringEnum {
-        First = "first",
-        Second = "second"
-    }
+describe('IsFullWidth', () => {
+  const validValues = ['ひらがな・カタカナ、.漢字', '3ー0 a@com', 'Fカタカナ゙ᆲ', 'Good=Parts'];
+  const invalidValues = [null, undefined, 'abc', 'abc123'];
 
-    const validValues = [MyEnum.First, MyEnum.Second];
-    const validStringValues = [MyStringEnum.First, MyStringEnum.Second];
-    const invalidValues = [
-        true,
-        false,
-        0,
-        {},
-        null,
-        undefined,
-        "F2irst"
-    ];
+  class MyClass {
+    @IsFullWidth()
+    someProperty: string;
+  }
 
-    class MyClass {
-        @IsEnum(MyEnum)
-        someProperty: MyEnum;
-    }
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    class MyClass2 {
-        @IsEnum(MyStringEnum)
-        someProperty: MyStringEnum;
-    }
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isFullWidth(value)).toBeTruthy());
+  });
 
-    it("should not fail if validator.validate said that its valid (string enum)", () => {
-        return checkValidValues(new MyClass2(), validStringValues);
-    });
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isFullWidth(value)).toBeFalsy());
+  });
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+  it('should return error object with proper data', () => {
+    const validationType = 'isFullWidth';
+    const message = 'someProperty must contain a full-width characters';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if validator.validate said that its invalid (string enum)", () => {
-        return checkInvalidValues(new MyClass2(), invalidValues);
-    });
+describe('IsHalfWidth', () => {
+  const validValues = ['l-btn_02--active', 'abc123い', 'カタカナ゙ᆲ←'];
+  const invalidValues = [null, undefined, 'あいうえお', '0011'];
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isEnum(value, MyEnum)).toBeTruthy());
-    });
+  class MyClass {
+    @IsHalfWidth()
+    someProperty: string;
+  }
 
-    it("should not fail if method in validator said that its valid (string enum)", () => {
-        validStringValues.forEach(value => expect(isEnum(value, MyStringEnum)).toBeTruthy());
-    });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isEnum(value, MyEnum)).toBeFalsy());
-    });
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-    it("should fail if method in validator said that its invalid (string enum)", () => {
-        invalidValues.forEach(value => expect(isEnum(value, MyStringEnum)).toBeFalsy());
-    });
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isHalfWidth(value)).toBeTruthy());
+  });
 
-    it("should return error object with proper data", () => {
-        const validationType = "isEnum";
-        const message = "someProperty must be a valid enum value";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isHalfWidth(value)).toBeFalsy());
+  });
 
-    it("should return error object with proper data (string enum)", () => {
-        const validationType = "isEnum";
-        const message = "someProperty must be a valid enum value";
-        checkReturnedError(new MyClass2(), invalidValues, validationType, message);
-    });
+  it('should return error object with proper data', () => {
+    const validationType = 'isHalfWidth';
+    const message = 'someProperty must contain a half-width characters';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("IsDivisibleBy", () => {
-    const constraint = 2;
-    const validValues = [2, 4, 100, 1000];
-    const invalidValues = ["", undefined, null];
+describe('IsVariableWidth', () => {
+  const validValues = ['ひらがなカタカナ漢字ABCDE', '3ー0123', 'Fカタカナ゙ᆲ', 'Good=Parts'];
+  const invalidValues = [
+    null,
+    undefined,
+    'abc',
+    'abc123',
+    '!"#$%&()<>/+=-_? ~^|.,@`{}[]',
+    'ひらがな・カタカナ、.漢字',
+    '123456',
+    'カタカナ゙ᆲ',
+  ];
+
+  class MyClass {
+    @IsVariableWidth()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isVariableWidth(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isVariableWidth(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isVariableWidth';
+    const message = 'someProperty must contain a full-width and half-width characters';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    class MyClass {
-        @IsDivisibleBy(constraint)
-        someProperty: string;
-    }
+describe('IsHexColor', () => {
+  const validValues = ['#ff0034', '#CCCCCC', 'fff', '#f00'];
+  const invalidValues = [null, undefined, '#ff', '#xxxx', '#ff12FG'];
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  class MyClass {
+    @IsHexColor()
+    someProperty: string;
+  }
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isDivisibleBy(value, constraint)).toBeTruthy());
-    });
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isDivisibleBy(value as any, constraint)).toBeFalsy());
-    });
+  it('should not fail if method in validator said that its valid', () => {
+    invalidValues.forEach(value => expect(isHexColor(value)).toBeFalsy());
+  });
 
-    it("should return error object with proper data", () => {
-        const validationType = "isDivisibleBy";
-        const message = "someProperty must be divisible by " + constraint;
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+  it('should fail if method in validator said that its invalid', () => {
+    validValues.forEach(value => expect(isHexColor(value)).toBeTruthy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isHexColor';
+    const message = 'someProperty must be a hexadecimal color';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("IsPositive", () => {
-    const validValues = [
-        3,
-        5000,
-    ];
-    const invalidValues = [
-        "-1",
-        "-2",
-        "0",
-        "1",
-        "2",
-        "3",
-        "4",
-        "5",
-        "6",
-        "7",
-        "8",
-        "9",
-        "100000",
-        -500,
-        -123,
-        -1,
-        "   ",
-        ""
-    ];
+describe('IsHexadecimal', () => {
+  const validValues = ['deadBEEF', 'ff0044'];
+  const invalidValues = [null, undefined, 'abcdefg', '', '..'];
 
-    class MyClass {
-        @IsPositive()
-        someProperty: string;
-    }
+  class MyClass {
+    @IsHexadecimal()
+    someProperty: string;
+  }
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isPositive(value)).toBeTruthy());
-    });
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isHexadecimal(value)).toBeTruthy());
+  });
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isPositive(value as any)).toBeFalsy());
-    });
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isHexadecimal(value)).toBeFalsy());
+  });
 
-    it("should return error object with proper data", () => {
-        const validationType = "isPositive";
-        const message = "someProperty must be a positive number";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+  it('should return error object with proper data', () => {
+    const validationType = 'isHexadecimal';
+    const message = 'someProperty must be a hexadecimal number';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("IsNegative", () => {
-    const validValues = [
-        -3,
-        -5000,
-        -0.1,
-    ];
-    const invalidValues = [
-        "-1",
-        "-2",
-        "0",
-        "1",
-        "2",
-        "3",
-        "4",
-        "5",
-        "6",
-        "7",
-        "8",
-        "9",
-        "100000",
-        500,
-        123,
-        1,
-        "   ",
-        ""
-    ];
+describe('IsMACAddress', () => {
+  const validValues = ['ab:ab:ab:ab:ab:ab', 'FF:FF:FF:FF:FF:FF', '01:02:03:04:05:ab', '01:AB:03:04:05:06'];
+  const invalidValues = [
+    null,
+    undefined,
+    'abc',
+    '01:02:03:04:05',
+    '01:02:03:04::ab',
+    '1:2:3:4:5:6',
+    'AB:CD:EF:GH:01:02',
+    'A9C5 D4 9F EB D3',
+    '01-02 03:04 05 ab',
+  ];
+
+  class MyClass {
+    @IsMACAddress()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isMACAddress(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isMACAddress(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isMacAddress';
+    const message = 'someProperty must be a MAC Address';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    class MyClass {
-        @IsNegative()
-        someProperty: string;
-    }
+describe('IsIP', () => {
+  const validValues = [
+    '127.0.0.1',
+    '0.0.0.0',
+    '255.255.255.255',
+    '1.2.3.4',
+    '::1',
+    '2001:db8:0000:1:1:1:1:1',
+    '2001:41d0:2:a141::1',
+    '::ffff:127.0.0.1',
+    '::0000',
+    '0000::',
+    '1::',
+    '1111:1:1:1:1:1:1:1',
+    'fe80::a6db:30ff:fe98:e946',
+    '::',
+    '::ffff:127.0.0.1',
+    '0:0:0:0:0:ffff:127.0.0.1',
+  ];
+  const invalidValues = [
+    null,
+    undefined,
+    'abc',
+    '256.0.0.0',
+    '0.0.0.256',
+    '26.0.0.256',
+    '::banana',
+    'banana::',
+    '::1banana',
+    '::1::',
+    '1:',
+    ':1',
+    ':1:1:1::2',
+    '1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1',
+    '::11111',
+    '11111:1:1:1:1:1:1:1',
+    '2001:db8:0000:1:1:1:1::1',
+    '0:0:0:0:0:0:ffff:127.0.0.1',
+    '0:0:0:0:ffff:127.0.0.1',
+  ];
+
+  class MyClass {
+    @IsIP()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isIP(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isIP(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isIp';
+    const message = 'someProperty must be an ip address';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+describe('IsISBN version 10', () => {
+  const validValues = [
+    '3836221195',
+    '3-8362-2119-5',
+    '3 8362 2119 5',
+    '1617290858',
+    '1-61729-085-8',
+    '1 61729 085-8',
+    '0007269706',
+    '0-00-726970-6',
+    '0 00 726970 6',
+    '3423214120',
+    '3-423-21412-0',
+    '3 423 21412 0',
+    '340101319X',
+    '3-401-01319-X',
+    '3 401 01319 X',
+  ];
+  const invalidValues = [
+    null,
+    undefined,
+    '3423214121',
+    '3-423-21412-1',
+    '3 423 21412 1',
+    '978-3836221191',
+    '9783836221191',
+    '123456789a',
+    'foo',
+  ];
+
+  class MyClass {
+    @IsISBN(10)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isISBN(value, '10')).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isISBN(value, '10')).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isIsbn';
+    const message = 'someProperty must be an ISBN';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+describe('IsISBN version 13', () => {
+  const validValues = [
+    '9783836221191',
+    '978-3-8362-2119-1',
+    '978 3 8362 2119 1',
+    '9783401013190',
+    '978-3401013190',
+    '978 3401013190',
+    '9784873113685',
+    '978-4-87311-368-5',
+    '978 4 87311 368 5',
+  ];
+  const invalidValues = [
+    null,
+    undefined,
+    '9783836221190',
+    '978-3-8362-2119-0',
+    '978 3 8362 2119 0',
+    '3836221195',
+    '3-8362-2119-5',
+    '3 8362 2119 5',
+    '01234567890ab',
+    'foo',
+    '',
+  ];
+
+  class MyClass {
+    @IsISBN(13)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isISBN(value, '13')).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isISBN(value, '13')).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isIsbn';
+    const message = 'someProperty must be an ISBN';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isNegative(value)).toBeTruthy());
-    });
+describe('IsISO8601', () => {
+  const validValues = [
+    '2009-12T12:34',
+    '2009',
+    '2009-05-19',
+    '2009-05-19',
+    '20090519',
+    '2009123',
+    '2009-05',
+    '2009-123',
+    '2009-222',
+    '2009-001',
+    '2009-W01-1',
+    '2009-W51-1',
+    '2009-W511',
+    '2009-W33',
+    '2009W511',
+    '2009-05-19',
+    '2009-05-19 00:00',
+    '2009-05-19 14',
+    '2009-05-19 14:31',
+    '2009-05-19 14:39:22',
+    '2009-05-19T14:39Z',
+    '2009-W21-2',
+    '2009-W21-2T01:22',
+    '2009-139',
+    '2009-05-19 14:39:22-06:00',
+    '2009-05-19 14:39:22+0600',
+    '2009-05-19 14:39:22-01',
+    '20090621T0545Z',
+    '2007-04-06T00:00',
+    '2007-04-05T24:00',
+    '2010-02-18T16:23:48.5',
+    '2010-02-18T16:23:48,444',
+    '2010-02-18T16:23:48,3-06:00',
+    '2010-02-18T16:23.4',
+    '2010-02-18T16:23,25',
+    '2010-02-18T16:23.33+0600',
+    '2010-02-18T16.23334444',
+    '2010-02-18T16,2283',
+    '2009-05-19 143922.500',
+    '2009-05-19 1439,55',
+  ];
+  const invalidValues = [
+    null,
+    undefined,
+    '200905',
+    '2009367',
+    '2009-',
+    '2007-04-05T24:50',
+    '2009-000',
+    '2009-M511',
+    '2009M511',
+    '2009-05-19T14a39r',
+    '2009-05-19T14:3924',
+    '2009-0519',
+    '2009-05-1914:39',
+    '2009-05-19 14:',
+    '2009-05-19r14:39',
+    '2009-05-19 14a39a22',
+    '200912-01',
+    '2009-05-19 14:39:22+06a00',
+    '2009-05-19 146922.500',
+    '2010-02-18T16.5:23.35:48',
+    '2010-02-18T16:23.35:48',
+    '2010-02-18T16:23.35:48.45',
+    '2009-05-19 14.5.44',
+    '2010-02-18T16:23.33.600',
+    '2010-02-18T16,25:23:48,444',
+  ];
+
+  class MyClass {
+    @IsISO8601()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isISO8601(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isISO8601(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isIso8601';
+    const message = 'someProperty must be a valid ISO 8601 date string';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isNegative(value as any)).toBeFalsy());
-    });
+describe('IsJSON', () => {
+  const validValues = ['{ "key": "value" }', '{}'];
+  const invalidValues = [null, undefined, '{ key: "value" }', "{ 'key': 'value' }", 'null', '1234', 'false', '"nope"'];
 
-    it("should return error object with proper data", () => {
-        const validationType = "isNegative";
-        const message = "someProperty must be a negative number";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
+  class MyClass {
+    @IsJSON()
+    someProperty: string;
+  }
 
-describe("Min", () => {
-    const constraint = 10;
-    const validValues = [10, 11, 20, 30, 40];
-    const invalidValues = [2, 3, 4, 5, 6, 7, 8, 9, -10];
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    class MyClass {
-        @Min(constraint)
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(min(value, constraint)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(min(value, constraint)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "min";
-        const message = "someProperty must not be less than " + constraint;
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("Max", () => {
-    const constraint = 10;
-    const validValues = [1, 2, 3, 4, 5, 6, 7, 8, 9, -10, 10];
-    const invalidValues = [11, 20, 30, 40];
-
-    class MyClass {
-        @Max(constraint)
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(max(value, constraint)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(max(value, constraint)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "max";
-        const message = "someProperty must not be greater than " + constraint;
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("MinDate", () => {
-    const constraint = new Date(1995, 11, 17);
-    const validValues = [new Date()];
-    const invalidValues = [new Date(1994, 11, 17)];
-
-    class MyClass {
-        @MinDate(constraint)
-        someProperty: Date;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(minDate(value, constraint)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(minDate(value, constraint)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "minDate";
-        const message = "minimal allowed date for someProperty is " + constraint;
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("MaxDate", () => {
-    const constraint = new Date(1995, 11, 17);
-    const validValues = [new Date(1994, 11, 17)];
-    const invalidValues = [new Date()];
-
-    class MyClass {
-        @MaxDate(constraint)
-        someProperty: Date;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(maxDate(value, constraint)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(maxDate(value, constraint)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "maxDate";
-        const message = "maximal allowed date for someProperty is " + constraint;
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsBooleanString", () => {
-    const validValues = [
-        "1",
-        "0",
-        "true",
-        "false"
-    ];
-    const invalidValues = [
-        "2",
-        "3",
-        "falze"
-    ];
-
-    class MyClass {
-        @IsBooleanString()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isBooleanString(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isBooleanString(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isBooleanString";
-        const message = "someProperty must be a boolean string";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsNumberString", () => {
-    const validValues = [
-        "123",
-        "123.123",
-        "00123",
-        "-00123",
-        "0",
-        "-0",
-        "+123"
-    ];
-    const invalidValues = [
-        " ",
-        "."
-    ];
-
-    class MyClass {
-        @IsNumberString()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isNumberString(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isNumberString(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isNumberString";
-        const message = "someProperty must be a number string";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("Contains", () => {
-    const constraint = "hello";
-    const validValues = ["hello world"];
-    const invalidValues = [null, undefined, "bye world"];
-
-    class MyClass {
-        @Contains(constraint)
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(contains(value, constraint)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(contains(value, constraint)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "contains";
-        const message = "someProperty must contain a " + constraint + " string";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("NotContains", () => {
-    const constraint = "hello";
-    const validValues = ["bye world"];
-    const invalidValues = [null, undefined, "hello world"];
-
-    class MyClass {
-        @NotContains(constraint)
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(notContains(value, constraint)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(notContains(value, constraint)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "notContains";
-        const message = "someProperty should not contain a " + constraint + " string";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsAlpha", () => {
-    const constraint = "en-GB";
-    const validValues = ["hellomynameisalex"];
-    const invalidValues = [null, undefined, "hello1mynameisalex"];
-
-    class MyClass {
-        @IsAlpha()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isAlpha(value, constraint)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isAlpha(value, constraint)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isAlpha";
-        const message = "someProperty must contain only letters (a-zA-Z)";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsAlphanumeric", () => {
-    const constraint = "";
-    const validValues = ["hellomyname1salex"];
-    const invalidValues = [null, undefined, "hell*mynameisalex"];
-
-    class MyClass {
-        @IsAlphanumeric()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isAlphanumeric(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isAlphanumeric(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isAlphanumeric";
-        const message = "someProperty must contain only letters and numbers";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsAscii", () => {
-    const constraint = "";
-    const validValues = ["hellomyname1salex"];
-    const invalidValues = [null, undefined, "hell*mynameisлеха"];
-
-    class MyClass {
-        @IsAscii()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isAscii(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isAscii(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isAscii";
-        const message = "someProperty must contain only ASCII characters";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsDecimal", () => {
-    const validValues = [
-        "100.0",
-        "100.1",
-        "100.3",
-        "100.4",
-        "100.5",
-        "100.6",
-        "100.7",
-        "100.8",
-        "100.9",
-        "1.9",
-        "-1.9",
-        "-124.1"
-    ];
-
-    const invalidValues = [
-        null,
-        undefined,
-        "hello",
-        "",
-        "1",
-        "1.",
-        "1,",
-        "-1",
-        "100",
-        "100,100",
-        "100.23",
-        "100.214141",
-        "100,23",
-        "100,2143192"
-    ];
-
-    const isDecimalOptions: ValidatorJS.IsDecimalOptions = {
-        // eslint-disable-next-line @typescript-eslint/camelcase
-        force_decimal: true,
-        // eslint-disable-next-line @typescript-eslint/camelcase
-        decimal_digits: "1",
-        locale: "en-US"
-    };
-
-    class MyClass {
-        @IsDecimal(isDecimalOptions)
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isDecimal(value, isDecimalOptions)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isDecimal(value, isDecimalOptions)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isDecimal";
-        const message = "someProperty is not a valid decimal number.";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsBase32", () => {
-    const constraint = "";
-    const validValues = [
-        "ZG======",
-        "JBSQ====",
-        "JBSWY===",
-        "JBSWY3A=",
-        "JBSWY3DP",
-        "JBSWY3DPEA======",
-        "K5SWYY3PNVSSA5DPEBXG6ZA=",
-        "K5SWYY3PNVSSA5DPEBXG6===",
-    ];
-    const invalidValues = [
-        null,
-        undefined,
-        "12345",
-        "",
-        "JBSWY3DPtesting123",
-        "ZG=====",
-        "Z======",
-        "Zm=8JBSWY3DP",
-        "=m9vYg==",
-        "Zm9vYm/y====",
-    ];
-
-    class MyClass {
-        @IsBase32()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isBase32(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isBase32(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isBase32";
-        const message = "someProperty must be base32 encoded";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsBase64", () => {
-    const constraint = "";
-    const validValues = ["aGVsbG8="];
-    const invalidValues = [null, undefined, "hell*mynameisalex"];
-
-    class MyClass {
-        @IsBase64()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isBase64(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isBase64(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isBase64";
-        const message = "someProperty must be base64 encoded";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsIBAN", () => {
-
-    const constraint = "";
-    const validValues = ["GR96 0810 0010 0000 0123 4567 890"];
-    const invalidValues = [null, undefined, "XX22YYY1234567890123"];
-
-    class MyClass {
-        @IsIBAN()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isIBAN(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isIBAN(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isIBAN";
-        const message = "someProperty must be an IBAN";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsBIC", () => {
-
-    const constraint = "";
-    const validValues = ["SBICKEN1345"];
-    const invalidValues = [null, undefined, "SBIC23NXXX"];
-
-    class MyClass {
-        @IsBIC()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isBIC(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isBIC(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isBIC";
-        const message = "someProperty must be a BIC or SWIFT code";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsEthereumAddress", () => {
-
-    const constraint = "";
-    const validValues = ["0x683E07492fBDfDA84457C16546ac3f433BFaa128"];
-    const invalidValues = [null, undefined, "0xFCb5AFB808b5679b4911230Aa41FfCD0cd335b422222"];
-
-    class MyClass {
-        @IsEthereumAddress()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isEthereumAddress(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isEthereumAddress(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isEthereumAddress";
-        const message = "someProperty must be an Ethereum address";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsBtcAddress", () => {
-
-    const constraint = "";
-    const validValues = ["bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq"];
-    const invalidValues = [null, undefined, "pp8skudq3x5hzw8ew7vzsw8tn4k8wxsqsv0lt0mf3g"];
-
-    class MyClass {
-        @IsBtcAddress()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isBtcAddress(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isBtcAddress(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isBtcAddress";
-        const message = "someProperty must be a BTC address";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsDataURI", () => {
-
-    const constraint = "";
-    const validValues = ["data:text/html;charset=US-ASCII,%3Ch1%3EHello!%3C%2Fh1%3E"];
-    const invalidValues = [null, undefined, "data:HelloWorld"];
-
-    class MyClass {
-        @IsDataURI()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isDataURI(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isDataURI(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isDataURI";
-        const message = "someProperty must be a data uri format";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsHSL", () => {
-
-    const constraint = "";
-    const validValues = ["hsl(-540, 03%, 4%)"];
-    const invalidValues = [null, undefined, "hsl(-0160, 100%, 100a)"];
-
-    class MyClass {
-        @IsHSL()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isHSL(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isHSL(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isHSL";
-        const message = "someProperty must be a HSL color";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsRgbColor", () => {
-
-    const constraint = "";
-    const validValues = ["rgba(255,255,255,0.1)"];
-    const invalidValues = [null, undefined, "rgba(0,0,0)"];
-
-    class MyClass {
-        @IsRgbColor()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isRgbColor(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isRgbColor(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isRgbColor";
-        const message = "someProperty must be RGB color";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsIdentityCard", () => {
-
-    const constraint = "he-IL";
-    const validValues = ["335240479"];
-    const invalidValues = [null, undefined, "A1234567L"];
-
-    class MyClass {
-        @IsIdentityCard(constraint)
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isIdentityCard(value, constraint)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isIdentityCard(value, constraint)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isIdentityCard";
-        const message = "someProperty must be a identity card number";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsEAN", () => {
-
-    const constraint = "";
-    const validValues = ["9771234567003"];
-    const invalidValues = [null, undefined, "079777681629"];
-
-    class MyClass {
-        @IsEAN()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isEAN(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isEAN(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isEAN";
-        const message = "someProperty must be an EAN (European Article Number)";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsISRC", () => {
-
-    const constraint = "";
-    const validValues = ["GBAYE6800011"];
-    const invalidValues = [null, undefined, "SRC15705223"];
-
-    class MyClass {
-        @IsISRC()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isISRC(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isISRC(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isISRC";
-        const message = "someProperty must be an ISRC";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsRFC3339", () => {
-
-    const constraint = "";
-    const validValues = ["2010-02-18t00:23:23.33+06:00"];
-    const invalidValues = [null, undefined, "2009-05-31 14:60:55Z"];
-
-    class MyClass {
-        @IsRFC3339()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isRFC3339(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isRFC3339(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isRFC3339";
-        const message = "someProperty must be RFC 3339 date";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsLocale", () => {
-
-    const constraint = "";
-    const validValues = ["en_US_POSIX"];
-    const invalidValues = [null, undefined, "lo_POP"];
-
-    class MyClass {
-        @IsLocale()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isLocale(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isLocale(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isLocale";
-        const message = "someProperty must be locale";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsMagnetURI", () => {
-
-    const constraint = "";
-    const validValues = ["magnet:?xt=urn:btih:1GSHJVBDVDVJFYEHKFHEFIO8573898434JBFEGHD&dn=foo&tr=udp://foo.com:1337"];
-    const invalidValues = [null, undefined, "magnet:?xt=uarn:btih:MCJDCYUFHEUD6E2752T7UJNEKHSUGEJFGTFHVBJS&dn=bar&tr=udp://bar.com:1337"];
-
-    class MyClass {
-        @IsMagnetURI()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isMagnetURI(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isMagnetURI(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isMagnetURI";
-        const message = "someProperty must be magnet uri format";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsMimeType", () => {
-
-    const constraint = "";
-    const validValues = ["multipart/form-data; boundary=something; charset=utf-8"];
-    const invalidValues = [null, undefined, "font/woff2; charset=utf-8"];
-
-    class MyClass {
-        @IsMimeType()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isMimeType(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isMimeType(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isMimeType";
-        const message = "someProperty must be MIME type format";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsOctal", () => {
-
-    const constraint = "";
-    const validValues = ["0o01234567"];
-    const invalidValues = [null, undefined, "00c12345670c"];
-
-    class MyClass {
-        @IsOctal()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isOctal(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isOctal(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isOctal";
-        const message = "someProperty must be valid octal number";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsPassportNumber", () => {
-
-    const constraint = "DE";
-    const validValues = ["C26VMVVC3"];
-    const invalidValues = [null, undefined, "AS0123456"];
-
-    class MyClass {
-        @IsPassportNumber(constraint)
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isPassportNumber(value, constraint)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isPassportNumber(value, constraint)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isPassportNumber";
-        const message = "someProperty must be valid passport number";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsPostalCode", () => {
-
-    const constraint = "BR";
-    const validValues = ["39100-000"];
-    const invalidValues = [null, undefined, "13165-00"];
-
-    class MyClass {
-        @IsPostalCode(constraint)
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isPostalCode(value, constraint)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isPostalCode(value, constraint)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isPostalCode";
-        const message = "someProperty must be a postal code";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsSemVer", () => {
-
-    const constraint = "";
-    const validValues = ["1.1.2+meta-valid"];
-    const invalidValues = [null, undefined, "1.0.0-alpha_beta"];
-
-    class MyClass {
-        @IsSemVer()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isSemVer(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isSemVer(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isSemVer";
-        const message = "someProperty must be a Semantic Versioning Specification";
-        checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
-});
-
-describe("IsByteLength", () => {
-    const constraint1 = 2;
-    const constraint2 = 20;
-    const validValues = ["hellostring"];
-    const invalidValues = [null, undefined, "helloveryveryveryverylongstring"];
-
-    class MyClass {
-        @IsByteLength(constraint1, constraint2)
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isByteLength(value, constraint1, constraint2)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isByteLength(value, constraint1, constraint2)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isByteLength";
-        const message = "someProperty's byte length must fall into (" + constraint1 + ", " + constraint2 + ") range";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsCreditCard", () => {
-    const validValues = [
-        "375556917985515",
-        "36050234196908",
-        "4716461583322103",
-        "4716-2210-5188-5662",
-        "4929 7226 5379 7141",
-        "5398228707871527"
-    ];
-    const invalidValues = [null, undefined, "foo", "foo", "5398228707871528"];
-
-    class MyClass {
-        @IsCreditCard()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isCreditCard(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isCreditCard(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isCreditCard";
-        const message = "someProperty must be a credit card";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsCurrency", () => {
-    const validValues = [
-        "-$10,123.45",
-        "$10,123.45",
-        "$10123.45",
-        "10,123.45",
-        "10123.45",
-        "10,123",
-        "1,123,456",
-        "1123456",
-        "1.39",
-        ".03",
-        "0.10",
-        "$0.10",
-        "-$0.01",
-        "-$.99",
-        "$100,234,567.89",
-        "$10,123",
-        "10,123",
-        "-10123"
-    ];
-    const invalidValues = [
-        null,
-        undefined,
-        "1.234",
-        "$1.1",
-        "$ 32.50",
-        "500$",
-        ".0001",
-        "$.001",
-        "$0.001",
-        "12,34.56",
-        "123456,123,123456",
-        "123,4",
-        ",123",
-        "$-,123",
-        "$",
-        ".",
-        ",",
-        "00",
-        "$-",
-        "$-,.",
-        "-",
-        "-$",
-        "",
-        "- $"
-    ];
-
-    class MyClass {
-        @IsCurrency()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isCurrency(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isCurrency(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isCurrency";
-        const message = "someProperty must be a currency";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsEmail", () => {
-    const validValues = [
-        "foo@bar.com",
-        "x@x.au",
-        "foo@bar.com.au",
-        "foo+bar@bar.com",
-        "hans.m端ller@test.com",
-        "hans@m端ller.com",
-        "test|123@m端ller.com",
-        "\"foobar\"@example.com",
-        "\"  foo  m端ller \"@example.com",
-        "\"foo\\@bar\"@example.com"
-    ];
-    const invalidValues = [
-        null,
-        undefined,
-        "invalidemail@",
-        "invalid.com",
-        "@invalid.com",
-        "foo@bar.com.",
-        "somename@gmail.com",
-        "foo@bar.co.uk.",
-        "z@co.c",
-        "gmail...ignores...dots...@gmail.com",
-        "gmailgmailgmailgmailgmail@gmail.com"
-    ];
-
-    class MyClass {
-        @IsEmail()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => {
-            expect(isEmail(value)).toBeTruthy();
-        });
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isEmail(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isEmail";
-        const message = "someProperty must be an email";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsFQDN", () => {
-    const validValues = [
-        "domain.com",
-        "dom.plato",
-        "a.domain.co",
-        "foo--bar.com",
-        "xn--froschgrn-x9a.com",
-        "rebecca.blackfriday"
-    ];
-    const invalidValues = [
-        null,
-        undefined,
-        "abc",
-        "256.0.0.0",
-        "_.com",
-        "*.some.com",
-        "s!ome.com",
-        "domain.com/",
-        "/more.com"
-    ];
-
-    class MyClass {
-        @IsFQDN()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isFQDN(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isFQDN(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isFqdn";
-        const message = "someProperty must be a valid domain name";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsFullWidth", () => {
-    const validValues = [
-        "ひらがな・カタカナ、.漢字",
-        "3ー0 a@com",
-        "Fカタカナ゙ᆲ",
-        "Good=Parts"
-    ];
-    const invalidValues = [
-        null,
-        undefined,
-        "abc",
-        "abc123"
-    ];
-
-    class MyClass {
-        @IsFullWidth()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isFullWidth(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isFullWidth(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isFullWidth";
-        const message = "someProperty must contain a full-width characters";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsHalfWidth", () => {
-
-    const validValues = [
-        "l-btn_02--active",
-        "abc123い",
-        "カタカナ゙ᆲ←"
-    ];
-    const invalidValues = [
-        null,
-        undefined,
-        "あいうえお",
-        "0011"
-    ];
-
-    class MyClass {
-        @IsHalfWidth()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isHalfWidth(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isHalfWidth(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isHalfWidth";
-        const message = "someProperty must contain a half-width characters";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsVariableWidth", () => {
-    const validValues = [
-        "ひらがなカタカナ漢字ABCDE",
-        "3ー0123",
-        "Fカタカナ゙ᆲ",
-        "Good=Parts"
-    ];
-    const invalidValues = [
-        null,
-        undefined,
-        "abc",
-        "abc123",
-        "!\"#$%&()<>/+=-_? ~^|.,@`{}[]",
-        "ひらがな・カタカナ、.漢字",
-        "123456",
-        "カタカナ゙ᆲ"
-    ];
-
-    class MyClass {
-        @IsVariableWidth()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isVariableWidth(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isVariableWidth(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isVariableWidth";
-        const message = "someProperty must contain a full-width and half-width characters";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsHexColor", () => {
-    const validValues = [
-        "#ff0034",
-        "#CCCCCC",
-        "fff",
-        "#f00"
-    ];
-    const invalidValues = [
-        null,
-        undefined,
-        "#ff",
-        "#xxxx",
-        "#ff12FG"
-    ];
-
-    class MyClass {
-        @IsHexColor()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        invalidValues.forEach(value => expect(isHexColor(value)).toBeFalsy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        validValues.forEach(value => expect(isHexColor(value)).toBeTruthy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isHexColor";
-        const message = "someProperty must be a hexadecimal color";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsHexadecimal", () => {
-
-    const validValues = [
-        "deadBEEF",
-        "ff0044"
-    ];
-    const invalidValues = [
-        null,
-        undefined,
-        "abcdefg",
-        "",
-        ".."
-    ];
-
-    class MyClass {
-        @IsHexadecimal()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isHexadecimal(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isHexadecimal(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isHexadecimal";
-        const message = "someProperty must be a hexadecimal number";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsMACAddress", () => {
-    const validValues = [
-        "ab:ab:ab:ab:ab:ab",
-        "FF:FF:FF:FF:FF:FF",
-        "01:02:03:04:05:ab",
-        "01:AB:03:04:05:06"
-    ];
-    const invalidValues = [
-        null,
-        undefined,
-        "abc",
-        "01:02:03:04:05",
-        "01:02:03:04::ab",
-        "1:2:3:4:5:6",
-        "AB:CD:EF:GH:01:02",
-        "A9C5 D4 9F EB D3",
-        "01-02 03:04 05 ab",
-    ];
-
-    class MyClass {
-        @IsMACAddress()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isMACAddress(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isMACAddress(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isMacAddress";
-        const message = "someProperty must be a MAC Address";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsIP", () => {
-    const validValues = [
-        "127.0.0.1",
-        "0.0.0.0",
-        "255.255.255.255",
-        "1.2.3.4",
-        "::1",
-        "2001:db8:0000:1:1:1:1:1",
-        "2001:41d0:2:a141::1",
-        "::ffff:127.0.0.1",
-        "::0000",
-        "0000::",
-        "1::",
-        "1111:1:1:1:1:1:1:1",
-        "fe80::a6db:30ff:fe98:e946",
-        "::",
-        "::ffff:127.0.0.1",
-        "0:0:0:0:0:ffff:127.0.0.1"
-    ];
-    const invalidValues = [
-        null,
-        undefined,
-        "abc",
-        "256.0.0.0",
-        "0.0.0.256",
-        "26.0.0.256",
-        "::banana",
-        "banana::",
-        "::1banana",
-        "::1::",
-        "1:",
-        ":1",
-        ":1:1:1::2",
-        "1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1",
-        "::11111",
-        "11111:1:1:1:1:1:1:1",
-        "2001:db8:0000:1:1:1:1::1",
-        "0:0:0:0:0:0:ffff:127.0.0.1",
-        "0:0:0:0:ffff:127.0.0.1"
-    ];
-
-    class MyClass {
-        @IsIP()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isIP(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isIP(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isIp";
-        const message = "someProperty must be an ip address";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsISBN version 10", () => {
-    const validValues = [
-        "3836221195", "3-8362-2119-5", "3 8362 2119 5"
-        , "1617290858", "1-61729-085-8", "1 61729 085-8"
-        , "0007269706", "0-00-726970-6", "0 00 726970 6"
-        , "3423214120", "3-423-21412-0", "3 423 21412 0"
-        , "340101319X", "3-401-01319-X", "3 401 01319 X"
-    ];
-    const invalidValues = [
-        null, undefined, "3423214121", "3-423-21412-1", "3 423 21412 1"
-        , "978-3836221191", "9783836221191"
-        , "123456789a", "foo"
-    ];
-
-    class MyClass {
-        @IsISBN(10)
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isISBN(value, "10")).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isISBN(value, "10")).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isIsbn";
-        const message = "someProperty must be an ISBN";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsISBN version 13", () => {
-    const validValues = [
-        "9783836221191", "978-3-8362-2119-1", "978 3 8362 2119 1"
-        , "9783401013190", "978-3401013190", "978 3401013190"
-        , "9784873113685", "978-4-87311-368-5", "978 4 87311 368 5"
-    ];
-    const invalidValues = [
-        null, undefined, "9783836221190", "978-3-8362-2119-0", "978 3 8362 2119 0"
-        , "3836221195", "3-8362-2119-5", "3 8362 2119 5"
-        , "01234567890ab", "foo", ""
-    ];
-
-    class MyClass {
-        @IsISBN(13)
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isISBN(value, "13")).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isISBN(value, "13")).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isIsbn";
-        const message = "someProperty must be an ISBN";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsISO8601", () => {
-    const validValues = [
-        "2009-12T12:34"
-        , "2009"
-        , "2009-05-19"
-        , "2009-05-19"
-        , "20090519"
-        , "2009123"
-        , "2009-05"
-        , "2009-123"
-        , "2009-222"
-        , "2009-001"
-        , "2009-W01-1"
-        , "2009-W51-1"
-        , "2009-W511"
-        , "2009-W33"
-        , "2009W511"
-        , "2009-05-19"
-        , "2009-05-19 00:00"
-        , "2009-05-19 14"
-        , "2009-05-19 14:31"
-        , "2009-05-19 14:39:22"
-        , "2009-05-19T14:39Z"
-        , "2009-W21-2"
-        , "2009-W21-2T01:22"
-        , "2009-139"
-        , "2009-05-19 14:39:22-06:00"
-        , "2009-05-19 14:39:22+0600"
-        , "2009-05-19 14:39:22-01"
-        , "20090621T0545Z"
-        , "2007-04-06T00:00"
-        , "2007-04-05T24:00"
-        , "2010-02-18T16:23:48.5"
-        , "2010-02-18T16:23:48,444"
-        , "2010-02-18T16:23:48,3-06:00"
-        , "2010-02-18T16:23.4"
-        , "2010-02-18T16:23,25"
-        , "2010-02-18T16:23.33+0600"
-        , "2010-02-18T16.23334444"
-        , "2010-02-18T16,2283"
-        , "2009-05-19 143922.500"
-        , "2009-05-19 1439,55"
-    ];
-    const invalidValues = [
-        null
-        , undefined
-        , "200905"
-        , "2009367"
-        , "2009-"
-        , "2007-04-05T24:50"
-        , "2009-000"
-        , "2009-M511"
-        , "2009M511"
-        , "2009-05-19T14a39r"
-        , "2009-05-19T14:3924"
-        , "2009-0519"
-        , "2009-05-1914:39"
-        , "2009-05-19 14:"
-        , "2009-05-19r14:39"
-        , "2009-05-19 14a39a22"
-        , "200912-01"
-        , "2009-05-19 14:39:22+06a00"
-        , "2009-05-19 146922.500"
-        , "2010-02-18T16.5:23.35:48"
-        , "2010-02-18T16:23.35:48"
-        , "2010-02-18T16:23.35:48.45"
-        , "2009-05-19 14.5.44"
-        , "2010-02-18T16:23.33.600"
-        , "2010-02-18T16,25:23:48,444"
-    ];
-
-    class MyClass {
-        @IsISO8601()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isISO8601(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isISO8601(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isIso8601";
-        const message = "someProperty must be a valid ISO 8601 date string";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsJSON", () => {
-    const validValues = ["{ \"key\": \"value\" }", "{}"];
-    const invalidValues = [null, undefined, "{ key: \"value\" }", "{ 'key': 'value' }", "null", "1234", "false", "\"nope\""];
-
-    class MyClass {
-        @IsJSON()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isJSON(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isJSON(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isJson";
-        const message = "someProperty must be a json string";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsJWT", () => {
-    const validValues = [
-        "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dnZWRJbkFzIjoiYWRtaW4iLCJpYXQiOjE0MjI3Nzk2Mzh9.gzSraSYS8EXBxLN_oWnFSRgCzcmJmMjLiuyu5CSpyHI",
-        "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb3JlbSI6Imlwc3VtIn0.ymiJSsMJXR6tMSr8G9usjQ15_8hKPDv_CArLhxw28MI",
-        "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkb2xvciI6InNpdCIsImFtZXQiOlsibG9yZW0iLCJpcHN1bSJdfQ.rRpe04zbWbbJjwM43VnHzAboDzszJtGrNsUxaqQ-GQ8",
-        "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqb2huIjp7ImFnZSI6MjUsImhlaWdodCI6MTg1fSwiamFrZSI6eyJhZ2UiOjMwLCJoZWlnaHQiOjI3MH19.YRLPARDmhGMC3BBk_OhtwwK21PIkVCqQe8ncIRPKo-E",
-        "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ", // No signature
-    ];
-    const invalidValues = [
-        "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9",
-        "$Zs.ewu.su84",
-        "ks64$S/9.dy$§kz.3sd73b",
-    ];
-
-    class MyClass {
-        @IsJWT()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isJWT(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isJWT(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isJwt";
-        const message = "someProperty must be a jwt string";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsObject", () => {
-    const validValues = [{"key": "value"}, {key: "value"}, {}];
-    const invalidValues: any[] = [null, undefined, "{ key: \"value\" }", "{ 'key': 'value' }", "string", 1234, false, "[]", [], [{key: "value"}]];
-
-    class MyClass {
-        @IsObject()
-        someProperty: object;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isObject(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isObject(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isObject";
-        const message = "someProperty must be an object";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsNotEmptyObject", () => {
-    const validValues = [{"key": "value"}, {key: "value"}];
-    const invalidValues = [null, undefined, "{ key: \"value\" }", "{ 'key': 'value' }", "string", 1234, false, {}, [], [{key: "value"}]];
-
-    class MyClass {
-        @IsNotEmptyObject()
-        someProperty: object;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isNotEmptyObject(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isNotEmptyObject(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isNotEmptyObject";
-        const message = "someProperty must be a non-empty object";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsLowercase", () => {
-    const validValues = [
-        "abc"
-        , "abc123"
-        , "this is lowercase."
-        , "tr竪s 端ber"
-    ];
-    const invalidValues = [
-        null
-        , undefined
-        , "fooBar"
-        , "123A"
-    ];
-
-    class MyClass {
-        @IsLowercase()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isLowercase(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isLowercase(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isLowercase";
-        const message = "someProperty must be a lowercase string";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsMongoId", () => {
-    const validValues = [
-        "507f1f77bcf86cd799439011"
-    ];
-    const invalidValues = [
-        null
-        , undefined
-        , "507f1f77bcf86cd7994390"
-        , "507f1f77bcf86cd79943901z"
-        , ""
-        , "507f1f77bcf86cd799439011 "
-    ];
-
-    class MyClass {
-        @IsMongoId()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isMongoId(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isMongoId(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isMongoId";
-        const message = "someProperty must be a mongodb id";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsMultibyte", () => {
-    const validValues = [
-        "ひらがな・カタカナ、.漢字"
-        , "あいうえお foobar"
-        , "test@example.com"
-        , "1234abcDExyz"
-        , "カタカナ"
-        , "中文"
-    ];
-    const invalidValues = [
-        null
-        , undefined
-        , "abc"
-        , "abc123"
-        , "<>@\" *."
-    ];
-
-    class MyClass {
-        @IsMultibyte()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isMultibyte(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isMultibyte(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isMultibyte";
-        const message = "someProperty must contain one or more multibyte chars";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsSurrogatePair", () => {
-    const validValues = [
-        "𠮷野𠮷"
-        , "𩸽"
-        , "ABC千𥧄1-2-3"
-    ];
-    const invalidValues = [
-        null
-        , undefined
-        , "吉野竈"
-        , "鮪"
-        , "ABC1-2-3"
-    ];
-
-    class MyClass {
-        @IsSurrogatePair()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isSurrogatePair(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isSurrogatePair(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isSurrogatePair";
-        const message = "someProperty must contain any surrogate pairs chars";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsUrl", () => {
-    const validValues = [
-        "foobar.com"
-        , "www.foobar.com"
-        , "foobar.com/"
-        , "valid.au"
-        , "http://www.foobar.com/"
-        , "http://www.foobar.com:23/"
-        , "http://www.foobar.com:65535/"
-        , "http://www.foobar.com:5/"
-        , "https://www.foobar.com/"
-        , "ftp://www.foobar.com/"
-        , "http://www.foobar.com/~foobar"
-        , "http://user:pass@www.foobar.com/"
-        , "http://user:@www.foobar.com/"
-        , "http://127.0.0.1/"
-        , "http://10.0.0.0/"
-        , "http://189.123.14.13/"
-        , "http://duckduckgo.com/?q=%2F"
-        , "http://foobar.com/t$-_.+!*\"(),"
-        , "http://foobar.com/?foo=bar#baz=qux"
-        , "http://foobar.com?foo=bar"
-        , "http://foobar.com#baz=qux"
-        , "http://www.xn--froschgrn-x9a.net/"
-        , "http://xn--froschgrn-x9a.com/"
-        , "http://foo--bar.com"
-        , "http://høyfjellet.no"
-        , "http://xn--j1aac5a4g.xn--j1amh"
-    ];
-    const invalidValues = [
-        null
-        , undefined
-        , "xyz://foobar.com"
-        , "invalid/"
-        , "invalid.x"
-        , "invalid."
-        , ".com"
-        , "http://com/"
-        , "http://300.0.0.1/"
-        , "mailto:foo@bar.com"
-        , "rtmp://foobar.com"
-        , "http://www.xn--.com/"
-        , "http://xn--.com/"
-        , "http://www.foobar.com:0/"
-        , "http://www.foobar.com:70000/"
-        , "http://www.foobar.com:99999/"
-        , "http://www.-foobar.com/"
-        , "http://www.foobar-.com/"
-        , "http://foobar/# lol"
-        , "http://foobar/? lol"
-        , "http://foobar/ lol/"
-        , "http://lol @foobar.com/"
-        , "http://lol:lol @foobar.com/"
-        , "http://lol:lol:lol@foobar.com/"
-        , "http://lol: @foobar.com/"
-        , "http://www.foo_bar.com/"
-        , "http://www.foobar.com/\t"
-        , "http://\n@www.foobar.com/"
-        , ""
-        , "http://localhost:61500this is an invalid url!!!!"
-        , "http://foobar.com/" + new Array(2083).join("f")
-        , "http://*.foo.com"
-        , "*.foo.com"
-        , "!.foo.com"
-        , "http://example.com."
-        , "////foobar.com"
-        , "http:////foobar.com"
-    ];
-
-    class MyClass {
-        @IsUrl()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isURL(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isURL(value)).toBeFalsy());
-    });
-
-    it("should fail on localhost without require_tld option", () => {
-        expect(isURL("http://localhost:3000/")).toBeFalsy();
-    });
-
-    it("should pass on localhost with require_tld option", () => {
-        // eslint-disable-next-line @typescript-eslint/camelcase
-        expect(isURL("http://localhost:3000/", {require_tld: false})).toBeTruthy();
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isUrl";
-        const message = "someProperty must be an URL address";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsUUID", () => {
-    const validValues = [
-        "A987FBC9-4BED-3078-CF07-9141BA07C9F3"
-        , "A987FBC9-4BED-4078-8F07-9141BA07C9F3"
-        , "A987FBC9-4BED-5078-AF07-9141BA07C9F3"
-    ];
-    const invalidValues = [
-        null
-        , undefined
-        , ""
-        , "xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3"
-        , "A987FBC9-4BED-3078-CF07-9141BA07C9F3xxx"
-        , "A987FBC94BED3078CF079141BA07C9F3"
-        , "934859"
-        , "987FBC9-4BED-3078-CF07A-9141BA07C9F3"
-        , "AAAAAAAA-1111-1111-AAAG-111111111111"
-    ];
-
-    class MyClass {
-        @IsUUID()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isUUID(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isUUID(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isUuid";
-        const message = "someProperty must be an UUID";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsUUID v3", () => {
-    const validValues = [
-        "A987FBC9-4BED-3078-CF07-9141BA07C9F3"
-    ];
-    const invalidValues = [
-        null
-        , undefined
-        , ""
-        , "xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3"
-        , "934859"
-        , "AAAAAAAA-1111-1111-AAAG-111111111111"
-        , "A987FBC9-4BED-4078-8F07-9141BA07C9F3"
-        , "A987FBC9-4BED-5078-AF07-9141BA07C9F3"
-    ];
-
-    class MyClass {
-        @IsUUID("3")
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isUUID(value, "3")).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isUUID(value, "3")).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isUuid";
-        const message = "someProperty must be an UUID";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsUUID v4", () => {
-    const validValues = [
-        "713ae7e3-cb32-45f9-adcb-7c4fa86b90c1"
-        , "625e63f3-58f5-40b7-83a1-a72ad31acffb"
-        , "57b73598-8764-4ad0-a76a-679bb6640eb1"
-        , "9c858901-8a57-4791-81fe-4c455b099bc9"
-    ];
-    const invalidValues = [
-        null
-        , undefined
-        , ""
-        , "xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3"
-        , "934859"
-        , "AAAAAAAA-1111-1111-AAAG-111111111111"
-        , "A987FBC9-4BED-5078-AF07-9141BA07C9F3"
-        , "A987FBC9-4BED-3078-CF07-9141BA07C9F3"
-    ];
-
-    class MyClass {
-        @IsUUID("4")
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isUUID(value, "4")).toBeTruthy());
-    });
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isJSON(value)).toBeTruthy());
+  });
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isUUID(value, "4")).toBeFalsy());
-    });
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isJSON(value)).toBeFalsy());
+  });
 
-    it("should return error object with proper data", () => {
-        const validationType = "isUuid";
-        const message = "someProperty must be an UUID";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+  it('should return error object with proper data', () => {
+    const validationType = 'isJson';
+    const message = 'someProperty must be a json string';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("IsUUID v5", () => {
-    const validValues = [
-        "987FBC97-4BED-5078-AF07-9141BA07C9F3"
-        , "987FBC97-4BED-5078-BF07-9141BA07C9F3"
-        , "987FBC97-4BED-5078-8F07-9141BA07C9F3"
-        , "987FBC97-4BED-5078-9F07-9141BA07C9F3"
-    ];
-    const invalidValues = [
-        null
-        , undefined
-        , ""
-        , "xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3"
-        , "934859"
-        , "AAAAAAAA-1111-1111-AAAG-111111111111"
-        , "9c858901-8a57-4791-81fe-4c455b099bc9"
-        , "A987FBC9-4BED-3078-CF07-9141BA07C9F3",
-    ];
-
-    class MyClass {
-        @IsUUID("5")
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isUUID(value, "5")).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isUUID(value, "5")).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isUuid";
-        const message = "someProperty must be an UUID";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+describe('IsJWT', () => {
+  const validValues = [
+    'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dnZWRJbkFzIjoiYWRtaW4iLCJpYXQiOjE0MjI3Nzk2Mzh9.gzSraSYS8EXBxLN_oWnFSRgCzcmJmMjLiuyu5CSpyHI',
+    'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb3JlbSI6Imlwc3VtIn0.ymiJSsMJXR6tMSr8G9usjQ15_8hKPDv_CArLhxw28MI',
+    'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkb2xvciI6InNpdCIsImFtZXQiOlsibG9yZW0iLCJpcHN1bSJdfQ.rRpe04zbWbbJjwM43VnHzAboDzszJtGrNsUxaqQ-GQ8',
+    'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqb2huIjp7ImFnZSI6MjUsImhlaWdodCI6MTg1fSwiamFrZSI6eyJhZ2UiOjMwLCJoZWlnaHQiOjI3MH19.YRLPARDmhGMC3BBk_OhtwwK21PIkVCqQe8ncIRPKo-E',
+    'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ', // No signature
+  ];
+  const invalidValues = ['eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9', '$Zs.ewu.su84', 'ks64$S/9.dy$§kz.3sd73b'];
+
+  class MyClass {
+    @IsJWT()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isJWT(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isJWT(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isJwt';
+    const message = 'someProperty must be a jwt string';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("IsFirebasePushId", () => {
-    const validValues = [
-        "-M-Jh_1KAH5rYJF_7-kY"
-        , "-M1yvu7FKe87rR_62NH7"
-        , "-M1jVySxQQPktYyXA2qE"
-        , "-JhLeOlGIEjaIOFHR0xd"
-        , "-JhQ76OEK_848CkIFhAq"
-        , "-JhQ7APk0UtyRTFO9-TS"
-
-    ];
-    const invalidValues = [
-        null
-        , undefined
-        , true
-        , false
-        , ""
-        , "5584fa9e-6146-497a-85c9-dbb459ef7b74"
-        , "Steve"
-        , "dbfa63ea-2c1f-4cf8-b6b9-192b070b558c"
-    ];
-
-    class MyClass {
-        @IsFirebasePushId()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isFirebasePushId(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isFirebasePushId(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "IsFirebasePushId";
-        const message = "someProperty must be a Firebase Push Id";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+describe('IsObject', () => {
+  const validValues = [{ key: 'value' }, { key: 'value' }, {}];
+  const invalidValues: any[] = [
+    null,
+    undefined,
+    '{ key: "value" }',
+    "{ 'key': 'value' }",
+    'string',
+    1234,
+    false,
+    '[]',
+    [],
+    [{ key: 'value' }],
+  ];
+
+  class MyClass {
+    @IsObject()
+    someProperty: object;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isObject(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isObject(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isObject';
+    const message = 'someProperty must be an object';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("IsUppercase", () => {
-    const validValues = [
-        "ABC"
-        , "ABC123"
-        , "ALL CAPS IS FUN."
-        , "   ."
-    ];
-    const invalidValues = [
-        null,
-        undefined,
-        "fooBar",
-        "123abc"
-    ];
-
-    class MyClass {
-        @IsUppercase()
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isUppercase(value)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isUppercase(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isUppercase";
-        const message = "someProperty must be uppercase";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+describe('IsNotEmptyObject', () => {
+  const validValues = [{ key: 'value' }, { key: 'value' }, { key: undefined }, { key: null }];
+  const invalidValues = [
+    null,
+    undefined,
+    '{ key: "value" }',
+    "{ 'key': 'value' }",
+    'string',
+    1234,
+    false,
+    {},
+    [],
+    [{ key: 'value' }],
+  ];
+  const nullableValidValues = [{ key: 'value' }, { key: 'value' }];
+  const nullableInvalidValues = [
+    null,
+    undefined,
+    '{ key: "value" }',
+    "{ 'key': 'value' }",
+    'string',
+    1234,
+    false,
+    {},
+    { key: undefined },
+    { key: null },
+    [],
+    [{ key: 'value' }],
+  ];
+
+  class MyClass {
+    @IsNotEmptyObject()
+    someProperty: object;
+  }
+
+  class NullableMyClass {
+    @IsNotEmptyObject({ nullable: true })
+    someProperty: object;
+  }
+
+  it.each([
+    [new MyClass(), validValues],
+    [new NullableMyClass(), nullableValidValues],
+  ])('should not fail if validator.validate said that its valid', (validationObject, values) => {
+    return checkValidValues(validationObject, values);
+  });
+
+  it.each([
+    [new MyClass(), invalidValues],
+    [new NullableMyClass(), nullableInvalidValues],
+  ])('should fail if validator.validate said that its invalid', (validationObject, values) => {
+    return checkInvalidValues(validationObject, values);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isNotEmptyObject(value)).toBeTruthy());
+    nullableValidValues.forEach(value => expect(isNotEmptyObject(value, { nullable: true })).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isNotEmptyObject(value)).toBeFalsy());
+    nullableInvalidValues.forEach(value => expect(isNotEmptyObject(value, { nullable: true })).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isNotEmptyObject';
+    const message = 'someProperty must be a non-empty object';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("Length", () => {
-    const constraint1 = 2;
-    const constraint2 = 3;
-    const validValues = ["abc", "de"];
-    const invalidValues = [null, undefined, "", "a", "abcd"];
-
-    class MyClass {
-        @Length(constraint1, constraint2)
-        someProperty: string;
-    }
+describe('IsLowercase', () => {
+  const validValues = ['abc', 'abc123', 'this is lowercase.', 'tr竪s 端ber'];
+  const invalidValues = [null, undefined, 'fooBar', '123A'];
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  class MyClass {
+    @IsLowercase()
+    someProperty: string;
+  }
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(length(value, constraint1, constraint2)).toBeTruthy());
-    });
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(length(value, constraint1, constraint2)).toBeFalsy());
-    });
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isLowercase(value)).toBeTruthy());
+  });
 
-    it("should return error object with proper data", () => {
-        const validationType = "length";
-        const message = "someProperty must be longer than or equal to " + constraint1 + " characters";
-        checkReturnedError(new MyClass(), ["", "a"], validationType, message);
-    });
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isLowercase(value)).toBeFalsy());
+  });
 
-    it("should return error object with proper data", () => {
-        const validationType = "length";
-        const message = "someProperty must be shorter than or equal to " + constraint2 + " characters";
-        checkReturnedError(new MyClass(), ["aaaa", "azzazza"], validationType, message);
-    });
+  it('should return error object with proper data', () => {
+    const validationType = 'isLowercase';
+    const message = 'someProperty must be a lowercase string';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("MinLength", () => {
-    const constraint1 = 10;
-    const validValues = ["helloworld", "hello how are you"];
-    const invalidValues = [null, undefined, "hellowar", "howareyou"];
-
-    class MyClass {
-        @MinLength(constraint1)
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(minLength(value, constraint1)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(minLength(value, constraint1)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "minLength";
-        const message = "someProperty must be longer than or equal to " + constraint1 + " characters";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+describe('IsMongoId', () => {
+  const validValues = ['507f1f77bcf86cd799439011'];
+  const invalidValues = [
+    null,
+    undefined,
+    '507f1f77bcf86cd7994390',
+    '507f1f77bcf86cd79943901z',
+    '',
+    '507f1f77bcf86cd799439011 ',
+  ];
+
+  class MyClass {
+    @IsMongoId()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isMongoId(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isMongoId(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isMongoId';
+    const message = 'someProperty must be a mongodb id';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("MaxLength", () => {
-    const constraint1 = 10;
-    const validValues = ["hellowar", "howareyou", "helloworld"];
-    const invalidValues = [null, undefined, "helloworld!", "hello how are you"];
-
-    class MyClass {
-        @MaxLength(constraint1)
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(maxLength(value, constraint1)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(maxLength(value, constraint1)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "maxLength";
-        const message = "someProperty must be shorter than or equal to " + constraint1 + " characters";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+describe('IsMultibyte', () => {
+  const validValues = [
+    'ひらがな・カタカナ、.漢字',
+    'あいうえお foobar',
+    'test@example.com',
+    '1234abcDExyz',
+    'カタカナ',
+    '中文',
+  ];
+  const invalidValues = [null, undefined, 'abc', 'abc123', '<>@" *.'];
+
+  class MyClass {
+    @IsMultibyte()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isMultibyte(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isMultibyte(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isMultibyte';
+    const message = 'someProperty must contain one or more multibyte chars';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("Matches", () => {
-    const constraint = /abc/;
-    const validValues = ["abc", "abcdef", "123abc"];
-    const invalidValues = [null, undefined, "acb", "Abc"];
+describe('IsSurrogatePair', () => {
+  const validValues = ['𠮷野𠮷', '𩸽', 'ABC千𥧄1-2-3'];
+  const invalidValues = [null, undefined, '吉野竈', '鮪', 'ABC1-2-3'];
 
-    class MyClass {
-        @Matches(constraint)
-        someProperty: string;
-    }
+  class MyClass {
+    @IsSurrogatePair()
+    someProperty: string;
+  }
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(matches(value, constraint)).toBeTruthy());
-    });
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isSurrogatePair(value)).toBeTruthy());
+  });
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(matches(value, constraint)).toBeFalsy());
-    });
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isSurrogatePair(value)).toBeFalsy());
+  });
 
-    it("should return error object with proper data", () => {
-        const validationType = "matches";
-        const message = "someProperty must match " + constraint + " regular expression";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+  it('should return error object with proper data', () => {
+    const validationType = 'isSurrogatePair';
+    const message = 'someProperty must contain any surrogate pairs chars';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("IsMilitaryTime", () => {
-    class MyClass {
-        @IsMilitaryTime()
-        someProperty: string;
-    }
-
-    it("should not fail for a valid time in the format HH:MM", () => {
-        const validValues = ["10:22", "12:03", "16:32", "23:59", "00:00"];
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail for invalid time format", () => {
-        const invalidValues = ["23:61", "25:00", "08:08 pm", "04:00am"];
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should fail for invalid values", () => {
-        const invalidValues = [undefined, null, "23:00 and invalid counterpart"];
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+describe('IsUrl', () => {
+  const validValues = [
+    'foobar.com',
+    'www.foobar.com',
+    'foobar.com/',
+    'valid.au',
+    'http://www.foobar.com/',
+    'http://www.foobar.com:23/',
+    'http://www.foobar.com:65535/',
+    'http://www.foobar.com:5/',
+    'https://www.foobar.com/',
+    'ftp://www.foobar.com/',
+    'http://www.foobar.com/~foobar',
+    'http://user:pass@www.foobar.com/',
+    'http://user:@www.foobar.com/',
+    'http://127.0.0.1/',
+    'http://10.0.0.0/',
+    'http://189.123.14.13/',
+    'http://duckduckgo.com/?q=%2F',
+    'http://foobar.com/t$-_.+!*"(),',
+    'http://foobar.com/?foo=bar#baz=qux',
+    'http://foobar.com?foo=bar',
+    'http://foobar.com#baz=qux',
+    'http://www.xn--froschgrn-x9a.net/',
+    'http://xn--froschgrn-x9a.com/',
+    'http://foo--bar.com',
+    'http://høyfjellet.no',
+    'http://xn--j1aac5a4g.xn--j1amh',
+  ];
+  const invalidValues = [
+    null,
+    undefined,
+    'xyz://foobar.com',
+    'invalid/',
+    'invalid.x',
+    'invalid.',
+    '.com',
+    'http://com/',
+    'http://300.0.0.1/',
+    'mailto:foo@bar.com',
+    'rtmp://foobar.com',
+    'http://www.xn--.com/',
+    'http://xn--.com/',
+    'http://www.foobar.com:0/',
+    'http://www.foobar.com:70000/',
+    'http://www.foobar.com:99999/',
+    'http://www.-foobar.com/',
+    'http://www.foobar-.com/',
+    'http://foobar/# lol',
+    'http://foobar/? lol',
+    'http://foobar/ lol/',
+    'http://lol @foobar.com/',
+    'http://lol:lol @foobar.com/',
+    'http://lol:lol:lol@foobar.com/',
+    'http://lol: @foobar.com/',
+    'http://www.foo_bar.com/',
+    'http://www.foobar.com/\t',
+    'http://\n@www.foobar.com/',
+    '',
+    'http://localhost:61500this is an invalid url!!!!',
+    'http://foobar.com/' + new Array(2083).join('f'),
+    'http://*.foo.com',
+    '*.foo.com',
+    '!.foo.com',
+    'http://example.com.',
+    '////foobar.com',
+    'http:////foobar.com',
+  ];
+
+  class MyClass {
+    @IsUrl()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isURL(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isURL(value)).toBeFalsy());
+  });
+
+  it('should fail on localhost without require_tld option', () => {
+    expect(isURL('http://localhost:3000/')).toBeFalsy();
+  });
+
+  it('should pass on localhost with require_tld option', () => {
+    // eslint-disable-next-line @typescript-eslint/camelcase
+    expect(isURL('http://localhost:3000/', { require_tld: false })).toBeTruthy();
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isUrl';
+    const message = 'someProperty must be an URL address';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("isPhoneNumber", () => {
-    describe("with region", () => {
-        const validValues = [
-            "0311111111", "031 633 60 01", "079 4 666 666", "075 416 20 30",
-            "+41 311111111", "+41 31 633 60 01", "+41 79 4 666 666", "+41 75 416 20 30",
-            "+41 (0)311111111", "+41 (0)31 633 60 01", "+41 (0)79 4 666 666", "+41 (0)75 416 20 30",
-            "+49 9072 1111"
-        ];
-        const invalidValues = [undefined, null, "asdf", "1"];
-
-        class MyClass {
-            @IsPhoneNumber("CH")
-            someProperty: string;
-        }
-
-        it("should not fail if validator.validate said that its valid", () => {
-            return checkValidValues(new MyClass(), validValues);
-        });
-
-        it("should fail if validator.validate said that its invalid", () => {
-            return checkInvalidValues(new MyClass(), invalidValues);
-        });
-    });
-
-    describe("no region", () => {
-        const validValues = [
-            "+41 311111111", "+41 31 633 60 01", "+41 79 4 666 666", "+41 75 416 20 30",
-            "+41 (0)311111111", "+41 (0)31 633 60 01", "+41 (0)79 4 666 666", "+41 (0)75 416 20 30",
-            "+49 9072 1111"
-        ];
-        const invalidValues = [
-            "0311111111", "031 633 60 01", "079 4 666 666", "075 416 20 30",
-            undefined, null, "asdf", "1"
-        ];
-
-        class MyClass {
-            @IsPhoneNumber(null)
-            someProperty: string;
-        }
-
-        it("should not fail if validator.validate said that its valid", () => {
-            return checkValidValues(new MyClass(), validValues);
-        });
-
-        it("should fail if validator.validate said that its invalid", () => {
-            return checkInvalidValues(new MyClass(), invalidValues);
-        });
-    });
+describe('IsUUID', () => {
+  const validValues = [
+    'A987FBC9-4BED-3078-CF07-9141BA07C9F3',
+    'A987FBC9-4BED-4078-8F07-9141BA07C9F3',
+    'A987FBC9-4BED-5078-AF07-9141BA07C9F3',
+  ];
+  const invalidValues = [
+    null,
+    undefined,
+    '',
+    'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3',
+    'A987FBC9-4BED-3078-CF07-9141BA07C9F3xxx',
+    'A987FBC94BED3078CF079141BA07C9F3',
+    '934859',
+    '987FBC9-4BED-3078-CF07A-9141BA07C9F3',
+    'AAAAAAAA-1111-1111-AAAG-111111111111',
+  ];
+
+  class MyClass {
+    @IsUUID()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isUUID(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isUUID(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isUuid';
+    const message = 'someProperty must be an UUID';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("IsISO31661Alpha2", () => {
-    class MyClass {
-        @IsISO31661Alpha2()
-        someProperty: string;
-    }
-
-    it("should not fail for a valid ISO31661 Alpha2 code", () => {
-        const validValues = ["AD", "AE", "AF", "AG"];
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail for invalid values", () => {
-        const invalidValues = [undefined, null, "", "AFR"];
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+describe('IsUUID v3', () => {
+  const validValues = ['A987FBC9-4BED-3078-CF07-9141BA07C9F3'];
+  const invalidValues = [
+    null,
+    undefined,
+    '',
+    'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3',
+    '934859',
+    'AAAAAAAA-1111-1111-AAAG-111111111111',
+    'A987FBC9-4BED-4078-8F07-9141BA07C9F3',
+    'A987FBC9-4BED-5078-AF07-9141BA07C9F3',
+  ];
+
+  class MyClass {
+    @IsUUID('3')
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isUUID(value, '3')).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isUUID(value, '3')).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isUuid';
+    const message = 'someProperty must be an UUID';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("IsISO31661Alpha3", () => {
-    class MyClass {
-        @IsISO31661Alpha3()
-        someProperty: string;
-    }
+describe('IsUUID v4', () => {
+  const validValues = [
+    '713ae7e3-cb32-45f9-adcb-7c4fa86b90c1',
+    '625e63f3-58f5-40b7-83a1-a72ad31acffb',
+    '57b73598-8764-4ad0-a76a-679bb6640eb1',
+    '9c858901-8a57-4791-81fe-4c455b099bc9',
+  ];
+  const invalidValues = [
+    null,
+    undefined,
+    '',
+    'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3',
+    '934859',
+    'AAAAAAAA-1111-1111-AAAG-111111111111',
+    'A987FBC9-4BED-5078-AF07-9141BA07C9F3',
+    'A987FBC9-4BED-3078-CF07-9141BA07C9F3',
+  ];
+
+  class MyClass {
+    @IsUUID('4')
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isUUID(value, '4')).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isUUID(value, '4')).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isUuid';
+    const message = 'someProperty must be an UUID';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should not fail for a valid ISO31661 Alpha3 code", () => {
-        const validValues = ["ABW", "HND", "KHM", "RWA"];
-        return checkValidValues(new MyClass(), validValues);
-    });
+describe('IsUUID v5', () => {
+  const validValues = [
+    '987FBC97-4BED-5078-AF07-9141BA07C9F3',
+    '987FBC97-4BED-5078-BF07-9141BA07C9F3',
+    '987FBC97-4BED-5078-8F07-9141BA07C9F3',
+    '987FBC97-4BED-5078-9F07-9141BA07C9F3',
+  ];
+  const invalidValues = [
+    null,
+    undefined,
+    '',
+    'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3',
+    '934859',
+    'AAAAAAAA-1111-1111-AAAG-111111111111',
+    '9c858901-8a57-4791-81fe-4c455b099bc9',
+    'A987FBC9-4BED-3078-CF07-9141BA07C9F3',
+  ];
+
+  class MyClass {
+    @IsUUID('5')
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isUUID(value, '5')).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isUUID(value, '5')).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isUuid';
+    const message = 'someProperty must be an UUID';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail for invalid values", () => {
-        const invalidValues = [undefined, null, "", "FR", "fR", "GB", "PT", "CM", "JP", "PM", "ZW"];
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+describe('IsFirebasePushId', () => {
+  const validValues = [
+    '-M-Jh_1KAH5rYJF_7-kY',
+    '-M1yvu7FKe87rR_62NH7',
+    '-M1jVySxQQPktYyXA2qE',
+    '-JhLeOlGIEjaIOFHR0xd',
+    '-JhQ76OEK_848CkIFhAq',
+    '-JhQ7APk0UtyRTFO9-TS',
+  ];
+  const invalidValues = [
+    null,
+    undefined,
+    true,
+    false,
+    '',
+    '5584fa9e-6146-497a-85c9-dbb459ef7b74',
+    'Steve',
+    'dbfa63ea-2c1f-4cf8-b6b9-192b070b558c',
+  ];
+
+  class MyClass {
+    @IsFirebasePushId()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isFirebasePushId(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isFirebasePushId(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'IsFirebasePushId';
+    const message = 'someProperty must be a Firebase Push Id';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("isHash", () => {
-    function testHash(algorithm: ValidatorJS.HashAlgorithm, validValues: any[], invalidValues: any[]): void {
-        class MyClass {
-            @IsHash(algorithm)
-            someProperty: string;
-        }
+describe('IsUppercase', () => {
+  const validValues = ['ABC', 'ABC123', 'ALL CAPS IS FUN.', '   .'];
+  const invalidValues = [null, undefined, 'fooBar', '123abc'];
 
-        it("should not fail if validator.validate said that its valid", () => {
-            return checkValidValues(new MyClass(), validValues);
-        });
+  class MyClass {
+    @IsUppercase()
+    someProperty: string;
+  }
 
-        it("should fail if validator.validate said that its invalid", () => {
-            return checkInvalidValues(new MyClass(), invalidValues);
-        });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-        it("should not fail if method in validator said that its valid", () => {
-            validValues.forEach(value => expect(isHash(value, algorithm)).toBeTruthy());
-        });
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-        it("should fail if method in validator said that its invalid", () => {
-            invalidValues.forEach(value => expect(isHash(value, algorithm)).toBeFalsy());
-        });
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isUppercase(value)).toBeTruthy());
+  });
 
-        it("should return error object with proper data", () => {
-            const validationType = "isHash";
-            const message = `someProperty must be a hash of type ${algorithm}`;
-            return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-        });
-    }
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isUppercase(value)).toBeFalsy());
+  });
 
-    for (const algorithm of ["md5", "md4", "ripemd128", "tiger128"]) {
-        const validValues = [
-            "d94f3f016ae679c3008de268209132f2",
-            "751adbc511ccbe8edf23d486fa4581cd",
-            "88dae00e614d8f24cfd5a8b3f8002e93",
-            "0bf1c35032a71a14c2f719e5a14c1e96"
-        ];
-        const invalidValues = [
-            undefined, null,
-            "q94375dj93458w34",
-            "39485729348",
-            "%&FHKJFvk",
-            "KYT0bf1c35032a71a14c2f719e5a1"
-        ];
-
-        testHash(algorithm as ValidatorJS.HashAlgorithm, validValues, invalidValues);
-    }
+  it('should return error object with proper data', () => {
+    const validationType = 'isUppercase';
+    const message = 'someProperty must be uppercase';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    for (const algorithm of ["crc32", "crc32b"]) {
-        const validValues = [
-            "d94f3f01",
-            "751adbc5",
-            "88dae00e",
-            "0bf1c350",
-        ];
-        const invalidValues = [
-            undefined, null,
-            "KYT0bf1c35032a71a14c2f719e5a14c1",
-            "q94375dj93458w34",
-            "q943",
-            "39485729348",
-            "%&FHKJFvk",
-        ];
-
-        testHash(algorithm as ValidatorJS.HashAlgorithm, validValues, invalidValues);
-    }
+describe('Length', () => {
+  const constraint1 = 2;
+  const constraint2 = 3;
+  const validValues = ['abc', 'de'];
+  const invalidValues = [null, undefined, '', 'a', 'abcd'];
+
+  class MyClass {
+    @Length(constraint1, constraint2)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(length(value, constraint1, constraint2)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(length(value, constraint1, constraint2)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'length';
+    const message = 'someProperty must be longer than or equal to ' + constraint1 + ' characters';
+    checkReturnedError(new MyClass(), ['', 'a'], validationType, message);
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'length';
+    const message = 'someProperty must be shorter than or equal to ' + constraint2 + ' characters';
+    checkReturnedError(new MyClass(), ['aaaa', 'azzazza'], validationType, message);
+  });
+});
 
-    for (const algorithm of ["sha1", "tiger160", "ripemd160"]) {
-        const validValues = [
-            "3ca25ae354e192b26879f651a51d92aa8a34d8d3",
-            "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d",
-            "beb8c3f30da46be179b8df5f5ecb5e4b10508230",
-            "efd5d3b190e893ed317f38da2420d63b7ae0d5ed",
-        ];
-        const invalidValues = [
-            undefined, null,
-            "KYT0bf1c35032a71a14c2f719e5a14c1",
-            "KYT0bf1c35032a71a14c2f719e5a14c1dsjkjkjkjkkjk",
-            "q94375dj93458w34",
-            "39485729348",
-            "%&FHKJFvk",
-        ];
-
-        testHash(algorithm as ValidatorJS.HashAlgorithm, validValues, invalidValues);
-    }
+describe('MinLength', () => {
+  const constraint1 = 10;
+  const validValues = ['helloworld', 'hello how are you'];
+  const invalidValues = [null, undefined, 'hellowar', 'howareyou'];
+
+  class MyClass {
+    @MinLength(constraint1)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(minLength(value, constraint1)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(minLength(value, constraint1)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'minLength';
+    const message = 'someProperty must be longer than or equal to ' + constraint1 + ' characters';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    for (const algorithm of ["sha256"]) {
-        const validValues = [
-            "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824",
-            "1d996e033d612d9af2b44b70061ee0e868bfd14c2dd90b129e1edeb7953e7985",
-            "80f70bfeaed5886e33536bcfa8c05c60afef5a0e48f699a7912d5e399cdcc441",
-            "579282cfb65ca1f109b78536effaf621b853c9f7079664a3fbe2b519f435898c",
-        ];
-        const invalidValues = [
-            undefined, null,
-            "KYT0bf1c35032a71a14c2f719e5a14c1",
-            "KYT0bf1c35032a71a14c2f719e5a14c1dsjkjkjkjkkjk",
-            "q94375dj93458w34",
-            "39485729348",
-            "%&FHKJFvk",
-        ];
-
-        testHash(algorithm as ValidatorJS.HashAlgorithm, validValues, invalidValues);
-    }
+describe('MaxLength', () => {
+  const constraint1 = 10;
+  const validValues = ['hellowar', 'howareyou', 'helloworld'];
+  const invalidValues = [null, undefined, 'helloworld!', 'hello how are you'];
+
+  class MyClass {
+    @MaxLength(constraint1)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(maxLength(value, constraint1)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(maxLength(value, constraint1)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'maxLength';
+    const message = 'someProperty must be shorter than or equal to ' + constraint1 + ' characters';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    for (const algorithm of ["sha384"]) {
-        const validValues = [
-            "3fed1f814d28dc5d63e313f8a601ecc4836d1662a19365cbdcf6870f6b56388850b58043f7ebf2418abb8f39c3a42e31",
-            "b330f4e575db6e73500bd3b805db1a84b5a034e5d21f0041d91eec85af1dfcb13e40bb1c4d36a72487e048ac6af74b58",
-            "bf547c3fc5841a377eb1519c2890344dbab15c40ae4150b4b34443d2212e5b04aa9d58865bf03d8ae27840fef430b891",
-            "fc09a3d11368386530f985dacddd026ae1e44e0e297c805c3429d50744e6237eb4417c20ffca8807b071823af13a3f65",
-        ];
-        const invalidValues = [
-            undefined, null,
-            "KYT0bf1c35032a71a14c2f719e5a14c1",
-            "KYT0bf1c35032a71a14c2f719e5a14c1dsjkjkjkjkkjk",
-            "q94375dj93458w34",
-            "39485729348",
-            "%&FHKJFvk",
-        ];
-
-        testHash(algorithm as ValidatorJS.HashAlgorithm, validValues, invalidValues);
-    }
+describe('Matches pattern RegExp', () => {
+  const constraint = /abc/;
+  const validValues = ['abc', 'abcdef', '123abc'];
+  const invalidValues = [null, undefined, 'acb', 'Abc'];
+
+  class MyClass {
+    @Matches(constraint)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(matches(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(matches(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'matches';
+    const message = 'someProperty must match ' + constraint + ' regular expression';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    for (const algorithm of ["sha512"]) {
-        const validValues = [
-            "9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043",
-            "83c586381bf5ba94c8d9ba8b6b92beb0997d76c257708742a6c26d1b7cbb9269af92d527419d5b8475f2bb6686d2f92a6649b7f174c1d8306eb335e585ab5049",
-            "45bc5fa8cb45ee408c04b6269e9f1e1c17090c5ce26ffeeda2af097735b29953ce547e40ff3ad0d120e5361cc5f9cee35ea91ecd4077f3f589b4d439168f91b9",
-            "432ac3d29e4f18c7f604f7c3c96369a6c5c61fc09bf77880548239baffd61636d42ed374f41c261e424d20d98e320e812a6d52865be059745fdb2cb20acff0ab",
-        ];
-        const invalidValues = [
-            undefined, null,
-            "KYT0bf1c35032a71a14c2f719e5a14c1",
-            "KYT0bf1c35032a71a14c2f719e5a14c1dsjkjkjkjkkjk",
-            "q94375dj93458w34",
-            "39485729348",
-            "%&FHKJFvk",
-        ];
-
-        testHash(algorithm as ValidatorJS.HashAlgorithm, validValues, invalidValues);
-    }
+describe('Matches pattern string with modifier', () => {
+  const constraint = 'abc';
+  const modifier = 'i';
+  const validValues = ['abc', 'abcdef', '123abc', 'AbC'];
+  const invalidValues = [null, undefined, 'acb'];
+
+  class MyClass {
+    @Matches(constraint, modifier)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(matches(value, constraint, modifier)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(matches(value, constraint, modifier)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'matches';
+    const message = 'someProperty must match ' + constraint + ' regular expression';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    for (const algorithm of ["tiger192"]) {
-        const validValues = [
-            "6281a1f098c5e7290927ed09150d43ff3990a0fe1a48267c",
-            "56268f7bc269cf1bc83d3ce42e07a85632394737918f4760",
-            "46fc0125a148788a3ac1d649566fc04eb84a746f1a6e4fa7",
-            "7731ea1621ae99ea3197b94583d034fdbaa4dce31a67404a",
-        ];
-        const invalidValues = [
-            undefined, null,
-            "KYT0bf1c35032a71a14c2f719e5a14c1",
-            "KYT0bf1c35032a71a14c2f719e5a14c1dsjkjkjkjkkjk",
-            "q94375dj93458w34",
-            "39485729348",
-            "%&FHKJFvk",
-        ];
-
-        testHash(algorithm as ValidatorJS.HashAlgorithm, validValues, invalidValues);
-    }
+describe('IsMilitaryTime', () => {
+  class MyClass {
+    @IsMilitaryTime()
+    someProperty: string;
+  }
+
+  it('should not fail for a valid time in the format HH:MM', () => {
+    const validValues = ['10:22', '12:03', '16:32', '23:59', '00:00'];
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail for invalid time format', () => {
+    const invalidValues = ['23:61', '25:00', '08:08 pm', '04:00am'];
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should fail for invalid values', () => {
+    const invalidValues = [undefined, null, '23:00 and invalid counterpart'];
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 });
 
-describe("IsISSN", () => {
+describe('isPhoneNumber', () => {
+  describe('with region', () => {
     const validValues = [
-        "0378-5955",
-        "0000-0000",
-        "2434-561X",
-        "2434-561x",
-        "01896016",
-        "20905076",
-    ];
-    const invalidValues = [
-        null,
-        undefined,
-        "0378-5954",
-        "0000-0001",
-        "0378-123",
-        "037-1234",
-        "0",
-        "2434-561c",
-        "1684-5370",
-        "19960791",
-        "",
+      '0311111111',
+      '031 633 60 01',
+      '079 4 666 666',
+      '075 416 20 30',
+      '+41 311111111',
+      '+41 31 633 60 01',
+      '+41 79 4 666 666',
+      '+41 75 416 20 30',
+      '+41 (0)311111111',
+      '+41 (0)31 633 60 01',
+      '+41 (0)79 4 666 666',
+      '+41 (0)75 416 20 30',
+      '+49 9072 1111',
     ];
+    const invalidValues = [undefined, null, 'asdf', '1'];
 
     class MyClass {
-        @IsISSN()
-        someProperty: string;
+      @IsPhoneNumber('CH')
+      someProperty: string;
     }
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
+    it('should not fail if validator.validate said that its valid', () => {
+      return checkValidValues(new MyClass(), validValues);
     });
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isISSN(value)).toBeTruthy());
+    it('should fail if validator.validate said that its invalid', () => {
+      return checkInvalidValues(new MyClass(), invalidValues);
     });
+  });
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isISSN(value)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isISSN";
-        const message = "someProperty must be a ISSN";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
-
-describe("IsISSN with options", () => {
-    // eslint-disable-next-line @typescript-eslint/camelcase
-    const options = {case_sensitive: true, require_hyphen: true};
+  describe('no region', () => {
     const validValues = [
-        "2434-561X",
-        "0378-5955",
+      '+41 311111111',
+      '+41 31 633 60 01',
+      '+41 79 4 666 666',
+      '+41 75 416 20 30',
+      '+41 (0)311111111',
+      '+41 (0)31 633 60 01',
+      '+41 (0)79 4 666 666',
+      '+41 (0)75 416 20 30',
+      '+49 9072 1111',
     ];
     const invalidValues = [
-        null,
-        undefined,
-        "2434-561x",
-        "2434561X",
-        "2434561x",
-        "03785955",
+      '0311111111',
+      '031 633 60 01',
+      '079 4 666 666',
+      '075 416 20 30',
+      undefined,
+      null,
+      'asdf',
+      '1',
     ];
 
     class MyClass {
-        @IsISSN(options)
-        someProperty: string;
+      @IsPhoneNumber(null)
+      someProperty: string;
     }
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
+    it('should not fail if validator.validate said that its valid', () => {
+      return checkValidValues(new MyClass(), validValues);
     });
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isISSN(value, options)).toBeTruthy());
+    it('should fail if validator.validate said that its invalid', () => {
+      return checkInvalidValues(new MyClass(), invalidValues);
     });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isISSN(value, options)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "isISSN";
-        const message = "someProperty must be a ISSN";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-
+  });
 });
 
-describe("ArrayContains", () => {
-    const constraint = ["superman"];
-    const validValues = [["world", "hello", "superman"], ["world", "superman", "hello"], ["superman", "world", "hello"]];
-    const invalidValues = [null, undefined, ["world", "hello"]];
-
-    class MyClass {
-        @ArrayContains(constraint)
-        someProperty: string[];
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(arrayContains(value, constraint)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(arrayContains(value, constraint)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "arrayContains";
-        const message = "someProperty must contain " + constraint + " values";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+describe('IsISO31661Alpha2', () => {
+  class MyClass {
+    @IsISO31661Alpha2()
+    someProperty: string;
+  }
+
+  it('should not fail for a valid ISO31661 Alpha2 code', () => {
+    const validValues = ['AD', 'AE', 'AF', 'AG'];
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail for invalid values', () => {
+    const invalidValues = [undefined, null, '', 'AFR'];
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 });
 
-describe("ArrayNotContains", () => {
-    const constraint = ["superman"];
-    const validValues = [["world", "hello"]];
-    const invalidValues = [null, undefined, ["world", "hello", "superman"], ["world", "superman", "hello"], ["superman", "world", "hello"]];
+describe('IsISO31661Alpha3', () => {
+  class MyClass {
+    @IsISO31661Alpha3()
+    someProperty: string;
+  }
+
+  it('should not fail for a valid ISO31661 Alpha3 code', () => {
+    const validValues = ['ABW', 'HND', 'KHM', 'RWA'];
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail for invalid values', () => {
+    const invalidValues = [undefined, null, '', 'FR', 'fR', 'GB', 'PT', 'CM', 'JP', 'PM', 'ZW'];
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+});
 
+describe('isHash', () => {
+  function testHash(algorithm: ValidatorJS.HashAlgorithm, validValues: any[], invalidValues: any[]): void {
     class MyClass {
-        @ArrayNotContains(constraint)
-        someProperty: string[];
+      @IsHash(algorithm)
+      someProperty: string;
     }
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
+    it('should not fail if validator.validate said that its valid', () => {
+      return checkValidValues(new MyClass(), validValues);
     });
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
+    it('should fail if validator.validate said that its invalid', () => {
+      return checkInvalidValues(new MyClass(), invalidValues);
     });
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(arrayNotContains(value, constraint)).toBeTruthy());
+    it('should not fail if method in validator said that its valid', () => {
+      validValues.forEach(value => expect(isHash(value, algorithm)).toBeTruthy());
     });
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(arrayNotContains(value, constraint)).toBeFalsy());
+    it('should fail if method in validator said that its invalid', () => {
+      invalidValues.forEach(value => expect(isHash(value, algorithm)).toBeFalsy());
     });
 
-    it("should return error object with proper data", () => {
-        const validationType = "arrayNotContains";
-        const message = "someProperty should not contain " + constraint + " values";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+    it('should return error object with proper data', () => {
+      const validationType = 'isHash';
+      const message = `someProperty must be a hash of type ${algorithm}`;
+      return checkReturnedError(new MyClass(), invalidValues, validationType, message);
     });
-});
+  }
 
-describe("ArrayNotEmpty", () => {
-    const validValues = [[0], [""], [null], [undefined], [false], ["world", "hello", "superman"], ["world", "superman", "hello"], ["superman", "world", "hello"]];
-    const invalidValues: any[] = [null, undefined, []];
+  for (const algorithm of ['md5', 'md4', 'ripemd128', 'tiger128']) {
+    const validValues = [
+      'd94f3f016ae679c3008de268209132f2',
+      '751adbc511ccbe8edf23d486fa4581cd',
+      '88dae00e614d8f24cfd5a8b3f8002e93',
+      '0bf1c35032a71a14c2f719e5a14c1e96',
+    ];
+    const invalidValues = [
+      undefined,
+      null,
+      'q94375dj93458w34',
+      '39485729348',
+      '%&FHKJFvk',
+      'KYT0bf1c35032a71a14c2f719e5a1',
+    ];
 
-    class MyClass {
-        @ArrayNotEmpty()
-        someProperty: string[];
-    }
+    testHash(algorithm as ValidatorJS.HashAlgorithm, validValues, invalidValues);
+  }
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  for (const algorithm of ['crc32', 'crc32b']) {
+    const validValues = ['d94f3f01', '751adbc5', '88dae00e', '0bf1c350'];
+    const invalidValues = [
+      undefined,
+      null,
+      'KYT0bf1c35032a71a14c2f719e5a14c1',
+      'q94375dj93458w34',
+      'q943',
+      '39485729348',
+      '%&FHKJFvk',
+    ];
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+    testHash(algorithm as ValidatorJS.HashAlgorithm, validValues, invalidValues);
+  }
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(arrayNotEmpty(value)).toBeTruthy());
-    });
+  for (const algorithm of ['sha1', 'tiger160', 'ripemd160']) {
+    const validValues = [
+      '3ca25ae354e192b26879f651a51d92aa8a34d8d3',
+      'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d',
+      'beb8c3f30da46be179b8df5f5ecb5e4b10508230',
+      'efd5d3b190e893ed317f38da2420d63b7ae0d5ed',
+    ];
+    const invalidValues = [
+      undefined,
+      null,
+      'KYT0bf1c35032a71a14c2f719e5a14c1',
+      'KYT0bf1c35032a71a14c2f719e5a14c1dsjkjkjkjkkjk',
+      'q94375dj93458w34',
+      '39485729348',
+      '%&FHKJFvk',
+    ];
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(arrayNotEmpty(value)).toBeFalsy());
-    });
+    testHash(algorithm as ValidatorJS.HashAlgorithm, validValues, invalidValues);
+  }
 
-    it("should return error object with proper data", () => {
-        const validationType = "arrayNotEmpty";
-        const message = "someProperty should not be empty";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
-});
+  for (const algorithm of ['sha256']) {
+    const validValues = [
+      '2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824',
+      '1d996e033d612d9af2b44b70061ee0e868bfd14c2dd90b129e1edeb7953e7985',
+      '80f70bfeaed5886e33536bcfa8c05c60afef5a0e48f699a7912d5e399cdcc441',
+      '579282cfb65ca1f109b78536effaf621b853c9f7079664a3fbe2b519f435898c',
+    ];
+    const invalidValues = [
+      undefined,
+      null,
+      'KYT0bf1c35032a71a14c2f719e5a14c1',
+      'KYT0bf1c35032a71a14c2f719e5a14c1dsjkjkjkjkkjk',
+      'q94375dj93458w34',
+      '39485729348',
+      '%&FHKJFvk',
+    ];
 
-describe("ArrayMinSize", () => {
-    const constraint = 2;
-    const validValues = [["world", "hello"]];
-    const invalidValues = [null, undefined, ["hi"]];
+    testHash(algorithm as ValidatorJS.HashAlgorithm, validValues, invalidValues);
+  }
 
-    class MyClass {
-        @ArrayMinSize(constraint)
-        someProperty: string;
-    }
+  for (const algorithm of ['sha384']) {
+    const validValues = [
+      '3fed1f814d28dc5d63e313f8a601ecc4836d1662a19365cbdcf6870f6b56388850b58043f7ebf2418abb8f39c3a42e31',
+      'b330f4e575db6e73500bd3b805db1a84b5a034e5d21f0041d91eec85af1dfcb13e40bb1c4d36a72487e048ac6af74b58',
+      'bf547c3fc5841a377eb1519c2890344dbab15c40ae4150b4b34443d2212e5b04aa9d58865bf03d8ae27840fef430b891',
+      'fc09a3d11368386530f985dacddd026ae1e44e0e297c805c3429d50744e6237eb4417c20ffca8807b071823af13a3f65',
+    ];
+    const invalidValues = [
+      undefined,
+      null,
+      'KYT0bf1c35032a71a14c2f719e5a14c1',
+      'KYT0bf1c35032a71a14c2f719e5a14c1dsjkjkjkjkkjk',
+      'q94375dj93458w34',
+      '39485729348',
+      '%&FHKJFvk',
+    ];
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+    testHash(algorithm as ValidatorJS.HashAlgorithm, validValues, invalidValues);
+  }
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+  for (const algorithm of ['sha512']) {
+    const validValues = [
+      '9b71d224bd62f3785d96d46ad3ea3d73319bfbc2890caadae2dff72519673ca72323c3d99ba5c11d7c7acc6e14b8c5da0c4663475c2e5c3adef46f73bcdec043',
+      '83c586381bf5ba94c8d9ba8b6b92beb0997d76c257708742a6c26d1b7cbb9269af92d527419d5b8475f2bb6686d2f92a6649b7f174c1d8306eb335e585ab5049',
+      '45bc5fa8cb45ee408c04b6269e9f1e1c17090c5ce26ffeeda2af097735b29953ce547e40ff3ad0d120e5361cc5f9cee35ea91ecd4077f3f589b4d439168f91b9',
+      '432ac3d29e4f18c7f604f7c3c96369a6c5c61fc09bf77880548239baffd61636d42ed374f41c261e424d20d98e320e812a6d52865be059745fdb2cb20acff0ab',
+    ];
+    const invalidValues = [
+      undefined,
+      null,
+      'KYT0bf1c35032a71a14c2f719e5a14c1',
+      'KYT0bf1c35032a71a14c2f719e5a14c1dsjkjkjkjkkjk',
+      'q94375dj93458w34',
+      '39485729348',
+      '%&FHKJFvk',
+    ];
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(arrayMinSize(value, constraint)).toBeTruthy());
-    });
+    testHash(algorithm as ValidatorJS.HashAlgorithm, validValues, invalidValues);
+  }
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(arrayMinSize(value, constraint)).toBeFalsy());
-    });
+  for (const algorithm of ['tiger192']) {
+    const validValues = [
+      '6281a1f098c5e7290927ed09150d43ff3990a0fe1a48267c',
+      '56268f7bc269cf1bc83d3ce42e07a85632394737918f4760',
+      '46fc0125a148788a3ac1d649566fc04eb84a746f1a6e4fa7',
+      '7731ea1621ae99ea3197b94583d034fdbaa4dce31a67404a',
+    ];
+    const invalidValues = [
+      undefined,
+      null,
+      'KYT0bf1c35032a71a14c2f719e5a14c1',
+      'KYT0bf1c35032a71a14c2f719e5a14c1dsjkjkjkjkkjk',
+      'q94375dj93458w34',
+      '39485729348',
+      '%&FHKJFvk',
+    ];
 
-    it("should return error object with proper data", () => {
-        const validationType = "arrayMinSize";
-        const message = "someProperty must contain at least " + constraint + " elements";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+    testHash(algorithm as ValidatorJS.HashAlgorithm, validValues, invalidValues);
+  }
 });
 
-describe("ArrayMaxSize", () => {
-    const constraint = 2;
-    const validValues = [["world", "hello"]];
-    const invalidValues = [null, undefined, ["hi", "hello", "javascript"]];
-
-    class MyClass {
-        @ArrayMaxSize(constraint)
-        someProperty: string;
-    }
-
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
-
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
-
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(arrayMaxSize(value, constraint)).toBeTruthy());
-    });
-
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(arrayMaxSize(value, constraint)).toBeFalsy());
-    });
-
-    it("should return error object with proper data", () => {
-        const validationType = "arrayMaxSize";
-        const message = "someProperty must contain not more than " + constraint + " elements";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+describe('IsISSN', () => {
+  const validValues = ['0378-5955', '0000-0000', '2434-561X', '2434-561x', '01896016', '20905076'];
+  const invalidValues = [
+    null,
+    undefined,
+    '0378-5954',
+    '0000-0001',
+    '0378-123',
+    '037-1234',
+    '0',
+    '2434-561c',
+    '1684-5370',
+    '19960791',
+    '',
+  ];
+
+  class MyClass {
+    @IsISSN()
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isISSN(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isISSN(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isISSN';
+    const message = 'someProperty must be a ISSN';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("ArrayUnique", () => {
-    const validValues = [["world", "hello", "superman"], ["world", "superman", "hello"], ["superman", "world", "hello"]];
-    const invalidValues: any[] = [null, undefined, ["world", "hello", "hello"], ["world", "hello", "world"], ["1", "1", "1"]];
+describe('IsISSN with options', () => {
+  // eslint-disable-next-line @typescript-eslint/camelcase
+  const options = { case_sensitive: true, require_hyphen: true };
+  const validValues = ['2434-561X', '0378-5955'];
+  const invalidValues = [null, undefined, '2434-561x', '2434561X', '2434561x', '03785955'];
+
+  class MyClass {
+    @IsISSN(options)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isISSN(value, options)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isISSN(value, options)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'isISSN';
+    const message = 'someProperty must be a ISSN';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    class MyClass {
-        @ArrayUnique()
-        someProperty: string[];
-    }
+describe('ArrayContains', () => {
+  const constraint = ['superman'];
+  const validValues = [
+    ['world', 'hello', 'superman'],
+    ['world', 'superman', 'hello'],
+    ['superman', 'world', 'hello'],
+  ];
+  const invalidValues = [null, undefined, ['world', 'hello']];
+
+  class MyClass {
+    @ArrayContains(constraint)
+    someProperty: string[];
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(arrayContains(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(arrayContains(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'arrayContains';
+    const message = 'someProperty must contain ' + constraint + ' values';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+describe('ArrayNotContains', () => {
+  const constraint = ['superman'];
+  const validValues = [['world', 'hello']];
+  const invalidValues = [
+    null,
+    undefined,
+    ['world', 'hello', 'superman'],
+    ['world', 'superman', 'hello'],
+    ['superman', 'world', 'hello'],
+  ];
+
+  class MyClass {
+    @ArrayNotContains(constraint)
+    someProperty: string[];
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(arrayNotContains(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(arrayNotContains(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'arrayNotContains';
+    const message = 'someProperty should not contain ' + constraint + ' values';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+describe('ArrayNotEmpty', () => {
+  const validValues = [
+    [0],
+    [''],
+    [null],
+    [undefined],
+    [false],
+    ['world', 'hello', 'superman'],
+    ['world', 'superman', 'hello'],
+    ['superman', 'world', 'hello'],
+  ];
+  const invalidValues: any[] = [null, undefined, []];
+
+  class MyClass {
+    @ArrayNotEmpty()
+    someProperty: string[];
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(arrayNotEmpty(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(arrayNotEmpty(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'arrayNotEmpty';
+    const message = 'someProperty should not be empty';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(arrayUnique(value)).toBeTruthy());
-    });
+describe('ArrayMinSize', () => {
+  const constraint = 2;
+  const validValues = [['world', 'hello']];
+  const invalidValues = [null, undefined, ['hi']];
+
+  class MyClass {
+    @ArrayMinSize(constraint)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(arrayMinSize(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(arrayMinSize(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'arrayMinSize';
+    const message = 'someProperty must contain at least ' + constraint + ' elements';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(arrayUnique(value)).toBeFalsy());
-    });
+describe('ArrayMaxSize', () => {
+  const constraint = 2;
+  const validValues = [['world', 'hello']];
+  const invalidValues = [null, undefined, ['hi', 'hello', 'javascript']];
+
+  class MyClass {
+    @ArrayMaxSize(constraint)
+    someProperty: string;
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(arrayMaxSize(value, constraint)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(arrayMaxSize(value, constraint)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'arrayMaxSize';
+    const message = 'someProperty must contain not more than ' + constraint + ' elements';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
+});
 
-    it("should return error object with proper data", () => {
-        const validationType = "arrayUnique";
-        const message = "All someProperty's elements must be unique";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+describe('ArrayUnique', () => {
+  const validValues = [
+    ['world', 'hello', 'superman'],
+    ['world', 'superman', 'hello'],
+    ['superman', 'world', 'hello'],
+  ];
+  const invalidValues: any[] = [
+    null,
+    undefined,
+    ['world', 'hello', 'hello'],
+    ['world', 'hello', 'world'],
+    ['1', '1', '1'],
+  ];
+
+  class MyClass {
+    @ArrayUnique()
+    someProperty: string[];
+  }
+
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
+
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
+
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(arrayUnique(value)).toBeTruthy());
+  });
+
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(arrayUnique(value)).toBeFalsy());
+  });
+
+  it('should return error object with proper data', () => {
+    const validationType = 'arrayUnique';
+    const message = "All someProperty's elements must be unique";
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
 
-describe("isInstance", () => {
-    class MySubClass {
-        // Empty
-    }
+describe('isInstance', () => {
+  class MySubClass {
+    // Empty
+  }
 
-    class WrongSubClass {
-        // Empty
-    }
+  class WrongSubClass {
+    // Empty
+  }
 
-    class MyClass {
-        @IsInstance(MySubClass)
-        someProperty: MySubClass;
-    }
+  class MyClass {
+    @IsInstance(MySubClass)
+    someProperty: MySubClass;
+  }
 
-    const validValues = [new MySubClass()];
-    const invalidValues = [null, undefined, 15, "something", new WrongSubClass(), (): null => null];
+  const validValues = [new MySubClass()];
+  const invalidValues = [null, undefined, 15, 'something', new WrongSubClass(), (): null => null];
 
-    it("should not fail if validator.validate said that its valid", () => {
-        return checkValidValues(new MyClass(), validValues);
-    });
+  it('should not fail if validator.validate said that its valid', () => {
+    return checkValidValues(new MyClass(), validValues);
+  });
 
-    it("should fail if validator.validate said that its invalid", () => {
-        return checkInvalidValues(new MyClass(), invalidValues);
-    });
+  it('should fail if validator.validate said that its invalid', () => {
+    return checkInvalidValues(new MyClass(), invalidValues);
+  });
 
-    it("should not fail if method in validator said that its valid", () => {
-        validValues.forEach(value => expect(isInstance(value, MySubClass)).toBeTruthy());
-    });
+  it('should not fail if method in validator said that its valid', () => {
+    validValues.forEach(value => expect(isInstance(value, MySubClass)).toBeTruthy());
+  });
 
-    it("should fail if method in validator said that its invalid", () => {
-        invalidValues.forEach(value => expect(isInstance(value, MySubClass)).toBeFalsy());
-    });
+  it('should fail if method in validator said that its invalid', () => {
+    invalidValues.forEach(value => expect(isInstance(value, MySubClass)).toBeFalsy());
+  });
 
-    it("should return error object with proper data", () => {
-        const validationType = "isInstance";
-        const message = "someProperty must be an instance of MySubClass";
-        return checkReturnedError(new MyClass(), invalidValues, validationType, message);
-    });
+  it('should return error object with proper data', () => {
+    const validationType = 'isInstance';
+    const message = 'someProperty must be an instance of MySubClass';
+    return checkReturnedError(new MyClass(), invalidValues, validationType, message);
+  });
 });
diff --git a/test/functional/validation-options.spec.ts b/test/functional/validation-options.spec.ts
index 60932ecc9a..b072a66858 100644
--- a/test/functional/validation-options.spec.ts
+++ b/test/functional/validation-options.spec.ts
@@ -1,1037 +1,1217 @@
-import {Contains, IsDefined, Matches, MinLength, Validate, ValidateNested, ValidatorConstraint} from "../../src/decorator/decorators";
-import {Validator} from "../../src/validation/Validator";
-import {registerDecorator, ValidationArguments, ValidationError, ValidationOptions, ValidatorConstraintInterface} from "../../src";
+import {
+  Contains,
+  IsDefined,
+  Matches,
+  MinLength,
+  Validate,
+  ValidateNested,
+  ValidatorConstraint,
+  IsOptional,
+  IsNotEmpty,
+} from '../../src/decorator/decorators';
+import { Validator } from '../../src/validation/Validator';
+import {
+  registerDecorator,
+  ValidationArguments,
+  ValidationError,
+  ValidationOptions,
+  ValidatorConstraintInterface,
+} from '../../src';
 
 const validator = new Validator();
 
-describe("message", () => {
+describe('message', () => {
+  it('should contain a custom message', () => {
+    class MyClass {
+      @Contains('hello', {
+        message: 'String is not valid. You string must contain a hello word',
+      })
+      someProperty: string;
+    }
 
-    it("should contain a custom message", () => {
-        class MyClass {
-            @Contains("hello", {
-                message: "String is not valid. You string must contain a hello word"
-            })
-            someProperty: string;
-        }
+    const model = new MyClass();
+    // TODO: Why is this commented out?
+    // model.someProperty = "hell no world";
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].constraints).toEqual({ contains: 'String is not valid. You string must contain a hello word' });
+    });
+  });
 
-        const model = new MyClass();
-        // TODO: Why is this commented out?
-        // model.someProperty = "hell no world";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].constraints).toEqual({contains: "String is not valid. You string must contain a hello word"});
-        });
+  it('$value token should be replaced in a custom message', () => {
+    class MyClass {
+      @Contains('hello', {
+        message: '$value is not valid. You string must contain a hello word',
+      })
+      someProperty: string;
+    }
+
+    const model = new MyClass();
+    model.someProperty = 'hell no world';
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].constraints).toEqual({
+        contains: 'hell no world is not valid. You string must contain a hello word',
+      });
     });
+  });
 
-    it("$value token should be replaced in a custom message", () => {
-        class MyClass {
-            @Contains("hello", {
-                message: "$value is not valid. You string must contain a hello word"
-            })
-            someProperty: string;
-        }
+  it('$value token should be replaced in a custom message', () => {
+    class MyClass {
+      @MinLength(2, {
+        message: args => {
+          if (args.value.length < 2) {
+            return '$value is too short, minimum length is $constraint1 characters $property';
+          }
+        },
+      })
+      name: string;
+    }
 
-        const model = new MyClass();
-        model.someProperty = "hell no world";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].constraints).toEqual({contains: "hell no world is not valid. You string must contain a hello word"});
-        });
+    const model = new MyClass();
+    model.name = '';
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].constraints).toEqual({ minLength: ' is too short, minimum length is 2 characters name' });
     });
+  });
 
-    it("$value token should be replaced in a custom message", () => {
-        class MyClass {
-            @MinLength(2, {
-                message: args => {
-                    if (args.value.length < 2) {
-                        return "$value is too short, minimum length is $constraint1 characters $property";
-                    }
-                }
-            })
-            name: string;
-        }
+  it('$constraint1 token should be replaced in a custom message', () => {
+    class MyClass {
+      @Contains('hello', {
+        message: 'String is not valid. You string must contain a $constraint1 word',
+      })
+      someProperty: string;
+    }
 
-        const model = new MyClass();
-        model.name = "";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].constraints).toEqual({minLength: " is too short, minimum length is 2 characters name"});
-        });
+    const model = new MyClass();
+    model.someProperty = 'hell no world';
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].constraints).toEqual({ contains: 'String is not valid. You string must contain a hello word' });
     });
+  });
 
-    it("$constraint1 token should be replaced in a custom message", () => {
-        class MyClass {
-            @Contains("hello", {
-                message: "String is not valid. You string must contain a $constraint1 word"
-            })
-            someProperty: string;
-        }
+  it('$target token should be replaced in a custom message', () => {
+    class MyClass {
+      @Contains('hello', {
+        message: '$target is not valid.',
+      })
+      someProperty: string;
+    }
 
-        const model = new MyClass();
-        model.someProperty = "hell no world";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].constraints).toEqual({contains: "String is not valid. You string must contain a hello word"});
-        });
+    const model = new MyClass();
+    model.someProperty = 'hell no world';
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].constraints).toEqual({ contains: 'MyClass is not valid.' });
+    });
+  });
+
+  it('$property token should be replaced in a custom message', () => {
+    class MyClass {
+      @Contains('hello', {
+        message: '$property is not valid.',
+      })
+      someProperty: string;
+    }
+
+    const model = new MyClass();
+    model.someProperty = 'hell no world';
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].constraints).toEqual({ contains: 'someProperty is not valid.' });
+    });
+  });
+
+  it('should replace all token', () => {
+    class MyClass {
+      @Contains('hello', {
+        message: '$target#$property is not valid: $value must contain a $constraint1 word',
+      })
+      someProperty: string;
+    }
+
+    const model = new MyClass();
+    model.someProperty = 'hell no world';
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].constraints).toEqual({
+        contains: 'MyClass#someProperty is not valid: hell no world must contain a hello word',
+      });
+    });
+  });
+});
+
+describe('each', () => {
+  describe('Array', () => {
+    it('should apply validation to each item in the array', () => {
+      class MyClass {
+        @Contains('hello', {
+          each: true,
+        })
+        someProperty: string[];
+      }
+
+      const model = new MyClass();
+      model.someProperty = ['hell no world', 'hello', 'helo world', 'hello world', 'hello dear friend'];
+      return validator.validate(model).then(errors => {
+        expect(errors.length).toEqual(1);
+        expect(errors[0].constraints).toEqual({ contains: 'each value in someProperty must contain a hello string' });
+        expect(errors[0].value).toEqual(model.someProperty);
+        expect(errors[0].target).toEqual(model);
+        expect(errors[0].property).toEqual('someProperty');
+      });
     });
 
-    it("$target token should be replaced in a custom message", () => {
-        class MyClass {
-            @Contains("hello", {
-                message: "$target is not valid."
-            })
-            someProperty: string;
+    it('should apply validation via custom constraint class to array items (but not array itself)', () => {
+      @ValidatorConstraint({ name: 'customIsNotArrayConstraint', async: false })
+      class CustomIsNotArrayConstraint implements ValidatorConstraintInterface {
+        validate(value: any): boolean {
+          return !(value instanceof Array);
         }
+      }
 
-        const model = new MyClass();
-        model.someProperty = "hell no world";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].constraints).toEqual({contains: "MyClass is not valid."});
-        });
+      class MyClass {
+        @Validate(CustomIsNotArrayConstraint, {
+          each: true,
+        })
+        someArrayOfNonArrayItems: string[];
+      }
+
+      const model = new MyClass();
+      model.someArrayOfNonArrayItems = ['not array', 'also not array', 'not array at all'];
+      return validator.validate(model).then(errors => {
+        expect(errors.length).toEqual(0);
+      });
     });
 
-    it("$property token should be replaced in a custom message", () => {
-        class MyClass {
-            @Contains("hello", {
-                message: "$property is not valid."
-            })
-            someProperty: string;
+    it('should apply validation via custom constraint class with synchronous logic to each item in the array', () => {
+      @ValidatorConstraint({ name: 'customContainsHelloConstraint', async: false })
+      class CustomContainsHelloConstraint implements ValidatorConstraintInterface {
+        validate(value: any): boolean {
+          return !(value instanceof Array) && String(value).includes('hello');
         }
+      }
 
-        const model = new MyClass();
-        model.someProperty = "hell no world";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].constraints).toEqual({contains: "someProperty is not valid."});
-        });
+      class MyClass {
+        @Validate(CustomContainsHelloConstraint, {
+          each: true,
+        })
+        someProperty: string[];
+      }
+
+      const model = new MyClass();
+      model.someProperty = ['hell no world', 'hello', 'helo world', 'hello world', 'hello dear friend'];
+      return validator.validate(model).then(errors => {
+        expect(errors.length).toEqual(1);
+        expect(errors[0].constraints).toEqual({ customContainsHelloConstraint: '' });
+        expect(errors[0].value).toEqual(model.someProperty);
+        expect(errors[0].target).toEqual(model);
+        expect(errors[0].property).toEqual('someProperty');
+      });
     });
 
-    it("should replace all token", () => {
-        class MyClass {
-            @Contains("hello", {
-                message: "$target#$property is not valid: $value must contain a $constraint1 word"
-            })
-            someProperty: string;
+    it('should apply validation via custom constraint class with async logic to each item in the array', () => {
+      @ValidatorConstraint({ name: 'customAsyncContainsHelloConstraint', async: true })
+      class CustomAsyncContainsHelloConstraint implements ValidatorConstraintInterface {
+        validate(value: any): Promise<boolean> {
+          const isValid = !(value instanceof Array) && String(value).includes('hello');
+          return Promise.resolve(isValid);
         }
+      }
 
-        const model = new MyClass();
-        model.someProperty = "hell no world";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].constraints).toEqual({contains: "MyClass#someProperty is not valid: hell no world must contain a hello word"});
-        });
+      class MyClass {
+        @Validate(CustomAsyncContainsHelloConstraint, {
+          each: true,
+        })
+        someProperty: string[];
+      }
+
+      const model = new MyClass();
+      model.someProperty = ['hell no world', 'hello', 'helo world', 'hello world', 'hello dear friend'];
+      return validator.validate(model).then(errors => {
+        expect(errors.length).toEqual(1);
+        expect(errors[0].constraints).toEqual({ customAsyncContainsHelloConstraint: '' });
+        expect(errors[0].value).toEqual(model.someProperty);
+        expect(errors[0].target).toEqual(model);
+        expect(errors[0].property).toEqual('someProperty');
+      });
     });
 
-});
+    it('should apply validation via custom constraint class with mixed (synchronous + async) logic to each item in the array', () => {
+      @ValidatorConstraint({ name: 'customMixedContainsHelloConstraint', async: true })
+      class CustomMixedContainsHelloConstraint implements ValidatorConstraintInterface {
+        validate(value: any): boolean | Promise<boolean> {
+          const isValid = !(value instanceof Array) && String(value).includes('hello');
+          return isValid ? isValid : Promise.resolve(isValid);
+        }
+      }
 
-describe("each", () => {
-
-    describe("Array", () => {
-
-        it("should apply validation to each item in the array", () => {
-            class MyClass {
-                @Contains("hello", {
-                    each: true
-                })
-                someProperty: string[];
-            }
-
-            const model = new MyClass();
-            model.someProperty = ["hell no world", "hello", "helo world", "hello world", "hello dear friend"];
-            return validator.validate(model).then(errors => {
-                expect(errors.length).toEqual(1);
-                expect(errors[0].constraints).toEqual({contains: "each value in someProperty must contain a hello string"});
-                expect(errors[0].value).toEqual(model.someProperty);
-                expect(errors[0].target).toEqual(model);
-                expect(errors[0].property).toEqual("someProperty");
-            });
-        });
+      class MyClass {
+        @Validate(CustomMixedContainsHelloConstraint, {
+          each: true,
+        })
+        someProperty: string[];
+      }
+
+      const model = new MyClass();
+      model.someProperty = ['hell no world', 'hello', 'helo world', 'hello world', 'hello dear friend'];
+      return validator.validate(model).then(errors => {
+        expect(errors.length).toEqual(1);
+        expect(errors[0].constraints).toEqual({ customMixedContainsHelloConstraint: '' });
+        expect(errors[0].value).toEqual(model.someProperty);
+        expect(errors[0].target).toEqual(model);
+        expect(errors[0].property).toEqual('someProperty');
+      });
+    });
+  });
 
-        it("should apply validation via custom constraint class to array items (but not array itself)", () => {
-            @ValidatorConstraint({name: "customIsNotArrayConstraint", async: false})
-            class CustomIsNotArrayConstraint implements ValidatorConstraintInterface {
-                validate(value: any): boolean {
-                    return !(value instanceof Array);
-                }
-            }
-
-            class MyClass {
-                @Validate(CustomIsNotArrayConstraint, {
-                    each: true
-                })
-                someArrayOfNonArrayItems: string[];
-            }
-
-            const model = new MyClass();
-            model.someArrayOfNonArrayItems = ["not array", "also not array", "not array at all"];
-            return validator.validate(model).then(errors => {
-                expect(errors.length).toEqual(0);
-            });
-        });
+  describe('Set', () => {
+    it('should apply validation to each item in the Set', () => {
+      class MyClass {
+        @Contains('hello', {
+          each: true,
+        })
+        someProperty: Set<string>;
+      }
+
+      const model = new MyClass();
+      model.someProperty = new Set<string>([
+        'hell no world',
+        'hello',
+        'helo world',
+        'hello world',
+        'hello dear friend',
+      ]);
+      return validator.validate(model).then(errors => {
+        expect(errors.length).toEqual(1);
+        expect(errors[0].constraints).toEqual({ contains: 'each value in someProperty must contain a hello string' });
+        expect(errors[0].value).toEqual(model.someProperty);
+        expect(errors[0].target).toEqual(model);
+        expect(errors[0].property).toEqual('someProperty');
+      });
+    });
 
-        it("should apply validation via custom constraint class with synchronous logic to each item in the array", () => {
-            @ValidatorConstraint({name: "customContainsHelloConstraint", async: false})
-            class CustomContainsHelloConstraint implements ValidatorConstraintInterface {
-                validate(value: any): boolean {
-                    return !(value instanceof Array) && String(value).includes("hello");
-                }
-            }
-
-            class MyClass {
-                @Validate(CustomContainsHelloConstraint, {
-                    each: true
-                })
-                someProperty: string[];
-            }
-
-            const model = new MyClass();
-            model.someProperty = ["hell no world", "hello", "helo world", "hello world", "hello dear friend"];
-            return validator.validate(model).then(errors => {
-                expect(errors.length).toEqual(1);
-                expect(errors[0].constraints).toEqual({customContainsHelloConstraint: ""});
-                expect(errors[0].value).toEqual(model.someProperty);
-                expect(errors[0].target).toEqual(model);
-                expect(errors[0].property).toEqual("someProperty");
-            });
-        });
+    it('should apply validation via custom constraint class to Set items (but not Set itself)', () => {
+      @ValidatorConstraint({ name: 'customIsNotSetConstraint', async: false })
+      class CustomIsNotSetConstraint implements ValidatorConstraintInterface {
+        validate(value: any): boolean {
+          return !(value instanceof Set);
+        }
+      }
 
-        it("should apply validation via custom constraint class with async logic to each item in the array", () => {
-            @ValidatorConstraint({name: "customAsyncContainsHelloConstraint", async: true})
-            class CustomAsyncContainsHelloConstraint implements ValidatorConstraintInterface {
-                validate(value: any): Promise<boolean> {
-                    const isValid = !(value instanceof Array) && String(value).includes("hello");
-                    return Promise.resolve(isValid);
-                }
-            }
-
-            class MyClass {
-                @Validate(CustomAsyncContainsHelloConstraint, {
-                    each: true
-                })
-                someProperty: string[];
-            }
-
-            const model = new MyClass();
-            model.someProperty = ["hell no world", "hello", "helo world", "hello world", "hello dear friend"];
-            return validator.validate(model).then(errors => {
-                expect(errors.length).toEqual(1);
-                expect(errors[0].constraints).toEqual({customAsyncContainsHelloConstraint: ""});
-                expect(errors[0].value).toEqual(model.someProperty);
-                expect(errors[0].target).toEqual(model);
-                expect(errors[0].property).toEqual("someProperty");
-            });
-        });
+      class MyClass {
+        @Validate(CustomIsNotSetConstraint, {
+          each: true,
+        })
+        someSetOfNonSetItems: Set<string>;
+      }
+
+      const model = new MyClass();
+      model.someSetOfNonSetItems = new Set<string>(['not array', 'also not array', 'not array at all']);
+      return validator.validate(model).then(errors => {
+        expect(errors.length).toEqual(0);
+      });
+    });
 
-        it("should apply validation via custom constraint class with mixed (synchronous + async) logic to each item in the array", () => {
-            @ValidatorConstraint({name: "customMixedContainsHelloConstraint", async: true})
-            class CustomMixedContainsHelloConstraint implements ValidatorConstraintInterface {
-                validate(value: any): boolean | Promise<boolean> {
-                    const isValid = !(value instanceof Array) && String(value).includes("hello");
-                    return isValid ? isValid : Promise.resolve(isValid);
-                }
-            }
-
-            class MyClass {
-                @Validate(CustomMixedContainsHelloConstraint, {
-                    each: true
-                })
-                someProperty: string[];
-            }
-
-            const model = new MyClass();
-            model.someProperty = ["hell no world", "hello", "helo world", "hello world", "hello dear friend"];
-            return validator.validate(model).then(errors => {
-                expect(errors.length).toEqual(1);
-                expect(errors[0].constraints).toEqual({customMixedContainsHelloConstraint: ""});
-                expect(errors[0].value).toEqual(model.someProperty);
-                expect(errors[0].target).toEqual(model);
-                expect(errors[0].property).toEqual("someProperty");
-            });
-        });
+    it('should apply validation via custom constraint class with synchronous logic to each item in the Set', () => {
+      @ValidatorConstraint({ name: 'customContainsHelloConstraint', async: false })
+      class CustomContainsHelloConstraint implements ValidatorConstraintInterface {
+        validate(value: any): boolean {
+          return !(value instanceof Set) && String(value).includes('hello');
+        }
+      }
+
+      class MyClass {
+        @Validate(CustomContainsHelloConstraint, {
+          each: true,
+        })
+        someProperty: Set<string>;
+      }
+
+      const model = new MyClass();
+      model.someProperty = new Set<string>([
+        'hell no world',
+        'hello',
+        'helo world',
+        'hello world',
+        'hello dear friend',
+      ]);
+      return validator.validate(model).then(errors => {
+        expect(errors.length).toEqual(1);
+        expect(errors[0].constraints).toEqual({ customContainsHelloConstraint: '' });
+        expect(errors[0].value).toEqual(model.someProperty);
+        expect(errors[0].target).toEqual(model);
+        expect(errors[0].property).toEqual('someProperty');
+      });
     });
 
-    describe("Set", () => {
-
-        it("should apply validation to each item in the Set", () => {
-            class MyClass {
-                @Contains("hello", {
-                    each: true
-                })
-                someProperty: Set<string>;
-            }
-
-            const model = new MyClass();
-            model.someProperty = new Set<string>(["hell no world", "hello", "helo world", "hello world", "hello dear friend"]);
-            return validator.validate(model).then(errors => {
-                expect(errors.length).toEqual(1);
-                expect(errors[0].constraints).toEqual({contains: "each value in someProperty must contain a hello string"});
-                expect(errors[0].value).toEqual(model.someProperty);
-                expect(errors[0].target).toEqual(model);
-                expect(errors[0].property).toEqual("someProperty");
-            });
-        });
+    it('should apply validation via custom constraint class with async logic to each item in the Set', () => {
+      @ValidatorConstraint({ name: 'customAsyncContainsHelloConstraint', async: true })
+      class CustomAsyncContainsHelloConstraint implements ValidatorConstraintInterface {
+        validate(value: any): Promise<boolean> {
+          const isValid = !(value instanceof Set) && String(value).includes('hello');
+          return Promise.resolve(isValid);
+        }
+      }
 
-        it("should apply validation via custom constraint class to Set items (but not Set itself)", () => {
-            @ValidatorConstraint({name: "customIsNotSetConstraint", async: false})
-            class CustomIsNotSetConstraint implements ValidatorConstraintInterface {
-                validate(value: any): boolean {
-                    return !(value instanceof Set);
-                }
-            }
-
-            class MyClass {
-                @Validate(CustomIsNotSetConstraint, {
-                    each: true
-                })
-                someSetOfNonSetItems: Set<string>;
-            }
-
-            const model = new MyClass();
-            model.someSetOfNonSetItems = new Set<string>(["not array", "also not array", "not array at all"]);
-            return validator.validate(model).then(errors => {
-                expect(errors.length).toEqual(0);
-            });
-        });
+      class MyClass {
+        @Validate(CustomAsyncContainsHelloConstraint, {
+          each: true,
+        })
+        someProperty: Set<string>;
+      }
+
+      const model = new MyClass();
+      model.someProperty = new Set<string>([
+        'hell no world',
+        'hello',
+        'helo world',
+        'hello world',
+        'hello dear friend',
+      ]);
+      return validator.validate(model).then(errors => {
+        expect(errors.length).toEqual(1);
+        expect(errors[0].constraints).toEqual({ customAsyncContainsHelloConstraint: '' });
+        expect(errors[0].value).toEqual(model.someProperty);
+        expect(errors[0].target).toEqual(model);
+        expect(errors[0].property).toEqual('someProperty');
+      });
+    });
 
-        it("should apply validation via custom constraint class with synchronous logic to each item in the Set", () => {
-            @ValidatorConstraint({name: "customContainsHelloConstraint", async: false})
-            class CustomContainsHelloConstraint implements ValidatorConstraintInterface {
-                validate(value: any): boolean {
-                    return !(value instanceof Set) && String(value).includes("hello");
-                }
-            }
-
-            class MyClass {
-                @Validate(CustomContainsHelloConstraint, {
-                    each: true
-                })
-                someProperty: Set<string>;
-            }
-
-            const model = new MyClass();
-            model.someProperty = new Set<string>(["hell no world", "hello", "helo world", "hello world", "hello dear friend"]);
-            return validator.validate(model).then(errors => {
-                expect(errors.length).toEqual(1);
-                expect(errors[0].constraints).toEqual({customContainsHelloConstraint: ""});
-                expect(errors[0].value).toEqual(model.someProperty);
-                expect(errors[0].target).toEqual(model);
-                expect(errors[0].property).toEqual("someProperty");
-            });
-        });
+    it('should apply validation via custom constraint class with mixed (synchronous + async) logic to each item in the Set', () => {
+      @ValidatorConstraint({ name: 'customMixedContainsHelloConstraint', async: true })
+      class CustomMixedContainsHelloConstraint implements ValidatorConstraintInterface {
+        validate(value: any): boolean | Promise<boolean> {
+          const isValid = !(value instanceof Set) && String(value).includes('hello');
+          return isValid ? isValid : Promise.resolve(isValid);
+        }
+      }
 
-        it("should apply validation via custom constraint class with async logic to each item in the Set", () => {
-            @ValidatorConstraint({name: "customAsyncContainsHelloConstraint", async: true})
-            class CustomAsyncContainsHelloConstraint implements ValidatorConstraintInterface {
-                validate(value: any): Promise<boolean> {
-                    const isValid = !(value instanceof Set) && String(value).includes("hello");
-                    return Promise.resolve(isValid);
-                }
-            }
-
-            class MyClass {
-                @Validate(CustomAsyncContainsHelloConstraint, {
-                    each: true
-                })
-                someProperty: Set<string>;
-            }
-
-            const model = new MyClass();
-            model.someProperty = new Set<string>(["hell no world", "hello", "helo world", "hello world", "hello dear friend"]);
-            return validator.validate(model).then(errors => {
-                expect(errors.length).toEqual(1);
-                expect(errors[0].constraints).toEqual({customAsyncContainsHelloConstraint: ""});
-                expect(errors[0].value).toEqual(model.someProperty);
-                expect(errors[0].target).toEqual(model);
-                expect(errors[0].property).toEqual("someProperty");
-            });
-        });
+      class MyClass {
+        @Validate(CustomMixedContainsHelloConstraint, {
+          each: true,
+        })
+        someProperty: Set<string>;
+      }
+
+      const model = new MyClass();
+      model.someProperty = new Set<string>([
+        'hell no world',
+        'hello',
+        'helo world',
+        'hello world',
+        'hello dear friend',
+      ]);
+      return validator.validate(model).then(errors => {
+        expect(errors.length).toEqual(1);
+        expect(errors[0].constraints).toEqual({ customMixedContainsHelloConstraint: '' });
+        expect(errors[0].value).toEqual(model.someProperty);
+        expect(errors[0].target).toEqual(model);
+        expect(errors[0].property).toEqual('someProperty');
+      });
+    });
+  });
 
-        it("should apply validation via custom constraint class with mixed (synchronous + async) logic to each item in the Set", () => {
-            @ValidatorConstraint({name: "customMixedContainsHelloConstraint", async: true})
-            class CustomMixedContainsHelloConstraint implements ValidatorConstraintInterface {
-                validate(value: any): boolean | Promise<boolean> {
-                    const isValid = !(value instanceof Set) && String(value).includes("hello");
-                    return isValid ? isValid : Promise.resolve(isValid);
-                }
-            }
-
-            class MyClass {
-                @Validate(CustomMixedContainsHelloConstraint, {
-                    each: true
-                })
-                someProperty: Set<string>;
-            }
-
-            const model = new MyClass();
-            model.someProperty = new Set<string>(["hell no world", "hello", "helo world", "hello world", "hello dear friend"]);
-            return validator.validate(model).then(errors => {
-                expect(errors.length).toEqual(1);
-                expect(errors[0].constraints).toEqual({customMixedContainsHelloConstraint: ""});
-                expect(errors[0].value).toEqual(model.someProperty);
-                expect(errors[0].target).toEqual(model);
-                expect(errors[0].property).toEqual("someProperty");
-            });
-        });
+  describe('Map', () => {
+    it('should apply validation to each item in the Map', () => {
+      class MyClass {
+        @Contains('hello', {
+          each: true,
+        })
+        someProperty: Map<string, string>;
+      }
+
+      const model = new MyClass();
+      model.someProperty = new Map<string, string>([
+        ['key1', 'hell no world'],
+        ['key2', 'hello'],
+        ['key3', 'helo world'],
+        ['key4', 'hello world'],
+        ['key5', 'hello dear friend'],
+      ]);
+      return validator.validate(model).then(errors => {
+        expect(errors.length).toEqual(1);
+        expect(errors[0].constraints).toEqual({ contains: 'each value in someProperty must contain a hello string' });
+        expect(errors[0].value).toEqual(model.someProperty);
+        expect(errors[0].target).toEqual(model);
+        expect(errors[0].property).toEqual('someProperty');
+      });
+    });
+
+    it('should apply validation via custom constraint class to Map items (but not Map itself)', () => {
+      @ValidatorConstraint({ name: 'customIsNotMapConstraint', async: false })
+      class CustomIsNotMapConstraint implements ValidatorConstraintInterface {
+        validate(value: any): boolean {
+          return !(value instanceof Map);
+        }
+      }
 
+      class MyClass {
+        @Validate(CustomIsNotMapConstraint, {
+          each: true,
+        })
+        someArrayOfNonArrayItems: Map<string, string>;
+      }
+
+      const model = new MyClass();
+      model.someArrayOfNonArrayItems = new Map<string, string>([
+        ['key1', 'not array'],
+        ['key2', 'also not array'],
+        ['key3', 'not array at all'],
+      ]);
+      return validator.validate(model).then(errors => {
+        expect(errors.length).toEqual(0);
+      });
     });
 
-    describe("Map", () => {
+    it('should apply validation via custom constraint class with synchronous logic to each item in the Map', () => {
+      @ValidatorConstraint({ name: 'customContainsHelloConstraint', async: false })
+      class CustomContainsHelloConstraint implements ValidatorConstraintInterface {
+        validate(value: any): boolean {
+          return !(value instanceof Map) && String(value).includes('hello');
+        }
+      }
 
-        it("should apply validation to each item in the Map", () => {
-            class MyClass {
-                @Contains("hello", {
-                    each: true
-                })
-                someProperty: Map<string, string>;
-            }
+      class MyClass {
+        @Validate(CustomContainsHelloConstraint, {
+          each: true,
+        })
+        someProperty: Map<string, string>;
+      }
+
+      const model = new MyClass();
+      model.someProperty = new Map<string, string>([
+        ['key1', 'hell no world'],
+        ['key2', 'hello'],
+        ['key3', 'helo world'],
+        ['key4', 'hello world'],
+        ['key5', 'hello dear friend'],
+      ]);
+      return validator.validate(model).then(errors => {
+        expect(errors.length).toEqual(1);
+        expect(errors[0].constraints).toEqual({ customContainsHelloConstraint: '' });
+        expect(errors[0].value).toEqual(model.someProperty);
+        expect(errors[0].target).toEqual(model);
+        expect(errors[0].property).toEqual('someProperty');
+      });
+    });
 
-            const model = new MyClass();
-            model.someProperty = new Map<string, string>([["key1", "hell no world"], ["key2", "hello"], ["key3", "helo world"], ["key4", "hello world"], ["key5", "hello dear friend"]]);
-            return validator.validate(model).then(errors => {
-                expect(errors.length).toEqual(1);
-                expect(errors[0].constraints).toEqual({contains: "each value in someProperty must contain a hello string"});
-                expect(errors[0].value).toEqual(model.someProperty);
-                expect(errors[0].target).toEqual(model);
-                expect(errors[0].property).toEqual("someProperty");
-            });
-        });
+    it('should apply validation via custom constraint class with async logic to each item in the Map', () => {
+      @ValidatorConstraint({ name: 'customAsyncContainsHelloConstraint', async: true })
+      class CustomAsyncContainsHelloConstraint implements ValidatorConstraintInterface {
+        validate(value: any): Promise<boolean> {
+          const isValid = !(value instanceof Map) && String(value).includes('hello');
+          return Promise.resolve(isValid);
+        }
+      }
 
-        it("should apply validation via custom constraint class to Map items (but not Map itself)", () => {
-            @ValidatorConstraint({name: "customIsNotMapConstraint", async: false})
-            class CustomIsNotMapConstraint implements ValidatorConstraintInterface {
-                validate(value: any): boolean {
-                    return !(value instanceof Map);
-                }
-            }
-
-            class MyClass {
-                @Validate(CustomIsNotMapConstraint, {
-                    each: true
-                })
-                someArrayOfNonArrayItems: Map<string, string>;
-            }
-
-            const model = new MyClass();
-            model.someArrayOfNonArrayItems = new Map<string, string>([["key1", "not array"], ["key2", "also not array"], ["key3", "not array at all"]]);
-            return validator.validate(model).then(errors => {
-                expect(errors.length).toEqual(0);
-            });
-        });
+      class MyClass {
+        @Validate(CustomAsyncContainsHelloConstraint, {
+          each: true,
+        })
+        someProperty: Map<string, string>;
+      }
+
+      const model = new MyClass();
+      model.someProperty = new Map<string, string>([
+        ['key1', 'hell no world'],
+        ['key2', 'hello'],
+        ['key3', 'helo world'],
+        ['key4', 'hello world'],
+        ['key5', 'hello dear friend'],
+      ]);
+      return validator.validate(model).then(errors => {
+        expect(errors.length).toEqual(1);
+        expect(errors[0].constraints).toEqual({ customAsyncContainsHelloConstraint: '' });
+        expect(errors[0].value).toEqual(model.someProperty);
+        expect(errors[0].target).toEqual(model);
+        expect(errors[0].property).toEqual('someProperty');
+      });
+    });
 
-        it("should apply validation via custom constraint class with synchronous logic to each item in the Map", () => {
-            @ValidatorConstraint({name: "customContainsHelloConstraint", async: false})
-            class CustomContainsHelloConstraint implements ValidatorConstraintInterface {
-                validate(value: any): boolean {
-                    return !(value instanceof Map) && String(value).includes("hello");
-                }
-            }
-
-            class MyClass {
-                @Validate(CustomContainsHelloConstraint, {
-                    each: true
-                })
-                someProperty: Map<string, string>;
-            }
-
-            const model = new MyClass();
-            model.someProperty = new Map<string, string>([["key1", "hell no world"], ["key2", "hello"], ["key3", "helo world"], ["key4", "hello world"], ["key5", "hello dear friend"]]);
-            return validator.validate(model).then(errors => {
-                expect(errors.length).toEqual(1);
-                expect(errors[0].constraints).toEqual({customContainsHelloConstraint: ""});
-                expect(errors[0].value).toEqual(model.someProperty);
-                expect(errors[0].target).toEqual(model);
-                expect(errors[0].property).toEqual("someProperty");
-            });
-        });
+    it('should apply validation via custom constraint class with mixed (synchronous + async) logic to each item in the Map', () => {
+      @ValidatorConstraint({ name: 'customMixedContainsHelloConstraint', async: true })
+      class CustomMixedContainsHelloConstraint implements ValidatorConstraintInterface {
+        validate(value: any): boolean | Promise<boolean> {
+          const isValid = !(value instanceof Map) && String(value).includes('hello');
+          return isValid ? isValid : Promise.resolve(isValid);
+        }
+      }
 
-        it("should apply validation via custom constraint class with async logic to each item in the Map", () => {
-            @ValidatorConstraint({name: "customAsyncContainsHelloConstraint", async: true})
-            class CustomAsyncContainsHelloConstraint implements ValidatorConstraintInterface {
-                validate(value: any): Promise<boolean> {
-                    const isValid = !(value instanceof Map) && String(value).includes("hello");
-                    return Promise.resolve(isValid);
-                }
-            }
-
-            class MyClass {
-                @Validate(CustomAsyncContainsHelloConstraint, {
-                    each: true
-                })
-                someProperty: Map<string, string>;
-            }
-
-            const model = new MyClass();
-            model.someProperty = new Map<string, string>([["key1", "hell no world"], ["key2", "hello"], ["key3", "helo world"], ["key4", "hello world"], ["key5", "hello dear friend"]]);
-            return validator.validate(model).then(errors => {
-                expect(errors.length).toEqual(1);
-                expect(errors[0].constraints).toEqual({customAsyncContainsHelloConstraint: ""});
-                expect(errors[0].value).toEqual(model.someProperty);
-                expect(errors[0].target).toEqual(model);
-                expect(errors[0].property).toEqual("someProperty");
-            });
-        });
+      class MyClass {
+        @Validate(CustomMixedContainsHelloConstraint, {
+          each: true,
+        })
+        someProperty: Map<string, string>;
+      }
+
+      const model = new MyClass();
+      model.someProperty = new Map<string, string>([
+        ['key1', 'hell no world'],
+        ['key2', 'hello'],
+        ['key3', 'helo world'],
+        ['key4', 'hello world'],
+        ['key5', 'hello dear friend'],
+      ]);
+      return validator.validate(model).then(errors => {
+        expect(errors.length).toEqual(1);
+        expect(errors[0].constraints).toEqual({ customMixedContainsHelloConstraint: '' });
+        expect(errors[0].value).toEqual(model.someProperty);
+        expect(errors[0].target).toEqual(model);
+        expect(errors[0].property).toEqual('someProperty');
+      });
+    });
+  });
+});
 
-        it("should apply validation via custom constraint class with mixed (synchronous + async) logic to each item in the Map", () => {
-            @ValidatorConstraint({name: "customMixedContainsHelloConstraint", async: true})
-            class CustomMixedContainsHelloConstraint implements ValidatorConstraintInterface {
-                validate(value: any): boolean | Promise<boolean> {
-                    const isValid = !(value instanceof Map) && String(value).includes("hello");
-                    return isValid ? isValid : Promise.resolve(isValid);
-                }
-            }
-
-            class MyClass {
-                @Validate(CustomMixedContainsHelloConstraint, {
-                    each: true
-                })
-                someProperty: Map<string, string>;
-            }
-
-            const model = new MyClass();
-            model.someProperty = new Map<string, string>([["key1", "hell no world"], ["key2", "hello"], ["key3", "helo world"], ["key4", "hello world"], ["key5", "hello dear friend"]]);
-            return validator.validate(model).then(errors => {
-                expect(errors.length).toEqual(1);
-                expect(errors[0].constraints).toEqual({customMixedContainsHelloConstraint: ""});
-                expect(errors[0].value).toEqual(model.someProperty);
-                expect(errors[0].target).toEqual(model);
-                expect(errors[0].property).toEqual("someProperty");
-            });
-        });
+describe('groups', () => {
+  function expectTitleContains(error: ValidationError): void {
+    expect(error.constraints).toEqual({ contains: 'title must contain a hello string' });
+  }
+
+  function expectTextContains(error: ValidationError): void {
+    expect(error.constraints).toEqual({ contains: 'text must contain a bye string' });
+  }
+
+  class MyClass {
+    @Contains('hello', {
+      groups: ['title-validation'],
+    })
+    title: string;
+
+    @Contains('bye', {
+      groups: ['text-validation'],
+    })
+    text: string;
+  }
+
+  const validTitle = new MyClass();
+  validTitle.title = 'hello world';
+  validTitle.text = 'hello world';
+
+  const validText = new MyClass();
+  validText.title = 'bye world';
+  validText.text = 'bye world';
+
+  const validBoth = new MyClass();
+  validBoth.title = 'hello world';
+  validBoth.text = 'bye world';
+
+  const validNone = new MyClass();
+  validNone.title = 'bye world';
+  validNone.text = 'hello world';
+
+  describe('should validate only properties of the given group: title-validation', () => {
+    it('with valid title', () => {
+      return validator.validate(validTitle, { groups: ['title-validation'] }).then(errors => {
+        expect(errors.length).toEqual(0);
+      });
+    });
 
+    it('with valid text', () => {
+      return validator.validate(validText, { groups: ['title-validation'] }).then(errors => {
+        expect(errors.length).toEqual(1);
+        expectTitleContains(errors[0]);
+      });
     });
 
-});
+    it('with both valid', () => {
+      return validator.validate(validBoth, { groups: ['title-validation'] }).then(errors => {
+        expect(errors.length).toEqual(0);
+      });
+    });
 
-describe("groups", () => {
-    function expectTitleContains(error: ValidationError): void {
-        expect(error.constraints).toEqual({contains: "title must contain a hello string"});
-    }
+    it('with none valid', () => {
+      return validator.validate(validNone, { groups: ['title-validation'] }).then(errors => {
+        expect(errors.length).toEqual(1);
+        expectTitleContains(errors[0]);
+      });
+    });
+  });
+
+  describe('should validate only properties of the given group: text-validation', () => {
+    it('with valid title', () => {
+      return validator.validate(validTitle, { groups: ['text-validation'] }).then(errors => {
+        expect(errors.length).toEqual(1);
+        expectTextContains(errors[0]);
+      });
+    });
 
-    function expectTextContains(error: ValidationError): void {
-        expect(error.constraints).toEqual({contains: "text must contain a bye string"});
-    }
+    it('with valid text', () => {
+      return validator.validate(validText, { groups: ['text-validation'] }).then(errors => {
+        expect(errors.length).toEqual(0);
+      });
+    });
 
-    class MyClass {
-        @Contains("hello", {
-            groups: ["title-validation"]
-        })
-        title: string;
+    it('with both valid', () => {
+      return validator.validate(validBoth, { groups: ['text-validation'] }).then(errors => {
+        expect(errors.length).toEqual(0);
+      });
+    });
 
-        @Contains("bye", {
-            groups: ["text-validation"]
-        })
-        text: string;
-    }
+    it('with none valid', () => {
+      return validator.validate(validNone, { groups: ['text-validation'] }).then(errors => {
+        expect(errors.length).toEqual(1);
+        expectTextContains(errors[0]);
+      });
+    });
+  });
+
+  describe('should validate only properties of the given groups: both groups', () => {
+    it('with valid title', () => {
+      return validator.validate(validTitle, { groups: ['title-validation', 'text-validation'] }).then(errors => {
+        expect(errors.length).toEqual(1);
+        expectTextContains(errors[0]);
+      });
+    });
 
-    const validTitle = new MyClass();
-    validTitle.title = "hello world";
-    validTitle.text = "hello world";
+    it('with valid text', () => {
+      return validator.validate(validText, { groups: ['title-validation', 'text-validation'] }).then(errors => {
+        expect(errors.length).toEqual(1);
+        expectTitleContains(errors[0]);
+      });
+    });
 
-    const validText = new MyClass();
-    validText.title = "bye world";
-    validText.text = "bye world";
+    it('with both valid', () => {
+      return validator.validate(validBoth, { groups: ['title-validation', 'text-validation'] }).then(errors => {
+        expect(errors.length).toEqual(0);
+      });
+    });
 
-    const validBoth = new MyClass();
-    validBoth.title = "hello world";
-    validBoth.text = "bye world";
+    it('with none valid', () => {
+      return validator.validate(validNone, { groups: ['title-validation', 'text-validation'] }).then(errors => {
+        expect(errors.length).toEqual(2);
+        expectTitleContains(errors[0]);
+        expectTextContains(errors[1]);
+      });
+    });
+  });
+
+  describe('should validate all if no group is given', () => {
+    it('with valid title', () => {
+      // todo: all or without? what is better expected behaviour?
+      return validator.validate(validTitle).then(errors => {
+        expect(errors.length).toEqual(1);
+        expectTextContains(errors[0]);
+      });
+    });
 
-    const validNone = new MyClass();
-    validNone.title = "bye world";
-    validNone.text = "hello world";
-
-    describe("should validate only properties of the given group: title-validation", () => {
-        it("with valid title", () => {
-            return validator.validate(validTitle, {groups: ["title-validation"]}).then(errors => {
-                expect(errors.length).toEqual(0);
-            });
-        });
+    it('with valid text', () => {
+      // todo: all or without? what is better expected behaviour?
+      return validator.validate(validText).then(errors => {
+        expect(errors.length).toEqual(1);
+        expectTitleContains(errors[0]);
+      });
+    });
 
-        it("with valid text", () => {
-            return validator.validate(validText, {groups: ["title-validation"]}).then(errors => {
-                expect(errors.length).toEqual(1);
-                expectTitleContains(errors[0]);
-            });
-        });
+    it('with both valid', () => {
+      // todo: all or without? what is better expected behaviour?
+      return validator.validate(validBoth).then(errors => {
+        expect(errors.length).toEqual(0);
+      });
+    });
 
-        it("with both valid", () => {
-            return validator.validate(validBoth, {groups: ["title-validation"]}).then(errors => {
-                expect(errors.length).toEqual(0);
-            });
-        });
+    it('with none valid', () => {
+      // todo: all or without? what is better expected behaviour?
+      return validator.validate(validNone).then(errors => {
+        expect(errors.length).toEqual(2);
+        expectTitleContains(errors[0]);
+        expectTextContains(errors[1]);
+      });
+    });
+  });
+
+  describe('should validate all groups if empty group array is given', () => {
+    it('with valid title', () => {
+      return validator.validate(validTitle, { groups: [] }).then(errors => {
+        expect(errors.length).toEqual(1);
+        expectTextContains(errors[0]);
+      });
+    });
 
-        it("with none valid", () => {
-            return validator.validate(validNone, {groups: ["title-validation"]}).then(errors => {
-                expect(errors.length).toEqual(1);
-                expectTitleContains(errors[0]);
-            });
-        });
+    it('with valid text', () => {
+      return validator.validate(validText, { groups: [] }).then(errors => {
+        expect(errors.length).toEqual(1);
+        expectTitleContains(errors[0]);
+      });
+    });
 
+    it('with both valid', () => {
+      return validator.validate(validBoth, { groups: [] }).then(errors => {
+        expect(errors.length).toEqual(0);
+      });
     });
 
-    describe("should validate only properties of the given group: text-validation", () => {
-        it("with valid title", () => {
-            return validator.validate(validTitle, {groups: ["text-validation"]}).then(errors => {
-                expect(errors.length).toEqual(1);
-                expectTextContains(errors[0]);
-            });
-        });
+    it('with none valid', () => {
+      return validator.validate(validNone, { groups: [] }).then(errors => {
+        expect(errors.length).toEqual(2);
+        expectTitleContains(errors[0]);
+        expectTextContains(errors[1]);
+      });
+    });
+  });
 
-        it("with valid text", () => {
-            return validator.validate(validText, {groups: ["text-validation"]}).then(errors => {
-                expect(errors.length).toEqual(0);
-            });
-        });
+  describe('multiple groups per property', () => {
+    class MyClass {
+      @Contains('hello', { groups: ['contains'] })
+      @Matches(/.*stranger.*/, { groups: ['matches'] })
+      title: string;
+    }
 
-        it("with both valid", () => {
-            return validator.validate(validBoth, {groups: ["text-validation"]}).then(errors => {
-                expect(errors.length).toEqual(0);
-            });
-        });
+    function expectTitleMatches(error: ValidationError): void {
+      expect(error.constraints).toEqual({ matches: 'title must match /.*stranger.*/ regular expression' });
+    }
 
-        it("with none valid", () => {
-            return validator.validate(validNone, {groups: ["text-validation"]}).then(errors => {
-                expect(errors.length).toEqual(1);
-                expectTextContains(errors[0]);
-            });
-        });
+    const validContains = new MyClass();
+    validContains.title = 'hello';
 
-    });
+    const validMatches = new MyClass();
+    validMatches.title = 'stranger';
+
+    const validBoth = new MyClass();
+    validBoth.title = 'hello stranger';
 
-    describe("should validate only properties of the given groups: both groups", () => {
-        it("with valid title", () => {
-            return validator.validate(validTitle, {groups: ["title-validation", "text-validation"]}).then(errors => {
-                expect(errors.length).toEqual(1);
-                expectTextContains(errors[0]);
-            });
+    const validNone = new MyClass();
+    validNone.title = 'howdy rowdy';
+
+    describe('group: contains', () => {
+      it('with valid contains', () => {
+        return validator.validate(validContains, { groups: ['contains'] }).then(errors => {
+          expect(errors.length).toEqual(0);
         });
+      });
 
-        it("with valid text", () => {
-            return validator.validate(validText, {groups: ["title-validation", "text-validation"]}).then(errors => {
-                expect(errors.length).toEqual(1);
-                expectTitleContains(errors[0]);
-            });
+      it('with valid matches', () => {
+        return validator.validate(validMatches, { groups: ['contains'] }).then(errors => {
+          expect(errors.length).toEqual(1);
+          expectTitleContains(errors[0]);
         });
+      });
 
-        it("with both valid", () => {
-            return validator.validate(validBoth, {groups: ["title-validation", "text-validation"]}).then(errors => {
-                expect(errors.length).toEqual(0);
-            });
+      it('with valid both', () => {
+        return validator.validate(validBoth, { groups: ['contains'] }).then(errors => {
+          expect(errors.length).toEqual(0);
         });
+      });
 
-        it("with none valid", () => {
-            return validator.validate(validNone, {groups: ["title-validation", "text-validation"]}).then(errors => {
-                expect(errors.length).toEqual(2);
-                expectTitleContains(errors[0]);
-                expectTextContains(errors[1]);
-            });
+      it('with valid none', () => {
+        return validator.validate(validNone, { groups: ['contains'] }).then(errors => {
+          expect(errors.length).toEqual(1);
+          expectTitleContains(errors[0]);
         });
+      });
     });
 
-    describe("should validate all if no group is given", () => {
-        it("with valid title", () => { // todo: all or without? what is better expected behaviour?
-            return validator.validate(validTitle).then(errors => {
-                expect(errors.length).toEqual(1);
-                expectTextContains(errors[0]);
-            });
+    describe('group: matches', () => {
+      it('with valid contains', () => {
+        return validator.validate(validContains, { groups: ['matches'] }).then(errors => {
+          expect(errors.length).toEqual(1);
+          expectTitleMatches(errors[0]);
         });
+      });
 
-        it("with valid text", () => { // todo: all or without? what is better expected behaviour?
-            return validator.validate(validText).then(errors => {
-                expect(errors.length).toEqual(1);
-                expectTitleContains(errors[0]);
-            });
+      it('with valid matches', () => {
+        return validator.validate(validMatches, { groups: ['matches'] }).then(errors => {
+          expect(errors.length).toEqual(0);
         });
+      });
 
-        it("with both valid", () => { // todo: all or without? what is better expected behaviour?
-            return validator.validate(validBoth).then(errors => {
-                expect(errors.length).toEqual(0);
-            });
+      it('with valid both', () => {
+        return validator.validate(validBoth, { groups: ['matches'] }).then(errors => {
+          expect(errors.length).toEqual(0);
         });
+      });
 
-        it("with none valid", () => { // todo: all or without? what is better expected behaviour?
-            return validator.validate(validNone).then(errors => {
-                expect(errors.length).toEqual(2);
-                expectTitleContains(errors[0]);
-                expectTextContains(errors[1]);
-            });
+      it('with valid none', () => {
+        return validator.validate(validNone, { groups: ['matches'] }).then(errors => {
+          expect(errors.length).toEqual(1);
+          expectTitleMatches(errors[0]);
         });
-
+      });
     });
 
-    describe("should validate all groups if empty group array is given", () => {
-        it("with valid title", () => {
-            return validator.validate(validTitle, {groups: []}).then(errors => {
-                expect(errors.length).toEqual(1);
-                expectTextContains(errors[0]);
-            });
+    describe('groups: contains & matches', () => {
+      it('with valid contains', () => {
+        return validator.validate(validContains, { groups: ['contains', 'matches'] }).then(errors => {
+          expect(errors.length).toEqual(1);
+          expectTitleMatches(errors[0]);
         });
+      });
 
-        it("with valid text", () => {
-            return validator.validate(validText, {groups: []}).then(errors => {
-                expect(errors.length).toEqual(1);
-                expectTitleContains(errors[0]);
-            });
+      it('with valid matches', () => {
+        return validator.validate(validMatches, { groups: ['contains', 'matches'] }).then(errors => {
+          expect(errors.length).toEqual(1);
+          expectTitleContains(errors[0]);
         });
+      });
 
-        it("with both valid", () => {
-            return validator.validate(validBoth, {groups: []}).then(errors => {
-                expect(errors.length).toEqual(0);
-            });
+      it('with valid both', () => {
+        return validator.validate(validBoth, { groups: ['contains', 'matches'] }).then(errors => {
+          expect(errors.length).toEqual(0);
         });
-
-        it("with none valid", () => {
-            return validator.validate(validNone, {groups: []}).then(errors => {
-                expect(errors.length).toEqual(2);
-                expectTitleContains(errors[0]);
-                expectTextContains(errors[1]);
-            });
+      });
+
+      it('with valid none', () => {
+        return validator.validate(validNone, { groups: ['contains', 'matches'] }).then(errors => {
+          expect(errors.length).toEqual(1);
+          expect(errors[0].constraints).toEqual({
+            contains: 'title must contain a hello string',
+            matches: 'title must match /.*stranger.*/ regular expression',
+          });
         });
+      });
     });
+  });
 
-    describe("multiple groups per property", () => {
-        class MyClass {
-            @Contains("hello", {groups: ["contains"]})
-            @Matches(/.*stranger.*/, {groups: ["matches"]})
-            title: string;
-        }
-
-        function expectTitleMatches(error: ValidationError): void {
-            expect(error.constraints).toEqual({matches: "title must match /.*stranger.*/ regular expression"});
-        }
+  describe('ValidationOptions.always', function () {
+    class MyClass {
+      @Contains('noOptions')
+      noOptions: string;
+
+      @Contains('groupA', {
+        groups: ['A'],
+      })
+      groupA: string;
+
+      @Contains('alwaysFalse', {
+        always: false,
+      })
+      alwaysFalse: string;
+
+      @Contains('alwaysTrue', {
+        always: true,
+      })
+      alwaysTrue: string;
+    }
 
-        const validContains = new MyClass();
-        validContains.title = "hello";
-
-        const validMatches = new MyClass();
-        validMatches.title = "stranger";
-
-        const validBoth = new MyClass();
-        validBoth.title = "hello stranger";
-
-        const validNone = new MyClass();
-        validNone.title = "howdy rowdy";
-
-        describe("group: contains", () => {
-            it("with valid contains", () => {
-                return validator.validate(validContains, {groups: ["contains"]}).then(errors => {
-                    expect(errors.length).toEqual(0);
-                });
-            });
-
-            it("with valid matches", () => {
-                return validator.validate(validMatches, {groups: ["contains"]}).then(errors => {
-                    expect(errors.length).toEqual(1);
-                    expectTitleContains(errors[0]);
-                });
-            });
-
-            it("with valid both", () => {
-                return validator.validate(validBoth, {groups: ["contains"]}).then(errors => {
-                    expect(errors.length).toEqual(0);
-                });
-            });
-
-            it("with valid none", () => {
-                return validator.validate(validNone, {groups: ["contains"]}).then(errors => {
-                    expect(errors.length).toEqual(1);
-                    expectTitleContains(errors[0]);
-                });
-            });
+    const model1 = new MyClass();
+    model1.noOptions = 'XXX';
+    model1.groupA = 'groupA';
+    model1.alwaysFalse = 'alwaysFalse';
+    model1.alwaysTrue = 'alwaysTrue';
+
+    const model2 = new MyClass();
+    model2.noOptions = 'noOptions';
+    model2.groupA = 'XXX';
+    model2.alwaysFalse = 'alwaysFalse';
+    model2.alwaysTrue = 'alwaysTrue';
+
+    const model3 = new MyClass();
+    model3.noOptions = 'noOptions';
+    model3.groupA = 'groupA';
+    model3.alwaysFalse = 'XXX';
+    model3.alwaysTrue = 'alwaysTrue';
+
+    const model4 = new MyClass();
+    model4.noOptions = 'noOptions';
+    model4.groupA = 'groupA';
+    model4.alwaysFalse = 'alwaysFalse';
+    model4.alwaysTrue = 'XXX';
+
+    it('should validate decorator without options', function () {
+      return validator.validate(model1, { always: true, groups: ['A'] }).then(errors => {
+        expect(errors).toHaveLength(1);
+      });
+    });
 
-        });
+    it('should not validate decorator with groups if validating without matching groups', function () {
+      return validator.validate(model2, { always: true, groups: ['B'] }).then(errors => {
+        expect(errors).toHaveLength(0);
+      });
+    });
 
-        describe("group: matches", () => {
-
-            it("with valid contains", () => {
-                return validator.validate(validContains, {groups: ["matches"]}).then(errors => {
-                    expect(errors.length).toEqual(1);
-                    expectTitleMatches(errors[0]);
-                });
-            });
-
-            it("with valid matches", () => {
-                return validator.validate(validMatches, {groups: ["matches"]}).then(errors => {
-                    expect(errors.length).toEqual(0);
-                });
-            });
-
-            it("with valid both", () => {
-                return validator.validate(validBoth, {groups: ["matches"]}).then(errors => {
-                    expect(errors.length).toEqual(0);
-                });
-            });
-
-            it("with valid none", () => {
-                return validator.validate(validNone, {groups: ["matches"]}).then(errors => {
-                    expect(errors.length).toEqual(1);
-                    expectTitleMatches(errors[0]);
-                });
-            });
+    it('should not validate decorator with always set to false', function () {
+      return validator.validate(model3, { always: true, groups: ['A'] }).then(errors => {
+        expect(errors).toHaveLength(0);
+      });
+    });
 
-        });
+    it('should validate decorator with always set to true', function () {
+      return validator.validate(model4, { always: true, groups: ['A'] }).then(errors => {
+        expect(errors).toHaveLength(1);
+      });
+    });
+  });
 
-        describe("groups: contains & matches", () => {
-            it("with valid contains", () => {
-                return validator.validate(validContains, {groups: ["contains", "matches"]}).then(errors => {
-                    expect(errors.length).toEqual(1);
-                    expectTitleMatches(errors[0]);
-                });
-            });
-
-            it("with valid matches", () => {
-                return validator.validate(validMatches, {groups: ["contains", "matches"]}).then(errors => {
-                    expect(errors.length).toEqual(1);
-                    expectTitleContains(errors[0]);
-                });
-            });
-
-            it("with valid both", () => {
-                return validator.validate(validBoth, {groups: ["contains", "matches"]}).then(errors => {
-                    expect(errors.length).toEqual(0);
-                });
-            });
-
-            it("with valid none", () => {
-                return validator.validate(validNone, {groups: ["contains", "matches"]}).then(errors => {
-                    expect(errors.length).toEqual(1);
-                    expect(errors[0].constraints).toEqual({
-                        contains: "title must contain a hello string",
-                        matches: "title must match /.*stranger.*/ regular expression"
-                    });
-                });
-            });
+  describe('strictGroups', function () {
+    class MyClass {
+      @Contains('hello', {
+        groups: ['A'],
+      })
+      title: string;
+    }
 
-        });
+    const model1 = new MyClass();
 
+    it('should ignore decorators with groups if validating without groups', function () {
+      return validator.validate(model1, { strictGroups: true }).then(errors => {
+        expect(errors).toHaveLength(0);
+      });
     });
 
-    describe("always", () => {
-
-        class MyClass {
-            @Contains("hello", {
-                groups: ["sometimes"]
-            })
-            title: string;
+    it('should ignore decorators with groups if validating with empty groups array', function () {
+      return validator.validate(model1, { strictGroups: true, groups: [] }).then(errors => {
+        expect(errors).toHaveLength(0);
+      });
+    });
 
-            @Contains("bye", {
-                groups: ["always"],
-                always: true
-            })
-            text: string;
-        }
+    it('should include decorators with groups if validating with matching groups', function () {
+      return validator.validate(model1, { strictGroups: true, groups: ['A'] }).then(errors => {
+        expect(errors).toHaveLength(1);
+        expectTitleContains(errors[0]);
+      });
+    });
 
-        const model = new MyClass();
+    it('should not include decorators with groups if validating with different groups', function () {
+      return validator.validate(model1, { strictGroups: true, groups: ['B'] }).then(errors => {
+        expect(errors).toHaveLength(0);
+      });
+    });
+  });
 
-        it("should always validate a marked field even if another group is specified", () => {
-            return validator.validate(model, {groups: ["sometimes"]}).then(errors => {
-                expect(errors.length).toEqual(2);
-                expectTitleContains(errors[0]);
-                expectTextContains(errors[1]);
-            });
-        });
+  describe('always', () => {
+    class MyClass {
+      @Contains('hello', {
+        groups: ['sometimes'],
+      })
+      title: string;
+
+      @Contains('bye', {
+        groups: ['always'],
+        always: true,
+      })
+      text: string;
+    }
 
-        it("should always validate a marked field if its group is specified also (doubly enabled)", () => {
-            return validator.validate(model, {groups: ["always"]}).then(errors => {
-                expect(errors.length).toEqual(1);
-                expectTextContains(errors[0]);
-            });
-        });
+    const model = new MyClass();
 
-        it("should always validate *all* fields if group is not specified", () => {
-            return validator.validate(model, {groups: undefined}).then(errors => {
-                expect(errors.length).toEqual(2);
-                expectTitleContains(errors[0]);
-                expectTextContains(errors[1]);
-            });
-        });
+    it('should always validate a marked field even if another group is specified', () => {
+      return validator.validate(model, { groups: ['sometimes'] }).then(errors => {
+        expect(errors.length).toEqual(2);
+        expectTitleContains(errors[0]);
+        expectTextContains(errors[1]);
+      });
+    });
 
-        it("should always validate *all* fields if groups array is empty", () => {
-            return validator.validate(model, {groups: []}).then(errors => {
-                expect(errors.length).toEqual(2);
-                expectTitleContains(errors[0]);
-                expectTextContains(errors[1]);
-            });
-        });
+    it('should always validate a marked field if its group is specified also (doubly enabled)', () => {
+      return validator.validate(model, { groups: ['always'] }).then(errors => {
+        expect(errors.length).toEqual(1);
+        expectTextContains(errors[0]);
+      });
+    });
 
+    it('should always validate *all* fields if group is not specified', () => {
+      return validator.validate(model, { groups: undefined }).then(errors => {
+        expect(errors.length).toEqual(2);
+        expectTitleContains(errors[0]);
+        expectTextContains(errors[1]);
+      });
     });
 
-    describe("groups - nested", () => {
-        class Nested {
-            @Contains("hello", {
-                groups: ["always"],
-                always: true
-            })
-            text: string;
-        }
+    it('should always validate *all* fields if groups array is empty', () => {
+      return validator.validate(model, { groups: [] }).then(errors => {
+        expect(errors.length).toEqual(2);
+        expectTitleContains(errors[0]);
+        expectTextContains(errors[1]);
+      });
+    });
+  });
+
+  describe('groups - nested', () => {
+    class Nested {
+      @Contains('hello', {
+        groups: ['always'],
+        always: true,
+      })
+      text: string;
+    }
 
-        class Root {
-            @ValidateNested({groups: ["always"], always: true})
-            always = new Nested;
+    class Root {
+      @ValidateNested({ groups: ['always'], always: true })
+      always = new Nested();
 
-            @ValidateNested({groups: ["sometimes"]})
-            sometimes = new Nested;
+      @ValidateNested({ groups: ['sometimes'] })
+      sometimes = new Nested();
 
-            @ValidateNested({groups: ["other"]})
-            other = new Nested;
-        }
+      @ValidateNested({ groups: ['other'] })
+      other = new Nested();
+    }
 
-        const model = new Root();
+    const model = new Root();
 
-        function expectChildConstraint(error: ValidationError, childName: string): void {
-            expect(error.property).toEqual(childName);
-            expect(error.children.length).toEqual(1);
-            expect(error.children[0].property).toEqual("text");
-            expect(error.children[0].constraints).toEqual({contains: "text must contain a hello string"});
-        }
+    function expectChildConstraint(error: ValidationError, childName: string): void {
+      expect(error.property).toEqual(childName);
+      expect(error.children.length).toEqual(1);
+      expect(error.children[0].property).toEqual('text');
+      expect(error.children[0].constraints).toEqual({ contains: 'text must contain a hello string' });
+    }
 
-        it("should validate all children if no group is given", () => {
-            return validator.validate(model, {groups: undefined}).then(errors => {
-                expect(errors.length).toEqual(3);
-                expectChildConstraint(errors[0], "always");
-                expectChildConstraint(errors[1], "sometimes");
-                expectChildConstraint(errors[2], "other");
-            });
-        });
+    it('should validate all children if no group is given', () => {
+      return validator.validate(model, { groups: undefined }).then(errors => {
+        expect(errors.length).toEqual(3);
+        expectChildConstraint(errors[0], 'always');
+        expectChildConstraint(errors[1], 'sometimes');
+        expectChildConstraint(errors[2], 'other');
+      });
+    });
 
-        it("should validate only the given group + always", () => {
-            return validator.validate(model, {groups: ["sometimes"]}).then(errors => {
-                expect(errors.length).toEqual(2);
-                expectChildConstraint(errors[0], "always");
-                expectChildConstraint(errors[1], "sometimes");
-            });
-        });
+    it('should validate only the given group + always', () => {
+      return validator.validate(model, { groups: ['sometimes'] }).then(errors => {
+        expect(errors.length).toEqual(2);
+        expectChildConstraint(errors[0], 'always');
+        expectChildConstraint(errors[1], 'sometimes');
+      });
+    });
 
-        it("should validate only the given group + always", () => {
-            return validator.validate(model, {groups: ["always"]}).then(errors => {
-                expect(errors.length).toEqual(1);
-                expectChildConstraint(errors[0], "always");
-            });
-        });
+    it('should validate only the given group + always', () => {
+      return validator.validate(model, { groups: ['always'] }).then(errors => {
+        expect(errors.length).toEqual(1);
+        expectChildConstraint(errors[0], 'always');
+      });
     });
+  });
 });
 
-describe("context", () => {
-
-    it("should map context", () => {
-        function IsLongerThan(property: string, validationOptions?: ValidationOptions) {
-            return function(object: object, propertyName: string): void {
-                registerDecorator({
-                    target: object.constructor,
-                    propertyName: propertyName,
-                    options: validationOptions,
-                    constraints: [property],
-                    name: "isLongerThan",
-                    validator: {
-                        validate(value: any, args: ValidationArguments): boolean {
-                            const [relatedPropertyName] = args.constraints;
-                            const relatedValue = (args.object as any)[relatedPropertyName];
-                            if (relatedValue === undefined || relatedValue === null)
-                                return true;
-
-                            return typeof value === "string" &&
-                                typeof relatedValue === "string" &&
-                                value.length > relatedValue.length;
-                        }
-                    }
-                });
-            };
-        }
+describe('context', () => {
+  it('should map context', () => {
+    function IsLongerThan(property: string, validationOptions?: ValidationOptions) {
+      return function (object: object, propertyName: string): void {
+        registerDecorator({
+          target: object.constructor,
+          propertyName: propertyName,
+          options: validationOptions,
+          constraints: [property],
+          name: 'isLongerThan',
+          validator: {
+            validate(value: any, args: ValidationArguments): boolean {
+              const [relatedPropertyName] = args.constraints;
+              const relatedValue = (args.object as any)[relatedPropertyName];
+              if (relatedValue === undefined || relatedValue === null) return true;
+
+              return (
+                typeof value === 'string' && typeof relatedValue === 'string' && value.length > relatedValue.length
+              );
+            },
+          },
+        });
+      };
+    }
 
-        class MyClass {
-            @Contains("hello", {
-                message: "String is not valid. You string must contain a hello word",
-                context: {
-                    hi: "there"
-                }
-            })
-            someProperty: string;
-
-            @Contains("bye", {
-                message: "String is not valid. You string must contain a bye word",
-                context: {
-                    bye: "now"
-                }
-            })
-            someOtherProperty: string;
-
-            @IsDefined({
-                context: {
-                    foo: "bar"
-                }
-            })
-            requiredProperty: string;
-
-            @IsLongerThan("lastName", {
-                context: {baz: "qux"},
-                message: "$property must be longer then $constraint1. Given value: $value"
-            })
-            firstName: string;
-
-            lastName: string;
-        }
+    class MyClass {
+      @Contains('hello', {
+        message: 'String is not valid. You string must contain a hello word',
+        context: {
+          hi: 'there',
+        },
+      })
+      someProperty: string;
+
+      @Contains('bye', {
+        message: 'String is not valid. You string must contain a bye word',
+        context: {
+          bye: 'now',
+        },
+      })
+      someOtherProperty: string;
+
+      @IsDefined({
+        context: {
+          foo: 'bar',
+        },
+      })
+      requiredProperty: string;
+
+      @IsLongerThan('lastName', {
+        context: { baz: 'qux' },
+        message: '$property must be longer then $constraint1. Given value: $value',
+      })
+      firstName: string;
+
+      lastName: string;
+    }
 
-        const model = new MyClass();
-        model.firstName = "Short";
-        model.lastName = "LongerThanFirstName";
+    const model = new MyClass();
+    model.firstName = 'Short';
+    model.lastName = 'LongerThanFirstName';
 
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(4);
-            expect(errors[0].contexts["contains"]).toEqual({hi: "there"});
-            expect(errors[1].contexts["contains"]).toEqual({bye: "now"});
-            expect(errors[2].contexts["isDefined"]).toEqual({foo: "bar"});
-            expect(errors[3].contexts["isLongerThan"]).toEqual({baz: "qux"});
-        });
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(4);
+      expect(errors[0].contexts['contains']).toEqual({ hi: 'there' });
+      expect(errors[1].contexts['contains']).toEqual({ bye: 'now' });
+      expect(errors[2].contexts['isDefined']).toEqual({ foo: 'bar' });
+      expect(errors[3].contexts['isLongerThan']).toEqual({ baz: 'qux' });
     });
+  });
 
-    it("should map multiple context on a single property for different constraints", () => {
-        class MyClass {
-            @Contains("hello", {
-                message: "String is not valid. You string must contain a hello word",
-                context: {
-                    hi: "there"
-                }
-            })
-            @MinLength(20, {
-                context: {
-                    whats: "up"
-                }
-            })
-            someProperty: string;
-        }
+  it('should map multiple context on a single property for different constraints', () => {
+    class MyClass {
+      @Contains('hello', {
+        message: 'String is not valid. You string must contain a hello word',
+        context: {
+          hi: 'there',
+        },
+      })
+      @MinLength(20, {
+        context: {
+          whats: 'up',
+        },
+      })
+      someProperty: string;
+    }
 
-        const model = new MyClass();
-        model.someProperty = "bippity";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].contexts["contains"]).toEqual({hi: "there"});
-            expect(errors[0].contexts["minLength"]).toEqual({whats: "up"});
-        });
+    const model = new MyClass();
+    model.someProperty = 'bippity';
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].contexts['contains']).toEqual({ hi: 'there' });
+      expect(errors[0].contexts['minLength']).toEqual({ whats: 'up' });
     });
+  });
 
-    it("should not map no context", () => {
-        class MyClass {
-            @Contains("hello", {
-                message: "String is not valid. You string must contain a hello word"
-            })
-            someProperty: string;
-
-            @Contains("bye", {
-                message: "String is not valid. You string must contain a bye word",
-                context: {
-                    bye: "now"
-                }
-            })
-            someOtherProperty: string;
-        }
+  it('should not map no context', () => {
+    class MyClass {
+      @Contains('hello', {
+        message: 'String is not valid. You string must contain a hello word',
+      })
+      someProperty: string;
+
+      @Contains('bye', {
+        message: 'String is not valid. You string must contain a bye word',
+        context: {
+          bye: 'now',
+        },
+      })
+      someOtherProperty: string;
+    }
 
-        const model = new MyClass();
-        // model.someProperty = "hell no world";
-        return validator.validate(model).then(errors => {
-            expect(errors.length).toEqual(2);
-            expect(errors[0].contexts).toBeUndefined();
-            expect(errors[1].contexts["contains"]).toEqual({bye: "now"});
-        });
+    const model = new MyClass();
+    // model.someProperty = "hell no world";
+    return validator.validate(model).then(errors => {
+      expect(errors.length).toEqual(2);
+      expect(errors[0].contexts).toBeUndefined();
+      expect(errors[1].contexts['contains']).toEqual({ bye: 'now' });
     });
+  });
 
+  it('should stop at first error.', () => {
+    class MyClass {
+      @IsDefined({
+        message: 'isDefined',
+      })
+      @Contains('hello', {
+        message: 'String is not valid. You string must contain a hello word',
+      })
+      sameProperty: string;
+    }
+
+    const model = new MyClass();
+    return validator.validate(model, { stopAtFirstError: true }).then(errors => {
+      console.log();
+      expect(errors.length).toEqual(1);
+      expect(Object.keys(errors[0].constraints).length).toBe(1);
+      expect(errors[0].constraints['isDefined']).toBe('isDefined');
+    });
+  });
 });
diff --git a/test/functional/validator-options.spec.ts b/test/functional/validator-options.spec.ts
index fa689b6f12..b14fbf125b 100644
--- a/test/functional/validator-options.spec.ts
+++ b/test/functional/validator-options.spec.ts
@@ -1,49 +1,47 @@
-import {IsNotEmpty} from "../../src/decorator/decorators";
-import {Validator} from "../../src/validation/Validator";
+import { IsNotEmpty } from '../../src/decorator/decorators';
+import { Validator } from '../../src/validation/Validator';
 
 const validator = new Validator();
 
-describe("validator options", () => {
-    it("should not return target in validation error if validationError: { target: false } is set", () => {
-        class MyClass {
-            @IsNotEmpty()
-            title: string = "";
-            isActive: boolean;
-        }
-
-        const model = new MyClass();
-        model.title = "";
-        return validator.validate(model, { skipMissingProperties: true, validationError: { target: false } }).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].target).toBeUndefined();
-            expect(errors[0].property).toEqual("title");
-            expect(errors[0].constraints).toEqual({ isNotEmpty: "title should not be empty" });
-            expect(errors[0].value).toEqual("");
-        });
-    });
-
-    it("should returns error on unknown objects if forbidUnknownValues is true", function () {
-
-        const anonymousObject = { badKey: "This should not pass." };
-
-        return validator.validate(anonymousObject, { forbidUnknownValues: true }).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].target).toEqual(anonymousObject);
-            expect(errors[0].property).toEqual(undefined);
-            expect(errors[0].value).toEqual(undefined);
-            expect(errors[0].children).toBeInstanceOf(Array);
-            expect(errors[0].constraints).toEqual({ unknownValue: "an unknown value was passed to the validate function" });
-        });
+describe('validator options', () => {
+  it('should not return target in validation error if validationError: { target: false } is set', () => {
+    class MyClass {
+      @IsNotEmpty()
+      title: string = '';
+      isActive: boolean;
+    }
+
+    const model = new MyClass();
+    model.title = '';
+    return validator
+      .validate(model, { skipMissingProperties: true, validationError: { target: false } })
+      .then(errors => {
+        expect(errors.length).toEqual(1);
+        expect(errors[0].target).toBeUndefined();
+        expect(errors[0].property).toEqual('title');
+        expect(errors[0].constraints).toEqual({ isNotEmpty: 'title should not be empty' });
+        expect(errors[0].value).toEqual('');
+      });
+  });
+
+  it('should returns error on unknown objects if forbidUnknownValues is true', function () {
+    const anonymousObject = { badKey: 'This should not pass.' };
+
+    return validator.validate(anonymousObject, { forbidUnknownValues: true }).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].target).toEqual(anonymousObject);
+      expect(errors[0].property).toEqual(undefined);
+      expect(errors[0].value).toEqual(undefined);
+      expect(errors[0].children).toBeInstanceOf(Array);
+      expect(errors[0].constraints).toEqual({ unknownValue: 'an unknown value was passed to the validate function' });
     });
+  });
 
-    it("should return no error on unknown objects if forbidUnknownValues is false", function () {
-
-        const anonymousObject = { badKey: "This should not pass." };
+  it('should return no error on unknown objects if forbidUnknownValues is false', function () {
+    const anonymousObject = { badKey: 'This should not pass.' };
 
-        return validator.validate(anonymousObject, { forbidUnknownValues: false }).then(errors => {
-            expect(errors.length).toEqual(0);
-        });
+    return validator.validate(anonymousObject, { forbidUnknownValues: false }).then(errors => {
+      expect(errors.length).toEqual(0);
     });
-
-
+  });
 });
diff --git a/test/functional/whitelist-validation.spec.ts b/test/functional/whitelist-validation.spec.ts
index 9baf2860b8..f303706621 100644
--- a/test/functional/whitelist-validation.spec.ts
+++ b/test/functional/whitelist-validation.spec.ts
@@ -1,67 +1,62 @@
-import {Allow, IsDefined, Min} from "../../src/decorator/decorators";
-import {Validator} from "../../src/validation/Validator";
-import {ValidationTypes} from "../../src";
+import { Allow, IsDefined, Min } from '../../src/decorator/decorators';
+import { Validator } from '../../src/validation/Validator';
+import { ValidationTypes } from '../../src';
 
 const validator = new Validator();
 
-describe("whitelist validation", () => {
-
-    it("should strip non whitelisted properties, but leave whitelisted untouched", () => {
-
-        class MyClass {
-            @IsDefined()
-            title: string;
-
-            @Min(0)
-            views: number;
-        }
-
-        const model: any = new MyClass();
-
-        model.title = "hello";
-        model.views = 56;
-        model.unallowedProperty = 42;
-        return validator.validate(model, { whitelist: true }).then(errors => {
-            expect(errors.length).toEqual(0);
-            expect(model.unallowedProperty).toBeUndefined();
-            expect(model.title).toEqual("hello");
-            expect(model.views).toEqual(56);
-        });
+describe('whitelist validation', () => {
+  it('should strip non whitelisted properties, but leave whitelisted untouched', () => {
+    class MyClass {
+      @IsDefined()
+      title: string;
+
+      @Min(0)
+      views: number;
+    }
+
+    const model: any = new MyClass();
+
+    model.title = 'hello';
+    model.views = 56;
+    model.unallowedProperty = 42;
+    return validator.validate(model, { whitelist: true }).then(errors => {
+      expect(errors.length).toEqual(0);
+      expect(model.unallowedProperty).toBeUndefined();
+      expect(model.title).toEqual('hello');
+      expect(model.views).toEqual(56);
     });
+  });
 
-    it("should be able to whitelist with @Allow", () => {
-        class MyClass {
-            @Allow()
-            views: number;
-        }
+  it('should be able to whitelist with @Allow', () => {
+    class MyClass {
+      @Allow()
+      views: number;
+    }
 
-        const model: any = new MyClass();
+    const model: any = new MyClass();
 
-        model.views = 420;
-        model.unallowedProperty = "non-whitelisted";
+    model.views = 420;
+    model.unallowedProperty = 'non-whitelisted';
 
-        return validator.validate(model, { whitelist: true }).then(errors => {
-            expect(errors.length).toEqual(0);
-            expect(model.unallowedProperty).toBeUndefined();
-            expect(model.views).toEqual(420);
-        });
+    return validator.validate(model, { whitelist: true }).then(errors => {
+      expect(errors.length).toEqual(0);
+      expect(model.unallowedProperty).toBeUndefined();
+      expect(model.views).toEqual(420);
     });
+  });
 
-    it("should throw an error when forbidNonWhitelisted flag is set", () => {
-
-        class MyClass {
-        }
+  it('should throw an error when forbidNonWhitelisted flag is set', () => {
+    class MyClass {}
 
-        const model: any = new MyClass();
+    const model: any = new MyClass();
 
-        model.unallowedProperty = "non-whitelisted";
+    model.unallowedProperty = 'non-whitelisted';
 
-        return validator.validate(model, { whitelist: true, forbidNonWhitelisted: true }).then(errors => {
-            expect(errors.length).toEqual(1);
-            expect(errors[0].target).toEqual(model);
-            expect(errors[0].property).toEqual("unallowedProperty");
-            expect(errors[0].constraints).toHaveProperty(ValidationTypes.WHITELIST);
-        });
+    return validator.validate(model, { whitelist: true, forbidNonWhitelisted: true }).then(errors => {
+      expect(errors.length).toEqual(1);
+      expect(errors[0].target).toEqual(model);
+      expect(errors[0].property).toEqual('unallowedProperty');
+      expect(errors[0].constraints).toHaveProperty(ValidationTypes.WHITELIST);
     });
-
+  });
 });
diff --git a/test/utils.spec.ts b/test/utils.spec.ts
index a39015cb16..04b92ec519 100644
--- a/test/utils.spec.ts
+++ b/test/utils.spec.ts
@@ -1,33 +1,33 @@
-import {convertToArray} from "../src/utils";
+import { convertToArray } from '../src/utils';
 
-describe("convertToArray", () => {
-    it("convert Set into array", () => {
-        const setExample = new Set<string>();
-        setExample.add("hello");
-        setExample.add("world");
-        const newArr = convertToArray(setExample);
-        expect(newArr).toBeInstanceOf(Array);
-        expect(newArr.length).toEqual(2);
-        expect(newArr).toContain("hello");
-        expect(newArr).toContain("world");
-    });
+describe('convertToArray', () => {
+  it('convert Set into array', () => {
+    const setExample = new Set<string>();
+    setExample.add('hello');
+    setExample.add('world');
+    const newArr = convertToArray(setExample);
+    expect(newArr).toBeInstanceOf(Array);
+    expect(newArr.length).toEqual(2);
+    expect(newArr).toContain('hello');
+    expect(newArr).toContain('world');
+  });
 
-    it("convert Map into array of values", () => {
-        const map = new Map<string, string>();
-        map.set("key1", "hello");
-        map.set("key2", "world");
-        const newArr = convertToArray(map);
-        expect(newArr).toBeInstanceOf(Array);
-        expect(newArr.length).toEqual(2);
-        expect(newArr).toContain("hello");
-        expect(newArr).toContain("world");
-    });
+  it('convert Map into array of values', () => {
+    const map = new Map<string, string>();
+    map.set('key1', 'hello');
+    map.set('key2', 'world');
+    const newArr = convertToArray(map);
+    expect(newArr).toBeInstanceOf(Array);
+    expect(newArr.length).toEqual(2);
+    expect(newArr).toContain('hello');
+    expect(newArr).toContain('world');
+  });
 
-    it("should return array untouched", () => {
-        const arr = ["hello", "world"];
-        expect(arr).toBeInstanceOf(Array);
-        expect(arr.length).toEqual(2);
-        expect(arr).toContain("hello");
-        expect(arr).toContain("world");
-    });
+  it('should return array untouched', () => {
+    const arr = ['hello', 'world'];
+    expect(arr).toBeInstanceOf(Array);
+    expect(arr.length).toEqual(2);
+    expect(arr).toContain('hello');
+    expect(arr).toContain('world');
+  });
 });
diff --git a/tsconfig.json b/tsconfig.json
index a08e39dd4f..0bcb1e4900 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,25 +1,18 @@
 {
-    "version": "2.0.3",
-    "compilerOptions": {
-        "outDir": "dist/esm5",
-        "target": "es5",
-        "module": "commonjs",
-        "moduleResolution": "node",
-        "emitDecoratorMetadata": true,
-        "experimentalDecorators": true,
-        "sourceMap": true,
-        "stripInternal": true,
-        "noImplicitAny": true,
-        "declaration": true,
-        "declarationMap": true,
-        "declarationDir": "dist/types",
-        "lib": ["es6"],
-        "resolveJsonModule": true,
-        "importHelpers": true,
-    },
-    "exclude": [
-        "build",
-        "dist",
-        "node_modules"
-    ]
+  "compilerOptions": {
+    "module": "commonjs",
+    "moduleResolution": "node",
+    "target": "es2018",
+    "lib": ["es2018"],
+    "outDir": "build/node",
+    "rootDir": "./src",
+    "strict": true,
+    "sourceMap": true,
+    "removeComments": false,
+    "esModuleInterop": true,
+    "experimentalDecorators": true,
+    "emitDecoratorMetadata": true,
+    "forceConsistentCasingInFileNames": true
+  },
+  "exclude": ["build", "node_modules", "sample", "**/*.spec.ts", "test/**"]
 }
diff --git a/tsconfig.prod.cjs.json b/tsconfig.prod.cjs.json
new file mode 100644
index 0000000000..8f8b22e900
--- /dev/null
+++ b/tsconfig.prod.cjs.json
@@ -0,0 +1,7 @@
+{
+  "extends": "./tsconfig.prod.json",
+  "compilerOptions": {
+    "module": "CommonJS",
+    "outDir": "build/cjs"
+  },
+}
diff --git a/tsconfig.prod.esm2015.json b/tsconfig.prod.esm2015.json
new file mode 100644
index 0000000000..c109ec5a01
--- /dev/null
+++ b/tsconfig.prod.esm2015.json
@@ -0,0 +1,7 @@
+{
+  "extends": "./tsconfig.prod.json",
+  "compilerOptions": {
+    "module": "ES2015",
+    "outDir": "build/esm2015",
+  },
+}
diff --git a/tsconfig.prod.esm5.json b/tsconfig.prod.esm5.json
new file mode 100644
index 0000000000..ca56760a90
--- /dev/null
+++ b/tsconfig.prod.esm5.json
@@ -0,0 +1,8 @@
+{
+  "extends": "./tsconfig.prod.json",
+  "compilerOptions": {
+    "module": "ES2015",
+    "target": "ES5",
+    "outDir": "build/esm5",
+  },
+}
diff --git a/tsconfig.prod.json b/tsconfig.prod.json
new file mode 100644
index 0000000000..7daa5be4fe
--- /dev/null
+++ b/tsconfig.prod.json
@@ -0,0 +1,7 @@
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "strict": false,
+    "declaration": false,
+  },
+}
diff --git a/tsconfig.prod.types.json b/tsconfig.prod.types.json
new file mode 100644
index 0000000000..8de58dd290
--- /dev/null
+++ b/tsconfig.prod.types.json
@@ -0,0 +1,8 @@
+{
+  "extends": "./tsconfig.prod.json",
+  "compilerOptions": {
+    "declaration": true,
+    "emitDeclarationOnly": true,
+    "outDir": "build/types",
+  },
+}
diff --git a/tsconfig.spec.json b/tsconfig.spec.json
new file mode 100644
index 0000000000..c0215c96a0
--- /dev/null
+++ b/tsconfig.spec.json
@@ -0,0 +1,11 @@
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "strict": false,
+    "strictPropertyInitialization": false,
+    "sourceMap": false,
+    "removeComments": true,
+    "noImplicitAny": false,
+  },
+  "exclude": ["node_modules"]
+}
diff --git a/typings.json b/typings.json
deleted file mode 100644
index f74ca2c7a0..0000000000
--- a/typings.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-  "globalDevDependencies": {
-    "Q": "github:DefinitelyTyped/DefinitelyTyped/q/Q.d.ts#efd40e67ff323f7147651bdbef03c03ead7b1675",
-    "assertion-error": "registry:dt/assertion-error#1.0.0+20141105053942",
-    "chai": "registry:dt/chai#3.4.0+20160216071402",
-    "chai-as-promised": "registry:dt/chai-as-promised#0.0.0+20160219015317",
-    "gulp": "registry:dt/gulp#3.8.0+20150825164847",
-    "mocha": "registry:dt/mocha#2.2.5+20151023103246",
-    "orchestrator": "registry:dt/orchestrator#0.0.0+20150821143159",
-    "promises-a-plus": "registry:dt/promises-a-plus#0.0.0+20150118213706",
-    "sinon": "registry:dt/sinon#1.16.0+20151027143416"
-  },
-  "globalDependencies": {
-    "es6-shim": "registry:dt/es6-shim#0.31.2+20160215162030",
-    "node": "registry:dt/node#4.0.0+20160226132328"
-  }
-}